1 /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
2 file Copyright.txt or https://cmake.org/licensing for details. */
6 #include "cmConfigure.h" // IWYU pragma: keep
12 #include <cm/filesystem>
13 #include <cm/string_view>
14 #include <cm/type_traits>
15 #include <cmext/string_view>
18 #if defined(__SUNPRO_CC) && defined(__sparc)
19 // Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
20 // the full 'is_pathable' and 'is_move_pathable' checks. We use it only to
21 // improve error messages via 'enable_if' when calling methods with incorrect
22 // types. Just pretend all types are allowed so we can at least compile valid
25 struct is_pathable : std::true_type
30 struct is_move_pathable : std::true_type
35 template <typename T, typename = void>
36 struct is_pathable : std::false_type
41 struct is_pathable<cm::filesystem::path> : std::true_type
45 struct is_pathable<std::string> : std::true_type
49 struct is_pathable<cm::string_view> : std::true_type
53 struct is_pathable<cm::static_string_view> : std::true_type
59 cm::enable_if_t<std::is_same<char*, typename std::decay<T>::type>::value,
61 : cm::bool_constant<std::is_same<char*, typename std::decay<T>::type>::value>
66 struct is_move_pathable : std::false_type
71 struct is_move_pathable<cm::filesystem::path> : std::true_type
75 struct is_move_pathable<std::string> : std::true_type
84 template <typename Source>
85 using enable_if_move_pathable =
86 cm::enable_if_t<detail::is_move_pathable<Source>::value, cmCMakePath&>;
88 template <typename Source>
89 using enable_if_pathable =
90 cm::enable_if_t<detail::is_pathable<Source>::value, cmCMakePath&>;
93 using value_type = cm::filesystem::path::value_type;
94 using string_type = cm::filesystem::path::string_type;
96 enum format : unsigned char
99 static_cast<unsigned char>(cm::filesystem::path::format::auto_format),
101 static_cast<unsigned char>(cm::filesystem::path::format::native_format),
103 static_cast<unsigned char>(cm::filesystem::path::format::generic_format)
107 using const_iterator = iterator;
109 cmCMakePath() noexcept = default;
111 cmCMakePath(const cmCMakePath&) = default;
113 cmCMakePath(cmCMakePath&& path) noexcept
114 : Path(std::forward<cm::filesystem::path>(path.Path))
118 cmCMakePath(cm::filesystem::path path) noexcept
119 : Path(std::move(path))
122 cmCMakePath(cm::string_view source, format fmt = generic_format) noexcept
123 : Path(FormatPath(source, fmt))
126 template <typename Source, typename = enable_if_move_pathable<Source>>
127 cmCMakePath(Source source, format fmt = generic_format)
128 : Path(FormatPath(std::move(source), fmt))
132 template <typename Source, typename = enable_if_move_pathable<Source>>
133 cmCMakePath& Assign(Source&& source)
135 this->Path = std::forward<Source>(source);
138 template <typename Source, typename = enable_if_pathable<Source>>
139 cmCMakePath& Assign(const Source& source)
145 cmCMakePath& operator=(const cmCMakePath& path)
148 this->Path = path.Path;
152 cmCMakePath& operator=(cmCMakePath&& path) noexcept
155 this->Path = std::move(path.Path);
159 template <typename Source, typename = enable_if_move_pathable<Source>>
160 cmCMakePath& operator=(Source&& source)
162 this->Assign(std::forward<Source>(source));
165 template <typename Source, typename = enable_if_pathable<Source>>
166 cmCMakePath& operator=(const Source& source)
168 this->Assign(source);
173 cmCMakePath& Append(const cmCMakePath& path)
175 return this->Append(path.Path);
177 cmCMakePath& Append(const cm::filesystem::path& path)
180 // filesystem::path::append use preferred_separator ('\' on Windows)
181 // so convert back to '/'
182 this->Path = this->Path.generic_string();
186 template <typename Source, typename = enable_if_pathable<Source>>
187 cmCMakePath& Append(const Source& source)
189 return this->Append(cm::filesystem::path(source));
192 cmCMakePath& operator/=(const cmCMakePath& path)
194 return this->Append(path);
196 template <typename Source, typename = enable_if_pathable<Source>>
197 cmCMakePath& operator/=(const Source& source)
199 return this->Append(source);
202 cmCMakePath& Concat(const cmCMakePath& path)
204 this->Path += path.Path;
207 cmCMakePath& Concat(cm::static_string_view source)
209 this->Path.concat(std::string(source));
212 template <typename Source, typename = enable_if_pathable<Source>>
213 cmCMakePath& Concat(const Source& source)
215 this->Path.concat(source);
219 cmCMakePath& operator+=(const cmCMakePath& path)
221 return this->Concat(path);
223 template <typename Source, typename = enable_if_pathable<Source>>
224 cmCMakePath& operator+=(const Source& source)
226 return this->Concat(source);
230 void Clear() noexcept { this->Path.clear(); }
232 cmCMakePath& RemoveFileName()
234 this->Path.remove_filename();
238 cmCMakePath& ReplaceFileName(const cmCMakePath& filename)
240 if (this->Path.has_filename()) {
241 this->Path.replace_filename(filename.Path);
245 template <typename Source, typename = enable_if_pathable<Source>>
246 cmCMakePath& ReplaceFileName(const Source& filename)
248 if (this->Path.has_filename()) {
249 this->Path.replace_filename(filename);
254 cmCMakePath& ReplaceExtension(const cmCMakePath& extension = cmCMakePath())
256 this->Path.replace_extension(extension.Path);
259 template <typename Source, typename = enable_if_pathable<Source>>
260 cmCMakePath& ReplaceExtension(const Source& extension)
262 this->Path.replace_extension(extension);
266 cmCMakePath& ReplaceWideExtension(
267 const cmCMakePath& extension = cmCMakePath())
269 return this->ReplaceWideExtension(
270 static_cast<cm::string_view>(extension.Path.string()));
272 template <typename Source, typename = enable_if_pathable<Source>>
273 cmCMakePath& ReplaceWideExtension(const Source& extension)
275 return this->ReplaceWideExtension(cm::string_view(extension));
277 cmCMakePath& ReplaceWideExtension(cm::string_view extension);
279 cmCMakePath& RemoveExtension()
281 if (this->Path.has_extension()) {
282 this->ReplaceExtension(cm::string_view(""));
287 cmCMakePath& RemoveWideExtension()
289 if (this->Path.has_extension()) {
290 this->ReplaceWideExtension(cm::string_view(""));
295 void swap(cmCMakePath& other) noexcept { this->Path.swap(other.Path); }
298 std::string String() const { return this->Path.string(); }
299 std::wstring WString() const { return this->Path.wstring(); }
301 string_type Native() const
304 this->GetNativePath(path);
308 std::string NativeString() const
311 this->GetNativePath(path);
315 std::wstring NativeWString() const
318 this->GetNativePath(path);
322 std::string GenericString() const { return this->Path.generic_string(); }
323 std::wstring GenericWString() const { return this->Path.generic_wstring(); }
326 cmCMakePath GetRootName() const { return this->Path.root_name(); }
327 cmCMakePath GetRootDirectory() const { return this->Path.root_directory(); }
328 cmCMakePath GetRootPath() const { return this->Path.root_path(); }
329 cmCMakePath GetFileName() const { return this->Path.filename(); }
330 cmCMakePath GetExtension() const { return this->Path.extension(); }
331 cmCMakePath GetWideExtension() const;
332 cmCMakePath GetStem() const { return this->Path.stem(); }
333 cmCMakePath GetNarrowStem() const;
335 cmCMakePath GetRelativePath() const { return this->Path.relative_path(); }
336 cmCMakePath GetParentPath() const { return this->Path.parent_path(); }
339 cmCMakePath Normal() const
341 auto path = this->Path.lexically_normal();
342 // filesystem::path:lexically_normal use preferred_separator ('\') on
343 // Windows) so convert back to '/'
344 return path.generic_string();
347 cmCMakePath Relative(const cmCMakePath& base) const
349 return this->Relative(base.Path);
351 cmCMakePath Relative(const cm::filesystem::path& base) const
353 auto path = this->Path.lexically_relative(base);
354 // filesystem::path:lexically_relative use preferred_separator ('\') on
355 // Windows) so convert back to '/'
356 return path.generic_string();
358 template <typename Source, typename = enable_if_pathable<Source>>
359 cmCMakePath Relative(const Source& base) const
361 return this->Relative(cm::filesystem::path(base));
364 cmCMakePath Proximate(const cmCMakePath& base) const
366 return this->Proximate(base.Path);
368 cmCMakePath Proximate(const cm::filesystem::path& base) const
370 auto path = this->Path.lexically_proximate(base);
371 // filesystem::path::lexically_proximate use preferred_separator ('\') on
372 // Windows) so convert back to '/'
373 return path.generic_string();
375 template <typename Source, typename = enable_if_pathable<Source>>
376 cmCMakePath Proximate(const Source& base) const
378 return this->Proximate(cm::filesystem::path(base));
381 cmCMakePath Absolute(const cmCMakePath& base) const
383 return this->Absolute(base.Path);
385 template <typename Source, typename = enable_if_pathable<Source>>
386 cmCMakePath Absolute(const Source& base) const
388 return this->Absolute(cm::filesystem::path(base));
390 cmCMakePath Absolute(const cm::filesystem::path& base) const;
393 int Compare(const cmCMakePath& path) const noexcept
395 return this->Path.compare(path.Path);
399 bool IsEmpty() const noexcept { return this->Path.empty(); }
401 bool HasRootPath() const { return this->Path.has_root_path(); }
402 bool HasRootName() const { return this->Path.has_root_name(); }
403 bool HasRootDirectory() const { return this->Path.has_root_directory(); }
404 bool HasRelativePath() const { return this->Path.has_relative_path(); }
405 bool HasParentPath() const { return this->Path.has_parent_path(); }
406 bool HasFileName() const { return this->Path.has_filename(); }
407 bool HasStem() const { return this->Path.has_stem(); }
408 bool HasExtension() const { return this->Path.has_extension(); }
410 bool IsAbsolute() const { return this->Path.is_absolute(); }
411 bool IsRelative() const { return this->Path.is_relative(); }
412 bool IsPrefix(const cmCMakePath& path) const;
416 inline iterator begin() const;
417 inline iterator end() const;
421 friend inline bool operator==(const cmCMakePath& lhs,
422 const cmCMakePath& rhs) noexcept
424 return lhs.Compare(rhs) == 0;
426 friend inline bool operator!=(const cmCMakePath& lhs,
427 const cmCMakePath& rhs) noexcept
429 return lhs.Compare(rhs) != 0;
432 friend inline cmCMakePath operator/(const cmCMakePath& lhs,
433 const cmCMakePath& rhs)
435 cmCMakePath result(lhs);
442 friend std::size_t hash_value(const cmCMakePath& path) noexcept;
444 static std::string FormatPath(std::string path, format fmt = generic_format);
445 static std::string FormatPath(cm::string_view path,
446 format fmt = generic_format)
448 return FormatPath(std::string(path), fmt);
451 void GetNativePath(std::string& path) const;
452 void GetNativePath(std::wstring& path) const;
454 cm::filesystem::path Path;
457 class cmCMakePath::iterator
460 using iterator_category = cm::filesystem::path::iterator::iterator_category;
462 using value_type = cmCMakePath;
463 using difference_type = cm::filesystem::path::iterator::difference_type;
464 using pointer = const cmCMakePath*;
465 using reference = const cmCMakePath&;
467 iterator() = default;
469 iterator(const iterator& other)
470 : Iterator(other.Iterator)
472 , PathElement(*this->Iterator)
476 ~iterator() = default;
478 iterator& operator=(const iterator& other)
480 if (this != &other) {
481 this->Iterator = other.Iterator;
482 this->Path = other.Path;
483 this->PathElement = *this->Iterator;
489 reference operator*() const { return this->PathElement; }
491 pointer operator->() const { return &this->PathElement; }
493 iterator& operator++()
496 this->PathElement = *this->Iterator;
501 iterator operator++(int)
508 iterator& operator--()
511 this->PathElement = *this->Iterator;
516 iterator operator--(int)
524 friend class cmCMakePath;
525 friend bool operator==(const iterator&, const iterator&);
527 iterator(const cmCMakePath* path, const cm::filesystem::path::iterator& it)
530 , PathElement(*this->Iterator)
534 cm::filesystem::path::iterator Iterator;
535 const cmCMakePath* Path = nullptr;
536 cmCMakePath PathElement;
539 inline cmCMakePath::iterator cmCMakePath::begin() const
541 return iterator(this, this->Path.begin());
543 inline cmCMakePath::iterator cmCMakePath::end() const
545 return iterator(this, this->Path.end());
548 // Non-member functions
549 // ====================
550 inline bool operator==(const cmCMakePath::iterator& lhs,
551 const cmCMakePath::iterator& rhs)
553 return lhs.Path == rhs.Path && lhs.Path != nullptr &&
554 lhs.Iterator == rhs.Iterator;
557 inline bool operator!=(const cmCMakePath::iterator& lhs,
558 const cmCMakePath::iterator& rhs)
560 return !(lhs == rhs);
563 inline void swap(cmCMakePath& lhs, cmCMakePath& rhs) noexcept
568 inline std::size_t hash_value(const cmCMakePath& path) noexcept
570 return cm::filesystem::hash_value(path.Path);