_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, const hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) { return !(__hs1 == __hs2); } template inline void swap(hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs1, hash_multiset<_Val, _HashFcn, _EqualKey, _Alloc>& __hs2) { __hs1.swap(__hs2); } _GLIBCXX_END_NAMESPACE _GLIBCXX_BEGIN_NAMESPACE(std) // Specialization of insert_iterator so that it will work for hash_set // and hash_multiset. template class insert_iterator<__gnu_cxx::hash_set<_Value, _HashFcn, _EqualKey, _Alloc> > { protected: typedef __gnu_cxx::hash_set<_Value, _HashFcn, _EqualKey, _Alloc> _Container; _Container* container; public: typedef _Container container_type; typedef output_iterator_tag iterator_category; typedef void value_type; typedef void difference_type; typedef void pointer; typedef void reference; insert_iterator(_Container& __x) : container(&__x) {} insert_iterator(_Container& __x, typename _Container::iterator) : container(&__x) {} insert_iterator<_Container>& operator=(const typename _Container::value_type& __value) { container->insert(__value); return *this; } insert_iterator<_Container>& operator*() { return *this; } insert_iterator<_Container>& operator++() { return *this; } insert_iterator<_Container>& operator++(int) { return *this; } }; template class insert_iterator<__gnu_cxx::hash_multiset<_Value, _HashFcn, _EqualKey, _Alloc> > { protected: typedef __gnu_cxx::hash_multiset<_Value, _HashFcn, _EqualKey, _Alloc> _Container; _Container* container; typename _Container::iterator iter; public: typedef _Container container_type; typedef output_iterator_tag iterator_category; typedef void value_type; typedef void difference_type; typedef void pointer; typedef void reference; insert_iterator(_Container& __x) : container(&__x) {} insert_iterator(_Container& __x, typename _Container::iterator) : container(&__x) {} insert_iterator<_Container>& operator=(const typename _Container::value_type& __value) { container->insert(__value); return *this; } insert_iterator<_Container>& operator*() { return *this; } insert_iterator<_Container>& operator++() { return *this; } insert_iterator<_Container>& operator++(int) { return *this; } }; _GLIBCXX_END_NAMESPACE #endif // Iostreams wrapper for stdio FILE* -*- C++ -*- // Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 2, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License along // with this library; see the file COPYING. If not, write to the Free // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, // USA. // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by // the GNU General Public License. /** @file ext/stdio_sync_filebuf.h * This file is a GNU extension to the Standard C++ Library. */ #ifndef _STDIO_SYNC_FILEBUF_H #define _STDIO_SYNC_FILEBUF_H 1 #pragma GCC system_header #include #include #include #include // For __c_file #ifdef _GLIBCXX_USE_WCHAR_T #include #endif _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) /// class stdio_sync_filebuf. template > class stdio_sync_filebuf : public std::basic_streambuf<_CharT, _Traits> { public: // Types: typedef _CharT char_type; typedef _Traits traits_type; typedef typename traits_type::int_type int_type; typedef typename traits_type::pos_type pos_type; typedef typename traits_type::off_type off_type; private: // Underlying stdio FILE std::__c_file* const _M_file; // Last character gotten. This is used when pbackfail is // called from basic_streambuf::sungetc() int_type _M_unget_buf; public: explicit stdio_sync_filebuf(std::__c_file* __f) : _M_file(__f), _M_unget_buf(traits_type::eof()) { } /** * @return The underlying FILE*. * * This function can be used to access the underlying "C" file pointer. * Note that there is no way for the library to track what you do * with the file, so be careful. */ std::__c_file* const file() { return this->_M_file; } protected: int_type syncgetc(); int_type syncungetc(int_type __c); int_type syncputc(int_type __c); virtual int_type underflow() { int_type __c = this->syncgetc(); return this->syncungetc(__c); } virtual int_type uflow() { // Store the gotten character in case we need to unget it. _M_unget_buf = this->syncgetc(); return _M_unget_buf; } virtual int_type pbackfail(int_type __c = traits_type::eof()) { int_type __ret; const int_type __eof = traits_type::eof(); // Check if the unget or putback was requested if (traits_type::eq_int_type(__c, __eof)) // unget { if (!traits_type::eq_int_type(_M_unget_buf, __eof)) __ret = this->syncungetc(_M_unget_buf); else // buffer invalid, fail. __ret = __eof; } else // putback __ret = this->syncungetc(__c); // The buffered character is no longer valid, discard it. _M_unget_buf = __eof; return __ret; } virtual std::streamsize xsgetn(char_type* __s, std::streamsize __n); virtual int_type overflow(int_type __c = traits_type::eof()) { int_type __ret; if (traits_type::eq_int_type(__c, traits_type::eof())) { if (std::fflush(_M_file)) __ret = traits_type::eof(); else __ret = traits_type::not_eof(__c); } else __ret = this->syncputc(__c); return __ret; } virtual std::streamsize xsputn(const char_type* __s, std::streamsize __n); virtual int sync() { return std::fflush(_M_file); } virtual std::streampos seekoff(std::streamoff __off, std::ios_base::seekdir __dir, std::ios_base::openmode = std::ios_base::in | std::ios_base::out) { std::streampos __ret(std::streamoff(-1)); int __whence; if (__dir == std::ios_base::beg) __whence = SEEK_SET; else if (__dir == std::ios_base::cur) __whence = SEEK_CUR; else __whence = SEEK_END; #ifdef _GLIBCXX_USE_LFS if (!fseeko64(_M_file, __off, __whence)) __ret = std::streampos(ftello64(_M_file)); #else if (!fseek(_M_file, __off, __whence)) __ret = std::streampos(std::ftell(_M_file)); #endif return __ret; } virtual std::streampos seekpos(std::streampos __pos, std::ios_base::openmode __mode = std::ios_base::in | std::ios_base::out) { return seekoff(std::streamoff(__pos), std::ios_base::beg, __mode); } }; template<> inline stdio_sync_filebuf::int_type stdio_sync_filebuf::syncgetc() { return std::getc(_M_file); } template<> inline stdio_sync_filebuf::int_type stdio_sync_filebuf::syncungetc(int_type __c) { return std::ungetc(__c, _M_file); } template<> inline stdio_sync_filebuf::int_type stdio_sync_filebuf::syncputc(int_type __c) { return std::putc(__c, _M_file); } template<> inline std::streamsize stdio_sync_filebuf::xsgetn(char* __s, std::streamsize __n) { std::streamsize __ret = std::fread(__s, 1, __n, _M_file); if (__ret > 0) _M_unget_buf = traits_type::to_int_type(__s[__ret - 1]); else _M_unget_buf = traits_type::eof(); return __ret; } template<> inline std::streamsize stdio_sync_filebuf::xsputn(const char* __s, std::streamsize __n) { return std::fwrite(__s, 1, __n, _M_file); } #ifdef _GLIBCXX_USE_WCHAR_T template<> inline stdio_sync_filebuf::int_type stdio_sync_filebuf::syncgetc() { return std::getwc(_M_file); } template<> inline stdio_sync_filebuf::int_type stdio_sync_filebuf::syncungetc(int_type __c) { return std::ungetwc(__c, _M_file); } template<> inline stdio_sync_filebuf::int_type stdio_sync_filebuf::syncputc(int_type __c) { return std::putwc(__c, _M_file); } template<> inline std::streamsize stdio_sync_filebuf::xsgetn(wchar_t* __s, std::streamsize __n) { std::streamsize __ret = 0; const int_type __eof = traits_type::eof(); while (__n--) { int_type __c = this->syncgetc(); if (traits_type::eq_int_type(__c, __eof)) break; __s[__ret] = traits_type::to_char_type(__c); ++__ret; } if (__ret > 0) _M_unget_buf = traits_type::to_int_type(__s[__ret - 1]); else _M_unget_buf = traits_type::eof(); return __ret; } template<> inline std::streamsize stdio_sync_filebuf::xsputn(const wchar_t* __s, std::streamsize __n) { std::streamsize __ret = 0; const int_type __eof = traits_type::eof(); while (__n--) { if (traits_type::eq_int_type(this->syncputc(*__s++), __eof)) break; ++__ret; } return __ret; } #endif #if _GLIBCXX_EXTERN_TEMPLATE extern template class stdio_sync_filebuf; #ifdef _GLIBCXX_USE_WCHAR_T extern template class stdio_sync_filebuf; #endif #endif _GLIBCXX_END_NAMESPACE #endif // Memory extensions -*- C++ -*- // Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 2, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License along // with this library; see the file COPYING. If not, write to the Free // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, // USA. // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by // the GNU General Public License. /* * * Copyright (c) 1994 * Hewlett-Packard Company * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Hewlett-Packard Company makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * * Copyright (c) 1996 * Silicon Graphics Computer Systems, Inc. * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Silicon Graphics makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. */ /** @file ext/memory * This file is a GNU extension to the Standard C++ Library (possibly * containing extensions from the HP/SGI STL subset). */ #ifndef _EXT_MEMORY #define _EXT_MEMORY 1 #pragma GCC system_header #include #include _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) using std::ptrdiff_t; using std::pair; using std::__iterator_category; using std::_Temporary_buffer; template pair<_InputIter, _ForwardIter> __uninitialized_copy_n(_InputIter __first, _Size __count, _ForwardIter __result, std::input_iterator_tag) { _ForwardIter __cur = __result; try { for (; __count > 0 ; --__count, ++__first, ++__cur) std::_Construct(&*__cur, *__first); return pair<_InputIter, _ForwardIter>(__first, __cur); } catch(...) { std::_Destroy(__result, __cur); __throw_exception_again; } } template inline pair<_RandomAccessIter, _ForwardIter> __uninitialized_copy_n(_RandomAccessIter __first, _Size __count, _ForwardIter __result, std::random_access_iterator_tag) { _RandomAccessIter __last = __first + __count; return (pair<_RandomAccessIter, _ForwardIter> (__last, std::uninitialized_copy(__first, __last, __result))); } template inline pair<_InputIter, _ForwardIter> __uninitialized_copy_n(_InputIter __first, _Size __count, _ForwardIter __result) { return __uninitialized_copy_n(__first, __count, __result, __iterator_category(__first)); } /** * @brief Copies the range [first,last) into result. * @param first An input iterator. * @param last An input iterator. * @param result An output iterator. * @return result + (first - last) * @ingroup SGIextensions * * Like copy(), but does not require an initialized output range. */ template inline pair<_InputIter, _ForwardIter> uninitialized_copy_n(_InputIter __first, _Size __count, _ForwardIter __result) { return __uninitialized_copy_n(__first, __count, __result, __iterator_category(__first)); } // An alternative version of uninitialized_copy_n that constructs // and destroys objects with a user-provided allocator. template pair<_InputIter, _ForwardIter> __uninitialized_copy_n_a(_InputIter __first, _Size __count, _ForwardIter __result, _Allocator __alloc) { _ForwardIter __cur = __result; try { for (; __count > 0 ; --__count, ++__first, ++__cur) __alloc.construct(&*__cur, *__first); return pair<_InputIter, _ForwardIter>(__first, __cur); } catch(...) { std::_Destroy(__result, __cur, __alloc); __throw_exception_again; } } template inline pair<_InputIter, _ForwardIter> __uninitialized_copy_n_a(_InputIter __first, _Size __count, _ForwardIter __result, std::allocator<_Tp>) { return uninitialized_copy_n(__first, __count, __result); } /** * This class provides similar behavior and semantics of the standard * functions get_temporary_buffer() and return_temporary_buffer(), but * encapsulated in a type vaguely resembling a standard container. * * By default, a temporary_buffer stores space for objects of * whatever type the Iter iterator points to. It is constructed from a * typical [first,last) range, and provides the begin(), end(), size() * functions, as well as requested_size(). For non-trivial types, copies * of *first will be used to initialize the storage. * * @c malloc is used to obtain underlying storage. * * Like get_temporary_buffer(), not all the requested memory may be * available. Ideally, the created buffer will be large enough to hold a * copy of [first,last), but if size() is less than requested_size(), * then this didn't happen. * * @ingroup SGIextensions */ template ::value_type > struct temporary_buffer : public _Temporary_buffer<_ForwardIterator, _Tp> { /// Requests storage large enough to hold a copy of [first,last). temporary_buffer(_ForwardIterator __first, _ForwardIterator __last) : _Temporary_buffer<_ForwardIterator, _Tp>(__first, __last) { } /// Destroys objects and frees storage. ~temporary_buffer() { } }; _GLIBCXX_END_NAMESPACE #endif // -*- C++ -*- // Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the terms // of the GNU General Public License as published by the Free Software // Foundation; either version 2, or (at your option) any later // version. // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // You should have received a copy of the GNU General Public License // along with this library; see the file COPYING. If not, write to // the Free Software Foundation, 59 Temple Place - Suite 330, Boston, // MA 02111-1307, USA. // As a special exception, you may use this file as part of a free // software library without restriction. Specifically, if other files // instantiate templates or use macros or inline functions from this // file, or you compile this file and link it with other files to // produce an executable, this file does not by itself cause the // resulting executable to be covered by the GNU General Public // License. This exception does not however invalidate any other // reasons why the executable file might be covered by the GNU General // Public License. // Copyright (C) 2004 Ami Tavory and Vladimir Dreizin, IBM-HRL. // Permission to use, copy, modify, sell, and distribute this software // is hereby granted without fee, provided that the above copyright // notice appears in all copies, and that both that copyright notice // and this permission notice appear in supporting documentation. None // of the above authors, nor IBM Haifa Research Laboratories, make any // representation about the suitability of this software for any // purpose. It is provided "as is" without express or implied // warranty. /** @file ext/throw_allocator.h * This file is a GNU extension to the Standard C++ Library. * * Contains an exception-throwing allocator, useful for testing * exception safety. In addition, allocation addresses are stored and * sanity checked. */ #ifndef _THROW_ALLOCATOR_H #define _THROW_ALLOCATOR_H 1 #include #include #include #include #include #include #include #include #include #include #include _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) class twister_rand_gen { public: twister_rand_gen(unsigned int seed = static_cast(std::time(0))); void init(unsigned int); double get_prob(); private: std::tr1::mt19937 _M_generator; }; /// Thown by throw_allocator. struct forced_exception_error : public std::exception { }; // Substitute for concurrence_error object in the case of -fno-exceptions. inline void __throw_forced_exception_error() { #if __EXCEPTIONS throw forced_exception_error(); #else __builtin_abort(); #endif } /// Base class. class throw_allocator_base { public: void init(unsigned long seed); static void set_throw_prob(double throw_prob); static double get_throw_prob(); static void set_label(size_t l); static bool empty(); struct group_throw_prob_adjustor { group_throw_prob_adjustor(size_t size) : _M_throw_prob_orig(_S_throw_prob) { _S_throw_prob = 1 - std::pow(double(1 - _S_throw_prob), double(0.5 / (size + 1))); } ~group_throw_prob_adjustor() { _S_throw_prob = _M_throw_prob_orig; } private: const double _M_throw_prob_orig; }; struct zero_throw_prob_adjustor { zero_throw_prob_adjustor() : _M_throw_prob_orig(_S_throw_prob) { _S_throw_prob = 0; } ~zero_throw_prob_adjustor() { _S_throw_prob = _M_throw_prob_orig; } private: const double _M_throw_prob_orig; }; protected: static void insert(void*, size_t); static void erase(void*, size_t); static void throw_conditionally(); // See if a particular address and size has been allocated by this // allocator. static void check_allocated(void*, size_t); // See if a given label has been allocated by this allocator. static void check_allocated(size_t); private: typedef std::pair alloc_data_type; typedef std::map map_type; typedef map_type::value_type entry_type; typedef map_type::const_iterator const_iterator; typedef map_type::const_reference const_reference; friend std::ostream& operator<<(std::ostream&, const throw_allocator_base&); static entry_type make_entry(void*, size_t); static void print_to_string(std::string&); static void print_to_string(std::string&, const_reference); static twister_rand_gen _S_g; static map_type _S_map; static double _S_throw_prob; static size_t _S_label; }; /// Allocator class with logging and exception control. template class throw_allocator : public throw_allocator_base { public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef value_type& reference; typedef const value_type& const_reference; template struct rebind { typedef throw_allocator other; }; throw_allocator() throw() { } throw_allocator(const throw_allocator&) throw() { } template throw_allocator(const throw_allocator&) throw() { } ~throw_allocator() throw() { } size_type max_size() const throw() { return std::allocator().max_size(); } pointer allocate(size_type __n, std::allocator::const_pointer hint = 0) { if (__builtin_expect(__n > this->max_size(), false)) std::__throw_bad_alloc(); throw_conditionally(); value_type* const a = std::allocator().allocate(__n, hint); insert(a, sizeof(value_type) * __n); return a; } void construct(pointer __p, const T& val) { return std::allocator().construct(__p, val); } #ifdef __GXX_EXPERIMENTAL_CXX0X__ template void construct(pointer __p, _Args&&... __args) { return std::allocator(). construct(__p, std::forward<_Args>(__args)...); } #endif void destroy(pointer __p) { std::allocator().destroy(__p); } void deallocate(pointer __p, size_type __n) { erase(__p, sizeof(value_type) * __n); std::allocator().deallocate(__p, __n); } void check_allocated(pointer __p, size_type __n) { throw_allocator_base::check_allocated(__p, sizeof(value_type) * __n); } void check_allocated(size_type label) { throw_allocator_base::check_allocated(label); } }; template inline bool operator==(const throw_allocator&, const throw_allocator&) { return true; } template inline bool operator!=(const throw_allocator&, const throw_allocator&) { return false; } std::ostream& operator<<(std::ostream& os, const throw_allocator_base& alloc) { std::string error; throw_allocator_base::print_to_string(error); os << error; return os; } // XXX Should be in .cc. twister_rand_gen:: twister_rand_gen(unsigned int seed) : _M_generator(seed) { } void twister_rand_gen:: init(unsigned int seed) { _M_generator.seed(seed); } double twister_rand_gen:: get_prob() { const double eng_min = _M_generator.min(); const double eng_range = static_cast(_M_generator.max() - eng_min); const double eng_res = static_cast(_M_generator() - eng_min); const double ret = eng_res / eng_range; _GLIBCXX_DEBUG_ASSERT(ret >= 0 && ret <= 1); return ret; } twister_rand_gen throw_allocator_base::_S_g; throw_allocator_base::map_type throw_allocator_base::_S_map; double throw_allocator_base::_S_throw_prob; size_t throw_allocator_base::_S_label = 0; throw_allocator_base::entry_type throw_allocator_base::make_entry(void* p, size_t size) { return std::make_pair(p, alloc_data_type(_S_label, size)); } void throw_allocator_base::init(unsigned long seed) { _S_g.init(seed); } void throw_allocator_base::set_throw_prob(double throw_prob) { _S_throw_prob = throw_prob; } double throw_allocator_base::get_throw_prob() { return _S_throw_prob; } void throw_allocator_base::set_label(size_t l) { _S_label = l; } void throw_allocator_base::insert(void* p, size_t size) { const_iterator found_it = _S_map.find(p); if (found_it != _S_map.end()) { std::string error("throw_allocator_base::insert"); error += "double insert!"; error += '\n'; print_to_string(error, make_entry(p, size)); print_to_string(error, *found_it); std::__throw_logic_error(error.c_str()); } _S_map.insert(make_entry(p, size)); } bool throw_allocator_base::empty() { return _S_map.empty(); } void throw_allocator_base::erase(void* p, size_t size) { check_allocated(p, size); _S_map.erase(p); } void throw_allocator_base::check_allocated(void* p, size_t size) { const_iterator found_it = _S_map.find(p); if (found_it == _S_map.end()) { std::string error("throw_allocator_base::check_allocated by value "); error += "null erase!"; error += '\n'; print_to_string(error, make_entry(p, size)); std::__throw_logic_error(error.c_str()); } if (found_it->second.second != size) { std::string error("throw_allocator_base::check_allocated by value "); error += "wrong-size erase!"; error += '\n'; print_to_string(error, make_entry(p, size)); print_to_string(error, *found_it); std::__throw_logic_error(error.c_str()); } } void throw_allocator_base::check_allocated(size_t label) { std::string found; const_iterator it = _S_map.begin(); while (it != _S_map.end()) { if (it->second.first == label) print_to_string(found, *it); ++it; } if (!found.empty()) { std::string error("throw_allocator_base::check_allocated by label "); error += '\n'; error += found; std::__throw_logic_error(error.c_str()); } } void throw_allocator_base::throw_conditionally() { if (_S_g.get_prob() < _S_throw_prob) __throw_forced_exception_error(); } void throw_allocator_base::print_to_string(std::string& s) { const_iterator begin = throw_allocator_base::_S_map.begin(); const_iterator end = throw_allocator_base::_S_map.end(); for (; begin != end; ++begin) print_to_string(s, *begin); } void throw_allocator_base::print_to_string(std::string& s, const_reference ref) { char buf[40]; const char tab('\t'); s += "address: "; __builtin_sprintf(buf, "%p", ref.first); s += buf; s += tab; s += "label: "; unsigned long l = static_cast(ref.second.first); __builtin_sprintf(buf, "%lu", l); s += buf; s += tab; s += "size: "; l = static_cast(ref.second.second); __builtin_sprintf(buf, "%lu", l); s += buf; s += '\n'; } _GLIBCXX_END_NAMESPACE #endif // Short-string-optimized versatile string base -*- C++ -*- // Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 2, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License along // with this library; see the file COPYING. If not, write to the Free // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, // USA. // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by // the GNU General Public License. /** @file ext/sso_string_base.h * This file is a GNU extension to the Standard C++ Library. * This is an internal header file, included by other library headers. * You should not attempt to use it directly. */ #ifndef _SSO_STRING_BASE_H #define _SSO_STRING_BASE_H 1 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) template class __sso_string_base : protected __vstring_utility<_CharT, _Traits, _Alloc> { public: typedef _Traits traits_type; typedef typename _Traits::char_type value_type; typedef __vstring_utility<_CharT, _Traits, _Alloc> _Util_Base; typedef typename _Util_Base::_CharT_alloc_type _CharT_alloc_type; typedef typename _CharT_alloc_type::size_type size_type; private: // Data Members: typename _Util_Base::template _Alloc_hider<_CharT_alloc_type> _M_dataplus; size_type _M_string_length; enum { _S_local_capacity = 15 }; union { _CharT _M_local_data[_S_local_capacity + 1]; size_type _M_allocated_capacity; }; void _M_data(_CharT* __p) { _M_dataplus._M_p = __p; } void _M_length(size_type __length) { _M_string_length = __length; } void _M_capacity(size_type __capacity) { _M_allocated_capacity = __capacity; } bool _M_is_local() const { return _M_data() == _M_local_data; } // Create & Destroy _CharT* _M_create(size_type&, size_type); void _M_dispose() { if (!_M_is_local()) _M_destroy(_M_allocated_capacity); } void _M_destroy(size_type __size) throw() { _M_get_allocator().deallocate(_M_data(), __size + 1); } // _M_construct_aux is used to implement the 21.3.1 para 15 which // requires special behaviour if _InIterator is an integral type template void _M_construct_aux(_InIterator __beg, _InIterator __end, std::__false_type) { typedef typename iterator_traits<_InIterator>::iterator_category _Tag; _M_construct(__beg, __end, _Tag()); } // _GLIBCXX_RESOLVE_LIB_DEFECTS // 438. Ambiguity in the "do the right thing" clause template void _M_construct_aux(_Integer __beg, _Integer __end, std::__true_type) { _M_construct(static_cast(__beg), __end); } template void _M_construct(_InIterator __beg, _InIterator __end) { typedef typename std::__is_integer<_InIterator>::__type _Integral; _M_construct_aux(__beg, __end, _Integral()); } // For Input Iterators, used in istreambuf_iterators, etc. template void _M_construct(_InIterator __beg, _InIterator __end, std::input_iterator_tag); // For forward_iterators up to random_access_iterators, used for // string::iterator, _CharT*, etc. template void _M_construct(_FwdIterator __beg, _FwdIterator __end, std::forward_iterator_tag); void _M_construct(size_type __req, _CharT __c); public: size_type _M_max_size() const { return (_M_get_allocator().max_size() - 1) / 2; } _CharT* _M_data() const { return _M_dataplus._M_p; } size_type _M_length() const { return _M_string_length; } size_type _M_capacity() const { return _M_is_local() ? size_type(_S_local_capacity) : _M_allocated_capacity; } bool _M_is_shared() const { return false; } void _M_set_leaked() { } void _M_leak() { } void _M_set_length(size_type __n) { _M_length(__n); traits_type::assign(_M_data()[__n], _CharT()); } __sso_string_base() : _M_dataplus(_M_local_data) { _M_set_length(0); } __sso_string_base(const _Alloc& __a); __sso_string_base(const __sso_string_base& __rcs); #ifdef __GXX_EXPERIMENTAL_CXX0X__ __sso_string_base(__sso_string_base&& __rcs); #endif __sso_string_base(size_type __n, _CharT __c, const _Alloc& __a); template __sso_string_base(_InputIterator __beg, _InputIterator __end, const _Alloc& __a); ~__sso_string_base() { _M_dispose(); } _CharT_alloc_type& _M_get_allocator() { return _M_dataplus; } const _CharT_alloc_type& _M_get_allocator() const { return _M_dataplus; } void _M_swap(__sso_string_base& __rcs); void _M_assign(const __sso_string_base& __rcs); void _M_reserve(size_type __res); void _M_mutate(size_type __pos, size_type __len1, const _CharT* __s, size_type __len2); void _M_erase(size_type __pos, size_type __n); void _M_clear() { _M_set_length(0); } bool _M_compare(const __sso_string_base&) const { return false; } }; template void __sso_string_base<_CharT, _Traits, _Alloc>:: _M_swap(__sso_string_base& __rcs) { // _GLIBCXX_RESOLVE_LIB_DEFECTS // 431. Swapping containers with unequal allocators. std::__alloc_swap<_CharT_alloc_type>::_S_do_it(_M_get_allocator(), __rcs._M_get_allocator()); if (_M_is_local()) if (__rcs._M_is_local()) { if (_M_length() && __rcs._M_length()) { _CharT __tmp_data[_S_local_capacity + 1]; traits_type::copy(__tmp_data, __rcs._M_local_data, _S_local_capacity + 1); traits_type::copy(__rcs._M_local_data, _M_local_data, _S_local_capacity + 1); traits_type::copy(_M_local_data, __tmp_data, _S_local_capacity + 1); } else if (__rcs._M_length()) { traits_type::copy(_M_local_data, __rcs._M_local_data, _S_local_capacity + 1); _M_length(__rcs._M_length()); __rcs._M_set_length(0); return; } else if (_M_length()) { traits_type::copy(__rcs._M_local_data, _M_local_data, _S_local_capacity + 1); __rcs._M_length(_M_length()); _M_set_length(0); return; } } else { const size_type __tmp_capacity = __rcs._M_allocated_capacity; traits_type::copy(__rcs._M_local_data, _M_local_data, _S_local_capacity + 1); _M_data(__rcs._M_data()); __rcs._M_data(__rcs._M_local_data); _M_capacity(__tmp_capacity); } else { const size_type __tmp_capacity = _M_allocated_capacity; if (__rcs._M_is_local()) { traits_type::copy(_M_local_data, __rcs._M_local_data, _S_local_capacity + 1); __rcs._M_data(_M_data()); _M_data(_M_local_data); } else { _CharT* __tmp_ptr = _M_data(); _M_data(__rcs._M_data()); __rcs._M_data(__tmp_ptr); _M_capacity(__rcs._M_allocated_capacity); } __rcs._M_capacity(__tmp_capacity); } const size_type __tmp_length = _M_length(); _M_length(__rcs._M_length()); __rcs._M_length(__tmp_length); } template _CharT* __sso_string_base<_CharT, _Traits, _Alloc>:: _M_create(size_type& __capacity, size_type __old_capacity) { // _GLIBCXX_RESOLVE_LIB_DEFECTS // 83. String::npos vs. string::max_size() if (__capacity > _M_max_size()) std::__throw_length_error(__N("__sso_string_base::_M_create")); // The below implements an exponential growth policy, necessary to // meet amortized linear time requirements of the library: see // http://gcc.gnu.org/ml/libstdc++/2001-07/msg00085.html. if (__capacity > __old_capacity && __capacity < 2 * __old_capacity) { __capacity = 2 * __old_capacity; // Never allocate a string bigger than max_size. if (__capacity > _M_max_size()) __capacity = _M_max_size(); } // NB: Need an array of char_type[__capacity], plus a terminating // null char_type() element. return _M_get_allocator().allocate(__capacity + 1); } template __sso_string_base<_CharT, _Traits, _Alloc>:: __sso_string_base(const _Alloc& __a) : _M_dataplus(__a, _M_local_data) { _M_set_length(0); } template __sso_string_base<_CharT, _Traits, _Alloc>:: __sso_string_base(const __sso_string_base& __rcs) : _M_dataplus(__rcs._M_get_allocator(), _M_local_data) { _M_construct(__rcs._M_data(), __rcs._M_data() + __rcs._M_length()); } #ifdef __GXX_EXPERIMENTAL_CXX0X__ template __sso_string_base<_CharT, _Traits, _Alloc>:: __sso_string_base(__sso_string_base&& __rcs) : _M_dataplus(__rcs._M_get_allocator(), _M_local_data) { if (__rcs._M_is_local()) { if (__rcs._M_length()) traits_type::copy(_M_local_data, __rcs._M_local_data, _S_local_capacity + 1); } else { _M_data(__rcs._M_data()); _M_capacity(__rcs._M_allocated_capacity); } _M_length(__rcs._M_length()); __rcs._M_length(0); __rcs._M_data(__rcs._M_local_data); } #endif template __sso_string_base<_CharT, _Traits, _Alloc>:: __sso_string_base(size_type __n, _CharT __c, const _Alloc& __a) : _M_dataplus(__a, _M_local_data) { _M_construct(__n, __c); } template template __sso_string_base<_CharT, _Traits, _Alloc>:: __sso_string_base(_InputIterator __beg, _InputIterator __end, const _Alloc& __a) : _M_dataplus(__a, _M_local_data) { _M_construct(__beg, __end); } // NB: This is the special case for Input Iterators, used in // istreambuf_iterators, etc. // Input Iterators have a cost structure very different from // pointers, calling for a different coding style. template template void __sso_string_base<_CharT, _Traits, _Alloc>:: _M_construct(_InIterator __beg, _InIterator __end, std::input_iterator_tag) { size_type __len = 0; size_type __capacity = size_type(_S_local_capacity); while (__beg != __end && __len < __capacity) { _M_data()[__len++] = *__beg; ++__beg; } try { while (__beg != __end) { if (__len == __capacity) { // Allocate more space. __capacity = __len + 1; _CharT* __al7m7n7o7p7nother = _M_create(__capacity, __len); _S_copy(__another, _M_data(), __len); _M_dispose(); _M_data(__another); _M_capacity(__capacity); } _M_data()[__len++] = *__beg; ++__beg; } } catch(...) { _M_dispose(); __throw_exception_again; } _M_set_length(__len); } template template void __sso_string_base<_CharT, _Traits, _Alloc>:: _M_construct(_InIterator __beg, _InIterator __end, std::forward_iterator_tag) { // NB: Not required, but considered best practice. if (__builtin_expect(__is_null_pointer(__beg) && __beg != __end, 0)) std::__throw_logic_error(__N("__sso_string_base::" "_M_construct NULL not valid")); size_type __dnew = static_cast(std::distance(__beg, __end)); if (__dnew > size_type(_S_local_capacity)) { _M_data(_M_create(__dnew, size_type(0))); _M_capacity(__dnew); } // Check for out_of_range and length_error exceptions. try { _S_copy_chars(_M_data(), __beg, __end); } catch(...) { _M_dispose(); __throw_exception_again; } _M_set_length(__dnew); } template void __sso_string_base<_CharT, _Traits, _Alloc>:: _M_construct(size_type __n, _CharT __c) { if (__n > size_type(_S_local_capacity)) { _M_data(_M_create(__n, size_type(0))); _M_capacity(__n); } if (__n) _S_assign(_M_data(), __n, __c); _M_set_length(__n); } template void __sso_string_base<_CharT, _Traits, _Alloc>:: _M_assign(const __sso_string_base& __rcs) { if (this != &__rcs) { const size_type __rsize = __rcs._M_length(); const size_type __capacity = _M_capacity(); if (__rsize > __capacity) { size_type __new_capacity = __rsize; _CharT* __tmp = _M_create(__new_capacity, __capacity); _M_dispose(); _M_data(__tmp); _M_capacity(__new_capacity); } if (__rsize) _S_copy(_M_data(), __rcs._M_data(), __rsize); _M_set_length(__rsize); } } template void __sso_string_base<_CharT, _Traits, _Alloc>:: _M_reserve(size_type __res) { // Make sure we don't shrink below the current size. if (__res < _M_length()) __res = _M_length(); const size_type __capacity = _M_capacity(); if (__res != __capacity) { if (__res > __capacity || __res > size_type(_S_local_capacity)) { _CharT* __tmp = _M_create(__res, __capacity); _S_copy(__tmp, _M_data(), _M_length() + 1); _M_dispose(); _M_data(__tmp); _M_capacity(__res); } else if (!_M_is_local()) { _S_copy(_M_local_data, _M_data(), _M_length() + 1); _M_destroy(__capacity); _M_data(_M_local_data); } } } template void __sso_string_base<_CharT, _Traits, _Alloc>:: _M_mutate(size_type __pos, size_type __len1, const _CharT* __s, const size_type __len2) { const size_type __how_much = _M_length() - __pos - __len1; size_type __new_capacity = _M_length() + __len2 - __len1; _CharT* __r = _M_create(__new_capacity, _M_capacity()); if (__pos) _S_copy(__r, _M_data(), __pos); if (__s && __len2) _S_copy(__r + __pos, __s, __len2); if (__how_much) _S_copy(__r + __pos + __len2, _M_data() + __pos + __len1, __how_much); _M_dispose(); _M_data(__r); _M_capacity(__new_capacity); } template void __sso_string_base<_CharT, _Traits, _Alloc>:: _M_erase(size_type __pos, size_type __n) { const size_type __how_much = _M_length() - __pos - __n; if (__how_much && __n) _S_move(_M_data() + __pos, _M_data() + __pos + __n, __how_much); _M_set_length(_M_length() - __n); } _GLIBCXX_END_NAMESPACE #endif /* _SSO_STRING_BASE_H */ // filebuf with encoding state type -*- C++ -*- // Copyright (C) 2002, 2003, 2004, 2007 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 2, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License along // with this library; see the file COPYING. If not, write to the Free // Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, // USA. // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by // the GNU General Public License. /** @file ext/enc_filebuf.h * This file is a GNU extension to the Standard C++ Library. */ #ifndef _EXT_ENC_FILEBUF_H #define _EXT_ENC_FILEBUF_H 1 #include #include #include _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) /// class enc_filebuf. template class enc_filebuf : public std::basic_filebuf<_CharT, encoding_char_traits<_CharT> > { public: typedef encoding_char_traits<_CharT> traits_type; typedef typename traits_type::state_type state_type; typedef typename traits_type::pos_type pos_type; enc_filebuf(state_type& __state) : std::basic_filebuf<_CharT, encoding_char_traits<_CharT> >() { this->_M_state_beg = __state; } private: // concept requirements: // Set state type to something useful. // Something more than copyconstructible is needed here, so // require default and copy constructible + assignment operator. __glibcxx_class_requires(state_type, _SGIAssignableConcept) }; _GLIBCXX_END_NAMESPACE #endif // Versatile string utility -*- C++ -*- // Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 2, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License along // with this library; see the file COPYING. If not, write to the Free // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, // USA. // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by // the GNU General Public License. /** @file ext/vstring_util.h * This file is a GNU extension to the Standard C++ Library. * This is an internal header file, included by other library headers. * You should not attempt to use it directly. */ #ifndef _VSTRING_UTIL_H #define _VSTRING_UTIL_H 1 #pragma GCC system_header #include #include #include // For less #include #include #include #include #include #include _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) template struct __vstring_utility { typedef typename _Alloc::template rebind<_CharT>::other _CharT_alloc_type; typedef _Traits traits_type; typedef typename _Traits::char_type value_type; typedef typename _CharT_alloc_type::size_type size_type; typedef typename _CharT_alloc_type::difference_type difference_type; typedef typename _CharT_alloc_type::pointer pointer; typedef typename _CharT_alloc_type::const_pointer const_pointer; // For __sso_string. typedef __gnu_cxx:: __normal_iterator > __sso_iterator; typedef __gnu_cxx:: __normal_iterator > __const_sso_iterator; // For __rc_string. typedef __gnu_cxx:: __normal_iterator > __rc_iterator; typedef __gnu_cxx:: __normal_iterator > __const_rc_iterator; // NB: When the allocator is empty, deriving from it saves space // (http://www.cantrip.org/emptyopt.html). template struct _Alloc_hider : public _Alloc1 { _Alloc_hider(_CharT* __ptr) : _Alloc1(), _M_p(__ptr) { } _Alloc_hider(const _Alloc1& __a, _CharT* __ptr) : _Alloc1(__a), _M_p(__ptr) { } _CharT* _M_p; // The actual data. }; // When __n = 1 way faster than the general multichar // traits_type::copy/move/assign. static void _S_copy(_CharT* __d, const _CharT* __s, size_type __n) { if (__n == 1) traits_type::assign(*__d, *__s); else traits_type::copy(__d, __s, __n); } static void _S_move(_CharT* __d, const _CharT* __s, size_type __n) { if (__n == 1) traits_type::assign(*__d, *__s); else traits_type::move(__d, __s, __n); } static void _S_assign(_CharT* __d, size_type __n, _CharT __c) { if (__n == 1) traits_type::assign(*__d, __c); else traits_type::assign(__d, __n, __c); } // _S_copy_chars is a separate template to permit specialization // to optimize for the common case of pointers as iterators. template static void _S_copy_chars(_CharT* __p, _Iterator __k1, _Iterator __k2) { for (; __k1 != __k2; ++__k1, ++__p) traits_type::assign(*__p, *__k1); // These types are off. } static void _S_copy_chars(_CharT* __p, __sso_iterator __k1, __sso_iterator __k2) { _S_copy_chars(__p, __k1.base(), __k2.base()); } static void _S_copy_chars(_CharT* __p, __const_sso_iterator __k1, __const_sso_iterator __k2) { _S_copy_chars(__p, __k1.base(), __k2.base()); } static void _S_copy_chars(_CharT* __p, __rc_iterator __k1, __rc_iterator __k2) { _S_copy_chars(__p, __k1.base(), __k2.base()); } static void _S_copy_chars(_CharT* __p, __const_rc_iterator __k1, __const_rc_iterator __k2) { _S_copy_chars(__p, __k1.base(), __k2.base()); } static void _S_copy_chars(_CharT* __p, _CharT* __k1, _CharT* __k2) { _S_copy(__p, __k1, __k2 - __k1); } static void _S_copy_chars(_CharT* __p, const _CharT* __k1, const _CharT* __k2) { _S_copy(__p, __k1, __k2 - __k1); } static int _S_compare(size_type __n1, size_type __n2) { const difference_type __d = difference_type(__n1 - __n2); if (__d > __numeric_traits_integer::__max) return __numeric_traits_integer::__max; else if (__d < __numeric_traits_integer::__min) return __numeric_traits_integer::__min; else return int(__d); } }; _GLIBCXX_END_NAMESPACE #endif /* _VSTRING_UTIL_H */ // Allocators -*- C++ -*- // Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 2, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License along // with this library; see the file COPYING. If not, write to the Free // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, // USA. // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files instantiate // templates or use macros or inline functions from this file, or you compile // this file and link it with other files to produce an executable, this // file does not by itself cause the resulting executable to be covered by // the GNU General Public License. This exception does not however // invalidate any other reasons why the executable file might be covered by // the GNU General Public License. /* * Copyright (c) 1996-1997 * Silicon Graphics Computer Systems, Inc. * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Silicon Graphics makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. */ /** @file ext/debug_allocator.h * This file is a GNU extension to the Standard C++ Library. * You should only include this header if you are using GCC 3 or later. */ #ifndef _DEBUG_ALLOCATOR_H #define _DEBUG_ALLOCATOR_H 1 #include _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) using std::size_t; /** * @brief A meta-allocator with debugging bits, as per [20.4]. * * This is precisely the allocator defined in the C++ Standard. * - all allocation calls operator new * - all deallocation calls operator delete */ template class debug_allocator { public: typedef typename _Alloc::size_type size_type; typedef typename _Alloc::difference_type difference_type; typedef typename _Alloc::pointer pointer; typedef typename _Alloc::const_pointer const_pointer; typedef typename _Alloc::reference reference; typedef typename _Alloc::const_reference const_reference; typedef typename _Alloc::value_type value_type; private: // _M_extra is the number of objects that correspond to the // extra space where debug information is stored. size_type _M_extra; _Alloc _M_allocator; public: debug_allocator() { const size_t __obj_size = sizeof(value_type); _M_extra = (sizeof(size_type) + __obj_size - 1) / __obj_size; } pointer allocate(size_type __n) { pointer __res = _M_allocator.allocate(__n + _M_extra); size_type* __ps = reinterpret_cast(__res); *__ps = __n; return __res + _M_extra; } pointer allocate(size_type __n, const void* __hint) { pointer __res = _M_allocator.allocate(__n + _M_extra, __hint); size_type* __ps = reinterpret_cast(__res); *__ps = __n; return __res + _M_extra; } void deallocate(pointer __p, size_type __n) { if (__p) { pointer __real_p = __p - _M_extra; if (*reinterpret_cast(__real_p) != __n) { throw std::runtime_error("debug_allocator::deallocate" " wrong size"); } _M_allocator.deallocate(__real_p, __n + _M_extra); } else throw std::runtime_error("debug_allocator::deallocate null pointer"); } }; _GLIBCXX_END_NAMESPACE #endif // Support for atomic operations -*- C++ -*- // Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 2, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License along // with this library; see the file COPYING. If not, write to the Free // Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, // USA. // As a special exception, you may use this file as part of a free software // library without restriction. Specifically, if other files in