Coverage Report

Created: 2023-12-20 07:15

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