resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmCMakePath.h
1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt 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 #include <cmext/string_view>
16
17 namespace detail {
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
23 // code.
24 template <typename T>
25 struct is_pathable : std::true_type
26 {
27 };
28
29 template <typename T>
30 struct is_move_pathable : std::true_type
31 {
32 };
33
34 #else
35 template <typename T, typename = void>
36 struct is_pathable : std::false_type
37 {
38 };
39
40 template <>
41 struct is_pathable<cm::filesystem::path> : std::true_type
42 {
43 };
44 template <>
45 struct is_pathable<std::string> : std::true_type
46 {
47 };
48 template <>
49 struct is_pathable<cm::string_view> : std::true_type
50 {
51 };
52 template <>
53 struct is_pathable<cm::static_string_view> : std::true_type
54 {
55 };
56 template <typename T>
57 struct is_pathable<
58   T,
59   cm::enable_if_t<std::is_same<char*, typename std::decay<T>::type>::value,
60                   void>>
61   : cm::bool_constant<std::is_same<char*, typename std::decay<T>::type>::value>
62 {
63 };
64
65 template <typename T>
66 struct is_move_pathable : std::false_type
67 {
68 };
69
70 template <>
71 struct is_move_pathable<cm::filesystem::path> : std::true_type
72 {
73 };
74 template <>
75 struct is_move_pathable<std::string> : std::true_type
76 {
77 };
78 #endif
79 }
80
81 class cmCMakePath
82 {
83 private:
84   template <typename Source>
85   using enable_if_move_pathable =
86     cm::enable_if_t<detail::is_move_pathable<Source>::value, cmCMakePath&>;
87
88   template <typename Source>
89   using enable_if_pathable =
90     cm::enable_if_t<detail::is_pathable<Source>::value, cmCMakePath&>;
91
92 public:
93   using value_type = cm::filesystem::path::value_type;
94   using string_type = cm::filesystem::path::string_type;
95
96   enum format : unsigned char
97   {
98     auto_format =
99       static_cast<unsigned char>(cm::filesystem::path::format::auto_format),
100     native_format =
101       static_cast<unsigned char>(cm::filesystem::path::format::native_format),
102     generic_format =
103       static_cast<unsigned char>(cm::filesystem::path::format::generic_format)
104   };
105
106   class iterator;
107   using const_iterator = iterator;
108
109   cmCMakePath() noexcept = default;
110
111   cmCMakePath(const cmCMakePath&) = default;
112
113   cmCMakePath(cmCMakePath&& path) noexcept
114     : Path(std::forward<cm::filesystem::path>(path.Path))
115   {
116   }
117
118   cmCMakePath(cm::filesystem::path path) noexcept
119     : Path(std::move(path))
120   {
121   }
122   cmCMakePath(cm::string_view source, format fmt = generic_format) noexcept
123     : Path(FormatPath(source, fmt))
124   {
125   }
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))
129   {
130   }
131
132   template <typename Source, typename = enable_if_move_pathable<Source>>
133   cmCMakePath& Assign(Source&& source)
134   {
135     this->Path = std::forward<Source>(source);
136     return *this;
137   }
138   template <typename Source, typename = enable_if_pathable<Source>>
139   cmCMakePath& Assign(const Source& source)
140   {
141     this->Path = source;
142     return *this;
143   }
144
145   cmCMakePath& operator=(const cmCMakePath& path)
146   {
147     if (this != &path) {
148       this->Path = path.Path;
149     }
150     return *this;
151   }
152   cmCMakePath& operator=(cmCMakePath&& path) noexcept
153   {
154     if (this != &path) {
155       this->Path = std::move(path.Path);
156     }
157     return *this;
158   }
159   template <typename Source, typename = enable_if_move_pathable<Source>>
160   cmCMakePath& operator=(Source&& source)
161   {
162     this->Assign(std::forward<Source>(source));
163     return *this;
164   }
165   template <typename Source, typename = enable_if_pathable<Source>>
166   cmCMakePath& operator=(const Source& source)
167   {
168     this->Assign(source);
169     return *this;
170   }
171
172   // Concatenation
173   cmCMakePath& Append(const cmCMakePath& path)
174   {
175     return this->Append(path.Path);
176   }
177   cmCMakePath& Append(const cm::filesystem::path& path)
178   {
179     this->Path /= path;
180     // filesystem::path::append use preferred_separator ('\' on Windows)
181     // so convert back to '/'
182     this->Path = this->Path.generic_string();
183     return *this;
184   }
185
186   template <typename Source, typename = enable_if_pathable<Source>>
187   cmCMakePath& Append(const Source& source)
188   {
189     return this->Append(cm::filesystem::path(source));
190   }
191
192   cmCMakePath& operator/=(const cmCMakePath& path)
193   {
194     return this->Append(path);
195   }
196   template <typename Source, typename = enable_if_pathable<Source>>
197   cmCMakePath& operator/=(const Source& source)
198   {
199     return this->Append(source);
200   }
201
202   cmCMakePath& Concat(const cmCMakePath& path)
203   {
204     this->Path += path.Path;
205     return *this;
206   }
207   cmCMakePath& Concat(cm::static_string_view source)
208   {
209     this->Path.concat(std::string(source));
210     return *this;
211   }
212   template <typename Source, typename = enable_if_pathable<Source>>
213   cmCMakePath& Concat(const Source& source)
214   {
215     this->Path.concat(source);
216     return *this;
217   }
218
219   cmCMakePath& operator+=(const cmCMakePath& path)
220   {
221     return this->Concat(path);
222   }
223   template <typename Source, typename = enable_if_pathable<Source>>
224   cmCMakePath& operator+=(const Source& source)
225   {
226     return this->Concat(source);
227   }
228
229   // Manipulation
230   void Clear() noexcept { this->Path.clear(); }
231
232   cmCMakePath& RemoveFileName()
233   {
234     this->Path.remove_filename();
235     return *this;
236   }
237
238   cmCMakePath& ReplaceFileName(const cmCMakePath& filename)
239   {
240     if (this->Path.has_filename()) {
241       this->Path.replace_filename(filename.Path);
242     }
243     return *this;
244   }
245   template <typename Source, typename = enable_if_pathable<Source>>
246   cmCMakePath& ReplaceFileName(const Source& filename)
247   {
248     if (this->Path.has_filename()) {
249       this->Path.replace_filename(filename);
250     }
251     return *this;
252   }
253
254   cmCMakePath& ReplaceExtension(const cmCMakePath& extension = cmCMakePath())
255   {
256     this->Path.replace_extension(extension.Path);
257     return *this;
258   }
259   template <typename Source, typename = enable_if_pathable<Source>>
260   cmCMakePath& ReplaceExtension(const Source& extension)
261   {
262     this->Path.replace_extension(extension);
263     return *this;
264   }
265
266   cmCMakePath& ReplaceWideExtension(
267     const cmCMakePath& extension = cmCMakePath())
268   {
269     return this->ReplaceWideExtension(
270       static_cast<cm::string_view>(extension.Path.string()));
271   }
272   template <typename Source, typename = enable_if_pathable<Source>>
273   cmCMakePath& ReplaceWideExtension(const Source& extension)
274   {
275     return this->ReplaceWideExtension(cm::string_view(extension));
276   }
277   cmCMakePath& ReplaceWideExtension(cm::string_view extension);
278
279   cmCMakePath& RemoveExtension()
280   {
281     if (this->Path.has_extension()) {
282       this->ReplaceExtension(cm::string_view(""));
283     }
284     return *this;
285   }
286
287   cmCMakePath& RemoveWideExtension()
288   {
289     if (this->Path.has_extension()) {
290       this->ReplaceWideExtension(cm::string_view(""));
291     }
292     return *this;
293   }
294
295   void swap(cmCMakePath& other) noexcept { this->Path.swap(other.Path); }
296
297   // Observers
298   std::string String() const { return this->Path.string(); }
299   std::wstring WString() const { return this->Path.wstring(); }
300
301   string_type Native() const
302   {
303     string_type path;
304     this->GetNativePath(path);
305
306     return path;
307   }
308   std::string NativeString() const
309   {
310     std::string path;
311     this->GetNativePath(path);
312
313     return path;
314   }
315   std::wstring NativeWString() const
316   {
317     std::wstring path;
318     this->GetNativePath(path);
319
320     return path;
321   }
322   std::string GenericString() const { return this->Path.generic_string(); }
323   std::wstring GenericWString() const { return this->Path.generic_wstring(); }
324
325   // Decomposition
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;
334
335   cmCMakePath GetRelativePath() const { return this->Path.relative_path(); }
336   cmCMakePath GetParentPath() const { return this->Path.parent_path(); }
337
338   // Generation
339   cmCMakePath Normal() const
340   {
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();
345   }
346
347   cmCMakePath Relative(const cmCMakePath& base) const
348   {
349     return this->Relative(base.Path);
350   }
351   cmCMakePath Relative(const cm::filesystem::path& base) const
352   {
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();
357   }
358   template <typename Source, typename = enable_if_pathable<Source>>
359   cmCMakePath Relative(const Source& base) const
360   {
361     return this->Relative(cm::filesystem::path(base));
362   }
363
364   cmCMakePath Proximate(const cmCMakePath& base) const
365   {
366     return this->Proximate(base.Path);
367   }
368   cmCMakePath Proximate(const cm::filesystem::path& base) const
369   {
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();
374   }
375   template <typename Source, typename = enable_if_pathable<Source>>
376   cmCMakePath Proximate(const Source& base) const
377   {
378     return this->Proximate(cm::filesystem::path(base));
379   }
380
381   cmCMakePath Absolute(const cmCMakePath& base) const
382   {
383     return this->Absolute(base.Path);
384   }
385   template <typename Source, typename = enable_if_pathable<Source>>
386   cmCMakePath Absolute(const Source& base) const
387   {
388     return this->Absolute(cm::filesystem::path(base));
389   }
390   cmCMakePath Absolute(const cm::filesystem::path& base) const;
391
392   // Comparison
393   int Compare(const cmCMakePath& path) const noexcept
394   {
395     return this->Path.compare(path.Path);
396   }
397
398   // Query
399   bool IsEmpty() const noexcept { return this->Path.empty(); }
400
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(); }
409
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;
413
414   // Iterators
415   // =========
416   inline iterator begin() const;
417   inline iterator end() const;
418
419   // Non-members
420   // ===========
421   friend inline bool operator==(const cmCMakePath& lhs,
422                                 const cmCMakePath& rhs) noexcept
423   {
424     return lhs.Compare(rhs) == 0;
425   }
426   friend inline bool operator!=(const cmCMakePath& lhs,
427                                 const cmCMakePath& rhs) noexcept
428   {
429     return lhs.Compare(rhs) != 0;
430   }
431
432   friend inline cmCMakePath operator/(const cmCMakePath& lhs,
433                                       const cmCMakePath& rhs)
434   {
435     cmCMakePath result(lhs);
436     result /= rhs;
437
438     return result;
439   }
440
441 private:
442   friend std::size_t hash_value(const cmCMakePath& path) noexcept;
443
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)
447   {
448     return FormatPath(std::string(path), fmt);
449   }
450
451   void GetNativePath(std::string& path) const;
452   void GetNativePath(std::wstring& path) const;
453
454   cm::filesystem::path Path;
455 };
456
457 class cmCMakePath::iterator
458 {
459 public:
460   using iterator_category = cm::filesystem::path::iterator::iterator_category;
461
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&;
466
467   iterator() = default;
468
469   iterator(const iterator& other)
470     : Iterator(other.Iterator)
471     , Path(other.Path)
472     , PathElement(*this->Iterator)
473   {
474   }
475
476   ~iterator() = default;
477
478   iterator& operator=(const iterator& other)
479   {
480     if (this != &other) {
481       this->Iterator = other.Iterator;
482       this->Path = other.Path;
483       this->PathElement = *this->Iterator;
484     }
485
486     return *this;
487   }
488
489   reference operator*() const { return this->PathElement; }
490
491   pointer operator->() const { return &this->PathElement; }
492
493   iterator& operator++()
494   {
495     ++this->Iterator;
496     this->PathElement = *this->Iterator;
497
498     return *this;
499   }
500
501   iterator operator++(int)
502   {
503     iterator it(*this);
504     this->operator++();
505     return it;
506   }
507
508   iterator& operator--()
509   {
510     --this->Iterator;
511     this->PathElement = *this->Iterator;
512
513     return *this;
514   }
515
516   iterator operator--(int)
517   {
518     iterator it(*this);
519     this->operator--();
520     return it;
521   }
522
523 private:
524   friend class cmCMakePath;
525   friend bool operator==(const iterator&, const iterator&);
526
527   iterator(const cmCMakePath* path, const cm::filesystem::path::iterator& it)
528     : Iterator(it)
529     , Path(path)
530     , PathElement(*this->Iterator)
531   {
532   }
533
534   cm::filesystem::path::iterator Iterator;
535   const cmCMakePath* Path = nullptr;
536   cmCMakePath PathElement;
537 };
538
539 inline cmCMakePath::iterator cmCMakePath::begin() const
540 {
541   return iterator(this, this->Path.begin());
542 }
543 inline cmCMakePath::iterator cmCMakePath::end() const
544 {
545   return iterator(this, this->Path.end());
546 }
547
548 // Non-member functions
549 // ====================
550 inline bool operator==(const cmCMakePath::iterator& lhs,
551                        const cmCMakePath::iterator& rhs)
552 {
553   return lhs.Path == rhs.Path && lhs.Path != nullptr &&
554     lhs.Iterator == rhs.Iterator;
555 }
556
557 inline bool operator!=(const cmCMakePath::iterator& lhs,
558                        const cmCMakePath::iterator& rhs)
559 {
560   return !(lhs == rhs);
561 }
562
563 inline void swap(cmCMakePath& lhs, cmCMakePath& rhs) noexcept
564 {
565   lhs.swap(rhs);
566 }
567
568 inline std::size_t hash_value(const cmCMakePath& path) noexcept
569 {
570   return cm::filesystem::hash_value(path.Path);
571 }