9e7f1d5d4ad6bafdd1f9f64827f5ad76e514a8ab
[platform/upstream/aspell.git] / common / string.hpp
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/.
6
7 #ifndef ASPELL_STRING__HPP
8 #define ASPELL_STRING__HPP
9
10 #include <string.h>
11 #include <stdlib.h>
12
13 #include <algorithm>
14
15 #include "hash_fun.hpp"
16 #include "parm_string.hpp"
17 #include "mutable_string.hpp"
18 #include "ostream.hpp"
19 #include "istream.hpp"
20
21 //
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
31 // string changes.
32 //
33
34 namespace acommon {
35
36   template <typename Ret> class PosibErr;
37   
38   class String : public OStream
39   {
40   public:
41     typedef const char * const_iterator;
42     typedef char *       iterator;
43     typedef size_t       size_type;
44
45   private:
46     // if begin_ != 0 than storage_end_ - begin_ > 1
47     char * begin_;
48     char * end_;
49     char * storage_end_;
50
51     void assign_only_nonnull(const char * b, unsigned size)
52     {
53       begin_ = (char *)malloc(size + 1);
54       memmove(begin_, b, size);
55       end_   = begin_ + size;
56       storage_end_ = end_ + 1;
57     }
58     void zero() 
59     {
60       begin_ = 0;
61       end_ = 0;
62       storage_end_ = 0;
63     }
64     void assign_only(const char * b)
65     {
66       if (b && *b) assign_only_nonnull(b, strlen(b));
67       else zero();
68     }
69     void assign_only(const char * b, unsigned size) 
70     {
71       if (b && size > 0) assign_only_nonnull(b, size);
72       else zero();
73     }
74     void reserve_i(size_t s = 0);
75   public:
76     void reserve(size_t s) 
77     {
78       if (storage_end_ - begin_ >= (int)s + 1) return;
79       reserve_i(s);
80     }
81
82     char * begin() {return begin_;}
83     char * end() {return end_;}
84
85     const char * begin() const {return begin_;}
86     const char * end()   const {return end_;}
87
88     char * pbegin() {return begin_;}
89     char * pend() {return end_;}
90
91     const char * pbegin() const {return begin_;}
92     const char * pend()   const {return end_;}
93
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;}
98
99     void ensure_null_end() const {
100       if (!begin_) const_cast<String *>(this)->reserve_i();
101       *end_ = '\0';
102     }
103
104     const char * c_str() const {
105       if (begin_) {ensure_null_end(); return begin_;}
106       else return "";
107     }
108     const char * str() const {return c_str();}
109     char * mstr() 
110     {
111       if (!begin_) reserve_i();
112       ensure_null_end();
113       return begin_;
114     }
115
116     char * data() {return begin_;}
117     const char * data() const {return begin_;}
118
119     char * data(int pos) {return begin_ + pos;}
120     char * data_end() {return end_;}
121
122     template <typename U>
123     U * datap() { 
124       return reinterpret_cast<U * >(begin_);
125     }
126     template <typename U>
127     U * datap(int pos) {
128       return reinterpret_cast<U * >(begin_ + pos);
129     }
130
131     char & operator[] (size_t pos) {return begin_[pos];}
132     char operator[] (size_t pos) const {return begin_[pos];}
133
134     char & back() {return end_[-1];}
135     char back() const {return end_[-1];}
136
137     void clear() {end_ = begin_;}
138
139     //
140     // constructors
141     //
142
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_);}
149
150     //
151     // assign
152     //
153
154     void assign(const char * b, size_t size)
155     {
156       clear();
157       if (size != 0) {
158         reserve(size);
159         memmove(begin_, b, size);
160         end_   = begin_ + size;
161       } 
162     }
163     void assign(const char * b) 
164     {
165       if (b) assign(b, strlen(b));
166     }
167     String & operator= (const char * s) {
168       assign(s);
169       return *this;
170     }
171     inline String & operator= (const PosibErr<const char *> & s);
172     String & operator= (ParmStr s) {
173       assign(s, s.size());
174       return *this;
175     }
176     String & operator= (MutableString s) {
177       assign(s.str, s.size);
178       return *this;
179     }
180     String & operator= (const String & s) {
181       assign(s.begin_, s.end_ - s.begin_);
182       return *this;
183     }
184     /*inline*/ String & operator= (const PosibErr<String> & s);
185
186     //
187     // append
188     //
189
190     String & append(const void * str, unsigned int sz)
191     {
192       reserve(size() + sz);
193       if (sz > 0) memcpy(end_, str, sz);
194       end_ += sz;
195       return *this;
196     }
197     String & append(const void * d, const void * e)
198     {
199       append(d, (const char *)e - (const char *)d);
200       return *this;
201     }
202     String & append(String & str, unsigned int sz)
203     {
204       append(str.begin_, sz);
205       return *this;
206     }
207     String & append(const char * str)
208     {
209       if (!end_) reserve_i();
210       for (; *str && end_ != storage_end_ - 1; ++str, ++end_)
211         *end_ = *str;
212       if (end_ == storage_end_ - 1) append(str, strlen(str));
213       return *this;
214     }
215     String & append(char c)
216     {
217       reserve(size() + 1);
218       *end_ = c;
219       ++end_;
220       return *this;
221     }
222
223     String & operator+= (const char * s) {
224       append(s);
225       return *this;
226     }
227     String & operator+= (char c) {
228       append(c);
229       return *this;
230     }
231     String & operator+= (ParmStr s) {
232       if (s.have_size())
233         append(s, s.size());
234       else
235         append(s);
236       return *this;
237     }
238     String & operator+= (MutableString s) {
239       append(s.str, s.size);
240       return *this;
241     }
242     String & operator+= (const String & s) {
243       append(s.begin_, s.end_ - s.begin_);
244       return *this;
245     }
246
247     //
248     //
249     //
250
251     ~String() {if (begin_) free(begin_);}
252
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_);
257     }
258
259     //
260     // 
261     //
262
263     int vprintf(const char * format, va_list ap);
264
265     //
266     //
267     //
268
269     void push_back(char c) {append(c);}
270
271     void pop_back(size_t p = 1) {end_ -= p;}
272
273     char * insert(size_t p, char c)
274     {
275       reserve(size() + 1);
276       char * pos = begin_ + p;
277       size_t to_move = end_ - pos;
278       if (to_move) memmove(pos + 1, pos, to_move);
279       *pos = c;
280       ++end_;
281       return pos;
282     }
283     char * insert(char * pos, char c) 
284     {
285       return insert(pos - begin_, c);
286     }
287     void insert(size_t p, const char * str, size_t sz)
288     {
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);
294       end_ += sz;
295     }
296     void insert(char * pos, const char * f, const char * l) 
297     {
298       insert(pos - begin_, f, l - f);
299     }
300
301     char * erase(char * pos)
302     {
303       size_t to_move = end_ - pos - 1;
304       if (to_move) memmove(pos, pos + 1, to_move);
305       --end_;
306       return pos;
307     }
308     char * erase(char * f, char * l)
309     {
310       if (l >= end_) {
311         end_ = f < end_ ? f : end_;
312       } else {
313         size_t sz = l - f;
314         memmove(f, f + sz, end_ - l);
315         end_ -= sz;
316       }
317       return f;
318     }
319     void erase(size_t pos, size_t s)
320     {
321       erase(begin_ + pos, begin_ + pos + s);
322     }
323
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) 
328     {
329       iterator i = erase(start,stop);
330       insert(i, rstart, rstop);
331     }
332
333     void replace(size_t pos, size_t n, const char * with, size_t s)
334     {
335       replace(begin_ + pos, begin_ + pos + n, with, with + s);
336     }
337     void resize(size_t n)
338     {
339       reserve(n);
340       end_ = begin_ + n;
341     }
342     void resize(size_t n, char c)
343     {
344       size_t old_size = size();
345       reserve(n);
346       end_ = begin_ + n;
347       int diff = n - old_size;
348       if (diff > 0) memset(begin_ + old_size, c, diff);
349     }
350     int alloc(int s) {
351       int pos = size();
352       resize(pos + s);
353       return pos;
354     }
355
356     bool prefix(ParmStr str, size_t offset = 0) const
357     {
358       if (str.size() > size() - offset) return false;
359       return memcmp(begin_ + offset, str.str(), str.size()) == 0;
360     };
361     bool suffix(ParmStr str) const
362     {
363       if (str.size() > size()) return false;
364       return memcmp(end_ - str.size(), str.str(), str.size()) == 0;
365     }
366
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_;
373     }
374     size_t rfind(char c) const {
375       for (int i = size() - 1; i >= 0; --i) {
376         if (begin_[i] == c) return i;
377       }
378       return npos;
379     }
380     String substr(size_t pos = 0, size_t n = npos) const
381     {
382       if (n == npos)
383         return String(begin_ + pos, size() - pos);
384       else
385         return String(begin_ + pos, n);
386     }
387     // END FIXME
388
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));}
393
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);}
397
398
399     String & operator << (ParmStr str) {
400       append(str);
401       return *this;
402     }
403
404     String & operator << (char c) {
405       append(c);
406       return *this;
407     }
408   };
409
410   inline String operator+ (ParmStr lhs, ParmStr rhs)
411   {
412     String tmp;
413     tmp.reserve(lhs.size() + rhs.size());
414     tmp += lhs;
415     tmp += rhs;
416     return tmp;
417   }
418
419   inline bool operator== (const String & x, const String & y)
420   {
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;
424   }
425   inline bool operator== (const String & x, const char * y)
426   {
427     return strcmp(x.c_str(), y) == 0;
428   }
429   inline bool operator== (const char * x, const String & y)
430   {
431     return strcmp(x, y.c_str()) == 0;
432   }
433   inline bool operator== (const String & x, ParmStr y)
434   {
435     if (y == 0) return x.size() == 0;
436     return strcmp(x.c_str(), y) == 0;
437   }
438   inline bool operator== (ParmStr x, const String & y)
439   {
440     if (x == 0) return y.size() == 0;
441     return strcmp(x, y.c_str()) == 0;
442   }
443
444   inline bool operator!= (const String & x, const String & y)
445   {
446     return !(x == y);
447   }
448   inline bool operator!= (const String & x, const char * y)
449   {
450     return strcmp(x.c_str(), y) != 0;
451   }
452   inline bool operator!= (const char * x, const String & y)
453   {
454     return strcmp(x, y.c_str()) != 0;
455   }
456   inline bool operator!= (const String & x, ParmStr y)
457   {
458     return !(x == y);
459   }
460   inline bool operator!= (ParmStr x, const String & y)
461   {
462     return !(x == y);
463   }
464
465   inline ParmString::ParmString(const String & s) : str_(s.c_str()), size_(s.size()) {}
466
467   class StringIStream : public IStream {
468     const char * in_str;
469     char         delem;
470   public:
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);
475   };
476
477   template <> struct hash<String> : public HashString<String> {};
478
479   inline bool IStream::getline(String & str, char c) 
480   {
481     str.clear(); 
482     return append_line(str,c);
483   }
484
485   inline bool IStream::getline(String & str) 
486   {
487     str.clear(); 
488     return append_line(str,delem);
489   }
490
491 }
492
493 namespace std
494 {
495   template<> inline void swap(acommon::String & x, acommon::String & y) {return x.swap(y);}
496 }
497
498 #endif