// include/const_string_facade.hh // This file is part of libpbe; see http://svn.chezphil.org/libpbe/ // (C) 2007 Philip Endecott // This program 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 of the License, or // any later version. // // This program 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 program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifndef pbe_const_string_facade_hh #define pbe_const_string_facade_hh #include #include #include #include #include // const_string_facade makes it simpler to implement a class with // an interface similar to a const std::string. The implementation // simply needs to provide access to pointers to the beginning and // end of the raw data. // If the raw data is null-terminated then c_str() will work. // See ../examples/const_string_facade.cc for example usage. namespace pbe { template inline size_t strlen(const CHAR* s) { return std::find(s,s-1,0) - s; } template<> inline size_t strlen(const char* s) { return ::strlen(s); } template<> inline size_t strlen(const unsigned char* s) { return ::strlen(reinterpret_cast(s)); } template<> inline size_t strlen(const signed char* s) { return ::strlen(reinterpret_cast(s)); } template inline bool contains(ITER b, ITER e, CHAR c) { return std::find(b,e,c)!=e; } template inline bool not_contains(ITER b, ITER e, CHAR c) { return std::find(b,e,c)==e; } template inline int strcmp(CHAR* abeg, CHAR* aend, CHAR* bbeg, CHAR* bend) { CHAR* a = abeg; CHAR* b = bbeg; while (a *b) { return 1; } ++a; ++b; } if (a class const_string_facade {}; template class const_string_facade { DERIVED& derived() { return *static_cast(this); } const DERIVED& derived() const { return *static_cast(this); } public: typedef CHAR value_type; typedef CHAR* pointer; typedef CHAR& reference; typedef const CHAR& const_reference; typedef size_t size_type; typedef ptrdiff_t difference_type; static const size_type npos = -1; typedef CHAR* iterator; typedef const CHAR* const_iterator; typedef boost::reverse_iterator reverse_iterator; typedef boost::reverse_iterator const_reverse_iterator; iterator begin() { return derived().get_begin(); } iterator end() { return derived().get_end(); } const_iterator begin() const { return derived().get_begin(); } const_iterator end() const { return derived().get_end(); } reverse_iterator rbegin() { return reverse_iterator(derived().get_end()); } reverse_iterator rend() { return reverse_iterator(derived().get_begin()); } const_reverse_iterator rbegin() const { return const_reverse_iterator(derived().get_end()); } const_reverse_iterator rend() const { return const_reverse_iterator(derived().get_begin()); } size_type size() const { return end() - begin(); } size_type length() const { return end() - begin(); } size_type max_size() const { return end() - begin(); } // ??? size_type capacity() const { return end() - begin(); } // ??? bool empty() const { return end() == begin(); } reference operator[](size_type n) { return *(begin()+n); } const_reference operator[](size_type n) const { return *(begin()+n); } const CHAR* data() const { return begin(); } size_type copy(CHAR* buf, size_type n, size_type pos=0) const { // Is n allowed to be larger than size() ? return std::copy(begin()+pos, std::min(end(),begin()+pos+n), buf) - buf; } template size_type find(const STR& s, size_type pos=0) const { const_iterator i = std::search(begin()+pos, end(), s.begin(), s.end()); return (i==end()) ? npos : (i-begin()); } size_type find(const CHAR* s, size_type pos, size_type n) const { const_iterator i = std::search(begin()+pos, end(), s, s+n); return (i==end()) ? npos : (i-begin()); } size_type find(const CHAR* s, size_type pos=0) const { size_t len = strlen(s); return find(s,pos,len); } size_type find(CHAR c, size_type pos=0) const { const_iterator i = std::find(begin()+pos, end(), c); return (i==end()) ? npos : (i-begin()); } template size_type rfind(const STR& s, size_type pos=npos) const { const_reverse_iterator start = rend() - std::min(pos,size()); const_reverse_iterator i = std::search(start, rend(), s.rbegin(), s.rend()); return (i==rend()) ? npos : (rend()-i-s.size()); } size_type rfind(const CHAR* s, size_type pos, size_type n) const { const_reverse_iterator start = rend() - std::min(pos,size()); const_reverse_iterator i = std::search(start, rend(), const_reverse_iterator(s+n), const_reverse_iterator(s)); return (i==rend()) ? npos : (rend()-i-n); } size_type rfind(const CHAR* s, size_type pos=npos) const { size_t len = strlen(s); return rfind(s,pos,len); } size_type rfind(CHAR c, size_type pos=npos) const { const_reverse_iterator start = rend() - std::min(pos,size()); const_reverse_iterator i = std::find(start, rend(), c); return (i==rend()) ? npos : (rend()-i-1); } template size_type find_first_of(const STR& s, size_type pos=0) const { const_iterator i = std::find_if(begin()+pos, end(), boost::bind(&contains,s.begin(),s.end(),_1)); return (i==end()) ? npos : (i-begin()); } size_type find_first_of(const CHAR* s, size_type pos, size_type n) const { const_iterator i = std::find_if(begin()+pos, end(), boost::bind(&contains,s,s+n,_1)); return (i==end()) ? npos : (i-begin()); } size_type find_first_of(const CHAR* s, size_type pos=0) const { size_t len = strlen(s); return find_first_of(s,pos,len); } size_type find_first_of(CHAR c, size_type pos=0) const { return find(c,pos); } template size_type find_first_not_of(const STR& s, size_type pos=0) const { const_iterator i = std::find_if(begin()+pos, end(), boost::bind(¬_contains,s.begin(),s.end(),_1)); return (i==end()) ? npos : (i-begin()); } size_type find_first_not_of(const CHAR* s, size_type pos, size_type n) const { const_iterator i = std::find_if(begin()+pos, end(), boost::bind(¬_contains,s,s+n,_1)); return (i==end()) ? npos : (i-begin()); } size_type find_first_not_of(const CHAR* s, size_type pos=0) const { size_t len = strlen(s); return find_first_not_of(s,pos,len); } size_type find_first_not_of(CHAR c, size_type pos=0) const { return find_first_not_of(&c, pos, 1); // FIXME should use find_if } template size_type find_last_of(const STR& s, size_type pos=npos) const { const_reverse_iterator start = rend() - std::min(pos,size()); const_reverse_iterator i = std::find_if(start, rend(), boost::bind(&contains,s.begin(),s.end(),_1)); return (i==rend()) ? npos : (rend()-i-1); } size_type find_last_of(const CHAR* s, size_type pos, size_type n) const { const_reverse_iterator start = rend() - std::min(pos,size()); const_reverse_iterator i = std::find_if(start, rend(), boost::bind(&contains,s,s+n,_1)); return (i==rend()) ? npos : (rend()-i-1); } size_type find_last_of(const CHAR* s, size_type pos=npos) const { size_t len = strlen(s); return find_last_of(s,pos,len); } size_type find_last_of(CHAR c, size_type pos=npos) const { return rfind(c,pos); } template size_type find_last_not_of(const STR& s, size_type pos=npos) const { const_reverse_iterator start = rend() - std::min(pos,size()); const_reverse_iterator i = std::find_if(start, rend(), boost::bind(¬_contains,s.begin(),s.end(),_1)); return (i==rend()) ? npos : (rend()-i-1); } size_type find_last_not_of(const CHAR* s, size_type pos, size_type n) const { const_reverse_iterator start = rend() - std::min(pos,size()); const_reverse_iterator i = std::find_if(start, rend(), boost::bind(¬_contains,s,s+n,_1)); return (i==rend()) ? npos : (rend()-i-1); } size_type find_last_not_of(const CHAR* s, size_type pos=npos) const { size_t len = strlen(s); return find_last_not_of(s,pos,len); } size_type find_last_not_of(CHAR c, size_type pos=npos) const { return find_last_not_of(&c, pos, 1); // FIXME should use find_if } std::basic_string substr(size_type pos=0, size_type n=npos) const { return std::basic_string(begin()+pos,begin()+std::min(n,size())); } template int compare(const STR& s) const { return strcmp(begin(), end(), s.begin(), s.end()); } template int compare(size_type pos, size_type n, const STR& s) const { return strcmp(begin()+pos, begin()+pos+n, s.begin(), s.end()); } template int compare(size_type pos, size_type n, const STR& s, size_type pos1, size_type n1) const { return strcmp(begin()+pos, begin()+pos+n, s.begin()+pos1, s.begin()+pos1+n1); } int compare(const CHAR* s) const { return strcmp(begin(), end, s, s+strlen(s)); } int compare(size_type pos, size_type n, const CHAR* s, size_type len=npos) const { return strcmp(begin()+pos, begin()+pos+n, s, s+std::min(len,strlen(s))); // traits::length??? } }; #if 0 template class const_string_facade: public const_string_facade { public: const CHAR* c_str() const { return begin(); } }; #endif template inline bool operator==(const const_string_facade& s1, const const_string_facade& s2) { return s1.compare(s2) == 0; } template inline bool operator==(const CHAR* s1, const const_string_facade& s2) { return s2.compare(s1) == 0; } template inline bool operator==(const const_string_facade& s1, const CHAR* s2) { return s1.compare(s2) == 0; } template inline bool operator!=(const const_string_facade& s1, const const_string_facade& s2) { return s1.compare(s2) != 0; } template inline bool operator!=(const CHAR* s1, const const_string_facade& s2) { return s2.compare(s1) != 0; } template inline bool operator!=(const const_string_facade& s1, const CHAR* s2) { return s1.compare(s2) != 0; } template inline bool operator<(const const_string_facade& s1, const const_string_facade& s2) { return s1.compare(s2) < 0; } template inline bool operator<(const CHAR* s1, const const_string_facade& s2) { return s2.compare(s1) < 0; } template inline bool operator<(const const_string_facade& s1, const CHAR* s2) { return s1.compare(s2) < 0; } template inline std::basic_ostream& operator<<(std::basic_ostream& os, const const_string_facade& s) { std::ostream_iterator osi(os); copy(s.begin(),s.end(),osi); // something about os.width() ??? return os; } }; #endif