Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/std/cm/filesystem
Line
Count
Source
1
// -*-c++-*-
2
// vim: set ft=cpp:
3
4
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
5
   file LICENSE.rst or https://cmake.org/licensing for details.  */
6
#pragma once
7
8
#include "cmSTL.hxx" // IWYU pragma: keep
9
10
#include <cstdint>
11
#include <cstring>
12
#include <iterator>
13
#include <string>
14
#include <utility>
15
16
#include <cm/string_view>
17
#include <cm/type_traits>
18
#include <cmext/iterator>
19
20
#if defined(CMake_HAVE_CXX_FILESYSTEM)
21
22
#  include <filesystem> // IWYU pragma: export
23
24
#else
25
26
#  include <cstddef>
27
#  include <iostream>
28
#  include <memory>
29
30
#  include <cm/iomanip>
31
32
#  if defined(_WIN32) && !defined(__CYGWIN__)
33
#    include <algorithm>
34
#  endif
35
36
#endif
37
38
namespace cm {
39
namespace filesystem {
40
41
#if !defined(CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR)
42
// Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
43
// the source_traits for iterator check.  So disable it for now.
44
#  define CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR 0
45
#endif
46
47
namespace internals {
48
49
class unicode_helper
50
{
51
protected:
52
  using utf8_state = unsigned char;
53
  static utf8_state const s_start = 0;
54
  static utf8_state const s_reject = 8;
55
56
  static inline bool in_range(std::uint32_t c, std::uint32_t lo,
57
                              std::uint32_t hi)
58
0
  {
59
0
    return (static_cast<std::uint32_t>(c - lo) < (hi - lo + 1));
60
0
  }
61
62
  static inline bool is_surrogate(std::uint32_t c)
63
0
  {
64
0
    return in_range(c, 0xd800, 0xdfff);
65
0
  }
66
67
  static inline bool is_high_surrogate(std::uint32_t c)
68
0
  {
69
0
    return (c & 0xfffffc00) == 0xd800;
70
0
  }
71
72
  static inline bool is_low_surrogate(std::uint32_t c)
73
0
  {
74
0
    return (c & 0xfffffc00) == 0xdc00;
75
0
  }
76
77
  template <typename Char>
78
  static void append(std::basic_string<Char>& str, std::uint32_t codepoint)
79
0
  {
80
0
    if (codepoint <= 0x7f) {
81
0
      str.push_back(static_cast<Char>(codepoint));
82
0
    } else if (codepoint >= 0x80 && codepoint <= 0x7ff) {
83
0
      str.push_back(static_cast<Char>((codepoint >> 6) + 192));
84
0
      str.push_back(static_cast<Char>((codepoint & 0x3f) + 128));
85
0
    } else if ((codepoint >= 0x800 && codepoint <= 0xd7ff) ||
86
0
               (codepoint >= 0xe000 && codepoint <= 0xffff)) {
87
0
      str.push_back(static_cast<Char>((codepoint >> 12) + 224));
88
0
      str.push_back(static_cast<Char>(((codepoint & 0xfff) >> 6) + 128));
89
0
      str.push_back(static_cast<Char>((codepoint & 0x3f) + 128));
90
0
    } else if (codepoint >= 0x10000 && codepoint <= 0x10ffff) {
91
0
      str.push_back(static_cast<Char>((codepoint >> 18) + 240));
92
0
      str.push_back(static_cast<Char>(((codepoint & 0x3ffff) >> 12) + 128));
93
0
      str.push_back(static_cast<Char>(((codepoint & 0xfff) >> 6) + 128));
94
0
      str.push_back(static_cast<Char>((codepoint & 0x3f) + 128));
95
0
    } else {
96
0
      append(str, 0xfffd);
97
0
    }
98
0
  }
99
100
  static utf8_state decode(utf8_state const state, std::uint8_t const fragment,
101
                           std::uint32_t& codepoint);
102
};
103
104
template <typename Char, typename = void>
105
class unicode
106
{
107
};
108
109
template <typename Char>
110
class unicode<Char, typename std::enable_if<(sizeof(Char) == 4)>::type>
111
  : public unicode_helper
112
{
113
public:
114
  // UTF32 -> UTF8
115
  template <typename UTF8Char>
116
  static std::basic_string<UTF8Char> to_utf8(wchar_t const* str)
117
0
  {
118
0
    std::basic_string<UTF8Char> result;
119
0
    while (auto c = *str++) {
120
0
      append(result, c);
121
0
    }
122
0
    return result;
123
0
  }
124
  template <typename UTF8Char>
125
  static std::basic_string<UTF8Char> to_utf8(std::wstring const& str)
126
0
  {
127
0
    return unicode<Char>::template to_utf8<UTF8Char>(str.c_str());
128
0
  }
129
  template <typename UTF8Char>
130
  static std::basic_string<UTF8Char> to_utf8(wchar_t c)
131
0
  {
132
0
    std::basic_string<UTF8Char> result;
133
0
    append(result, c);
134
0
    return result;
135
0
  }
136
137
  // UTF8 -> UTF32
138
  template <typename UTF8Char>
139
  static std::wstring from_utf8(UTF8Char const* str, std::size_t length)
140
0
  {
141
0
    std::wstring result;
142
0
    result.reserve(length);
143
0
    utf8_state state = s_start;
144
0
    std::uint32_t codepoint = 0;
145
0
    while (*str) {
146
0
      if ((state = decode(state, static_cast<std::uint8_t>(*str++),
147
0
                          codepoint)) == s_start) {
148
0
        result += static_cast<std::wstring::value_type>(codepoint);
149
0
        codepoint = 0;
150
0
      } else if (state == s_reject) {
151
0
        result += static_cast<std::wstring::value_type>(0xfffd);
152
0
        state = s_start;
153
0
        codepoint = 0;
154
0
      }
155
0
    }
156
0
    if (state) {
157
0
      result += static_cast<std::wstring::value_type>(0xfffd);
158
0
    }
159
0
    return result;
160
0
  }
161
  template <typename UTF8Char>
162
  static std::wstring from_utf8(UTF8Char const* str)
163
0
  {
164
0
    return unicode<Char>::from_utf8(
165
0
      str, std::strlen(reinterpret_cast<char const*>(str)));
166
0
  }
167
  template <typename UTF8Char>
168
  static std::wstring from_utf8(std::basic_string<UTF8Char> const& str)
169
0
  {
170
0
    return unicode<Char>::from_utf8(str.c_str(), str.length());
171
0
  }
172
  template <typename UTF8Char>
173
  static std::wstring from_utf8(UTF8Char c)
174
0
  {
175
0
    std::wstring result;
176
0
    utf8_state state = s_start;
177
0
    std::uint32_t codepoint = 0;
178
0
    if ((state = decode(state, static_cast<std::uint8_t>(c), codepoint)) ==
179
0
        s_start) {
180
0
      result += static_cast<std::wstring::value_type>(codepoint);
181
0
    } else {
182
0
      result += static_cast<std::wstring::value_type>(0xfffd);
183
0
    }
184
0
185
0
    return result;
186
0
  }
187
};
188
189
template <typename Char>
190
class unicode<Char, typename std::enable_if<(sizeof(Char) == 2)>::type>
191
  : public unicode_helper
192
{
193
public:
194
  // UTF16 -> UTF8
195
  template <typename UTF8Char>
196
  static std::basic_string<UTF8Char> to_utf8(wchar_t const* str)
197
  {
198
    std::basic_string<UTF8Char> result;
199
    for (; *str; ++str) {
200
      std::uint32_t c = *str;
201
      if (is_surrogate(c)) {
202
        ++str;
203
        if (*str && is_high_surrogate(c) && is_low_surrogate(*str)) {
204
          append(result, (std::uint32_t(c) << 10) + *str - 0x35fdc00);
205
        } else {
206
          append(result, 0xfffd);
207
          if (!*str) {
208
            break;
209
          }
210
        }
211
      } else {
212
        append(result, c);
213
      }
214
    }
215
    return result;
216
  }
217
  template <typename UTF8Char>
218
  static std::basic_string<UTF8Char> to_utf8(std::wstring const& str)
219
  {
220
    return unicode<Char>::template to_utf8<UTF8Char>(str.c_str());
221
  }
222
  template <typename UTF8Char>
223
  static std::basic_string<UTF8Char> to_utf8(wchar_t c)
224
  {
225
    std::basic_string<UTF8Char> result;
226
    if (is_surrogate(c)) {
227
      append(result, 0xfffd);
228
    } else {
229
      append(result, c);
230
    }
231
    return result;
232
  }
233
234
  // UTF8 -> UTF16
235
  template <typename UTF8Char>
236
  static std::wstring from_utf8(UTF8Char const* str, std::size_t length)
237
  {
238
    std::wstring result;
239
    result.reserve(length);
240
    utf8_state state = s_start;
241
    std::uint32_t codepoint = 0;
242
    while (*str) {
243
      if ((state = decode(state, static_cast<std::uint8_t>(*str++),
244
                          codepoint)) == s_start) {
245
        if (codepoint <= 0xffff) {
246
          result += static_cast<std::wstring::value_type>(codepoint);
247
        } else {
248
          codepoint -= 0x10000;
249
          result +=
250
            static_cast<std::wstring::value_type>((codepoint >> 10) + 0xd800);
251
          result += static_cast<std::wstring::value_type>((codepoint & 0x3ff) +
252
                                                          0xdc00);
253
        }
254
        codepoint = 0;
255
      } else if (state == s_reject) {
256
        result += static_cast<std::wstring::value_type>(0xfffd);
257
        state = s_start;
258
        codepoint = 0;
259
      }
260
    }
261
    if (state) {
262
      result += static_cast<std::wstring::value_type>(0xfffd);
263
    }
264
    return result;
265
  }
266
  template <typename UTF8Char>
267
  static std::wstring from_utf8(UTF8Char const* str)
268
  {
269
    return unicode<Char>::from_utf8(
270
      str, std::strlen(reinterpret_cast<char const*>(str)));
271
  }
272
  template <typename UTF8Char>
273
  static std::wstring from_utf8(std::basic_string<UTF8Char> const& str)
274
  {
275
    return unicode<Char>::from_utf8(str.c_str(), str.length());
276
  }
277
  template <typename UTF8Char>
278
  static std::wstring from_utf8(UTF8Char c)
279
  {
280
    std::wstring result;
281
    utf8_state state = s_start;
282
    std::uint32_t codepoint = 0;
283
    if ((state = decode(state, static_cast<std::uint8_t>(c), codepoint)) ==
284
        s_start) {
285
      if (codepoint <= 0xffff) {
286
        result += static_cast<std::wstring::value_type>(codepoint);
287
      } else {
288
        codepoint -= 0x10000;
289
        result +=
290
          static_cast<std::wstring::value_type>((codepoint >> 10) + 0xd800);
291
        result +=
292
          static_cast<std::wstring::value_type>((codepoint & 0x3ff) + 0xdc00);
293
      }
294
    } else {
295
      result += static_cast<std::wstring::value_type>(0xfffd);
296
    }
297
    return result;
298
  }
299
};
300
301
template <typename In, typename Out>
302
class unicode_converter;
303
304
template <>
305
class unicode_converter<char, wchar_t>
306
{
307
public:
308
  std::wstring operator()(std::string const& in)
309
0
  {
310
0
    return unicode<wchar_t>::from_utf8(in);
311
0
  }
312
  std::wstring operator()(std::string&& in)
313
0
  {
314
0
    return unicode<wchar_t>::from_utf8(in);
315
0
  }
316
  std::wstring operator()(char const* in)
317
0
  {
318
0
    return unicode<wchar_t>::from_utf8(in);
319
0
  }
320
0
  std::wstring operator()(char in) { return unicode<wchar_t>::from_utf8(in); }
321
};
322
template <>
323
class unicode_converter<wchar_t, char>
324
{
325
public:
326
  std::string operator()(std::wstring const& in)
327
0
  {
328
0
    return unicode<wchar_t>::to_utf8<char>(in);
329
0
  }
330
  std::string operator()(std::wstring&& in)
331
0
  {
332
0
    return unicode<wchar_t>::to_utf8<char>(in);
333
0
  }
334
  std::string operator()(wchar_t const* in)
335
0
  {
336
0
    return unicode<wchar_t>::to_utf8<char>(in);
337
0
  }
338
  std::string operator()(wchar_t in)
339
0
  {
340
0
    return unicode<wchar_t>::to_utf8<char>(in);
341
0
  }
342
};
343
template <>
344
class unicode_converter<char, char>
345
{
346
public:
347
0
  std::string operator()(std::string const& in) { return in; }
348
0
  std::string operator()(std::string&& in) { return in; }
349
0
  std::string operator()(char const* in) { return std::string(in); }
350
0
  std::string operator()(char in) { return std::string(1, in); }
351
};
352
template <>
353
class unicode_converter<wchar_t, wchar_t>
354
{
355
public:
356
0
  std::wstring operator()(std::wstring const& in) { return in; }
357
0
  std::wstring operator()(std::wstring&& in) { return in; }
358
0
  std::wstring operator()(wchar_t const* in) { return std::wstring(in); }
359
0
  std::wstring operator()(wchar_t in) { return std::wstring(1, in); }
360
};
361
#if defined(__cpp_char8_t)
362
template <>
363
class unicode_converter<char, char8_t>
364
{
365
public:
366
  std::u8string operator()(std::string const& in)
367
  {
368
    return std::u8string{ reinterpret_cast<char8_t const*>(in.c_str()) };
369
  }
370
  std::u8string operator()(std::string&& in)
371
  {
372
    return std::u8string{ reinterpret_cast<char8_t const*>(in.c_str()) };
373
  }
374
  std::u8string operator()(char const* in)
375
  {
376
    return std::u8string{ reinterpret_cast<char8_t const*>(in) };
377
  }
378
  std::u8string operator()(char in)
379
  {
380
    return std::u8string{ 1, static_cast<char8_t>(in) };
381
  }
382
};
383
template <>
384
class unicode_converter<char8_t, char>
385
{
386
public:
387
  std::string operator()(std::u8string const& in)
388
  {
389
    return std::string{ reinterpret_cast<char const*>(in.c_str()) };
390
  }
391
  std::string operator()(std::u8string&& in)
392
  {
393
    return std::string{ reinterpret_cast<char const*>(in.c_str()) };
394
  }
395
  std::string operator()(char8_t const* in)
396
  {
397
    return std::string{ reinterpret_cast<char const*>(in) };
398
  }
399
  std::string operator()(char8_t in)
400
  {
401
    return std::string{ 1, static_cast<char>(in) };
402
  }
403
};
404
template <>
405
class unicode_converter<wchar_t, char8_t>
406
{
407
public:
408
  std::u8string operator()(std::wstring const& in)
409
  {
410
    return unicode<wchar_t>::to_utf8<char8_t>(in);
411
  }
412
  std::u8string operator()(std::wstring&& in)
413
  {
414
    return unicode<wchar_t>::to_utf8<char8_t>(in);
415
  }
416
  std::u8string operator()(wchar_t const* in)
417
  {
418
    return unicode<wchar_t>::to_utf8<char8_t>(in);
419
  }
420
  std::u8string operator()(wchar_t in)
421
  {
422
    return unicode<wchar_t>::to_utf8<char8_t>(in);
423
  }
424
};
425
template <>
426
class unicode_converter<char8_t, wchar_t>
427
{
428
public:
429
  std::wstring operator()(std::u8string const& in)
430
  {
431
    return unicode<wchar_t>::from_utf8(in);
432
  }
433
  std::wstring operator()(std::u8string&& in)
434
  {
435
    return unicode<wchar_t>::from_utf8(in);
436
  }
437
  std::wstring operator()(char8_t const* in)
438
  {
439
    return unicode<wchar_t>::from_utf8(in);
440
  }
441
  std::wstring operator()(char8_t in)
442
  {
443
    return unicode<wchar_t>::from_utf8(in);
444
  }
445
};
446
#endif
447
448
template <typename In>
449
struct string_converter
450
{
451
};
452
453
template <>
454
struct string_converter<char>
455
{
456
  // some compilers, like gcc 4.8 does not implement the following C++11
457
  // signature:
458
  // std::string::string(const string&, const Allocator&)
459
  // As workaround, use char* pointer.
460
  template <typename Char, typename Traits, typename Alloc>
461
  static std::basic_string<Char, Traits, Alloc> to(std::string const& in,
462
                                                   Alloc const& a)
463
  {
464
    return std::basic_string<Char, Traits, Alloc>(
465
      unicode_converter<char, Char>()(in).c_str(), a);
466
  }
467
  template <typename Char, typename Traits, typename Alloc>
468
  static std::basic_string<Char, Traits, Alloc> to(char const* in,
469
                                                   Alloc const& a)
470
  {
471
    return std::basic_string<Char, Traits, Alloc>(
472
      unicode_converter<char, Char>()(in).c_str(), a);
473
  }
474
  template <typename Char, typename Traits, typename Alloc>
475
  static std::basic_string<Char, Traits, Alloc> to(char in, Alloc const& a)
476
  {
477
    return std::basic_string<Char, Traits, Alloc>(
478
      unicode_converter<char, Char>()(in).c_str(), a);
479
  }
480
481
  template <typename Char>
482
  static std::basic_string<Char> to(std::string const& in)
483
0
  {
484
0
    return std::basic_string<Char>(unicode_converter<char, Char>()(in));
485
0
  }
486
  template <typename Char>
487
  static std::basic_string<Char> to(std::string&& in)
488
0
  {
489
0
    return std::basic_string<Char>(
490
0
      unicode_converter<char, Char>()(std::move(in)));
491
0
  }
492
  template <typename Char>
493
  static std::basic_string<Char> to(cm::string_view in)
494
  {
495
    return std::basic_string<Char>(
496
      unicode_converter<char, Char>()(std::string{ in.begin(), in.end() }));
497
  }
498
  template <typename Char>
499
  static std::basic_string<Char> to(char const* in)
500
  {
501
    return std::basic_string<Char>(unicode_converter<char, Char>()(in));
502
  }
503
  template <typename Char>
504
  static std::basic_string<Char> to(char in)
505
  {
506
    return std::basic_string<Char>(unicode_converter<char, Char>()(in));
507
  }
508
509
  template <typename Char, typename Iterator>
510
  static std::basic_string<Char> to(Iterator it)
511
  {
512
    char e = '\0';
513
    std::string tmp;
514
    for (; *it != e; ++it) {
515
      tmp.push_back(*it);
516
    }
517
    return std::basic_string<Char>(
518
      unicode_converter<char, Char>()(std::move(tmp)));
519
  }
520
  template <typename Char, typename Iterator>
521
  static std::basic_string<Char> to(Iterator begin, Iterator end)
522
  {
523
    return std::basic_string<Char>(
524
      unicode_converter<char, Char>()(std::string{ begin, end }));
525
  }
526
};
527
template <>
528
struct string_converter<wchar_t>
529
{
530
  // some compilers, like gcc 4.8 does not implement the following C++11
531
  // signature:
532
  // std::string::string(const string&, const Allocator&)
533
  // As workaround, use char* pointer.
534
  template <typename Char, typename Traits, typename Alloc>
535
  static std::basic_string<Char, Traits, Alloc> to(std::wstring const& in,
536
                                                   Alloc const& a)
537
  {
538
    return std::basic_string<Char, Traits, Alloc>(
539
      unicode_converter<wchar_t, Char>()(in).c_str(), a);
540
  }
541
  template <typename Char, typename Traits, typename Alloc>
542
  static std::basic_string<Char, Traits, Alloc> to(wchar_t const* in,
543
                                                   Alloc const& a)
544
  {
545
    return std::basic_string<Char, Traits, Alloc>(
546
      unicode_converter<wchar_t, Char>()(in).c_str(), a);
547
  }
548
  template <typename Char, typename Traits, typename Alloc>
549
  static std::basic_string<Char, Traits, Alloc> to(wchar_t in, Alloc const& a)
550
  {
551
    return std::basic_string<Char, Traits, Alloc>(
552
      unicode_converter<wchar_t, Char>()(in).c_str(), a);
553
  }
554
555
  template <typename Char>
556
  static std::basic_string<Char> to(std::wstring const& in)
557
0
  {
558
0
    return std::basic_string<Char>(unicode_converter<wchar_t, Char>()(in));
559
0
  }
560
  template <typename Char>
561
  static std::basic_string<Char> to(std::wstring&& in)
562
0
  {
563
0
    return std::basic_string<Char>(
564
0
      unicode_converter<wchar_t, Char>()(std::move(in)));
565
0
  }
566
  template <typename Char>
567
  static std::basic_string<Char> to(wchar_t const* in)
568
  {
569
    return std::basic_string<Char>(unicode_converter<wchar_t, Char>()(in));
570
  }
571
  template <typename Char>
572
  static std::basic_string<Char> to(wchar_t in)
573
  {
574
    return std::basic_string<Char>(unicode_converter<wchar_t, Char>()(in));
575
  }
576
577
  template <typename Char, typename Iterator>
578
  static std::basic_string<Char> to(Iterator it)
579
  {
580
    wchar_t e = '\0';
581
    std::wstring tmp;
582
    for (; *it != e; ++it) {
583
      tmp.push_back(*it);
584
    }
585
    return std::basic_string<Char>(
586
      unicode_converter<wchar_t, Char>()(std::move(tmp)));
587
  }
588
  template <typename Char, typename Iterator>
589
  static std::basic_string<Char> to(Iterator begin, Iterator end)
590
0
  {
591
0
    return std::basic_string<Char>(
592
0
      unicode_converter<wchar_t, Char>()(std::wstring{ begin, end }));
593
0
  }
594
};
595
#if defined(__cpp_char8_t)
596
template <>
597
struct string_converter<char8_t>
598
{
599
  // some compilers, like gcc 4.8 does not implement the following C++11
600
  // signature:
601
  // std::string::string(const string&, const Allocator&)
602
  // As workaround, use char* pointer.
603
  template <typename Char, typename Traits, typename Alloc>
604
  static std::basic_string<Char, Traits, Alloc> to(std::u8string const& in,
605
                                                   Alloc const& a)
606
  {
607
    return std::basic_string<Char, Traits, Alloc>(
608
      unicode_converter<char8_t, Char>()(in).c_str(), a);
609
  }
610
  template <typename Char, typename Traits, typename Alloc>
611
  static std::basic_string<Char, Traits, Alloc> to(char8_t const* in,
612
                                                   Alloc const& a)
613
  {
614
    return std::basic_string<Char, Traits, Alloc>(
615
      unicode_converter<char8_t, Char>()(in).c_str(), a);
616
  }
617
  template <typename Char, typename Traits, typename Alloc>
618
  static std::basic_string<Char, Traits, Alloc> to(char8_t in, Alloc const& a)
619
  {
620
    return std::basic_string<Char, Traits, Alloc>(
621
      unicode_converter<char8_t, Char>()(in).c_str(), a);
622
  }
623
624
  template <typename Char>
625
  static std::basic_string<Char> to(std::u8string const& in)
626
  {
627
    return std::basic_string<Char>(unicode_converter<char8_t, Char>()(in));
628
  }
629
  template <typename Char>
630
  static std::basic_string<Char> to(std::u8string&& in)
631
  {
632
    return std::basic_string<Char>(
633
      unicode_converter<char8_t, Char>()(std::move(in)));
634
  }
635
  template <typename Char>
636
  static std::basic_string<Char> to(char8_t const* in)
637
  {
638
    return std::basic_string<Char>(unicode_converter<char8_t, Char>()(in));
639
  }
640
  template <typename Char>
641
  static std::basic_string<Char> to(char8_t in)
642
  {
643
    return std::basic_string<Char>(unicode_converter<char8_t, Char>()(in));
644
  }
645
646
  template <typename Char, typename Iterator>
647
  static std::basic_string<Char> to(Iterator it)
648
  {
649
    char8_t e = '\0';
650
    std::u8string tmp;
651
    for (; *it != e; ++it) {
652
      tmp.push_back(*it);
653
    }
654
    return std::basic_string<Char>(
655
      unicode_converter<char8_t, Char>()(std::move(tmp)));
656
  }
657
  template <typename Char, typename Iterator>
658
  static std::basic_string<Char> to(Iterator begin, Iterator end)
659
  {
660
    return std::basic_string<Char>(
661
      unicode_converter<char8_t, Char>()(std::u8string{ begin, end }));
662
  }
663
};
664
#endif
665
666
template <typename T, typename = void>
667
struct source_traits
668
{
669
};
670
671
template <typename T, std::size_t N>
672
struct source_traits<T[N]>
673
{
674
  using value_type = T;
675
};
676
677
template <typename T>
678
struct source_traits<T*>
679
{
680
  using value_type = cm::decay_t<T>;
681
};
682
683
template <typename Char, typename Traits, typename Alloc>
684
struct source_traits<std::basic_string<Char, Traits, Alloc>>
685
{
686
  using value_type =
687
    typename std::basic_string<Char, Traits, Alloc>::value_type;
688
};
689
690
template <>
691
struct source_traits<cm::string_view>
692
{
693
  using value_type = cm::string_view::value_type;
694
};
695
696
#if CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR
697
template <typename T>
698
struct source_traits<T, cm::enable_if_t<cm::is_iterator<T>::value, void>>
699
{
700
  using value_type =
701
    typename std::iterator_traits<typename std::decay<T>::type>::value_type;
702
};
703
#endif
704
705
template <typename T>
706
struct is_pathable_string : std::false_type
707
{
708
};
709
template <typename Traits, typename Alloc>
710
struct is_pathable_string<std::basic_string<char, Traits, Alloc>>
711
  : std::true_type
712
{
713
};
714
template <typename Traits, typename Alloc>
715
struct is_pathable_string<std::basic_string<wchar_t, Traits, Alloc>>
716
  : std::true_type
717
{
718
};
719
template <>
720
struct is_pathable_string<cm::string_view> : std::true_type
721
{
722
};
723
724
template <typename T, typename = void>
725
struct is_pathable_char_array : std::false_type
726
{
727
};
728
template <typename T>
729
struct is_pathable_char_array<
730
  T,
731
  cm::enable_if_t<
732
    std::is_same<char*, typename std::decay<T>::type>::value ||
733
      std::is_same<wchar_t*, typename std::decay<T>::type>::value,
734
    void>>
735
  : bool_constant<std::is_same<char*, typename std::decay<T>::type>::value ||
736
                  std::is_same<wchar_t*, typename std::decay<T>::type>::value>
737
{
738
};
739
740
template <typename T, typename = void>
741
struct is_pathable_iterator : std::false_type
742
{
743
};
744
template <typename T>
745
struct is_pathable_iterator<
746
  T,
747
  cm::enable_if_t<
748
    is_input_iterator<T>::value &&
749
      (std::is_same<char,
750
                    typename std::iterator_traits<
751
                      typename std::decay<T>::type>::value_type>::value ||
752
       std::is_same<wchar_t,
753
                    typename std::iterator_traits<
754
                      typename std::decay<T>::type>::value_type>::value),
755
    void>>
756
  : bool_constant<
757
      std::is_same<char,
758
                   typename std::iterator_traits<
759
                     typename std::decay<T>::type>::value_type>::value ||
760
      std::is_same<wchar_t,
761
                   typename std::iterator_traits<
762
                     typename std::decay<T>::type>::value_type>::value>
763
{
764
};
765
766
#if defined(__SUNPRO_CC) && defined(__sparc)
767
// Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
768
// the full 'is_pathable' check.  We use it only to improve error messages
769
// via 'enable_if' when calling methods with incorrect types.  Just
770
// pretend all types are allowed so we can at least compile valid code.
771
template <typename T>
772
struct is_pathable : std::true_type
773
{
774
};
775
#else
776
template <typename T>
777
struct is_pathable
778
  : bool_constant<is_pathable_string<T>::value ||
779
                  is_pathable_char_array<T>::value ||
780
                  is_pathable_iterator<T>::value>
781
{
782
};
783
#endif
784
785
template <typename In, typename Out>
786
struct source_converter
787
{
788
};
789
790
template <>
791
struct source_converter<char, char>
792
{
793
  template <typename Iterator>
794
  static void append_range(std::string& p, Iterator b, Iterator e)
795
0
  {
796
0
    if (b == e) {
797
0
      return;
798
0
    }
799
0
    p.append(b, e);
800
0
  }
Unexecuted instantiation: void cm::filesystem::internals::source_converter<char, char>::append_range<char const*>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, char const*, char const*)
Unexecuted instantiation: void cm::filesystem::internals::source_converter<char, char>::append_range<std::__1::__wrap_iter<char const*> >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, std::__1::__wrap_iter<char const*>, std::__1::__wrap_iter<char const*>)
801
  template <typename Iterator>
802
  static void append_range(std::string& p, Iterator b)
803
0
  {
804
0
    char e = '\0';
805
0
806
0
    if (*b == e) {
807
0
      return;
808
0
    }
809
0
    for (; *b != e; ++b) {
810
0
      p.push_back(*b);
811
0
    }
812
0
  }
813
814
  static void append_source(std::string& p, cm::string_view s)
815
0
  {
816
0
    append_range(p, s.begin(), s.end());
817
0
  }
818
  static void append_source(std::string& p, std::string const& s)
819
0
  {
820
0
    append_range(p, s.begin(), s.end());
821
0
  }
822
  template <typename Source>
823
  static void append_source(std::string& p, Source const& s)
824
0
  {
825
0
    append_range(p, s);
826
0
  }
827
828
0
  static void set_source(std::string& p, std::string&& s) { p = std::move(s); }
829
830
  static std::string from(cm::string_view s)
831
0
  {
832
0
    return std::string{ s.begin(), s.end() };
833
0
  }
834
0
  static std::string from(std::string const& s) { return s; }
835
1.74k
  static std::string from(std::string&& s) { return s; }
836
  template <typename Source>
837
  static std::string from(Source const& s)
838
0
  {
839
0
    std::string result;
840
0
    append_source(result, s);
841
0
    return result;
842
0
  }
843
  template <typename Iterator>
844
  static std::string from(Iterator first, Iterator last)
845
0
  {
846
0
    return std::string{ first, last };
847
0
  }
848
};
849
template <>
850
struct source_converter<char, wchar_t>
851
{
852
  static std::wstring from(std::string const& s)
853
0
  {
854
0
    return string_converter<char>::to<wchar_t>(s);
855
0
  }
856
  static std::wstring from(std::string&& s)
857
0
  {
858
0
    return string_converter<char>::to<wchar_t>(std::move(s));
859
0
  }
860
  template <typename Source>
861
  static std::wstring from(Source const& s)
862
  {
863
    return string_converter<char>::to<wchar_t>(s);
864
  }
865
  template <typename Iterator>
866
  static std::wstring from(Iterator first, Iterator last)
867
  {
868
    return string_converter<char>::to<wchar_t>(first, last);
869
  }
870
};
871
872
template <>
873
struct source_converter<wchar_t, wchar_t>
874
{
875
  template <typename Iterator>
876
  static void append_range(std::wstring& p, Iterator b, Iterator e)
877
  {
878
    if (b == e) {
879
      return;
880
    }
881
    p.append(b, e);
882
  }
883
  template <typename Iterator>
884
  static void append_range(std::wstring& p, Iterator b)
885
  {
886
    char e = '\0';
887
888
    if (*b == e) {
889
      return;
890
    }
891
    for (; *b != e; ++b) {
892
      p.push_back(*b);
893
    }
894
  }
895
896
  template <typename Source>
897
  static void append_source(std::wstring& p, Source const& s)
898
  {
899
    append_range(p, s);
900
  }
901
902
0
  static std::wstring from(std::wstring const& s) { return s; }
903
0
  static std::wstring from(std::wstring&& s) { return s; }
904
  template <typename Source>
905
  static std::wstring from(Source const& s)
906
  {
907
    std::wstring result;
908
    append_source(result, s);
909
    return result;
910
  }
911
  template <typename Iterator>
912
  static std::wstring from(Iterator first, Iterator last)
913
  {
914
    return std::wstring{ first, last };
915
  }
916
};
917
template <>
918
struct source_converter<wchar_t, char>
919
{
920
  template <typename Iterator>
921
  static void append_range(std::string& p, Iterator b, Iterator e)
922
0
  {
923
0
    if (b == e) {
924
0
      return;
925
0
    }
926
0
927
0
    std::string dest = string_converter<wchar_t>::to<char>(b, e);
928
0
    p.append(dest.begin(), dest.end());
929
0
  }
930
  template <typename Iterator>
931
  static void append_range(std::string& p, Iterator b)
932
  {
933
    wchar_t e = '\0';
934
935
    if (*b == e) {
936
      return;
937
    }
938
939
    std::string dest = string_converter<wchar_t>::to<char>(b);
940
    p.append(dest.begin(), dest.end());
941
  }
942
943
  static void append_source(std::string& p, std::wstring const& s)
944
0
  {
945
0
    append_range(p, s.begin(), s.end());
946
0
  }
947
  template <typename Source>
948
  static void append_source(std::string& p, Source const& s)
949
  {
950
    append_range(p, s);
951
  }
952
953
  static void set_source(std::string& p, std::wstring&& s)
954
0
  {
955
0
    p = string_converter<wchar_t>::to<char>(std::move(s));
956
0
  }
957
958
  static std::string from(std::wstring const& s)
959
0
  {
960
0
    return string_converter<wchar_t>::to<char>(s);
961
0
  }
962
  static std::string from(std::wstring&& s)
963
0
  {
964
0
    return string_converter<wchar_t>::to<char>(std::move(s));
965
0
  }
966
  template <typename Source>
967
  static std::string from(Source const& s)
968
  {
969
    return string_converter<wchar_t>::to<char>(s);
970
  }
971
  template <typename Iterator>
972
  static std::string from(Iterator first, Iterator last)
973
  {
974
    return string_converter<wchar_t>::to<char>(first, last);
975
  }
976
};
977
978
#if defined(__cpp_char8_t)
979
template <>
980
struct source_converter<char, char8_t>
981
{
982
  static std::u8string from(std::string const& s)
983
  {
984
    return string_converter<char>::to<char8_t>(s);
985
  }
986
  static std::u8string from(std::string&& s)
987
  {
988
    return string_converter<char>::to<char8_t>(std::move(s));
989
  }
990
  template <typename Source>
991
  static std::u8string from(Source const& s)
992
  {
993
    return string_converter<char>::to<char8_t>(s);
994
  }
995
  template <typename Iterator>
996
  static std::u8string from(Iterator first, Iterator last)
997
  {
998
    return string_converter<char>::to<char8_t>(first, last);
999
  }
1000
};
1001
template <>
1002
struct source_converter<char8_t, char>
1003
{
1004
  static std::string from(std::u8string const& s)
1005
  {
1006
    return string_converter<char8_t>::to<char>(s);
1007
  }
1008
  static std::string from(std::u8string&& s)
1009
  {
1010
    return string_converter<char8_t>::to<char>(std::move(s));
1011
  }
1012
  template <typename Source>
1013
  static std::string from(Source const& s)
1014
  {
1015
    return string_converter<char8_t>::to<char>(s);
1016
  }
1017
  template <typename Iterator>
1018
  static std::string from(Iterator first, Iterator last)
1019
  {
1020
    return string_converter<char8_t>::to<char>(first, last);
1021
  }
1022
};
1023
template <>
1024
struct source_converter<wchar_t, char8_t>
1025
{
1026
  static std::u8string from(std::wstring const& s)
1027
  {
1028
    return string_converter<wchar_t>::to<char8_t>(s);
1029
  }
1030
  static std::u8string from(std::wstring&& s)
1031
  {
1032
    return string_converter<wchar_t>::to<char8_t>(std::move(s));
1033
  }
1034
  template <typename Source>
1035
  static std::u8string from(Source const& s)
1036
  {
1037
    return string_converter<wchar_t>::to<char8_t>(s);
1038
  }
1039
  template <typename Iterator>
1040
  static std::u8string from(Iterator first, Iterator last)
1041
  {
1042
    return string_converter<wchar_t>::to<char8_t>(first, last);
1043
  }
1044
};
1045
template <>
1046
struct source_converter<char8_t, wchar_t>
1047
{
1048
  static std::wstring from(std::u8string const& s)
1049
  {
1050
    return string_converter<char8_t>::to<wchar_t>(s);
1051
  }
1052
  static std::wstring from(std::u8string&& s)
1053
  {
1054
    return string_converter<char8_t>::to<wchar_t>(std::move(s));
1055
  }
1056
  template <typename Source>
1057
  static std::wstring from(Source const& s)
1058
  {
1059
    return string_converter<char8_t>::to<wchar_t>(s);
1060
  }
1061
  template <typename Iterator>
1062
  static std::wstring from(Iterator first, Iterator last)
1063
  {
1064
    return string_converter<char8_t>::to<wchar_t>(first, last);
1065
  }
1066
};
1067
#endif
1068
}
1069
1070
#if defined(CMake_HAVE_CXX_FILESYSTEM)
1071
1072
class path : public std::filesystem::path
1073
{
1074
private:
1075
  using base = std::filesystem::path;
1076
  // define the char type to convert to
1077
#  if defined(__cpp_char8_t) && defined(_WIN32) && !defined(__CYGWIN__)
1078
  using target_type = char8_t;
1079
#  else
1080
  using target_type = base::value_type;
1081
#  endif
1082
1083
  template <typename Source>
1084
  using enable_if_pathable =
1085
    enable_if_t<filesystem::internals::is_pathable<Source>::value, path&>;
1086
1087
  template <typename Source, typename Target = target_type>
1088
  using string_converter = filesystem::internals::source_converter<
1089
    typename filesystem::internals::source_traits<Source>::value_type, Target>;
1090
  template <typename Iterator, typename Target = target_type>
1091
  using range_converter = filesystem::internals::source_converter<
1092
    typename std::iterator_traits<Iterator>::value_type, Target>;
1093
1094
public:
1095
  class iterator;
1096
  using const_iterator = iterator;
1097
1098
  // Constructors
1099
  // ============
1100
0
  path() noexcept {}
1101
  path(path const& p)
1102
348
    : base(p)
1103
348
  {
1104
348
  }
1105
  path(path&& p) noexcept
1106
2.80k
    : base(std::move(p))
1107
2.80k
  {
1108
2.80k
  }
1109
  path(string_type&& source, format fmt = format::auto_format)
1110
1.39k
    : base(string_converter<string_type>::from(std::move(source)), fmt)
1111
1.39k
  {
1112
1.39k
  }
1113
  template <typename Source, typename = enable_if_pathable<Source>>
1114
  path(Source const& source, format fmt = format::auto_format)
1115
    : base(string_converter<Source>::from(source), fmt)
1116
  {
1117
  }
1118
  template <typename Iterator, typename = enable_if_pathable<Iterator>>
1119
  path(Iterator first, Iterator last, format fmt = format::auto_format)
1120
    : base(range_converter<Iterator>::from(first, last), fmt)
1121
  {
1122
  }
1123
1124
7.71k
  ~path() = default;
1125
1126
  // Assignments
1127
  // ===========
1128
  path& operator=(path const& p)
1129
0
  {
1130
0
    if (this != &p) {
1131
0
      this->base::operator=(static_cast<base const&>(p));
1132
0
    }
1133
0
    return *this;
1134
0
  }
1135
  path& operator=(path&& p) noexcept
1136
0
  {
1137
0
    if (this != &p) {
1138
0
      this->base::operator=(std::move(static_cast<base&&>(p)));
1139
0
    }
1140
0
    return *this;
1141
0
  }
1142
1143
  path& operator=(string_type&& source)
1144
348
  {
1145
348
    return this->assign(std::move(source));
1146
348
  }
1147
  template <typename Source, typename = enable_if_pathable<Source>>
1148
  path& operator=(Source const& source)
1149
  {
1150
    return this->assign(source);
1151
  }
1152
1153
  path& assign(string_type&& source)
1154
348
  {
1155
348
    this->base::assign(string_converter<string_type>::from(std::move(source)));
1156
348
    return *this;
1157
348
  }
1158
  template <typename Source, typename = enable_if_pathable<Source>>
1159
  path& assign(Source const& source)
1160
  {
1161
    this->base::assign(string_converter<Source>::from(source));
1162
    return *this;
1163
  }
1164
  template <typename Iterator, typename = enable_if_pathable<Iterator>>
1165
  path& assign(Iterator first, Iterator last)
1166
  {
1167
    this->base::assign(range_converter<Iterator>::from(first, last));
1168
    return *this;
1169
  }
1170
1171
  // Concatenation
1172
  // =============
1173
  path& operator/=(path const& p)
1174
348
  {
1175
348
    this->base::operator/=(static_cast<base const&>(p));
1176
348
    return *this;
1177
348
  }
1178
  template <typename Source>
1179
  path& operator/=(Source const& source)
1180
  {
1181
    return this->append(source);
1182
  }
1183
  template <typename Source, typename = enable_if_pathable<Source>>
1184
  path& append(Source const& source)
1185
  {
1186
    this->base::append(string_converter<Source>::from(source));
1187
    return *this;
1188
  }
1189
  template <typename Iterator, typename = enable_if_pathable<Iterator>>
1190
  path& append(Iterator first, Iterator last)
1191
  {
1192
    this->base::append(range_converter<Iterator>::from(first, last));
1193
    return *this;
1194
  }
1195
1196
  path& operator+=(path const& p)
1197
0
  {
1198
0
    this->base::operator+=(static_cast<base const&>(p));
1199
0
    return *this;
1200
0
  }
1201
0
  path& operator+=(string_type const& str) { return this->concat(str); }
1202
  path& operator+=(cm::string_view str)
1203
0
  {
1204
0
    this->concat(str.begin(), str.end());
1205
0
    return *this;
1206
0
  }
1207
0
  path& operator+=(value_type const* str) { return this->concat(str); }
1208
  path& operator+=(value_type const c)
1209
0
  {
1210
0
    return this->concat(string_type{ 1, c });
1211
0
  }
1212
  template <typename Source>
1213
  path& operator+=(Source const& source)
1214
  {
1215
    return this->concat(source);
1216
  }
1217
  template <typename Source, typename = enable_if_pathable<Source>>
1218
  path& concat(Source const& source)
1219
0
  {
1220
0
    this->base::concat(string_converter<Source>::from(source));
1221
0
    return *this;
1222
0
  }
Unexecuted instantiation: cm::filesystem::path& cm::filesystem::path::concat<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, cm::filesystem::path&>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: cm::filesystem::path& cm::filesystem::path::concat<char const*, cm::filesystem::path&>(char const* const&)
1223
  template <typename Iterator, typename = enable_if_pathable<Iterator>>
1224
  path& concat(Iterator first, Iterator last)
1225
0
  {
1226
0
    this->base::concat(range_converter<Iterator>::from(first, last));
1227
0
    return *this;
1228
0
  }
1229
1230
  // Format observers
1231
  // ================
1232
  string_type const& native() const noexcept
1233
0
  {
1234
0
#  if defined(_WIN32) && !defined(__CYGWIN__)
1235
0
    this->native_path_ = this->wstring();
1236
0
    return this->native_path_;
1237
0
#  else
1238
0
    return this->base::native();
1239
0
#  endif
1240
0
  }
1241
0
  value_type const* c_str() const noexcept { return this->native().c_str(); }
1242
0
  operator string_type() const { return this->native(); }
1243
1244
  std::string string() const
1245
1.05k
  {
1246
#  if defined(_WIN32) && !defined(__CYGWIN__)
1247
#    if defined(__cpp_char8_t)
1248
    return string_converter<std::u8string, std::string::value_type>::from(
1249
      this->base::u8string());
1250
#    else
1251
    return string_converter<std::wstring, std::string::value_type>::from(
1252
      this->base::wstring());
1253
#    endif
1254
#  else
1255
1.05k
    return this->base::string();
1256
1.05k
#  endif
1257
1.05k
  }
1258
0
  std::wstring wstring() const { return this->base::wstring(); }
1259
#  if defined(__cpp_char8_t)
1260
  std::u8string u8string() const
1261
#  else
1262
  std::string u8string() const
1263
#  endif
1264
0
  {
1265
0
#  if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__cpp_char8_t)
1266
0
    return string_converter<std::wstring, std::string::value_type>::from(
1267
0
      this->base::wstring());
1268
0
#  else
1269
0
    return this->base::u8string();
1270
0
#  endif
1271
0
  }
1272
1273
  std::string generic_string() const
1274
1.05k
  {
1275
#  if defined(_WIN32) && !defined(__CYGWIN__)
1276
#    if defined(__cpp_char8_t)
1277
    return string_converter<std::u8string, std::string::value_type>::from(
1278
      this->base::generic_u8string());
1279
#    else
1280
    return string_converter<std::wstring, std::string::value_type>::from(
1281
      this->base::generic_wstring());
1282
#    endif
1283
#  else
1284
1.05k
    return this->base::generic_string();
1285
1.05k
#  endif
1286
1.05k
  }
1287
  std::wstring generic_wstring() const
1288
0
  {
1289
0
    return this->base::generic_wstring();
1290
0
  }
1291
#  if defined(__cpp_char8_t)
1292
  std::u8string generic_u8string() const
1293
#  else
1294
  std::string generic_u8string() const
1295
#  endif
1296
0
  {
1297
0
#  if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__cpp_char8_t)
1298
0
    return string_converter<std::wstring, std::string::value_type>::from(
1299
0
      this->base::generic_wstring());
1300
0
#  else
1301
0
    return this->base::generic_u8string();
1302
0
#  endif
1303
0
  }
1304
1305
  // Generation
1306
  // ==========
1307
351
  path lexically_normal() const { return this->base::lexically_normal(); }
1308
1309
  path lexically_relative(path const& root) const
1310
0
  {
1311
0
    return this->base::lexically_relative(root);
1312
0
  }
1313
1314
  path lexically_proximate(path const& root) const
1315
0
  {
1316
0
    return this->base::lexically_proximate(root);
1317
0
  }
1318
1319
  // Decomposition
1320
  // =============
1321
351
  path root_name() const { return this->base::root_name(); }
1322
1323
351
  path root_directory() const { return this->base::root_directory(); }
1324
1325
351
  path root_path() const { return this->base::root_path(); }
1326
1327
351
  path relative_path() const { return this->base::relative_path(); }
1328
1329
351
  path parent_path() const { return this->base::parent_path(); }
1330
1331
351
  path filename() const { return this->base::filename(); }
1332
1333
351
  path stem() const { return this->base::stem(); }
1334
351
  path extension() const { return this->base::extension(); }
1335
1336
  // Iterators
1337
  // =========
1338
  inline iterator begin() const;
1339
  inline iterator end() const;
1340
1341
  // Non-members
1342
  // ===========
1343
  friend inline path operator/(path const& lhs, path const& rhs)
1344
0
  {
1345
0
    path result{ lhs };
1346
0
    result /= rhs;
1347
0
1348
0
    return result;
1349
0
  }
1350
1351
private:
1352
  friend class iterator;
1353
  path(base&& p)
1354
3.15k
    : base(std::move(p))
1355
3.15k
  {
1356
3.15k
  }
1357
  mutable string_type native_path_;
1358
};
1359
1360
class path::iterator
1361
{
1362
public:
1363
  using iterator_category = std::filesystem::path::iterator::iterator_category;
1364
1365
  using value_type = path;
1366
  using difference_type = std::filesystem::path::iterator::difference_type;
1367
  using pointer = path const*;
1368
  using reference = path const&;
1369
1370
  iterator() = default;
1371
  iterator(iterator const& other)
1372
    : iterator_(other.iterator_)
1373
0
  {
1374
0
  }
1375
1376
  ~iterator() = default;
1377
1378
  iterator& operator=(iterator const& other)
1379
0
  {
1380
0
    this->iterator_ = other.iterator_;
1381
0
    return *this;
1382
0
  }
1383
1384
  reference operator*() const
1385
0
  {
1386
0
    this->path_element_ = path{ *this->iterator_ };
1387
0
    return this->path_element_;
1388
0
  }
1389
1390
  pointer operator->() const
1391
0
  {
1392
0
    this->path_element_ = path{ *this->iterator_ };
1393
0
    return &this->path_element_;
1394
0
  }
1395
1396
  iterator& operator++()
1397
0
  {
1398
0
    this->iterator_++;
1399
0
    return *this;
1400
0
  }
1401
1402
  iterator operator++(int)
1403
0
  {
1404
0
    iterator it(*this);
1405
0
    this->operator++();
1406
0
    return *this;
1407
0
  }
1408
1409
  iterator& operator--()
1410
0
  {
1411
0
    this->iterator_--;
1412
0
    return *this;
1413
0
  }
1414
1415
  iterator operator--(int)
1416
0
  {
1417
0
    iterator it(*this);
1418
0
    this->operator--();
1419
0
    return it;
1420
0
  }
1421
1422
private:
1423
  friend class path;
1424
  friend bool operator==(iterator const&, iterator const&);
1425
1426
  iterator(std::filesystem::path::iterator it)
1427
    : iterator_(it)
1428
0
  {
1429
0
  }
1430
1431
  std::filesystem::path::iterator iterator_;
1432
  mutable path path_element_;
1433
};
1434
1435
inline path::iterator path::begin() const
1436
0
{
1437
0
  return iterator{ this->base::begin() };
1438
0
}
1439
inline path::iterator path::end() const
1440
0
{
1441
0
  return iterator{ this->base::end() };
1442
0
}
1443
1444
// Non-member functions
1445
// ====================
1446
inline bool operator==(path::iterator const& lhs, path::iterator const& rhs)
1447
0
{
1448
0
  return lhs.iterator_ == rhs.iterator_;
1449
0
}
1450
1451
inline bool operator!=(path::iterator const& lhs, path::iterator const& rhs)
1452
0
{
1453
0
  return !(lhs == rhs);
1454
0
}
1455
1456
inline void swap(path& lhs, path& rhs) noexcept
1457
0
{
1458
0
  lhs.swap(rhs);
1459
0
}
1460
1461
inline std::size_t hash_value(path const& p) noexcept
1462
0
{
1463
0
  return std::filesystem::hash_value(p);
1464
0
}
1465
1466
#else
1467
1468
namespace internals {
1469
1470
class path_parser;
1471
1472
}
1473
1474
class path
1475
{
1476
protected:
1477
  using path_type = std::string;
1478
1479
  template <typename Source>
1480
  using enable_if_pathable =
1481
    enable_if_t<internals::is_pathable<Source>::value, path&>;
1482
1483
  enum class filename_fragment : unsigned char
1484
  {
1485
    stem,
1486
    extension
1487
  };
1488
1489
public:
1490
#  if defined(_WIN32) && !defined(__CYGWIN__)
1491
  using value_type = wchar_t;
1492
#  else
1493
  using value_type = char;
1494
#  endif
1495
  using string_type = std::basic_string<value_type>;
1496
1497
  class iterator;
1498
  using const_iterator = iterator;
1499
1500
  enum format : unsigned char
1501
  {
1502
    auto_format,
1503
    native_format,
1504
    generic_format
1505
  };
1506
1507
#  if defined(_WIN32) && !defined(__CYGWIN__)
1508
  static constexpr value_type preferred_separator = L'\\';
1509
#  else
1510
  static constexpr value_type preferred_separator = '/';
1511
#  endif
1512
1513
  // Constructors
1514
  // ============
1515
  path() noexcept {}
1516
  path(path const& p)
1517
    : path_(p.path_)
1518
  {
1519
  }
1520
  path(path&& p) noexcept
1521
    : path_(std::move(p.path_))
1522
  {
1523
  }
1524
  path(string_type&& source, format fmt = auto_format)
1525
  {
1526
    (void)fmt;
1527
    internals::source_converter<value_type, path_type::value_type>::set_source(
1528
      this->path_, std::move(source));
1529
  }
1530
  template <typename Source, typename = enable_if_pathable<Source>>
1531
  path(Source const& source, format fmt = auto_format)
1532
  {
1533
    (void)fmt;
1534
    internals::source_converter<
1535
      typename internals::source_traits<Source>::value_type,
1536
      path_type::value_type>::append_source(this->path_, source);
1537
  }
1538
  template <typename Iterator, typename = enable_if_pathable<Iterator>>
1539
  path(Iterator first, Iterator last, format fmt = auto_format)
1540
  {
1541
    (void)fmt;
1542
    internals::source_converter<
1543
      typename std::iterator_traits<Iterator>::value_type,
1544
      path_type::value_type>::append_range(this->path_, first, last);
1545
  }
1546
1547
  ~path() = default;
1548
1549
  // Assignments
1550
  // ===========
1551
  path& operator=(path const& p)
1552
  {
1553
    if (this != &p) {
1554
      this->path_ = p.path_;
1555
    }
1556
    return *this;
1557
  }
1558
  path& operator=(path&& p) noexcept
1559
  {
1560
    if (this != &p) {
1561
      this->path_ = std::move(p.path_);
1562
    }
1563
    return *this;
1564
  }
1565
  path& operator=(string_type&& source)
1566
  {
1567
    return this->assign(std::move(source));
1568
  }
1569
  template <typename Source, typename = enable_if_pathable<Source>>
1570
  path& operator=(Source const& source)
1571
  {
1572
    return this->assign(source);
1573
  }
1574
1575
  path& assign(string_type&& source)
1576
  {
1577
    internals::source_converter<value_type, path_type::value_type>::set_source(
1578
      this->path_, std::move(source));
1579
    return *this;
1580
  }
1581
  template <typename Source, typename = enable_if_pathable<Source>>
1582
  path& assign(Source const& source)
1583
  {
1584
    this->path_.clear();
1585
    internals::source_converter<
1586
      typename internals::source_traits<Source>::value_type,
1587
      path_type::value_type>::append_source(this->path_, source);
1588
    return *this;
1589
  }
1590
  template <typename Iterator, typename = enable_if_pathable<Iterator>>
1591
  path& assign(Iterator first, Iterator last)
1592
  {
1593
    this->path_.clear();
1594
    internals::source_converter<
1595
      typename std::iterator_traits<Iterator>::value_type,
1596
      path_type::value_type>::append_range(this->path_, first, last);
1597
    return *this;
1598
  }
1599
1600
  // Concatenation
1601
  // =============
1602
  path& operator/=(path const& p);
1603
1604
  template <typename Source, typename = enable_if_pathable<Source>>
1605
  path& append(Source const& source)
1606
  {
1607
    return this->operator/=(path(source));
1608
  }
1609
  template <typename Source>
1610
  path& operator/=(Source const& source)
1611
  {
1612
    return this->append(source);
1613
  }
1614
1615
  template <typename Iterator, typename = enable_if_pathable<Iterator>>
1616
  path& append(Iterator first, Iterator last)
1617
  {
1618
    return this->operator/=(path(first, last));
1619
  }
1620
1621
  path& operator+=(path const& p)
1622
  {
1623
    this->path_ += p.path_;
1624
    return *this;
1625
  }
1626
  path& operator+=(string_type const& str)
1627
  {
1628
    this->path_ +=
1629
      internals::string_converter<value_type>::to<path_type::value_type>(str);
1630
    return *this;
1631
  }
1632
  path& operator+=(cm::string_view str)
1633
  {
1634
    this->path_.append(str.begin(), str.end());
1635
    return *this;
1636
  }
1637
  path& operator+=(value_type const* str)
1638
  {
1639
    this->path_ +=
1640
      internals::string_converter<value_type>::to<path_type::value_type>(str);
1641
    return *this;
1642
  }
1643
  path& operator+=(value_type const c)
1644
  {
1645
    this->path_ +=
1646
      internals::string_converter<value_type>::to<path_type::value_type>(c);
1647
    return *this;
1648
  }
1649
  template <typename Source, typename = enable_if_pathable<Source>>
1650
  path& concat(Source const& source)
1651
  {
1652
    internals::source_converter<
1653
      typename internals::source_traits<Source>::value_type,
1654
      path_type::value_type>::append_source(this->path_, source);
1655
    return *this;
1656
  }
1657
  template <typename Source>
1658
  path& operator+=(Source const& source)
1659
  {
1660
    return this->concat(source);
1661
  }
1662
  template <typename Iterator, typename = enable_if_pathable<Iterator>>
1663
  path& concat(Iterator first, Iterator last)
1664
  {
1665
    internals::source_converter<
1666
      typename std::iterator_traits<Iterator>::value_type,
1667
      path_type::value_type>::append_range(this->path_, first, last);
1668
    return *this;
1669
  }
1670
1671
  // Modifiers
1672
  // =========
1673
  void clear() noexcept { this->path_.clear(); }
1674
1675
  path& make_preferred()
1676
  {
1677
#  if defined(_WIN32) && !defined(__CYGWIN__)
1678
    std::replace(
1679
      this->path_.begin(), this->path_.end(), '/',
1680
      static_cast<path_type::value_type>(this->preferred_separator));
1681
#  endif
1682
    return *this;
1683
  }
1684
1685
  path& remove_filename()
1686
  {
1687
    auto fname = this->get_filename();
1688
    if (!fname.empty()) {
1689
      this->path_.erase(fname.data() -
1690
                        // Avoid C++17 non-const .data() that may reallocate.
1691
                        static_cast<path_type const&>(this->path_).data());
1692
    }
1693
    return *this;
1694
  }
1695
1696
  path& replace_filename(path const& replacement)
1697
  {
1698
    this->remove_filename();
1699
    this->operator/=(replacement);
1700
    return *this;
1701
  }
1702
1703
  path& replace_extension(path const& replacement = path())
1704
  {
1705
    auto ext = this->get_filename_fragment(filename_fragment::extension);
1706
    if (!ext.empty()) {
1707
      this->path_.erase(ext.data() -
1708
                        // Avoid C++17 non-const .data() that may reallocate.
1709
                        static_cast<path_type const&>(this->path_).data());
1710
    }
1711
    if (!replacement.path_.empty()) {
1712
      if (replacement.path_[0] != '.') {
1713
        this->path_ += '.';
1714
      }
1715
      this->path_.append(replacement.path_);
1716
    }
1717
    return *this;
1718
  }
1719
1720
  void swap(path& other) noexcept { this->path_.swap(other.path_); }
1721
1722
  // Format observers
1723
  // ================
1724
  string_type const& native() const noexcept
1725
  {
1726
#  if defined(_WIN32) && !defined(__CYGWIN__)
1727
    this->native_path_ = internals::string_converter<
1728
      path_type::value_type>::to<string_type::value_type>(this->path_);
1729
    return this->native_path_;
1730
#  else
1731
    return this->path_;
1732
#  endif
1733
  }
1734
  value_type const* c_str() const noexcept { return this->native().c_str(); }
1735
  operator string_type() const { return this->native(); }
1736
1737
  template <
1738
    typename Char, typename Traits = std::char_traits<Char>,
1739
    typename Alloc = std::allocator<Char>,
1740
    cm::enable_if_t<(std::is_same<Char, char>::value &&
1741
                     std::is_same<Traits, std::char_traits<char>>::value) ||
1742
                      (std::is_same<Char, wchar_t>::value &&
1743
                       std::is_same<Traits, std::char_traits<wchar_t>>::value),
1744
                    int> = 1>
1745
  std::basic_string<Char, Traits, Alloc> string(Alloc const& a = Alloc()) const
1746
  {
1747
    return internals::string_converter<path_type::value_type>::to<Char, Traits,
1748
                                                                  Alloc>(
1749
      this->path_, a);
1750
  }
1751
  std::string string() const { return this->path_; }
1752
  std::wstring wstring() const
1753
  {
1754
    return internals::string_converter<path_type::value_type>::to<
1755
      std::wstring::value_type>(this->string());
1756
  }
1757
  std::string u8string() const { return this->path_; }
1758
1759
  template <
1760
    typename Char, typename Traits = std::char_traits<Char>,
1761
    typename Alloc = std::allocator<Char>,
1762
    cm::enable_if_t<(std::is_same<Char, char>::value &&
1763
                     std::is_same<Traits, std::char_traits<char>>::value) ||
1764
                      (std::is_same<Char, wchar_t>::value &&
1765
                       std::is_same<Traits, std::char_traits<wchar_t>>::value),
1766
                    int> = 1>
1767
  std::basic_string<Char, Traits, Alloc> generic_string(
1768
    Alloc const& a = Alloc()) const
1769
  {
1770
    return internals::string_converter<path_type::value_type>::to<Char, Traits,
1771
                                                                  Alloc>(
1772
      this->get_generic(), a);
1773
  }
1774
  std::string generic_string() const { return this->get_generic(); }
1775
  std::wstring generic_wstring() const
1776
  {
1777
    return internals::string_converter<path_type::value_type>::to<
1778
      std::wstring::value_type>(this->generic_string());
1779
  }
1780
  std::string generic_u8string() const { return this->get_generic(); }
1781
1782
  // Compare
1783
  // =======
1784
  int compare(path const& p) const noexcept
1785
  {
1786
    return this->compare_path(p.path_);
1787
  }
1788
  int compare(string_type const& str) const
1789
  {
1790
    return this->compare_path(
1791
      internals::string_converter<value_type>::to<path_type::value_type>(str));
1792
  }
1793
  int compare(value_type const* str) const
1794
  {
1795
    return this->compare_path(
1796
      internals::string_converter<value_type>::to<path_type::value_type>(str));
1797
  }
1798
  int compare(cm::string_view str) const { return this->compare_path(str); }
1799
1800
  // Generation
1801
  // ==========
1802
  path lexically_normal() const;
1803
1804
  path lexically_relative(path const& base) const;
1805
1806
  path lexically_proximate(path const& base) const
1807
  {
1808
    path result = this->lexically_relative(base);
1809
    return result.empty() ? *this : result;
1810
  }
1811
1812
  // Decomposition
1813
  // =============
1814
  path root_name() const { return get_root_name(); }
1815
1816
  path root_directory() const { return this->get_root_directory(); }
1817
1818
  path root_path() const
1819
  {
1820
    return this->root_name().append(this->get_root_directory());
1821
  }
1822
1823
  path relative_path() const { return this->get_relative_path(); }
1824
1825
  path parent_path() const { return this->get_parent_path(); }
1826
1827
  path filename() const { return this->get_filename(); }
1828
1829
  path stem() const
1830
  {
1831
    return this->get_filename_fragment(filename_fragment::stem);
1832
  }
1833
  path extension() const
1834
  {
1835
    return this->get_filename_fragment(filename_fragment::extension);
1836
  }
1837
1838
  // Queries
1839
  // =======
1840
  bool empty() const noexcept { return this->path_.empty(); }
1841
1842
  bool has_root_name() const { return !this->get_root_name().empty(); }
1843
1844
  bool has_root_directory() const
1845
  {
1846
    return !this->get_root_directory().empty();
1847
  }
1848
1849
  bool has_root_path() const
1850
  {
1851
    return this->has_root_name() || this->has_root_directory();
1852
  }
1853
1854
  bool has_relative_path() const { return !this->get_relative_path().empty(); }
1855
1856
  bool has_parent_path() const { return !this->get_parent_path().empty(); }
1857
1858
  bool has_filename() const { return !this->get_filename().empty(); }
1859
1860
  bool has_stem() const
1861
  {
1862
    return !this->get_filename_fragment(filename_fragment::stem).empty();
1863
  }
1864
  bool has_extension() const
1865
  {
1866
    return !this->get_filename_fragment(filename_fragment::extension).empty();
1867
  }
1868
1869
  bool is_absolute() const
1870
  {
1871
#  if defined(_WIN32) && !defined(__CYGWIN__)
1872
    return this->has_root_name() && this->has_root_directory();
1873
#  else
1874
    // For CYGWIN, root_name (i.e. //host or /cygdrive/x) is not considered.
1875
    // Same as current GNU g++ implementation (9.3).
1876
    return this->has_root_directory();
1877
#  endif
1878
  }
1879
1880
  bool is_relative() const { return !this->is_absolute(); }
1881
1882
  // Iterators
1883
  // =========
1884
  inline iterator begin() const;
1885
  inline iterator end() const;
1886
1887
  // Non-members
1888
  // ===========
1889
  friend inline bool operator==(path const& lhs, path const& rhs) noexcept
1890
  {
1891
    return lhs.compare(rhs) == 0;
1892
  }
1893
  friend inline bool operator!=(path const& lhs, path const& rhs) noexcept
1894
  {
1895
    return lhs.compare(rhs) != 0;
1896
  }
1897
  friend inline bool operator<(path const& lhs, path const& rhs) noexcept
1898
  {
1899
    return lhs.compare(rhs) < 0;
1900
  }
1901
  friend inline bool operator<=(path const& lhs, path const& rhs) noexcept
1902
  {
1903
    return lhs.compare(rhs) <= 0;
1904
  }
1905
  friend inline bool operator>(path const& lhs, path const& rhs) noexcept
1906
  {
1907
    return lhs.compare(rhs) > 0;
1908
  }
1909
  friend inline bool operator>=(path const& lhs, path const& rhs) noexcept
1910
  {
1911
    return lhs.compare(rhs) >= 0;
1912
  }
1913
1914
  friend inline path operator/(path const& lhs, path const& rhs)
1915
  {
1916
    path result(lhs);
1917
    result /= rhs;
1918
1919
    return result;
1920
  }
1921
1922
  template <typename Char, typename Traits>
1923
  friend inline cm::enable_if_t<
1924
    (std::is_same<Char, path::value_type>::value &&
1925
     std::is_same<Traits, std::char_traits<path::value_type>>::value) ||
1926
      (std::is_same<Char, path::path_type::value_type>::value &&
1927
       std::is_same<Traits,
1928
                    std::char_traits<path::path_type::value_type>>::value),
1929
    std::basic_ostream<Char, Traits>&>
1930
  operator<<(std::basic_ostream<Char, Traits>& os, path const& p)
1931
  {
1932
    os << cm::quoted(p.string<Char, Traits>());
1933
    return os;
1934
  }
1935
1936
  template <typename Char, typename Traits>
1937
  friend inline cm::enable_if_t<
1938
    (std::is_same<Char, path::value_type>::value &&
1939
     std::is_same<Traits, std::char_traits<path::value_type>>::value) ||
1940
      (std::is_same<Char, path::path_type::value_type>::value &&
1941
       std::is_same<Traits,
1942
                    std::char_traits<path::path_type::value_type>>::value),
1943
    std::basic_istream<Char, Traits>&>
1944
  operator>>(std::basic_istream<Char, Traits>& is, path& p)
1945
  {
1946
    std::basic_string<Char, Traits> tmp;
1947
    is >> cm::quoted(tmp);
1948
    p = tmp;
1949
    return is;
1950
  }
1951
1952
private:
1953
  friend class iterator;
1954
  friend std::size_t hash_value(path const& p) noexcept;
1955
1956
  path_type get_generic() const;
1957
1958
  cm::string_view get_root_name() const;
1959
  cm::string_view get_root_directory() const;
1960
  cm::string_view get_relative_path() const;
1961
  cm::string_view get_parent_path() const;
1962
  cm::string_view get_filename() const;
1963
  cm::string_view get_filename_fragment(filename_fragment fragment) const;
1964
1965
  int compare_path(cm::string_view str) const;
1966
1967
  path_type path_;
1968
#  if defined(_WIN32) && !defined(__CYGWIN__)
1969
  mutable string_type native_path_;
1970
#  endif
1971
};
1972
1973
class path::iterator
1974
{
1975
public:
1976
  using iterator_category = std::bidirectional_iterator_tag;
1977
1978
  using value_type = path;
1979
  using difference_type = std::ptrdiff_t;
1980
  using pointer = path const*;
1981
  using reference = path const&;
1982
1983
  iterator();
1984
  iterator(iterator const& other);
1985
1986
  ~iterator();
1987
1988
  iterator& operator=(iterator const& other);
1989
1990
  reference operator*() const { return this->path_element_; }
1991
1992
  pointer operator->() const { return &this->path_element_; }
1993
1994
  iterator& operator++();
1995
1996
  iterator operator++(int)
1997
  {
1998
    iterator it(*this);
1999
    this->operator++();
2000
    return it;
2001
  }
2002
2003
  iterator& operator--();
2004
2005
  iterator operator--(int)
2006
  {
2007
    iterator it(*this);
2008
    this->operator--();
2009
    return it;
2010
  }
2011
2012
private:
2013
  friend class path;
2014
  friend bool operator==(iterator const&, iterator const&);
2015
2016
  iterator(path const* p, bool at_end = false);
2017
2018
  path const* path_;
2019
  std::unique_ptr<internals::path_parser> parser_;
2020
  path path_element_;
2021
};
2022
2023
inline path::iterator path::begin() const
2024
{
2025
  return iterator(this);
2026
}
2027
inline path::iterator path::end() const
2028
{
2029
  return iterator(this, true);
2030
}
2031
2032
// Non-member functions
2033
// ====================
2034
bool operator==(path::iterator const& lhs, path::iterator const& rhs);
2035
2036
inline bool operator!=(path::iterator const& lhs, path::iterator const& rhs)
2037
{
2038
  return !(lhs == rhs);
2039
}
2040
2041
inline void swap(path& lhs, path& rhs) noexcept
2042
{
2043
  lhs.swap(rhs);
2044
}
2045
2046
std::size_t hash_value(path const& p) noexcept;
2047
2048
#endif
2049
2050
} // namespace filesystem
2051
} // namespace cm