1 // This file is part of The New Aspell
2 // Copyright (C) 2001 by Kevin Atkinson under the GNU LGPL license
3 // version 2.0 or 2.1. You should have received a copy of the LGPL
4 // license along with this library if you did not you can find
5 // it at http://www.gnu.org/.
7 #ifndef ASPELL_STRING__HPP
8 #define ASPELL_STRING__HPP
15 #include "hash_fun.hpp"
16 #include "parm_string.hpp"
17 #include "mutable_string.hpp"
18 #include "ostream.hpp"
19 #include "istream.hpp"
22 // acommon::String is similar to std::string, but without many of the
23 // extra non-stl like methods. The string is guaranteed to be stored
24 // in a continues areas of memory but is not guaranteed to be null
25 // terminated. However, space is always allocated for the null
26 // characters. Thus, the c_str() method will never invalided any
27 // exiting pointers. The string is also null terminated when accesed
28 // via the str() and mstr() methods. In addition the method
29 // ensure_null_end() will null terminate the string. Once null
30 // terminated the string will remain as such until the length of the
36 template <typename Ret> class PosibErr;
38 class String : public OStream
41 typedef const char * const_iterator;
42 typedef char * iterator;
43 typedef size_t size_type;
46 // if begin_ != 0 than storage_end_ - begin_ > 1
51 void assign_only_nonnull(const char * b, unsigned size)
53 begin_ = (char *)malloc(size + 1);
54 memmove(begin_, b, size);
56 storage_end_ = end_ + 1;
64 void assign_only(const char * b)
66 if (b && *b) assign_only_nonnull(b, strlen(b));
69 void assign_only(const char * b, unsigned size)
71 if (b && size > 0) assign_only_nonnull(b, size);
74 void reserve_i(size_t s = 0);
76 void reserve(size_t s)
78 if (storage_end_ - begin_ >= (int)s + 1) return;
82 char * begin() {return begin_;}
83 char * end() {return end_;}
85 const char * begin() const {return begin_;}
86 const char * end() const {return end_;}
88 char * pbegin() {return begin_;}
89 char * pend() {return end_;}
91 const char * pbegin() const {return begin_;}
92 const char * pend() const {return end_;}
94 size_t size() const {return end_ - begin_;}
95 bool empty() const {return begin_ == end_;}
96 size_t max_size() const {return INT_MAX;}
97 size_t capacity() const {return storage_end_ ? storage_end_ - begin_ - 1 : 0;}
99 void ensure_null_end() const {
100 if (!begin_) const_cast<String *>(this)->reserve_i();
104 const char * c_str() const {
105 if (begin_) {ensure_null_end(); return begin_;}
108 const char * str() const {return c_str();}
111 if (!begin_) reserve_i();
116 char * data() {return begin_;}
117 const char * data() const {return begin_;}
119 char * data(int pos) {return begin_ + pos;}
120 char * data_end() {return end_;}
122 template <typename U>
124 return reinterpret_cast<U * >(begin_);
126 template <typename U>
128 return reinterpret_cast<U * >(begin_ + pos);
131 char & operator[] (size_t pos) {return begin_[pos];}
132 char operator[] (size_t pos) const {return begin_[pos];}
134 char & back() {return end_[-1];}
135 char back() const {return end_[-1];}
137 void clear() {end_ = begin_;}
143 String() : begin_(0), end_(0), storage_end_(0) {}
144 String(const char * s) {assign_only(s);}
145 String(const char * s, unsigned size) {assign_only(s, size);}
146 String(ParmStr s) {assign_only(s, s.size());}
147 String(MutableString s) {assign_only(s.str, s.size);}
148 String(const String & other) {assign_only(other.begin_, other.end_-other.begin_);}
154 void assign(const char * b, size_t size)
159 memmove(begin_, b, size);
160 end_ = begin_ + size;
163 void assign(const char * b)
165 if (b) assign(b, strlen(b));
167 String & operator= (const char * s) {
171 inline String & operator= (const PosibErr<const char *> & s);
172 String & operator= (ParmStr s) {
176 String & operator= (MutableString s) {
177 assign(s.str, s.size);
180 String & operator= (const String & s) {
181 assign(s.begin_, s.end_ - s.begin_);
184 /*inline*/ String & operator= (const PosibErr<String> & s);
190 String & append(const void * str, unsigned int sz)
192 reserve(size() + sz);
193 if (sz > 0) memcpy(end_, str, sz);
197 String & append(const void * d, const void * e)
199 append(d, (const char *)e - (const char *)d);
202 String & append(String & str, unsigned int sz)
204 append(str.begin_, sz);
207 String & append(const char * str)
209 if (!end_) reserve_i();
210 for (; *str && end_ != storage_end_ - 1; ++str, ++end_)
212 if (end_ == storage_end_ - 1) append(str, strlen(str));
215 String & append(char c)
223 String & operator+= (const char * s) {
227 String & operator+= (char c) {
231 String & operator+= (ParmStr s) {
238 String & operator+= (MutableString s) {
239 append(s.str, s.size);
242 String & operator+= (const String & s) {
243 append(s.begin_, s.end_ - s.begin_);
251 ~String() {if (begin_) free(begin_);}
253 void swap(String & other) {
254 std::swap(begin_, other.begin_);
255 std::swap(end_, other.end_);
256 std::swap(storage_end_, other.storage_end_);
263 int vprintf(const char * format, va_list ap);
269 void push_back(char c) {append(c);}
271 void pop_back(size_t p = 1) {end_ -= p;}
273 char * insert(size_t p, char c)
276 char * pos = begin_ + p;
277 size_t to_move = end_ - pos;
278 if (to_move) memmove(pos + 1, pos, to_move);
283 char * insert(char * pos, char c)
285 return insert(pos - begin_, c);
287 void insert(size_t p, const char * str, size_t sz)
289 reserve(size() + sz);
290 char * pos = begin_ + p;
291 size_t to_move = end_ - pos;
292 if (to_move) memmove(pos + sz, pos, to_move);
293 memcpy(pos, str, sz);
296 void insert(char * pos, const char * f, const char * l)
298 insert(pos - begin_, f, l - f);
301 char * erase(char * pos)
303 size_t to_move = end_ - pos - 1;
304 if (to_move) memmove(pos, pos + 1, to_move);
308 char * erase(char * f, char * l)
311 end_ = f < end_ ? f : end_;
314 memmove(f, f + sz, end_ - l);
319 void erase(size_t pos, size_t s)
321 erase(begin_ + pos, begin_ + pos + s);
324 //FIXME: Make this more efficent by rewriting the implemenation
325 // to work with raw memory rather than using vector<char>
326 template <typename Itr>
327 void replace(iterator start, iterator stop, Itr rstart, Itr rstop)
329 iterator i = erase(start,stop);
330 insert(i, rstart, rstop);
333 void replace(size_t pos, size_t n, const char * with, size_t s)
335 replace(begin_ + pos, begin_ + pos + n, with, with + s);
337 void resize(size_t n)
342 void resize(size_t n, char c)
344 size_t old_size = size();
347 int diff = n - old_size;
348 if (diff > 0) memset(begin_ + old_size, c, diff);
356 bool prefix(ParmStr str, size_t offset = 0) const
358 if (str.size() > size() - offset) return false;
359 return memcmp(begin_ + offset, str.str(), str.size()) == 0;
361 bool suffix(ParmStr str) const
363 if (str.size() > size()) return false;
364 return memcmp(end_ - str.size(), str.str(), str.size()) == 0;
367 // FIXME: Eventually remove
368 static const size_t npos = INT_MAX;
369 size_t find(char c, size_t pos = 0) const {
370 char * res = (char *)memchr(begin_ + pos, c, size() - pos);
371 if (res == 0) return npos;
372 else return res - begin_;
374 size_t rfind(char c) const {
375 for (int i = size() - 1; i >= 0; --i) {
376 if (begin_[i] == c) return i;
380 String substr(size_t pos = 0, size_t n = npos) const
383 return String(begin_ + pos, size() - pos);
385 return String(begin_ + pos, n);
389 unsigned short & at16(unsigned int pos)
390 {return reinterpret_cast<unsigned short &>(operator[](pos));}
391 unsigned int & at32(unsigned int pos)
392 {return reinterpret_cast<unsigned int &>(operator[](pos));}
394 void write (char c) {append(c);}
395 void write (ParmStr str) {operator+=(str);}
396 void write (const void * str, unsigned int sz) {append(str,sz);}
399 String & operator << (ParmStr str) {
404 String & operator << (char c) {
410 inline String operator+ (ParmStr lhs, ParmStr rhs)
413 tmp.reserve(lhs.size() + rhs.size());
419 inline bool operator== (const String & x, const String & y)
421 if (x.size() != y.size()) return false;
422 if (x.size() == 0) return true;
423 return memcmp(x.data(), y.data(), x.size()) == 0;
425 inline bool operator== (const String & x, const char * y)
427 return strcmp(x.c_str(), y) == 0;
429 inline bool operator== (const char * x, const String & y)
431 return strcmp(x, y.c_str()) == 0;
433 inline bool operator== (const String & x, ParmStr y)
435 if (y == 0) return x.size() == 0;
436 return strcmp(x.c_str(), y) == 0;
438 inline bool operator== (ParmStr x, const String & y)
440 if (x == 0) return y.size() == 0;
441 return strcmp(x, y.c_str()) == 0;
444 inline bool operator!= (const String & x, const String & y)
448 inline bool operator!= (const String & x, const char * y)
450 return strcmp(x.c_str(), y) != 0;
452 inline bool operator!= (const char * x, const String & y)
454 return strcmp(x, y.c_str()) != 0;
456 inline bool operator!= (const String & x, ParmStr y)
460 inline bool operator!= (ParmStr x, const String & y)
465 inline ParmString::ParmString(const String & s) : str_(s.c_str()), size_(s.size()) {}
467 class StringIStream : public IStream {
471 StringIStream(ParmStr s, char d = ';')
472 : IStream(d), in_str(s) {}
473 bool append_line(String & str, char c);
474 bool read(void * data, unsigned int size);
477 template <> struct hash<String> : public HashString<String> {};
479 inline bool IStream::getline(String & str, char c)
482 return append_line(str,c);
485 inline bool IStream::getline(String & str)
488 return append_line(str,delem);
495 template<> inline void swap(acommon::String & x, acommon::String & y) {return x.swap(y);}