1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 **************************************************************************/
27 // File: vogl_dynamic_string.cpp
28 #include "vogl_core.h"
29 #include "vogl_strutils.h"
30 #include "vogl_json.h"
32 #if VOGL_SLOW_STRING_LEN_CHECKS
33 #warning vogl_dynamic_string.cpp: Slow string checking enabled
38 dynamic_string g_empty_dynamic_string;
40 dynamic_string::dynamic_string(eVarArg dummy, const char *p, ...)
42 VOGL_NOTE_UNUSED(dummy);
44 set_to_empty_small_string();
54 dynamic_string::dynamic_string(const char *p)
56 VOGL_ASSUME(cMaxDynamicStringBufSize <= cINT32_MAX);
57 // This class assumes little endian byte order, because the low bits of m_dyn.m_pStr must alias m_small.m_flag
58 VOGL_ASSUME(VOGL_LITTLE_ENDIAN_CPU);
62 set_to_empty_small_string();
67 dynamic_string::dynamic_string(const char *p, uint len)
71 set_to_empty_small_string();
76 dynamic_string::dynamic_string(const dynamic_string &other)
78 set_to_empty_small_string();
83 void dynamic_string::clear()
89 vogl_delete_array(m_dyn.m_pStr);
92 set_to_empty_small_string();
95 void dynamic_string::empty()
100 void dynamic_string::optimize()
106 if ((m_len + 1U) <= cSmallStringBufSize)
110 char *pStr = m_dyn.m_pStr;
112 memcpy(m_small.m_buf, pStr, m_len + 1);
114 vogl_delete_array(pStr);
116 set_small_string_flag();
128 uint32 min_buf_size = m_len + 1;
130 // TODO: In some cases it'll make no difference to try to shrink the block due to allocation alignment, etc. issues
131 if (m_dyn.m_buf_size > min_buf_size)
133 char *p = vogl_new_array(char, min_buf_size);
134 memcpy(p, m_dyn.m_pStr, m_len + 1);
136 vogl_delete_array(m_dyn.m_pStr);
138 set_dyn_string_ptr(p);
140 m_dyn.m_buf_size = min_buf_size;
148 void dynamic_string::reserve(uint new_capacity)
150 ensure_buf(new_capacity, true);
153 int dynamic_string::compare(const char *p, bool case_sensitive) const
157 const int result = (case_sensitive ? strcmp : vogl_stricmp)(get_ptr_priv(), p);
167 int dynamic_string::compare(const dynamic_string &rhs, bool case_sensitive) const
169 return compare(rhs.get_ptr_priv(), case_sensitive);
172 int dynamic_string::compare_using_length(const char *p, bool case_sensitive) const
174 uint l_len = get_len();
175 uint r_len = vogl_strlen(p);
179 else if (l_len == r_len)
180 return compare(p, case_sensitive);
185 int dynamic_string::compare_using_length(const dynamic_string &rhs, bool case_sensitive) const
187 return compare_using_length(rhs.get_ptr(), case_sensitive);
190 dynamic_string &dynamic_string::set(const char *p, uint max_len)
194 const uint len = math::minimum<uint>(max_len, vogl_strlen(p));
195 VOGL_ASSERT(len <= cMaxDynamicStringLen);
197 if ((!len) || (len > cMaxDynamicStringLen))
201 char *pStr = get_ptr_priv();
202 uint buf_size = get_buf_size();
203 if ((p >= pStr) && (p < (pStr + buf_size)))
206 memmove(pStr, p, len);
211 else if (ensure_buf(len, false))
214 memcpy(get_ptr_priv(), p, m_len + 1);
223 dynamic_string &dynamic_string::set(const dynamic_string &other, uint max_len)
229 get_ptr_priv()[max_len] = '\0';
235 const uint len = math::minimum<uint>(max_len, other.m_len);
239 else if (ensure_buf(len, false))
241 char *pStr = get_ptr_priv();
243 memcpy(pStr, other.get_ptr_priv(), m_len);
253 bool dynamic_string::set_len(uint new_len, char fill_char)
255 if ((new_len > cMaxDynamicStringLen) || (!fill_char))
261 uint cur_len = m_len;
263 if (ensure_buf(new_len, true))
265 char *pStr = get_ptr_priv();
267 if (new_len > cur_len)
268 memset(pStr + cur_len, fill_char, new_len - cur_len);
280 dynamic_string &dynamic_string::set_from_raw_buf_and_assume_ownership(char *pBuf, uint buf_size_in_bytes, uint len_in_chars)
282 VOGL_ASSERT(buf_size_in_bytes <= cMaxDynamicStringBufSize);
283 VOGL_ASSERT((len_in_chars + 1) <= buf_size_in_bytes);
284 VOGL_ASSERT(len_in_chars <= cMaxDynamicStringLen);
285 VOGL_ASSERT(!pBuf || !pBuf[len_in_chars]);
286 VOGL_ASSERT(pBuf || ((!buf_size_in_bytes) && (!len_in_chars)));
293 set_dyn_string_ptr(pBuf);
294 m_dyn.m_buf_size = buf_size_in_bytes;
295 m_len = len_in_chars;
302 dynamic_string &dynamic_string::set_from_buf(const void *pBuf, uint buf_len_in_chars)
306 VOGL_ASSERT(!buf_len_in_chars);
311 if (buf_len_in_chars > cMaxDynamicStringLen)
318 #ifdef VOGL_BUILD_DEBUG
319 if ((buf_len_in_chars) && (memchr(pBuf, 0, buf_len_in_chars) != NULL))
327 if (ensure_buf(buf_len_in_chars, false))
329 char *pStr = get_ptr_priv();
331 if (buf_len_in_chars)
332 memcpy(pStr, pBuf, buf_len_in_chars);
334 pStr[buf_len_in_chars] = 0;
336 m_len = buf_len_in_chars;
344 dynamic_string &dynamic_string::set_char(uint index, char c)
346 VOGL_ASSERT(index <= m_len);
350 else if (index < m_len)
352 get_ptr_priv()[index] = c;
356 else if (index == m_len)
362 dynamic_string &dynamic_string::append_char(char c)
366 // Can't append a zero terminator - there's already one there.
371 if (m_len == cMaxDynamicStringLen)
377 if (ensure_buf(m_len + 1))
379 char *pStr = get_ptr_priv();
382 pStr[m_len + 1] = '\0';
390 dynamic_string &dynamic_string::truncate(uint new_len)
394 get_ptr_priv()[new_len] = '\0';
401 dynamic_string &dynamic_string::shorten(uint chars_to_remove)
403 VOGL_ASSERT(m_len >= chars_to_remove);
404 if (m_len < chars_to_remove)
406 return truncate(m_len - chars_to_remove);
409 dynamic_string &dynamic_string::tolower()
413 vogl_strlwr(get_ptr_priv());
418 dynamic_string &dynamic_string::toupper()
422 vogl_strupr(get_ptr_priv());
427 dynamic_string &dynamic_string::append(const char *p, uint len)
430 VOGL_ASSERT(len <= vogl_strlen(p));
435 if (ptr_refers_to_self(p))
437 dynamic_string temp(*this);
443 if (len > (cMaxDynamicStringLen - m_len))
449 uint new_total_len = m_len + len;
450 VOGL_ASSERT(new_total_len <= cMaxDynamicStringLen);
451 if ((new_total_len) && (ensure_buf(new_total_len)))
453 char *pStr = get_ptr_priv();
455 memcpy(pStr + m_len, p, len);
456 pStr[m_len + len] = '\0';
464 dynamic_string &dynamic_string::append(const char *p)
468 if (ptr_refers_to_self(p))
470 dynamic_string temp(*this);
476 uint len = vogl_strlen(p);
477 if (len > (cMaxDynamicStringLen - m_len))
483 uint new_total_len = m_len + len;
484 VOGL_ASSERT(new_total_len <= cMaxDynamicStringLen);
485 if ((new_total_len) && (ensure_buf(new_total_len)))
487 memcpy(get_ptr_priv() + m_len, p, len + 1);
495 dynamic_string &dynamic_string::append(const dynamic_string &other)
499 dynamic_string temp(*this);
505 uint len = other.m_len;
507 if (len > (cMaxDynamicStringLen - m_len))
513 uint new_total_len = m_len + len;
514 VOGL_ASSERT(new_total_len <= cMaxDynamicStringLen);
515 if ((new_total_len) && ensure_buf(new_total_len))
517 memcpy(get_ptr_priv() + m_len, other.get_ptr_priv(), len + 1);
525 dynamic_string operator+(const char *p, const dynamic_string &a)
527 return dynamic_string(p).append(a);
530 dynamic_string operator+(const dynamic_string &a, const char *p)
532 return dynamic_string(a).append(p);
535 dynamic_string operator+(const dynamic_string &a, const dynamic_string &b)
537 return dynamic_string(a).append(b);
540 dynamic_string &dynamic_string::format_args(const char *p, va_list args)
544 const uint cBufSize = 4096;
545 int buf_size = cBufSize;
550 int l = vsnprintf_s(pBuf, buf_size, _TRUNCATE, p, args);
552 int l = vsnprintf(pBuf, buf_size, p, args);
558 pBuf = static_cast<char *>(vogl_malloc(buf_size));
561 l = vsnprintf_s(pBuf, buf_size, _TRUNCATE, p, args);
563 l = vsnprintf(pBuf, buf_size, p, args);
567 if (l > cMaxDynamicStringLen)
574 else if (ensure_buf(l, false))
576 memcpy(get_ptr_priv(), pBuf, l + 1);
593 dynamic_string &dynamic_string::format(const char *p, ...)
599 format_args(p, args);
604 dynamic_string &dynamic_string::format_append(const char *p, ...)
612 temp.format_args(p, args);
620 dynamic_string &dynamic_string::crop(uint start, uint len)
628 len = math::minimum<uint>(len, m_len - start);
630 char *pStr = get_ptr_priv();
633 memmove(pStr, pStr + start, len);
644 dynamic_string &dynamic_string::remove(uint start, uint len)
646 VOGL_ASSERT(start < m_len);
648 if ((start >= m_len) || (!len))
651 uint max_len = m_len - start;
652 VOGL_ASSERT(len <= max_len);
656 uint num_chars_remaining = m_len - (start + len);
658 // + 1 to move terminator
659 memmove(get_ptr_priv() + start, get_ptr_priv() + start + len, num_chars_remaining + 1);
661 m_len = start + num_chars_remaining;
668 dynamic_string &dynamic_string::substring(uint start, uint end)
670 VOGL_ASSERT(start <= end);
673 return crop(start, end - start);
676 dynamic_string &dynamic_string::left(uint len)
678 return substring(0, len);
681 dynamic_string &dynamic_string::mid(uint start, uint len)
683 return crop(start, len);
686 dynamic_string &dynamic_string::right(uint start)
688 return substring(start, get_len());
691 dynamic_string &dynamic_string::tail(uint num)
693 return substring(math::maximum<int>(static_cast<int>(get_len()) - static_cast<int>(num), 0), get_len());
696 // This is not particularly efficient. Just here as a one-off utility method.
697 dynamic_string &dynamic_string::replace(const char *pFind, const char *pReplacement, bool case_sensitive, uint *pNum_found, uint max_replacements)
704 VOGL_ASSERT(max_replacements);
705 if (!max_replacements)
710 uint find_len = vogl_strlen(pFind);
711 uint replacement_len = pReplacement ? vogl_strlen(pReplacement) : 0;
718 int find_ofs = find_left(pFind, case_sensitive, cur_ofs);
723 temp.truncate(find_ofs);
725 temp += pReplacement;
726 temp += right(find_ofs + find_len);
729 cur_ofs = find_ofs + replacement_len;
732 if (num_found >= max_replacements)
737 *pNum_found = num_found;
742 dynamic_string &dynamic_string::unquote()
746 if (((*this)[0] == '\"') && ((*this)[m_len - 1] == '\"'))
748 return mid(1, m_len - 2);
755 int dynamic_string::find_left(const char *p, bool case_sensitive, uint start_ofs) const
758 VOGL_ASSERT(start_ofs <= m_len);
760 const uint p_len = vogl_strlen(p);
765 const char *pStr = get_ptr_priv();
767 for (uint i = start_ofs; i <= m_len - p_len; i++)
768 if ((case_sensitive ? strncmp : vogl_strnicmp)(p, pStr + i, p_len) == 0)
774 bool dynamic_string::contains(const char *p, bool case_sensitive) const
776 return find_left(p, case_sensitive) >= 0;
779 bool dynamic_string::contains(char c) const
781 return find_left(c) >= 0;
784 bool dynamic_string::begins_with(const char *p, bool case_sensitive) const
788 const uint p_len = vogl_strlen(p);
789 if ((!p_len) || (m_len < p_len))
792 return (case_sensitive ? strncmp : vogl_strnicmp)(p, get_ptr_priv(), p_len) == 0;
795 bool dynamic_string::ends_with(const char *p, bool case_sensitive) const
799 const uint p_len = vogl_strlen(p);
800 if ((!p_len) || (m_len < p_len))
803 return (case_sensitive ? strcmp : vogl_stricmp)(get_ptr_priv() + m_len - p_len, p) == 0;
806 uint dynamic_string::count_char(char c) const
808 const char *pStr = get_ptr_priv();
811 for (uint i = 0; i < m_len; i++)
817 int dynamic_string::find_left(char c, int start_ofs) const
819 const char *pStr = get_ptr_priv();
821 for (uint i = start_ofs; i < m_len; i++)
827 int dynamic_string::find_right(char c) const
831 const char *pStr = get_ptr_priv();
847 int dynamic_string::find_right(char c, uint start_ofs) const
849 if (start_ofs >= m_len)
857 const char *pStr = get_ptr_priv();
873 int dynamic_string::find_right(const char *p, bool case_sensitive) const
876 const uint p_len = vogl_strlen(p);
883 const char *pStr = get_ptr_priv();
885 uint i = m_len - p_len;
888 if ((case_sensitive ? strncmp : vogl_strnicmp)(p, &pStr[i], p_len) == 0)
899 dynamic_string &dynamic_string::trim()
901 VOGL_ASSERT(m_len <= cMaxDynamicStringLen);
903 const char *pStr = get_ptr_priv();
906 for (s = 0; s < static_cast<int>(m_len); s++)
907 if (!vogl_isspace(pStr[s]))
910 for (e = m_len - 1; e > s; e--)
911 if (!vogl_isspace(pStr[e]))
914 return crop(s, e - s + 1);
917 dynamic_string &dynamic_string::trim_end()
919 VOGL_ASSERT(m_len <= cMaxDynamicStringLen);
921 const char *pStr = get_ptr_priv();
924 for (e = static_cast<int>(m_len) - 1; e >= 0; e--)
925 if (!vogl_isspace(pStr[e]))
928 return crop(0, e + 1);
931 dynamic_string &dynamic_string::trim_crlf()
933 VOGL_ASSERT(m_len <= cMaxDynamicStringLen);
935 const char *pStr = get_ptr_priv();
939 for (e = static_cast<int>(m_len) - 1; e > s; e--)
940 if ((pStr[e] != 13) && (pStr[e] != 10))
943 return crop(s, e - s + 1);
946 dynamic_string &dynamic_string::remap(int from_char, int to_char)
948 char *pStr = get_ptr_priv();
950 for (uint i = 0; i < m_len; i++)
951 if (pStr[i] == from_char)
952 pStr[i] = static_cast<char>(to_char);
957 bool dynamic_string::validate() const
962 vogl_debug_break_if_debugging(); \
965 CHECK(m_len < get_buf_size());
966 CHECK(m_len <= cMaxDynamicStringLen);
970 CHECK(m_dyn.m_pStr != NULL);
971 CHECK(m_dyn.m_buf_size);
972 CHECK(m_dyn.m_buf_size <= cMaxDynamicStringBufSize);
974 CHECK(((m_dyn.m_pStr + m_dyn.m_buf_size) <= (const char *)this) || (m_dyn.m_pStr >= (const char *)(this + 1)));
975 CHECK(((uint64_t)m_dyn.m_pStr & (VOGL_MIN_ALLOC_ALIGNMENT - 1)) == 0);
976 CHECK(vogl_msize_array(m_dyn.m_pStr) >= m_dyn.m_buf_size);
979 const char *pStr = get_ptr_priv();
983 #if VOGL_SLOW_STRING_LEN_CHECKS
984 CHECK(vogl_strlen(pStr) == m_len);
991 void dynamic_string::ensure_dynamic()
996 uint new_buf_size = math::maximum(m_len + 1, 16U);
998 new_buf_size = math::minimum<uint>(new_buf_size, cMaxDynamicStringBufSize);
1000 char *p = vogl_new_array(char, new_buf_size);
1002 VOGL_ASSERT(new_buf_size >= (m_len + 1));
1003 memcpy(p, m_small.m_buf, m_len + 1);
1005 set_dyn_string_ptr(p);
1007 m_dyn.m_buf_size = static_cast<uint32>(math::minimum<uint64_t>(cMaxDynamicStringBufSize, vogl_msize_array(m_dyn.m_pStr)));
1008 VOGL_ASSERT(m_dyn.m_buf_size >= new_buf_size);
1013 bool dynamic_string::ensure_buf(uint len, bool preserve_contents)
1015 uint buf_size_needed = len + 1;
1016 if (buf_size_needed > cMaxDynamicStringBufSize)
1022 if (buf_size_needed > get_buf_size())
1023 return expand_buf(buf_size_needed, preserve_contents);
1028 bool dynamic_string::expand_buf(uint new_buf_size, bool preserve_contents)
1030 VOGL_ASSERT(new_buf_size <= cMaxDynamicStringBufSize);
1032 new_buf_size = static_cast<uint>(math::minimum<uint64_t>(cMaxDynamicStringBufSize, math::next_pow2(new_buf_size)));
1034 char *p = vogl_new_array(char, new_buf_size);
1036 if (preserve_contents)
1038 VOGL_ASSERT(new_buf_size >= (m_len + 1));
1039 memcpy(p, get_ptr_priv(), m_len + 1);
1044 vogl_delete_array(m_dyn.m_pStr);
1047 set_dyn_string_ptr(p);
1048 m_dyn.m_buf_size = static_cast<uint32>(math::minimum<uint64_t>(cMaxDynamicStringBufSize, vogl_msize_array(m_dyn.m_pStr)));
1049 VOGL_ASSERT(m_dyn.m_buf_size >= new_buf_size);
1051 if (preserve_contents)
1054 return get_buf_size() >= new_buf_size;
1057 void dynamic_string::swap(dynamic_string &other)
1059 VOGL_ASSUME((sizeof(*this) & (sizeof(uint32) - 1)) == 0);
1060 uint32 *pA = reinterpret_cast<uint32 *>(this);
1061 uint32 *pB = reinterpret_cast<uint32 *>(&other);
1063 uint num_uint32s = sizeof(*this) / sizeof(uint32);
1064 while (num_uint32s >= 4)
1066 std::swap(reinterpret_cast<uint64_t *>(pA)[0], reinterpret_cast<uint64_t *>(pB)[0]);
1067 std::swap(reinterpret_cast<uint64_t *>(pA)[1], reinterpret_cast<uint64_t *>(pB)[1]);
1073 while (num_uint32s >= 2)
1075 std::swap(reinterpret_cast<uint64_t *>(pA)[0], reinterpret_cast<uint64_t *>(pB)[0]);
1082 std::swap(pA[0], pB[0]);
1085 int dynamic_string::serialize(void *pBuf, uint buf_size, bool little_endian) const
1087 uint buf_left = buf_size;
1089 VOGL_ASSUME(sizeof(m_len) == sizeof(uint32));
1091 if (!utils::write_val(static_cast<uint32>(m_len), pBuf, buf_left, little_endian))
1094 if (buf_left < m_len)
1097 memcpy(pBuf, get_ptr_priv(), m_len);
1101 return buf_size - buf_left;
1104 int dynamic_string::deserialize(const void *pBuf, uint buf_size, bool little_endian)
1106 uint buf_left = buf_size;
1108 if (buf_left < sizeof(uint32))
1112 if (!utils::read_obj(len, pBuf, buf_left, little_endian))
1118 if (len > cMaxDynamicStringLen)
1121 set_from_buf(pBuf, len);
1125 return buf_size - buf_left;
1128 void dynamic_string::translate_lf_to_crlf()
1130 if (find_left(0x0A) < 0)
1134 if (!tmp.ensure_buf(m_len + 2))
1140 // normal sequence is 0x0D 0x0A (CR LF, \r\n)
1143 for (uint i = 0; i < get_len(); i++)
1145 const int cur_char = (*this)[i];
1147 if ((cur_char == 0x0A) && (prev_char != 0x0D))
1148 tmp.append_char(0x0D);
1150 tmp.append_char(cur_char);
1152 prev_char = cur_char;
1158 // simple strtok wrapper
1159 void dynamic_string::tokenize(const char *pDelims, dynamic_string_array &tokens, bool trim) const
1161 if (!pDelims || !pDelims[0])
1164 vogl::vector<char> tok_buf;
1165 tok_buf.append(get_ptr(), get_len());
1167 tok_buf.push_back('\0');
1169 char *pTok = strtok(tok_buf.get_ptr(), pDelims);
1173 dynamic_string tok(pTok);
1174 tokens.enlarge(1)->swap(tok);
1176 pTok = strtok(NULL, pDelims);
1181 for (uint i = 0; i < tokens.size(); i++)
1186 bool json_serialize(const dynamic_string &str, json_value &val)
1192 bool json_deserialize(dynamic_string &str, const json_value &val)
1194 str = val.as_string();
1198 bool dynamic_string_test()
1206 x = "This is a test";
1207 dynamic_string y(x);
1208 CHECK(x.compare(y, true) == 0);
1210 CHECK(x.compare(y, true) == 0);
1212 CHECK(x.compare(y, true) == 0);
1216 CHECK(y.compare(x, true) == 0);
1220 dynamic_string x("BlahCool");
1221 CHECK(x.contains("Cool"));
1222 CHECK(x.find_left("Cool") == 4);
1223 CHECK(x.find_left("hC") == 3);
1224 CHECK(x.find_right("o") == 6);
1225 CHECK(x.find_right("hC") == 3);
1226 CHECK(x.replace("Cool", "XXXX") == "BlahXXXX");
1229 CHECK(x.replace("Blah", "Z") == "ZCool");
1232 CHECK(x.replace("Blah", "BlahBlah") == "BlahBlahCool");
1237 CHECK(x.compare("abcdef") == 0);
1238 CHECK(x.compare("ABCDEF") == 0);
1239 CHECK(x.compare("abcdef", true) == 0);
1240 CHECK(x.compare("ABCDEF", true) > 0);
1243 CHECK(x.compare("abcdef") == 0);
1244 CHECK(x.compare("ABCDEF") == 0);
1245 CHECK(x.compare("abcdef", true) < 0);
1246 CHECK(x.compare("ABCDEF", true) == 0);
1250 dynamic_string x("Blah");
1252 CHECK(x == "BlahBlah");
1253 x.append(x.get_ptr());
1254 CHECK(x == "BlahBlahBlahBlah");
1255 x.append(x.get_ptr(), x.get_len());
1256 CHECK(x == "BlahBlahBlahBlahBlahBlahBlahBlah");
1257 x.append(x.get_ptr(), x.get_len());
1258 CHECK(x == "BlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlah");
1259 x.append(x.get_ptr(), x.get_len());
1260 CHECK(x == "BlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlah");
1261 x.append(x.get_ptr(), x.get_len());
1262 CHECK(x == "BlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlahBlah");
1266 dynamic_string_array tokens;
1267 dynamic_string x(" This is,a, test ");
1268 x.tokenize(" ,", tokens, true);
1269 CHECK(tokens.size() == 4);
1270 CHECK(tokens[0] == "This");
1271 CHECK(tokens[1] == "is");
1272 CHECK(tokens[2] == "a");
1273 CHECK(tokens[3] == "test");
1277 const uint N = 10000;
1278 dynamic_string_array x(N);
1279 vogl::vector<uint64_t> y(N);
1280 for (uint i = 0; i < N; i++)
1282 uint64_t r = g_random.urand64();
1283 x[i].format("%" PRIu64, r);
1284 CHECK(string_to_uint64(x[i].get_ptr()) == r);
1288 for (uint i = 0; i < 100000; i++)
1290 uint k = g_random.irand(0, N);
1291 uint l = g_random.irand(0, N);
1292 CHECK(string_to_uint64(x[k].get_ptr()) == y[k]);
1293 CHECK(string_to_uint64(x[l].get_ptr()) == y[l]);
1295 std::swap(x[k], x[l]);
1296 std::swap(y[k], y[l]);
1298 CHECK(string_to_uint64(x[k].get_ptr()) == y[k]);
1299 CHECK(string_to_uint64(x[l].get_ptr()) == y[l]);
1302 for (uint i = 0; i < N; i++)
1303 x[i].ensure_dynamic();
1304 for (uint i = 0; i < N; i++)
1305 CHECK(string_to_uint64(x[i].get_ptr()) == y[i]);
1307 for (uint i = 0; i < N; i++)
1309 for (uint i = 0; i < N; i++)
1310 CHECK(string_to_uint64(x[i].get_ptr()) == y[i]);
1312 for (uint i = 0; i < N; i++)
1314 dynamic_string temp(x[i]);
1317 for (uint i = 0; i < N; i++)
1318 CHECK(string_to_uint64(x[i].get_ptr()) == y[i]);
1320 for (uint i = 0; i < N; i++)
1322 dynamic_string temp(x[i]);
1323 x[i] = temp.get_ptr();
1325 for (uint i = 0; i < N; i++)
1326 CHECK(string_to_uint64(x[i].get_ptr()) == y[i]);
1331 vogl::vector<char> y;
1332 for (uint t = 0; t < 10000000; t++)
1334 if (g_random.irand(0, 1000) == 0)
1340 if (g_random.irand(0, 100) == 0)
1342 else if (g_random.irand(0, 100) == 0)
1344 else if (g_random.irand(0, 10000) == 0)
1345 x = dynamic_string(x);
1346 else if (g_random.irand(0, 4000) == 0)
1349 xx.set(x.get_ptr());
1352 else if (g_random.irand(0, 4000) == 0)
1355 xx.set(x.get_ptr());
1358 else if (g_random.irand(0, 4000) == 0)
1362 uint left = y.size();
1365 uint n = g_random.irand_inclusive(1, left);
1367 if ((n == 1) && (g_random.get_bit()))
1368 x.append_char(y[pos]);
1371 vogl::vector<char> z;
1372 z.append(&y[pos], n);
1374 x.append(z.get_ptr());
1382 if (g_random.irand(0, 1000) == 0)
1385 y.append(vogl::vector<char>(y));
1388 if (x.get_len() > 1000000)
1390 x.truncate(x.get_len() / 2);
1391 y.resize(y.size() / 2);
1394 switch (g_random.irand(0, 6))
1398 uint n = (uint)fabs(g_random.gaussian(10, 10));
1399 for (uint i = 0; i < n; i++)
1401 int c = g_random.irand_inclusive(1, 255);
1411 uint p = g_random.irand(0, x.get_len());
1412 uint n = (uint)fabs(g_random.gaussian(10, 10));
1413 n = math::minimum(n, x.get_len() - p);
1415 if (g_random.get_bit())
1416 x = dynamic_string(x).left(p) + dynamic_string(x).right(p + n);
1427 int c = g_random.irand_inclusive(1, 255);
1428 uint p = g_random.irand_inclusive(0, x.get_len());
1430 x = dynamic_string(x).left(p) + dynamic_string(cVarArg, "%c", c) + dynamic_string(x).right(p);
1439 if (g_random.get_bit())
1442 x.truncate(x.get_len() - 1);
1449 char buf[3] = {(char)g_random.irand_inclusive(1, 255), g_random.get_bit() ? (char)g_random.irand(1, 255) : (char)0, 0 };
1450 uint l = vogl_strlen(buf);
1452 int p0 = x.find_left(buf, true);
1455 for (int i = 0; i <= (int)y.size() - (int)l; i++)
1457 if (strncmp(&y[i], buf, l) == 0)
1470 char buf[3] = {(char)g_random.irand_inclusive(1, 255), g_random.get_bit() ? (char)g_random.irand(1, 255) : (char)0, 0 };
1471 uint l = vogl_strlen(buf);
1473 int p0 = x.find_right(buf, true);
1476 for (int i = (int)y.size() - (int)l; i >= 0; --i)
1478 if (strncmp(&y[i], buf, l) == 0)
1494 CHECK(x.get_len() == y.size());
1495 for (uint i = 0; i < x.get_len(); i++)
1497 CHECK(x[i] == y[i]);
1500 printf("%u: %u\n", t, x.size());
1506 for (uint t = 0; t < N; t++)
1508 uint i = g_random.irand_inclusive(0, cMaxDynamicStringLen);
1509 printf("Size: %u\n", i);
1513 int fill_char = g_random.irand_inclusive(1, 255);
1514 CHECK(k.set_len(i, (char)fill_char));
1516 CHECK(k.validate());
1520 CHECK(k.validate());
1524 CHECK(k.validate());
1526 CHECK(k.get_len() == i);
1528 for (uint i = 0; i < k.get_len(); i++)
1529 CHECK(k[i] == (char)fill_char);
1531 //if ((t & 4095) == 4095)
1532 printf("%3.3f%%\n", t * 100.0f / N);
1536 for (uint i = 0; i < 1000000; i++)
1538 uint k0 = g_random.irand(0, 20000);
1539 uint k1 = g_random.irand(0, 20000);
1541 dynamic_string a0(cVarArg, "%u", k0);
1542 dynamic_string a1(cVarArg, "%u", k1);
1544 vogl::vector<char> b0;
1545 b0.append(a0.get_ptr(), a0.get_len());
1547 vogl::vector<char> b1;
1548 b1.append(a1.get_ptr(), a1.get_len());
1557 if ((a0 < a1) != c0)
1559 if ((a0 <= a1) != c1)
1561 if ((a0 > a1) != c2)
1563 if ((a0 >= a1) != c3)
1565 if ((a0 == a1) != c4)
1567 if ((a0 != a1) != c5)