1 #ifndef __WCFixedString_h__
2 #define __WCFixedString_h__
5 #include "WCFixedString.h"
7 // do not #include anything else here but standard C++ library files, this file should be free from any and all depandencies
8 // do not put any DEBUG_s or TRACE_s in this file, since it is used in BgkConsole functions
19 #include "BasicTypes/WUDefines.h"
20 #include "BasicTypes/WTByteOrder.h"
21 #include "WavesPublicAPI/wstdint.h"
22 #include "MiscUtils/MinMaxUtilities.h"
24 // use this macro instead of std :: string to mark the that use of std :: string could not be replaced
26 #define std_string_approved std::string
29 const char* const kStrNewLine = "\n";
32 const char* const kStrNewLine = "\r\n";
35 class DllExport WCFixedStringBase
39 typedef intptr_t spos_t; // signed position, defined to intptr_t because Windows does not have ssize_t
40 static const pos_t npos = UINTPTR_MAX; // Same as size_max
42 WCFixedStringBase(char* const in_begin, const size_t in_MaxFixedStringLength) :
44 m_MaxFixedStringLength(in_MaxFixedStringLength),
50 inline WCFixedStringBase& operator=(const WCFixedStringBase& in_fixedStrToAssign)
52 if (this != &in_fixedStrToAssign)
55 operator<<(in_fixedStrToAssign);
61 inline WCFixedStringBase& operator=(const char* in_CStrToAssign)
64 operator<<(in_CStrToAssign);
69 inline WCFixedStringBase& operator=(const char in_charToAssign)
72 operator<<(in_charToAssign);
77 char operator[](const pos_t in_index) const
79 if (in_index < m_MaxFixedStringLength)
80 return m_begin[in_index];
82 return m_begin[m_MaxFixedStringLength]; // in_index was too big
85 char& operator[](const pos_t in_index)
87 if (in_index < m_MaxFixedStringLength)
88 return m_begin[in_index];
90 return m_begin[m_MaxFixedStringLength]; // in_index was too big
93 inline size_t resize(const size_t in_newSize)
95 m_end = m_begin + WUMin<size_t>(in_newSize, m_MaxFixedStringLength);
102 return m_MaxFixedStringLength;
107 return m_MaxFixedStringLength;
116 inline const char * c_str() const
128 inline size_t size() const
130 return m_end - m_begin;
133 inline char* begin() const
138 inline char* end() const
143 inline size_t length() const
148 inline bool empty() const
150 return m_begin == m_end;
153 inline void reverse(char* in_left, char* in_right)
155 char* left = in_left;
156 char* right = in_right;
159 char temp = *--right;
165 inline void reverse()
167 reverse(m_begin, m_end);
170 inline void to_lower()
172 char* pToDo = m_begin;
174 while (pToDo < m_end)
176 *pToDo = static_cast<char>(std::tolower(*pToDo));
181 inline void to_upper()
183 char* pToDo = m_begin;
185 while (pToDo < m_end)
187 *pToDo = static_cast<char>(std::toupper(*pToDo));
192 // append a single char in_count times
193 inline void append(const char in_charToAppend, const size_t in_count)
196 while ((m_end < m_begin+m_MaxFixedStringLength) && counter++ < in_count)
197 *m_end++ = in_charToAppend;
198 #if kEnableDebug == 1
199 if (counter < in_count) // if there wasn't enough room for some appended chars
201 m_begin[0] = '@'; // mark the string as overflowed
207 inline void append(const char* in_chars)
209 operator<<(in_chars);
212 // append "iterator style"
213 inline void append(const char* in_chars_begin, const char* in_chars_end)
215 const char* curr_char = in_chars_begin;
216 while ((m_end < m_begin+m_MaxFixedStringLength) && curr_char < in_chars_end && *curr_char != '\0')
217 *m_end++ = *curr_char++;
219 #if kEnableDebug == 1
220 if (curr_char < in_chars_end) // if there wasn't enough room for some appended chars
222 m_begin[0] = '@'; // mark the string as overflowed
228 // append from a char* in_count chars, (no \0 is required to terminate the input string)
229 inline void append(const char* in_chars_begin, const size_t in_count)
231 append(in_chars_begin, in_chars_begin + in_count);
234 // assign from a char* in_count chars, (no \0 is required to terminate the input string)
235 inline void assign(const char* in_chars_begin, const size_t in_count)
238 append(in_chars_begin, in_chars_begin + in_count);
241 // assign from a char* , (a \0 is required to terminate the input string)
242 inline void assign(const char* in_chars_ptr)
245 operator<<(in_chars_ptr);
248 // assign from a char* to a char*
249 inline void assign(const char* in_begin, const char* in_end)
251 assign(in_begin, size_t(in_end - in_begin));
254 inline void append_double_with_precision(const double in_double, const int in_precision)
256 const unsigned int tempBufSize = 32;
257 char buf[tempBufSize];
260 _snprintf_s(buf, tempBufSize, tempBufSize - 1, "%.*f", in_precision, in_double);
263 std::snprintf(buf, tempBufSize, "%.*f", in_precision, in_double);
266 snprintf(buf, tempBufSize, "%.*f", in_precision, in_double);
272 inline void append_uint(const uint64_t in_uint, const int_fast16_t in_base = 10)
274 uint_fast64_t num = in_uint;
276 char* lasr_char_before = m_end;
279 char remainder(static_cast<char>(num % in_base));
281 if ( remainder < 10 )
282 operator<<(char(remainder + '0'));
284 operator<<(char(remainder - 10 + 'A'));
289 reverse(lasr_char_before, m_end);
292 inline void append_hex_binary(const uint8_t* in_binary, const size_t in_size)
294 static const char hexdigits[] = "0123456789ABCDEF";
296 #if _BYTEORDER_BIG_ENDIAN==1
297 for (size_t ibyte = 0; ibyte < in_size; ++ibyte)
298 #elif _BYTEORDER_BIG_ENDIAN==0
299 for (size_t ibyte = in_size; ibyte > 0; --ibyte)
302 operator<<(hexdigits[in_binary[ibyte - 1] >> 4]);
303 operator<<(hexdigits[in_binary[ibyte - 1] & 0x0F]);
307 inline WCFixedStringBase& operator<<(const char in_charToAppend)
309 if (m_end < m_begin+m_MaxFixedStringLength)
310 *m_end++ = in_charToAppend;
311 #if kEnableDebug == 1
312 else // if there wasn't enough room for the appended char
314 m_begin[0] = '@'; // mark the string as overflowed
323 inline WCFixedStringBase& operator<<(const char* const in_strToAppend)
325 if (0 != in_strToAppend)
327 const char* pSource = in_strToAppend;
329 while (*pSource != '\0' && m_end < m_begin+m_MaxFixedStringLength)
330 *m_end++ = *pSource++;
332 #if kEnableDebug == 1
333 if (*pSource != '\0') // if there wasn't enough room for some appended chars
335 m_begin[0] = '@'; // mark the string as overflowed
344 WCFixedStringBase& operator<<(const uint64_t in_uint)
346 append_uint(in_uint, 10);
352 // Warning prevention: the operator<< function overload for unsigneds used to create lots
353 // of warnings once size_t usage was becoming widespread. So for each OS we define only
354 // those overloads that are actually needed. On Windows 32 bit we still get
355 // 'warning C4267: 'argument' : conversion from 'size_t' to 'const unsigned int', possible loss of data'
356 // warning which we do not know how to solve yet. The function DummyFunctionsForWarningTest
357 // in file WCFixedStringStream.cpp calls all combinations of operator<<(unsigned something)
358 // And should produce no warnings - (except the C4267 on windows).
359 #if defined(__MACOS__) // both 32 & 64 bit
360 WCFixedStringBase& operator<<(const size_t in_uint) {
361 return operator<<(static_cast<unsigned long long>(in_uint));
364 // WCFixedStringBase& operator<<(const unsigned char in_uint) {
365 // return operator<<(static_cast<const unsigned long long>(in_uint));
368 // WCFixedStringBase& operator<<(const size_t in_uint) {
369 // return operator<<(static_cast<const uint64_t>(in_uint));
372 #if defined(__MACOS__) || defined(_WINDOWS) || defined(__linux__) // both 32 & 64 bit
373 WCFixedStringBase& operator<<(const unsigned int in_uint) {
374 return operator<<(static_cast<uint64_t>(in_uint));
378 #if defined(_WINDOWS) || defined(__linux__) // both 32 & 64 bit
379 WCFixedStringBase& operator<<(const unsigned long in_uint) {
380 return operator<<(static_cast<uint64_t>(in_uint));
384 WCFixedStringBase& operator<<(const long long in_int)
389 // uintmax_t unsigned_in_num = _abs64(in_int);
390 uintmax_t unsigned_in_num = in_int < 0 ? static_cast<uintmax_t>(-in_int) : static_cast<uintmax_t>(in_int);
392 uintmax_t unsigned_in_num = std::abs(in_int);
394 append_uint(unsigned_in_num, 10);
399 WCFixedStringBase& operator<<(const short in_int) {
400 return operator<<(static_cast<int64_t>(in_int));
403 WCFixedStringBase& operator<<(const int in_int) {
404 return operator<<(static_cast<int64_t>(in_int));
407 WCFixedStringBase& operator<<(const long in_int) {
408 return operator<<(static_cast<int64_t>(in_int));
411 WCFixedStringBase& operator<<(const double in_doubleToWrite)
413 append_double_with_precision(in_doubleToWrite, 10);
418 WCFixedStringBase& operator<<(const float in_floatToWrite)
420 append_double_with_precision(double(in_floatToWrite), 5);
425 inline WCFixedStringBase& operator<<(const WCFixedStringBase& in_fixedStrToAppend)
427 operator<<(in_fixedStrToAppend.c_str());
432 WCFixedStringBase& operator<< (bool abool)
434 return abool ? operator<<("true") : operator<<("false");
437 template<typename T> WCFixedStringBase& operator+=(T in_type)
439 return operator<<(in_type);
442 ptrdiff_t compare(const char* in_to_compare) const
444 ptrdiff_t retVal = 1;
446 if (0 != in_to_compare)
448 retVal = strcmp(c_str(), in_to_compare);
455 ptrdiff_t compare(const WCFixedStringBase& in_to_compare) const
457 ptrdiff_t retVal = compare(in_to_compare.c_str());
461 ptrdiff_t case_insensitive_compare(const char* in_to_compare) const
463 ptrdiff_t retVal = 1;
465 if (0 != in_to_compare)
468 retVal = _stricmp(c_str(), in_to_compare);
470 #if defined(__linux__) || defined(__MACOS__)
471 retVal = strcasecmp(c_str(), in_to_compare);
478 ptrdiff_t case_insensitive_compare(const WCFixedStringBase& in_to_compare) const
480 ptrdiff_t retVal = case_insensitive_compare(in_to_compare.c_str());
484 pos_t find(const char in_char_to_find) const
486 const char* pCurrChar = m_begin;
487 while (pCurrChar < m_end && *pCurrChar != in_char_to_find)
490 return (pCurrChar < m_end) ? (pCurrChar - m_begin) : npos;
493 pos_t rfind(const char in_char_to_find) const
496 const char* pCurrChar = m_end;
498 while (pCurrChar != m_begin)
501 if (*pCurrChar == in_char_to_find)
503 retVal = pCurrChar - m_begin;
511 pos_t find(const char* in_chars_to_find, const pos_t in_start_from = 0) const
514 size_t to_find_size = ::strlen(in_chars_to_find);
516 if (to_find_size > 0 && to_find_size <= size() && in_start_from < size())
518 const char* pCurrChar = m_begin + in_start_from;
519 while ((m_end - pCurrChar) >= (ptrdiff_t)to_find_size)
521 int found = ::memcmp(pCurrChar, in_chars_to_find, to_find_size);
524 retVal = (pCurrChar - m_begin);
535 pos_t rfind(const char* in_chars_to_find) const
538 size_t to_find_size = ::strlen(in_chars_to_find);
540 if (to_find_size > 0 && to_find_size <= size())
542 const char* pCurrChar = m_end - to_find_size;
543 while (m_begin <= pCurrChar)
545 int found = ::memcmp(pCurrChar, in_chars_to_find, to_find_size);
548 retVal = (pCurrChar - m_begin);
559 pos_t find_case_insensitive(const char* in_chars_to_find, const pos_t in_start_from = 0) const
562 size_t to_find_size = ::strlen(in_chars_to_find);
564 if (to_find_size > 0 && to_find_size <= size() && in_start_from < size())
566 const char* pCurrChar = m_begin + in_start_from;
567 while ((m_end - pCurrChar) >= (ptrdiff_t)to_find_size)
570 for (i = 0; i < to_find_size; ++i)
572 if (tolower(*(pCurrChar+i)) != tolower(in_chars_to_find[i]))
576 if (i == to_find_size)
578 retVal = (pCurrChar - m_begin);
589 pos_t find_first_of(const char* in_possibe_chars_to_find, const pos_t in_start_from = 0) const
593 if (in_start_from < size())
595 const char* pFoundChar = strpbrk(m_begin + in_start_from, in_possibe_chars_to_find);
598 retVal = (pFoundChar - m_begin);
605 pos_t find_last_of(const char* in_possibe_chars_to_find, const pos_t in_start_from = 0) const
609 pos_t curr_location = in_start_from;
611 while (size() > curr_location)
613 pos_t found = find_first_of(in_possibe_chars_to_find, curr_location);
617 curr_location = found + 1;
626 pos_t find_first_not_of(const char* in_acceptable_chars, const pos_t in_start_from = 0) const
630 if (in_start_from < size())
632 retVal = (strspn(m_begin + in_start_from, in_acceptable_chars));
633 if (size() <= retVal + in_start_from)
639 retVal += in_start_from;
646 pos_t find_last_not_of(const char* in_acceptable_chars, const pos_t in_start_from = 0) const
650 pos_t curr_location = in_start_from;
652 while (size() > curr_location)
654 pos_t found = find_first_not_of(in_acceptable_chars, curr_location);
658 curr_location = found + 1;
667 // return true if in_begin_text is found at position 0 OR if in_begin_text is empty
668 bool begins_with(const char* in_begin_text) const
670 pos_t where = find(in_begin_text, 0);
671 bool retVal = (0 == where) || (0 == ::strlen(in_begin_text));
675 // return true if in_end_text is found at th end OR if in_end_text is empty
676 bool ends_with(const char* in_end_text) const
678 pos_t where = rfind(in_end_text);
679 bool retVal = ((size() - strlen(in_end_text)) == where) || (0 == ::strlen(in_end_text));
683 size_t replace(const char in_look_for, const char in_replace_with)
687 char* pCurrChar = m_begin;
688 while (pCurrChar < m_end)
690 if (*pCurrChar == in_look_for)
692 *pCurrChar = in_replace_with;
701 // erase in_size chars starting from in_location
702 void erase(const pos_t in_location, const size_t in_num_chars = 1)
704 if (size() > in_location && in_num_chars > 0)
706 size_t actual_num_chars = WUMin(in_num_chars, size_t(size() - in_location));
707 char* pTo = m_begin + in_location;
708 char* pFrom = pTo + actual_num_chars;
710 while (pFrom < m_end)
713 resize(size() - actual_num_chars);
717 // erase any char that appear in in_forbidden_chars
718 void erase_all_of(const char* in_forbidden_chars)
720 pos_t curr_location = 0;
722 while (npos != curr_location)
724 curr_location = find_first_of(in_forbidden_chars, curr_location);
725 if (npos != curr_location)
726 erase(curr_location);
730 // erase any char that do not appear in in_allowed_chars
731 void erase_all_not_of(const char* in_allowed_chars)
733 pos_t curr_location = 0;
735 while (npos != curr_location)
737 curr_location = find_first_not_of(in_allowed_chars, curr_location);
738 if (npos != curr_location)
739 erase(curr_location);
743 //! Copy the content of fixed string to a buffer appending a '\0' at the end.
744 //! If in_buffer_size is more than the allocated buffer size memory over write will happen!
745 void copy_to_buffer(const size_t in_buffer_size, char* out_buffer)
747 if (in_buffer_size > 0 && 0 != out_buffer)
749 char* cur_buffer = out_buffer;
750 const char* cur_fixed = m_begin;
751 const char* end_buffer = out_buffer + (WUMin<size_t>(in_buffer_size - 1, m_end - m_begin));
752 while (cur_buffer < end_buffer)
753 *cur_buffer++ = *cur_fixed++;
760 ~WCFixedStringBase() {}
763 const size_t m_MaxFixedStringLength;
768 WCFixedStringBase(const WCFixedStringBase& in_fixedStrToCopy);
771 m_begin(in_fixedStrToCopy.m_begin),
772 m_MaxFixedStringLength(in_fixedStrToCopy.m_MaxFixedStringLength),
773 m_end(in_fixedStrToCopy.m_end)
779 template<size_t kMaxFixedStringLength> class DllExport WCFixedString : public WCFixedStringBase
783 inline WCFixedString() :
784 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
788 inline WCFixedString(const char* const in_strToAssign) :
789 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
791 operator<<(in_strToAssign);
794 inline WCFixedString(const WCFixedStringBase& in_fixedStrToAssign) :
795 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
797 operator<<(in_fixedStrToAssign);
800 inline WCFixedString(const WCFixedString& in_fixedStrToAssign) :
801 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
803 operator<<(in_fixedStrToAssign);
806 inline WCFixedString(const char in_char, const size_t in_count = 1) :
807 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
809 append(in_char, in_count);
812 inline WCFixedString(const char* in_chars, const size_t in_count) :
813 WCFixedStringBase(m_fixedString, kMaxFixedStringLength)
815 append(in_chars, in_count);
818 // substr now supports negative in_length, which means "from the end" so
819 // "abcdefg".substr(1, -1) == "bcdef"
820 inline const WCFixedString substr(const pos_t in_pos = 0, const spos_t in_length = kMaxFixedStringLength) const
822 pos_t adjusted_pos = WUMin<size_t>(in_pos, size());
823 size_t adjusted_length = 0;
826 adjusted_length = size_t(WUMax<spos_t>(0, spos_t(size() - adjusted_pos) + in_length));
829 adjusted_length = WUMin<size_t>(in_length, size() - adjusted_pos);
831 WCFixedString retVal;
832 retVal.append(m_begin + adjusted_pos, adjusted_length);
839 char m_fixedString[kMaxFixedStringLength + 1]; // the "+ 1" is so that *m_end is always valid, and we can put the '\0' there};
842 inline bool operator==(const WCFixedStringBase& in_left, const WCFixedStringBase& in_right)
844 return 0 == in_left.compare(in_right.c_str());
847 inline bool operator==(const WCFixedStringBase& in_left, const char* const in_right)
849 return 0 == in_left.compare(in_right);
852 inline bool operator!=(const WCFixedStringBase& in_left, const WCFixedStringBase& in_right)
854 return 0 != in_left.compare(in_right.c_str());
857 inline bool operator!=(const WCFixedStringBase& in_left, const char* const in_right)
859 return 0 != in_left.compare(in_right);
862 // class WCFixedStringBase
863 typedef WCFixedString<4> WCFixedString4;
864 typedef WCFixedString<15> WCFixedString15;
865 typedef WCFixedString<31> WCFixedString31;
866 typedef WCFixedString<63> WCFixedString63;
867 typedef WCFixedString<127> WCFixedString127;
868 typedef WCFixedString<255> WCFixedString255;
869 typedef WCFixedString<511> WCFixedString511;
870 typedef WCFixedString<1023> WCFixedString1023;
871 typedef WCFixedString<2047> WCFixedString2047;
873 template<size_t kSizeOfFirst, size_t kSizeOfSecond>
874 class WCFixedStringPair : public std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >
877 WCFixedStringPair(const char* const in_firstStr = 0, const char* const in_secondStr = 0) :
878 std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
879 WCFixedStringPair(const WCFixedStringBase& in_firstStr, const char* const in_secondStr = 0) :
880 std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
881 WCFixedStringPair(const WCFixedStringBase& in_firstStr, const WCFixedStringBase& in_secondStr) :
882 std::pair< WCFixedString<kSizeOfFirst>, WCFixedString<kSizeOfSecond> >(in_firstStr, in_secondStr) {}
885 #endif // #ifndef __WCFixedString_h__