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 ){
38 return *string == '\0';
41 /// \brief Returns true if \p string length is not zero.
43 inline bool string_not_empty( const char* string ){
44 return !string_empty( string );
47 /// \brief Returns <0 if \p string is lexicographically less than \p other.
48 /// Returns >0 if \p string is lexicographically greater than \p other.
49 /// Returns 0 if \p string is lexicographically equal to \p other.
51 inline int string_compare( const char* string, const char* other ){
52 return std::strcmp( string, other );
55 /// \brief Returns true if \p string is lexicographically equal to \p other.
57 inline bool string_equal( const char* string, const char* other ){
58 return string_compare( string, other ) == 0;
61 /// \brief Returns true if [\p string, \p string + \p n) is lexicographically equal to [\p other, \p other + \p n).
63 inline bool string_equal_n( const char* string, const char* other, std::size_t n ){
64 return std::strncmp( string, other, n ) == 0;
67 /// \brief Returns true if \p string is lexicographically less than \p other.
69 inline bool string_less( const char* string, const char* other ){
70 return string_compare( string, other ) < 0;
73 /// \brief Returns true if \p string is lexicographically greater than \p other.
75 inline bool string_greater( const char* string, const char* other ){
76 return string_compare( string, other ) > 0;
79 /// \brief Returns <0 if \p string is lexicographically less than \p other after converting both to lower-case.
80 /// Returns >0 if \p string is lexicographically greater than \p other after converting both to lower-case.
81 /// Returns 0 if \p string is lexicographically equal to \p other after converting both to lower-case.
83 inline int string_compare_nocase( const char* string, const char* other ){
85 return _stricmp( string, other );
87 return strcasecmp( string, other );
91 /// \brief Returns <0 if [\p string, \p string + \p n) is lexicographically less than [\p other, \p other + \p n).
92 /// Returns >0 if [\p string, \p string + \p n) is lexicographically greater than [\p other, \p other + \p n).
93 /// Returns 0 if [\p string, \p string + \p n) is lexicographically equal to [\p other, \p other + \p n).
94 /// Treats all ascii characters as lower-case during comparisons.
96 inline int string_compare_nocase_n( const char* string, const char* other, std::size_t n ){
98 return _strnicmp( string, other, n );
100 return strncasecmp( string, other, n );
104 /// \brief Returns true if \p string is lexicographically equal to \p other.
105 /// Treats all ascii characters as lower-case during comparisons.
107 inline bool string_equal_nocase( const char* string, const char* other ){
108 return string_compare_nocase( string, other ) == 0;
111 /// \brief Returns true if [\p string, \p string + \p n) is lexicographically equal to [\p other, \p other + \p n).
112 /// Treats all ascii characters as lower-case during comparisons.
114 inline bool string_equal_nocase_n( const char* string, const char* other, std::size_t n ){
115 return string_compare_nocase_n( string, other, n ) == 0;
118 /// \brief Returns true if \p string is lexicographically less than \p other.
119 /// Treats all ascii characters as lower-case during comparisons.
121 inline bool string_less_nocase( const char* string, const char* other ){
122 return string_compare_nocase( string, other ) < 0;
125 /// \brief Returns true if \p string is lexicographically greater than \p other.
126 /// Treats all ascii characters as lower-case during comparisons.
128 inline bool string_greater_nocase( const char* string, const char* other ){
129 return string_compare_nocase( string, other ) > 0;
132 /// \brief Returns the number of non-null characters in \p string.
134 inline std::size_t string_length( const char* string ){
135 return std::strlen( string );
138 /// \brief Returns true if the beginning of \p string is equal to \p prefix.
140 inline bool string_equal_prefix( const char* string, const char* prefix ){
141 return string_equal_n( string, prefix, string_length( prefix ) );
144 /// \brief Returns true if the ending of \p string is equal to \p suffix.
146 inline bool string_equal_suffix( const char* string, const char* suffix){
147 const char *s = string + string_length( string ) - string_length( suffix );
148 return string_equal_n( s , suffix, string_length( suffix ) );
151 inline bool string_equal_suffix_nocase( const char* string, const char* suffix){
152 const char *s = string + string_length( string ) - string_length( suffix );
153 return string_equal_nocase_n( s , suffix, string_length( suffix ) );
156 /// \brief Copies \p other into \p string and returns \p string.
157 /// Assumes that the space allocated for \p string is at least string_length(other) + 1.
159 inline char* string_copy( char* string, const char* other ){
160 return std::strcpy( string, other );
163 /// \brief Allocates a string buffer large enough to hold \p length characters, using \p allocator.
164 /// The returned buffer must be released with \c string_release using a matching \p allocator.
165 template<typename Allocator>
166 inline char* string_new( std::size_t length, Allocator& allocator ){
167 return allocator.allocate( length + 1 );
170 /// \brief Deallocates the \p buffer large enough to hold \p length characters, using \p allocator.
171 template<typename Allocator>
172 inline void string_release( char* buffer, std::size_t length, Allocator& allocator ){
173 allocator.deallocate( buffer, length + 1 );
176 /// \brief Returns a newly-allocated string which is a clone of \p other, using \p allocator.
177 /// The returned buffer must be released with \c string_release using a matching \p allocator.
178 template<typename Allocator>
179 inline char* string_clone( const char* other, Allocator& allocator ){
180 char* copied = string_new( string_length( other ), allocator );
181 std::strcpy( copied, other );
185 /// \brief Returns a newly-allocated string which is a clone of [\p first, \p last), using \p allocator.
186 /// The returned buffer must be released with \c string_release using a matching \p allocator.
187 template<typename Allocator>
188 inline char* string_clone_range( StringRange range, Allocator& allocator ){
189 std::size_t length = range.last - range.first;
190 char* copied = strncpy( string_new( length, allocator ), range.first, length );
191 copied[length] = '\0';
195 /// \brief Allocates a string buffer large enough to hold \p length characters.
196 /// The returned buffer must be released with \c string_release.
197 inline char* string_new( std::size_t length ){
198 DefaultAllocator<char> allocator;
199 return string_new( length, allocator );
202 /// \brief Deallocates the \p buffer large enough to hold \p length characters.
203 inline void string_release( char* string, std::size_t length ){
204 DefaultAllocator<char> allocator;
205 string_release( string, length, allocator );
208 /// \brief Returns a newly-allocated string which is a clone of \p other.
209 /// The returned buffer must be released with \c string_release.
210 inline char* string_clone( const char* other ){
211 DefaultAllocator<char> allocator;
212 return string_clone( other, allocator );
215 /// \brief Returns a newly-allocated string which is a clone of [\p first, \p last).
216 /// The returned buffer must be released with \c string_release.
217 inline char* string_clone_range( StringRange range ){
218 DefaultAllocator<char> allocator;
219 return string_clone_range( range, allocator );
222 typedef char* char_pointer;
223 /// \brief Swaps the values of \p string and \p other.
224 inline void string_swap( char_pointer& string, char_pointer& other ){
225 std::swap( string, other );
228 typedef const char* char_const_pointer;
229 /// \brief Swaps the values of \p string and \p other.
230 inline void string_swap( char_const_pointer& string, char_const_pointer& other ){
231 std::swap( string, other );
234 /// \brief Converts each character of \p string to lower-case and returns \p string.
236 inline char* string_to_lowercase( char* string ){
237 for ( char* p = string; *p != '\0'; ++p )
239 *p = (char)std::tolower( *p );
244 /// \brief Converts each character of \p string to upper-case and returns \p string.
246 inline char* string_to_uppercase( char* string ){
247 for ( char* p = string; *p != '\0'; ++p )
249 *p = (char)std::toupper( *p );
254 /// \brief A re-entrant string tokeniser similar to strchr.
255 class StringTokeniser
257 bool istoken( char c ) const {
258 if ( strchr( m_delimiters, c ) != 0 ) {
263 const char* advance(){
264 const char* token = m_pos;
266 while ( !string_empty( m_pos ) )
268 if ( !istoken( *m_pos ) ) {
272 else if ( !intoken ) {
279 std::size_t m_length;
282 const char* m_delimiters;
284 StringTokeniser( const char* string, const char* delimiters = " \n\r\t\v" ) :
285 m_length( string_length( string ) ),
286 m_string( string_copy( string_new( m_length ), string ) ),
288 m_delimiters( delimiters ){
289 while ( !string_empty( m_pos ) && !istoken( *m_pos ) )
295 string_release( m_string, m_length );
297 /// \brief Returns the next token or "" if there are no more tokens available.
298 const char* getToken(){
303 /// \brief A non-mutable c-style string.
305 /// \param Buffer The string storage implementation. Must be DefaultConstructible, CopyConstructible and Assignable. Must implement:
306 /// \li Buffer(const char* string) - constructor which copies a c-style \p string.
307 /// \li Buffer(const char* first, const char*) - constructor which copies a c-style string range [\p first, \p last).
308 /// \li void swap(Buffer& other) - swaps contents with \p other.
309 /// \li const char* c_str() - returns the stored non-mutable c-style string.
310 template<typename Buffer>
311 class String : public Buffer
318 String( const char* string )
321 String( StringRange range )
325 String& operator=( const String& other ){
326 String temp( other );
330 String& operator=( const char* string ){
331 String temp( string );
335 String& operator=( StringRange range ){
336 String temp( range );
341 void swap( String& other ){
342 Buffer::swap( other );
346 return string_empty( Buffer::c_str() );
350 template<typename Buffer>
351 inline bool operator<( const String<Buffer>& self, const String<Buffer>& other ){
352 return string_less( self.c_str(), other.c_str() );
355 template<typename Buffer>
356 inline bool operator>( const String<Buffer>& self, const String<Buffer>& other ){
357 return string_greater( self.c_str(), other.c_str() );
360 template<typename Buffer>
361 inline bool operator==( const String<Buffer>& self, const String<Buffer>& other ){
362 return string_equal( self.c_str(), other.c_str() );
365 template<typename Buffer>
366 inline bool operator!=( const String<Buffer>& self, const String<Buffer>& other ){
367 return !string_equal( self.c_str(), other.c_str() );
370 template<typename Buffer>
371 inline bool operator==( const String<Buffer>& self, const char* other ){
372 return string_equal( self.c_str(), other );
375 template<typename Buffer>
376 inline bool operator!=( const String<Buffer>& self, const char* other ){
377 return !string_equal( self.c_str(), other );
382 /// \brief Swaps the values of \p self and \p other.
383 /// Overloads std::swap.
384 template<typename Buffer>
385 inline void swap( String<Buffer>& self, String<Buffer>& other ){
391 /// \brief A non-mutable string buffer which manages memory allocation.
392 template<typename Allocator>
393 class CopiedBuffer : private Allocator
397 char* copy_range( StringRange range ){
398 return string_clone_range( range, static_cast<Allocator&>( *this ) );
400 char* copy( const char* other ){
401 return string_clone( other, static_cast<Allocator&>( *this ) );
403 void destroy( char* string ){
404 string_release( string, string_length( string ), static_cast<Allocator&>( *this ) );
413 : m_string( copy( "" ) ){
415 explicit CopiedBuffer( const Allocator& allocator )
416 : Allocator( allocator ), m_string( copy( "" ) ){
418 CopiedBuffer( const CopiedBuffer& other )
419 : Allocator( other ), m_string( copy( other.m_string ) ){
421 CopiedBuffer( const char* string, const Allocator& allocator = Allocator() )
422 : Allocator( allocator ), m_string( copy( string ) ){
424 CopiedBuffer( StringRange range, const Allocator& allocator = Allocator() )
425 : Allocator( allocator ), m_string( copy_range( range ) ){
427 const char* c_str() const {
430 void swap( CopiedBuffer& other ){
431 string_swap( m_string, other.m_string );
435 /// \brief A non-mutable string which uses copy-by-value for assignment.
436 typedef String< CopiedBuffer< DefaultAllocator<char> > > CopiedString;
439 /// \brief A non-mutable string buffer which uses reference-counting to avoid unnecessary allocations.
440 template<typename Allocator>
441 class SmartBuffer : private Allocator
445 char* copy_range( StringRange range ){
446 char* buffer = Allocator::allocate( sizeof( std::size_t ) + ( range.last - range.first ) + 1 );
447 strncpy( buffer + sizeof( std::size_t ), range.first, range.last - range.first );
448 buffer[sizeof( std::size_t ) + ( range.last - range.first )] = '\0';
449 *reinterpret_cast<std::size_t*>( buffer ) = 0;
452 char* copy( const char* string ){
453 char* buffer = Allocator::allocate( sizeof( std::size_t ) + string_length( string ) + 1 );
454 strcpy( buffer + sizeof( std::size_t ), string );
455 *reinterpret_cast<std::size_t*>( buffer ) = 0;
458 void destroy( char* buffer ){
459 Allocator::deallocate( buffer, sizeof( std::size_t ) + string_length( c_str() ) + 1 );
462 void incref( char* buffer ){
463 ++( *reinterpret_cast<std::size_t*>( buffer ) );
465 void decref( char* buffer ){
466 if ( --( *reinterpret_cast<std::size_t*>( buffer ) ) == 0 ) {
477 : m_buffer( copy( "" ) ){
480 explicit SmartBuffer( const Allocator& allocator )
481 : Allocator( allocator ), m_buffer( copy( "" ) ){
484 SmartBuffer( const SmartBuffer& other )
485 : Allocator( other ), m_buffer( other.m_buffer ){
488 SmartBuffer( const char* string, const Allocator& allocator = Allocator() )
489 : Allocator( allocator ), m_buffer( copy( string ) ){
492 SmartBuffer( StringRange range, const Allocator& allocator = Allocator() )
493 : Allocator( allocator ), m_buffer( copy_range( range ) ){
496 const char* c_str() const {
497 return m_buffer + sizeof( std::size_t );
499 void swap( SmartBuffer& other ){
500 string_swap( m_buffer, other.m_buffer );
504 /// \brief A non-mutable string which uses copy-by-reference for assignment of SmartString.
505 typedef String< SmartBuffer< DefaultAllocator<char> > > SmartString;
507 class StringEqualNoCase
510 bool operator()( const CopiedString& key, const CopiedString& other ) const {
511 return string_equal_nocase( key.c_str(), other.c_str() );
515 struct StringLessNoCase
517 bool operator()( const CopiedString& x, const CopiedString& y ) const {
518 return string_less_nocase( x.c_str(), y.c_str() );
522 struct RawStringEqual
524 bool operator()( const char* x, const char* y ) const {
525 return string_equal( x, y );
531 bool operator()( const char* x, const char* y ) const {
532 return string_less( x, y );
536 struct RawStringLessNoCase
538 bool operator()( const char* x, const char* y ) const {
539 return string_less_nocase( x, y );