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