2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #if !defined(INCLUDED_STRING_STRING_H)
23 #define INCLUDED_STRING_STRING_H
26 /// C-style null-terminated-character-array string library.
32 #include "memory/allocator.h"
34 /// \brief Returns true if \p string length is zero.
36 inline bool string_empty(const char* string)
38 return *string == '\0';
41 /// \brief Returns true if \p string length is not zero.
43 inline bool string_not_empty(const char* string)
45 return !string_empty(string);
48 /// \brief Returns <0 if \p string is lexicographically less than \p other.
49 /// Returns >0 if \p string is lexicographically greater than \p other.
50 /// Returns 0 if \p string is lexicographically equal to \p other.
52 inline int string_compare(const char* string, const char* other)
54 return std::strcmp(string, other);
57 /// \brief Returns true if \p string is lexicographically equal to \p other.
59 inline bool string_equal(const char* string, const char* other)
61 return string_compare(string, other) == 0;
64 /// \brief Returns true if [\p string, \p string + \p n) is lexicographically equal to [\p other, \p other + \p n).
66 inline bool string_equal_n(const char* string, const char* other, std::size_t n)
68 return std::strncmp(string, other, n) == 0;
71 /// \brief Returns true if \p string is lexicographically less than \p other.
73 inline bool string_less(const char* string, const char* other)
75 return string_compare(string, other) < 0;
78 /// \brief Returns true if \p string is lexicographically greater than \p other.
80 inline bool string_greater(const char* string, const char* other)
82 return string_compare(string, other) > 0;
85 /// \brief Returns <0 if \p string is lexicographically less than \p other after converting both to lower-case.
86 /// Returns >0 if \p string is lexicographically greater than \p other after converting both to lower-case.
87 /// Returns 0 if \p string is lexicographically equal to \p other after converting both to lower-case.
89 inline int string_compare_nocase(const char* string, const char* other)
92 return _stricmp(string, other);
94 return strcasecmp(string, other);
98 /// \brief Returns <0 if [\p string, \p string + \p n) is lexicographically less than [\p other, \p other + \p n).
99 /// Returns >0 if [\p string, \p string + \p n) is lexicographically greater than [\p other, \p other + \p n).
100 /// Returns 0 if [\p string, \p string + \p n) is lexicographically equal to [\p other, \p other + \p n).
101 /// Treats all ascii characters as lower-case during comparisons.
103 inline int string_compare_nocase_n(const char* string, const char* other, std::size_t n)
106 return _strnicmp(string, other, n);
108 return strncasecmp(string, other, n);
112 /// \brief Returns true if \p string is lexicographically equal to \p other.
113 /// Treats all ascii characters as lower-case during comparisons.
115 inline bool string_equal_nocase(const char* string, const char* other)
117 return string_compare_nocase(string, other) == 0;
120 /// \brief Returns true if [\p string, \p string + \p n) is lexicographically equal to [\p other, \p other + \p n).
121 /// Treats all ascii characters as lower-case during comparisons.
123 inline bool string_equal_nocase_n(const char* string, const char* other, std::size_t n)
125 return string_compare_nocase_n(string, other, n) == 0;
128 /// \brief Returns true if \p string is lexicographically less than \p other.
129 /// Treats all ascii characters as lower-case during comparisons.
131 inline bool string_less_nocase(const char* string, const char* other)
133 return string_compare_nocase(string, other) < 0;
136 /// \brief Returns true if \p string is lexicographically greater than \p other.
137 /// Treats all ascii characters as lower-case during comparisons.
139 inline bool string_greater_nocase(const char* string, const char* other)
141 return string_compare_nocase(string, other) > 0;
144 /// \brief Returns the number of non-null characters in \p string.
146 inline std::size_t string_length(const char* string)
148 return std::strlen(string);
151 /// \brief Returns true if the beginning of \p string is equal to \p prefix.
153 inline bool string_equal_prefix(const char* string, const char* prefix)
155 return string_equal_n(string, prefix, string_length(prefix));
158 /// \brief Copies \p other into \p string and returns \p string.
159 /// Assumes that the space allocated for \p string is at least string_length(other) + 1.
161 inline char* string_copy(char* string, const char* other)
163 return std::strcpy(string, other);
166 /// \brief Allocates a string buffer large enough to hold \p length characters, using \p allocator.
167 /// The returned buffer must be released with \c string_release using a matching \p allocator.
168 template<typename Allocator>
169 inline char* string_new(std::size_t length, Allocator& allocator)
171 return allocator.allocate(length + 1);
174 /// \brief Deallocates the \p buffer large enough to hold \p length characters, using \p allocator.
175 template<typename Allocator>
176 inline void string_release(char* buffer, std::size_t length, Allocator& allocator)
178 allocator.deallocate(buffer, length + 1);
181 /// \brief Returns a newly-allocated string which is a clone of \p other, using \p allocator.
182 /// The returned buffer must be released with \c string_release using a matching \p allocator.
183 template<typename Allocator>
184 inline char* string_clone(const char* other, Allocator& allocator)
186 char* copied = string_new(string_length(other), allocator);
187 std::strcpy(copied, other);
191 /// \brief Returns a newly-allocated string which is a clone of [\p first, \p last), using \p allocator.
192 /// The returned buffer must be released with \c string_release using a matching \p allocator.
193 template<typename Allocator>
194 inline char* string_clone_range(const char* first, const char* last, Allocator& allocator)
196 std::size_t length = last - first;
197 char* copied = strncpy(string_new(length, allocator), first, length);
198 copied[length] = '\0';
202 /// \brief Allocates a string buffer large enough to hold \p length characters.
203 /// The returned buffer must be released with \c string_release.
204 inline char* string_new(std::size_t length)
206 DefaultAllocator<char> allocator;
207 return string_new(length, allocator);
210 /// \brief Deallocates the \p buffer large enough to hold \p length characters.
211 inline void string_release(char* string, std::size_t length)
213 DefaultAllocator<char> allocator;
214 string_release(string, length, allocator);
217 /// \brief Returns a newly-allocated string which is a clone of \p other.
218 /// The returned buffer must be released with \c string_release.
219 inline char* string_clone(const char* other)
221 DefaultAllocator<char> allocator;
222 return string_clone(other, allocator);
225 /// \brief Returns a newly-allocated string which is a clone of [\p first, \p last).
226 /// The returned buffer must be released with \c string_release.
227 inline char* string_clone_range(const char* first, const char* last)
229 DefaultAllocator<char> allocator;
230 return string_clone_range(first, last, allocator);
233 typedef char* char_pointer;
234 /// \brief Swaps the values of \p string and \p other.
235 inline void string_swap(char_pointer& string, char_pointer& other)
237 std::swap(string, other);
240 typedef const char* char_const_pointer;
241 /// \brief Swaps the values of \p string and \p other.
242 inline void string_swap(char_const_pointer& string, char_const_pointer& other)
244 std::swap(string, other);
247 /// \brief Converts each character of \p string to lower-case and returns \p string.
249 inline char* string_to_lowercase(char* string)
251 for(char* p = string; *p != '\0'; ++p)
253 *p = std::tolower(*p);
258 /// \brief Converts each character of \p string to upper-case and returns \p string.
260 inline char* string_to_uppercase(char* string)
262 for(char* p = string; *p != '\0'; ++p)
264 *p = std::toupper(*p);
269 /// \brief A re-entrant string tokeniser similar to strchr.
270 class StringTokeniser
272 bool istoken(char c) const
274 if(strchr(m_delimiters, c) != 0)
280 const char* advance()
282 const char* token = m_pos;
284 while(!string_empty(m_pos))
299 std::size_t m_length;
302 const char* m_delimiters;
304 StringTokeniser(const char* string, const char* delimiters = " \n\r\t\v") :
305 m_length(string_length(string)),
306 m_string(string_copy(string_new(m_length), string)),
308 m_delimiters(delimiters)
310 while(!string_empty(m_pos) && !istoken(*m_pos))
317 string_release(m_string, m_length);
319 /// \brief Returns the next token or "" if there are no more tokens available.
320 const char* getToken()
326 /// \brief A non-mutable c-style string.
328 /// \param Buffer The string storage implementation. Must be DefaultConstructible, CopyConstructible and Assignable. Must implement:
329 /// \li Buffer(const char* string) - constructor which copies a c-style \p string.
330 /// \li Buffer(const char* first, const char*) - constructor which copies a c-style string range [\p first, \p last).
331 /// \li void swap(Buffer& other) - swaps contents with \p other.
332 /// \li const char* c_str() - returns the stored non-mutable c-style string.
333 template<typename Buffer>
334 class String : public Buffer
342 String(const char* string)
346 String(const char* first, const char* last)
347 : Buffer(first, last)
351 String& operator=(const String& other)
357 String& operator=(const char* string)
364 void swap(String& other)
371 return string_empty(Buffer::c_str());
375 template<typename Buffer>
376 inline bool operator<(const String<Buffer>& self, const String<Buffer>& other)
378 return string_less(self.c_str(), other.c_str());
381 template<typename Buffer>
382 inline bool operator>(const String<Buffer>& self, const String<Buffer>& other)
384 return string_greater(self.c_str(), other.c_str());
387 template<typename Buffer>
388 inline bool operator==(const String<Buffer>& self, const String<Buffer>& other)
390 return string_equal(self.c_str(), other.c_str());
393 template<typename Buffer>
394 inline bool operator!=(const String<Buffer>& self, const String<Buffer>& other)
396 return !string_equal(self.c_str(), other.c_str());
399 template<typename Buffer>
400 inline bool operator==(const String<Buffer>& self, const char* other)
402 return string_equal(self.c_str(), other);
405 template<typename Buffer>
406 inline bool operator!=(const String<Buffer>& self, const char* other)
408 return !string_equal(self.c_str(), other);
413 /// \brief Swaps the values of \p self and \p other.
414 /// Overloads std::swap.
415 template<typename Buffer>
416 inline void swap(String<Buffer>& self, String<Buffer>& other)
423 /// \brief A non-mutable string buffer which manages memory allocation.
424 template<typename Allocator>
425 class CopiedBuffer : private Allocator
429 char* copy_range(const char* first, const char* last)
431 return string_clone_range(first, last, static_cast<Allocator&>(*this));
433 char* copy(const char* other)
435 return string_clone(other, static_cast<Allocator&>(*this));
437 void destroy(char* string)
439 string_release(string, string_length(string), static_cast<Allocator&>(*this));
452 explicit CopiedBuffer(const Allocator& allocator)
453 : Allocator(allocator), m_string(copy(""))
456 CopiedBuffer(const CopiedBuffer& other)
457 : Allocator(other), m_string(copy(other.m_string))
460 CopiedBuffer(const char* string, const Allocator& allocator = Allocator())
461 : Allocator(allocator), m_string(copy(string))
464 CopiedBuffer(const char* first, const char* last, const Allocator& allocator = Allocator())
465 : Allocator(allocator), m_string(copy_range(first, last))
468 const char* c_str() const
472 void swap(CopiedBuffer& other)
474 string_swap(m_string, other.m_string);
478 /// \brief A non-mutable string which uses copy-by-value for assignment.
479 typedef String< CopiedBuffer< DefaultAllocator<char> > > CopiedString;
482 /// \brief A non-mutable string buffer which uses reference-counting to avoid unnecessary allocations.
483 template<typename Allocator>
484 class SmartBuffer : private Allocator
488 char* copy_range(const char* first, const char* last)
490 char* buffer = Allocator::allocate(sizeof(std::size_t) + (last - first) + 1);
491 strncpy(buffer + sizeof(std::size_t), first, last - first);
492 buffer[sizeof(std::size_t) + (last - first)] = '\0';
493 *reinterpret_cast<std::size_t*>(buffer) = 0;
496 char* copy(const char* string)
498 char* buffer = Allocator::allocate(sizeof(std::size_t) + string_length(string) + 1);
499 strcpy(buffer + sizeof(std::size_t), string);
500 *reinterpret_cast<std::size_t*>(buffer) = 0;
503 void destroy(char* buffer)
505 Allocator::deallocate(buffer, sizeof(std::size_t) + string_length(c_str()) + 1);
508 void incref(char* buffer)
510 ++(*reinterpret_cast<std::size_t*>(buffer));
512 void decref(char* buffer)
514 if(--(*reinterpret_cast<std::size_t*>(buffer)) == 0)
529 explicit SmartBuffer(const Allocator& allocator)
530 : Allocator(allocator), m_buffer(copy(""))
534 SmartBuffer(const SmartBuffer& other)
535 : Allocator(other), m_buffer(other.m_buffer)
539 SmartBuffer(const char* string, const Allocator& allocator = Allocator())
540 : Allocator(allocator), m_buffer(copy(string))
544 SmartBuffer(const char* first, const char* last, const Allocator& allocator = Allocator())
545 : Allocator(allocator), m_buffer(copy_range(first, last))
549 const char* c_str() const
551 return m_buffer + sizeof(std::size_t);
553 void swap(SmartBuffer& other)
555 string_swap(m_buffer, other.m_buffer);
559 /// \brief A non-mutable string which uses copy-by-reference for assignment of SmartString.
560 typedef String< SmartBuffer< DefaultAllocator<char> > > SmartString;
562 class StringEqualNoCase
565 bool operator()(const CopiedString& key, const CopiedString& other) const
567 return string_equal_nocase(key.c_str(), other.c_str());
571 struct StringLessNoCase
573 bool operator()(const CopiedString& x, const CopiedString& y) const
575 return string_less_nocase(x.c_str(), y.c_str());
579 struct RawStringEqual
581 bool operator()(const char* x, const char* y) const
583 return string_equal(x, y);
589 bool operator()(const char* x, const char* y) const
591 return string_less(x, y);
595 struct RawStringLessNoCase
597 bool operator()(const char* x, const char* y) const
599 return string_less_nocase(x, y);