path.append.pass.cpp 7.8 KB

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