// string_t.h // // STL interface to Windows API string BSTR // // (c) George Salnikov. 2002-2003. GeorgeSalnikov@comcast.net // http://GeorgeSalnikov.home.comcast.net // // The code is free. Use it at your own risk. I will not accept any blame // for damages and misuse, and gladly will accept any kind of contributions, // endorsements, and admirations. // //////////////////////////////////////////////////////////////////////////////// #ifndef _STRING_T_INCLUDED_ #define _STRING_T_INCLUDED_ #include #include #include #pragma warning(disable: 4786) #include //////////////////////////////////////////////////////////////////////////////// // template class SysString_allocator // allocator { public: typedef E value_type; typedef value_type* pointer; typedef value_type const* const_pointer; typedef value_type& reference; typedef value_type const& const_reference; typedef ptrdiff_t difference_type; typedef size_t size_type; SysString_allocator() throw() {} template SysString_allocator(const SysString_allocator &) throw() {} ~SysString_allocator() throw() {} size_type max_size() const throw() { return static_cast(-1) / sizeof(value_type); } pointer address(reference x) const throw() { return &x; } const_pointer address(const_reference x) const throw() { return &x; } pointer allocate(size_type n, const void*hint) { return (pointer) ::SysAllocStringByteLen(NULL, n * sizeof(value_type)); } void deallocate(pointer p, size_type) { ::SysFreeString(p); } void deallocate(pointer p) { ::SysFreeString(p); } void construct(pointer p, value_type const &x) { new(p) value_type(x); } void construct(pointer p) { new(p) value_type(); } void destroy(pointer p) throw() { p->~E(); } private: typedef SysString_allocator class_type; class_type const &operator =(class_type const &); // no copy assignment allowed }; templateinline bool operator==(const SysString_allocator&, const SysString_allocator&){ return true; } templateinline bool operator!=(const SysString_allocator&, const SysString_allocator&){ return false;} //////////////////////////////////////////////////////////////////////////////// // // class template BSTR_Impl wraps up BSTR and has a signaturure for string_t. // Allocates manipulates memory with Win API BSTR call (::SysAllocString, // ::SysFreeString, and such) // template > class BSTR_Impl { public: E* m_str; private: BSTR_Impl& operator=(const BSTR_Impl&); protected: typedef typename A::size_type size_type; typedef E* iterator; typedef const E* const_iterator; typedef A allocator_type; BSTR_Impl(const BSTR_Impl& s) : m_str(s.size()? ::SysAllocStringLen(s.begin(), s.size()):0) {} BSTR_Impl(const A&) : m_str(0) {} BSTR_Impl(const E* s, size_type len, const A&) : m_str(s!=0 && len!=0? ::SysAllocStringLen(s, len):0) {} BSTR_Impl(size_type len, E c, const A&) : m_str(len!=0? ::SysAllocStringLen(NULL, len):0) { if(m_str !=0) std::uninitialized_fill(begin(), end(), c); } ~BSTR_Impl() { ::SysFreeString(m_str); } iterator begin() { return m_str; } const_iterator begin() const { return m_str; } iterator end() { return m_str + size(); } const_iterator end() const { return m_str + size(); } size_type size() const { return ::SysStringLen(m_str); } size_type max_size() const { return size_t(-1) / sizeof(E) - 1; } size_type capacity() const { return size(); } const E* c_str() const { if(m_str==0) const_cast(m_str) =::SysAllocString(L""); return m_str; } const E* data() const { return c_str(); } void swap(BSTR_Impl& rhs) { std::swap(m_str, rhs.m_str); } void reserve(size_type resSize) { resize(resSize, E()); } void resize(size_type resSize, E c) { if(resSize < capacity()) // shrink to fit { BSTR_Impl temp(c_str(), resSize, A()); swap(temp); } else if(resSize > capacity()) // expand { BSTR_Impl temp(resSize, c, A()); std::uninitialized_copy(begin(), end(), temp.begin()); swap(temp); } } A get_allocator() const { return A(); } public: // // Windows ATL's sake extension // E* Detach() { E* ret(0); std::swap(m_str, ret); return ret; } void Attach(E* str) { ::SysFreeString(m_str); m_str = str; } void Empty() { ::SysFreeString(m_str); m_str = 0; } }; //////////////////////////////////////////////////////////////////////////////// // // class template string_t // STL std::basic_string interface implementation. Instead of Allocator you // are to use Impl class, which should implement specific memory allocation, and // member access methods // template< typename E, class T = std::char_traits, class Impl = BSTR_Impl > > class string_t : public Impl { public: // // typedefs // typedef T traits_type; typedef typename traits_type::char_type value_type; typedef Impl::allocator_type allocator_type; typedef typename allocator_type::size_type size_type; typedef typename allocator_type::difference_type difference_type; typedef allocator_type::reference reference; typedef allocator_type::const_reference const_reference; typedef allocator_type::pointer pointer; typedef allocator_type::const_pointer const_pointer; typedef typename Impl::iterator iterator; typedef typename Impl::const_iterator const_iterator; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; static const size_type npos; // = -1 private: // // assertion's flavors for 'p'osition and 'n'umber of symbols to operate withing string_t // inline void assert_p(const string_t& s, size_type p) { if(p > s.size()) throw std::out_of_range("string_t position"); } inline void assert_p(size_type p) const { if(p > size()) throw std::out_of_range("string_t position"); } inline void correct_n(size_type p, size_type& n) const { assert_p(p); size_type N=length()-p; if(n>N) n=N;} inline void correct_n(const string_t& s, size_type p, size_type& n) { assert_p(s,p); size_type N=s.length()-p; if(n>N) n=N;} inline size_t get_correct_n(const string_t& s, size_type p, size_type& n) { correct_n(s,p,n); return n; } inline size_t get_correct_n(size_type p, size_type& n) const { correct_n(p,n); return n; } static inline size_t min_(size_t a, size_type b) { return a < b? a:b; } // because std::min gets mixed up with windows #define min public: // 21.3.1 construct/copy/destroy: explicit string_t(const allocator_type& a=allocator_type()) : Impl(a) {} string_t(const string_t& s, size_type p=0, size_type n=npos, const allocator_type& a=allocator_type()) : Impl(a) { assign(s, p, n);} string_t(const value_type* s, const allocator_type& a=allocator_type()) : Impl(s, traits_type::length(s), a) {} string_t(const value_type* s, size_type n, allocator_type& a=allocator_type()): Impl(s, n, a) {} string_t(size_type n, value_type c, allocator_type& a=allocator_type()) : Impl(n, c, a) {} template string_t(InputIterator itb, InputIterator ite, allocator_type& a=allocator_type()) : Impl(a) { _append(itb, ite, std::iterator_traits::iterator_category()); } ~string_t() {} string_t& operator=(const string_t& s) { return &s ==this? *this : assign(s); } string_t& operator=(const value_type* s) { string_t(s).swap(*this); return *this; } string_t& operator=(value_type c) { return assign(&c, 1); } // 21.3.2 iterators: iterator begin () { return Impl::begin(); } iterator end () { return Impl::end(); } reverse_iterator rbegin () { return reverse_iterator(end()); } reverse_iterator rend () { return reverse_iterator(begin()); } const_iterator begin () const { return Impl::begin(); } const_iterator end () const { return Impl::end(); } const_reverse_iterator rbegin () const { return const_reverse_iterator(end()); } const_reverse_iterator rend () const { return const_reverse_iterator(begin()); } // 21.3.3 capacity: size_type size() const { return Impl::size(); } size_type length() const { return size(); } size_type max_size() const { return Impl::max_size(); } void resize(size_type n, value_type c) { Impl::resize(n, c); } void resize(size_type n) { resize(n, E(0)); } size_type capacity() const { return Impl::capacity(); } void reserve(size_type n=0) { if(n >max_size())throw std::length_error("string_t::reserve"); Impl::reserve(n);} void clear() { resize(0); } bool empty() const { return size() == 0; } // 21.3.4 element access: const_reference operator[] (size_type p) const { return *(begin() + p); } reference operator[] (size_type p) { return *(begin() + p); } const_reference at (size_type p) const { assert_p(p); return (*this)[p]; } reference at (size_type p) { assert_p(p); return (*this)[p]; } // 21.3.5 modifiers: string_t& operator+=(const string_t& s) { return append(s); } string_t& operator+=(const value_type* s) { return append(s); } string_t& operator+=(value_type c) { return append(1, c); } string_t& append (const string_t& s) { return append(s, 0, npos); } string_t& append (const string_t& s, size_type p, size_type n) { return insert(size(), s, p, n); } string_t& append (const value_type* s, size_type n) { return insert(size(), s, n); } string_t& append (const value_type* s) { return append(s, traits_type::length(s)); } string_t& append (size_type n, value_type c) { return insert(size(), n, c); } template string_t& append(InputIterator itb, InputIterator ite) { return _append(itb, ite, std::iterator_traits::iterator_category()); } private: template string_t& _append(InputIterator itb, InputIterator ite, std::input_iterator_tag) { for( ; itb != ite ; ++itb) *this += E(*itb); return *this; } template string_t& _append(InputIterator itb, InputIterator ite, std::random_access_iterator_tag)//std::bidirectional_access_iterator_tag) { size_type oldSize = size(); reserve(oldSize +std::distance(ite, itb)); std::copy(itb, ite, begin() + oldSize); return *this; } public: string_t& assign(const string_t& s) { return assign(s, 0, npos); } string_t& assign(const string_t& s, size_type p, size_type n) { return assign((s.begin()+p), get_correct_n(s,p,n)); } string_t& assign(const value_type* s) { return assign(s, traits_type::length(s)); } string_t& assign(const value_type* s, size_type n) { return replace(begin(), end(), s, n); } string_t& assign(size_type n, value_type c) { return replace(begin(), end(), n, c); } template string_t& assign(InputIterator itb, InputIterator ite) { return replace(begin(), end(), itb, ite); } string_t& insert(size_type p, const string_t& s) { return insert(p, s, 0, npos); } string_t& insert(size_type p1, const string_t& s, size_type p2, size_type n) { return replace(p1, 0, s, p2, n); } string_t& insert(size_type p, const value_type* s, size_type n) { return replace(p, 0, s, n); } string_t& insert(size_type p, const value_type* s) { return insert(p, s, traits_type::length(s)); } string_t& insert(size_type p, size_type n, value_type c) { return replace(p, 0, n, c); } iterator insert(iterator it, value_type c = value_type()) { size_type p(it-begin()); insert(p,&c,1); return begin()+p; } void insert(iterator it, size_type n, value_type c) { insert(it - begin(), n, c); } template void insert(iterator it, InputIterator itb, InputIterator ite) { replace(it, it, itb, ite); } string_t& erase(size_type p=0, size_type n=npos) { return replace(p, n, 0, value_type()); } iterator erase(iterator it) { size_type p(it-begin()); erase(p, 1); return begin() +p; } iterator erase(iterator itb, iterator ite) { size_type p(itb-begin()); erase(p, ite-itb); return begin()+p; } string_t& replace(size_type p, size_type n, const string_t& s) { return replace(p, n, s, 0, npos); } string_t& replace(size_type p, size_type n, const string_t& s, size_type p2, size_type n2) { return replace(p, n, s.begin() +p2, get_correct_n(s,p2,n2));} string_t& replace(size_type p, size_type n, const value_type* s) { return replace(p, n, s, traits_type::length(s)); } string_t& replace(size_type p, size_type n1, size_type n2, value_type c) { return replace(p, n1, string_t(n2, c)); } string_t& replace(iterator itb, iterator ite, const string_t& s) { return replace(itb, ite, s.c_str(), s.length()); } string_t& replace(iterator itb, iterator ite, const value_type* s, size_type n) { return replace(itb-begin(), ite-itb, s, n); } string_t& replace(iterator itb, iterator ite, const value_type* s) { return replace(itb,ite,s,traits_type::length(s));} string_t& replace(iterator itb, iterator ite, size_type n, value_type c) { return replace(itb-begin(), ite -itb, n, c); } template string_t& replace(iterator itb, iterator ite, InpIterator ib, InpIterator ie) { return replace(itb, ite, string_t(ib, ie)); } string_t& replace(size_type p, size_type n, const value_type* s, size_type n2) { correct_n(p, n); if((n2 >= max_size() -p)) throw std::length_error("string_t::replace"); size_type oldSize = size(); if(n < n2) resize(oldSize - n + n2); traits_type::move(begin() + p + n2, begin() + p + n, oldSize - p - n); std::copy(s, s + n2, begin() + p); if(n > n2) resize(size() - n + n2); return *this; } size_type copy(value_type* s, size_type n, size_type p = 0) const { correct_n(p, n); std::copy(begin() + p, begin() + p + n, s); return n; } void swap(string_t& rhs) { this->Impl::swap(static_cast(rhs)); } // 21.3.6 string operations: const value_type* c_str() const { return Impl::c_str(); } const value_type* data() const { return Impl::data(); } allocator_type get_allocator() const { return Impl::get_allocator(); } // find* flavors size_type find (const string_t& s, size_type p=0) const{ return find (s.c_str(), p, s.length()); } size_type find_first_of (const string_t& s, size_type p=0) const{ return find_first_of (s.c_str(), p, s.length()); } size_type find_first_not_of (const string_t& s, size_type p=0) const{ return find_first_not_of (s.c_str(), p, s.length()); } size_type rfind (const string_t& s, size_type p=npos) const{ return rfind (s.c_str(), p, s.length()); } size_type find_last_of (const string_t& s, size_type p=npos) const{ return find_last_of (s.c_str(), p, s.length()); } size_type find_last_not_of (const string_t& s, size_type p=npos) const{ return find_last_not_of (s.c_str(), p, s.length()); } size_type find (const value_type* s, size_type p=0) const{ return find (s, p, traits_type::length(s));} size_type find_first_of (const value_type* s, size_type p=0) const{ return find_first_of (s, p, traits_type::length(s));} size_type find_first_not_of (const value_type* s, size_type p=0) const{ return find_first_not_of (s, p, traits_type::length(s));} size_type rfind (const value_type* s, size_type p=npos) const{ return rfind (s, p, traits_type::length(s));} size_type find_last_of (const value_type* s, size_type p=npos) const{ return find_last_of (s, p, traits_type::length(s));} size_type find_last_not_of (const value_type* s, size_type p=npos) const{ return find_last_not_of (s, p, traits_type::length(s));} size_type find (value_type c, size_type p=0) const{ return find (&c, p, 1); } size_type find_first_of (value_type c, size_type p=0) const{ return find_first_of (&c, p, 1); } size_type find_first_not_of (value_type c, size_type p=0) const{ return find_first_not_of (&c, p, 1); } size_type rfind (value_type c, size_type p=npos) const{ return rfind (&c, p, 1); } size_type find_last_of (value_type c, size_type p=npos) const{ return find_last_of (&c, p, 1); } size_type find_last_not_of (value_type c, size_type p=npos) const{ return find_last_not_of (&c, p, 1); } size_type find(const value_type* s, size_type p, size_type n) const { for( ; p <= size() ; ++p) if(traits_type::compare(begin() + p, s, n) == 0) return p; return npos; } size_type find_first_of(const value_type* s, size_type p, size_type n) const { if(p < length() && n != 0) for(const_iterator it=begin() +p , itEnd =end() ; it != itEnd ; ++it) if(traits_type::find(s, n, *it) != 0) return it - begin(); return npos; } size_type find_first_not_of(const value_type* s, size_type p, size_type n) const { if(p < length()) for(const_iterator it =begin() +p , itEnd =end() ; it != itEnd ; ++it) if(traits_type::find(s, n, *it) == 0) return it - begin(); return npos; } size_type find_last_of(const value_type* s, size_type p, size_type n) const { if(!empty() && n > 0) { for(const_iterator it=begin() +min_(p, length() -1) ; ; --it) { if(traits_type::find(s, n, *it) != 0) return it - begin(); if(it == begin()) break; } } return npos; } size_type find_last_not_of (const value_type* s, size_type p, size_type n) const { if(!empty() && n > 0) { for(const_iterator it =begin() +min_(p, length() -1) ; ; --it) { if(traits_type::find(s, n, *it) == 0) return it - begin(); if(it == begin()) break; } } return npos; } size_type rfind(const value_type* s, size_type pos, size_type n) const { if(n > length()) return npos; p = min_(p, length() - n); if(n ==0) return p; for(const_iterator it = begin() + p ; ; --it) { if(traits_type::eq(*it, *s) && traits_type::compare(it, s, n) == 0) return it - begin(); if(it == begin()) break; } return npos; } string_t substr(size_type p=0, size_type n=npos) const{ return string_t(data() +p, get_correct_n(p,n)); } int compare(const string_t& s) const{ return compare(0, size(), s.data(), s.length()); } int compare(const value_type* s) const{ return compare(0, size(), s, traits_type::length(s)); } int compare(size_type p, size_type n, const string_t& s)const{ return compare(p, n, s.data(), s.length()); } int compare(size_type p, size_type n, const string_t& s, size_type p2, size_type n2) const{ return compare(p, n, s.data() +p2, get_correct_n(s,p2,n2)); } int compare(size_type p, size_type n, const value_type* s, size_type n2=npos) const { int res = traits_type::compare(data() + p, s, min_(get_correct_n(p, n), n2)); return res != 0? res : n -n2; } }; // // non-member functions // template string_t operator+(const string_t& lhs, const string_t& rhs) { string_t str; str.reserve(lhs.size() + rhs.size()); return str.append(lhs).append(rhs); } template string_t operator+(const string_t::value_type* lhs, const string_t& rhs) { const size_type len = traits_type::length(lhs); string_t str; str.reserve(len + rhs.size()); return str.append(lhs, len).append(rhs); } template string_t operator+(typename string_t::value_type lhs, const string_t& rhs) { string_t str; str.reserve(rhs.size() +1); return str.append(lhs).append(rhs); } template string_t operator+(const string_t& lhs, const string_t::value_type* rhs) { const size_type len = traits_type::length(rhs); string_t str; str.reserve(lhs.size() + len); return str.append(lhs).append(rhs, len); } template string_t operator+(const string_t& lhs, string_t::value_type rhs) { string_t str; str.reserve(lhs.size() + 1); return str.append(lhs).append(rhs); } template bool operator==(const string_t& lhs, const string_t& rhs) { return lhs.compare(rhs) == 0; } template bool operator==(const string_t::value_type* lhs, const string_t& rhs) { return rhs == lhs; } template bool operator==(const string_t& lhs, const string_t::value_type* rhs) { return lhs.compare(rhs) == 0; } template bool operator!=(const string_t& lhs, const string_t& rhs) { return !(lhs == rhs); } template bool operator!=(const string_t::value_type* lhs, const string_t& rhs) { return !(lhs == rhs); } template bool operator!=(const string_t& lhs, const string_t::value_type* rhs) { return !(lhs == rhs); } template bool operator<(const string_t& lhs, const string_t& rhs) { return lhs.compare(rhs) < 0; } template bool operator<(const string_t& lhs, const string_t::value_type* rhs) { return lhs.compare(rhs) < 0; } template bool operator<(const string_t::value_type* lhs, const string_t& rhs) { return rhs.compare(lhs) > 0; } template bool operator>(const string_t& lhs, const string_t& rhs) { return rhs < lhs; } template bool operator>(const string_t& lhs, const string_t::value_type* rhs) { return rhs < lhs; } template bool operator>(const string_t::value_type* lhs, const string_t& rhs) { return rhs < lhs; } template bool operator<=(const string_t& lhs, const string_t& rhs) { return !(rhs < lhs); } template bool operator<=(const string_t& lhs, const string_t::value_type* rhs) { return !(rhs < lhs); } template bool operator<=(const string_t::value_type* lhs, const string_t& rhs) { return !(rhs < lhs); } template bool operator>=(const string_t& lhs, const string_t& rhs) { return !(lhs < rhs); } template bool operator>=(const string_t& lhs, const string_t::value_type* rhs) { return !(lhs < rhs); } template bool operator>=(const string_t::value_type* lhs, const string_t& rhs) { return !(lhs < rhs); } template void swap(string_t& lhs, string_t& rhs) { lhs.swap(rhs); } // 21.3.7.8 template std::basic_ostream::value_type, typename string_t::traits_type>& operator<<(std::basic_ostream::value_type, string_t::traits_type>& os, const string_t& s) { return os << s.c_str(); } template const typename string_t::size_type string_t::npos = (typename string_t::size_type)(-1); // re do (optimize) template std::basic_istream::value_type, typename string_t::traits_type>& operator>>(std::basic_istream::value_type, string_t::traits_type>& is, string_t& s) { std::basic_string stdstr; is >> stdstr; s = stdstr.c_str(); return is; } template std::basic_istream::value_type, typename string_t::traits_type>& getline(std::basic_istream::value_type, string_t::traits_type>& is, string_t& s, string_t::value_type delim) { std::basic_string stdstr; std::getline(is, stdstr, delim); s = stdstr.c_str(); return is; } template std::basic_istream::value_type, typename string_t::traits_type>& getline(std::basic_istream::value_type, string_t::traits_type>& is, string_t& s) { std::basic_string stdstr; std::getline(is, stdstr); s = stdstr.c_str(); return is; } ///////////////////////////////////////////////////////////////////////////////// // typedef string_t, BSTR_Impl > > ComBSTRing; #endif // _STRING_T_INCLUDED_