filesystem 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173
  1. // -*-c++-*-
  2. // vim: set ft=cpp:
  3. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  4. file Copyright.txt or https://cmake.org/licensing for details. */
  5. #ifndef cm_filesystem
  6. #define cm_filesystem
  7. #include "cmSTL.hxx" // IWYU pragma: keep
  8. #if defined(CMake_HAVE_CXX_FILESYSTEM)
  9. # include <filesystem> // IWYU pragma: export
  10. #else
  11. # include <cstddef>
  12. # include <cstdint>
  13. # include <iostream>
  14. # include <iterator>
  15. # include <memory>
  16. # include <string>
  17. # include <utility>
  18. # include <cm/iomanip>
  19. # include <cm/string_view>
  20. # include <cm/type_traits>
  21. # include <cmext/iterator>
  22. # if defined(_WIN32)
  23. # include <algorithm>
  24. # endif
  25. #endif
  26. namespace cm {
  27. namespace filesystem {
  28. #if defined(CMake_HAVE_CXX_FILESYSTEM)
  29. using std::filesystem::path;
  30. using std::filesystem::swap;
  31. using std::filesystem::hash_value;
  32. #else
  33. # if !defined(CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR)
  34. // Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
  35. // the source_traits for iterator check. So disable it for now.
  36. # define CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR 0
  37. # endif
  38. namespace internals {
  39. class path_parser;
  40. class unicode_helper
  41. {
  42. protected:
  43. using utf8_state = unsigned char;
  44. static const utf8_state s_start = 0;
  45. static const utf8_state s_reject = 8;
  46. static inline bool in_range(std::uint32_t c, std::uint32_t lo,
  47. std::uint32_t hi)
  48. {
  49. return (static_cast<std::uint32_t>(c - lo) < (hi - lo + 1));
  50. }
  51. static inline bool is_surrogate(std::uint32_t c)
  52. {
  53. return in_range(c, 0xd800, 0xdfff);
  54. }
  55. static inline bool is_high_surrogate(std::uint32_t c)
  56. {
  57. return (c & 0xfffffc00) == 0xd800;
  58. }
  59. static inline bool is_low_surrogate(std::uint32_t c)
  60. {
  61. return (c & 0xfffffc00) == 0xdc00;
  62. }
  63. static void append(std::string& str, std::uint32_t codepoint);
  64. static utf8_state decode(const utf8_state state, const std::uint8_t fragment,
  65. std::uint32_t& codepoint);
  66. };
  67. template <typename Char, typename = void>
  68. class unicode
  69. {
  70. };
  71. template <typename Char>
  72. class unicode<Char, typename std::enable_if<(sizeof(Char) == 4)>::type>
  73. : public unicode_helper
  74. {
  75. public:
  76. // UTF32 -> UTF8
  77. static std::string to_utf8(const std::wstring& str)
  78. {
  79. std::string result;
  80. for (auto c : str) {
  81. append(result, c);
  82. }
  83. return result;
  84. }
  85. static std::string to_utf8(Char c)
  86. {
  87. std::string result;
  88. append(result, c);
  89. return result;
  90. }
  91. // UTF8 -> UTF32
  92. static std::wstring from_utf8(const std::string& str)
  93. {
  94. std::wstring result;
  95. result.reserve(str.length());
  96. auto iter = str.begin();
  97. utf8_state state = s_start;
  98. std::uint32_t codepoint = 0;
  99. while (iter < str.end()) {
  100. if ((state = decode(state, static_cast<std::uint8_t>(*iter++),
  101. codepoint)) == s_start) {
  102. result += static_cast<std::wstring::value_type>(codepoint);
  103. codepoint = 0;
  104. } else if (state == s_reject) {
  105. result += static_cast<std::wstring::value_type>(0xfffd);
  106. state = s_start;
  107. codepoint = 0;
  108. }
  109. }
  110. if (state) {
  111. result += static_cast<std::wstring::value_type>(0xfffd);
  112. }
  113. return result;
  114. }
  115. static std::wstring from_utf8(char c)
  116. {
  117. std::wstring result;
  118. utf8_state state = s_start;
  119. std::uint32_t codepoint = 0;
  120. if ((state = decode(state, static_cast<std::uint8_t>(c), codepoint)) ==
  121. s_start) {
  122. result += static_cast<std::wstring::value_type>(codepoint);
  123. } else {
  124. result += static_cast<std::wstring::value_type>(0xfffd);
  125. }
  126. return result;
  127. }
  128. };
  129. template <typename Char>
  130. class unicode<Char, typename std::enable_if<(sizeof(Char) == 2)>::type>
  131. : public unicode_helper
  132. {
  133. public:
  134. // UTF16 -> UTF8
  135. static std::string to_utf8(const std::wstring& str)
  136. {
  137. std::string result;
  138. for (auto iter = str.begin(); iter != str.end(); ++iter) {
  139. std::uint32_t c = *iter;
  140. if (is_surrogate(c)) {
  141. ++iter;
  142. if (iter != str.end() && is_high_surrogate(c) &&
  143. is_low_surrogate(*iter)) {
  144. append(result, (std::uint32_t(c) << 10) + *iter - 0x35fdc00);
  145. } else {
  146. append(result, 0xfffd);
  147. if (iter == str.end()) {
  148. break;
  149. }
  150. }
  151. } else {
  152. append(result, c);
  153. }
  154. }
  155. return result;
  156. }
  157. static std::string to_utf8(Char c)
  158. {
  159. std::string result;
  160. if (is_surrogate(c)) {
  161. append(result, 0xfffd);
  162. } else {
  163. append(result, c);
  164. }
  165. return result;
  166. }
  167. // UTF8 -> UTF16
  168. static std::wstring from_utf8(const std::string& str)
  169. {
  170. std::wstring result;
  171. result.reserve(str.length());
  172. auto iter = str.begin();
  173. utf8_state state = s_start;
  174. std::uint32_t codepoint = 0;
  175. while (iter < str.end()) {
  176. if ((state = decode(state, static_cast<std::uint8_t>(*iter++),
  177. codepoint)) == s_start) {
  178. if (codepoint <= 0xffff) {
  179. result += static_cast<std::wstring::value_type>(codepoint);
  180. } else {
  181. codepoint -= 0x10000;
  182. result +=
  183. static_cast<std::wstring::value_type>((codepoint >> 10) + 0xd800);
  184. result += static_cast<std::wstring::value_type>((codepoint & 0x3ff) +
  185. 0xdc00);
  186. }
  187. codepoint = 0;
  188. } else if (state == s_reject) {
  189. result += static_cast<std::wstring::value_type>(0xfffd);
  190. state = s_start;
  191. codepoint = 0;
  192. }
  193. }
  194. if (state) {
  195. result += static_cast<std::wstring::value_type>(0xfffd);
  196. }
  197. return result;
  198. }
  199. static std::wstring from_utf8(char c)
  200. {
  201. std::wstring result;
  202. utf8_state state = s_start;
  203. std::uint32_t codepoint = 0;
  204. if ((state = decode(state, static_cast<std::uint8_t>(c), codepoint)) ==
  205. s_start) {
  206. if (codepoint <= 0xffff) {
  207. result += static_cast<std::wstring::value_type>(codepoint);
  208. } else {
  209. codepoint -= 0x10000;
  210. result +=
  211. static_cast<std::wstring::value_type>((codepoint >> 10) + 0xd800);
  212. result +=
  213. static_cast<std::wstring::value_type>((codepoint & 0x3ff) + 0xdc00);
  214. }
  215. } else {
  216. result += static_cast<std::wstring::value_type>(0xfffd);
  217. }
  218. return result;
  219. }
  220. };
  221. template <typename In, typename Out>
  222. class unicode_converter;
  223. template <>
  224. class unicode_converter<char, wchar_t>
  225. {
  226. public:
  227. std::wstring operator()(const std::string& in)
  228. {
  229. return unicode<wchar_t>::from_utf8(in);
  230. }
  231. std::wstring operator()(const char* in)
  232. {
  233. return unicode<wchar_t>::from_utf8(in);
  234. }
  235. std::wstring operator()(char in) { return unicode<wchar_t>::from_utf8(in); }
  236. };
  237. template <>
  238. class unicode_converter<wchar_t, char>
  239. {
  240. public:
  241. std::string operator()(const std::wstring& in)
  242. {
  243. return unicode<wchar_t>::to_utf8(in);
  244. }
  245. std::string operator()(const wchar_t* in)
  246. {
  247. return unicode<wchar_t>::to_utf8(in);
  248. }
  249. std::string operator()(wchar_t in) { return unicode<wchar_t>::to_utf8(in); }
  250. };
  251. template <>
  252. class unicode_converter<char, char>
  253. {
  254. public:
  255. std::string operator()(const std::string& in) { return in; }
  256. std::string operator()(const char* in) { return std::string(in); }
  257. std::string operator()(char in) { return std::string(1, in); }
  258. };
  259. template <>
  260. class unicode_converter<wchar_t, wchar_t>
  261. {
  262. public:
  263. std::wstring operator()(const std::wstring& in) { return in; }
  264. std::wstring operator()(const wchar_t* in) { return std::wstring(in); }
  265. std::wstring operator()(wchar_t in) { return std::wstring(1, in); }
  266. };
  267. template <typename In>
  268. struct string_converter
  269. {
  270. };
  271. template <>
  272. struct string_converter<char>
  273. {
  274. // some compilers, like gcc 4.8 does not implement the following C++11
  275. // signature:
  276. // std::string::string(const string&, const Allocator&)
  277. // As workaround, use char* pointer.
  278. template <typename Char, typename Traits, typename Alloc>
  279. static std::basic_string<Char, Traits, Alloc> to(const std::string& in,
  280. const Alloc& a)
  281. {
  282. return std::basic_string<Char, Traits, Alloc>(
  283. unicode_converter<char, Char>()(in).c_str(), a);
  284. }
  285. template <typename Char, typename Traits, typename Alloc>
  286. static std::basic_string<Char, Traits, Alloc> to(const char* in,
  287. const Alloc& a)
  288. {
  289. return std::basic_string<Char, Traits, Alloc>(
  290. unicode_converter<char, Char>()(in).c_str(), a);
  291. }
  292. template <typename Char, typename Traits, typename Alloc>
  293. static std::basic_string<Char, Traits, Alloc> to(char in, const Alloc& a)
  294. {
  295. return std::basic_string<Char, Traits, Alloc>(
  296. unicode_converter<char, Char>()(in).c_str(), a);
  297. }
  298. template <typename Char>
  299. static std::basic_string<Char> to(const std::string& in)
  300. {
  301. return std::basic_string<Char>(unicode_converter<char, Char>()(in));
  302. }
  303. template <typename Char>
  304. static std::basic_string<Char> to(const char* in)
  305. {
  306. return std::basic_string<Char>(unicode_converter<char, Char>()(in));
  307. }
  308. template <typename Char>
  309. static std::basic_string<Char> to(char in)
  310. {
  311. return std::basic_string<Char>(unicode_converter<char, Char>()(in));
  312. }
  313. };
  314. template <>
  315. struct string_converter<wchar_t>
  316. {
  317. // some compilers, like gcc 4.8 does not implement the following C++11
  318. // signature:
  319. // std::string::string(const string&, const Allocator&)
  320. // As workaround, use char* pointer.
  321. template <typename Char, typename Traits, typename Alloc>
  322. static std::basic_string<Char, Traits, Alloc> to(const std::wstring& in,
  323. const Alloc& a)
  324. {
  325. return std::basic_string<Char, Traits, Alloc>(
  326. unicode_converter<wchar_t, Char>()(in).c_str(), a);
  327. }
  328. template <typename Char, typename Traits, typename Alloc>
  329. static std::basic_string<Char, Traits, Alloc> to(const wchar_t* in,
  330. const Alloc& a)
  331. {
  332. return std::basic_string<Char, Traits, Alloc>(
  333. unicode_converter<wchar_t, Char>()(in).c_str(), a);
  334. }
  335. template <typename Char, typename Traits, typename Alloc>
  336. static std::basic_string<Char, Traits, Alloc> to(wchar_t in, const Alloc& a)
  337. {
  338. return std::basic_string<Char, Traits, Alloc>(
  339. unicode_converter<wchar_t, Char>()(in).c_str(), a);
  340. }
  341. template <typename Char>
  342. static std::basic_string<Char> to(const std::wstring& in)
  343. {
  344. return std::basic_string<Char>(unicode_converter<wchar_t, Char>()(in));
  345. }
  346. template <typename Char>
  347. static std::basic_string<Char> to(const wchar_t* in)
  348. {
  349. return std::basic_string<Char>(unicode_converter<wchar_t, Char>()(in));
  350. }
  351. template <typename Char>
  352. static std::basic_string<Char> to(wchar_t in)
  353. {
  354. return std::basic_string<Char>(unicode_converter<wchar_t, Char>()(in));
  355. }
  356. };
  357. template <typename T, typename = void>
  358. struct source_traits
  359. {
  360. };
  361. template <typename T, std::size_t N>
  362. struct source_traits<T[N]>
  363. {
  364. using value_type = T;
  365. };
  366. template <typename Char, typename Traits, typename Alloc>
  367. struct source_traits<std::basic_string<Char, Traits, Alloc>>
  368. {
  369. using value_type =
  370. typename std::basic_string<Char, Traits, Alloc>::value_type;
  371. };
  372. template <>
  373. struct source_traits<cm::string_view>
  374. {
  375. using value_type = cm::string_view::value_type;
  376. };
  377. # if CM_FILESYSTEM_SOURCE_TRAITS_ITERATOR
  378. template <typename T>
  379. struct source_traits<T, cm::enable_if_t<cm::is_iterator<T>::value, void>>
  380. {
  381. using value_type =
  382. typename std::iterator_traits<typename std::decay<T>::type>::value_type;
  383. };
  384. # endif
  385. template <typename In, typename Out>
  386. struct source_converter
  387. {
  388. };
  389. template <>
  390. struct source_converter<char, char>
  391. {
  392. template <typename Iterator>
  393. static void append_range(std::string& p, Iterator b, Iterator e)
  394. {
  395. if (b == e) {
  396. return;
  397. }
  398. p.append(b, e);
  399. }
  400. template <typename Iterator>
  401. static void append_range(std::string& p, Iterator b)
  402. {
  403. char e = '\0';
  404. if (*b == e) {
  405. return;
  406. }
  407. for (; *b != e; ++b) {
  408. p.push_back(*b);
  409. }
  410. }
  411. static void append_source(std::string& p, const cm::string_view s)
  412. {
  413. append_range(p, s.begin(), s.end());
  414. }
  415. template <typename Traits, typename Alloc>
  416. static void append_source(std::string& p,
  417. const std::basic_string<char, Traits, Alloc>& s)
  418. {
  419. append_range(p, s.begin(), s.end());
  420. }
  421. template <typename Source>
  422. static void append_source(std::string& p, const Source& s)
  423. {
  424. append_range(p, s);
  425. }
  426. static void set_source(std::string& p, std::string&& s) { p = std::move(s); }
  427. };
  428. template <>
  429. struct source_converter<wchar_t, char>
  430. {
  431. template <typename Iterator>
  432. static void append_range(std::string& p, Iterator b, Iterator e)
  433. {
  434. if (b == e) {
  435. return;
  436. }
  437. std::wstring tmp(b, e);
  438. std::string dest = string_converter<wchar_t>::to<char>(tmp);
  439. p.append(dest.begin(), dest.end());
  440. }
  441. template <typename Iterator>
  442. static void append_range(std::string& p, Iterator b)
  443. {
  444. wchar_t e = '\0';
  445. if (*b == e) {
  446. return;
  447. }
  448. std::wstring tmp;
  449. for (; *b != e; ++b) {
  450. tmp.push_back(*b);
  451. }
  452. std::string dest = string_converter<wchar_t>::to<char>(tmp);
  453. p.append(dest.begin(), dest.end());
  454. }
  455. template <typename Traits, typename Alloc>
  456. static void append_source(std::string& p,
  457. const std::basic_string<wchar_t, Traits, Alloc>& s)
  458. {
  459. append_range(p, s.begin(), s.end());
  460. }
  461. template <typename Source>
  462. static void append_source(std::string& p, const Source& s)
  463. {
  464. append_range(p, s);
  465. }
  466. static void set_source(std::string& p, std::wstring&& s)
  467. {
  468. p = string_converter<wchar_t>::to<char>(s);
  469. }
  470. };
  471. template <typename T>
  472. struct is_pathable_string : std::false_type
  473. {
  474. };
  475. template <typename Traits, typename Alloc>
  476. struct is_pathable_string<std::basic_string<char, Traits, Alloc>>
  477. : std::true_type
  478. {
  479. };
  480. template <typename Traits, typename Alloc>
  481. struct is_pathable_string<std::basic_string<wchar_t, Traits, Alloc>>
  482. : std::true_type
  483. {
  484. };
  485. template <>
  486. struct is_pathable_string<cm::string_view> : std::true_type
  487. {
  488. };
  489. template <typename T, typename = void>
  490. struct is_pathable_char_array : std::false_type
  491. {
  492. };
  493. template <typename T>
  494. struct is_pathable_char_array<
  495. T,
  496. cm::enable_if_t<
  497. std::is_same<char*, typename std::decay<T>::type>::value ||
  498. std::is_same<wchar_t*, typename std::decay<T>::type>::value,
  499. void>>
  500. : bool_constant<std::is_same<char*, typename std::decay<T>::type>::value ||
  501. std::is_same<wchar_t*, typename std::decay<T>::type>::value>
  502. {
  503. };
  504. template <typename T, typename = void>
  505. struct is_pathable_iterator : std::false_type
  506. {
  507. };
  508. template <typename T>
  509. struct is_pathable_iterator<
  510. T,
  511. cm::enable_if_t<
  512. is_input_iterator<T>::value &&
  513. (std::is_same<char,
  514. typename std::iterator_traits<
  515. typename std::decay<T>::type>::value_type>::value ||
  516. std::is_same<wchar_t,
  517. typename std::iterator_traits<
  518. typename std::decay<T>::type>::value_type>::value),
  519. void>>
  520. : bool_constant<
  521. std::is_same<char,
  522. typename std::iterator_traits<
  523. typename std::decay<T>::type>::value_type>::value ||
  524. std::is_same<wchar_t,
  525. typename std::iterator_traits<
  526. typename std::decay<T>::type>::value_type>::value>
  527. {
  528. };
  529. # if defined(__SUNPRO_CC) && defined(__sparc)
  530. // Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile
  531. // the full 'is_pathable' check. We use it only to improve error messages
  532. // via 'enable_if' when calling methods with incorrect types. Just
  533. // pretend all types are allowed so we can at least compile valid code.
  534. template <typename T>
  535. struct is_pathable : std::true_type
  536. {
  537. };
  538. # else
  539. template <typename T>
  540. struct is_pathable
  541. : bool_constant<is_pathable_string<T>::value ||
  542. is_pathable_char_array<T>::value ||
  543. is_pathable_iterator<T>::value>
  544. {
  545. };
  546. # endif
  547. }
  548. class path
  549. {
  550. using path_type = std::string;
  551. template <typename Source>
  552. using enable_if_pathable =
  553. enable_if_t<internals::is_pathable<Source>::value, path&>;
  554. enum class filename_fragment : unsigned char
  555. {
  556. stem,
  557. extension
  558. };
  559. public:
  560. # if defined(_WIN32)
  561. using value_type = wchar_t;
  562. # else
  563. using value_type = char;
  564. # endif
  565. using string_type = std::basic_string<value_type>;
  566. class iterator;
  567. using const_iterator = iterator;
  568. enum format : unsigned char
  569. {
  570. auto_format,
  571. native_format,
  572. generic_format
  573. };
  574. # if defined(_WIN32)
  575. static constexpr value_type preferred_separator = L'\\';
  576. # else
  577. static constexpr value_type preferred_separator = '/';
  578. # endif
  579. // Constructors
  580. // ============
  581. path() noexcept {}
  582. path(const path& p)
  583. : path_(p.path_)
  584. {
  585. }
  586. path(path&& p) noexcept
  587. : path_(std::move(p.path_))
  588. {
  589. }
  590. path(string_type&& source, format fmt = auto_format)
  591. {
  592. (void)fmt;
  593. internals::source_converter<value_type, path_type::value_type>::set_source(
  594. this->path_, std::move(source));
  595. }
  596. template <typename Source, typename = enable_if_pathable<Source>>
  597. path(const Source& source, format fmt = auto_format)
  598. {
  599. (void)fmt;
  600. internals::source_converter<
  601. typename internals::source_traits<Source>::value_type,
  602. path_type::value_type>::append_source(this->path_, source);
  603. }
  604. template <typename Iterator, typename = enable_if_pathable<Iterator>>
  605. path(const Iterator first, Iterator last, format fmt = auto_format)
  606. {
  607. (void)fmt;
  608. internals::source_converter<
  609. typename std::iterator_traits<Iterator>::value_type,
  610. path_type::value_type>::append_range(this->path_, first, last);
  611. }
  612. ~path() = default;
  613. // Assignments
  614. // ===========
  615. path& operator=(const path& p)
  616. {
  617. if (this != &p) {
  618. this->path_ = p.path_;
  619. }
  620. return *this;
  621. }
  622. path& operator=(path&& p) noexcept
  623. {
  624. if (this != &p) {
  625. this->path_ = std::move(p.path_);
  626. }
  627. return *this;
  628. }
  629. path& operator=(string_type&& source) { return this->assign(source); }
  630. template <typename Source, typename = enable_if_pathable<Source>>
  631. path& operator=(const Source& source)
  632. {
  633. return this->assign(source);
  634. }
  635. path& assign(string_type&& source)
  636. {
  637. internals::source_converter<value_type, path_type::value_type>::set_source(
  638. this->path_, std::move(source));
  639. return *this;
  640. }
  641. template <typename Source, typename = enable_if_pathable<Source>>
  642. path& assign(const Source& source)
  643. {
  644. this->path_.clear();
  645. internals::source_converter<
  646. typename internals::source_traits<Source>::value_type,
  647. path_type::value_type>::append_source(this->path_, source);
  648. return *this;
  649. }
  650. template <typename Iterator, typename = enable_if_pathable<Iterator>>
  651. path& assign(Iterator first, Iterator last)
  652. {
  653. this->path_.clear();
  654. internals::source_converter<
  655. typename std::iterator_traits<Iterator>::value_type,
  656. path_type::value_type>::append_range(this->path_, first, last);
  657. return *this;
  658. }
  659. // Concatenation
  660. // =============
  661. path& operator/=(const path& p);
  662. template <typename Source, typename = enable_if_pathable<Source>>
  663. path& append(const Source& source)
  664. {
  665. return this->operator/=(path(source));
  666. }
  667. template <typename Source>
  668. path& operator/=(const Source& source)
  669. {
  670. return this->append(source);
  671. }
  672. template <typename Iterator, typename = enable_if_pathable<Iterator>>
  673. path& append(Iterator first, Iterator last)
  674. {
  675. return this->operator/=(path(first, last));
  676. }
  677. path& operator+=(const path& p)
  678. {
  679. this->path_ += p.path_;
  680. return *this;
  681. }
  682. path& operator+=(const string_type& str)
  683. {
  684. this->path_ +=
  685. internals::string_converter<value_type>::to<path_type::value_type>(str);
  686. return *this;
  687. }
  688. path& operator+=(cm::string_view str)
  689. {
  690. this->path_.append(str.begin(), str.end());
  691. return *this;
  692. }
  693. path& operator+=(const value_type* str)
  694. {
  695. this->path_ +=
  696. internals::string_converter<value_type>::to<path_type::value_type>(str);
  697. return *this;
  698. }
  699. path& operator+=(const value_type c)
  700. {
  701. this->path_ +=
  702. internals::string_converter<value_type>::to<path_type::value_type>(c);
  703. return *this;
  704. }
  705. template <typename Source, typename = enable_if_pathable<Source>>
  706. path& concat(const Source& source)
  707. {
  708. internals::source_converter<
  709. typename internals::source_traits<Source>::value_type,
  710. path_type::value_type>::append_source(this->path_, source);
  711. return *this;
  712. }
  713. template <typename Source>
  714. path& operator+=(const Source& source)
  715. {
  716. return this->concat(source);
  717. }
  718. template <typename Iterator, typename = enable_if_pathable<Iterator>>
  719. path& concat(Iterator first, Iterator last)
  720. {
  721. internals::source_converter<
  722. typename std::iterator_traits<Iterator>::value_type,
  723. path_type::value_type>::append_range(this->path_, first, last);
  724. return *this;
  725. }
  726. // Modifiers
  727. // =========
  728. void clear() noexcept { this->path_.clear(); }
  729. path& make_preferred()
  730. {
  731. # if defined(_WIN32)
  732. std::replace(
  733. this->path_.begin(), this->path_.end(), '/',
  734. static_cast<path_type::value_type>(this->preferred_separator));
  735. # endif
  736. return *this;
  737. }
  738. path& remove_filename()
  739. {
  740. auto fname = this->get_filename();
  741. if (!fname.empty()) {
  742. this->path_.erase(fname.data() - this->path_.data());
  743. }
  744. return *this;
  745. }
  746. path& replace_filename(const path& replacement)
  747. {
  748. this->remove_filename();
  749. this->operator/=(replacement);
  750. return *this;
  751. }
  752. path& replace_extension(const path& replacement = path())
  753. {
  754. auto ext = this->get_filename_fragment(filename_fragment::extension);
  755. if (!ext.empty()) {
  756. this->path_.erase(ext.data() - this->path_.data());
  757. }
  758. if (!replacement.path_.empty()) {
  759. if (replacement.path_[0] != '.') {
  760. this->path_ += '.';
  761. }
  762. this->path_.append(replacement.path_);
  763. }
  764. return *this;
  765. }
  766. void swap(path& other) noexcept { this->path_.swap(other.path_); }
  767. // Format observers
  768. // ================
  769. const string_type& native() const noexcept
  770. {
  771. # if defined(_WIN32)
  772. this->native_path_ = internals::string_converter<
  773. path_type::value_type>::to<string_type::value_type>(this->path_);
  774. return this->native_path_;
  775. # else
  776. return this->path_;
  777. # endif
  778. }
  779. const value_type* c_str() const noexcept { return this->native().c_str(); }
  780. operator string_type() const { return this->native(); }
  781. template <
  782. typename Char, typename Traits = std::char_traits<Char>,
  783. typename Alloc = std::allocator<Char>,
  784. cm::enable_if_t<(std::is_same<Char, char>::value &&
  785. std::is_same<Traits, std::char_traits<char>>::value) ||
  786. (std::is_same<Char, wchar_t>::value &&
  787. std::is_same<Traits, std::char_traits<wchar_t>>::value),
  788. int> = 1>
  789. std::basic_string<Char, Traits, Alloc> string(const Alloc& a = Alloc()) const
  790. {
  791. return internals::string_converter<path_type::value_type>::to<Char, Traits,
  792. Alloc>(
  793. this->path_, a);
  794. }
  795. const std::string string() const { return this->path_; }
  796. std::wstring wstring() const
  797. {
  798. std::string out = this->string();
  799. return internals::string_converter<path_type::value_type>::to<
  800. std::wstring::value_type>(out);
  801. }
  802. template <
  803. typename Char, typename Traits = std::char_traits<Char>,
  804. typename Alloc = std::allocator<Char>,
  805. cm::enable_if_t<(std::is_same<Char, char>::value &&
  806. std::is_same<Traits, std::char_traits<char>>::value) ||
  807. (std::is_same<Char, wchar_t>::value &&
  808. std::is_same<Traits, std::char_traits<wchar_t>>::value),
  809. int> = 1>
  810. std::basic_string<Char, Traits, Alloc> generic_string(
  811. const Alloc& a = Alloc()) const
  812. {
  813. return internals::string_converter<path_type::value_type>::to<Char, Traits,
  814. Alloc>(
  815. this->get_generic(), a);
  816. }
  817. std::string generic_string() const { return this->get_generic(); }
  818. std::wstring generic_wstring() const
  819. {
  820. auto dest = this->generic_string();
  821. return internals::string_converter<path_type::value_type>::to<
  822. std::wstring::value_type>(dest);
  823. }
  824. // Compare
  825. // =======
  826. int compare(const path& p) const noexcept
  827. {
  828. return this->compare_path(p.path_);
  829. }
  830. int compare(const string_type& str) const
  831. {
  832. return this->compare_path(
  833. internals::string_converter<value_type>::to<path_type::value_type>(str));
  834. }
  835. int compare(const value_type* str) const
  836. {
  837. return this->compare_path(
  838. internals::string_converter<value_type>::to<path_type::value_type>(str));
  839. }
  840. int compare(cm::string_view str) const { return this->compare_path(str); }
  841. // Generation
  842. // ==========
  843. path lexically_normal() const;
  844. path lexically_relative(const path& base) const;
  845. path lexically_proximate(const path& base) const
  846. {
  847. path result = this->lexically_relative(base);
  848. return result.empty() ? *this : result;
  849. }
  850. // Decomposition
  851. // =============
  852. path root_name() const { return get_root_name(); }
  853. path root_directory() const { return this->get_root_directory(); }
  854. path root_path() const
  855. {
  856. return this->root_name().append(this->get_root_directory());
  857. }
  858. path relative_path() const { return this->get_relative_path(); }
  859. path parent_path() const { return this->get_parent_path(); }
  860. path filename() const { return this->get_filename(); }
  861. path stem() const
  862. {
  863. return this->get_filename_fragment(filename_fragment::stem);
  864. }
  865. path extension() const
  866. {
  867. return this->get_filename_fragment(filename_fragment::extension);
  868. }
  869. // Queries
  870. // =======
  871. bool empty() const noexcept { return this->path_.empty(); }
  872. bool has_root_name() const { return !this->get_root_name().empty(); }
  873. bool has_root_directory() const
  874. {
  875. return !this->get_root_directory().empty();
  876. }
  877. bool has_root_path() const
  878. {
  879. return this->has_root_name() || this->has_root_directory();
  880. }
  881. bool has_relative_path() const { return !this->get_relative_path().empty(); }
  882. bool has_parent_path() const { return !this->get_parent_path().empty(); }
  883. bool has_filename() const { return !this->get_filename().empty(); }
  884. bool has_stem() const
  885. {
  886. return !this->get_filename_fragment(filename_fragment::stem).empty();
  887. }
  888. bool has_extension() const
  889. {
  890. return !this->get_filename_fragment(filename_fragment::extension).empty();
  891. }
  892. bool is_absolute() const
  893. {
  894. # if defined(_WIN32)
  895. return this->has_root_name() && this->has_root_directory();
  896. # else
  897. return this->has_root_directory();
  898. # endif
  899. }
  900. bool is_relative() const { return !this->is_absolute(); }
  901. // Iterators
  902. // =========
  903. inline iterator begin() const;
  904. inline iterator end() const;
  905. // Non-members
  906. // ===========
  907. friend inline bool operator==(const path& lhs, const path& rhs) noexcept
  908. {
  909. return lhs.compare(rhs) == 0;
  910. }
  911. friend inline bool operator!=(const path& lhs, const path& rhs) noexcept
  912. {
  913. return lhs.compare(rhs) != 0;
  914. }
  915. friend inline bool operator<(const path& lhs, const path& rhs) noexcept
  916. {
  917. return lhs.compare(rhs) < 0;
  918. }
  919. friend inline bool operator<=(const path& lhs, const path& rhs) noexcept
  920. {
  921. return lhs.compare(rhs) <= 0;
  922. }
  923. friend inline bool operator>(const path& lhs, const path& rhs) noexcept
  924. {
  925. return lhs.compare(rhs) > 0;
  926. }
  927. friend inline bool operator>=(const path& lhs, const path& rhs) noexcept
  928. {
  929. return lhs.compare(rhs) >= 0;
  930. }
  931. friend inline path operator/(const path& lhs, const path& rhs)
  932. {
  933. path result(lhs);
  934. result /= rhs;
  935. return result;
  936. }
  937. template <typename Char, typename Traits>
  938. friend inline cm::enable_if_t<
  939. (std::is_same<Char, path::value_type>::value &&
  940. std::is_same<Traits, std::char_traits<path::value_type>>::value) ||
  941. (std::is_same<Char, path::path_type::value_type>::value &&
  942. std::is_same<Traits,
  943. std::char_traits<path::path_type::value_type>>::value),
  944. std::basic_ostream<Char, Traits>&>
  945. operator<<(std::basic_ostream<Char, Traits>& os, const path& p)
  946. {
  947. os << cm::quoted(p.string<Char, Traits>());
  948. return os;
  949. }
  950. template <typename Char, typename Traits>
  951. friend inline cm::enable_if_t<
  952. (std::is_same<Char, path::value_type>::value &&
  953. std::is_same<Traits, std::char_traits<path::value_type>>::value) ||
  954. (std::is_same<Char, path::path_type::value_type>::value &&
  955. std::is_same<Traits,
  956. std::char_traits<path::path_type::value_type>>::value),
  957. std::basic_istream<Char, Traits>&>
  958. operator>>(std::basic_istream<Char, Traits>& is, path& p)
  959. {
  960. std::basic_string<Char, Traits> tmp;
  961. is >> cm::quoted(tmp);
  962. p = tmp;
  963. return is;
  964. }
  965. private:
  966. friend class iterator;
  967. friend std::size_t hash_value(const path& p) noexcept;
  968. path_type get_generic() const;
  969. cm::string_view get_root_name() const;
  970. cm::string_view get_root_directory() const;
  971. cm::string_view get_relative_path() const;
  972. cm::string_view get_parent_path() const;
  973. cm::string_view get_filename() const;
  974. cm::string_view get_filename_fragment(filename_fragment fragment) const;
  975. int compare_path(cm::string_view str) const;
  976. path_type path_;
  977. # if defined(_WIN32)
  978. mutable string_type native_path_;
  979. # endif
  980. };
  981. class path::iterator
  982. {
  983. public:
  984. using iterator_category = std::bidirectional_iterator_tag;
  985. using value_type = path;
  986. using difference_type = std::ptrdiff_t;
  987. using pointer = const path*;
  988. using reference = const path&;
  989. iterator();
  990. iterator(const iterator& other);
  991. ~iterator();
  992. iterator& operator=(const iterator& other);
  993. reference operator*() const { return this->path_element_; }
  994. pointer operator->() const { return &this->path_element_; }
  995. iterator& operator++();
  996. iterator operator++(int)
  997. {
  998. iterator it(*this);
  999. this->operator++();
  1000. return it;
  1001. }
  1002. iterator& operator--();
  1003. iterator operator--(int)
  1004. {
  1005. iterator it(*this);
  1006. this->operator--();
  1007. return it;
  1008. }
  1009. private:
  1010. friend class path;
  1011. friend bool operator==(const iterator&, const iterator&);
  1012. iterator(const path* p, bool at_end = false);
  1013. const path* path_;
  1014. std::unique_ptr<internals::path_parser> parser_;
  1015. path path_element_;
  1016. };
  1017. inline path::iterator path::begin() const
  1018. {
  1019. return iterator(this);
  1020. }
  1021. inline path::iterator path::end() const
  1022. {
  1023. return iterator(this, true);
  1024. }
  1025. bool operator==(const path::iterator& lhs, const path::iterator& rhs);
  1026. inline bool operator!=(const path::iterator& lhs, const path::iterator& rhs)
  1027. {
  1028. return !(lhs == rhs);
  1029. }
  1030. // Non-member functions
  1031. // ====================
  1032. inline void swap(path& lhs, path& rhs) noexcept
  1033. {
  1034. lhs.swap(rhs);
  1035. }
  1036. std::size_t hash_value(const path& p) noexcept;
  1037. #endif
  1038. } // namespace filesystem
  1039. } // namespace cm
  1040. #endif