path.append.pass.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is dual licensed under the MIT and the University of Illinois Open
  6. // Source Licenses. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. // UNSUPPORTED: c++98, c++03
  10. // <experimental/filesystem>
  11. // class path
  12. // path& operator/=(path const&)
  13. // template <class Source>
  14. // path& operator/=(Source const&);
  15. // template <class Source>
  16. // path& append(Source const&);
  17. // template <class InputIterator>
  18. // path& append(InputIterator first, InputIterator last);
  19. #include "filesystem_include.hpp"
  20. #include <type_traits>
  21. #include <string_view>
  22. #include <cassert>
  23. #include "test_macros.h"
  24. #include "test_iterators.h"
  25. #include "count_new.hpp"
  26. #include "filesystem_test_helper.hpp"
  27. #include "verbose_assert.h"
  28. struct AppendOperatorTestcase {
  29. MultiStringType lhs;
  30. MultiStringType rhs;
  31. MultiStringType expect;
  32. };
  33. #define S(Str) MKSTR(Str)
  34. const AppendOperatorTestcase Cases[] =
  35. {
  36. {S(""), S(""), S("")}
  37. , {S("p1"), S("p2"), S("p1/p2")}
  38. , {S("p1/"), S("p2"), S("p1/p2")}
  39. , {S("p1"), S("/p2"), S("/p2")}
  40. , {S("p1/"), S("/p2"), S("/p2")}
  41. , {S("p1"), S("\\p2"), S("p1/\\p2")}
  42. , {S("p1\\"), S("p2"), S("p1\\/p2")}
  43. , {S("p1\\"), S("\\p2"), S("p1\\/\\p2")}
  44. , {S(""), S("p2"), S("p2")}
  45. , {S("/p1"), S("p2"), S("/p1/p2")}
  46. , {S("/p1"), S("/p2"), S("/p2")}
  47. , {S("/p1/p3"), S("p2"), S("/p1/p3/p2")}
  48. , {S("/p1/p3/"), S("p2"), S("/p1/p3/p2")}
  49. , {S("/p1/"), S("p2"), S("/p1/p2")}
  50. , {S("/p1/p3/"), S("/p2/p4"), S("/p2/p4")}
  51. , {S("/"), S(""), S("/")}
  52. , {S("/p1"), S("/p2/"), S("/p2/")}
  53. , {S("p1"), S(""), S("p1/")}
  54. , {S("p1/"), S(""), S("p1/")}
  55. };
  56. const AppendOperatorTestcase LongLHSCases[] =
  57. {
  58. {S("p1"), S("p2"), S("p1/p2")}
  59. , {S("p1/"), S("p2"), S("p1/p2")}
  60. , {S("p1"), S("/p2"), S("/p2")}
  61. , {S("/p1"), S("p2"), S("/p1/p2")}
  62. };
  63. #undef S
  64. // The append operator may need to allocate a temporary buffer before a code_cvt
  65. // conversion. Test if this allocation occurs by:
  66. // 1. Create a path, `LHS`, and reserve enough space to append `RHS`.
  67. // This prevents `LHS` from allocating during the actual appending.
  68. // 2. Create a `Source` object `RHS`, which represents a "large" string.
  69. // (The string must not trigger the SSO)
  70. // 3. Append `RHS` to `LHS` and check for the expected allocation behavior.
  71. template <class CharT>
  72. void doAppendSourceAllocTest(AppendOperatorTestcase const& TC)
  73. {
  74. using namespace fs;
  75. using Ptr = CharT const*;
  76. using Str = std::basic_string<CharT>;
  77. using StrView = std::basic_string_view<CharT>;
  78. using InputIter = input_iterator<Ptr>;
  79. const Ptr L = TC.lhs;
  80. Str RShort = (Ptr)TC.rhs;
  81. Str EShort = (Ptr)TC.expect;
  82. assert(RShort.size() >= 2);
  83. CharT c = RShort.back();
  84. RShort.append(100, c);
  85. EShort.append(100, c);
  86. const Ptr R = RShort.data();
  87. const Str& E = EShort;
  88. std::size_t ReserveSize = E.size() + 3;
  89. // basic_string
  90. {
  91. path LHS(L); PathReserve(LHS, ReserveSize);
  92. Str RHS(R);
  93. {
  94. DisableAllocationGuard g;
  95. LHS /= RHS;
  96. }
  97. ASSERT_PRED(PathEq, LHS , E);
  98. }
  99. // basic_string_view
  100. {
  101. path LHS(L); PathReserve(LHS, ReserveSize);
  102. StrView RHS(R);
  103. {
  104. DisableAllocationGuard g;
  105. LHS /= RHS;
  106. }
  107. assert(PathEq(LHS, E));
  108. }
  109. // CharT*
  110. {
  111. path LHS(L); PathReserve(LHS, ReserveSize);
  112. Ptr RHS(R);
  113. {
  114. DisableAllocationGuard g;
  115. LHS /= RHS;
  116. }
  117. assert(PathEq(LHS, E));
  118. }
  119. {
  120. path LHS(L); PathReserve(LHS, ReserveSize);
  121. Ptr RHS(R);
  122. {
  123. DisableAllocationGuard g;
  124. LHS.append(RHS, StrEnd(RHS));
  125. }
  126. assert(PathEq(LHS, E));
  127. }
  128. // input iterator - For non-native char types, appends needs to copy the
  129. // iterator range into a contiguous block of memory before it can perform the
  130. // code_cvt conversions.
  131. // For "char" no allocations will be performed because no conversion is
  132. // required.
  133. bool DisableAllocations = std::is_same<CharT, char>::value;
  134. {
  135. path LHS(L); PathReserve(LHS, ReserveSize);
  136. InputIter RHS(R);
  137. {
  138. RequireAllocationGuard g; // requires 1 or more allocations occur by default
  139. if (DisableAllocations) g.requireExactly(0);
  140. LHS /= RHS;
  141. }
  142. assert(PathEq(LHS, E));
  143. }
  144. {
  145. path LHS(L); PathReserve(LHS, ReserveSize);
  146. InputIter RHS(R);
  147. InputIter REnd(StrEnd(R));
  148. {
  149. RequireAllocationGuard g;
  150. if (DisableAllocations) g.requireExactly(0);
  151. LHS.append(RHS, REnd);
  152. }
  153. assert(PathEq(LHS, E));
  154. }
  155. }
  156. template <class CharT>
  157. void doAppendSourceTest(AppendOperatorTestcase const& TC)
  158. {
  159. using namespace fs;
  160. using Ptr = CharT const*;
  161. using Str = std::basic_string<CharT>;
  162. using StrView = std::basic_string_view<CharT>;
  163. using InputIter = input_iterator<Ptr>;
  164. const Ptr L = TC.lhs;
  165. const Ptr R = TC.rhs;
  166. const Ptr E = TC.expect;
  167. // basic_string
  168. {
  169. path Result(L);
  170. Str RHS(R);
  171. path& Ref = (Result /= RHS);
  172. ASSERT_EQ(Result, E)
  173. << DISPLAY(L) << DISPLAY(R);
  174. assert(&Ref == &Result);
  175. }
  176. {
  177. path LHS(L);
  178. Str RHS(R);
  179. path& Ref = LHS.append(RHS);
  180. assert(PathEq(LHS, E));
  181. assert(&Ref == &LHS);
  182. }
  183. // basic_string_view
  184. {
  185. path LHS(L);
  186. StrView RHS(R);
  187. path& Ref = (LHS /= RHS);
  188. assert(PathEq(LHS, E));
  189. assert(&Ref == &LHS);
  190. }
  191. {
  192. path LHS(L);
  193. StrView RHS(R);
  194. path& Ref = LHS.append(RHS);
  195. assert(PathEq(LHS, E));
  196. assert(&Ref == &LHS);
  197. }
  198. // Char*
  199. {
  200. path LHS(L);
  201. Str RHS(R);
  202. path& Ref = (LHS /= RHS);
  203. assert(PathEq(LHS, E));
  204. assert(&Ref == &LHS);
  205. }
  206. {
  207. path LHS(L);
  208. Ptr RHS(R);
  209. path& Ref = LHS.append(RHS);
  210. assert(PathEq(LHS, E));
  211. assert(&Ref == &LHS);
  212. }
  213. {
  214. path LHS(L);
  215. Ptr RHS(R);
  216. path& Ref = LHS.append(RHS, StrEnd(RHS));
  217. ASSERT_PRED(PathEq, LHS, E)
  218. << DISPLAY(L) << DISPLAY(R);
  219. assert(&Ref == &LHS);
  220. }
  221. // iterators
  222. {
  223. path LHS(L);
  224. InputIter RHS(R);
  225. path& Ref = (LHS /= RHS);
  226. assert(PathEq(LHS, E));
  227. assert(&Ref == &LHS);
  228. }
  229. {
  230. path LHS(L); InputIter RHS(R);
  231. path& Ref = LHS.append(RHS);
  232. assert(PathEq(LHS, E));
  233. assert(&Ref == &LHS);
  234. }
  235. {
  236. path LHS(L);
  237. InputIter RHS(R);
  238. InputIter REnd(StrEnd(R));
  239. path& Ref = LHS.append(RHS, REnd);
  240. assert(PathEq(LHS, E));
  241. assert(&Ref == &LHS);
  242. }
  243. }
  244. template <class It, class = decltype(fs::path{}.append(std::declval<It>()))>
  245. constexpr bool has_append(int) { return true; }
  246. template <class It>
  247. constexpr bool has_append(long) { return false; }
  248. template <class It, class = decltype(fs::path{}.operator/=(std::declval<It>()))>
  249. constexpr bool has_append_op(int) { return true; }
  250. template <class It>
  251. constexpr bool has_append_op(long) { return false; }
  252. template <class It>
  253. constexpr bool has_append() {
  254. static_assert(has_append<It>(0) == has_append_op<It>(0), "must be same");
  255. return has_append<It>(0) && has_append_op<It>(0);
  256. }
  257. void test_sfinae()
  258. {
  259. using namespace fs;
  260. {
  261. using It = const char* const;
  262. static_assert(has_append<It>(), "");
  263. }
  264. {
  265. using It = input_iterator<const char*>;
  266. static_assert(has_append<It>(), "");
  267. }
  268. {
  269. struct Traits {
  270. using iterator_category = std::input_iterator_tag;
  271. using value_type = const char;
  272. using pointer = const char*;
  273. using reference = const char&;
  274. using difference_type = std::ptrdiff_t;
  275. };
  276. using It = input_iterator<const char*, Traits>;
  277. static_assert(has_append<It>(), "");
  278. }
  279. {
  280. using It = output_iterator<const char*>;
  281. static_assert(!has_append<It>(), "");
  282. }
  283. {
  284. static_assert(!has_append<int*>(), "");
  285. }
  286. {
  287. static_assert(!has_append<char>(), "");
  288. static_assert(!has_append<const char>(), "");
  289. }
  290. }
  291. int main()
  292. {
  293. using namespace fs;
  294. for (auto const & TC : Cases) {
  295. {
  296. const char* LHS_In = TC.lhs;
  297. const char* RHS_In = TC.rhs;
  298. path LHS(LHS_In);
  299. path RHS(RHS_In);
  300. path& Res = (LHS /= RHS);
  301. ASSERT_PRED(PathEq, Res, (const char*)TC.expect)
  302. << DISPLAY(LHS_In) << DISPLAY(RHS_In);
  303. assert(&Res == &LHS);
  304. }
  305. doAppendSourceTest<char> (TC);
  306. doAppendSourceTest<wchar_t> (TC);
  307. doAppendSourceTest<char16_t>(TC);
  308. doAppendSourceTest<char32_t>(TC);
  309. }
  310. for (auto const & TC : LongLHSCases) {
  311. doAppendSourceAllocTest<char>(TC);
  312. doAppendSourceAllocTest<wchar_t>(TC);
  313. }
  314. test_sfinae();
  315. }