1/*
2 * PROGRAM: string class definition
3 * MODULE: fb_string.h
4 * DESCRIPTION: Provides almost that same functionality,
5 * that STL::basic_string<char> does,
6 * but behaves MemoryPools friendly.
7 *
8 * The contents of this file are subject to the Initial
9 * Developer's Public License Version 1.0 (the "License");
10 * you may not use this file except in compliance with the
11 * License. You may obtain a copy of the License at
12 * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
13 *
14 * Software distributed under the License is distributed AS IS,
15 * WITHOUT WARRANTY OF ANY KIND, either express or implied.
16 * See the License for the specific language governing rights
17 * and limitations under the License.
18 *
19 * The Original Code was created by Alexander Peshkoff
20 * for the Firebird Open Source RDBMS project.
21 *
22 * Copyright (c) 2004 Alexander Peshkoff <peshkoff@mail.ru>
23 * and all contributors signed below.
24 *
25 * All Rights Reserved.
26 * Contributor(s): ______________________________________.
27 */
28
29#ifndef INCLUDE_FB_STRING_H
30#define INCLUDE_FB_STRING_H
31
32#include <stdio.h>
33#include <string.h>
34#include <stdarg.h>
35
36#include "firebird.h"
37#include "fb_types.h"
38#include "fb_exception.h"
39#include "../common/classes/alloc.h"
40#include "../common/classes/RefCounted.h"
41
42namespace Firebird
43{
44 class AbstractString : private AutoStorage
45 {
46 public:
47 typedef char char_type;
48 typedef size_t size_type;
49 typedef ptrdiff_t difference_type;
50 typedef char* pointer;
51 typedef const char* const_pointer;
52 typedef char& reference;
53 typedef const char& const_reference;
54 typedef char value_type;
55 typedef pointer iterator;
56 typedef const_pointer const_iterator;
57 static const size_type npos;
58 enum {INLINE_BUFFER_SIZE = 32, INIT_RESERVE = 16/*, KEEP_SIZE = 512*/};
59
60 protected:
61 typedef ULONG internal_size_type; // 32 bits!
62
63 private:
64 const internal_size_type max_length;
65
66 protected:
67 char_type inlineBuffer[INLINE_BUFFER_SIZE];
68 char_type* stringBuffer;
69 internal_size_type stringLength, bufferSize;
70
71 private:
72 void checkPos(size_type pos) const
73 {
74 if (pos >= length()) {
75 fatal_exception::raise("Firebird::string - pos out of range");
76 }
77 }
78
79 void checkLength(size_type len)
80 {
81 if (len > getMaxLength()) {
82 fatal_exception::raise("Firebird::string - length exceeds predefined limit");
83 }
84 }
85
86 // Reserve buffer to allow storing at least newLen characters there
87 // (not including null terminator). Existing contents of our string are preserved.
88 void reserveBuffer(const size_type newLen)
89 {
90 size_type newSize = newLen + 1;
91 fb_assert(newSize != 0); // This large argument would be a programming error for sure.
92 if (newSize > bufferSize)
93 {
94 // Make sure we do not exceed string length limit
95 checkLength(newLen);
96
97 // Order of assignments below is important in case of low memory conditions
98
99 // Grow buffer exponentially to prevent memory fragmentation
100 if (newSize / 2 < bufferSize)
101 newSize = size_t(bufferSize) * 2u;
102
103 // Do not grow buffer beyond string length limit
104 size_type max_length = getMaxLength() + 1;
105 if (newSize > max_length)
106 newSize = max_length;
107
108 // Allocate new buffer
109 char_type *newBuffer = FB_NEW(getPool()) char_type[newSize];
110
111 // Carefully copy string data including null terminator
112 memcpy(newBuffer, stringBuffer, sizeof(char_type) * (stringLength + 1u));
113
114 // Deallocate old buffer if needed
115 if (stringBuffer != inlineBuffer)
116 delete[] stringBuffer;
117
118 stringBuffer = newBuffer;
119 bufferSize = static_cast<internal_size_type>(newSize);
120 }
121 }
122
123 // Make sure our buffer is large enough to store at least <length> characters in it
124 // (not including null terminator). Resulting buffer is not initialized.
125 // Use it in constructors only when stringBuffer is not assigned yet.
126 void initialize(const size_type len)
127 {
128 if (len < INLINE_BUFFER_SIZE)
129 {
130 stringBuffer = inlineBuffer;
131 bufferSize = INLINE_BUFFER_SIZE;
132 }
133 else
134 {
135 stringBuffer = NULL; // Be safe in case of exception
136 checkLength(len);
137
138 // Reserve a few extra bytes in the buffer
139 size_type newSize = len + 1 + INIT_RESERVE;
140
141 // Do not grow buffer beyond string length limit
142 size_type max_length = getMaxLength() + 1;
143 if (newSize > max_length)
144 newSize = max_length;
145
146 // Allocate new buffer
147 stringBuffer = FB_NEW(getPool()) char_type[newSize];
148 bufferSize = static_cast<internal_size_type>(newSize);
149 }
150 stringLength = static_cast<internal_size_type>(len);
151 stringBuffer[stringLength] = 0;
152 }
153
154 void shrinkBuffer()
155 {
156 // Shrink buffer if we decide it is beneficial
157 }
158
159 protected:
160 AbstractString(const size_type limit, const size_type sizeL, const void* datap);
161
162 AbstractString(const size_type limit, const_pointer p1, const size_type n1,
163 const_pointer p2, const size_type n2);
164
165 AbstractString(const size_type limit, const AbstractString& v);
166
167 explicit AbstractString(const size_type limit) :
168 max_length(static_cast<internal_size_type>(limit)),
169 stringBuffer(inlineBuffer), stringLength(0), bufferSize(INLINE_BUFFER_SIZE)
170 {
171 stringBuffer[0] = 0;
172 }
173
174 AbstractString(const size_type limit, const size_type sizeL, char_type c);
175
176 AbstractString(const size_type limit, MemoryPool& p) : AutoStorage(p),
177 max_length(static_cast<internal_size_type>(limit)),
178 stringBuffer(inlineBuffer), stringLength(0), bufferSize(INLINE_BUFFER_SIZE)
179 {
180 stringBuffer[0] = 0;
181 }
182
183 AbstractString(const size_type limit, MemoryPool& p, const AbstractString& v)
184 : AutoStorage(p), max_length(static_cast<internal_size_type>(limit))
185 {
186 initialize(v.length());
187 memcpy(stringBuffer, v.c_str(), stringLength);
188 }
189
190 AbstractString(const size_type limit, MemoryPool& p, const void* s, const size_type l)
191 : AutoStorage(p), max_length(static_cast<internal_size_type>(limit))
192 {
193 initialize(l);
194 memcpy(stringBuffer, s, l);
195 }
196
197 pointer modify()
198 {
199 return stringBuffer;
200 }
201
202 // Trim the range making sure that it fits inside specified length
203 static void adjustRange(const size_type length, size_type& pos, size_type& n);
204
205 pointer baseAssign(const size_type n);
206
207 pointer baseAppend(const size_type n);
208
209 pointer baseInsert(const size_type p0, const size_type n);
210
211 void baseErase(size_type p0, size_type n);
212
213 enum TrimType {TrimLeft, TrimRight, TrimBoth};
214
215 void baseTrim(const TrimType whereTrim, const_pointer toTrim);
216
217 size_type getMaxLength() const
218 {
219 return max_length;
220 }
221
222 public:
223 const_pointer c_str() const
224 {
225 return stringBuffer;
226 }
227 size_type length() const
228 {
229 return stringLength;
230 }
231 size_type getCount() const
232 {
233 return stringLength;
234 }
235 // Almost same as c_str(), but return 0, not "",
236 // when string has no data. Useful when interacting
237 // with old code, which does check for NULL.
238 const_pointer nullStr() const
239 {
240 return stringLength ? stringBuffer : 0;
241 }
242 // Call it only when you have worked with at() or operator[]
243 // in case a null ASCII was inserted in the middle of the string.
244 size_type recalculate_length()
245 {
246 stringLength = static_cast<internal_size_type>(strlen(stringBuffer));
247 return stringLength;
248 }
249
250 void reserve(size_type n = 0);
251 void resize(const size_type n, char_type c = ' ');
252 void grow(const size_type n)
253 {
254 resize(n);
255 }
256
257 pointer getBuffer(size_t l)
258 {
259 return baseAssign(l);
260 }
261
262 size_type find(const AbstractString& str, size_type pos = 0) const
263 {
264 return find(str.c_str(), pos);
265 }
266 size_type find(const_pointer s, size_type pos = 0) const
267 {
268 const_pointer p = strstr(c_str() + pos, s);
269 return p ? p - c_str() : npos;
270 }
271 size_type find(char_type c, size_type pos = 0) const
272 {
273 const_pointer p = strchr(c_str() + pos, c);
274 return p ? p - c_str() : npos;
275 }
276 size_type rfind(const AbstractString& str, size_type pos = npos) const
277 {
278 return rfind(str.c_str(), pos);
279 }
280 size_type rfind(const_pointer s, const size_type pos = npos) const;
281 size_type rfind(char_type c, const size_type pos = npos) const;
282 size_type find_first_of(const AbstractString& str, size_type pos = 0) const
283 {
284 return find_first_of(str.c_str(), pos, str.length());
285 }
286 size_type find_first_of(const_pointer s, size_type pos, size_type n) const;
287 size_type find_first_of(const_pointer s, size_type pos = 0) const
288 {
289 return find_first_of(s, pos, strlen(s));
290 }
291 size_type find_first_of(char_type c, size_type pos = 0) const
292 {
293 return find(c, pos);
294 }
295 size_type find_last_of(const AbstractString& str, size_type pos = npos) const
296 {
297 return find_last_of(str.c_str(), pos, str.length());
298 }
299 size_type find_last_of(const_pointer s, const size_type pos, size_type n = npos) const;
300 size_type find_last_of(const_pointer s, size_type pos = npos) const
301 {
302 return find_last_of(s, pos, strlen(s));
303 }
304 size_type find_last_of(char_type c, size_type pos = npos) const
305 {
306 return rfind(c, pos);
307 }
308 size_type find_first_not_of(const AbstractString& str, size_type pos = 0) const
309 {
310 return find_first_not_of(str.c_str(), pos, str.length());
311 }
312 size_type find_first_not_of(const_pointer s, size_type pos, size_type n) const;
313 size_type find_first_not_of(const_pointer s, size_type pos = 0) const
314 {
315 return find_first_not_of(s, pos, strlen(s));
316 }
317 size_type find_first_not_of(char_type c, size_type pos = 0) const
318 {
319 const char_type s[2] = {c, 0};
320 return find_first_not_of(s, pos, 1);
321 }
322 size_type find_last_not_of(const AbstractString& str, size_type pos = npos) const
323 {
324 return find_last_not_of(str.c_str(), pos, str.length());
325 }
326 size_type find_last_not_of(const_pointer s, const size_type pos, size_type n = npos) const;
327 size_type find_last_not_of(const_pointer s, size_type pos = npos) const
328 {
329 return find_last_not_of(s, pos, strlen(s));
330 }
331 size_type find_last_not_of(char_type c, size_type pos = npos) const
332 {
333 const char_type s[2] = {c, 0};
334 return find_last_not_of(s, pos, 1);
335 }
336
337 iterator begin()
338 {
339 return modify();
340 }
341 const_iterator begin() const
342 {
343 return c_str();
344 }
345 iterator end()
346 {
347 return modify() + length();
348 }
349 const_iterator end() const
350 {
351 return c_str() + length();
352 }
353 const_reference at(const size_type pos) const
354 {
355 checkPos(pos);
356 return c_str()[pos];
357 }
358 reference at(const size_type pos)
359 {
360 checkPos(pos);
361 return modify()[pos];
362 }
363 const_reference operator[](size_type pos) const
364 {
365 return at(pos);
366 }
367 reference operator[](size_type pos)
368 {
369 return at(pos);
370 }
371 const_pointer data() const
372 {
373 return c_str();
374 }
375 size_type size() const
376 {
377 return length();
378 }
379 size_type capacity() const
380 {
381 return bufferSize - 1u;
382 }
383 bool empty() const
384 {
385 return length() == 0;
386 }
387 bool hasData() const
388 {
389 return !empty();
390 }
391 // to satisfy both ways to check for empty string
392 bool isEmpty() const
393 {
394 return empty();
395 }
396
397 void upper();
398 void lower();
399 void ltrim(const_pointer ToTrim = " ")
400 {
401 baseTrim(TrimLeft, ToTrim);
402 }
403 void rtrim(const_pointer ToTrim = " ")
404 {
405 baseTrim(TrimRight, ToTrim);
406 }
407 void trim(const_pointer ToTrim = " ")
408 {
409 baseTrim(TrimBoth, ToTrim);
410 }
411 void alltrim(const_pointer ToTrim = " ")
412 {
413 baseTrim(TrimBoth, ToTrim);
414 }
415
416 bool LoadFromFile(FILE* file);
417 void vprintf(const char* Format, va_list params);
418 void printf(const char* Format, ...);
419
420 size_type copyTo(pointer to, size_type toSize) const
421 {
422 fb_assert(to);
423 fb_assert(toSize);
424 if (--toSize > length())
425 {
426 toSize = length();
427 }
428 memcpy(to, c_str(), toSize);
429 to[toSize] = 0;
430 return toSize;
431 }
432
433 static unsigned int hash(const_pointer string, const size_type tableSize);
434
435 unsigned int hash(size_type tableSize) const
436 {
437 return hash(c_str(), tableSize);
438 }
439
440 bool equalsNoCase(const_pointer string) const;
441
442 AbstractString& append(const AbstractString& str)
443 {
444 fb_assert(&str != this);
445 return append(str.c_str(), str.length());
446 }
447 AbstractString& append(const AbstractString& str, size_type pos, size_type n)
448 {
449 fb_assert(&str != this);
450 adjustRange(str.length(), pos, n);
451 return append(str.c_str() + pos, n);
452 }
453 AbstractString& append(const_pointer s, const size_type n)
454 {
455 memcpy(baseAppend(n), s, n);
456 return *this;
457 }
458 AbstractString& append(const_pointer s)
459 {
460 return append(s, strlen(s));
461 }
462 AbstractString& append(size_type n, char_type c)
463 {
464 memset(baseAppend(n), c, n);
465 return *this;
466 }
467 AbstractString& append(const_iterator first, const_iterator last)
468 {
469 return append(first, last - first);
470 }
471
472 AbstractString& insert(size_type p0, const AbstractString& str)
473 {
474 fb_assert(&str != this);
475 return insert(p0, str.c_str(), str.length());
476 }
477 AbstractString& insert(size_type p0, const AbstractString& str, size_type pos,
478 size_type n)
479 {
480 fb_assert(&str != this);
481 adjustRange(str.length(), pos, n);
482 return insert(p0, &str.c_str()[pos], n);
483 }
484 AbstractString& insert(size_type p0, const_pointer s, const size_type n)
485 {
486 if (p0 >= length()) {
487 return append(s, n);
488 }
489 memcpy(baseInsert(p0, n), s, n);
490 return *this;
491 }
492 AbstractString& insert(size_type p0, const_pointer s)
493 {
494 return insert(p0, s, strlen(s));
495 }
496 AbstractString& insert(size_type p0, const size_type n, const char_type c)
497 {
498 if (p0 >= length()) {
499 return append(n, c);
500 }
501 memset(baseInsert(p0, n), c, n);
502 return *this;
503 }
504 // iterator insert(iterator it, char_type c); // what to return here?
505 void insert(iterator it, size_type n, char_type c)
506 {
507 insert(it - c_str(), n, c);
508 }
509 void insert(iterator it, const_iterator first, const_iterator last)
510 {
511 insert(it - c_str(), first, last - first);
512 }
513
514 AbstractString& erase(size_type p0 = 0, size_type n = npos)
515 {
516 baseErase(p0, n);
517 return *this;
518 }
519 iterator erase(iterator it)
520 {
521 erase(it - c_str(), 1);
522 return it;
523 }
524 iterator erase(iterator first, iterator last)
525 {
526 erase(first - c_str(), last - first);
527 return first;
528 }
529
530 AbstractString& replace(size_type p0, size_type n0, const AbstractString& str)
531 {
532 fb_assert(&str != this);
533 return replace(p0, n0, str.c_str(), str.length());
534 }
535 AbstractString& replace(const size_type p0, const size_type n0,
536 const AbstractString& str, size_type pos, size_type n)
537 {
538 fb_assert(&str != this);
539 adjustRange(str.length(), pos, n);
540 return replace(p0, n0, &str.c_str()[pos], n);
541 }
542 AbstractString& replace(const size_type p0, const size_type n0, const_pointer s,
543 size_type n)
544 {
545 erase(p0, n0);
546 return insert(p0, s, n);
547 }
548 AbstractString& replace(size_type p0, size_type n0, const_pointer s)
549 {
550 return replace(p0, n0, s, strlen(s));
551 }
552 AbstractString& replace(const size_type p0, const size_type n0, size_type n,
553 char_type c)
554 {
555 erase(p0, n0);
556 return insert(p0, n, c);
557 }
558 AbstractString& replace(iterator first0, iterator last0, const AbstractString& str)
559 {
560 fb_assert(&str != this);
561 return replace(first0 - c_str(), last0 - first0, str);
562 }
563 AbstractString& replace(iterator first0, iterator last0, const_pointer s,
564 size_type n)
565 {
566 return replace(first0 - c_str(), last0 - first0, s, n);
567 }
568 AbstractString& replace(iterator first0, iterator last0, const_pointer s)
569 {
570 return replace(first0 - c_str(), last0 - first0, s);
571 }
572 AbstractString& replace(iterator first0, iterator last0, size_type n, char_type c)
573 {
574 return replace(first0 - c_str(), last0 - first0, n, c);
575 }
576 AbstractString& replace(iterator first0, iterator last0, const_iterator first,
577 const_iterator last)
578 {
579 return replace(first0 - c_str(), last0 - first0, first, last - first);
580 }
581
582 ~AbstractString()
583 {
584 if (stringBuffer != inlineBuffer)
585 delete[] stringBuffer;
586 }
587 };
588
589 class StringComparator
590 {
591 public:
592 static int compare(AbstractString::const_pointer s1,
593 AbstractString::const_pointer s2,
594 const AbstractString::size_type n)
595 {
596 return memcmp(s1, s2, n);
597 }
598
599 static AbstractString::size_type getMaxLength()
600 {
601 return 0xFFFFFFFEu;
602 }
603 };
604
605 class PathNameComparator
606 {
607 public:
608 static int compare(AbstractString::const_pointer s1,
609 AbstractString::const_pointer s2,
610 const AbstractString::size_type n);
611
612 static AbstractString::size_type getMaxLength()
613 {
614 return 0xFFFEu;
615 }
616 };
617
618 class IgnoreCaseComparator
619 {
620 public:
621 static int compare(AbstractString::const_pointer s1,
622 AbstractString::const_pointer s2,
623 const AbstractString::size_type n);
624
625 static AbstractString::size_type getMaxLength()
626 {
627 return 0xFFFFFFFEu;
628 }
629 };
630
631 template<typename Comparator>
632 class StringBase : public AbstractString
633 {
634 typedef StringBase StringType;
635 protected:
636 StringBase(const_pointer p1, size_type n1,
637 const_pointer p2, size_type n2) :
638 AbstractString(Comparator::getMaxLength(), p1, n1, p2, n2) {}
639 private:
640 StringType add(const_pointer s, size_type n) const
641 {
642 return StringBase<Comparator>(c_str(), length(), s, n);
643 }
644 public:
645 StringBase() : AbstractString(Comparator::getMaxLength()) {}
646 StringBase(const StringType& v) : AbstractString(Comparator::getMaxLength(), v) {}
647 StringBase(const void* s, size_type n) : AbstractString(Comparator::getMaxLength(), n, s) {}
648 StringBase(const_pointer s) : AbstractString(Comparator::getMaxLength(), strlen(s), s) {}
649 explicit StringBase(const unsigned char* s) :
650 AbstractString(Comparator::getMaxLength(), strlen((char*)s), (char*)s) {}
651 StringBase(size_type n, char_type c) : AbstractString(Comparator::getMaxLength(), n, c) {}
652 StringBase(const_iterator first, const_iterator last) :
653 AbstractString(Comparator::getMaxLength(), last - first, first) {}
654 explicit StringBase(MemoryPool& p) : AbstractString(Comparator::getMaxLength(), p) {}
655 StringBase(MemoryPool& p, const AbstractString& v) : AbstractString(Comparator::getMaxLength(), p, v) {}
656 StringBase(MemoryPool& p, const char_type* s, size_type l) :
657 AbstractString(Comparator::getMaxLength(), p, s, l) {}
658
659 static size_type max_length()
660 {
661 return Comparator::getMaxLength();
662 }
663
664 StringType& assign(const StringType& str)
665 {
666 fb_assert(&str != this);
667 return assign(str.c_str(), str.length());
668 }
669 StringType& assign(const StringType& str, size_type pos, size_type n)
670 {
671 fb_assert(&str != this);
672 adjustRange(str.length(), pos, n);
673 return assign(&str.c_str()[pos], n);
674 }
675 StringType& assign(const void* s, size_type n)
676 {
677 memcpy(baseAssign(n), s, n);
678 return *this;
679 }
680 StringType& assign(const_pointer s)
681 {
682 return assign(s, strlen(s));
683 }
684 StringType& assign(size_type n, char_type c)
685 {
686 memset(baseAssign(n), c, n);
687 return *this;
688 }
689 StringType& assign(const_iterator first, const_iterator last)
690 {
691 return assign(first, last - first);
692 }
693
694 StringType& operator=(const StringType& v)
695 {
696 if (&v == this)
697 return *this;
698 return assign(v);
699 }
700 StringType& operator=(const_pointer s)
701 {
702 return assign(s, strlen(s));
703 }
704 StringType& operator=(char_type c)
705 {
706 return assign(&c, 1);
707 }
708 StringType& operator+=(const StringType& v)
709 {
710 fb_assert(&v != this);
711 append(v);
712 return *this;
713 }
714 StringType& operator+=(const_pointer s)
715 {
716 append(s);
717 return *this;
718 }
719 StringType& operator+=(char_type c)
720 {
721 append(1, c);
722 return *this;
723 }
724 StringType operator+(const StringType& v) const
725 {
726 return add(v.c_str(), v.length());
727 }
728 StringType operator+(const_pointer s) const
729 {
730 return add(s, strlen(s));
731 }
732 StringType operator+(char_type c) const
733 {
734 return add(&c, 1);
735 }
736
737 StringBase<StringComparator> ToString() const
738 {
739 return StringBase<StringComparator>(c_str());
740 }
741 StringBase<PathNameComparator> ToPathName() const
742 {
743 return StringBase<PathNameComparator>(c_str());
744 }
745 StringBase<IgnoreCaseComparator> ToNoCaseString() const
746 {
747 return StringBase<IgnoreCaseComparator>(c_str());
748 }
749
750 StringType substr(size_type pos = 0, size_type n = npos) const
751 {
752 adjustRange(length(), pos, n);
753 return StringType(&c_str()[pos], n);
754 }
755 int compare(const StringType& str) const
756 {
757 return compare(str.c_str(), str.length());
758 }
759 int compare(size_type p0, size_type n0, const StringType& str)
760 {
761 return compare(p0, n0, str.c_str(), str.length());
762 }
763 int compare(size_type p0, size_type n0, const StringType& str, size_type pos, size_type n)
764 {
765 adjustRange(str.length(), pos, n);
766 return compare(p0, n0, &str.c_str()[pos], n);
767 }
768 int compare(const_pointer s) const
769 {
770 return compare(s, strlen(s));
771 }
772 int compare(size_type p0, size_type n0, const_pointer s, const size_type n) const
773 {
774 adjustRange(length(), p0, n0);
775 const size_type ml = n0 < n ? n0 : n;
776 const int rc = Comparator::compare(&c_str()[p0], s, ml);
777 return rc ? rc : n0 - n;
778 }
779 int compare(const_pointer s, const size_type n) const
780 {
781 const size_type ml = length() < n ? length() : n;
782 const int rc = Comparator::compare(c_str(), s, ml);
783 if (rc)
784 {
785 return rc;
786 }
787 const difference_type dl = length() - n;
788 return (dl < 0) ? -1 : (dl > 0) ? 1 : 0;
789 }
790
791 // These four functions are to speed up the most common comparisons: equality and inequality.
792 bool equals(const StringType& str) const
793 {
794 const size_type n = str.length();
795 return (length() != n) ? false : (Comparator::compare(c_str(), str.c_str(), n) == 0);
796 }
797 bool different(const StringType& str) const
798 {
799 const size_type n = str.length();
800 return (length() != n) ? true : (Comparator::compare(c_str(), str.c_str(), n) != 0);
801 }
802 bool equals(const_pointer s) const
803 {
804 const size_type n = strlen(s);
805 return (length() != n) ? false : (Comparator::compare(c_str(), s, n) == 0);
806 }
807 bool different(const_pointer s) const
808 {
809 const size_type n = strlen(s);
810 return (length() != n) ? true : (Comparator::compare(c_str(), s, n) != 0);
811 }
812
813 bool operator< (const StringType& str) const {return compare(str) < 0;}
814 bool operator<=(const StringType& str) const {return compare(str) <= 0;}
815 bool operator==(const StringType& str) const {return equals(str);}
816 bool operator>=(const StringType& str) const {return compare(str) >= 0;}
817 bool operator> (const StringType& str) const {return compare(str) > 0;}
818 bool operator!=(const StringType& str) const {return different(str);}
819
820 bool operator< (const char_type* str) const {return compare(str) < 0;}
821 bool operator<=(const char_type* str) const {return compare(str) <= 0;}
822 bool operator==(const char_type* str) const {return equals(str);}
823 bool operator>=(const char_type* str) const {return compare(str) >= 0;}
824 bool operator> (const char_type* str) const {return compare(str) > 0;}
825 bool operator!=(const char_type* str) const {return different(str);}
826 };
827
828 typedef StringBase<StringComparator> string;
829 static inline string operator+(string::const_pointer s, const string& str)
830 {
831 string rc(s);
832 rc += str;
833 return rc;
834 }
835 static inline string operator+(string::char_type c, const string& str)
836 {
837 string rc(1, c);
838 rc += str;
839 return rc;
840 }
841
842 typedef StringBase<PathNameComparator> PathName;
843 static inline PathName operator+(PathName::const_pointer s, const PathName& str)
844 {
845 PathName rc(s);
846 rc += str;
847 return rc;
848 }
849 static inline PathName operator+(PathName::char_type c, const PathName& str)
850 {
851 PathName rc(1, c);
852 rc += str;
853 return rc;
854 }
855
856 typedef StringBase<IgnoreCaseComparator> NoCaseString;
857 static inline NoCaseString operator+(NoCaseString::const_pointer s, const NoCaseString& str)
858 {
859 NoCaseString rc(s);
860 rc += str;
861 return rc;
862 }
863 static inline NoCaseString operator+(NoCaseString::char_type c, const NoCaseString& str)
864 {
865 NoCaseString rc(1, c);
866 rc += str;
867 return rc;
868 }
869
870 // reference-counted strings
871 typedef AnyRef<string> RefString;
872 typedef RefPtr<RefString> RefStrPtr;
873}
874
875
876#endif // INCLUDE_FB_STRING_H
877