]> git.lyx.org Git - lyx.git/blob - src/support/lyxstring.h
hopefully solve some of the lyxstring problems.
[lyx.git] / src / support / lyxstring.h
1 // -*- C++ -*-
2 /* This file is part of
3  * ======================================================
4  * 
5  *           LyX, The Document Processor
6  *       
7  *          Copyright (C) 1995 Matthias Ettrich
8  *          Copyright (C) 1995-1999 The LyX Team.
9  *
10  *======================================================*/
11
12 // This one is heavily based on the string class in The C++
13 // Programming Language by Bjarne Stroustrup
14
15 #ifndef LYXSTRING_H
16 #define LYXSTRING_H 
17
18 #ifdef __GNUG__
19 #pragma interface
20 #endif
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h> // needed at least for compilers that do not
24 #endif              // understand `explicit' (JMarc)
25
26 #if 0
27 #include <iterator>
28 #endif
29
30 #include <cstring>
31 #include "LAssert.h"
32 /** A string class for LyX
33   
34   This is a permanent String class. It is modeled closely after the C++ STL
35   string class. In comparison with STL string LString lack support for
36   reverse iterators and allocators, in all other senses it is written to be
37   a drop in replacement for STL string (or as a transition tool). So
38   documentation for STL string should be valid for LString too.
39
40   Notes for usage:
41
42   When you declare an LString, it is initially empty. There is no need to
43   do things like #LString a= "";#, especially not in constructors.
44
45   If you want to use a default empty LString as a parameter, use
46   
47         #void foo(LString par = LString());     // Correct#
48   
49   rather than
50
51         #void foo(LString par = "");    // WRONG!#
52         #void foo(LString par = 0);     // WRONG!#
53
54   (The last one is only wrong because some compilers can't handle it.)
55
56   Methods that take an index as parameter all follow this rule: Valid indexes
57   go from 0 to length()-1.
58   \begin{tabular}{rl}
59   Correct: & #foo.substring(0, length()-1);# \\
60   Wrong:   & #bar.substring(0, length());#
61   \end{tabular}
62   
63   It is important that you declare LStrings as const if possible, because
64   some methods are much more efficient in const versions.
65   
66   If you want to check whether a string is empty, do
67
68         #if (foo.empty()) something right#
69
70   rather than something along the lines of
71
72         #if (!foo) completely wrong#
73
74 When you want to copy an LString, just do
75   
76         #LString a, b = "String";#
77         #a = b; // That's it!#
78
79   not something like
80   
81         #LString a, b = "String";#
82         #a = b.copy(); // This leaks.#
83   
84   The class automatically handles deep copying when required.
85 */
86 class lyxstring {
87 public:
88         /**@name Typedefs */
89         //@{
90         
91         ///
92         typedef char value_type;
93
94         ///
95         typedef value_type * pointer;
96
97         ///
98         typedef value_type & reference;
99
100         ///
101         typedef value_type const & const_reference;
102
103         ///
104         typedef size_t size_type;
105
106         ///
107         typedef int difference_type;
108
109         ///
110         typedef value_type * iterator;
111         ///
112         typedef const value_type * const_iterator;
113 #if 0
114         ///
115         typedef reverse_iterator<iterator, value_type, reference>
116 reverse_iterator;
117         ///
118         typedef reverse_iterator<const_iterator, const value_type,
119 const_reference> const_reverse_iterator;
120
121 #endif
122         //@}
123
124         ///
125         iterator begin();
126         ///
127         const_iterator begin() const;
128         ///
129         iterator end();
130         ///
131         const_iterator end() const;
132 #if 0
133         ///
134         reverse_iterator rbegin();
135         ///
136         const_reverse_iterator rbegin() const;
137         ///
138         reverse_iterator rend();
139         ///
140         const_reverse_iterator rend() const;
141 #endif
142         /**@name Constructors and Deconstructors. lyxstring has the same
143           constructors as STL, except the one using iterators, one other
144           difference is that lyxstring, do not allow the optional allocator
145           parameter. */
146         //@{
147         
148         /// "all characters" marker
149         static const size_type npos;
150
151         /// #lyxstring x;# 
152         inline lyxstring();
153         
154         /// #lyxstring x(lyxstring ...)# 
155         lyxstring(lyxstring const &, size_type pos = 0, size_type n = npos);
156         
157         /// #lyxstring x("abc", 2) -> "ab"#
158         lyxstring(value_type const *, size_type n);
159         
160         /// #lyxstring x("abc")#
161         lyxstring(value_type const *);
162         
163         /// lyxstring(5, 'n') -> "nnnnn"
164         lyxstring(size_type n, value_type c);
165
166         ///
167         lyxstring(iterator first, iterator last);
168         
169         ///
170         ~lyxstring() { if (--rep->ref == 0) delete rep; }
171
172         //@}
173
174         
175         /**@name Size and Capacity */
176         //@{
177         
178         /// number of characters
179         size_type size() const; // { return rep->sz; }
180
181         /// largest possible string
182         size_type max_size() const { return npos -1; }
183
184         ///
185         size_type length() const { return size(); }
186
187         ///
188         bool empty() const { return size() == 0; }
189
190         ///
191         void resize(size_type n, value_type c);
192
193         ///
194         void resize(size_type n) { resize(n, ' '); }
195
196         /// size of the memory (in number of elements) allocated.
197         size_type capacity() const;
198
199         ///
200         void reserve(size_type res_arg = 0);
201         
202         //@}
203
204
205         /**@name Assignment */
206         //@{
207
208         ///
209         lyxstring & operator=(lyxstring const &);
210         
211         ///
212         lyxstring & operator=(value_type const *);
213         
214         ///
215         lyxstring & operator=(value_type);
216
217         ///
218         lyxstring & assign(lyxstring const &);
219         
220         ///
221         lyxstring & assign(lyxstring const &, size_type pos, size_type n);
222         
223         ///
224         lyxstring & assign(value_type const * p, size_type n);
225         
226         ///
227         lyxstring & assign(value_type const * p);
228         
229         ///
230         lyxstring & assign(size_type n, value_type c);
231
232         ///
233         lyxstring & assign(iterator first, iterator last);
234         
235         //@}
236
237         /**@name Element Access. Since lyxstring does not use exceptions,
238           an abort is called on out-of-range access to at(). */
239         
240         /// unchecked access
241         const_reference operator[](size_type) const;
242         
243         /// unchecked access
244         reference operator[](size_type);
245         
246         /// checked access
247         const_reference at(size_type) const;
248         
249         /// checked access
250         reference at(size_type);
251
252         //@}
253
254         
255         /**@name Insert */
256         //@{
257         
258         // add characters after (*this)[length()-1]:
259         
260         ///
261         lyxstring & operator+=(lyxstring const &);
262         
263         ///
264         lyxstring & operator+=(value_type const *);
265         
266         ///
267         inline lyxstring & operator+=(value_type);
268
269         ///
270         void push_back(value_type);
271
272         ///
273         lyxstring & append(lyxstring const &);
274
275         ///
276         lyxstring & append(lyxstring const &, size_type pos, size_type n);
277
278         ///
279         lyxstring & append(value_type const *, size_type n);
280
281         ///
282         lyxstring & append(value_type const *);
283
284         ///
285         lyxstring & append(size_type n, value_type);
286
287         ///
288         lyxstring & append(iterator first, iterator last);
289         
290         // insert characters before (*this)[pos]:
291
292         ///
293         lyxstring & insert(size_type pos, lyxstring const &);
294         
295         ///
296         lyxstring & insert(size_type pos, lyxstring const &,
297                         size_type pos2, size_type n);
298         
299         ///
300         lyxstring & insert(size_type pos, value_type const * p,
301                          size_type n);
302
303         ///
304         lyxstring & insert(size_type pos, value_type const * p);
305
306         ///
307         lyxstring & insert(size_type pos, size_type n, value_type c);
308
309         // insert characters before p
310
311         ///
312         iterator insert(iterator p, value_type c);
313
314         ///
315         void insert(iterator p, size_type n , value_type c);
316
317         ///
318         void insert(iterator p, iterator first, iterator last);
319         
320         //@}
321
322         /**@name Find */
323         //@{
324
325         ///
326         size_type find(lyxstring const &, size_type i = 0) const;
327         
328         ///
329         size_type find(value_type const * p,
330                          size_type i, size_type n) const;
331         
332         ///
333         size_type find(value_type const * p, size_type i = 0) const;
334         
335         ///
336         size_type find(value_type c, size_type i = 0) const;
337
338         ///
339         size_type rfind(lyxstring const &, size_type i = npos) const;
340         
341         ///
342         size_type rfind(value_type const * p, size_type i, size_type n) const;
343         
344         ///
345         size_type rfind(value_type const * p, size_type i = npos) const;
346         
347         ///
348         size_type rfind(value_type c, size_type i = npos) const;
349
350         ///
351         size_type find_first_of(lyxstring const &, size_type i = 0) const;
352         
353         ///
354         size_type find_first_of(value_type const * p, size_type i, size_type n) const;
355         
356         ///
357         size_type find_first_of(value_type const * p, size_type i = 0) const;
358         
359         ///
360         size_type find_first_of(value_type c, size_type i = 0) const;
361
362         ///
363         size_type find_last_of(lyxstring const &, size_type i = npos) const;
364         
365         ///
366         size_type find_last_of(value_type const * p, size_type i, size_type n) const;
367         
368         ///
369         size_type find_last_of(value_type const * p, size_type i = npos) const;
370         
371         ///
372         size_type find_last_of(value_type c, size_type i = npos) const;
373
374         ///
375         size_type find_first_not_of(lyxstring const &, size_type i = 0) const;
376         
377         ///
378         size_type find_first_not_of(value_type const * p, size_type i,
379                                     size_type n) const;
380         
381         ///
382         size_type find_first_not_of(value_type const * p, size_type i = 0) const;
383         
384         ///
385         size_type find_first_not_of(value_type c, size_type i = 0) const;
386
387         ///
388         size_type find_last_not_of(lyxstring const &, size_type i = npos) const;
389         
390         ///
391         size_type find_last_not_of(value_type const * p, size_type i,
392                                    size_type n) const;
393         
394         ///
395         size_type find_last_not_of(value_type const * p, size_type i = npos) const;
396         
397         ///
398         size_type find_last_not_of(value_type c, size_type i = npos) const;
399
400         //*}
401
402         
403         /**@name Replace */
404         //@{
405
406         // replace [(*this)[i], (*this)[i+n]] with other characters:
407
408         ///
409         lyxstring & replace(size_type i,size_type n, lyxstring const & str);
410
411         ///
412         lyxstring & replace(size_type i,size_type n, lyxstring const & s,
413                           size_type i2, size_type n2);
414
415         ///
416         lyxstring & replace(size_type i,size_type n, value_type const * p,
417                           size_type n2);
418
419         ///
420         lyxstring & replace(size_type i,size_type n, value_type const * p);
421
422         ///
423         lyxstring & replace(size_type i, size_type n, size_type n2, value_type c);
424
425         ///
426         lyxstring & replace(iterator i, iterator i2, const lyxstring & str);
427
428         ///
429         lyxstring & replace(iterator i, iterator i2,
430                           value_type const * p, size_type n);
431
432         ///
433         lyxstring & replace(iterator i, iterator i2, value_type const * p);
434
435         ///
436         lyxstring & replace(iterator i, iterator i2, size_type n , value_type c);
437         
438         ///
439         lyxstring & replace(iterator i, iterator i2, iterator j, iterator j2);
440
441         /// Erase n chars from position i.
442         lyxstring & erase(size_type i = 0, size_type n = npos);
443
444         ///
445         lyxstring & clear() {
446                 return erase(0, npos);
447         }
448
449         ///
450         iterator erase(iterator i);
451
452         ///
453         iterator erase(iterator first, iterator last);
454
455         //@}
456
457         
458         /**@name Conversion to C-style Strings */
459         //@{
460         
461         /// 
462         value_type const * c_str() const;
463
464         /** Note that this is STL compilant, so you can not assume
465           that the returned array has a trailing '\0'. */
466         value_type const * data() const;
467
468         /** This one returns a verbatim copy. Not the trailing '\0'
469           The caller must provide a buffer with engough room.
470           */
471         size_type copy(value_type * buf, size_type len, size_type pos = 0) const;
472
473         //@}
474
475         
476         /**@name Comparisons. Combined > and == */
477         //@{
478         
479         ///
480         int compare(lyxstring const & str) const; 
481
482         ///
483         int compare(value_type const * p) const;
484
485         ///
486         int compare(size_type pos, size_type n, lyxstring const & str) const;
487
488         ///
489         int compare(size_type pos, size_type n, lyxstring const & str,
490                     size_type pos2, size_type n2) const;
491
492         ///
493         int compare(size_type pos, size_type n, value_type const * p,
494                     size_type n2 = npos) const;
495         
496         //@}
497
498         
499         
500         /**@name Substrings */
501         //@{
502
503         ///
504         lyxstring substr(size_type i = 0, size_type n = npos) const;
505         
506         //@}
507
508 private:
509         ///
510         lyxstring & operator+(int);
511         ///
512         lyxstring & operator=(int);
513         ///
514         lyxstring & operator+=(int);
515         
516         /// A string representation
517         struct Srep {
518                 ///
519                 static lyxstring::size_type const xtra = 
520                                         static_cast<lyxstring::size_type>(8);
521                 /// size
522                 lyxstring::size_type sz;
523                 /// Reference count
524                 unsigned short ref;
525                 /// The total amount of data reserved for this representaion
526                 lyxstring::size_type res;
527                 /// Data. At least 1 char for trailing null.
528                 lyxstring::value_type * s;
529
530                 ///
531                 Srep(lyxstring::size_type nsz, const lyxstring::value_type * p);
532                 ///
533                 Srep(lyxstring::size_type nsz, lyxstring::value_type ch);
534                 ///
535                 ~Srep() { delete[] s; }
536                 ///
537                 Srep * get_own_copy()
538                 {
539                         if (ref == 1) return this;
540                         ref--;
541                         return new Srep(sz, s);
542                 }
543                 
544                 ///
545                 void assign(lyxstring::size_type nsz, const lyxstring::value_type * p);
546                 ///
547                 void assign(lyxstring::size_type nsz, lyxstring::value_type ch);
548                 ///
549                 void append(lyxstring::size_type asz, const lyxstring::value_type * p);
550                 ///
551                 void push_back(lyxstring::value_type c);
552                 ///
553                 void insert(lyxstring::size_type pos,
554                             const lyxstring::value_type * p,
555                             lyxstring::size_type n);
556                 ///
557                 void resize(lyxstring::size_type n, lyxstring::value_type c);
558                 ///
559                 void reserve(lyxstring::size_type res_arg);
560                 ///
561                 void replace(lyxstring::size_type i, lyxstring::size_type n,
562                              lyxstring::value_type const * p, lyxstring::size_type n2);
563         private:
564                 Srep(const Srep &);
565                 Srep & operator=(const Srep &);
566         };
567
568         /** The empty_rep is a local static in each function that
569             benefits from one. There is no "global" empty srep but lyxstring
570             doesn't need one (no code actually relies upon a single
571             empty srep).
572             This overcomes *all* "static initialization" problems,
573             at maximum speed, with a small overhead of a few local static
574             empty_reps.
575          */
576
577         /// A string is a pointer to it's representation
578         Srep * rep;
579
580 #ifdef DEVEL_VERSION
581         /// lyxstringInvariant is used to test the lyxstring Invariant
582         friend class lyxstringInvariant;
583 #endif //DEVEL_VERSION
584 };
585
586 // The usual comparison operators ==, !=, >, <, >=, <= are
587 // provided for lyxstrings
588
589 bool operator==(lyxstring const &, lyxstring const &);
590 bool operator==(lyxstring::value_type const *, lyxstring const &);
591 bool operator==(lyxstring const &, lyxstring::value_type const *);
592
593
594 bool operator!=(lyxstring const &, lyxstring const &);
595 bool operator!=(lyxstring::value_type const *, lyxstring const &);
596 bool operator!=(lyxstring const &, lyxstring::value_type const *);
597
598
599 bool operator>(lyxstring const &, lyxstring const &);
600 bool operator>(lyxstring::value_type const *, lyxstring const &);
601 bool operator>(lyxstring const &, lyxstring::value_type const *);
602
603
604 bool operator<(lyxstring const &, lyxstring const &);
605 bool operator<(lyxstring::value_type const *, lyxstring const &);
606 bool operator<(lyxstring const &, lyxstring::value_type const *);
607
608
609 bool operator>=(lyxstring const &, lyxstring const &);
610 bool operator>=(lyxstring::value_type const *, lyxstring const &);
611 bool operator>=(lyxstring const &, lyxstring::value_type const *);
612
613
614 bool operator<=(lyxstring const &, lyxstring const &);
615 bool operator<=(lyxstring::value_type const *, lyxstring const &);
616 bool operator<=(lyxstring const &, lyxstring::value_type const *);
617
618
619 // Concatenation
620
621 lyxstring operator+(lyxstring const & a, lyxstring const & b);
622 lyxstring operator+(char const * a, lyxstring const & b);
623 lyxstring operator+(lyxstring::value_type a, lyxstring const & b);
624 lyxstring operator+(lyxstring const & a, lyxstring::value_type const * b);
625 lyxstring operator+(lyxstring const & a, lyxstring::value_type b);
626
627 class istream; class ostream;
628 istream & operator>>(istream &, lyxstring &);
629 ostream & operator<<(ostream &, lyxstring const &);
630 istream & getline(istream &, lyxstring &, lyxstring::value_type delim = '\n');
631
632 #endif