libcxx

libcxx mirror with random patches
git clone https://git.neptards.moe/neptards/libcxx.git
Log | Files | Refs

path.append.pass.cpp (8731B)


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