path.concat.pass.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  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+=(const path& x);
  13. // path& operator+=(const string_type& x);
  14. // path& operator+=(string_view x);
  15. // path& operator+=(const value_type* x);
  16. // path& operator+=(value_type x);
  17. // template <class Source>
  18. // path& operator+=(const Source& x);
  19. // template <class EcharT>
  20. // path& operator+=(EcharT x);
  21. // template <class Source>
  22. // path& concat(const Source& x);
  23. // template <class InputIterator>
  24. // path& concat(InputIterator first, InputIterator last);
  25. #include <experimental/filesystem>
  26. #include <type_traits>
  27. #include <string>
  28. #include <string_view>
  29. #include <cassert>
  30. #include "test_macros.h"
  31. #include "test_iterators.h"
  32. #include "count_new.hpp"
  33. #include "filesystem_test_helper.hpp"
  34. namespace fs = std::experimental::filesystem;
  35. struct ConcatOperatorTestcase {
  36. MultiStringType lhs;
  37. MultiStringType rhs;
  38. MultiStringType expect;
  39. };
  40. #define LONGSTR "LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR"
  41. #define S(Str) MKSTR(Str)
  42. const ConcatOperatorTestcase Cases[] =
  43. {
  44. {S(""), S(""), S("")}
  45. , {S("p1"), S("p2"), S("p1p2")}
  46. , {S("p1/"), S("/p2"), S("p1//p2")}
  47. , {S(""), S("\\foo/bar/baz"), S("\\foo/bar/baz")}
  48. , {S("c:\\foo"), S(""), S("c:\\foo")}
  49. , {S(LONGSTR), S("foo"), S(LONGSTR "foo")}
  50. , {S("abcdefghijklmnopqrstuvwxyz/\\"), S("/\\123456789"), S("abcdefghijklmnopqrstuvwxyz/\\/\\123456789")}
  51. };
  52. const ConcatOperatorTestcase LongLHSCases[] =
  53. {
  54. {S(""), S(LONGSTR), S(LONGSTR)}
  55. , {S("p1/"), S(LONGSTR), S("p1/" LONGSTR)}
  56. };
  57. const ConcatOperatorTestcase CharTestCases[] =
  58. {
  59. {S(""), S("P"), S("P")}
  60. , {S("/fooba"), S("r"), S("/foobar")}
  61. };
  62. #undef S
  63. #undef LONGSTR
  64. // The concat 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. Concat `RHS` to `LHS` and check for the expected allocation behavior.
  71. template <class CharT>
  72. void doConcatSourceAllocTest(ConcatOperatorTestcase 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. const Ptr R = TC.rhs;
  81. const Ptr E = TC.expect;
  82. std::size_t ReserveSize = StrLen(E) + 1;
  83. // basic_string
  84. {
  85. path LHS(L); PathReserve(LHS, ReserveSize);
  86. Str RHS(R);
  87. {
  88. DisableAllocationGuard g;
  89. LHS += RHS;
  90. }
  91. assert(LHS == E);
  92. }
  93. // basic_string_view
  94. {
  95. path LHS(L); PathReserve(LHS, ReserveSize);
  96. StrView RHS(R);
  97. {
  98. DisableAllocationGuard g;
  99. LHS += RHS;
  100. }
  101. assert(LHS == E);
  102. }
  103. // CharT*
  104. {
  105. path LHS(L); PathReserve(LHS, ReserveSize);
  106. Ptr RHS(R);
  107. {
  108. DisableAllocationGuard g;
  109. LHS += RHS;
  110. }
  111. assert(LHS == E);
  112. }
  113. {
  114. path LHS(L); PathReserve(LHS, ReserveSize);
  115. Ptr RHS(R);
  116. {
  117. DisableAllocationGuard g;
  118. LHS.concat(RHS, StrEnd(RHS));
  119. }
  120. assert(LHS == E);
  121. }
  122. // input iterator - For non-native char types, appends needs to copy the
  123. // iterator range into a contiguous block of memory before it can perform the
  124. // code_cvt conversions.
  125. // For "char" no allocations will be performed because no conversion is
  126. // required.
  127. bool DisableAllocations = std::is_same<CharT, char>::value;
  128. {
  129. path LHS(L); PathReserve(LHS, ReserveSize);
  130. InputIter RHS(R);
  131. {
  132. RequireAllocationGuard g; // requires 1 or more allocations occur by default
  133. if (DisableAllocations) g.requireExactly(0);
  134. LHS += RHS;
  135. }
  136. assert(LHS == E);
  137. }
  138. {
  139. path LHS(L); PathReserve(LHS, ReserveSize);
  140. InputIter RHS(R);
  141. InputIter REnd(StrEnd(R));
  142. {
  143. RequireAllocationGuard g;
  144. if (DisableAllocations) g.requireExactly(0);
  145. LHS.concat(RHS, REnd);
  146. }
  147. assert(LHS == E);
  148. }
  149. }
  150. template <class CharT>
  151. void doConcatSourceTest(ConcatOperatorTestcase const& TC)
  152. {
  153. using namespace fs;
  154. using Ptr = CharT const*;
  155. using Str = std::basic_string<CharT>;
  156. using StrView = std::basic_string_view<CharT>;
  157. using InputIter = input_iterator<Ptr>;
  158. const Ptr L = TC.lhs;
  159. const Ptr R = TC.rhs;
  160. const Ptr E = TC.expect;
  161. // basic_string
  162. {
  163. path LHS(L);
  164. Str RHS(R);
  165. path& Ref = (LHS += RHS);
  166. assert(LHS == E);
  167. assert(&Ref == &LHS);
  168. }
  169. {
  170. path LHS(L);
  171. Str RHS(R);
  172. path& Ref = LHS.concat(RHS);
  173. assert(LHS == E);
  174. assert(&Ref == &LHS);
  175. }
  176. // basic_string_view
  177. {
  178. path LHS(L);
  179. StrView RHS(R);
  180. path& Ref = (LHS += RHS);
  181. assert(LHS == E);
  182. assert(&Ref == &LHS);
  183. }
  184. {
  185. path LHS(L);
  186. StrView RHS(R);
  187. path& Ref = LHS.concat(RHS);
  188. assert(LHS == E);
  189. assert(&Ref == &LHS);
  190. }
  191. // Char*
  192. {
  193. path LHS(L);
  194. Str RHS(R);
  195. path& Ref = (LHS += RHS);
  196. assert(LHS == E);
  197. assert(&Ref == &LHS);
  198. }
  199. {
  200. path LHS(L);
  201. Ptr RHS(R);
  202. path& Ref = LHS.concat(RHS);
  203. assert(LHS == E);
  204. assert(&Ref == &LHS);
  205. }
  206. {
  207. path LHS(L);
  208. Ptr RHS(R);
  209. path& Ref = LHS.concat(RHS, StrEnd(RHS));
  210. assert(LHS == E);
  211. assert(&Ref == &LHS);
  212. }
  213. // iterators
  214. {
  215. path LHS(L);
  216. InputIter RHS(R);
  217. path& Ref = (LHS += RHS);
  218. assert(LHS == E);
  219. assert(&Ref == &LHS);
  220. }
  221. {
  222. path LHS(L); InputIter RHS(R);
  223. path& Ref = LHS.concat(RHS);
  224. assert(LHS == E);
  225. assert(&Ref == &LHS);
  226. }
  227. {
  228. path LHS(L);
  229. InputIter RHS(R);
  230. InputIter REnd(StrEnd(R));
  231. path& Ref = LHS.concat(RHS, REnd);
  232. assert(LHS == E);
  233. assert(&Ref == &LHS);
  234. }
  235. }
  236. template <class CharT>
  237. void doConcatECharTest(ConcatOperatorTestcase const& TC)
  238. {
  239. using namespace fs;
  240. using Ptr = CharT const*;
  241. const Ptr RStr = TC.rhs;
  242. assert(StrLen(RStr) == 1);
  243. const Ptr L = TC.lhs;
  244. const CharT R = RStr[0];
  245. const Ptr E = TC.expect;
  246. {
  247. path LHS(L);
  248. path& Ref = (LHS += R);
  249. assert(LHS == E);
  250. assert(&Ref == &LHS);
  251. }
  252. }
  253. template <class It, class = decltype(fs::path{}.concat(std::declval<It>()))>
  254. constexpr bool has_concat(int) { return true; }
  255. template <class It>
  256. constexpr bool has_concat(long) { return false; }
  257. template <class It, class = decltype(fs::path{}.operator+=(std::declval<It>()))>
  258. constexpr bool has_concat_op(int) { return true; }
  259. template <class It>
  260. constexpr bool has_concat_op(long) { return false; }
  261. template <class It>
  262. constexpr bool has_concat_op() { return has_concat_op<It>(0); }
  263. template <class It>
  264. constexpr bool has_concat() {
  265. static_assert(has_concat<It>(0) == has_concat_op<It>(0), "must be same");
  266. return has_concat<It>(0) && has_concat_op<It>(0);
  267. }
  268. void test_sfinae() {
  269. using namespace fs;
  270. {
  271. static_assert(has_concat_op<char>(), "");
  272. static_assert(has_concat_op<const char>(), "");
  273. static_assert(has_concat_op<char16_t>(), "");
  274. static_assert(has_concat_op<const char16_t>(), "");
  275. }
  276. {
  277. using It = const char* const;
  278. static_assert(has_concat<It>(), "");
  279. }
  280. {
  281. using It = input_iterator<const char*>;
  282. static_assert(has_concat<It>(), "");
  283. }
  284. {
  285. struct Traits {
  286. using iterator_category = std::input_iterator_tag;
  287. using value_type = const char;
  288. using pointer = const char*;
  289. using reference = const char&;
  290. using difference_type = std::ptrdiff_t;
  291. };
  292. using It = input_iterator<const char*, Traits>;
  293. static_assert(has_concat<It>(), "");
  294. }
  295. {
  296. using It = output_iterator<const char*>;
  297. static_assert(!has_concat<It>(), "");
  298. }
  299. {
  300. static_assert(!has_concat<int>(0), "");
  301. // operator+=(int) is well formed since it converts to operator+=(value_type)
  302. // but concat(int) isn't valid because there is no concat(value_type).
  303. // This should probably be addressed by a LWG issue.
  304. static_assert(has_concat_op<int>(), "");
  305. }
  306. {
  307. static_assert(!has_concat<int*>(), "");
  308. }
  309. }
  310. int main()
  311. {
  312. using namespace fs;
  313. for (auto const & TC : Cases) {
  314. {
  315. path LHS((const char*)TC.lhs);
  316. path RHS((const char*)TC.rhs);
  317. path& Ref = (LHS += RHS);
  318. assert(LHS == (const char*)TC.expect);
  319. assert(&Ref == &LHS);
  320. }
  321. {
  322. path LHS((const char*)TC.lhs);
  323. std::string_view RHS((const char*)TC.rhs);
  324. path& Ref = (LHS += RHS);
  325. assert(LHS == (const char*)TC.expect);
  326. assert(&Ref == &LHS);
  327. }
  328. doConcatSourceTest<char> (TC);
  329. doConcatSourceTest<wchar_t> (TC);
  330. doConcatSourceTest<char16_t>(TC);
  331. doConcatSourceTest<char32_t>(TC);
  332. }
  333. for (auto const & TC : LongLHSCases) {
  334. // Do path test
  335. {
  336. path LHS((const char*)TC.lhs);
  337. path RHS((const char*)TC.rhs);
  338. const char* E = TC.expect;
  339. PathReserve(LHS, StrLen(E) + 5);
  340. {
  341. DisableAllocationGuard g;
  342. path& Ref = (LHS += RHS);
  343. assert(&Ref == &LHS);
  344. }
  345. assert(LHS == E);
  346. }
  347. {
  348. path LHS((const char*)TC.lhs);
  349. std::string_view RHS((const char*)TC.rhs);
  350. const char* E = TC.expect;
  351. PathReserve(LHS, StrLen(E) + 5);
  352. {
  353. DisableAllocationGuard g;
  354. path& Ref = (LHS += RHS);
  355. assert(&Ref == &LHS);
  356. }
  357. assert(LHS == E);
  358. }
  359. doConcatSourceAllocTest<char>(TC);
  360. doConcatSourceAllocTest<wchar_t>(TC);
  361. }
  362. for (auto const& TC : CharTestCases) {
  363. doConcatECharTest<char>(TC);
  364. doConcatECharTest<wchar_t>(TC);
  365. doConcatECharTest<char16_t>(TC);
  366. doConcatECharTest<char32_t>(TC);
  367. }
  368. test_sfinae();
  369. }