356 lines
13 KiB
C++
356 lines
13 KiB
C++
// 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 <algorithm>
|
|
#include <iostream>
|
|
#include <boost/iterator/reverse_iterator.hpp>
|
|
#include <boost/bind.hpp>
|
|
|
|
#include <string.h>
|
|
|
|
// 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 <typename CHAR>
|
|
inline size_t strlen(const CHAR* s) { return std::find(s,s-1,0) - s; }
|
|
|
|
template<>
|
|
inline size_t strlen<char>(const char* s) { return ::strlen(s); }
|
|
|
|
template<>
|
|
inline size_t strlen<unsigned char>(const unsigned char* s) { return ::strlen(reinterpret_cast<const char*>(s)); }
|
|
|
|
template<>
|
|
inline size_t strlen<signed char>(const signed char* s) { return ::strlen(reinterpret_cast<const char*>(s)); }
|
|
|
|
template <typename ITER, typename CHAR>
|
|
inline bool contains(ITER b, ITER e, CHAR c) { return std::find(b,e,c)!=e; }
|
|
|
|
template <typename ITER, typename CHAR>
|
|
inline bool not_contains(ITER b, ITER e, CHAR c) { return std::find(b,e,c)==e; }
|
|
|
|
template <typename CHAR>
|
|
inline int strcmp(CHAR* abeg, CHAR* aend, CHAR* bbeg, CHAR* bend) {
|
|
CHAR* a = abeg;
|
|
CHAR* b = bbeg;
|
|
while (a<aend && b<bend) {
|
|
if (*a < *b) {
|
|
return -1;
|
|
}
|
|
if (*a > *b) {
|
|
return 1;
|
|
}
|
|
++a;
|
|
++b;
|
|
}
|
|
if (a<aend) {
|
|
return 1;
|
|
}
|
|
if (b<bend) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template <typename DERIVED, typename CHAR, bool null_terminated>
|
|
class const_string_facade {};
|
|
|
|
|
|
template <typename DERIVED, typename CHAR>
|
|
class const_string_facade<DERIVED, CHAR, false> {
|
|
|
|
DERIVED& derived() { return *static_cast<DERIVED*>(this); }
|
|
const DERIVED& derived() const { return *static_cast<const DERIVED*>(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<iterator> reverse_iterator;
|
|
typedef boost::reverse_iterator<const_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 <typename STR>
|
|
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<CHAR>(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 <typename STR>
|
|
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<CHAR>(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 <typename STR>
|
|
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<STR::const_iterator,CHAR>,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<const CHAR*,CHAR>,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<CHAR>(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 <typename STR>
|
|
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<STR::const_iterator,CHAR>,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<const CHAR*,CHAR>,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<CHAR>(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 <typename STR>
|
|
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<STR::const_iterator,CHAR>,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<const CHAR*,CHAR>,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<CHAR>(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 <typename STR>
|
|
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<STR::const_iterator,CHAR>,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<const CHAR*,CHAR>,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<CHAR>(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<CHAR> substr(size_type pos=0, size_type n=npos) const {
|
|
return std::basic_string<CHAR>(begin()+pos,begin()+std::min(n,size()));
|
|
}
|
|
|
|
template <typename STR>
|
|
int compare(const STR& s) const {
|
|
return strcmp(begin(), end(), s.begin(), s.end());
|
|
}
|
|
template <typename STR>
|
|
int compare(size_type pos, size_type n, const STR& s) const {
|
|
return strcmp(begin()+pos, begin()+pos+n, s.begin(), s.end());
|
|
}
|
|
template <typename STR>
|
|
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<CHAR>(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<CHAR>(s))); // traits::length???
|
|
}
|
|
|
|
};
|
|
|
|
|
|
#if 0
|
|
template <typename CHAR>
|
|
class const_string_facade<CHAR,true>: public const_string_facade<CHAR,false> {
|
|
public:
|
|
const CHAR* c_str() const { return begin(); }
|
|
};
|
|
#endif
|
|
|
|
|
|
|
|
template <typename CHAR, typename DERIVED1, bool null_terminated_1, typename DERIVED2, bool null_terminated_2>
|
|
inline bool operator==(const const_string_facade<DERIVED1,CHAR,null_terminated_1>& s1,
|
|
const const_string_facade<DERIVED2,CHAR,null_terminated_2>& s2) {
|
|
return s1.compare(s2) == 0;
|
|
}
|
|
|
|
template <typename CHAR, typename DERIVED2, bool null_terminated_2>
|
|
inline bool operator==(const CHAR* s1,
|
|
const const_string_facade<DERIVED2,CHAR,null_terminated_2>& s2) {
|
|
return s2.compare(s1) == 0;
|
|
}
|
|
|
|
template <typename CHAR, typename DERIVED1, bool null_terminated_1>
|
|
inline bool operator==(const const_string_facade<DERIVED1,CHAR,null_terminated_1>& s1,
|
|
const CHAR* s2) {
|
|
return s1.compare(s2) == 0;
|
|
}
|
|
|
|
|
|
template <typename CHAR, typename DERIVED1, bool null_terminated_1, typename DERIVED2, bool null_terminated_2>
|
|
inline bool operator!=(const const_string_facade<DERIVED1,CHAR,null_terminated_1>& s1,
|
|
const const_string_facade<DERIVED2,CHAR,null_terminated_2>& s2) {
|
|
return s1.compare(s2) != 0;
|
|
}
|
|
|
|
template <typename CHAR, typename DERIVED2, bool null_terminated_2>
|
|
inline bool operator!=(const CHAR* s1,
|
|
const const_string_facade<DERIVED2,CHAR,null_terminated_2>& s2) {
|
|
return s2.compare(s1) != 0;
|
|
}
|
|
|
|
template <typename CHAR, typename DERIVED1, bool null_terminated_1>
|
|
inline bool operator!=(const const_string_facade<DERIVED1,CHAR,null_terminated_1>& s1,
|
|
const CHAR* s2) {
|
|
return s1.compare(s2) != 0;
|
|
}
|
|
|
|
|
|
template <typename CHAR, typename DERIVED1, bool null_terminated_1, typename DERIVED2, bool null_terminated_2>
|
|
inline bool operator<(const const_string_facade<DERIVED1,CHAR,null_terminated_1>& s1,
|
|
const const_string_facade<DERIVED2,CHAR,null_terminated_2>& s2) {
|
|
return s1.compare(s2) < 0;
|
|
}
|
|
|
|
template <typename CHAR, typename DERIVED2, bool null_terminated_2>
|
|
inline bool operator<(const CHAR* s1,
|
|
const const_string_facade<DERIVED2,CHAR,null_terminated_2>& s2) {
|
|
return s2.compare(s1) < 0;
|
|
}
|
|
|
|
template <typename CHAR, typename DERIVED1, bool null_terminated_1>
|
|
inline bool operator<(const const_string_facade<DERIVED1,CHAR,null_terminated_1>& s1,
|
|
const CHAR* s2) {
|
|
return s1.compare(s2) < 0;
|
|
}
|
|
|
|
|
|
template <typename CHAR, typename TRAITS, typename DERIVED, bool null_terminated>
|
|
inline std::basic_ostream<CHAR, TRAITS>& operator<<(std::basic_ostream<CHAR, TRAITS>& os,
|
|
const const_string_facade<DERIVED, CHAR, null_terminated>& s) {
|
|
std::ostream_iterator<CHAR> osi(os);
|
|
copy(s.begin(),s.end(),osi); // something about os.width() ???
|
|
return os;
|
|
}
|
|
|
|
|
|
};
|
|
|
|
#endif
|
|
|