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: fixed_string.h
28 // Copyright (C) 2008-2009 Tenacious Software LLC, All rights reserved.
31 #include "vogl_core.h"
32 #include "vogl_fixed_array.h"
33 #include "vogl_hash.h"
34 #include "vogl_strutils.h"
38 // Simple hybrid C/Pascal style fixed string class, limited to a max buffer size of 65535 chars.
39 // Contains 16-bit length at beginning, followed by the zero terminated C-style string.
41 // TODO: Probably should delete this guy. This class is not nearly used as much as dynamic_string,
42 // which has the small string optimization so the value add here isn't high. This class
43 // never touches the heap, though, which could be useful.
44 // TODO: Create unit tests, this class has been barely used.
46 // Important note: For historical reasons the comparisons operators in this class are
47 // case insensitive (using locale independent helper functions) by default, mostly because
48 // the last X engines I've worked on used this default and I got used to it. Its the day after
49 // and now I'm regretting this idea.
50 template <uint BufSize>
57 cMaxLen = cBufSize - 1,
63 VOGL_ASSUME(BufSize < static_cast<uint>(cINT32_MAX));
67 inline fixed_string(eVarArg dummy, const char *p, ...) VOGL_ATTRIBUTE_PRINTF(3, 4)
69 VOGL_NOTE_UNUSED(dummy);
70 VOGL_ASSUME(BufSize < static_cast<uint>(cINT32_MAX));
78 inline fixed_string(const char *p)
80 VOGL_ASSUME(BufSize < static_cast<uint>(cINT32_MAX));
85 template <uint OtherBufSize>
86 explicit inline fixed_string(const fixed_string<OtherBufSize> &other)
87 : m_len(other.get_len())
89 memcpy(m_buf.get_ptr(), other.get_ptr(), other.get_len() + 1);
92 inline fixed_string &clear(bool full = false)
104 inline uint get_buf_size() const
109 inline uint get_max_len() const
114 inline uint get_len() const
119 inline uint size() const
124 // Truncates the string to 0 chars, but does not free the buffer.
130 inline bool is_empty() const
135 inline bool has_content() const
140 inline const char *get_ptr() const
142 return m_buf.get_ptr();
145 inline char front() const
147 return m_len ? get_ptr()[0] : '\0';
149 inline char back() const
151 return m_len ? get_ptr()[m_len - 1] : '\0';
154 inline char operator[](uint i) const
159 // Index string, beginning from back, 0 = last character, 1 = next to last char, etc.
160 inline char get_char_at_end(uint i) const
162 VOGL_ASSERT(i <= m_len);
163 return (i < m_len) ? get_ptr()[static_cast<int>(m_len) - 1 - static_cast<int>(i)] : '\0';
166 inline string_hash get_hash() const
168 return string_hash(get_ptr(), m_len);
171 inline fixed_string get_clone() const
173 return fixed_string(*this);
176 // IMPORTANT: These comparison methods are all CASE INSENSITIVE by default!
177 inline int compare(const fixed_string &rhs, bool case_sensitive = false) const
179 return compare(rhs.get_ptr(), case_sensitive);
182 inline int compare(const char *p, bool case_sensitive = false) const
190 result = strncmp(get_ptr(), p, l_len);
192 result = vogl_strnicmp(get_ptr(), p, l_len);
194 return (result < 0) ? -1 : ((result > 0) ? 1 : 0);
197 // IMPORTANT: These comparison methods are all CASE INSENSITIVE by default!
198 inline bool operator==(const fixed_string &rhs) const
200 return compare(rhs) == 0;
202 inline bool operator==(const char *p) const
204 return compare(p) == 0;
207 inline bool operator<(const fixed_string &rhs) const
209 return compare(rhs) < 0;
211 inline bool operator<(const char *p) const
213 return compare(p) < 0;
216 inline bool operator>(const fixed_string &rhs) const
218 return compare(rhs) > 0;
220 inline bool operator>(const char *p) const
222 return compare(p) > 0;
225 inline bool operator<=(const fixed_string &rhs) const
227 return compare(rhs) <= 0;
229 inline bool operator<=(const char *p) const
231 return compare(p) <= 0;
234 inline bool operator>=(const fixed_string &rhs) const
236 return compare(rhs) >= 0;
238 inline bool operator>=(const char *p) const
240 return compare(p) >= 0;
243 friend inline bool operator==(const char *p, const fixed_string &rhs)
245 return rhs.compare(p) == 0;
248 inline bool set(const char *p, uint max_len = UINT_MAX)
252 uint len = vogl_strlen(p);
254 const uint copy_len = math::minimum<uint>(max_len, len, cMaxLen);
256 memmove(m_buf.get_ptr(), p, copy_len * sizeof(char));
264 return copy_len == len;
267 template <uint OtherBufSize>
268 inline fixed_string &operator=(const fixed_string<OtherBufSize> &other)
270 if ((void *)this != (void *)&other)
272 memcpy(m_buf.get_ptr(), other.get_ptr(), other.get_len() + 1);
273 m_len = other.get_len();
281 inline fixed_string &operator=(const char *p)
287 inline fixed_string &set_char(uint index, char c)
289 VOGL_ASSERT(index <= m_len);
299 m_buf[index + 1] = 0;
300 m_len = math::minimum<uint>(cMaxLen, m_len + 1);
309 inline fixed_string &append_char(char c)
311 return set_char(m_len, c);
314 inline fixed_string &truncate(uint new_len)
316 VOGL_ASSERT(new_len <= m_len);
326 inline fixed_string &tolower()
332 inline fixed_string &toupper()
338 inline fixed_string &append(const char *p)
340 uint p_len = math::minimum<uint>(cMaxLen - m_len, vogl_strlen(p));
344 memmove(m_buf.get_ptr() + m_len, p, p_len);
346 m_len = m_len + p_len;
356 template <uint OtherBufSize>
357 inline fixed_string &append(const fixed_string<OtherBufSize> &b)
359 uint b_len = math::minimum<uint>(cMaxLen - m_len, b.get_len());
363 memmove(m_buf.get_ptr() + m_len, b.get_ptr(), b_len);
365 m_len = m_len + b_len;
375 inline fixed_string &operator+=(const char *p)
380 template <uint OtherBufSize>
381 inline fixed_string &operator+=(const fixed_string<OtherBufSize> &b)
386 friend inline fixed_string operator+(const fixed_string &a, const fixed_string &b)
388 return fixed_string(a).append(b);
391 inline fixed_string &format_args(const char *p, va_list args)
393 int l = vogl_vsprintf_s(m_buf.get_ptr(), BufSize, p, args);
405 inline fixed_string &format(const char *p, ...) VOGL_ATTRIBUTE_PRINTF(2, 3)
409 format_args(p, args);
414 // Note many of these ops are IN-PLACE string operations to avoid constructing new objects, which can make them inconvienent.
415 inline fixed_string &crop(uint start, uint len)
423 len = math::minimum<uint>(len, m_len - start);
426 memmove(m_buf.get_ptr(), m_buf.get_ptr() + start, len);
437 // half-open interval
438 inline fixed_string &substring(uint start, uint end)
440 VOGL_ASSERT(start <= end);
443 return crop(start, end - start);
446 inline fixed_string &left(uint len)
448 return substring(0, len);
451 inline fixed_string &mid(uint start, uint len)
453 return crop(start, len);
456 inline fixed_string &right(uint start)
458 return substring(start, get_len());
461 inline int find_left(const char *p, bool case_sensitive = false) const
465 const int p_len = vogl_strlen(p);
467 for (int i = 0; i <= (static_cast<int>(m_len) - p_len); i++)
468 if ((case_sensitive ? strncmp : vogl_strnicmp)(p, &m_buf[i], p_len) == 0)
474 inline int find_left(char c) const
476 for (uint i = 0; i < m_len; i++)
482 inline int find_right(char c) const
484 for (int i = (int)m_len - 1; i >= 0; i--)
490 inline int find_right(const char *p, bool case_sensitive = false) const
493 const int p_len = vogl_strlen(p);
495 for (int i = m_len - p_len; i >= 0; i--)
496 if ((case_sensitive ? strncmp : vogl_strnicmp)(p, &m_buf[i], p_len) == 0)
502 inline fixed_string &trim()
505 for (s = 0; s < (int)m_len; s++)
506 if (!vogl_isspace(m_buf[s]))
509 for (e = m_len - 1; e > s; e--)
510 if (!vogl_isspace(m_buf[e]))
519 fixed_array<char, BufSize> m_buf;
521 inline void check() const
523 VOGL_ASSERT(m_len <= cMaxLen);
524 VOGL_ASSERT(vogl_strlen(m_buf.get_ptr()) == m_len);
528 typedef fixed_string<32> fixed_string32;
529 typedef fixed_string<64> fixed_string64;
530 typedef fixed_string<128> fixed_string128;
531 typedef fixed_string<256> fixed_string256;
534 struct bitwise_movable<fixed_string<N> >
543 struct hasher<fixed_string<N> >
545 inline size_t operator()(const fixed_string<N> &key) const
547 return key.get_hash();