2 Copyright (C) 2013 Waves Audio Ltd.
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.
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.
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.
19 #ifndef __WCFixedString_h__
20 #define __WCFixedString_h__
23 #include "WCFixedString.h"
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
37 #include "BasicTypes/WUDefines.h"
38 #include "BasicTypes/WTByteOrder.h"
39 #include "WavesPublicAPI/wstdint.h"
40 #include "MiscUtils/MinMaxUtilities.h"
42 // use this macro instead of std :: string to mark the that use of std :: string could not be replaced
44 #define std_string_approved std::string
47 const char* const kStrNewLine = "\n";
50 const char* const kStrNewLine = "\r\n";
53 class DllExport WCFixedStringBase
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
60 WCFixedStringBase(char* const in_begin, const size_t in_MaxFixedStringLength) :
62 m_MaxFixedStringLength(in_MaxFixedStringLength),
68 inline WCFixedStringBase& operator=(const WCFixedStringBase& in_fixedStrToAssign)
70 if (this != &in_fixedStrToAssign)
73 operator<<(in_fixedStrToAssign);
79 inline WCFixedStringBase& operator=(const char* in_CStrToAssign)
82 operator<<(in_CStrToAssign);
87 inline WCFixedStringBase& operator=(const char in_charToAssign)
90 operator<<(in_charToAssign);
95 char operator[](const pos_t in_index) const
97 if (in_index < m_MaxFixedStringLength)
98 return m_begin[in_index];
100 return m_begin[m_MaxFixedStringLength]; // in_index was too big
103 char& operator[](const pos_t in_index)
105 if (in_index < m_MaxFixedStringLength)
106 return m_begin[in_index];
108 return m_begin[m_MaxFixedStringLength]; // in_index was too big
111 inline size_t resize(const size_t in_newSize)
113 m_end = m_begin + WUMin<size_t>(in_newSize, m_MaxFixedStringLength);
120 return m_MaxFixedStringLength;
125 return m_MaxFixedStringLength;
134 inline const char * c_str() const
146 inline size_t size() const
148 return m_end - m_begin;
151 inline char* begin() const
156 inline char* end() const
161 inline size_t length() const
166 inline bool empty() const
168 return m_begin == m_end;
171 inline void reverse(char* in_left, char* in_right)
173 char* left = in_left;
174 char* right = in_right;
177 char temp = *--right;
183 inline void reverse()
185 reverse(m_begin, m_end);
188 inline void to_lower()
190 char* pToDo = m_begin;
192 while (pToDo < m_end)
194 *pToDo = static_cast<char>(std::tolower(*pToDo));
199 inline void to_upper()
201 char* pToDo = m_begin;
203 while (pToDo < m_end)
205 *pToDo = static_cast<char>(std::toupper(*pToDo));
210 // append a single char in_count times
211 inline void append(const char in_charToAppend, const size_t in_count)
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
219 m_begin[0] = '@'; // mark the string as overflowed
225 inline void append(const char* in_chars)
227 operator<<(in_chars);
230 // append "iterator style"
231 inline void append(const char* in_chars_begin, const char* in_chars_end)
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++;
237 #if kEnableDebug == 1
238 if (curr_char < in_chars_end) // if there wasn't enough room for some appended chars
240 m_begin[0] = '@'; // mark the string as overflowed
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)
249 append(in_chars_begin, in_chars_begin + in_count);
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)
256 append(in_chars_begin, in_chars_begin + in_count);
259 // assign from a char* , (a \0 is required to terminate the input string)
260 inline void assign(const char* in_chars_ptr)
263 operator<<(in_chars_ptr);
266 // assign from a char* to a char*
267 inline void assign(const char* in_begin, const char* in_end)
269 assign(in_begin, size_t(in_end - in_begin));
272 inline void append_double_with_precision(const double in_double, const int in_precision)
274 const unsigned int tempBufSize = 32;
275 char buf[tempBufSize];
278 _snprintf_s(buf, tempBufSize, tempBufSize - 1, "%.*f", in_precision, in_double);
281 std::snprintf(buf, tempBufSize, "%.*f", in_precision, in_double);
284 snprintf(buf, tempBufSize, "%.*f", in_precision, in_double);
290 inline void append_uint(const uint64_t in_uint, const int_fast16_t in_base = 10)
292 uint_fast64_t num = in_uint;
294 char* lasr_char_before = m_end;
297 char remainder(static_cast<char>(num % in_base));
299 if ( remainder < 10 )
300 operator<<(char(remainder + '0'));
302 operator<<(char(remainder - 10 + 'A'));
307 reverse(lasr_char_before, m_end);
310 inline void append_hex_binary(const uint8_t* in_binary, const size_t in_size)
312 static const char hexdigits[] = "0123456789ABCDEF";
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)
320 operator<<(hexdigits[in_binary[ibyte - 1] >> 4]);
321 operator<<(hexdigits[in_binary[ibyte - 1] & 0x0F]);
325 inline WCFixedStringBase& operator<<(const char in_charToAppend)
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
332 m_begin[0] = '@'; // mark the string as overflowed
341 inline WCFixedStringBase& operator<<(const char* const in_strToAppend)
343 if (0 != in_strToAppend)
345 const char* pSource = in_strToAppend;
347 while (*pSource != '\0' && m_end < m_begin+m_MaxFixedStringLength)
348 *m_end++ = *pSource++;
350 #if kEnableDebug == 1
351 if (*pSource != '\0') // if there wasn't enough room for some appended chars
353 m_begin[0] = '@'; // mark the string as overflowed
362 WCFixedStringBase& operator<<(const uint64_t in_uint)
364 append_uint(in_uint, 10);
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));
382 // WCFixedStringBase& operator<<(const unsigned char in_uint) {
383 // return operator<<(static_cast<const unsigned long long>(in_uint));
386 // WCFixedStringBase& operator<<(const size_t in_uint) {
387 // return operator<<(static_cast<const uint64_t>(in_uint));
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));
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));
402 WCFixedStringBase& operator<<(const long long in_int)
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);
410 uintmax_t unsigned_in_num = std::abs(in_int);
412 append_uint(unsigned_in_num, 10);
417 WCFixedStringBase& operator<<(const short in_int) {
418 return operator<<(static_cast<int64_t>(in_int));
421 WCFixedStringBase& operator<<(const int in_int) {
422 return operator<<(static_cast<int64_t>(in_int));
425 WCFixedStringBase& operator<<(const long in_int) {
426 return operator<<(static_cast<int64_t>(in_int));
429 WCFixedStringBase& operator<<(const double in_doubleToWrite)
431 append_double_with_precision(in_doubleToWrite, 10);
436 WCFixedStringBase& operator<<(const float in_floatToWrite)
438 append_double_with_precision(double(in_floatToWrite), 5);
443 inline WCFixedStringBase& operator<<(const WCFixedStringBase& in_fixedStrToAppend)
445 operator<<(in_fixedStrToAppend.c_str());
450 WCFixedStringBase& operator<< (bool abool)
452 return abool ? operator<<("true") : operator<<("false");
455 template<typename T> WCFixedStringBase& operator+=(T in_type)
457 return operator<<(in_type);
460 ptrdiff_t compare(const char* in_to_compare) const
462 ptrdiff_t retVal = 1;
464 if (0 != in_to_compare)
466 retVal = strcmp(c_str(), in_to_compare);
473 ptrdiff_t compare(const WCFixedStringBase& in_to_compare) const
475 ptrdiff_t retVal = compare(in_to_compare.c_str());
479 ptrdiff_t case_insensitive_compare(const char* in_to_compare) const
481 ptrdiff_t retVal = 1;
483 if (0 != in_to_compare)
486 retVal = _stricmp(c_str(), in_to_compare);
488 #if defined(__linux__) || defined(__MACOS__)
489 retVal = strcasecmp(c_str(), in_to_compare);
496 ptrdiff_t case_insensitive_compare(const WCFixedStringBase& in_to_compare) const
498 ptrdiff_t retVal = case_insensitive_compare(in_to_compare.c_str());
502 pos_t find(const char in_char_to_find) const
504 const char* pCurrChar = m_begin;
505 while (pCurrChar < m_end && *pCurrChar != in_char_to_find)
508 return (pCurrChar < m_end) ? (pCurrChar - m_begin) : npos;
511 pos_t rfind(const char in_char_to_find) const
514 const char* pCurrChar = m_end;
516 while (pCurrChar != m_begin)
519 if (*pCurrChar == in_char_to_find)
521 retVal = pCurrChar - m_begin;
529 pos_t find(const char* in_chars_to_find, const pos_t in_start_from = 0) const
532 size_t to_find_size = ::strlen(in_chars_to_find);
534 if (to_find_size > 0 && to_find_size <= size() && in_start_from < size())
536 const char* pCurrChar = m_begin + in_start_from;
537 while ((m_end - pCurrChar) >= (ptrdiff_t)to_find_size)
539 int found = ::memcmp(pCurrChar, in_chars_to_find, to_find_size);
542 retVal = (pCurrChar - m_begin);
553 pos_t rfind(const char* in_chars_to_find) const
556 size_t to_find_size = ::strlen(in_chars_to_find);
558 if (to_find_size > 0 && to_find_size <= size())
560 const char* pCurrChar = m_end - to_find_size;
561 while (m_begin <= pCurrChar)
563 int found = ::memcmp(pCurrChar, in_chars_to_find, to_find_size);
566 retVal = (pCurrChar - m_begin);
577 pos_t find_case_insensitive(const char* in_chars_to_find, const pos_t in_start_from = 0) const
580 size_t to_find_size = ::strlen(in_chars_to_find);
582 if (to_find_size > 0 && to_find_size <= size() && in_start_from < size())
584 const char* pCurrChar = m_begin + in_start_from;
585 while ((m_end - pCurrChar) >= (ptrdiff_t)to_find_size)
588 for (i = 0; i < to_find_size; ++i)
590 if (tolower(*(pCurrChar+i)) != tolower(in_chars_to_find[i]))
594 if (i == to_find_size)
596 retVal = (pCurrChar - m_begin);
607 pos_t find_first_of(const char* in_possibe_chars_to_find, const pos_t in_start_from = 0) const
611 if (in_start_from < size())
613 const char* pFoundChar = strpbrk(m_begin + in_start_from, in_possibe_chars_to_find);
616 retVal = (pFoundChar - m_begin);
623 pos_t find_last_of(const char* in_possibe_chars_to_find, const pos_t in_start_from = 0) const
627 pos_t curr_location = in_start_from;
629 while (size() > curr_location)
631 pos_t found = find_first_of(in_possibe_chars_to_find, curr_location);
635 curr_location = found + 1;
644 pos_t find_first_not_of(const char* in_acceptable_chars, const pos_t in_start_from = 0) const
648 if (in_start_from < size())
650 retVal = (strspn(m_begin + in_start_from, in_acceptable_chars));
651 if (size() <= retVal + in_start_from)
657 retVal += in_start_from;
664 pos_t find_last_not_of(const char* in_acceptable_chars, const pos_t in_start_from = 0) const
668 pos_t curr_location = in_start_from;
670 while (size() > curr_location)
672 pos_t found = find_first_not_of(in_acceptable_chars, curr_location);
676 curr_location = found + 1;
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
688 pos_t where = find(in_begin_text, 0);
689 bool retVal = (0 == where) || (0 == ::strlen(in_begin_text));
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
696 pos_t where = rfind(in_end_text);
697 bool retVal = ((size() - strlen(in_end_text)) == where) || (0 == ::strlen(in_end_text));
701 size_t replace(const char in_look_for, const char in_replace_with)
705 char* pCurrChar = m_begin;
706 while (pCurrChar < m_end)
708 if (*pCurrChar == in_look_for)
710 *pCurrChar = in_replace_with;
719 // erase in_size chars starting from in_location
720 void erase(const pos_t in_location, const size_t in_num_chars = 1)
722 if (size() > in_location && in_num_chars > 0)
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;
728 while (pFrom < m_end)
731 resize(size() - actual_num_chars);
735 // erase any char that appear in in_forbidden_chars
736 void erase_all_of(const char* in_forbidden_chars)
738 pos_t curr_location = 0;
740 while (npos != curr_location)
742 curr_location = find_first_of(in_forbidden_chars, curr_location);
743 if (npos != curr_location)
744 erase(curr_location);
748 // erase any char that do not appear in in_allowed_chars
749 void erase_all_not_of(const char* in_allowed_chars)
751 pos_t curr_location = 0;
753 while (npos != curr_location)
755 curr_location = find_first_not_of(in_allowed_chars, curr_location);
756 if (npos != curr_location)
757 erase(curr_location);
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)
765 if (in_buffer_size > 0 && 0 != out_buffer)
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++;
778 ~WCFixedStringBase() {}
781 const size_t m_MaxFixedStringLength;
786 WCFixedStringBase(const WCFixedStringBase& in_fixedStrToCopy);
789 m_begin(in_fixedStrToCopy.m_begin),
790 m_MaxFixedStringLength(in_fixedStrToCopy.m_MaxFixedStringLength),
791 m_end(in_fixedStrToCopy.m_end)
797 template<size_t kMaxFixedStringLength> class DllExport WCFixedString : public WCFixedStringBase
801 inline WCFixedString() :
802 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
806 inline WCFixedString(const char* const in_strToAssign) :
807 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
809 operator<<(in_strToAssign);
812 inline WCFixedString(const WCFixedStringBase& in_fixedStrToAssign) :
813 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
815 operator<<(in_fixedStrToAssign);
818 inline WCFixedString(const WCFixedString& in_fixedStrToAssign) :
819 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
821 operator<<(in_fixedStrToAssign);
824 inline WCFixedString(const char in_char, const size_t in_count = 1) :
825 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
827 append(in_char, in_count);
830 inline WCFixedString(const char* in_chars, const size_t in_count) :
831 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
833 append(in_chars, in_count);
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
840 pos_t adjusted_pos = WUMin<size_t>(in_pos, size());
841 size_t adjusted_length = 0;
844 adjusted_length = size_t(WUMax<spos_t>(0, spos_t(size() - adjusted_pos) + in_length));
847 adjusted_length = WUMin<size_t>(in_length, size() - adjusted_pos);
849 WCFixedString retVal;
850 retVal.append(m_begin + adjusted_pos, adjusted_length);
857 char m_fixedString[kMaxFixedStringLength + 1]; // the "+ 1" is so that *m_end is always valid, and we can put the '\0' there};
860 inline bool operator==(const WCFixedStringBase& in_left, const WCFixedStringBase& in_right)
862 return 0 == in_left.compare(in_right.c_str());
865 inline bool operator==(const WCFixedStringBase& in_left, const char* const in_right)
867 return 0 == in_left.compare(in_right);
870 inline bool operator!=(const WCFixedStringBase& in_left, const WCFixedStringBase& in_right)
872 return 0 != in_left.compare(in_right.c_str());
875 inline bool operator!=(const WCFixedStringBase& in_left, const char* const in_right)
877 return 0 != in_left.compare(in_right);
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;
891 template<size_t kSizeOfFirst, size_t kSizeOfSecond>
892 class WCFixedStringPair : public std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >
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) {}
903 #endif // #ifndef __WCFixedString_h__