]> git.xonotic.org Git - xonotic/netradiant.git/blob - libs/string/string.h
Merge branch 'master' into Melanosuchus/cmake
[xonotic/netradiant.git] / libs / string / string.h
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
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.
11
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.
16
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
20  */
21
22 #if !defined( INCLUDED_STRING_STRING_H )
23 #define INCLUDED_STRING_STRING_H
24
25 /// \file
26 /// C-style null-terminated-character-array string library.
27
28 #include <cstring>
29 #include <cctype>
30 #include <algorithm>
31
32 #include "memory/allocator.h"
33 #include "generic/arrayrange.h"
34
35 /// \brief Returns true if \p string length is zero.
36 /// O(1)
37 inline bool string_empty( const char* string ){
38         return *string == '\0';
39 }
40
41 /// \brief Returns true if \p string length is not zero.
42 /// O(1)
43 inline bool string_not_empty( const char* string ){
44         return !string_empty( string );
45 }
46
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.
50 /// O(n)
51 inline int string_compare( const char* string, const char* other ){
52         return std::strcmp( string, other );
53 }
54
55 /// \brief Returns true if \p string is lexicographically equal to \p other.
56 /// O(n)
57 inline bool string_equal( const char* string, const char* other ){
58         return string_compare( string, other ) == 0;
59 }
60
61 /// \brief Returns true if [\p string, \p string + \p n) is lexicographically equal to [\p other, \p other + \p n).
62 /// O(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;
65 }
66
67 /// \brief Returns true if \p string is lexicographically less than \p other.
68 /// O(n)
69 inline bool string_less( const char* string, const char* other ){
70         return string_compare( string, other ) < 0;
71 }
72
73 /// \brief Returns <0 if \p string is lexicographically less than \p other after converting both to lower-case.
74 /// Returns >0 if \p string is lexicographically greater than \p other after converting both to lower-case.
75 /// Returns 0 if \p string is lexicographically equal to \p other after converting both to lower-case.
76 /// O(n)
77 inline int string_compare_nocase( const char* string, const char* other ){
78 #ifdef WIN32
79         return _stricmp( string, other );
80 #else
81         return strcasecmp( string, other );
82 #endif
83 }
84
85 /// \brief Returns <0 if [\p string, \p string + \p n) is lexicographically less than [\p other, \p other + \p n).
86 /// Returns >0 if [\p string, \p string + \p n) is lexicographically greater than [\p other, \p other + \p n).
87 /// Returns 0 if [\p string, \p string + \p n) is lexicographically equal to [\p other, \p other + \p n).
88 /// Treats all ascii characters as lower-case during comparisons.
89 /// O(n)
90 inline int string_compare_nocase_n( const char* string, const char* other, std::size_t n ){
91 #ifdef WIN32
92         return _strnicmp( string, other, n );
93 #else
94         return strncasecmp( string, other, n );
95 #endif
96 }
97
98 /// \brief Returns true if \p string is lexicographically equal to \p other.
99 /// Treats all ascii characters as lower-case during comparisons.
100 /// O(n)
101 inline bool string_equal_nocase( const char* string, const char* other ){
102         return string_compare_nocase( string, other ) == 0;
103 }
104
105 /// \brief Returns true if [\p string, \p string + \p n) is lexicographically equal to [\p other, \p other + \p n).
106 /// Treats all ascii characters as lower-case during comparisons.
107 /// O(n)
108 inline bool string_equal_nocase_n( const char* string, const char* other, std::size_t n ){
109         return string_compare_nocase_n( string, other, n ) == 0;
110 }
111
112 /// \brief Returns true if \p string is lexicographically less than \p other.
113 /// Treats all ascii characters as lower-case during comparisons.
114 /// O(n)
115 inline bool string_less_nocase( const char* string, const char* other ){
116         return string_compare_nocase( string, other ) < 0;
117 }
118
119 /// \brief Returns the number of non-null characters in \p string.
120 /// O(n)
121 inline std::size_t string_length( const char* string ){
122         return std::strlen( string );
123 }
124
125 /// \brief Returns true if the beginning of \p string is equal to \p prefix.
126 /// O(n)
127 inline bool string_equal_prefix( const char* string, const char* prefix ){
128         return string_equal_n( string, prefix, string_length( prefix ) );
129 }
130
131 /// \brief Returns true if the ending of \p string is equal to \p suffix.
132 /// O(n)
133 inline bool string_equal_suffix( const char* string, const char* suffix){
134         const char *s = string + string_length( string ) - string_length( suffix );
135         return string_equal_n( s , suffix, string_length( suffix ) );
136 }
137
138 /// \brief Copies \p other into \p string and returns \p string.
139 /// Assumes that the space allocated for \p string is at least string_length(other) + 1.
140 /// O(n)
141 inline char* string_copy( char* string, const char* other ){
142         return std::strcpy( string, other );
143 }
144
145 /// \brief Allocates a string buffer large enough to hold \p length characters, using \p allocator.
146 /// The returned buffer must be released with \c string_release using a matching \p allocator.
147 template<typename Allocator>
148 inline char* string_new( std::size_t length, Allocator& allocator ){
149         return allocator.allocate( length + 1 );
150 }
151
152 /// \brief Deallocates the \p buffer large enough to hold \p length characters, using \p allocator.
153 template<typename Allocator>
154 inline void string_release( char* buffer, std::size_t length, Allocator& allocator ){
155         allocator.deallocate( buffer, length + 1 );
156 }
157
158 /// \brief Returns a newly-allocated string which is a clone of \p other, using \p allocator.
159 /// The returned buffer must be released with \c string_release using a matching \p allocator.
160 template<typename Allocator>
161 inline char* string_clone( const char* other, Allocator& allocator ){
162         char* copied = string_new( string_length( other ), allocator );
163         std::strcpy( copied, other );
164         return copied;
165 }
166
167
168 /// \brief Allocates a string buffer large enough to hold \p length characters.
169 /// The returned buffer must be released with \c string_release.
170 inline char* string_new( std::size_t length ){
171         DefaultAllocator<char> allocator;
172         return string_new( length, allocator );
173 }
174
175 /// \brief Deallocates the \p buffer large enough to hold \p length characters.
176 inline void string_release( char* string, std::size_t length ){
177         DefaultAllocator<char> allocator;
178         string_release( string, length, allocator );
179 }
180
181 /// \brief Returns a newly-allocated string which is a clone of \p other.
182 /// The returned buffer must be released with \c string_release.
183 inline char* string_clone( const char* other ){
184         DefaultAllocator<char> allocator;
185         return string_clone( other, allocator );
186 }
187
188 /// \brief A re-entrant string tokeniser similar to strchr.
189 class StringTokeniser
190 {
191 bool istoken( char c ) const {
192         if ( strchr( m_delimiters, c ) != 0 ) {
193                 return false;
194         }
195         return true;
196 }
197 const char* advance(){
198         const char* token = m_pos;
199         bool intoken = true;
200         while ( !string_empty( m_pos ) )
201         {
202                 if ( !istoken( *m_pos ) ) {
203                         *m_pos = '\0';
204                         intoken = false;
205                 }
206                 else if ( !intoken ) {
207                         return token;
208                 }
209                 ++m_pos;
210         }
211         return token;
212 }
213 std::size_t m_length;
214 char* m_string;
215 char* m_pos;
216 const char* m_delimiters;
217 public:
218 StringTokeniser( const char* string, const char* delimiters = " \n\r\t\v" ) :
219         m_length( string_length( string ) ),
220         m_string( string_copy( string_new( m_length ), string ) ),
221         m_pos( m_string ),
222         m_delimiters( delimiters ){
223         while ( !string_empty( m_pos ) && !istoken( *m_pos ) )
224         {
225                 ++m_pos;
226         }
227 }
228 ~StringTokeniser(){
229         string_release( m_string, m_length );
230 }
231 /// \brief Returns the next token or "" if there are no more tokens available.
232 const char* getToken(){
233         return advance();
234 }
235 };
236
237 struct StringLessNoCase
238 {
239         bool operator()( const std::string& x, const std::string& y ) const {
240                 return string_less_nocase( x.c_str(), y.c_str() );
241         }
242
243         bool operator()( const char* x, const char* y ) const {
244                 return string_less_nocase( x, y );
245         }
246 };
247
248 typedef StringLessNoCase RawStringLessNoCase;
249
250 struct RawStringEqual
251 {
252         bool operator()( const char* x, const char* y ) const {
253                 return string_equal( x, y );
254         }
255 };
256
257 struct RawStringLess
258 {
259         bool operator()( const char* x, const char* y ) const {
260                 return string_less( x, y );
261         }
262 };
263 #endif