123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- //===----------------------------------------------------------------------===//
- //
- // The LLVM Compiler Infrastructure
- //
- // This file is dual licensed under the MIT and the University of Illinois Open
- // Source Licenses. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- // UNSUPPORTED: c++98, c++03
- // <experimental/filesystem>
- // class path
- // path& operator/=(path const&)
- // template <class Source>
- // path& operator/=(Source const&);
- // template <class Source>
- // path& append(Source const&);
- // template <class InputIterator>
- // path& append(InputIterator first, InputIterator last);
- #include <experimental/filesystem>
- #include <type_traits>
- #include <string_view>
- #include <cassert>
- #include "test_macros.h"
- #include "test_iterators.h"
- #include "count_new.hpp"
- #include "filesystem_test_helper.hpp"
- namespace fs = std::experimental::filesystem;
- struct AppendOperatorTestcase {
- MultiStringType lhs;
- MultiStringType rhs;
- MultiStringType expect;
- };
- #define S(Str) MKSTR(Str)
- const AppendOperatorTestcase Cases[] =
- {
- {S(""), S(""), S("")}
- , {S("p1"), S("p2"), S("p1/p2")}
- , {S("p1/"), S("p2"), S("p1/p2")}
- , {S("p1"), S("/p2"), S("p1/p2")}
- , {S("p1/"), S("/p2"), S("p1//p2")}
- , {S("p1"), S("\\p2"), S("p1/\\p2")}
- , {S("p1\\"), S("p2"), S("p1\\/p2")}
- , {S("p1\\"), S("\\p2"), S("p1\\/\\p2")}
- , {S("p1"), S(""), S("p1")}
- , {S(""), S("p2"), S("p2")}
- };
- const AppendOperatorTestcase LongLHSCases[] =
- {
- {S("p1"), S("p2"), S("p1/p2")}
- , {S("p1/"), S("p2"), S("p1/p2")}
- , {S("p1"), S("/p2"), S("p1/p2")}
- };
- #undef S
- // The append operator may need to allocate a temporary buffer before a code_cvt
- // conversion. Test if this allocation occurs by:
- // 1. Create a path, `LHS`, and reserve enough space to append `RHS`.
- // This prevents `LHS` from allocating during the actual appending.
- // 2. Create a `Source` object `RHS`, which represents a "large" string.
- // (The string must not trigger the SSO)
- // 3. Append `RHS` to `LHS` and check for the expected allocation behavior.
- template <class CharT>
- void doAppendSourceAllocTest(AppendOperatorTestcase const& TC)
- {
- using namespace fs;
- using Ptr = CharT const*;
- using Str = std::basic_string<CharT>;
- using StrView = std::basic_string_view<CharT>;
- using InputIter = input_iterator<Ptr>;
- const Ptr L = TC.lhs;
- Str RShort = (Ptr)TC.rhs;
- Str EShort = (Ptr)TC.expect;
- assert(RShort.size() >= 2);
- CharT c = RShort.back();
- RShort.append(100, c);
- EShort.append(100, c);
- const Ptr R = RShort.data();
- const Str& E = EShort;
- std::size_t ReserveSize = E.size() + 3;
- // basic_string
- {
- path LHS(L); PathReserve(LHS, ReserveSize);
- Str RHS(R);
- {
- DisableAllocationGuard g;
- LHS /= RHS;
- }
- assert(LHS == E);
- }
- // basic_string_view
- {
- path LHS(L); PathReserve(LHS, ReserveSize);
- StrView RHS(R);
- {
- DisableAllocationGuard g;
- LHS /= RHS;
- }
- assert(LHS == E);
- }
- // CharT*
- {
- path LHS(L); PathReserve(LHS, ReserveSize);
- Ptr RHS(R);
- {
- DisableAllocationGuard g;
- LHS /= RHS;
- }
- assert(LHS == E);
- }
- {
- path LHS(L); PathReserve(LHS, ReserveSize);
- Ptr RHS(R);
- {
- DisableAllocationGuard g;
- LHS.append(RHS, StrEnd(RHS));
- }
- assert(LHS == E);
- }
- // input iterator - For non-native char types, appends needs to copy the
- // iterator range into a contiguous block of memory before it can perform the
- // code_cvt conversions.
- // For "char" no allocations will be performed because no conversion is
- // required.
- bool DisableAllocations = std::is_same<CharT, char>::value;
- {
- path LHS(L); PathReserve(LHS, ReserveSize);
- InputIter RHS(R);
- {
- RequireAllocationGuard g; // requires 1 or more allocations occur by default
- if (DisableAllocations) g.requireExactly(0);
- LHS /= RHS;
- }
- assert(LHS == E);
- }
- {
- path LHS(L); PathReserve(LHS, ReserveSize);
- InputIter RHS(R);
- InputIter REnd(StrEnd(R));
- {
- RequireAllocationGuard g;
- if (DisableAllocations) g.requireExactly(0);
- LHS.append(RHS, REnd);
- }
- assert(LHS == E);
- }
- }
- template <class CharT>
- void doAppendSourceTest(AppendOperatorTestcase const& TC)
- {
- using namespace fs;
- using Ptr = CharT const*;
- using Str = std::basic_string<CharT>;
- using StrView = std::basic_string_view<CharT>;
- using InputIter = input_iterator<Ptr>;
- const Ptr L = TC.lhs;
- const Ptr R = TC.rhs;
- const Ptr E = TC.expect;
- // basic_string
- {
- path LHS(L);
- Str RHS(R);
- path& Ref = (LHS /= RHS);
- assert(LHS == E);
- assert(&Ref == &LHS);
- }
- {
- path LHS(L);
- Str RHS(R);
- path& Ref = LHS.append(RHS);
- assert(LHS == E);
- assert(&Ref == &LHS);
- }
- // basic_string_view
- {
- path LHS(L);
- StrView RHS(R);
- path& Ref = (LHS /= RHS);
- assert(LHS == E);
- assert(&Ref == &LHS);
- }
- {
- path LHS(L);
- StrView RHS(R);
- path& Ref = LHS.append(RHS);
- assert(LHS == E);
- assert(&Ref == &LHS);
- }
- // Char*
- {
- path LHS(L);
- Str RHS(R);
- path& Ref = (LHS /= RHS);
- assert(LHS == E);
- assert(&Ref == &LHS);
- }
- {
- path LHS(L);
- Ptr RHS(R);
- path& Ref = LHS.append(RHS);
- assert(LHS == E);
- assert(&Ref == &LHS);
- }
- {
- path LHS(L);
- Ptr RHS(R);
- path& Ref = LHS.append(RHS, StrEnd(RHS));
- assert(LHS == E);
- assert(&Ref == &LHS);
- }
- // iterators
- {
- path LHS(L);
- InputIter RHS(R);
- path& Ref = (LHS /= RHS);
- assert(LHS == E);
- assert(&Ref == &LHS);
- }
- {
- path LHS(L); InputIter RHS(R);
- path& Ref = LHS.append(RHS);
- assert(LHS == E);
- assert(&Ref == &LHS);
- }
- {
- path LHS(L);
- InputIter RHS(R);
- InputIter REnd(StrEnd(R));
- path& Ref = LHS.append(RHS, REnd);
- assert(LHS == E);
- assert(&Ref == &LHS);
- }
- }
- template <class It, class = decltype(fs::path{}.append(std::declval<It>()))>
- constexpr bool has_append(int) { return true; }
- template <class It>
- constexpr bool has_append(long) { return false; }
- template <class It, class = decltype(fs::path{}.operator/=(std::declval<It>()))>
- constexpr bool has_append_op(int) { return true; }
- template <class It>
- constexpr bool has_append_op(long) { return false; }
- template <class It>
- constexpr bool has_append() {
- static_assert(has_append<It>(0) == has_append_op<It>(0), "must be same");
- return has_append<It>(0) && has_append_op<It>(0);
- }
- void test_sfinae()
- {
- using namespace fs;
- {
- using It = const char* const;
- static_assert(has_append<It>(), "");
- }
- {
- using It = input_iterator<const char*>;
- static_assert(has_append<It>(), "");
- }
- {
- struct Traits {
- using iterator_category = std::input_iterator_tag;
- using value_type = const char;
- using pointer = const char*;
- using reference = const char&;
- using difference_type = std::ptrdiff_t;
- };
- using It = input_iterator<const char*, Traits>;
- static_assert(has_append<It>(), "");
- }
- {
- using It = output_iterator<const char*>;
- static_assert(!has_append<It>(), "");
- }
- {
- static_assert(!has_append<int*>(), "");
- }
- {
- static_assert(!has_append<char>(), "");
- static_assert(!has_append<const char>(), "");
- }
- }
- int main()
- {
- using namespace fs;
- for (auto const & TC : Cases) {
- {
- path LHS((const char*)TC.lhs);
- path RHS((const char*)TC.rhs);
- path& Ref = (LHS /= RHS);
- assert(LHS == (const char*)TC.expect);
- assert(&Ref == &LHS);
- }
- doAppendSourceTest<char> (TC);
- doAppendSourceTest<wchar_t> (TC);
- doAppendSourceTest<char16_t>(TC);
- doAppendSourceTest<char32_t>(TC);
- }
- for (auto const & TC : LongLHSCases) {
- doAppendSourceAllocTest<char>(TC);
- doAppendSourceAllocTest<wchar_t>(TC);
- }
- test_sfinae();
- }
|