Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmCMakePath.h
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
4
#pragma once
5
6
#include "cmConfigure.h" // IWYU pragma: keep
7
8
#include <cstddef>
9
#include <string>
10
#include <utility>
11
12
#include <cm/filesystem>
13
#include <cm/string_view>
14
#include <cm/type_traits>
15
16
namespace cm {
17
class static_string_view;
18
}
19
20
namespace detail {
21
#if defined(__SUNPRO_CC) && defined(__sparc)
22
// Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
23
// the full 'is_pathable' and 'is_move_pathable' checks.  We use it only to
24
// improve error messages via 'enable_if' when calling methods with incorrect
25
// types. Just pretend all types are allowed so we can at least compile valid
26
// code.
27
template <typename T>
28
struct is_pathable : std::true_type
29
{
30
};
31
32
template <typename T>
33
struct is_move_pathable : std::true_type
34
{
35
};
36
37
#else
38
template <typename T, typename = void>
39
struct is_pathable : std::false_type
40
{
41
};
42
43
template <>
44
struct is_pathable<cm::filesystem::path> : std::true_type
45
{
46
};
47
template <>
48
struct is_pathable<std::string> : std::true_type
49
{
50
};
51
template <>
52
struct is_pathable<cm::string_view> : std::true_type
53
{
54
};
55
template <>
56
struct is_pathable<cm::static_string_view> : std::true_type
57
{
58
};
59
template <typename T>
60
struct is_pathable<
61
  T,
62
  cm::enable_if_t<std::is_same<char*, typename std::decay<T>::type>::value,
63
                  void>>
64
  : cm::bool_constant<std::is_same<char*, typename std::decay<T>::type>::value>
65
{
66
};
67
68
template <typename T>
69
struct is_move_pathable : std::false_type
70
{
71
};
72
73
template <>
74
struct is_move_pathable<cm::filesystem::path> : std::true_type
75
{
76
};
77
template <>
78
struct is_move_pathable<std::string> : std::true_type
79
{
80
};
81
#endif
82
}
83
84
class cmCMakePath
85
{
86
private:
87
  template <typename Source>
88
  using enable_if_move_pathable =
89
    cm::enable_if_t<detail::is_move_pathable<Source>::value, cmCMakePath&>;
90
91
  template <typename Source>
92
  using enable_if_pathable =
93
    cm::enable_if_t<detail::is_pathable<Source>::value, cmCMakePath&>;
94
95
public:
96
  using value_type = cm::filesystem::path::value_type;
97
  using string_type = cm::filesystem::path::string_type;
98
99
  enum format : unsigned char
100
  {
101
    auto_format =
102
      static_cast<unsigned char>(cm::filesystem::path::format::auto_format),
103
    native_format =
104
      static_cast<unsigned char>(cm::filesystem::path::format::native_format),
105
    generic_format =
106
      static_cast<unsigned char>(cm::filesystem::path::format::generic_format)
107
  };
108
109
  class iterator;
110
  using const_iterator = iterator;
111
112
0
  cmCMakePath() noexcept = default;
113
114
348
  cmCMakePath(cmCMakePath const&) = default;
115
116
  cmCMakePath(cmCMakePath&& path) noexcept
117
    : Path(std::forward<cm::filesystem::path>(path.Path))
118
0
  {
119
0
  }
120
121
  cmCMakePath(cm::filesystem::path path) noexcept
122
2.80k
    : Path(std::move(path))
123
2.80k
  {
124
2.80k
  }
125
  cmCMakePath(cm::string_view source, format fmt = generic_format) noexcept
126
0
    : Path(FormatPath(source, fmt))
127
0
  {
128
0
  }
129
  cmCMakePath(char const* source, format fmt = generic_format) noexcept
130
0
    : Path(FormatPath(cm::string_view{ source }, fmt))
131
0
  {
132
0
  }
133
#if defined(__SUNPRO_CC) && defined(__sparc)
134
  // Oracle DeveloperStudio C++ compiler on Solaris/Sparc is confused when
135
  // standard methods and templates use the same name. The template is selected
136
  // rather than the standard one regardless the arguments of the method.
137
  cmCMakePath(std::string const& source, format fmt = generic_format)
138
    : Path(FormatPath(source, fmt))
139
  {
140
  }
141
  cmCMakePath(std::string&& source, format fmt = generic_format)
142
    : Path(FormatPath(std::move(source), fmt))
143
  {
144
  }
145
#else
146
  template <typename Source, typename = enable_if_move_pathable<Source>>
147
  cmCMakePath(Source source, format fmt = generic_format)
148
1.39k
    : Path(FormatPath(std::move(source), fmt))
149
1.39k
  {
150
1.39k
  }
151
#endif
152
153
  template <typename Source, typename = enable_if_move_pathable<Source>>
154
  cmCMakePath& Assign(Source&& source)
155
0
  {
156
0
    this->Path = std::forward<Source>(source);
157
0
    return *this;
158
0
  }
159
  template <typename Source, typename = enable_if_pathable<Source>>
160
  cmCMakePath& Assign(Source const& source)
161
0
  {
162
0
    this->Path = source;
163
0
    return *this;
164
0
  }
Unexecuted instantiation: cmCMakePath& cmCMakePath::Assign<cm::filesystem::path, cmCMakePath&>(cm::filesystem::path const&)
Unexecuted instantiation: cmCMakePath& cmCMakePath::Assign<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, cmCMakePath&>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
165
166
  cmCMakePath& operator=(cmCMakePath const& path)
167
0
  {
168
0
    if (this != &path) {
169
0
      this->Path = path.Path;
170
0
    }
171
0
    return *this;
172
0
  }
173
  cmCMakePath& operator=(cmCMakePath&& path) noexcept
174
0
  {
175
0
    if (this != &path) {
176
0
      this->Path = std::move(path.Path);
177
0
    }
178
0
    return *this;
179
0
  }
180
#if defined(__SUNPRO_CC) && defined(__sparc)
181
  // Oracle DeveloperStudio C++ compiler on Solaris/Sparc is confused when
182
  // standard methods and templates use the same name. The template is selected
183
  // rather than the standard one regardless the arguments of the method.
184
  cmCMakePath& operator=(cm::filesystem::path&& source)
185
  {
186
    this->Assign(std::forward<cm::filesystem::path>(source));
187
    return *this;
188
  }
189
  cmCMakePath& operator=(std::string&& source)
190
  {
191
    this->Assign(std::forward<std::string>(source));
192
    return *this;
193
  }
194
  cmCMakePath& operator=(cm::filesystem::path const& source)
195
  {
196
    this->Assign(source);
197
    return *this;
198
  }
199
  cmCMakePath& operator=(std::string const& source)
200
  {
201
    this->Assign(source);
202
    return *this;
203
  }
204
  cmCMakePath& operator=(cm::string_view const source)
205
  {
206
    this->Assign(source);
207
    return *this;
208
  }
209
  cmCMakePath& operator=(char const* source)
210
  {
211
    this->Assign(cm::string_view{ source });
212
    return *this;
213
  }
214
#else
215
  template <typename Source, typename = enable_if_move_pathable<Source>>
216
  cmCMakePath& operator=(Source&& source)
217
0
  {
218
0
    this->Assign(std::forward<Source>(source));
219
0
    return *this;
220
0
  }
221
  template <typename Source, typename = enable_if_pathable<Source>>
222
  cmCMakePath& operator=(Source const& source)
223
0
  {
224
0
    this->Assign(source);
225
0
    return *this;
226
0
  }
Unexecuted instantiation: cmCMakePath& cmCMakePath::operator=<cm::filesystem::path, cmCMakePath&>(cm::filesystem::path const&)
Unexecuted instantiation: cmCMakePath& cmCMakePath::operator=<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, cmCMakePath&>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
227
#endif
228
229
  // Concatenation
230
  cmCMakePath& Append(cmCMakePath const& path)
231
348
  {
232
348
    return this->Append(path.Path);
233
348
  }
234
  cmCMakePath& Append(cm::filesystem::path const& path)
235
348
  {
236
348
    this->Path /= path;
237
    // filesystem::path::append use preferred_separator ('\' on Windows)
238
    // so convert back to '/'
239
348
    this->Path = this->Path.generic_string();
240
348
    return *this;
241
348
  }
242
#if defined(__SUNPRO_CC) && defined(__sparc)
243
  // Oracle DeveloperStudio C++ compiler on Solaris/Sparc is confused when
244
  // standard methods and templates use the same name. The template is selected
245
  // rather than the standard one regardless the arguments of the method.
246
  cmCMakePath& Append(std::string const& source)
247
  {
248
    return this->Append(cm::filesystem::path(source));
249
  }
250
  cmCMakePath& Append(cm::string_view source)
251
  {
252
    return this->Append(cm::filesystem::path(source));
253
  }
254
  cmCMakePath& Append(char const* source)
255
  {
256
    return this->Append(cm::filesystem::path(cm::string_view{ source }));
257
  }
258
#else
259
  template <typename Source, typename = enable_if_pathable<Source>>
260
  cmCMakePath& Append(Source const& source)
261
0
  {
262
0
    return this->Append(cm::filesystem::path(source));
263
0
  }
Unexecuted instantiation: cmCMakePath& cmCMakePath::Append<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, cmCMakePath&>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: cmCMakePath& cmCMakePath::Append<char [21], cmCMakePath&>(char const (&) [21])
Unexecuted instantiation: cmCMakePath& cmCMakePath::Append<char [25], cmCMakePath&>(char const (&) [25])
Unexecuted instantiation: cmCMakePath& cmCMakePath::Append<char [19], cmCMakePath&>(char const (&) [19])
264
#endif
265
266
  cmCMakePath& operator/=(cmCMakePath const& path)
267
348
  {
268
348
    return this->Append(path);
269
348
  }
270
  template <typename Source, typename = enable_if_pathable<Source>>
271
  cmCMakePath& operator/=(Source const& source)
272
0
  {
273
0
    return this->Append(source);
274
0
  }
275
276
  cmCMakePath& Concat(cmCMakePath const& path)
277
0
  {
278
0
    this->Path += path.Path;
279
0
    return *this;
280
0
  }
281
  cmCMakePath& Concat(cm::string_view source)
282
0
  {
283
0
    this->Path.operator+=(std::string(source));
284
0
    return *this;
285
0
  }
286
#if defined(__SUNPRO_CC) && defined(__sparc)
287
  // Oracle DeveloperStudio C++ compiler on Solaris/Sparc is confused when
288
  // standard methods and templates use the same name. The template is selected
289
  // rather than the standard one regardless the arguments of the method.
290
  cmCMakePath& Concat(cm::filesystem::path const& source)
291
  {
292
    this->Path.operator+=(source);
293
    return *this;
294
  }
295
  cmCMakePath& Concat(std::string const& source)
296
  {
297
    this->Path.operator+=(source);
298
    return *this;
299
  }
300
  cmCMakePath& Concat(char const* source)
301
  {
302
    this->Path.operator+=(source);
303
    return *this;
304
  }
305
#else
306
  template <typename Source, typename = enable_if_pathable<Source>>
307
  cmCMakePath& Concat(Source const& source)
308
0
  {
309
0
    this->Path.operator+=(source);
310
0
    return *this;
311
0
  }
312
#endif
313
314
  cmCMakePath& operator+=(cmCMakePath const& path)
315
0
  {
316
0
    return this->Concat(path);
317
0
  }
318
  template <typename Source, typename = enable_if_pathable<Source>>
319
  cmCMakePath& operator+=(Source const& source)
320
0
  {
321
0
    return this->Concat(source);
322
0
  }
323
324
  // Manipulation
325
0
  void Clear() noexcept { this->Path.clear(); }
326
327
  cmCMakePath& RemoveFileName()
328
0
  {
329
0
    this->Path.remove_filename();
330
0
    return *this;
331
0
  }
332
333
  cmCMakePath& ReplaceFileName(cmCMakePath const& filename)
334
0
  {
335
0
    if (this->Path.has_filename()) {
336
0
      this->Path.replace_filename(filename.Path);
337
0
    }
338
0
    return *this;
339
0
  }
340
#if defined(__SUNPRO_CC) && defined(__sparc)
341
  // Oracle DeveloperStudio C++ compiler on Solaris/Sparc is confused when
342
  // standard methods and templates use the same name. The template is selected
343
  // rather than the standard one regardless the arguments of the method.
344
  cmCMakePath& ReplaceFileName(cm::filesystem::path const& filename)
345
  {
346
    if (this->Path.has_filename()) {
347
      this->Path.replace_filename(filename);
348
    }
349
    return *this;
350
  }
351
  cmCMakePath& ReplaceFileName(std::string const& filename)
352
  {
353
    if (this->Path.has_filename()) {
354
      this->Path.replace_filename(filename);
355
    }
356
    return *this;
357
  }
358
  cmCMakePath& ReplaceFileName(cm::string_view filename)
359
  {
360
    if (this->Path.has_filename()) {
361
      this->Path.replace_filename(filename);
362
    }
363
    return *this;
364
  }
365
#else
366
  template <typename Source, typename = enable_if_pathable<Source>>
367
  cmCMakePath& ReplaceFileName(Source const& filename)
368
0
  {
369
0
    if (this->Path.has_filename()) {
370
0
      this->Path.replace_filename(filename);
371
0
    }
372
0
    return *this;
373
0
  }
374
#endif
375
376
  cmCMakePath& ReplaceExtension(cmCMakePath const& extension = cmCMakePath())
377
0
  {
378
0
    this->Path.replace_extension(extension.Path);
379
0
    return *this;
380
0
  }
381
#if defined(__SUNPRO_CC) && defined(__sparc)
382
  // Oracle DeveloperStudio C++ compiler on Solaris/Sparc is confused when
383
  // standard methods and templates use the same name. The template is selected
384
  // rather than the standard one regardless the arguments of the method.
385
  cmCMakePath& ReplaceExtension(cm::filesystem::path const& extension)
386
  {
387
    this->Path.replace_extension(extension);
388
    return *this;
389
  }
390
  cmCMakePath& ReplaceExtension(std::string const& extension)
391
  {
392
    this->Path.replace_extension(extension);
393
    return *this;
394
  }
395
  cmCMakePath& ReplaceExtension(cm::string_view const extension)
396
  {
397
    this->Path.replace_extension(extension);
398
    return *this;
399
  }
400
#else
401
  template <typename Source, typename = enable_if_pathable<Source>>
402
  cmCMakePath& ReplaceExtension(Source const& extension)
403
0
  {
404
0
    this->Path.replace_extension(extension);
405
0
    return *this;
406
0
  }
407
#endif
408
409
  cmCMakePath& ReplaceWideExtension(
410
    cmCMakePath const& extension = cmCMakePath())
411
0
  {
412
0
    return this->ReplaceWideExtension(
413
0
      static_cast<cm::string_view>(extension.Path.string()));
414
0
  }
415
  cmCMakePath& ReplaceWideExtension(cm::filesystem::path const& extension)
416
0
  {
417
0
    return this->ReplaceWideExtension(
418
0
      static_cast<cm::string_view>(extension.string()));
419
0
  }
420
#if defined(__SUNPRO_CC) && defined(__sparc)
421
  // Oracle DeveloperStudio C++ compiler on Solaris/Sparc is confused when
422
  // standard methods and templates use the same name. The template is selected
423
  // rather than the standard one regardless the arguments of the method.
424
  cmCMakePath& ReplaceWideExtension(std::string const& extension)
425
  {
426
    return this->ReplaceWideExtension(cm::string_view{ extension });
427
  }
428
#else
429
  template <typename Source, typename = enable_if_pathable<Source>>
430
  cmCMakePath& ReplaceWideExtension(Source const& extension)
431
  {
432
    return this->ReplaceWideExtension(extension);
433
  }
434
#endif
435
  cmCMakePath& ReplaceWideExtension(cm::string_view extension);
436
437
  cmCMakePath& RemoveExtension()
438
0
  {
439
0
    if (this->Path.has_extension()) {
440
0
      this->ReplaceExtension(cm::string_view(""));
441
0
    }
442
0
    return *this;
443
0
  }
444
445
  cmCMakePath& RemoveWideExtension()
446
0
  {
447
0
    if (this->Path.has_extension()) {
448
0
      this->ReplaceWideExtension(cm::string_view(""));
449
0
    }
450
0
    return *this;
451
0
  }
452
453
0
  void swap(cmCMakePath& other) noexcept { this->Path.swap(other.Path); }
454
455
  // Observers
456
1.05k
  std::string String() const { return this->Path.string(); }
457
0
  std::wstring WString() const { return this->Path.wstring(); }
458
459
  string_type Native() const
460
0
  {
461
0
    string_type path;
462
0
    this->GetNativePath(path);
463
0
464
0
    return path;
465
0
  }
466
  std::string NativeString() const
467
0
  {
468
0
    std::string path;
469
0
    this->GetNativePath(path);
470
471
0
    return path;
472
0
  }
473
  std::wstring NativeWString() const
474
0
  {
475
0
    std::wstring path;
476
0
    this->GetNativePath(path);
477
0
478
0
    return path;
479
0
  }
480
351
  std::string GenericString() const { return this->Path.generic_string(); }
481
0
  std::wstring GenericWString() const { return this->Path.generic_wstring(); }
482
483
  // Decomposition
484
351
  cmCMakePath GetRootName() const { return this->Path.root_name(); }
485
351
  cmCMakePath GetRootDirectory() const { return this->Path.root_directory(); }
486
351
  cmCMakePath GetRootPath() const { return this->Path.root_path(); }
487
351
  cmCMakePath GetFileName() const { return this->Path.filename(); }
488
351
  cmCMakePath GetExtension() const { return this->Path.extension(); }
489
  cmCMakePath GetWideExtension() const;
490
351
  cmCMakePath GetStem() const { return this->Path.stem(); }
491
  cmCMakePath GetNarrowStem() const;
492
493
351
  cmCMakePath GetRelativePath() const { return this->Path.relative_path(); }
494
351
  cmCMakePath GetParentPath() const { return this->Path.parent_path(); }
495
496
  // Generation
497
  cmCMakePath Normal() const
498
351
  {
499
351
    auto path = this->Path.lexically_normal();
500
    // filesystem::path:lexically_normal use preferred_separator ('\') on
501
    // Windows) so convert back to '/'
502
351
    return path.generic_string();
503
351
  }
504
505
  cmCMakePath Relative(cmCMakePath const& base) const
506
0
  {
507
0
    return this->Relative(base.Path);
508
0
  }
509
  cmCMakePath Relative(cm::filesystem::path const& base) const
510
0
  {
511
0
    auto path = this->Path.lexically_relative(base);
512
    // filesystem::path:lexically_relative use preferred_separator ('\') on
513
    // Windows) so convert back to '/'
514
0
    return path.generic_string();
515
0
  }
516
#if defined(__SUNPRO_CC) && defined(__sparc)
517
  // Oracle DeveloperStudio C++ compiler on Solaris/Sparc is confused when
518
  // standard methods and templates use the same name. The template is selected
519
  // rather than the standard one regardless the arguments of the method.
520
  cmCMakePath Relative(std::string const& base) const
521
  {
522
    return this->Relative(cm::filesystem::path(base));
523
  }
524
  cmCMakePath Relative(cm::string_view base) const
525
  {
526
    return this->Relative(cm::filesystem::path(base));
527
  }
528
#else
529
  template <typename Source, typename = enable_if_pathable<Source>>
530
  cmCMakePath Relative(Source const& base) const
531
0
  {
532
0
    return this->Relative(cm::filesystem::path(base));
533
0
  }
534
#endif
535
  cmCMakePath Proximate(cmCMakePath const& base) const
536
0
  {
537
0
    return this->Proximate(base.Path);
538
0
  }
539
  cmCMakePath Proximate(cm::filesystem::path const& base) const
540
0
  {
541
0
    auto path = this->Path.lexically_proximate(base);
542
0
    // filesystem::path::lexically_proximate use preferred_separator ('\') on
543
0
    // Windows) so convert back to '/'
544
0
    return path.generic_string();
545
0
  }
546
#if defined(__SUNPRO_CC) && defined(__sparc)
547
  // Oracle DeveloperStudio C++ compiler on Solaris/Sparc is confused when
548
  // standard methods and templates use the same name. The template is selected
549
  // rather than the standard one regardless the arguments of the method.
550
  cmCMakePath Proximate(std::string const& base) const
551
  {
552
    return this->Proximate(cm::filesystem::path(base));
553
  }
554
  cmCMakePath Proximate(cm::string_view base) const
555
  {
556
    return this->Proximate(cm::filesystem::path(base));
557
  }
558
#else
559
  template <typename Source, typename = enable_if_pathable<Source>>
560
  cmCMakePath Proximate(Source const& base) const
561
  {
562
    return this->Proximate(cm::filesystem::path(base));
563
  }
564
#endif
565
566
  cmCMakePath Absolute(cmCMakePath const& base) const
567
0
  {
568
0
    return this->Absolute(base.Path);
569
0
  }
570
#if defined(__SUNPRO_CC) && defined(__sparc)
571
  // Oracle DeveloperStudio C++ compiler on Solaris/Sparc is confused when
572
  // standard methods and templates use the same name. The template is selected
573
  // rather than the standard one regardless the arguments of the method.
574
  cmCMakePath Absolute(std::string const& base) const
575
  {
576
    return this->Absolute(cm::filesystem::path(base));
577
  }
578
  cmCMakePath Absolute(cm::string_view base) const
579
  {
580
    return this->Absolute(cm::filesystem::path(base));
581
  }
582
#else
583
  template <typename Source, typename = enable_if_pathable<Source>>
584
  cmCMakePath Absolute(Source const& base) const
585
0
  {
586
0
    return this->Absolute(cm::filesystem::path(base));
587
0
  }
588
#endif
589
  cmCMakePath Absolute(cm::filesystem::path const& base) const;
590
591
  // Comparison
592
  int Compare(cmCMakePath const& path) const noexcept
593
348
  {
594
348
    return this->Path.compare(path.Path);
595
348
  }
596
597
  // Query
598
351
  bool IsEmpty() const noexcept { return this->Path.empty(); }
599
600
351
  bool HasRootPath() const { return this->Path.has_root_path(); }
601
351
  bool HasRootName() const { return this->Path.has_root_name(); }
602
351
  bool HasRootDirectory() const { return this->Path.has_root_directory(); }
603
351
  bool HasRelativePath() const { return this->Path.has_relative_path(); }
604
351
  bool HasParentPath() const { return this->Path.has_parent_path(); }
605
351
  bool HasFileName() const { return this->Path.has_filename(); }
606
351
  bool HasStem() const { return this->Path.has_stem(); }
607
351
  bool HasExtension() const { return this->Path.has_extension(); }
608
609
351
  bool IsAbsolute() const { return this->Path.is_absolute(); }
610
351
  bool IsRelative() const { return this->Path.is_relative(); }
611
  bool IsPrefix(cmCMakePath const& path) const;
612
613
  // Iterators
614
  // =========
615
  inline iterator begin() const;
616
  inline iterator end() const;
617
618
  // Non-members
619
  // ===========
620
  friend bool operator==(cmCMakePath const& lhs,
621
                         cmCMakePath const& rhs) noexcept
622
348
  {
623
348
    return lhs.Compare(rhs) == 0;
624
348
  }
625
  friend bool operator!=(cmCMakePath const& lhs,
626
                         cmCMakePath const& rhs) noexcept
627
0
  {
628
0
    return lhs.Compare(rhs) != 0;
629
0
  }
630
631
  friend cmCMakePath operator/(cmCMakePath const& lhs, cmCMakePath const& rhs)
632
348
  {
633
348
    cmCMakePath result(lhs);
634
348
    result /= rhs;
635
636
348
    return result;
637
348
  }
638
639
private:
640
  friend std::size_t hash_value(cmCMakePath const& path) noexcept;
641
642
  static std::string FormatPath(std::string path, format fmt = generic_format);
643
  static std::string FormatPath(cm::string_view path,
644
                                format fmt = generic_format)
645
0
  {
646
0
    return FormatPath(std::string(path), fmt);
647
0
  }
648
649
  void GetNativePath(std::string& path) const;
650
  void GetNativePath(std::wstring& path) const;
651
652
  cm::filesystem::path Path;
653
};
654
655
class cmCMakePath::iterator
656
{
657
public:
658
  using iterator_category = cm::filesystem::path::iterator::iterator_category;
659
660
  using value_type = cmCMakePath;
661
  using difference_type = cm::filesystem::path::iterator::difference_type;
662
  using pointer = cmCMakePath const*;
663
  using reference = cmCMakePath const&;
664
665
  iterator() = default;
666
667
0
  iterator(iterator const& other) = default;
668
669
0
  ~iterator() = default;
670
671
  iterator& operator=(iterator const& other)
672
0
  {
673
0
    if (this != &other) {
674
0
      this->Iterator = other.Iterator;
675
0
      this->Path = other.Path;
676
0
      this->PathElement = other.PathElement;
677
0
    }
678
0
679
0
    return *this;
680
0
  }
681
682
0
  reference operator*() const { return this->PathElement; }
683
684
0
  pointer operator->() const { return &this->PathElement; }
685
686
  iterator& operator++()
687
0
  {
688
0
    ++this->Iterator;
689
0
    if (this->Path && this->Iterator != this->Path->Path.end()) {
690
0
      this->PathElement = *this->Iterator;
691
0
    }
692
693
0
    return *this;
694
0
  }
695
696
  iterator operator++(int)
697
0
  {
698
0
    iterator it(*this);
699
0
    this->operator++();
700
0
    return it;
701
0
  }
702
703
  iterator& operator--()
704
0
  {
705
0
    --this->Iterator;
706
0
    if (this->Path && this->Iterator != this->Path->Path.end()) {
707
0
      this->PathElement = *this->Iterator;
708
0
    }
709
0
710
0
    return *this;
711
0
  }
712
713
  iterator operator--(int)
714
0
  {
715
0
    iterator it(*this);
716
0
    this->operator--();
717
0
    return it;
718
0
  }
719
720
private:
721
  friend class cmCMakePath;
722
  friend bool operator==(iterator const&, iterator const&);
723
724
  iterator(cmCMakePath const* path, cm::filesystem::path::iterator const& it)
725
0
    : Iterator(it)
726
0
    , Path(path)
727
0
  {
728
0
    if (this->Path && this->Iterator != this->Path->Path.end()) {
729
0
      this->PathElement = *this->Iterator;
730
0
    }
731
0
  }
732
733
  cm::filesystem::path::iterator Iterator;
734
  cmCMakePath const* Path = nullptr;
735
  cmCMakePath PathElement;
736
};
737
738
inline cmCMakePath::iterator cmCMakePath::begin() const
739
0
{
740
0
  return iterator(this, this->Path.begin());
741
0
}
742
inline cmCMakePath::iterator cmCMakePath::end() const
743
0
{
744
0
  return iterator(this, this->Path.end());
745
0
}
746
747
// Non-member functions
748
// ====================
749
inline bool operator==(cmCMakePath::iterator const& lhs,
750
                       cmCMakePath::iterator const& rhs)
751
0
{
752
0
  return lhs.Path == rhs.Path && lhs.Path && lhs.Iterator == rhs.Iterator;
753
0
}
754
755
inline bool operator!=(cmCMakePath::iterator const& lhs,
756
                       cmCMakePath::iterator const& rhs)
757
0
{
758
0
  return !(lhs == rhs);
759
0
}
760
761
inline void swap(cmCMakePath& lhs, cmCMakePath& rhs) noexcept
762
0
{
763
0
  lhs.swap(rhs);
764
0
}
765
766
inline std::size_t hash_value(cmCMakePath const& path) noexcept
767
0
{
768
0
  return cm::filesystem::hash_value(path.Path);
769
0
}