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"
33 #include "generic/arrayrange.h"
35 /// \brief Returns true if \p string length is zero.
37 inline bool string_empty(const char* string)
39 return *string == '\0';
42 /// \brief Returns true if \p string length is not zero.
44 inline bool string_not_empty(const char* string)
46 return !string_empty(string);
49 /// \brief Returns <0 if \p string is lexicographically less than \p other.
50 /// Returns >0 if \p string is lexicographically greater than \p other.
51 /// Returns 0 if \p string is lexicographically equal to \p other.
53 inline int string_compare(const char* string, const char* other)
55 return std::strcmp(string, other);
58 /// \brief Returns true if \p string is lexicographically equal to \p other.
60 inline bool string_equal(const char* string, const char* other)
62 return string_compare(string, other) == 0;
65 /// \brief Returns true if [\p string, \p string + \p n) is lexicographically equal to [\p other, \p other + \p n).
67 inline bool string_equal_n(const char* string, const char* other, std::size_t n)
69 return std::strncmp(string, other, n) == 0;
72 /// \brief Returns true if \p string is lexicographically less than \p other.
74 inline bool string_less(const char* string, const char* other)
76 return string_compare(string, other) < 0;
79 /// \brief Returns true if \p string is lexicographically greater than \p other.
81 inline bool string_greater(const char* string, const char* other)
83 return string_compare(string, other) > 0;
86 /// \brief Returns <0 if \p string is lexicographically less than \p other after converting both to lower-case.
87 /// Returns >0 if \p string is lexicographically greater than \p other after converting both to lower-case.
88 /// Returns 0 if \p string is lexicographically equal to \p other after converting both to lower-case.
90 inline int string_compare_nocase(const char* string, const char* other)
93 return _stricmp(string, other);
95 return strcasecmp(string, other);
99 /// \brief Returns <0 if [\p string, \p string + \p n) is lexicographically less than [\p other, \p other + \p n).
100 /// Returns >0 if [\p string, \p string + \p n) is lexicographically greater than [\p other, \p other + \p n).
101 /// Returns 0 if [\p string, \p string + \p n) is lexicographically equal to [\p other, \p other + \p n).
102 /// Treats all ascii characters as lower-case during comparisons.
104 inline int string_compare_nocase_n(const char* string, const char* other, std::size_t n)
107 return _strnicmp(string, other, n);
109 return strncasecmp(string, other, n);
113 /// \brief Returns true if \p string is lexicographically equal to \p other.
114 /// Treats all ascii characters as lower-case during comparisons.
116 inline bool string_equal_nocase(const char* string, const char* other)
118 return string_compare_nocase(string, other) == 0;
121 /// \brief Returns true if [\p string, \p string + \p n) is lexicographically equal to [\p other, \p other + \p n).
122 /// Treats all ascii characters as lower-case during comparisons.
124 inline bool string_equal_nocase_n(const char* string, const char* other, std::size_t n)
126 return string_compare_nocase_n(string, other, n) == 0;
129 /// \brief Returns true if \p string is lexicographically less than \p other.
130 /// Treats all ascii characters as lower-case during comparisons.
132 inline bool string_less_nocase(const char* string, const char* other)
134 return string_compare_nocase(string, other) < 0;
137 /// \brief Returns true if \p string is lexicographically greater than \p other.
138 /// Treats all ascii characters as lower-case during comparisons.
140 inline bool string_greater_nocase(const char* string, const char* other)
142 return string_compare_nocase(string, other) > 0;
145 /// \brief Returns the number of non-null characters in \p string.
147 inline std::size_t string_length(const char* string)
149 return std::strlen(string);
152 /// \brief Returns true if the beginning of \p string is equal to \p prefix.
154 inline bool string_equal_prefix(const char* string, const char* prefix)
156 return string_equal_n(string, prefix, string_length(prefix));
159 /// \brief Copies \p other into \p string and returns \p string.
160 /// Assumes that the space allocated for \p string is at least string_length(other) + 1.
162 inline char* string_copy(char* string, const char* other)
164 return std::strcpy(string, other);
167 /// \brief Allocates a string buffer large enough to hold \p length characters, using \p allocator.
168 /// The returned buffer must be released with \c string_release using a matching \p allocator.
169 template<typename Allocator>
170 inline char* string_new(std::size_t length, Allocator& allocator)
172 return allocator.allocate(length + 1);
175 /// \brief Deallocates the \p buffer large enough to hold \p length characters, using \p allocator.
176 template<typename Allocator>
177 inline void string_release(char* buffer, std::size_t length, Allocator& allocator)
179 allocator.deallocate(buffer, length + 1);
182 /// \brief Returns a newly-allocated string which is a clone of \p other, using \p allocator.
183 /// The returned buffer must be released with \c string_release using a matching \p allocator.
184 template<typename Allocator>
185 inline char* string_clone(const char* other, Allocator& allocator)
187 char* copied = string_new(string_length(other), allocator);
188 std::strcpy(copied, other);
192 /// \brief Returns a newly-allocated string which is a clone of [\p first, \p last), using \p allocator.
193 /// The returned buffer must be released with \c string_release using a matching \p allocator.
194 template<typename Allocator>
195 inline char* string_clone_range(StringRange range, Allocator& allocator)
197 std::size_t length = range.last - range.first;
198 char* copied = strncpy(string_new(length, allocator), range.first, length);
199 copied[length] = '\0';
203 /// \brief Allocates a string buffer large enough to hold \p length characters.
204 /// The returned buffer must be released with \c string_release.
205 inline char* string_new(std::size_t length)
207 DefaultAllocator<char> allocator;
208 return string_new(length, allocator);
211 /// \brief Deallocates the \p buffer large enough to hold \p length characters.
212 inline void string_release(char* string, std::size_t length)
214 DefaultAllocator<char> allocator;
215 string_release(string, length, allocator);
218 /// \brief Returns a newly-allocated string which is a clone of \p other.
219 /// The returned buffer must be released with \c string_release.
220 inline char* string_clone(const char* other)
222 DefaultAllocator<char> allocator;
223 return string_clone(other, allocator);
226 /// \brief Returns a newly-allocated string which is a clone of [\p first, \p last).
227 /// The returned buffer must be released with \c string_release.
228 inline char* string_clone_range(StringRange range)
230 DefaultAllocator<char> allocator;
231 return string_clone_range(range, allocator);
234 typedef char* char_pointer;
235 /// \brief Swaps the values of \p string and \p other.
236 inline void string_swap(char_pointer& string, char_pointer& other)
238 std::swap(string, other);
241 typedef const char* char_const_pointer;
242 /// \brief Swaps the values of \p string and \p other.
243 inline void string_swap(char_const_pointer& string, char_const_pointer& other)
245 std::swap(string, other);
248 /// \brief Converts each character of \p string to lower-case and returns \p string.
250 inline char* string_to_lowercase(char* string)
252 for(char* p = string; *p != '\0'; ++p)
254 *p = (char)std::tolower(*p);
259 /// \brief Converts each character of \p string to upper-case and returns \p string.
261 inline char* string_to_uppercase(char* string)
263 for(char* p = string; *p != '\0'; ++p)
265 *p = (char)std::toupper(*p);
270 /// \brief A re-entrant string tokeniser similar to strchr.
271 class StringTokeniser
273 bool istoken(char c) const
275 if(strchr(m_delimiters, c) != 0)
281 const char* advance()
283 const char* token = m_pos;
285 while(!string_empty(m_pos))
300 std::size_t m_length;
303 const char* m_delimiters;
305 StringTokeniser(const char* string, const char* delimiters = " \n\r\t\v") :
306 m_length(string_length(string)),
307 m_string(string_copy(string_new(m_length), string)),
309 m_delimiters(delimiters)
311 while(!string_empty(m_pos) && !istoken(*m_pos))
318 string_release(m_string, m_length);
320 /// \brief Returns the next token or "" if there are no more tokens available.
321 const char* getToken()
327 /// \brief A non-mutable c-style string.
329 /// \param Buffer The string storage implementation. Must be DefaultConstructible, CopyConstructible and Assignable. Must implement:
330 /// \li Buffer(const char* string) - constructor which copies a c-style \p string.
331 /// \li Buffer(const char* first, const char*) - constructor which copies a c-style string range [\p first, \p last).
332 /// \li void swap(Buffer& other) - swaps contents with \p other.
333 /// \li const char* c_str() - returns the stored non-mutable c-style string.
334 template<typename Buffer>
335 class String : public Buffer
343 String(const char* string)
347 String(StringRange range)
352 String& operator=(const String& other)
358 String& operator=(const char* string)
364 String& operator=(StringRange range)
371 void swap(String& other)
378 return string_empty(Buffer::c_str());
382 template<typename Buffer>
383 inline bool operator<(const String<Buffer>& self, const String<Buffer>& other)
385 return string_less(self.c_str(), other.c_str());
388 template<typename Buffer>
389 inline bool operator>(const String<Buffer>& self, const String<Buffer>& other)
391 return string_greater(self.c_str(), other.c_str());
394 template<typename Buffer>
395 inline bool operator==(const String<Buffer>& self, const String<Buffer>& other)
397 return string_equal(self.c_str(), other.c_str());
400 template<typename Buffer>
401 inline bool operator!=(const String<Buffer>& self, const String<Buffer>& other)
403 return !string_equal(self.c_str(), other.c_str());
406 template<typename Buffer>
407 inline bool operator==(const String<Buffer>& self, const char* other)
409 return string_equal(self.c_str(), other);
412 template<typename Buffer>
413 inline bool operator!=(const String<Buffer>& self, const char* other)
415 return !string_equal(self.c_str(), other);
420 /// \brief Swaps the values of \p self and \p other.
421 /// Overloads std::swap.
422 template<typename Buffer>
423 inline void swap(String<Buffer>& self, String<Buffer>& other)
430 /// \brief A non-mutable string buffer which manages memory allocation.
431 template<typename Allocator>
432 class CopiedBuffer : private Allocator
436 char* copy_range(StringRange range)
438 return string_clone_range(range, static_cast<Allocator&>(*this));
440 char* copy(const char* other)
442 return string_clone(other, static_cast<Allocator&>(*this));
444 void destroy(char* string)
446 string_release(string, string_length(string), static_cast<Allocator&>(*this));
459 explicit CopiedBuffer(const Allocator& allocator)
460 : Allocator(allocator), m_string(copy(""))
463 CopiedBuffer(const CopiedBuffer& other)
464 : Allocator(other), m_string(copy(other.m_string))
467 CopiedBuffer(const char* string, const Allocator& allocator = Allocator())
468 : Allocator(allocator), m_string(copy(string))
471 CopiedBuffer(StringRange range, const Allocator& allocator = Allocator())
472 : Allocator(allocator), m_string(copy_range(range))
475 const char* c_str() const
479 void swap(CopiedBuffer& other)
481 string_swap(m_string, other.m_string);
485 /// \brief A non-mutable string which uses copy-by-value for assignment.
486 typedef String< CopiedBuffer< DefaultAllocator<char> > > CopiedString;
489 /// \brief A non-mutable string buffer which uses reference-counting to avoid unnecessary allocations.
490 template<typename Allocator>
491 class SmartBuffer : private Allocator
495 char* copy_range(StringRange range)
497 char* buffer = Allocator::allocate(sizeof(std::size_t) + (range.last - range.first) + 1);
498 strncpy(buffer + sizeof(std::size_t), range.first, range.last - range.first);
499 buffer[sizeof(std::size_t) + (range.last - range.first)] = '\0';
500 *reinterpret_cast<std::size_t*>(buffer) = 0;
503 char* copy(const char* string)
505 char* buffer = Allocator::allocate(sizeof(std::size_t) + string_length(string) + 1);
506 strcpy(buffer + sizeof(std::size_t), string);
507 *reinterpret_cast<std::size_t*>(buffer) = 0;
510 void destroy(char* buffer)
512 Allocator::deallocate(buffer, sizeof(std::size_t) + string_length(c_str()) + 1);
515 void incref(char* buffer)
517 ++(*reinterpret_cast<std::size_t*>(buffer));
519 void decref(char* buffer)
521 if(--(*reinterpret_cast<std::size_t*>(buffer)) == 0)
536 explicit SmartBuffer(const Allocator& allocator)
537 : Allocator(allocator), m_buffer(copy(""))
541 SmartBuffer(const SmartBuffer& other)
542 : Allocator(other), m_buffer(other.m_buffer)
546 SmartBuffer(const char* string, const Allocator& allocator = Allocator())
547 : Allocator(allocator), m_buffer(copy(string))
551 SmartBuffer(StringRange range, const Allocator& allocator = Allocator())
552 : Allocator(allocator), m_buffer(copy_range(range))
556 const char* c_str() const
558 return m_buffer + sizeof(std::size_t);
560 void swap(SmartBuffer& other)
562 string_swap(m_buffer, other.m_buffer);
566 /// \brief A non-mutable string which uses copy-by-reference for assignment of SmartString.
567 typedef String< SmartBuffer< DefaultAllocator<char> > > SmartString;
569 class StringEqualNoCase
572 bool operator()(const CopiedString& key, const CopiedString& other) const
574 return string_equal_nocase(key.c_str(), other.c_str());
578 struct StringLessNoCase
580 bool operator()(const CopiedString& x, const CopiedString& y) const
582 return string_less_nocase(x.c_str(), y.c_str());
586 struct RawStringEqual
588 bool operator()(const char* x, const char* y) const
590 return string_equal(x, y);
596 bool operator()(const char* x, const char* y) const
598 return string_less(x, y);
602 struct RawStringLessNoCase
604 bool operator()(const char* x, const char* y) const
606 return string_less_nocase(x, y);