Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
StringHelper.inl
Go to the documentation of this file.
1/*
2Copyright (c) 2018 DIVIDE-Studio
3Copyright (c) 2009 Ionut Cava
4
5This file is part of DIVIDE Framework.
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software
9and associated documentation files (the "Software"), to deal in the Software
10without restriction,
11including without limitation the rights to use, copy, modify, merge, publish,
12distribute, sublicense,
13and/or sell copies of the Software, and to permit persons to whom the
14Software is furnished to do so,
15subject to the following conditions:
16
17The above copyright notice and this permission notice shall be included in
18all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21IMPLIED,
22INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
23PARTICULAR PURPOSE AND NONINFRINGEMENT.
24IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
25DAMAGES OR OTHER LIABILITY,
26WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
27IN CONNECTION WITH THE SOFTWARE
28OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30*/
31
32#pragma once
33#ifndef DVD_CORE_STRING_HELPER_INL_
34#define DVD_CORE_STRING_HELPER_INL_
35
36#ifndef FMT_EXCEPTIONS
37#define FMT_EXCEPTIONS 0
38#endif
39
41
42namespace Divide
43{
44 namespace Util
45 {
46 template<typename T_vec, typename T_str> requires is_vector<T_vec, T_str> && is_string<T_str>
47 void Split( const char* input, const char delimiter, T_vec& elems )
48 {
49 assert( input != nullptr );
50
51 const T_str original( input );
52 if ( !original.empty() )
53 {
54 {
55 size_t i = 0u;
56 const char* o = input;
57 for ( i = 0u; input[i]; (input[i] == delimiter) ? i++ : *(input++) )
58 {
59 NOP();
60 }
61 elems.resize( i + 1 );
62 input = o;
63 }
64
65 size_t idx = 0;
66 typename T_str::const_iterator start = eastl::begin( original );
67 typename T_str::const_iterator end = eastl::end( original );
68 typename T_str::const_iterator next = eastl::find( start, end, delimiter );
69 while ( next != end )
70 {
71 elems[idx++] = { start, next };
72 start = next + 1;
73 next = eastl::find( start, end, delimiter );
74 }
75 elems[idx] = { start, next };
76 }
77 else
78 {
79 elems.clear();
80 }
81 }
82
83 template<typename T_vec, typename T_str> requires is_vector<T_vec, T_str> && is_string<T_str>
84 T_vec Split( const char* input, const char delimiter )
85 {
86 T_vec elems;
87 Split<T_vec, T_str>( input, delimiter, elems );
88 return elems;
89 }
90
91 template<typename T_str> requires is_string<T_str>
92 bool IsNumber( const T_str& s )
93 {
94 return IsNumber( s.c_str() );
95 }
96
97 template<typename T_str> requires valid_replace_string<T_str>
98 void GetPermutations( std::string_view subject, vector<T_str>& permutationContainer )
99 {
100 permutationContainer.clear();
101 T_str tempCpy( subject );
102 std::sort( std::begin( tempCpy ), std::end( tempCpy ) );
103 do
104 {
105 permutationContainer.push_back( tempCpy );
106 }
107 while ( std::next_permutation( std::begin( tempCpy ), std::end( tempCpy ) ) );
108 }
109
110 template<typename T_str> requires valid_replace_string<T_str>
111 bool ReplaceStringInPlace( T_str& subject, const std::span<const std::string_view> search, std::string_view replace, bool recursive )
112 {
113 bool ret = true;
114 bool changed = true;
115 while ( changed )
116 {
117 changed = false;
118 for ( const std::string_view s : search )
119 {
120 changed = ReplaceStringInPlace( subject, s, replace, recursive );
121 ret = changed || ret;
122
123 }
124 }
125
126 return ret;
127 }
128
129 template<typename T_str> requires valid_replace_string<T_str>
130 T_str ReplaceString( std::string_view subject, const std::span<const std::string_view> search, std::string_view replace, bool recursive )
131 {
132 T_str ret{ subject };
133 bool changed = true;
134 while ( changed )
135 {
136 changed = false;
137 for ( const std::string_view s : search )
138 {
139 changed = ReplaceStringInPlace( ret, s, replace, recursive ) || changed;
140 }
141 }
142
143 return ret;
144 }
145
146 template<typename T_str> requires valid_replace_string<T_str>
147 bool ReplaceStringInPlace( T_str& subject,
148 const std::string_view search,
149 const std::string_view replace,
150 const bool recursive )
151 {
152 bool ret = false;
153 bool changed = true;
154 while ( changed )
155 {
156 changed = false;
157
158 size_t pos = 0;
159 while ( (pos = subject.find( search.data(), pos )) != T_str::npos )
160 {
161 subject.replace( pos, search.length(), replace.data() );
162 pos += replace.length();
163 changed = true;
164 ret = true;
165 }
166
167 if ( !recursive )
168 {
169 break;
170 }
171 }
172
173 return ret;
174 }
175
176 template<>
177 inline bool ReplaceStringInPlace( ResourcePath& subject,
178 const std::string_view search,
179 const std::string_view replace,
180 const bool recursive )
181 {
182 string temp = subject.string();
183 const bool ret = ReplaceStringInPlace( temp, search, replace, recursive );
184 subject = ResourcePath{ temp };
185 return ret;
186 }
187
188 template<typename T_str> requires valid_replace_string<T_str>
189 T_str ReplaceString( std::string_view subject,
190 std::string_view search,
191 std::string_view replace,
192 bool recursive )
193 {
194 T_str ret{ subject };
195 ReplaceStringInPlace( ret, search, replace, recursive );
196 return ret;
197 }
198
199 inline string MakeXMLSafe( const std::string_view subject )
200 {
201 constexpr std::string_view InvalidXMLStrings[10] =
202 {
203 " ", "[", "]", "...", "..", ".", "/", "'\'", "<", ">"
204 };
205
206 return ReplaceString( subject, InvalidXMLStrings, "__" );
207 }
208
210 {
211 return ResourcePath{ MakeXMLSafe( subject.string() ) };
212 }
213
214 inline bool BeginsWith( const std::string_view input, const std::string_view compare, bool ignoreWhitespace )
215 {
216 if ( ignoreWhitespace ) [[likely]]
217 {
218 const auto itBegin = input.find_first_not_of( " \t\n\r\f\v" );
219 if ( itBegin != std::string_view::npos )
220 {
221 return input.substr( itBegin ).starts_with( compare );
222 }
223 }
224
225 return input.starts_with( compare );
226 }
227
228
229 template<typename T_str> requires is_string<T_str>
230 T_str GetTrailingCharacters( const T_str& input, size_t count )
231 {
232 const size_t inputLength = input.length();
233 count = std::min( inputLength, count );
234 assert( count > 0 );
235 return input.substr( inputLength - count, inputLength ).data();
236 }
237
238 template<typename T_str> requires is_string<T_str>
239 T_str GetStartingCharacters( const T_str& input, size_t count )
240 {
241 const size_t inputLength = input.length();
242 count = std::min( inputLength, count );
243 assert( count > 0 );
244 return input.substr( 0, inputLength - count );
245 }
246
247 inline bool CompareIgnoreCase( const char* a, const char* b ) noexcept
248 {
249 if (a == nullptr || b == nullptr)
250 {
251 return false;
252 }
253
254 return strcasecmp( a, b ) == 0;
255 }
256
257 inline bool CompareIgnoreCase( const std::string_view a, const std::string_view b ) noexcept
258 {
259 if (a.size() != b.size())
260 {
261 return false;
262 }
263
264 for ( size_t i = 0; i < a.size(); ++i )
265 {
266 if ( tolower( a[i] ) != tolower( b[i] ) )
267 {
268 return false;
269 }
270 }
271
272 return true;
273 }
274
275 template<typename T_str> requires is_string<T_str>
276 U32 LineCount( const T_str& str )
277 {
278 return to_U32( std::count( std::cbegin( str ), std::cend( str ), '\n' ) ) + 1;
279 }
280
282 template<typename T_str> requires is_string<T_str>
283 T_str Ltrim( const T_str& s )
284 {
285 T_str temp( s );
286 return Ltrim( temp );
287 }
288
289 template<typename T_str> requires is_string<T_str>
290 T_str& Ltrim( T_str& s )
291 {
292 s.erase( s.begin(), std::find_if( s.begin(), s.end(), []( const T_str::value_type c ) noexcept
293 {
294 return !std::isspace( c );
295 } ) );
296 return s;
297 }
298
299 template<typename T_str> requires is_string<T_str>
300 T_str Rtrim( const T_str& s )
301 {
302 T_str temp( s );
303 return Rtrim( temp );
304 }
305
306 template<typename T_str> requires is_string<T_str>
307 T_str& Rtrim( T_str& s )
308 {
309 s.erase( std::find_if( s.rbegin(), s.rend(), []( const T_str::value_type c ) noexcept
310 {
311 return !std::isspace( c );
312 } ).base(), s.end() );
313 return s;
314 }
315
316 template<typename T_str> requires is_string<T_str>
317 T_str& Trim( T_str& s )
318 {
319 return Ltrim( Rtrim( s ) );
320 }
321
322 template<typename T_str> requires is_string<T_str>
323 T_str Trim( const T_str& s )
324 {
325 T_str temp( s );
326 return Trim( temp );
327 }
328
329 template<typename T_str> requires is_string<T_str>
330 bool GetLine( istringstream& input, T_str& line, const char delimiter )
331 {
332 if (std::getline(input, line, delimiter))
333 {
334 std::erase(line, '\r');
335 std::erase(line, '\n');
336 return true;
337 }
338
339 return false;
340 }
341
342 namespace detail
343 {
345
346 using custom_memory_buffer = fmt::basic_memory_buffer<char, fmt::inline_buffer_size, dvd_allocator<char>>;
347
348 FORCE_INLINE custom_memory_buffer vformat( fmt::string_view format_str, fmt::format_args args )
349 {
351 fmt::vformat_to( std::back_inserter( buf ), format_str, args );
352 return buf;
353 }
354
355 } //namespace detail
356
357 template <typename Str, typename... Args> requires (!concept_const_char<Str>)
358 FORCE_INLINE Str StringFormat( const char* fmt, Args&& ...args )
359 {
360 const detail::custom_memory_buffer buffer = detail::vformat( fmt, fmt::make_format_args( args... ) );
361 return Str( buffer.data(), buffer.size(), detail::s_allocator );
362 }
363
364 template <typename Str, typename... Args> requires (!concept_const_char<Str>)
365 FORCE_INLINE void StringFormat( Str& output, const char* fmt, Args&& ...args )
366 {
367 const detail::custom_memory_buffer buffer = detail::vformat( fmt, fmt::make_format_args( args... ) );
368 output.assign(buffer.data(), buffer.size());
369 }
370
371 template<typename T>
372 FORCE_INLINE string to_string( T value ) { return Util::StringFormat("{}", value ); }
373
374 } //namespace Util
375} //namespace Divide
376
377#endif //DVD_CORE_STRING_HELPER_INL_
#define NOP()
#define FORCE_INLINE
#define strcasecmp
mi_stl_allocator< T > dvd_allocator
fmt::basic_memory_buffer< char, fmt::inline_buffer_size, dvd_allocator< char > > custom_memory_buffer
dvd_allocator< char > s_allocator
FORCE_INLINE custom_memory_buffer vformat(fmt::string_view format_str, fmt::format_args args)
bool GetLine(istringstream &input, T_str &line, char delimiter='\n')
Str StringFormat(const char *fmt, Args &&...args)
string to_string(GET_PASS_TYPE< T > value)
void GetPermutations(std::string_view subject, vector< T_str > &permutationContainer)
bool CompareIgnoreCase(const char *a, const char *b) noexcept
bool BeginsWith(std::string_view input, std::string_view compare, bool ignoreWhitespace)
T_vec Split(const char *input, char delimiter)
http://stackoverflow.com/questions/236129/split-a-string-in-c
T_str & Trim(T_str &s)
T_str & Ltrim(T_str &s)
http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
T_str ReplaceString(std::string_view subject, std::span< const std::string_view > search, std::string_view replace, bool recursive=false)
string MakeXMLSafe(std::string_view subject)
bool IsNumber(const T_str &s)
U32 LineCount(const T_str &str)
T_str GetStartingCharacters(const T_str &input, size_t count)
T_str & Rtrim(T_str &s)
bool ReplaceStringInPlace(T_str &subject, std::span< const std::string_view > search, std::string_view replace, bool recursive=false)
T_str GetTrailingCharacters(const T_str &input, size_t count)
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
constexpr U32 to_U32(const T value)
eastl::vector< Type > vector
Definition: Vector.h:42
std::basic_istringstream< char, std::char_traits< char >, dvd_allocator< char > > istringstream
Definition: STLString.h:47
uint32_t U32
StringReturnType< N > string() const noexcept
Definition: ResourcePath.h:64