]> git.lyx.org Git - lyx.git/blob - src/support/lyxstring.C
cosmetic fix
[lyx.git] / src / support / lyxstring.C
1 /**
2  * \file lyxstring.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  *
8  * Full author contact details are available in file CREDITS
9  */
10
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include "lyxstring.h"
16
17 #include "LAssert.h"
18
19 #include "debug.h"
20
21 #include <iostream>
22 #include <cstdlib>
23 #include <cctype>
24 #include <algorithm>
25
26 using std::min;
27 using std::istream;
28 using std::ostream;
29
30 // This class is supposed to be functionaly equivalent to a
31 // standard conformant string. This mean among others that we
32 // are useing the same requirements. Before you change anything
33 // in this file consult me and/or the standard to discover the
34 // right behavior.
35
36 // Asserts with a STD! are required by the standard.
37 // Asserts with a OURS! are added by me.
38 // Some asserts could still be missing and some of the existing
39 // ones might be wrong or not needed.
40
41 // Reference count has been checked, empty_rep removed and
42 // introduced again in a similar guise. Where is empty_rep _really_
43 // needed?
44
45 // We are missing a couple of imporant things from the standard:
46 // reverse iterators and methods taking InputIterators as paramters.
47 // Also the methods returning iterators is returning the wrong value.
48
49 // All the different find functions need a good look over.
50 // I have so far not tested them extensively and would be
51 // happy if others took the time to have a peek.
52
53 // Space allocation of string.
54 // I have tried to do this very simple without using any special tricks.
55 // Earlier we used a fixed value to enlarge the string with this would
56 // cause a lot of reallocations with large strings (especially if
57 // push_back was used) and wasting space for very small strings.
58 // I have now changed the allocation to use a doubling of reserved
59 // space until it is large enough. So far tests show a small speed
60 // increase and a noticable memory saving.
61
62 // Lgb.
63
64 namespace lyx {
65
66 using support::Assert;
67
68 ///////////////////////////////////////
69 // The internal string representation
70 ///////////////////////////////////////
71
72 struct string::Srep {
73         /// size
74         size_t sz;
75         /// Reference count
76         size_t ref;
77         /// The total amount of data reserved for this representaion
78         size_t res;
79         /// Data. At least 1 char for trailing null.
80         string::value_type * s;
81
82         ///
83         Srep(string::size_type nsz, const string::value_type * p);
84         ///
85         Srep(string::size_type nsz, string::value_type ch);
86         ///
87         ~Srep() { delete[] s; }
88         ///
89         Srep * get_own_copy() {
90                 if (ref == 1) return this;
91                 --ref;
92                 return new Srep(sz, s);
93         }
94
95         ///
96         void assign(string::size_type nsz, const string::value_type * p);
97         ///
98         void assign(string::size_type nsz, string::value_type ch);
99         ///
100         void append(string::size_type asz, const string::value_type * p);
101         ///
102         void push_back(string::value_type c);
103         ///
104         void insert(string::size_type pos,
105                     const string::value_type * p,
106                     string::size_type n);
107         ///
108         void resize(string::size_type n, string::value_type c);
109         ///
110         void reserve(string::size_type res_arg);
111         ///
112         void replace(string::size_type i, string::size_type n,
113                      string::value_type const * p, string::size_type n2);
114 private:
115         Srep(const Srep &);
116         Srep & operator=(const Srep &);
117 };
118
119
120 string::Srep::Srep(string::size_type nsz, const value_type * p)
121 {
122         // can be called with p == 0 by
123         // string::assign(const value_type *, size_type)
124
125         sz = nsz;
126         ref = 1;
127         res = sz ? sz : 1;
128         s = new value_type[res + 1]; // add space for terminator
129         if (p && sz) {
130                 // if sz = 0 nothing gets copied and we have an error
131                 memcpy(s, p, sz);
132         } else {
133                 // possibly allows for large but empty string
134                 sz = 0;  // this line should be redundant
135                 s[0] = '\0';
136         }
137 }
138
139
140 string::Srep::Srep(string::size_type nsz, value_type ch)
141 {
142         sz = nsz;
143         ref = 1;
144         res = sz ? sz : 1;
145         s = new value_type[res + 1]; // add space for terminator
146         memset(s, ch, sz);
147         if (!ch) {
148                 // if ch == '\0' strlen(string.c_str()) == 0 so sz = 0
149                 // allows for large but empty string
150                 sz = 0;
151         }
152 }
153
154
155 void string::Srep::assign(string::size_type nsz, const value_type * p)
156 {
157         // can be called with p == 0
158         // by string::assign(const value_type *, size_type)
159
160         if (res < nsz) {
161                 delete[] s;
162                 sz = nsz;
163                 res = sz ? sz : 1;
164                 s = new value_type[res + 1]; // add space for terminator
165         } else {
166                 sz = nsz;
167         }
168         if (p && sz) {
169                 // if sz = 0 nothing gets copied and we have an error
170                 memcpy(s, p, sz);
171         } else {
172                 // stops segfaults
173                 sz = 0;  // this line should be redundant
174                 s[0] = '\0';
175         }
176 }
177
178
179 void string::Srep::assign(string::size_type nsz, value_type ch)
180 {
181         sz = nsz;
182         if (res < nsz) {
183                 delete[] s;
184                 res = sz ? sz : 1;
185                 s = new value_type[res + 1]; // add space for terminator
186         }
187         memset(s, ch, sz);
188         if (!ch) {
189                 // if ch == '\0' strlen(string.c_str()) == 0 so sz = 0
190                 // allows for a large empty string
191                 sz = 0;
192         }
193 }
194
195
196 void string::Srep::append(string::size_type asz, const value_type * p)
197 {
198         register unsigned int const len = sz + asz;
199         if (res < len) {
200                 do {
201                         res *= 2;
202                 } while (res < len);
203                 value_type * tmp = new value_type[res + 1];
204                 memcpy(tmp, s, sz);
205                 memcpy(tmp + sz, p, asz);
206                 sz += asz;
207                 delete[] s;
208                 s = tmp;
209         } else {
210                 memcpy(s + sz, p, asz);
211                 sz += asz;
212         }
213 }
214
215
216 void string::Srep::push_back(value_type c)
217 {
218         s[sz] = c; // it is always room to put a value_type at the end
219         ++sz;
220         if (res < sz) {
221                 do {
222                         res *= 2;
223                 } while (res < sz);
224                 value_type * tmp = new value_type[res + 1];
225                 memcpy(tmp, s, sz);
226                 delete[] s;
227                 s = tmp;
228         }
229 }
230
231
232 void string::Srep::insert(string::size_type pos, const value_type * p,
233                              string::size_type n)
234 {
235         if (res < n + sz) {
236                 do {
237                         res *= 2;
238                 } while (res < n + sz);
239                 value_type * tmp = new value_type[res + 1];
240                 memcpy(tmp, s, pos);
241                 memcpy(tmp + pos, p, n);
242                 memcpy(tmp + pos + n, &s[pos], sz - pos);
243                 sz += n;
244                 delete[] s;
245                 s = tmp;
246         } else {
247                 memmove(s + pos + n, &s[pos], sz - pos);
248                 memcpy(s + pos, p, n);
249                 sz += n;
250         }
251 }
252
253
254 void string::Srep::resize(size_type n, value_type c)
255 {
256         // This resets sz to res_arg
257         res = min(n, npos - 2); // We keep no xtra when we resize
258         value_type * tmp = new value_type[res + 1];
259         memcpy(tmp, s, min(sz, res));
260         if (res > sz)
261                 memset(tmp + sz, c, res - sz);
262         delete[] s;
263         sz = res;
264         s = tmp;
265 }
266
267
268 void string::Srep::reserve(string::size_type res_arg)
269 {
270         // This keeps the old sz, but
271         // increases res with res_arg
272         res += res_arg;
273         value_type * tmp = new value_type[res + 1];
274         memcpy(tmp, s, sz);
275         delete[] s;
276         s = tmp;
277 }
278
279
280 void string::Srep::replace(string::size_type i, string::size_type n,
281                               value_type const * p, size_type n2)
282 {
283 // can be called with p= 0 and n2= 0
284         n = min(sz - i, n);
285         sz -= n;
286         if (res >= n2 + sz) {
287                 memmove(s + i + n2, &s[i + n], sz - i);
288                 memcpy(s + i, p, n2);
289                 sz += n2;
290         } else {
291                 do {
292                         res *= 2;
293                 } while (res < n2 + sz);
294                 value_type * tmp = new value_type[res + 1];
295                 memcpy(tmp, s, i);
296                 memcpy(tmp + i, p, n2);
297                 memcpy(tmp + i + n2, &s[i + n], sz - i);
298                 delete[] s;
299                 s = tmp;
300                 sz += n2;
301         }
302 }
303
304
305 ///////////////////////////////////////
306 // The string Invariant tester
307 ///////////////////////////////////////
308
309 // There are no know bugs in string now, and it have been
310 // tested for a long time. so we disable the invariant checker. (Lgb)
311 #undef ENABLE_ASSERTIONS
312 #ifdef ENABLE_ASSERTIONS
313
314 /** Testing of the string invariant
315  * By creating an object that tests the string invariant during its
316  * construction *and* its deconstruction we greatly simplify our code.
317  * Calling TeststringInvariant() upon entry to an string method
318  * will test the invariant upon entry to the code.  If the Asserts fail
319  * then we know from the stack trace that the corruption occurred *before*
320  * entry to this method.  We can also be sure it didn't happen in any of
321  * the tested string methods.  It is therefore likely to be due to some
322  * other external force.
323  * Several string methods have multiple exit points which would otherwise
324  * require us to insert a separate test before each return.  But since we
325  * created an object its destructor will be called upon exit (any exit!).
326  * We thus get testing at both start and end of a method with one line of
327  * code at the head of a method.  More importantly,  we get good testing
328  * everytime we run the code.
329  * NOTE:  just because we test the invariant doesn't mean we can forget
330  * about testing pre and post conditions specific to any given method.
331  * This test simply proves that the string/Srep is in a valid state it
332  * does *not* prove that the method did what it was supposed to.
333  */
334 class stringInvariant {
335 public:
336         stringInvariant(string const *);
337         ~stringInvariant();
338 private:
339         void helper() const;
340         string const * object;
341 };
342
343
344 // To test if this scheme works "as advertised" uncomment the printf's in
345 // the constructor and destructor below and then uncomment the printf and the
346 // call to TestlyxstringInvariant() in string::operator=(char const *).
347 // The correct output when LyX has been recompiled and run is:
348 //     lyxstringInvariant constructor
349 //     string::operator=(char const *)
350 //     lyxstringInvariant constructor
351 //     lyxstringInvariant destructor completed
352 //     lyxstringInvariant destructor completed
353 // NOTE: The easiest way to catch this snippet of the output is to wait for
354 //       the splash screen to disappear and then open and close Help->Credits
355 //
356 stringInvariant::stringInvariant(string const * ls) : object(ls)
357 {
358         // printf("stringInvariant constructor\n");
359         helper();
360 }
361
362
363 stringInvariant::~stringInvariant()
364 {
365         helper();
366         // printf("stringInvariant destructor completed\n");
367 }
368
369
370 void stringInvariant::helper() const
371 {
372         // Some of these tests might look pointless but they are
373         // all part of the invariant and if we want to make sure
374         // we have a bullet proof implementation then we need to
375         // test every last little thing we *know* should be true.
376         // I may have missed a test or two, so feel free to fill
377         // in the gaps.  ARRae.
378         Assert(object);
379         Assert(object->rep);
380         Assert(object->rep->s);    // s is never 0
381         Assert(object->rep->res);  // res cannot be 0
382         Assert(object->rep->sz <= object->rep->res);
383         Assert(object->rep->ref >= 1);  // its in use so it must be referenced
384         Assert(object->rep->ref < 1UL << (8UL * sizeof(object->rep->ref) - 1));
385         // if it does ever == then we should be generating a new copy
386         // and starting again.  (Is char always 8-bits?)
387 }
388 #define TeststringInvariant(s) stringInvariant string_invariant(s);
389 #else
390 #define TeststringInvariant(s)
391 #endif /* ENABLE_ASSERTIONS */
392
393
394 ///////////////////////////////////////
395 // Constructors and Deconstructors.
396 ///////////////////////////////////////
397
398 string::size_type const string::npos =
399 static_cast<string::size_type>(-1);
400
401
402 string::string()
403 {
404         static Srep empty_rep(0, "");
405         ++empty_rep.ref;
406         rep = &empty_rep;
407 }
408
409
410 string::string(string const & x, size_type pos, size_type n)
411 {
412         Assert(pos <= x.rep->sz); // STD!
413         if (pos == 0 && n >= x.length()) { // this is the default
414                 x.rep->ref++;
415                 rep = x.rep;
416         } else {
417                 rep = new Srep(min(n, x.rep->sz - pos), &(x.rep->s[pos]));
418         }
419 }
420
421
422 string::string(value_type const * s, size_type n)
423 {
424         Assert(s && n < npos); // STD!
425         static Srep empty_rep(0, "");
426         if (n) { // n > 0
427                 rep = new Srep(n, s);
428         } else {
429                 ++empty_rep.ref;
430                 rep = &empty_rep;
431         }
432 }
433
434
435 string::string(value_type const * s)
436 {
437         Assert(s); // STD!
438         static Srep empty_rep(0, "");
439         if (*s) { // s is not empty string
440                 rep = new Srep(strlen(s), s);
441         } else {
442                 ++empty_rep.ref;
443                 rep = &empty_rep;
444         }
445 }
446
447
448 string::string(size_type n, value_type c)
449 {
450         Assert(n < npos); // STD!
451         rep = new Srep(n, c);
452 }
453
454
455 #warning string user, have a look here. (Lgb)
456 #if 0
457 // Commented out to avoid warnings from doxygen. (Lgb)
458 string::string(const_iterator first, const_iterator last)
459 {
460         rep = new Srep(last - first, first);
461 }
462 #endif
463
464
465 string::~string()
466 {
467         if (--rep->ref == 0) delete rep;
468 }
469
470 ///////////////////////
471 // Iterators
472 ///////////////////////
473
474 string::iterator string::begin()
475 {
476         rep = rep->get_own_copy();
477         return rep->s;
478 }
479
480
481 string::const_iterator string::begin() const
482 {
483         return rep->s;
484 }
485
486
487 string::iterator string::end()
488 {
489         rep = rep->get_own_copy();
490         return rep->s + rep->sz;
491 }
492
493
494 string::const_iterator string::end() const
495 {
496         return rep->s + rep->sz;
497 }
498
499 #if 0
500 reverse_iterator string::rbegin()
501 {
502         return reverse_iterator( end() );
503 }
504
505
506 const_reverse_iterator string::rbegin() const
507 {
508         return const_reverse_iterator( end() );
509 }
510
511
512 reverse_iterator string::rend()
513 {
514         return reverse_iterator( begin() );
515 }
516
517
518 const_reverse_iterator string::rend() const
519 {
520         return const_reverse_iterator( begin() );
521 }
522 #endif
523
524
525 ///////////////////////
526 // Size and Capacity
527 ///////////////////////
528
529 string::size_type string::size() const
530 {
531         return rep->sz;
532 }
533
534
535 void string::resize(size_type n, value_type c)
536 {
537         Assert(n <= npos); // STD!
538         TeststringInvariant(this);
539
540         // This resets sz to res_arg
541         rep = rep->get_own_copy();
542         rep->resize(n, c);
543 }
544
545
546 string::size_type string::capacity() const
547 {
548         return rep->res;
549 }
550
551
552 void string::reserve(size_type res_arg)
553 {
554         TeststringInvariant(this);
555
556         rep = rep->get_own_copy();
557         rep->reserve(res_arg);
558 }
559
560
561 ////////////////
562 // Assignment
563 ////////////////
564
565 string & string::operator=(string const & x)
566 {
567         TeststringInvariant(this);
568
569         return assign(x);
570 }
571
572
573 string & string::operator=(value_type const * s)
574 {
575         Assert(s); // OURS!
576         TeststringInvariant(this);
577 //      printf("string::operator= (value_type const *)\n");
578
579         return assign(s);
580 }
581
582
583 string & string::operator=(value_type c)
584 {
585         TeststringInvariant(this);
586
587         value_type s[1];
588         s[0] = c;
589         if (rep->ref == 1) // recycle rep
590                 rep->assign(1, s);
591         else {
592                 rep->ref--;
593                 rep = new Srep(1, s);
594         }
595         return *this;
596 }
597
598
599 string & string::assign(string const & x)
600 {
601         TeststringInvariant(this);
602
603         x.rep->ref++; // protect against ``st = st''
604         if (--rep->ref == 0) delete rep;
605         rep = x.rep; // share representation
606         return *this;
607 }
608
609
610 string & string::assign(string const & x, size_type pos, size_type n)
611 {
612         Assert(pos <= x.rep->sz); // STD!
613         TeststringInvariant(this);
614
615         return assign(x.substr(pos, n));
616 }
617
618
619 string & string::assign(value_type const * s, size_type n)
620 {
621         Assert(s && n < npos); // STD!
622         TeststringInvariant(this);
623
624         if (rep->ref == 1) // recycle rep
625                 rep->assign(n, s);
626         else {
627                 --rep->ref;
628                 rep = new Srep(n, s);
629         }
630         return *this;
631 }
632
633
634 string & string::assign(value_type const * s)
635 {
636         Assert(s); // OURS!
637         TeststringInvariant(this);
638
639         return assign(s, strlen(s));
640 }
641
642
643 string & string::assign(size_type n, value_type ch)
644 {
645         TeststringInvariant(this);
646
647         rep = rep->get_own_copy();
648         rep->assign(n, ch);
649         return *this;
650 }
651
652
653 string & string::assign(const_iterator first, const_iterator last)
654 {
655         TeststringInvariant(this);
656
657         rep = rep->get_own_copy();
658         rep->assign(last - first, first);
659         return *this;
660 }
661
662
663 ////////////////////
664 // Element Access
665 ////////////////////
666
667 string::const_reference string::operator[](size_type pos) const
668 {
669 #if 0
670         // This is actually what the standard requires,
671         Assert(pos <= rep->sz); // OURS!
672         static char const helper = '\0';
673         return pos == rep->sz ? helper : rep->s[pos];
674 #else
675         // but we use this one since it is stricter
676         // and more according to the real intent of std::string.
677         Assert(pos < rep->sz); // OURS!
678         return rep->s[pos];
679 #endif
680 }
681
682
683 string::reference string::operator[](size_type pos)
684 {
685         Assert(pos < rep->sz); // OURS!
686         TeststringInvariant(this);
687
688         rep = rep->get_own_copy();
689         return rep->s[pos];
690 }
691
692
693 string::const_reference string::at(size_type n) const
694 {
695         Assert(n < rep->sz); // STD!
696         return rep->s[n];
697 }
698
699
700 string::reference string::at(size_type n)
701 {
702         Assert(n < rep->sz); // STD!
703         TeststringInvariant(this);
704
705         rep = rep->get_own_copy();
706         return rep->s[n];
707 }
708
709
710 /////////////
711 // Insert
712 /////////////
713
714 string & string::operator+=(string const & x)
715 {
716         TeststringInvariant(this);
717
718         return append(x);
719 }
720
721
722 string & string::operator+=(value_type const * x)
723 {
724         Assert(x); // OURS!
725         TeststringInvariant(this);
726
727         return append(x);
728 }
729
730
731 string & string::operator+=(value_type c)
732 {
733         TeststringInvariant(this);
734
735         push_back(c);
736         return *this;
737 }
738
739
740 void string::push_back(value_type c)
741 {
742         TeststringInvariant(this);
743
744         rep = rep->get_own_copy();
745         rep->push_back(c);
746 }
747
748
749 string & string::append(string const & x)
750 {
751         TeststringInvariant(this);
752
753         if (x.empty()) return *this;
754         rep = rep->get_own_copy();
755         rep->append(x.length(), x.rep->s);
756         return *this;
757 }
758
759
760 string & string::append(string const & x, size_type pos, size_type n)
761 {
762         Assert(pos <= x.rep->sz); // STD!
763         TeststringInvariant(this);
764
765         return append(x.substr(pos, n));
766 }
767
768
769 string & string::append(value_type const * p, size_type n)
770 {
771         Assert(p); // OURS!
772         TeststringInvariant(this);
773
774         if (!*p || !n) return *this;
775         rep = rep->get_own_copy();
776         rep->append(n, p);
777         return *this;
778 }
779
780
781 string & string::append(value_type const * p)
782 {
783         Assert(p); // OURS!
784         return append(p, strlen(p));
785 }
786
787
788 string & string::append(size_type n, value_type c)
789 {
790         TeststringInvariant(this);
791
792         value_type * tmp = new value_type[n];
793         memset(tmp, c, n);
794         rep = rep->get_own_copy();
795         rep->append(n, tmp);
796         delete[] tmp;
797         return *this;
798 }
799
800
801 string & string::append(iterator first, iterator last)
802 {
803         TeststringInvariant(this);
804
805         rep = rep->get_own_copy();
806         rep->append(last - first, first);
807         return *this;
808 }
809
810 // insert characters before (*this)[pos]
811
812 string & string::insert(size_type pos, string const & x)
813 {
814         TeststringInvariant(this);
815
816         return insert(pos, x, 0, x.rep->sz);
817 }
818
819
820 string & string::insert(size_type pos, string const & x,
821                               size_type pos2, size_type n)
822 {
823         Assert(pos <= rep->sz && pos2 <= x.rep->sz); // STD!
824         TeststringInvariant(this);
825
826         rep = rep->get_own_copy();
827         rep->insert(pos, &(x.rep->s[pos2]), min(n, x.rep->sz));
828         return *this;
829 }
830
831
832 string & string::insert(size_type pos, value_type const * p, size_type n)
833 {
834         Assert(p); // OURS!
835         TeststringInvariant(this);
836
837         if (*p && n) {
838                 // insert nothing and you change nothing
839                 rep = rep->get_own_copy();
840                 rep->insert(pos, p, n);
841         }
842         return *this;
843 }
844
845
846 string & string::insert(size_type pos, value_type const * p)
847 {
848         Assert(p); // OURS!
849         return insert(pos, p, strlen(p));
850 }
851
852
853 string & string::insert(size_type pos, size_type n, value_type c)
854 {
855         TeststringInvariant(this);
856
857         rep = rep->get_own_copy();
858         value_type * tmp = new value_type[n];
859         memset(tmp, c, n);
860         rep->insert(pos, tmp, n);
861         delete[] tmp;
862         return *this;
863 }
864
865
866 string::iterator string::insert(iterator p, value_type c)
867 {
868         TeststringInvariant(this);
869
870         // what iterator is this supposed to return??
871         size_type tmp = p - begin();
872         insert(p - begin(), 1, c);
873         return begin() + tmp + 1; // ??
874 }
875
876
877 void string::insert(iterator p, size_type n , value_type c)
878 {
879         TeststringInvariant(this);
880
881         insert(p - begin(), n , c);
882 }
883
884
885 void string::insert(iterator p, iterator first, iterator last)
886 {
887         TeststringInvariant(this);
888
889         insert(p - begin(), first, last - first);
890 }
891
892
893 ////////////////
894 // Find
895 ////////////////
896
897          // All the below find functions should be verified,
898          // it is very likely that I have mixed up or interpreted
899          // some of the parameters wrong, also some of the funcs can surely
900          // be written more effectively.
901
902 string::size_type string::find(string const & a, size_type i) const
903 {
904         if (!rep->sz || i >= rep->sz) return npos;
905
906         TeststringInvariant(this);
907
908         size_type n = a.length();
909         if (!n) return npos;
910         for (size_type t = i; rep->sz - t >= n; ++t) {
911                 // search until (*this)[i] == a[0]
912                 if (rep->s[t] == a[0]) {
913                         // check if the rest of the value_types match
914                         bool equal = true;
915                         for (size_type j = 1; j < n; ++j) {
916                                 if (rep->s[t + j] != a[j]) {
917                                         equal = false;
918                                         break;
919                                 }
920                         }
921                         if (equal) return t;
922                 }
923         }
924         return npos;
925 }
926
927
928 string::size_type string::find(value_type const * ptr, size_type i,
929                                      size_type n) const
930 {
931         Assert(ptr); // OURS!
932         if (!rep->sz || !*ptr || i >= rep->sz) return npos;
933
934         TeststringInvariant(this);
935
936         // What is "n" here? is it the number of value_types to use in ptr
937         // or does "i" and "n" togeter form a substring to search
938         // for ptr in? For now I will assume that "n" tells the length
939         // of ptr. (Lgb)
940         n = min(n, strlen(ptr));
941         if (!n) return npos;
942         for (size_type t = i; rep->sz - t >= n; ++t) {
943                 // search until (*this)[i] == a[0]
944                 if (rep->s[t] == ptr[0]) {
945                         // check if the rest of the value_types match
946                         bool equal = true;
947                         for (size_type j = 1; j < n; ++j) {
948                                 if (rep->s[t + j] != ptr[j]) {
949                                         equal = false;
950                                         break;
951                                 }
952                         }
953                         if (equal) return t;
954                 }
955         }
956         return npos;
957 }
958
959
960 string::size_type string::find(value_type const * s, size_type i) const
961 {
962         Assert(s); // OURS!
963         if (!rep->sz || i >= rep->sz) return npos;
964
965         TeststringInvariant(this);
966
967         if (!s || !*s) return npos;
968         return find(s, i, strlen(s));
969 }
970
971
972 string::size_type string::find(value_type c, size_type i) const
973 {
974         if (!rep->sz || i >= rep->sz) return npos;
975
976         TeststringInvariant(this);
977
978         for (size_type t = 0; t + i < rep->sz; ++t) {
979                 if (rep->s[t + i] == c) return t + i;
980         }
981         return npos;
982 }
983
984
985 string::size_type string::rfind(string const & a, size_type i) const
986 {
987         TeststringInvariant(this);
988
989         size_type n = a.length();
990         if (!n || rep->sz < n)
991                 return npos;
992
993         size_type t = min(rep->sz - n, i);
994         do {
995                 if (rep->s[t] == a[0]) {
996                         // check if the rest of the value_types match
997                         bool equal = true;
998                         for (size_type j = 1; j < n; ++j) {
999                                 if (rep->s[t + j] != a[j]) {
1000                                         equal = false;
1001                                         break;
1002                                 }
1003                         }
1004                         if (equal) return t;
1005                 }
1006         } while (t-- > 0);
1007         return npos;
1008 }
1009
1010
1011 string::size_type string::rfind(value_type const * ptr, size_type i,
1012                                       size_type n) const
1013 {
1014         Assert(ptr); // OURS!
1015         TeststringInvariant(this);
1016
1017         n = min(n, strlen(ptr));
1018         if (!n || rep->sz < n)
1019                 return npos;
1020
1021         size_type t = min(rep->sz - n, i);
1022         do {
1023                 if (rep->s[t] == ptr[0]) {
1024                         // check if the rest of the value_types match
1025                         bool equal = true;
1026                         for (size_type j = 1; j < n; ++j) {
1027                                 if (rep->s[t + j] != ptr[j]) {
1028                                         equal = false;
1029                                         break;
1030                                 }
1031                         }
1032                         if (equal) return t;
1033                 }
1034         } while (t-- > 0);
1035         return npos;
1036 }
1037
1038
1039 string::size_type string::rfind(value_type const * ptr,
1040                                       size_type i) const
1041 {
1042         Assert(ptr); // OURS!
1043
1044         if (!ptr || !*ptr) return npos;
1045         return rfind(ptr, i, strlen(ptr));
1046 }
1047
1048
1049 string::size_type string::rfind(value_type c, size_type i) const
1050 {
1051         TeststringInvariant(this);
1052
1053         size_type const sz = rep->sz;
1054         if (sz < 1) return npos;
1055         size_type ii = min(sz - 1, i);
1056         do {
1057                 if (rep->s[ii] == c) return ii;
1058         } while (ii-- > 0);
1059         return npos;
1060 }
1061
1062
1063 string::size_type string::find_first_of(string const & a,
1064                                               size_type i) const
1065 {
1066         Assert(i <= rep->sz); // OURS!
1067         TeststringInvariant(this);
1068
1069         for (size_type t = i; t < rep->sz; ++t) {
1070                 if (a.find(rep->s[t]) != npos) return t;
1071         }
1072         return npos;
1073 }
1074
1075
1076 string::size_type string::find_first_of(value_type const * ptr,
1077                                               size_type i,
1078                                               size_type n) const
1079 {
1080         Assert(ptr && i <= rep->sz); // OURS!
1081         TeststringInvariant(this);
1082         if (!n) return npos;
1083
1084         for (size_type t = i; t < rep->sz; ++t) {
1085                 if (memchr(ptr, rep->s[t], n) != 0) return t;
1086         }
1087         return npos;
1088 }
1089
1090
1091 string::size_type string::find_first_of(value_type const * ptr,
1092                                               size_type i) const
1093 {
1094         Assert(ptr && i <= rep->sz); // OURS!
1095         TeststringInvariant(this);
1096
1097         for (size_type t = i; t < rep->sz; ++t) {
1098                 if (strchr(ptr, rep->s[t]) != 0) return t;
1099         }
1100         return npos;
1101 }
1102
1103
1104 string::size_type string::find_first_of(value_type c, size_type i) const
1105 {
1106         Assert(i <= rep->sz); // OURS!
1107         TeststringInvariant(this);
1108
1109         for (size_type t = i; t < rep->sz; ++t) {
1110                 if (rep->s[t] == c) return t;
1111         }
1112         return npos;
1113 }
1114
1115
1116 string::size_type string::find_last_of(string const & a,
1117                                              size_type i) const
1118 {
1119         TeststringInvariant(this);
1120
1121         size_type ii = min(rep->sz - 1, i);
1122         for (int t = ii; t >= 0; --t) {
1123                 if (a.find(rep->s[t]) != npos) return t;
1124         }
1125         return npos;
1126 }
1127
1128
1129 string::size_type string::find_last_of(value_type const * ptr,
1130                                              size_type i,
1131                                              size_type n) const
1132 {
1133         Assert(ptr); // OURS!
1134         TeststringInvariant(this);
1135         if (!n) return npos;
1136
1137         size_type ii = min(rep->sz - 1, i);
1138         for (int t = ii; t >= 0; --t) {
1139                 if (memchr(ptr, rep->s[t], n) != 0) return t;
1140         }
1141         return npos;
1142 }
1143
1144
1145 string::size_type string::find_last_of(value_type const * ptr,
1146                                              size_type i) const
1147 {
1148         Assert(ptr); // OURS!
1149         TeststringInvariant(this);
1150
1151         size_type ii = min(rep->sz - 1, i);
1152         for (int t = ii; t >= 0; --t) {
1153                 if (strchr(ptr, rep->s[t]) != 0) return t;
1154         }
1155         return npos;
1156 }
1157
1158
1159 string::size_type string::find_last_of(value_type c, size_type i) const
1160 {
1161         TeststringInvariant(this);
1162
1163         if (!rep->sz) return npos;
1164         size_type ii = min(rep->sz - 1, i);
1165         for (int t = ii; t >= 0; --t) {
1166                 if (rep->s[t] == c) return t;
1167         }
1168         return npos;
1169 }
1170
1171
1172 string::size_type string::find_first_not_of(string const & a,
1173                                                   size_type i) const
1174 {
1175         TeststringInvariant(this);
1176
1177         if (!rep->sz) return npos;
1178         Assert(i <= rep->sz);
1179         for (size_type t = i; t < rep->sz; ++t) {
1180                 if (a.find(rep->s[t]) == npos) return t;
1181         }
1182         return npos;
1183 }
1184
1185
1186 string::size_type string::find_first_not_of(value_type const * ptr,
1187                                                   size_type i,
1188                                                   size_type n) const
1189 {
1190         Assert(ptr && i <= rep->sz); // OURS!
1191         TeststringInvariant(this);
1192
1193         if (!n) return (i < rep->sz) ? i : npos;
1194         for (size_type t = i; t < rep->sz; ++t) {
1195                 if (memchr(ptr, rep->s[t], n) == 0) return t;
1196         }
1197         return npos;
1198 }
1199
1200
1201 string::size_type string::find_first_not_of(value_type const * ptr,
1202                                                   size_type i) const
1203 {
1204         Assert(ptr && i <= rep->sz); // OURS!
1205         TeststringInvariant(this);
1206
1207         for (size_type t = i; t < rep->sz; ++t) {
1208                 if (strchr(ptr, rep->s[t]) == 0) return t;
1209         }
1210         return npos;
1211 }
1212
1213
1214 string::size_type string::find_first_not_of(value_type c,
1215                                                   size_type i) const
1216 {
1217         if (!rep->sz) return npos;
1218         Assert(i <= rep->sz); // OURS!
1219         TeststringInvariant(this);
1220
1221         for (size_type t = i; t < rep->sz; ++t) {
1222                 if (rep->s[t] != c) return t;
1223         }
1224         return npos;
1225 }
1226
1227
1228 string::size_type string::find_last_not_of(string const & a,
1229                                                  size_type i) const
1230 {
1231         TeststringInvariant(this);
1232
1233         size_type ii = min(rep->sz - 1, i);
1234         for (int t = ii; t >= 0; --t) {
1235                 if (a.find(rep->s[t]) == npos) return t;
1236         }
1237         return npos;
1238 }
1239
1240
1241 string::size_type string::find_last_not_of(value_type const * ptr,
1242                                                  size_type i,
1243                                                  size_type n) const
1244 {
1245         Assert(ptr); // OURS!
1246         TeststringInvariant(this);
1247
1248         if (!n) return npos;
1249         size_type ii = min(rep->sz - 1, i);
1250
1251         for (int t = ii; t >= 0; --t) {
1252                 if (memchr(ptr, rep->s[t], n) == 0) return t;
1253         }
1254         return npos;
1255 }
1256
1257
1258 string::size_type string::find_last_not_of(value_type const * ptr,
1259                                                  size_type i) const
1260 {
1261         Assert(ptr); // OURS!
1262         TeststringInvariant(this);
1263
1264         size_type ii = min(rep->sz - 1, i);
1265         for (int t = ii; t >= 0; --t) {
1266                 if (strchr(ptr, rep->s[t]) == 0) return t;
1267         }
1268         return npos;
1269 }
1270
1271
1272 string::size_type string::find_last_not_of(value_type c,
1273                                                  size_type i) const
1274 {
1275         TeststringInvariant(this);
1276
1277         size_type ii = min(rep->sz - 1, i);
1278         for (int t = ii; t >= 0; --t) {
1279                 if (rep->s[t] != c) return t;
1280         }
1281         return npos;
1282 }
1283
1284
1285 /////////////////
1286 // Replace
1287 /////////////////
1288
1289 string & string::replace(size_type i, size_type n, string const & x)
1290 {
1291         Assert(i <= rep->sz); // OURS!
1292         TeststringInvariant(this);
1293
1294         return replace(i, n, x, 0, x.rep->sz);
1295 }
1296
1297
1298 string & string::replace(size_type i, size_type n, string const & x,
1299                                size_type i2, size_type n2)
1300 {
1301         Assert(i <= rep->sz && i2 <= x.rep->sz); // STD!
1302         TeststringInvariant(this);
1303
1304         rep = rep->get_own_copy();
1305         rep->replace(i, min(n, rep->sz), &(x.rep->s[i2]), min(n2, x.rep->sz));
1306         return *this;
1307 }
1308
1309
1310 string & string::replace(size_type i, size_type n,
1311                                value_type const * p, size_type n2)
1312 {
1313         Assert(p && i <= rep->sz); // OURS!
1314         TeststringInvariant(this);
1315
1316         rep = rep->get_own_copy();
1317         rep->replace(i, min(n, rep->sz), p, min(n2, strlen(p)));
1318         return *this;
1319 }
1320
1321
1322 string & string::replace(size_type i, size_type n, value_type const * p)
1323 {
1324         Assert(p && i <= rep->sz); // OURS!
1325         TeststringInvariant(this);
1326
1327         return replace(i, min(n, rep->sz), p, (!p) ? 0 : strlen(p));
1328 }
1329
1330
1331 string & string::replace(size_type i, size_type n,
1332                                size_type n2, value_type c)
1333 {
1334         Assert(i <= rep->sz);  // OURS!
1335         TeststringInvariant(this);
1336
1337         rep = rep->get_own_copy();
1338         value_type * tmp = new value_type[n2];
1339         memset(tmp, c, n2);
1340         rep->replace(i, min(n, rep->sz), tmp, n2);
1341         delete[] tmp;
1342         return *this;
1343 }
1344
1345
1346 /// FY! FY! FY! go away !
1347 string & string::replace(size_type i, size_type n, value_type c)
1348 {
1349         return replace(i, n, 1, c);
1350 }
1351
1352
1353 string & string::replace(iterator i, iterator i2, const string & str)
1354 {
1355         TeststringInvariant(this);
1356
1357         return replace(i - begin(), i2 - i, str);
1358 }
1359
1360
1361 string & string::replace(iterator i, iterator i2,
1362                                value_type const * p, size_type n)
1363 {
1364         Assert(p); // OURS!
1365         TeststringInvariant(this);
1366
1367         return replace(i - begin(), i2 - i, p, n);
1368 }
1369
1370
1371 string & string::replace(iterator i, iterator i2, value_type const * p)
1372 {
1373         Assert(p); // OURS!
1374         TeststringInvariant(this);
1375
1376         return replace(i - begin(), i2 - i, p);
1377 }
1378
1379
1380 string & string::replace(iterator i, iterator i2,
1381                                size_type n , value_type c)
1382 {
1383         TeststringInvariant(this);
1384
1385         return replace(i - begin(), i2 - i, n, c);
1386 }
1387
1388
1389 string & string::replace(iterator i, iterator i2,
1390                                iterator j, iterator j2)
1391 {
1392         TeststringInvariant(this);
1393
1394         return replace(i - begin(), i2 - i, j, j2 - j);
1395 }
1396
1397
1398 void string::swap(string & str)
1399 {
1400         if (rep == str.rep) return;
1401         Srep * tmp = str.rep;
1402         str.rep = rep;
1403         rep = tmp;
1404 }
1405
1406
1407 string & string::erase(size_type i, size_type n)
1408 {
1409         Assert(i <= rep->sz); // STD!
1410         TeststringInvariant(this);
1411
1412         rep = rep->get_own_copy();
1413         if (i == 0 && n >= rep->sz) {
1414                 rep->sz = 0;
1415         } else {
1416                 n = min(n, rep->sz - i);
1417                 memmove(&(rep->s[i]), &(rep->s[i + n]), rep->sz - i - n);
1418                 rep->sz -= n;
1419         }
1420         return *this;
1421 }
1422
1423
1424 string::iterator string::erase(iterator i)
1425 {
1426         TeststringInvariant(this);
1427
1428         // what iterator is this supposed to return?
1429         // the iterator after the one erased
1430         erase(i - begin(), 1);
1431         return begin(); // BUG
1432 }
1433
1434
1435 string::iterator string::erase(iterator first, iterator last)
1436 {
1437         TeststringInvariant(this);
1438
1439         erase(first - begin(), last - first);
1440         return begin(); // BUG
1441 }
1442
1443
1444 /////////////////////////////////////
1445 // Conversion to C-style Strings
1446 /////////////////////////////////////
1447
1448 string::value_type const * string::c_str() const
1449 {
1450         rep->s[length()] = '\0';
1451         return rep->s;
1452 }
1453
1454
1455 string::value_type const * string::data() const
1456 {
1457         return rep->s;
1458 }
1459
1460
1461 string::size_type string::copy(value_type * buf, size_type len,
1462                                      size_type pos) const
1463 {
1464         Assert(buf); // OURS!
1465         Assert(pos <= rep->sz); // STD!
1466         TeststringInvariant(this);
1467
1468         register int nn = min(len, length() - pos);
1469         memcpy(buf, &(rep->s[pos]), nn);
1470         return nn;
1471 }
1472
1473
1474 ////////////////////
1475 // Comparisons
1476 ////////////////////
1477
1478 // Compare funcs should be verified.
1479
1480 int string::internal_compare(size_type pos, size_type n,
1481                                 value_type const * s,
1482                                 size_type slen, size_type n2) const
1483 {
1484         if ((rep->sz == 0 || n == 0) && (!*s || n2 == 0)) return 0;
1485         if (!*s) return 1;
1486         // since n > n2, min(n, n2) == 0, c == 0 (stops segfault also)
1487
1488         // remember that n can very well be a lot larger than rep->sz
1489         // so we have to ensure that n is no larger than rep->sz
1490         n = min(n, rep->sz);
1491         n2 = min(n2, slen);
1492         if (n == n2)
1493                 return memcmp(&(rep->s[pos]), s, n);
1494         int c = memcmp(&(rep->s[pos]), s, min(n, n2));
1495         if (c)
1496                 return c;
1497         if (n < n2)
1498                 return -1;
1499         return 1;
1500 }
1501
1502
1503 int string::compare(string const & str) const
1504 {
1505         TeststringInvariant(this);
1506         return internal_compare(0, rep->sz, str.rep->s,
1507                                 str.rep->sz, str.rep->sz);
1508 }
1509
1510
1511 int string::compare(value_type const * s) const
1512 {
1513         Assert(s); //OURS!
1514         TeststringInvariant(this);
1515         int n = (!s) ? 0 : strlen(s);
1516         return internal_compare(0, rep->sz, s, n, n);
1517 }
1518
1519
1520 int string::compare(size_type pos, size_type n,
1521                        string const & str) const
1522 {
1523         Assert(pos <= rep->sz); // OURS!
1524         TeststringInvariant(this);
1525         return internal_compare(pos, n, str.rep->s, str.rep->sz, str.rep->sz);
1526 }
1527
1528
1529 int string::compare(size_type pos, size_type n, string const & str,
1530                        size_type pos2, size_type n2) const
1531 {
1532         Assert(pos <= rep->sz); // OURS!
1533         Assert(pos2 <= str.rep->sz); // OURS!
1534         TeststringInvariant(this);
1535         return internal_compare(pos, n,
1536                                 str.rep->s + pos2,
1537                                 str.rep->sz - pos2, n2);
1538 }
1539
1540
1541 int string::compare(size_type pos, size_type n, value_type const * s,
1542                        size_type n2) const
1543 {
1544         Assert(s && pos <= rep->sz); // OURS!
1545         TeststringInvariant(this);
1546         return internal_compare(pos, n, s, (!s) ? 0 : strlen(s), n2);
1547 }
1548
1549
1550 /////////////////
1551 // Substrings
1552 /////////////////
1553
1554 // i = index, n = length
1555 string string::substr(size_type i, size_type n) const
1556 {
1557         Assert(i <= rep->sz); // STD!
1558         TeststringInvariant(this);
1559
1560         return string(*this, i, n);
1561 }
1562
1563
1564 /////////////////////////////////////////////
1565 // String operators, non member functions
1566 /////////////////////////////////////////////
1567
1568 bool operator==(string const & a, string const & b)
1569 {
1570         return a.compare(b) == 0;
1571 }
1572
1573
1574 bool operator==(string::value_type const * a, string const & b)
1575 {
1576         Assert(a); // OURS!
1577         return b.compare(a) == 0;
1578 }
1579
1580
1581 bool operator==(string const & a, string::value_type const * b)
1582 {
1583         Assert(b); // OURS!
1584         return a.compare(b) == 0;
1585 }
1586
1587
1588 bool operator!=(string const & a, string const & b)
1589 {
1590         return a.compare(b) != 0;
1591 }
1592
1593
1594 bool operator!=(string::value_type const * a, string const & b)
1595 {
1596         Assert(a); // OURS!
1597         return b.compare(a) != 0;
1598 }
1599
1600
1601 bool operator!=(string const & a, string::value_type const * b)
1602 {
1603         Assert(b); // OURS!
1604         return a.compare(b) != 0;
1605 }
1606
1607
1608 bool operator>(string const & a, string const & b)
1609 {
1610         return a.compare(b) > 0;
1611 }
1612
1613
1614 bool operator>(string::value_type const * a, string const & b)
1615 {
1616         Assert(a); // OURS!
1617         return b.compare(a) < 0; // since we reverse the parameters
1618 }
1619
1620
1621 bool operator>(string const & a, string::value_type const * b)
1622 {
1623         Assert(b); // OURS!
1624         return a.compare(b) > 0;
1625 }
1626
1627
1628 bool operator<(string const & a, string const & b)
1629 {
1630         return a.compare(b) < 0;
1631 }
1632
1633
1634 bool operator<(string::value_type const * a, string const & b)
1635 {
1636         Assert(a); // OURS!
1637         return b.compare(a) > 0; // since we reverse the parameters
1638 }
1639
1640
1641 bool operator<(string const & a, string::value_type const * b)
1642 {
1643         Assert(b); // OURS!
1644         return a.compare(b) < 0;
1645 }
1646
1647
1648 bool operator>=(string const & a, string const & b)
1649 {
1650         return a.compare(b) >= 0;
1651 }
1652
1653
1654 bool operator>=(string::value_type const * a, string const & b)
1655 {
1656         Assert(a); // OURS!
1657         return b.compare(a) <= 0; // since we reverse the parameters
1658 }
1659
1660
1661 bool operator>=(string const & a, string::value_type const * b)
1662 {
1663         Assert(b); // OURS!
1664         return a.compare(b) >= 0;
1665 }
1666
1667
1668 bool operator<=(string const & a, string const & b)
1669 {
1670         return a.compare(b) <= 0;
1671 }
1672
1673
1674 bool operator<=(string::value_type const * a, string const & b)
1675 {
1676         Assert(a); // OURS!
1677         return b.compare(a) >= 0; // since we reverse the parameters
1678 }
1679
1680
1681 bool operator<=(string const & a, string::value_type const * b)
1682 {
1683         Assert(b); // OURS!
1684         return a.compare(b) <= 0;
1685 }
1686
1687
1688 string operator+(string const & a, string const & b)
1689 {
1690         string tmp(a);
1691         tmp += b;
1692         return tmp;
1693 }
1694
1695
1696 string operator+(string::value_type const * a, string const & b)
1697 {
1698         Assert(a); // OURS!
1699         string tmp(a);
1700         tmp += b;
1701         return tmp;
1702 }
1703
1704
1705 string operator+(string::value_type a, string const & b)
1706 {
1707         string tmp;
1708         tmp += a;
1709         tmp += b;
1710         return tmp;
1711 }
1712
1713
1714 string operator+(string const & a, string::value_type const * b)
1715 {
1716         Assert(b); // OURS!
1717         string tmp(a);
1718         tmp += b;
1719         return tmp;
1720 }
1721
1722
1723 string operator+(string const & a, string::value_type b)
1724 {
1725         string tmp(a);
1726         tmp += b;
1727         return tmp;
1728 }
1729
1730
1731 void swap(string & str1, string & str2)
1732 {
1733         str1.swap(str2);
1734 }
1735
1736
1737 istream & operator>>(istream & is, string & s)
1738 {
1739 #if 0
1740         // very bad solution
1741         char * nome = new char[1024];
1742         is >> nome;
1743         string tmp(nome);
1744         delete [] nome;
1745         if (!tmp.empty()) s = tmp;
1746 #else
1747         // better solution
1748         int w = is.width(0);
1749         s.clear();
1750         char c = 0;
1751         bool skipspace = true;
1752         while (is.get(c)) {
1753                 if (isspace(c)) {
1754                         if (!skipspace) {
1755                                 is.putback(c);
1756                                 break;
1757                         }
1758                 } else {
1759                         s += c;
1760                         skipspace = false;
1761                 }
1762                 if (--w == 1) break;
1763         }
1764         if (s.empty()) is.setstate(std::ios::failbit);
1765 #endif
1766         return is;
1767 }
1768
1769
1770 ostream & operator<<(ostream & o, string const & s)
1771 {
1772         return o.write(s.data(), s.length());
1773 }
1774
1775
1776 istream & getline(istream & is, string & s,
1777                   string::value_type delim)
1778 {
1779         // very bad solution
1780         char tmp = 0;
1781         s.erase();
1782         while (is) {
1783                 is.get(tmp);
1784                 if (tmp != delim) {
1785                         s += tmp;
1786                 } else {
1787                         break;
1788                 }
1789         }
1790         return is;
1791 }
1792
1793 } // namespace lyx
1794
1795 #ifdef TEST_MAIN
1796 int main() {
1797         lyx::string a = "abcac";
1798         cout << a.rfind("ab") << endl;
1799         cout << a.rfind("c") << endl;
1800         cout << a.rfind("d") << endl;
1801 }
1802 #endif