5d2cc88beb25f618baf14f1db25258e4ab8e0ef5
[ardour.git] / libs / backends / wavesaudio / wavesapi / MiscUtils / WCFixedString.h
1 /*
2     Copyright (C) 2014 Waves Audio Ltd.
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifndef __WCFixedString_h__
21         #define __WCFixedString_h__
22
23 /* Copy to include.
24 #include "WCFixedString.h"
25 */
26 // do not #include anything else here but standard C++ library files, this file should be free from any and all depandencies
27 // do not put any DEBUG_s or TRACE_s in this file, since it is used in BgkConsole functions
28
29 #include <algorithm>
30 #include <cctype>
31 #include <cstring>
32 #include <cstdio>
33
34 #ifdef __APPLE__
35 #include <strings.h>
36 #endif
37
38 #include "BasicTypes/WUDefines.h"
39 #include "BasicTypes/WTByteOrder.h"
40 #include "WavesPublicAPI/wstdint.h"
41 #include "MiscUtils/MinMaxUtilities.h"
42
43 // use this macro instead of std :: string to mark the that use of std :: string could not be replaced
44 // by WFixedString.
45 #define std_string_approved std::string
46
47 #ifdef __POSIX__
48 const char* const kStrNewLine = "\n";
49 #endif
50 #ifdef PLATFORM_WINDOWS
51 const char* const kStrNewLine = "\r\n";
52 #endif
53
54 class DllExport WCFixedStringBase
55 {
56 public:
57     typedef size_t pos_t;
58     typedef intptr_t spos_t; // signed position, defined to intptr_t because Windows does not have ssize_t
59         static const pos_t npos = UINTPTR_MAX; // Same as size_max
60
61         WCFixedStringBase(char* const in_begin, const size_t in_MaxFixedStringLength) : 
62                 m_begin(in_begin),
63                 m_MaxFixedStringLength(in_MaxFixedStringLength),
64                 m_end(in_begin)
65         {
66                 *m_end = '\0';
67         }
68
69         inline WCFixedStringBase& operator=(const WCFixedStringBase& in_fixedStrToAssign)
70         {
71                 if (this != &in_fixedStrToAssign)
72                 {
73                         clear();
74                         operator<<(in_fixedStrToAssign);
75                 }
76
77                 return *this;
78         }
79
80         inline WCFixedStringBase& operator=(const char* in_CStrToAssign)
81         {
82                 clear();
83                 operator<<(in_CStrToAssign);
84
85                 return *this;
86         }
87
88         inline WCFixedStringBase& operator=(const char in_charToAssign)
89         {
90                 clear();
91                 operator<<(in_charToAssign);
92
93                 return *this;
94         }
95
96         char operator[](const pos_t in_index) const
97         {
98                 if (in_index < m_MaxFixedStringLength)
99                         return m_begin[in_index];
100                 else
101                         return m_begin[m_MaxFixedStringLength]; // in_index was too big
102         }
103
104         char& operator[](const pos_t in_index)
105         {
106                 if (in_index < m_MaxFixedStringLength)
107                         return m_begin[in_index];
108                 else
109                         return m_begin[m_MaxFixedStringLength]; // in_index was too big
110         }
111
112         inline size_t resize(const size_t in_newSize)
113         {
114                 m_end = m_begin + WUMin<size_t>(in_newSize, m_MaxFixedStringLength);
115                 *m_end = '\0';
116                 return size();
117         }
118
119         size_t max_size()
120         {
121                 return m_MaxFixedStringLength;
122         }
123
124         size_t capacity()
125         {
126                 return m_MaxFixedStringLength;
127         }
128
129
130         inline char * peek()
131         {
132                 return m_begin;
133         }
134
135         inline const char * c_str() const
136         {
137                 *m_end = '\0';
138                 return m_begin;
139         }
140
141         inline void clear()
142         {
143                 m_end = m_begin;
144                 *m_end = '\0';
145         }
146
147         inline size_t size() const
148         {
149                 return m_end - m_begin;
150         }
151
152     inline char* begin() const
153     {
154         return m_begin;
155     }
156
157     inline char* end() const
158     {
159         return m_end;
160     }
161
162         inline size_t length() const
163         {
164                 return size();
165         }
166
167         inline bool empty() const
168         {
169                 return m_begin == m_end;
170         }
171
172         inline void reverse(char* in_left, char* in_right)
173         {
174                 char* left = in_left;
175                 char* right = in_right;
176                 while (left < right)
177                 {
178                         char temp = *--right;
179                         *right = *left;
180                         *left++ = temp;
181                 }
182         }
183
184         inline void reverse()
185         {
186                 reverse(m_begin, m_end);
187         }
188
189         inline void to_lower()
190         {
191                 char* pToDo = m_begin;
192
193                 while (pToDo < m_end)
194                 {
195                         *pToDo = static_cast<char>(std::tolower(*pToDo));
196                         ++pToDo;
197                 }
198         }
199
200         inline void to_upper()
201         {
202                 char* pToDo = m_begin;
203
204                 while (pToDo < m_end)
205                 {
206                         *pToDo = static_cast<char>(std::toupper(*pToDo));
207                         ++pToDo;
208                 }
209         }
210
211         // append a single char in_count times
212         inline void append(const char in_charToAppend, const size_t in_count)
213         {
214                 size_t counter = 0;
215                 while ((m_end < m_begin+m_MaxFixedStringLength) && counter++ < in_count)
216                         *m_end++ = in_charToAppend;
217 #if kEnableDebug == 1
218                 if (counter < in_count)    // if there wasn't enough room for some appended chars
219                 {
220                         m_begin[0] = '@';       // mark the string as overflowed
221                 }
222 #endif
223                 *m_end = '\0';
224         }
225
226         inline void append(const char* in_chars)
227         {
228                 operator<<(in_chars);
229         }
230
231         // append "iterator style"
232         inline void append(const char* in_chars_begin, const char* in_chars_end)
233         {
234                 const char* curr_char = in_chars_begin;
235                 while ((m_end < m_begin+m_MaxFixedStringLength) && curr_char < in_chars_end && *curr_char != '\0')
236                         *m_end++ = *curr_char++;
237
238 #if kEnableDebug == 1
239                 if (curr_char < in_chars_end)   // if there wasn't enough room for some appended chars
240                 {
241                         m_begin[0] = '@';           // mark the string as overflowed
242                 }
243 #endif
244                 *m_end = '\0';
245         }
246
247         // append from a char* in_count chars, (no \0 is required to terminate the input string)
248         inline void append(const char* in_chars_begin, const size_t in_count)
249         {
250                 append(in_chars_begin, in_chars_begin + in_count);
251         }
252
253         // assign from a char* in_count chars, (no \0 is required to terminate the input string)
254         inline void assign(const char* in_chars_begin, const size_t in_count)
255         {
256                 clear();
257                 append(in_chars_begin, in_chars_begin + in_count);
258         }
259
260         // assign from a char* , (a \0 is required to terminate the input string)
261         inline void assign(const char* in_chars_ptr)
262         {
263                 clear();
264                 operator<<(in_chars_ptr);
265         }
266
267     // assign from a char* to a char*
268     inline void assign(const char* in_begin, const char* in_end)
269     {
270         assign(in_begin, size_t(in_end - in_begin));
271     }
272
273         inline void append_double_with_precision(const double in_double, const int in_precision)
274         {
275                 const unsigned int tempBufSize = 32;
276                 char buf[tempBufSize];
277
278         #ifdef PLATFORM_WINDOWS
279                 _snprintf_s(buf, tempBufSize, tempBufSize - 1, "%.*f", in_precision, in_double);
280         #endif
281         #ifdef __APPLE__
282                 std::snprintf(buf, tempBufSize, "%.*f", in_precision, in_double);
283         #endif          
284         #ifdef __linux__        
285                 snprintf(buf, tempBufSize, "%.*f", in_precision, in_double);
286         #endif          
287
288                 operator<<(buf);
289         }
290
291         inline void append_uint(const uint64_t in_uint, const int_fast16_t in_base = 10)
292         {
293                 uint_fast64_t num = in_uint;
294
295                 char* lasr_char_before = m_end;
296
297                 do {
298                         char  remainder(static_cast<char>(num % in_base));
299
300                         if ( remainder < 10 )
301                                 operator<<(char(remainder + '0'));
302                         else
303                                 operator<<(char(remainder - 10 + 'A'));
304
305                         num /= in_base;
306                 } while (num != 0);
307
308                 reverse(lasr_char_before, m_end);
309         }
310
311         inline void append_hex_binary(const uint8_t* in_binary, const size_t in_size)
312         {
313                 static const char hexdigits[] = "0123456789ABCDEF";
314
315 #if _BYTEORDER_BIG_ENDIAN==1
316                 for (size_t ibyte = 0; ibyte < in_size; ++ibyte)
317 #elif _BYTEORDER_BIG_ENDIAN==0
318                         for (size_t ibyte = in_size; ibyte > 0; --ibyte)
319 #endif
320                         {
321                                 operator<<(hexdigits[in_binary[ibyte - 1] >> 4]);
322                                 operator<<(hexdigits[in_binary[ibyte - 1] & 0x0F]);
323                         }
324         }
325
326         inline WCFixedStringBase& operator<<(const char in_charToAppend)
327         {
328                 if (m_end < m_begin+m_MaxFixedStringLength)
329                         *m_end++ = in_charToAppend;
330 #if kEnableDebug == 1
331                 else                    // if there wasn't enough room for the appended char
332                 {
333                         m_begin[0] = '@'; // mark the string as overflowed
334                 }
335 #endif
336
337                 *m_end = '\0';
338
339                 return *this;
340         }
341
342         inline WCFixedStringBase& operator<<(const char* const in_strToAppend)
343         {
344                 if (0 != in_strToAppend)
345                 {
346                         const char* pSource = in_strToAppend;
347
348                         while (*pSource != '\0' && m_end < m_begin+m_MaxFixedStringLength)
349                                 *m_end++ = *pSource++;
350
351 #if kEnableDebug == 1
352                         if (*pSource != '\0')   // if there wasn't enough room for some appended chars
353                         {
354                                 m_begin[0] = '@';  // mark the string as overflowed
355                         }
356 #endif
357                         *m_end = '\0';
358                 }
359
360                 return *this;
361         }
362
363         WCFixedStringBase& operator<<(const uint64_t in_uint)
364         {
365                 append_uint(in_uint, 10);
366
367                 return *this;
368         }
369
370
371         // Warning prevention: the operator<< function overload for unsigneds used to create lots
372     // of warnings once size_t usage was becoming widespread. So for each OS we define only
373     // those overloads that are actually needed. On Windows 32 bit we still get
374         // 'warning C4267: 'argument' : conversion from 'size_t' to 'const unsigned int', possible loss of data'
375         // warning which we do not know how to solve yet. The function DummyFunctionsForWarningTest
376     // in file WCFixedStringStream.cpp calls all combinations of operator<<(unsigned something)
377     // And should produce no warnings - (except the C4267 on windows).
378 #if defined(__APPLE__) // both 32 & 64 bit
379         WCFixedStringBase& operator<<(const size_t in_uint) {
380                 return operator<<(static_cast<unsigned long long>(in_uint));
381         }
382 #endif
383 //      WCFixedStringBase& operator<<(const unsigned char in_uint) {
384 //              return operator<<(static_cast<const unsigned long long>(in_uint));
385 //              }
386 //              
387 //      WCFixedStringBase& operator<<(const size_t in_uint) {
388 //              return operator<<(static_cast<const uint64_t>(in_uint));
389 //              }
390 //              
391 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS) || defined(__linux__) // both 32 & 64 bit
392         WCFixedStringBase& operator<<(const unsigned int in_uint) {
393                 return operator<<(static_cast<uint64_t>(in_uint));
394         }
395 #endif
396 //              
397 #if defined(PLATFORM_WINDOWS) || defined(__linux__) // both 32 & 64 bit
398         WCFixedStringBase& operator<<(const unsigned long in_uint) {
399                 return operator<<(static_cast<uint64_t>(in_uint));
400         }
401 #endif
402
403         WCFixedStringBase& operator<<(const long long in_int)
404         {
405                 if (in_int < 0)
406                         operator<<('-');
407 #ifdef PLATFORM_WINDOWS
408 //        uintmax_t unsigned_in_num = _abs64(in_int);
409                 uintmax_t unsigned_in_num = in_int < 0 ? static_cast<uintmax_t>(-in_int) : static_cast<uintmax_t>(in_int);
410 #else
411                 uintmax_t unsigned_in_num = std::abs(in_int);
412 #endif
413                 append_uint(unsigned_in_num, 10);
414
415                 return *this;
416         }
417
418         WCFixedStringBase& operator<<(const short in_int) {
419                 return operator<<(static_cast<int64_t>(in_int));
420         }
421
422         WCFixedStringBase& operator<<(const int in_int) {
423                 return operator<<(static_cast<int64_t>(in_int));
424         }
425
426         WCFixedStringBase& operator<<(const long in_int) {
427                 return operator<<(static_cast<int64_t>(in_int));
428         }
429
430         WCFixedStringBase& operator<<(const double in_doubleToWrite)
431         {
432                 append_double_with_precision(in_doubleToWrite, 10);
433
434                 return *this;
435         }
436
437         WCFixedStringBase& operator<<(const float in_floatToWrite)
438         {
439                 append_double_with_precision(double(in_floatToWrite), 5);
440
441                 return *this;
442         }
443
444         inline WCFixedStringBase& operator<<(const WCFixedStringBase& in_fixedStrToAppend)
445         {
446                 operator<<(in_fixedStrToAppend.c_str());
447
448                 return *this;
449         }
450
451         WCFixedStringBase& operator<< (bool abool)
452         {
453                 return abool ? operator<<("true") : operator<<("false");
454         }
455
456         template<typename T> WCFixedStringBase& operator+=(T in_type)
457         {
458                 return operator<<(in_type);
459         }
460
461         ptrdiff_t compare(const char* in_to_compare) const
462         {
463                 ptrdiff_t retVal = 1;
464
465                 if (0 != in_to_compare)
466                 {
467                         retVal =  strcmp(c_str(), in_to_compare);
468                 }
469
470                 return retVal;
471         }
472
473
474         ptrdiff_t compare(const WCFixedStringBase& in_to_compare) const
475         {
476                 ptrdiff_t retVal = compare(in_to_compare.c_str());              
477                 return retVal;
478         }
479
480         ptrdiff_t case_insensitive_compare(const char* in_to_compare) const
481         {
482                 ptrdiff_t retVal = 1;
483
484                 if (0 != in_to_compare)
485                 {
486 #ifdef PLATFORM_WINDOWS
487                         retVal = _stricmp(c_str(), in_to_compare);
488 #endif
489 #if defined(__linux__) || defined(__APPLE__)
490                         retVal =  strcasecmp(c_str(), in_to_compare);
491 #endif
492                 }
493
494                 return retVal;
495         }
496
497         ptrdiff_t case_insensitive_compare(const WCFixedStringBase& in_to_compare) const
498         {
499                 ptrdiff_t retVal = case_insensitive_compare(in_to_compare.c_str());             
500                 return retVal;
501         }
502
503         pos_t find(const char in_char_to_find) const
504         {
505                 const char* pCurrChar = m_begin;
506                 while (pCurrChar < m_end && *pCurrChar != in_char_to_find)
507                         ++pCurrChar;
508
509                 return (pCurrChar < m_end) ? (pCurrChar - m_begin) : npos;
510         }
511
512     pos_t rfind(const char in_char_to_find) const
513     {
514         pos_t retVal = npos;
515         const char* pCurrChar = m_end;
516
517         while (pCurrChar != m_begin)
518         {
519             --pCurrChar;
520             if (*pCurrChar == in_char_to_find)
521             {
522                 retVal = pCurrChar - m_begin;
523                 break;
524             }
525         }
526
527         return retVal;
528     }
529
530         pos_t find(const char* in_chars_to_find, const pos_t in_start_from = 0) const
531         {
532                 pos_t retVal = npos;
533                 size_t to_find_size = ::strlen(in_chars_to_find);
534
535                 if (to_find_size > 0 && to_find_size <= size() && in_start_from < size())
536                 {
537                         const char* pCurrChar = m_begin + in_start_from;
538                         while ((m_end - pCurrChar) >= (ptrdiff_t)to_find_size)
539                         {
540                                 int found = ::memcmp(pCurrChar, in_chars_to_find, to_find_size);
541                                 if (0 == found)
542                                 {
543                                         retVal = (pCurrChar - m_begin);
544                                         break;
545                                 }
546
547                                 ++pCurrChar;
548                         }
549                 }
550
551                 return retVal;
552         }
553
554         pos_t rfind(const char* in_chars_to_find) const
555         {
556                 pos_t retVal = npos;
557                 size_t to_find_size = ::strlen(in_chars_to_find);
558
559                 if (to_find_size > 0 && to_find_size <= size())
560                 {
561                         const char* pCurrChar = m_end - to_find_size;
562                         while (m_begin <= pCurrChar)
563                         {
564                                 int found = ::memcmp(pCurrChar, in_chars_to_find, to_find_size);
565                                 if (0 == found)
566                                 {
567                                         retVal = (pCurrChar - m_begin);
568                                         break;
569                                 }
570
571                                 --pCurrChar;
572                         }
573                 }
574
575                 return retVal;
576         }
577
578         pos_t find_case_insensitive(const char* in_chars_to_find, const pos_t in_start_from = 0) const
579         {
580                 pos_t retVal = npos;
581                 size_t to_find_size = ::strlen(in_chars_to_find);
582
583                 if (to_find_size > 0 && to_find_size <= size() && in_start_from < size())
584                 {
585                         const char* pCurrChar = m_begin + in_start_from;
586                         while ((m_end - pCurrChar) >= (ptrdiff_t)to_find_size)
587                         {
588                 size_t i;
589                 for (i = 0; i < to_find_size; ++i)
590                 {
591                         if (tolower(*(pCurrChar+i)) != tolower(in_chars_to_find[i]))
592                         break;
593                 }
594
595                                 if (i == to_find_size)
596                                 {
597                                         retVal = (pCurrChar - m_begin);
598                                         break;
599                                 }
600
601                                 ++pCurrChar;
602                         }
603                 }
604
605                 return retVal;
606         }
607
608         pos_t find_first_of(const char* in_possibe_chars_to_find, const pos_t in_start_from = 0) const
609         {
610                 pos_t retVal = npos;
611
612                 if (in_start_from < size())
613                 {
614                         const char* pFoundChar = strpbrk(m_begin + in_start_from, in_possibe_chars_to_find);
615                         if (0 != pFoundChar)
616                         {
617                                 retVal = (pFoundChar - m_begin);
618                         }
619                 }
620
621                 return retVal;
622         }
623
624         pos_t find_last_of(const char* in_possibe_chars_to_find, const pos_t in_start_from = 0) const
625         {
626                 pos_t retVal = npos;
627
628                 pos_t curr_location = in_start_from;
629
630                 while (size() > curr_location)
631                 {
632                         pos_t found = find_first_of(in_possibe_chars_to_find, curr_location);
633                         if (npos != found)
634                         {
635                                 retVal = found;
636                                 curr_location = found + 1;
637                         }
638                         else
639                                 break;
640                 }
641
642                 return retVal;
643         }
644
645         pos_t find_first_not_of(const char* in_acceptable_chars, const pos_t in_start_from = 0) const
646         {
647                 pos_t retVal = npos;
648
649                 if (in_start_from < size())
650                 {
651                         retVal = (strspn(m_begin + in_start_from, in_acceptable_chars));
652                         if (size() <= retVal + in_start_from)
653                         {
654                                 retVal = npos;
655                         }
656                         else
657                         {
658                                 retVal += in_start_from;
659                         }
660                 }
661
662                 return retVal;
663         }
664
665         pos_t find_last_not_of(const char* in_acceptable_chars, const pos_t in_start_from = 0) const
666         {
667                 pos_t retVal = npos;
668
669                 pos_t curr_location = in_start_from;
670
671                 while (size() > curr_location)
672                 {
673                         pos_t found = find_first_not_of(in_acceptable_chars, curr_location);
674                         if (npos != found)
675                         {
676                                 retVal = found;
677                                 curr_location = found + 1;
678                         }
679                         else
680                                 break;
681                 }
682
683                 return retVal;
684         }
685
686         // return true if in_begin_text is found at position 0 OR if in_begin_text is empty
687         bool begins_with(const char* in_begin_text) const
688     {
689         pos_t where = find(in_begin_text, 0);
690         bool retVal = (0 == where) || (0 == ::strlen(in_begin_text));
691         return retVal;
692     }
693         
694     // return true if in_end_text is found at th end OR if in_end_text is empty
695         bool ends_with(const char* in_end_text) const
696     {
697         pos_t where = rfind(in_end_text);
698         bool retVal = ((size() - strlen(in_end_text)) == where) || (0 == ::strlen(in_end_text));
699         return retVal;
700     }
701
702         size_t replace(const char in_look_for, const char in_replace_with)
703         {
704                 size_t retVal = 0;
705
706                 char* pCurrChar = m_begin;
707                 while (pCurrChar < m_end)
708                 {
709                         if (*pCurrChar == in_look_for)
710                         {
711                                 *pCurrChar = in_replace_with;
712                                 ++retVal;
713                         }
714             ++pCurrChar;
715                 }
716
717                 return retVal;
718         }
719
720     // erase in_size chars starting from in_location
721         void erase(const pos_t in_location, const size_t in_num_chars = 1)
722         {
723                 if (size() > in_location && in_num_chars > 0)
724                 {
725                         size_t actual_num_chars = WUMin(in_num_chars, size_t(size() - in_location));
726                         char* pTo = m_begin + in_location;
727                         char* pFrom = pTo + actual_num_chars;
728
729                         while (pFrom < m_end)
730                                 *pTo++ = *pFrom++;
731
732                         resize(size() - actual_num_chars);
733                 }
734         }
735
736     // erase any char that appear in in_forbidden_chars
737         void erase_all_of(const char* in_forbidden_chars)
738         {
739                 pos_t curr_location = 0;
740
741                 while (npos != curr_location)
742                 {
743                         curr_location = find_first_of(in_forbidden_chars, curr_location);
744                         if (npos != curr_location)
745                                 erase(curr_location);
746                 }
747         }
748
749     // erase any char that do not appear in in_allowed_chars
750         void erase_all_not_of(const char* in_allowed_chars)
751         {
752                 pos_t curr_location = 0;
753
754                 while (npos != curr_location)
755                 {
756                         curr_location = find_first_not_of(in_allowed_chars, curr_location);
757                         if (npos != curr_location)
758                                 erase(curr_location);
759                 }
760         }
761
762         //! Copy the content of fixed string to a buffer appending a '\0' at the end.
763     //! If in_buffer_size is more than the allocated buffer size memory over write will happen!
764         void copy_to_buffer(const size_t in_buffer_size, char* out_buffer)
765     {
766         if (in_buffer_size > 0 && 0 != out_buffer)
767         {
768             char* cur_buffer = out_buffer;
769             const char* cur_fixed = m_begin;
770             const char* end_buffer = out_buffer + (WUMin<size_t>(in_buffer_size - 1, m_end - m_begin));
771             while (cur_buffer < end_buffer)
772                 *cur_buffer++ = *cur_fixed++;
773
774             *cur_buffer = '\0';
775         }
776     }
777
778 protected:      
779         ~WCFixedStringBase() {}
780
781         char* const m_begin;
782         const size_t m_MaxFixedStringLength;
783         char* m_end;
784
785 private:
786         WCFixedStringBase();
787         WCFixedStringBase(const WCFixedStringBase& in_fixedStrToCopy);
788 #if 0
789         :
790         m_begin(in_fixedStrToCopy.m_begin),
791         m_MaxFixedStringLength(in_fixedStrToCopy.m_MaxFixedStringLength),
792         m_end(in_fixedStrToCopy.m_end)
793         {
794         }
795 #endif
796 };
797
798 template<size_t kMaxFixedStringLength> class DllExport WCFixedString : public WCFixedStringBase
799 {
800 public:
801
802         inline WCFixedString() :
803                 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
804         {
805         }
806
807         inline  WCFixedString(const char* const in_strToAssign) :
808                 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
809         {
810                 operator<<(in_strToAssign);
811         }
812
813         inline  WCFixedString(const WCFixedStringBase& in_fixedStrToAssign) :
814                 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
815         {
816                 operator<<(in_fixedStrToAssign);
817         }
818
819         inline  WCFixedString(const WCFixedString& in_fixedStrToAssign) :
820                 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
821         {
822                 operator<<(in_fixedStrToAssign);
823         }
824
825         inline  WCFixedString(const char in_char, const size_t in_count = 1) :
826                 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
827         {
828                 append(in_char, in_count);
829         }
830
831         inline  WCFixedString(const char* in_chars, const size_t in_count) :
832                 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
833         {
834                 append(in_chars, in_count);
835         }
836
837     // substr now supports negative in_length, which means "from the end" so
838     // "abcdefg".substr(1, -1) == "bcdef"
839         inline const WCFixedString substr(const pos_t in_pos = 0, const spos_t in_length = kMaxFixedStringLength) const
840         {
841                 pos_t adjusted_pos = WUMin<size_t>(in_pos, size());
842         size_t adjusted_length = 0;
843         if (in_length < 0)
844         {
845                 adjusted_length = size_t(WUMax<spos_t>(0, spos_t(size() - adjusted_pos) + in_length));
846         }
847         else
848                 adjusted_length = WUMin<size_t>(in_length, size() - adjusted_pos);
849
850                 WCFixedString retVal;
851                 retVal.append(m_begin + adjusted_pos, adjusted_length);
852
853                 return retVal;
854         }
855
856 protected:      
857
858         char m_fixedString[kMaxFixedStringLength + 1]; // the "+ 1" is so that *m_end is always valid, and we can put the '\0' there};
859 };
860
861 inline bool operator==(const WCFixedStringBase& in_left, const WCFixedStringBase& in_right)     
862 {
863         return 0 == in_left.compare(in_right.c_str());
864 }
865
866 inline bool operator==(const WCFixedStringBase& in_left, const char* const in_right)
867 {
868         return 0 == in_left.compare(in_right);
869 }
870
871 inline bool operator!=(const WCFixedStringBase& in_left, const WCFixedStringBase& in_right)     
872 {
873         return 0 != in_left.compare(in_right.c_str());
874 }
875
876 inline bool operator!=(const WCFixedStringBase& in_left, const char* const in_right)
877 {
878         return 0 != in_left.compare(in_right);
879 }
880
881 // class WCFixedStringBase
882 typedef WCFixedString<4>        WCFixedString4;
883 typedef WCFixedString<15>       WCFixedString15;
884 typedef WCFixedString<31>       WCFixedString31;
885 typedef WCFixedString<63>       WCFixedString63;
886 typedef WCFixedString<127>      WCFixedString127;
887 typedef WCFixedString<255>      WCFixedString255;
888 typedef WCFixedString<511>      WCFixedString511;
889 typedef WCFixedString<1023>     WCFixedString1023;
890 typedef WCFixedString<2047>     WCFixedString2047;
891
892 template<size_t kSizeOfFirst, size_t kSizeOfSecond>
893         class WCFixedStringPair : public std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >
894 {
895 public:
896         WCFixedStringPair(const char* const in_firstStr = 0, const char* const in_secondStr = 0) :      
897         std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
898         WCFixedStringPair(const WCFixedStringBase& in_firstStr, const char* const in_secondStr = 0) :   
899         std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
900         WCFixedStringPair(const WCFixedStringBase& in_firstStr, const WCFixedStringBase& in_secondStr) :        
901         std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
902 };
903
904 #endif  //  #ifndef __WCFixedString_h__