path.append.pass.cpp 8.6 KB

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