Coverage Report

Created: 2025-06-25 07:00

/src/poco/Foundation/include/Poco/String.h
Line
Count
Source (jump to first uncovered line)
1
//
2
// String.h
3
//
4
// Library: Foundation
5
// Package: Core
6
// Module:  String
7
//
8
// String utility functions.
9
//
10
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
11
// and Contributors.
12
//
13
// SPDX-License-Identifier: BSL-1.0
14
//
15
16
17
#ifndef Foundation_String_INCLUDED
18
#define Foundation_String_INCLUDED
19
20
21
#include "Poco/Foundation.h"
22
#include "Poco/Ascii.h"
23
#include <cstring>
24
#if !defined(POCO_NO_WSTRING)
25
#include <cwchar>
26
#endif
27
#include <algorithm>
28
29
30
// ignore loop unrolling warnings in this file
31
#if defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 6))
32
# pragma clang diagnostic push
33
# pragma clang diagnostic ignored "-Wpass-failed"
34
#endif
35
36
37
namespace Poco {
38
39
40
template <typename C>
41
std::size_t cstrlen(const C* str)
42
  /// Returns the length of a zero-terminated C string.
43
  /// For char and wchar_t based strings, overloads are
44
  /// provided that call strlen() and wcslen().
45
{
46
  const C* end = str;
47
  while (*end) ++end;
48
  return end - str;
49
}
50
51
52
inline std::size_t cstrlen(const char* str)
53
  /// Returns the length of a zero-terminated C string.
54
  /// This implementation calls std::strlen().
55
0
{
56
0
  return std::strlen(str);
57
0
}
58
59
60
#if !defined(POCO_NO_WSTRING)
61
62
63
inline std::size_t cstrlen(const wchar_t* str)
64
  /// Returns the length of a zero-terminated C string.
65
  /// This implementation calls std::wcslen().
66
0
{
67
0
  return std::wcslen(str);
68
0
}
69
70
71
#endif
72
73
74
template <class S>
75
S trimLeft(const S& str)
76
  /// Returns a copy of str with all leading
77
  /// whitespace removed.
78
{
79
  typename S::const_iterator it  = str.begin();
80
  typename S::const_iterator end = str.end();
81
82
  while (it != end && Ascii::isSpace(*it)) ++it;
83
  return S(it, end);
84
}
85
86
87
template <class S>
88
S& trimLeftInPlace(S& str)
89
  /// Removes all leading whitespace in str.
90
{
91
  typename S::iterator it  = str.begin();
92
  typename S::iterator end = str.end();
93
94
  while (it != end && Ascii::isSpace(*it)) ++it;
95
  str.erase(str.begin(), it);
96
  return str;
97
}
98
99
100
template <class S>
101
S trimRight(const S& str)
102
  /// Returns a copy of str with all trailing
103
  /// whitespace removed.
104
{
105
  std::ptrdiff_t pos = static_cast<std::ptrdiff_t>(str.size()) - 1;
106
107
  while (pos >= 0 && Ascii::isSpace(str[pos])) --pos;
108
  return S(str, 0, pos + 1);
109
}
110
111
112
template <class S>
113
S& trimRightInPlace(S& str)
114
  /// Removes all trailing whitespace in str.
115
721k
{
116
721k
  std::ptrdiff_t pos = static_cast<std::ptrdiff_t>(str.size()) - 1;
117
118
815k
  while (pos >= 0 && Ascii::isSpace(str[pos])) --pos;
119
721k
  str.resize(pos + 1);
120
121
721k
  return str;
122
721k
}
123
124
125
template <class S>
126
S trim(const S& str)
127
  /// Returns a copy of str with all leading and
128
  /// trailing whitespace removed.
129
0
{
130
0
  std::ptrdiff_t first = 0;
131
0
  std::ptrdiff_t last  = static_cast<std::ptrdiff_t>(str.size()) - 1;
132
133
0
  while (first <= last && Ascii::isSpace(str[first])) ++first;
134
0
  while (last >= first && Ascii::isSpace(str[last])) --last;
135
136
0
  return S(str, first, last - first + 1);
137
0
}
138
139
140
template <class S>
141
S& trimInPlace(S& str)
142
  /// Removes all leading and trailing whitespace in str.
143
0
{
144
0
  std::ptrdiff_t first = 0;
145
0
  std::ptrdiff_t last  = static_cast<std::ptrdiff_t>(str.size()) - 1;
146
147
0
  while (first <= last && Ascii::isSpace(str[first])) ++first;
148
0
  while (last >= first && Ascii::isSpace(str[last])) --last;
149
150
0
  if (last >= 0)
151
0
  {
152
0
    str.resize(last + 1);
153
0
    str.erase(0, first);
154
0
  }
155
0
  return str;
156
0
}
157
158
159
template <class S>
160
S toUpper(const S& str)
161
  /// Returns a copy of str containing all upper-case characters.
162
63.2k
{
163
63.2k
  S result(str);
164
165
63.2k
  typename S::iterator it  = result.begin();
166
63.2k
  typename S::iterator end = result.end();
167
168
63.2k
#if defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 6))
169
63.2k
# pragma clang loop unroll(enable)
170
#elif defined(POCO_MSVS_VERSION) && (POCO_MSVS_VERSION >= 2017)
171
# pragma loop(hint_parallel(0))
172
#endif
173
337k
  while (it != end)
174
274k
  {
175
274k
    int ch = static_cast<unsigned char>(*it);
176
274k
    *it = static_cast<typename S::value_type>(Ascii::toUpper(ch));
177
274k
    ++it;
178
274k
  }
179
63.2k
  return result;
180
63.2k
}
181
182
183
template <class S>
184
S& toUpperInPlace(S& str)
185
  /// Replaces all characters in str with their upper-case counterparts.
186
{
187
  typename S::iterator it  = str.begin();
188
  typename S::iterator end = str.end();
189
190
#if defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 6))
191
# pragma clang loop unroll(enable)
192
#elif defined(POCO_MSVS_VERSION) && (POCO_MSVS_VERSION >= 2017)
193
# pragma loop(hint_parallel(0))
194
#endif
195
  while (it != end)
196
  {
197
    int ch = static_cast<unsigned char>(*it);
198
    *it = static_cast<typename S::value_type>(Ascii::toUpper(ch));
199
    ++it;
200
  }
201
  return str;
202
}
203
204
205
template <class S>
206
S toLower(const S& str)
207
  /// Returns a copy of str containing all lower-case characters.
208
47.6k
{
209
47.6k
  S result(str);
210
211
47.6k
  typename S::iterator it  = result.begin();
212
47.6k
  typename S::iterator end = result.end();
213
214
47.6k
#if defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 6))
215
47.6k
# pragma clang loop unroll(enable)
216
#elif defined(POCO_MSVS_VERSION) && (POCO_MSVS_VERSION >= 2017)
217
# pragma loop(hint_parallel(0))
218
#endif
219
764k
  while (it != end)
220
716k
  {
221
716k
    int ch = static_cast<unsigned char>(*it);
222
716k
    *it = static_cast<typename S::value_type>(Ascii::toLower(ch));
223
716k
    ++it;
224
716k
  }
225
47.6k
  return result;
226
47.6k
}
227
228
229
template <class S>
230
S& toLowerInPlace(S& str)
231
  /// Replaces all characters in str with their lower-case counterparts.
232
60.6k
{
233
60.6k
  typename S::iterator it  = str.begin();
234
60.6k
  typename S::iterator end = str.end();
235
236
60.6k
#if defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 6))
237
60.6k
# pragma clang loop unroll(enable)
238
#elif defined(POCO_MSVS_VERSION) && (POCO_MSVS_VERSION >= 2017)
239
# pragma loop(hint_parallel(0))
240
#endif
241
108M
  while (it != end)
242
108M
  {
243
108M
    int ch = static_cast<unsigned char>(*it);
244
108M
    *it = static_cast<typename S::value_type>(Ascii::toLower(ch));
245
108M
    ++it;
246
108M
  }
247
60.6k
  return str;
248
60.6k
}
249
250
251
#if !defined(POCO_NO_TEMPLATE_ICOMPARE)
252
253
254
template <class S, class It>
255
int icompare(
256
  const S& str,
257
  typename S::size_type pos,
258
  typename S::size_type n,
259
  It it2,
260
  It end2)
261
  /// Case-insensitive string comparison
262
{
263
  typename S::size_type sz = str.size();
264
  if (pos > sz) pos = sz;
265
  if (pos + n > sz) n = sz - pos;
266
  It it1  = str.begin() + pos;
267
  It end1 = str.begin() + pos + n;
268
  while (it1 != end1 && it2 != end2)
269
  {
270
    typename S::value_type c1(static_cast<typename S::value_type>(Ascii::toLower(*it1)));
271
    typename S::value_type c2(static_cast<typename S::value_type>(Ascii::toLower(*it2)));
272
    if (c1 < c2)
273
      return -1;
274
    else if (c1 > c2)
275
      return 1;
276
    ++it1; ++it2;
277
  }
278
279
  if (it1 == end1)
280
    return it2 == end2 ? 0 : -1;
281
  else
282
    return 1;
283
}
284
285
286
template <class S>
287
int icompare(const S& str1, const S& str2)
288
  // A special optimization for an often used case.
289
55.1M
{
290
55.1M
  typename S::const_iterator it1(str1.begin());
291
55.1M
  const typename S::const_iterator end1(str1.end());
292
55.1M
  typename S::const_iterator it2(str2.begin());
293
55.1M
  const typename S::const_iterator end2(str2.end());
294
122M
  while (it1 != end1 && it2 != end2)
295
71.2M
  {
296
71.2M
    const typename S::value_type c1(static_cast<typename S::value_type>(Ascii::toLower(*it1)));
297
71.2M
    const typename S::value_type c2(static_cast<typename S::value_type>(Ascii::toLower(*it2)));
298
71.2M
    if (c1 < c2)
299
942k
      return -1;
300
70.2M
    else if (c1 > c2)
301
2.48M
      return 1;
302
67.7M
    ++it1; ++it2;
303
67.7M
  }
304
305
51.7M
  if (it1 == end1)
306
51.6M
    return it2 == end2 ? 0 : -1;
307
69.2k
  else
308
69.2k
    return 1;
309
51.7M
}
310
311
312
template <class S>
313
int icompare(const S& str1, typename S::size_type n1, const S& str2, typename S::size_type n2)
314
{
315
  if (n2 > str2.size()) n2 = str2.size();
316
  return icompare(str1, 0, n1, str2.begin(), str2.begin() + n2);
317
}
318
319
320
template <class S>
321
int icompare(const S& str1, typename S::size_type n, const S& str2)
322
{
323
  if (n > str2.size()) n = str2.size();
324
  return icompare(str1, 0, n, str2.begin(), str2.begin() + n);
325
}
326
327
328
template <class S>
329
int icompare(const S& str1, typename S::size_type pos, typename S::size_type n, const S& str2)
330
{
331
  return icompare(str1, pos, n, str2.begin(), str2.end());
332
}
333
334
335
template <class S>
336
int icompare(
337
  const S& str1,
338
  typename S::size_type pos1,
339
  typename S::size_type n1,
340
  const S& str2,
341
  typename S::size_type pos2,
342
  typename S::size_type n2)
343
{
344
  typename S::size_type sz2 = str2.size();
345
  if (pos2 > sz2) pos2 = sz2;
346
  if (pos2 + n2 > sz2) n2 = sz2 - pos2;
347
  return icompare(str1, pos1, n1, str2.begin() + pos2, str2.begin() + pos2 + n2);
348
}
349
350
351
template <class S>
352
int icompare(
353
  const S& str1,
354
  typename S::size_type pos1,
355
  typename S::size_type n,
356
  const S& str2,
357
  typename S::size_type pos2)
358
{
359
  typename S::size_type sz2 = str2.size();
360
  if (pos2 > sz2) pos2 = sz2;
361
  if (pos2 + n > sz2) n = sz2 - pos2;
362
  return icompare(str1, pos1, n, str2.begin() + pos2, str2.begin() + pos2 + n);
363
}
364
365
366
template <class S>
367
int icompare(
368
  const S& str,
369
  typename S::size_type pos,
370
  typename S::size_type n,
371
  const typename S::value_type* ptr)
372
367k
{
373
367k
  poco_check_ptr (ptr);
374
367k
  typename S::size_type sz = str.size();
375
367k
  if (pos > sz) pos = sz;
376
367k
  if (pos + n > sz) n = sz - pos;
377
367k
  typename S::const_iterator it  = str.begin() + pos;
378
367k
  typename S::const_iterator end = str.begin() + pos + n;
379
466k
  while (it != end && *ptr)
380
454k
  {
381
454k
    typename S::value_type c1(static_cast<typename S::value_type>(Ascii::toLower(*it)));
382
454k
    typename S::value_type c2(static_cast<typename S::value_type>(Ascii::toLower(*ptr)));
383
454k
    if (c1 < c2)
384
211k
      return -1;
385
243k
    else if (c1 > c2)
386
144k
      return 1;
387
98.4k
    ++it; ++ptr;
388
98.4k
  }
389
390
11.3k
  if (it == end)
391
11.0k
    return *ptr == 0 ? 0 : -1;
392
281
  else
393
281
    return 1;
394
11.3k
}
395
396
397
template <class S>
398
int icompare(
399
  const S& str,
400
  typename S::size_type pos,
401
  const typename S::value_type* ptr)
402
{
403
  int n = static_cast<int>(pos < str.size() ? str.size() - pos : 0);
404
  return icompare(str, pos, n, ptr);
405
}
406
407
408
template <class S>
409
int icompare(
410
  const S& str,
411
  const typename S::value_type* ptr)
412
367k
{
413
367k
  return icompare(str, 0, str.size(), ptr);
414
367k
}
415
416
417
#else
418
419
420
int Foundation_API icompare(const std::string& str, std::string::size_type pos, std::string::size_type n, std::string::const_iterator it2, std::string::const_iterator end2);
421
int Foundation_API icompare(const std::string& str1, const std::string& str2);
422
int Foundation_API icompare(const std::string& str1, std::string::size_type n1, const std::string& str2, std::string::size_type n2);
423
int Foundation_API icompare(const std::string& str1, std::string::size_type n, const std::string& str2);
424
int Foundation_API icompare(const std::string& str1, std::string::size_type pos, std::string::size_type n, const std::string& str2);
425
int Foundation_API icompare(const std::string& str1, std::string::size_type pos1, std::string::size_type n1, const std::string& str2, std::string::size_type pos2, std::string::size_type n2);
426
int Foundation_API icompare(const std::string& str1, std::string::size_type pos1, std::string::size_type n, const std::string& str2, std::string::size_type pos2);
427
int Foundation_API icompare(const std::string& str, std::string::size_type pos, std::string::size_type n, const std::string::value_type* ptr);
428
int Foundation_API icompare(const std::string& str, std::string::size_type pos, const std::string::value_type* ptr);
429
int Foundation_API icompare(const std::string& str, const std::string::value_type* ptr);
430
431
432
#endif
433
434
435
template <class S>
436
S translate(const S& str, const S& from, const S& to)
437
  /// Returns a copy of str with all characters in
438
  /// from replaced by the corresponding (by position)
439
  /// characters in to. If there is no corresponding
440
  /// character in to, the character is removed from
441
  /// the copy.
442
0
{
443
0
  S result;
444
0
  result.reserve(str.size());
445
0
  typename S::const_iterator it  = str.begin();
446
0
  typename S::const_iterator end = str.end();
447
0
  typename S::size_type toSize = to.size();
448
0
  while (it != end)
449
0
  {
450
0
    typename S::size_type pos = from.find(*it);
451
0
    if (pos == S::npos)
452
0
    {
453
0
      result += *it;
454
0
    }
455
0
    else
456
0
    {
457
0
      if (pos < toSize) result += to[pos];
458
0
    }
459
0
    ++it;
460
0
  }
461
0
  return result;
462
0
}
463
464
465
template <class S>
466
S translate(const S& str, const typename S::value_type* from, const typename S::value_type* to)
467
0
{
468
0
  poco_check_ptr (from);
469
0
  poco_check_ptr (to);
470
0
  return translate(str, S(from), S(to));
471
0
}
472
473
474
template <class S>
475
S& translateInPlace(S& str, const S& from, const S& to)
476
  /// Replaces in str all occurrences of characters in from
477
  /// with the corresponding (by position) characters in to.
478
  /// If there is no corresponding character, the character
479
  /// is removed.
480
{
481
  str = translate(str, from, to);
482
  return str;
483
}
484
485
486
template <class S>
487
S translateInPlace(S& str, const typename S::value_type* from, const typename S::value_type* to)
488
{
489
  poco_check_ptr (from);
490
  poco_check_ptr (to);
491
  str = translate(str, S(from), S(to));
492
#if defined(__SUNPRO_CC)
493
// Fix around the RVO bug in SunStudio 12.4
494
  S ret(str);
495
  return ret;
496
#else
497
  return str;
498
#endif
499
}
500
501
502
#if !defined(POCO_NO_TEMPLATE_ICOMPARE)
503
504
505
template <class S>
506
S& replaceInPlace(S& str, const S& from, const S& to, typename S::size_type start = 0)
507
{
508
  poco_assert (from.size() > 0);
509
510
  S result;
511
  typename S::size_type pos = 0;
512
  result.append(str, 0, start);
513
  do
514
  {
515
    pos = str.find(from, start);
516
    if (pos != S::npos)
517
    {
518
      result.append(str, start, pos - start);
519
      result.append(to);
520
      start = pos + from.length();
521
    }
522
    else result.append(str, start, str.size() - start);
523
  }
524
  while (pos != S::npos);
525
  str.swap(result);
526
  return str;
527
}
528
529
530
template <class S>
531
S& replaceInPlace(S& str, const typename S::value_type* from, const typename S::value_type* to, typename S::size_type start = 0)
532
0
{
533
0
  poco_assert (*from);
534
535
0
  S result;
536
0
  typename S::size_type pos = 0;
537
0
  typename S::size_type fromLen = cstrlen(from);
538
0
  result.append(str, 0, start);
539
0
  do
540
0
  {
541
0
    pos = str.find(from, start);
542
0
    if (pos != S::npos)
543
0
    {
544
0
      result.append(str, start, pos - start);
545
0
      result.append(to);
546
0
      start = pos + fromLen;
547
0
    }
548
0
    else result.append(str, start, str.size() - start);
549
0
  }
550
0
  while (pos != S::npos);
551
0
  str.swap(result);
552
0
  return str;
553
0
}
554
555
556
template <class S>
557
S& replaceInPlace(S& str, const typename S::value_type from, const typename S::value_type to = 0, typename S::size_type start = 0)
558
0
{
559
0
  if (from == to) return str;
560
561
0
  typename S::size_type pos = 0;
562
0
  do
563
0
  {
564
0
    pos = str.find(from, start);
565
0
    if (pos != S::npos)
566
0
    {
567
0
      if (to) str[pos] = to;
568
0
      else str.erase(pos, 1);
569
0
    }
570
0
  } while (pos != S::npos);
571
572
0
  return str;
573
0
}
574
575
576
template <class S>
577
S& removeInPlace(S& str, const typename S::value_type ch, typename S::size_type start = 0)
578
0
{
579
0
  return replaceInPlace(str, ch, 0, start);
580
0
}
581
582
583
template <class S>
584
S replace(const S& str, const S& from, const S& to, typename S::size_type start = 0)
585
  /// Replace all occurrences of from (which must not be the empty string)
586
  /// in str with to, starting at position start.
587
{
588
  S result(str);
589
  replaceInPlace(result, from, to, start);
590
  return result;
591
}
592
593
594
template <class S>
595
S replace(const S& str, const typename S::value_type* from, const typename S::value_type* to, typename S::size_type start = 0)
596
{
597
  S result(str);
598
  replaceInPlace(result, from, to, start);
599
  return result;
600
}
601
602
603
template <class S>
604
S replace(const S& str, const typename S::value_type from, const typename S::value_type to = 0, typename S::size_type start = 0)
605
{
606
  S result(str);
607
  replaceInPlace(result, from, to, start);
608
  return result;
609
}
610
611
612
template <class S>
613
S remove(const S& str, const typename S::value_type ch, typename S::size_type start = 0)
614
{
615
  S result(str);
616
  replaceInPlace(result, ch, 0, start);
617
  return result;
618
}
619
620
621
#else
622
623
624
Foundation_API std::string replace(const std::string& str, const std::string& from, const std::string& to, std::string::size_type start = 0);
625
Foundation_API std::string replace(const std::string& str, const std::string::value_type* from, const std::string::value_type* to, std::string::size_type start = 0);
626
Foundation_API std::string replace(const std::string& str, const std::string::value_type from, const std::string::value_type to = 0, std::string::size_type start = 0);
627
Foundation_API std::string remove(const std::string& str, const std::string::value_type ch, std::string::size_type start = 0);
628
Foundation_API std::string& replaceInPlace(std::string& str, const std::string& from, const std::string& to, std::string::size_type start = 0);
629
Foundation_API std::string& replaceInPlace(std::string& str, const std::string::value_type* from, const std::string::value_type* to, std::string::size_type start = 0);
630
Foundation_API std::string& replaceInPlace(std::string& str, const std::string::value_type from, const std::string::value_type to = 0, std::string::size_type start = 0);
631
Foundation_API std::string& removeInPlace(std::string& str, const std::string::value_type ch, std::string::size_type start = 0);
632
633
634
#endif
635
636
637
template <class S>
638
S cat(const S& s1, const S& s2)
639
  /// Concatenates two strings.
640
{
641
  S result = s1;
642
  result.reserve(s1.size() + s2.size());
643
  result.append(s2);
644
  return result;
645
}
646
647
648
template <class S>
649
S cat(const S& s1, const S& s2, const S& s3)
650
  /// Concatenates three strings.
651
{
652
  S result = s1;
653
  result.reserve(s1.size() + s2.size() + s3.size());
654
  result.append(s2);
655
  result.append(s3);
656
  return result;
657
}
658
659
660
template <class S>
661
S cat(const S& s1, const S& s2, const S& s3, const S& s4)
662
  /// Concatenates four strings.
663
{
664
  S result = s1;
665
  result.reserve(s1.size() + s2.size() + s3.size() + s4.size());
666
  result.append(s2);
667
  result.append(s3);
668
  result.append(s4);
669
  return result;
670
}
671
672
673
template <class S>
674
S cat(const S& s1, const S& s2, const S& s3, const S& s4, const S& s5)
675
  /// Concatenates five strings.
676
{
677
  S result = s1;
678
  result.reserve(s1.size() + s2.size() + s3.size() + s4.size() + s5.size());
679
  result.append(s2);
680
  result.append(s3);
681
  result.append(s4);
682
  result.append(s5);
683
  return result;
684
}
685
686
687
template <class S>
688
S cat(const S& s1, const S& s2, const S& s3, const S& s4, const S& s5, const S& s6)
689
  /// Concatenates six strings.
690
{
691
  S result = s1;
692
  result.reserve(s1.size() + s2.size() + s3.size() + s4.size() + s5.size() + s6.size());
693
  result.append(s2);
694
  result.append(s3);
695
  result.append(s4);
696
  result.append(s5);
697
  result.append(s6);
698
  return result;
699
}
700
701
702
template <class S, class It>
703
S cat(const S& delim, const It& begin, const It& end)
704
  /// Concatenates a sequence of strings, delimited
705
  /// by the string given in delim.
706
{
707
  S result;
708
  for (It it = begin; it != end; ++it)
709
  {
710
    if (!result.empty()) result.append(delim);
711
    result += *it;
712
  }
713
  return result;
714
}
715
716
717
template <class S>
718
bool startsWith(const S& str, const S& prefix)
719
  /// Tests whether the string starts with the given prefix.
720
{
721
  return str.size() >= prefix.size() && equal(prefix.begin(), prefix.end(), str.begin());
722
}
723
724
725
template <class S>
726
bool endsWith(const S& str, const S& suffix)
727
  /// Tests whether the string ends with the given suffix.
728
{
729
  return str.size() >= suffix.size() && equal(suffix.rbegin(), suffix.rend(), str.rbegin());
730
}
731
732
733
//
734
// case-insensitive string equality
735
//
736
737
738
template <typename charT>
739
struct i_char_traits : public std::char_traits<charT>
740
{
741
  inline static bool eq(charT c1, charT c2)
742
  {
743
    return Ascii::toLower(c1) == Ascii::toLower(c2);
744
  }
745
746
  inline static bool ne(charT c1, charT c2)
747
  {
748
    return !eq(c1, c2);
749
  }
750
751
  inline static bool lt(charT c1, charT c2)
752
  {
753
    return Ascii::toLower(c1) < Ascii::toLower(c2);
754
  }
755
756
  static int compare(const charT* s1, const charT* s2, std::size_t n)
757
  {
758
    for (int i = 0; i < n && s1 && s2; ++i, ++s1, ++s2)
759
    {
760
      if (Ascii::toLower(*s1) == Ascii::toLower(*s2)) continue;
761
      else if (Ascii::toLower(*s1) < Ascii::toLower(*s2)) return -1;
762
      else return 1;
763
    }
764
765
    return 0;
766
  }
767
768
  static const charT* find(const charT* s, int n, charT a)
769
  {
770
    while(n-- > 0 && Ascii::toLower(*s) != Ascii::toLower(a)) { ++s; }
771
    return s;
772
  }
773
};
774
775
776
using istring = std::basic_string<char, i_char_traits<char>>;
777
  /// Case-insensitive std::string counterpart.
778
779
780
template<typename T>
781
std::size_t isubstr(const T& str, const T& sought)
782
  /// Case-insensitive substring; searches for a substring
783
  /// without regards to case.
784
{
785
  typename T::const_iterator it = std::search(str.begin(), str.end(),
786
    sought.begin(), sought.end(),
787
    i_char_traits<typename T::value_type>::eq);
788
789
  if (it != str.end()) return it - str.begin();
790
  else return static_cast<std::size_t>(T::npos);
791
}
792
793
794
struct CILess
795
  /// Case-insensitive less-than functor; useful for standard maps
796
  /// and sets with std::strings keys and case-insensitive ordering
797
  /// requirement.
798
{
799
  inline bool operator() (const std::string& s1, const std::string& s2) const
800
147k
  {
801
147k
    return icompare(s1, s2) < 0;
802
147k
  }
803
};
804
805
806
template <typename T>
807
void secureClear(T& str)
808
  /// Securely clears a string's contents by first overwriting
809
  /// the entire buffer (up to capacity) with zeroes, then
810
  /// clearing the string.
811
0
{
812
0
  str.resize(str.capacity());
813
0
  std::fill(str.begin(), str.end(), typename T::value_type());
814
0
  str.clear();
815
0
}
816
817
818
} // namespace Poco
819
820
821
#if defined(__clang__) && ((__clang_major__ > 3) || (__clang_major__ == 3 && __clang_minor__ >= 6))
822
# pragma clang diagnostic pop
823
#endif
824
825
826
#endif // Foundation_String_INCLUDED