path.append.pass.cpp 7.8 KB

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