brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.2 KiB · d4a3273 Raw
419 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// UNSUPPORTED: c++03, c++11, c++1410 11// These tests require locale for non-char paths12// UNSUPPORTED: no-localization13 14// In MinGW mode, with optimizations enabled with a DLL, the number of counted15// allocations mismatches, as some ctor/dtor calls are generated in the16// calling code, and some are called from the DLL.17// ADDITIONAL_COMPILE_FLAGS: -DALLOW_MISMATCHING_LIBRRARY_INTERNAL_ALLOCATIONS18 19// <filesystem>20 21// class path22 23// path& operator+=(const path& x);24// path& operator+=(const string_type& x);25// path& operator+=(string_view x);26// path& operator+=(const value_type* x);27// path& operator+=(value_type x);28// template <class Source>29//   path& operator+=(const Source& x);30// template <class EcharT>31//   path& operator+=(EcharT x);32// template <class Source>33//   path& concat(const Source& x);34// template <class InputIterator>35//   path& concat(InputIterator first, InputIterator last);36 37#include <filesystem>38#include <type_traits>39#include <string>40#include <string_view>41#include <cassert>42#include <utility>43 44// On Windows, charset conversions cause allocations in the path class in45// cases where no allocations are done on other platforms.46 47#include "../path_helper.h"48#include "count_new.h"49#include "make_string.h"50#include "test_iterators.h"51#include "test_macros.h"52namespace fs = std::filesystem;53 54struct ConcatOperatorTestcase {55  MultiStringType lhs;56  MultiStringType rhs;57  MultiStringType expect;58};59 60#define LONGSTR "LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR_LONGSTR"61#define S(Str) MKSTR(Str)62const ConcatOperatorTestcase Cases[] =63    {64        {S(""),         S(""),                  S("")}65      , {S("p1"),       S("p2"),                S("p1p2")}66      , {S("p1/"),      S("/p2"),               S("p1//p2")}67      , {S(""),         S("\\foo/bar/baz"),     S("\\foo/bar/baz")}68      , {S("c:\\foo"),  S(""),                  S("c:\\foo")}69      , {S(LONGSTR),    S("foo"),               S(LONGSTR "foo")}70      , {S("abcdefghijklmnopqrstuvwxyz/\\"), S("/\\123456789"), S("abcdefghijklmnopqrstuvwxyz/\\/\\123456789")}71    };72const ConcatOperatorTestcase LongLHSCases[] =73    {74        {S(""),        S(LONGSTR),     S(LONGSTR)}75      , {S("p1/"),     S(LONGSTR),      S("p1/" LONGSTR)}76    };77const ConcatOperatorTestcase CharTestCases[] =78    {79        {S(""),       S("P"), S("P")}80      , {S("/fooba"), S("r"), S("/foobar")}81    };82#undef S83#undef LONGSTR84 85// The concat operator may need to allocate a temporary buffer before a code_cvt86// conversion. Test if this allocation occurs by:87//   1. Create a path, `LHS`, and reserve enough space to append `RHS`.88//      This prevents `LHS` from allocating during the actual appending.89//   2. Create a `Source` object `RHS`, which represents a "large" string.90//      (The string must not trigger the SSO)91//   3. Concat `RHS` to `LHS` and check for the expected allocation behavior.92template <class CharT>93void doConcatSourceAllocTest(ConcatOperatorTestcase const& TC)94{95  using namespace fs;96  using Ptr = CharT const*;97  using Str = std::basic_string<CharT>;98  using StrView = std::basic_string_view<CharT>;99  using InputIter = cpp17_input_iterator<Ptr>;100 101  const Ptr L = TC.lhs;102  const Ptr R = TC.rhs;103  const Ptr E =  TC.expect;104  std::size_t ReserveSize = StrLen(E) + 1;105  // basic_string106  {107    path LHS(L); PathReserve(LHS, ReserveSize);108    Str  RHS(R);109    {110      TEST_NOT_WIN32(DisableAllocationGuard g);111      LHS += RHS;112    }113    assert(LHS == E);114  }115  // basic_string_view116  {117    path LHS(L); PathReserve(LHS, ReserveSize);118    StrView  RHS(R);119    {120      TEST_NOT_WIN32(DisableAllocationGuard g);121      LHS += RHS;122    }123    assert(LHS == E);124  }125  // CharT*126  {127    path LHS(L); PathReserve(LHS, ReserveSize);128    Ptr RHS(R);129    {130      TEST_NOT_WIN32(DisableAllocationGuard g);131      LHS += RHS;132    }133    assert(LHS == E);134  }135  {136    path LHS(L); PathReserve(LHS, ReserveSize);137    Ptr RHS(R);138    {139      TEST_NOT_WIN32(DisableAllocationGuard g);140      LHS.concat(RHS, StrEnd(RHS));141    }142    assert(LHS == E);143  }144  // input iterator - For non-native char types, appends needs to copy the145  // iterator range into a contiguous block of memory before it can perform the146  // code_cvt conversions.147  // For the path native type, no allocations will be performed because no148  // conversion is required.149 150#if TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS151  // Only check allocations if we can pick up allocations done within the152  // library implementation.153  bool ExpectNoAllocations = std::is_same<CharT, path::value_type>::value;154#endif155  {156    path LHS(L); PathReserve(LHS, ReserveSize);157    InputIter RHS(R);158    {159      RequireAllocationGuard g(0); // require "at least zero" allocations by default160#if TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS161      if (ExpectNoAllocations)162        g.requireExactly(0);163#endif164      LHS += RHS;165    }166    assert(LHS == E);167  }168  {169    path LHS(L); PathReserve(LHS, ReserveSize);170    InputIter RHS(R);171    InputIter REnd(StrEnd(R));172    {173      RequireAllocationGuard g(0); // require "at least zero" allocations by default174#if TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS175      if (ExpectNoAllocations)176        g.requireExactly(0);177#endif178      LHS.concat(RHS, REnd);179    }180    assert(LHS == E);181  }182}183 184template <class CharT>185void doConcatSourceTest(ConcatOperatorTestcase const& TC)186{187  using namespace fs;188  using Ptr = CharT const*;189  using Str = std::basic_string<CharT>;190  using StrView = std::basic_string_view<CharT>;191  using InputIter = cpp17_input_iterator<Ptr>;192  const Ptr L = TC.lhs;193  const Ptr R = TC.rhs;194  const Ptr E = TC.expect;195  // basic_string196  {197    path LHS(L);198    Str RHS(R);199    path& Ref = (LHS += RHS);200    assert(LHS == E);201    assert(&Ref == &LHS);202  }203  {204    path LHS(L);205    Str RHS(R);206    path& Ref = LHS.concat(RHS);207    assert(LHS == E);208    assert(&Ref == &LHS);209  }210  // basic_string_view211  {212    path LHS(L);213    StrView RHS(R);214    path& Ref = (LHS += RHS);215    assert(LHS == E);216    assert(&Ref == &LHS);217  }218  {219    path LHS(L);220    StrView RHS(R);221    path& Ref = LHS.concat(RHS);222    assert(LHS == E);223    assert(&Ref == &LHS);224  }225  // Char*226  {227    path LHS(L);228    Str RHS(R);229    path& Ref = (LHS += RHS);230    assert(LHS == E);231    assert(&Ref == &LHS);232  }233  {234    path LHS(L);235    Ptr RHS(R);236    path& Ref = LHS.concat(RHS);237    assert(LHS == E);238    assert(&Ref == &LHS);239  }240  {241    path LHS(L);242    Ptr RHS(R);243    path& Ref = LHS.concat(RHS, StrEnd(RHS));244    assert(LHS == E);245    assert(&Ref == &LHS);246  }247  // iterators248  {249    path LHS(L);250    InputIter RHS(R);251    path& Ref = (LHS += RHS);252    assert(LHS == E);253    assert(&Ref == &LHS);254  }255  {256    path LHS(L); InputIter RHS(R);257    path& Ref = LHS.concat(RHS);258    assert(LHS == E);259    assert(&Ref == &LHS);260  }261  {262    path LHS(L);263    InputIter RHS(R);264    InputIter REnd(StrEnd(R));265    path& Ref = LHS.concat(RHS, REnd);266    assert(LHS == E);267    assert(&Ref == &LHS);268  }269}270 271template <class CharT>272void doConcatECharTest(ConcatOperatorTestcase const& TC)273{274  using namespace fs;275  using Ptr = CharT const*;276  const Ptr RStr = TC.rhs;277  assert(StrLen(RStr) == 1);278  const Ptr L   = TC.lhs;279  const CharT R = RStr[0];280  const Ptr E   = TC.expect;281  {282    path LHS(L);283    path& Ref = (LHS += R);284    assert(LHS == E);285    assert(&Ref == &LHS);286  }287}288 289 290template <class It, class = decltype(fs::path{}.concat(std::declval<It>()))>291constexpr bool has_concat(int) { return true; }292template <class It>293constexpr bool has_concat(long) { return false; }294 295template <class It, class = decltype(fs::path{}.operator+=(std::declval<It>()))>296constexpr bool has_concat_op(int) { return true; }297template <class It>298constexpr bool has_concat_op(long) { return false; }299template <class It>300constexpr bool has_concat_op() { return has_concat_op<It>(0); }301 302template <class It>303constexpr bool has_concat() {304  static_assert(has_concat<It>(0) == has_concat_op<It>(0), "must be same");305  return has_concat<It>(0) && has_concat_op<It>(0);306}307 308void test_sfinae() {309  using namespace fs;310  {311    static_assert(has_concat_op<char>(), "");312    static_assert(has_concat_op<const char>(), "");313    static_assert(has_concat_op<char16_t>(), "");314    static_assert(has_concat_op<const char16_t>(), "");315  }316  {317    using It = const char* const;318    static_assert(has_concat<It>(), "");319  }320  {321    using It = cpp17_input_iterator<const char*>;322    static_assert(has_concat<It>(), "");323  }324  {325    struct Traits {326      using iterator_category = std::input_iterator_tag;327      using value_type = const char;328      using pointer = const char*;329      using reference = const char&;330      using difference_type = std::ptrdiff_t;331    };332    using It = cpp17_input_iterator<const char*, Traits>;333    static_assert(has_concat<It>(), "");334  }335  {336    using It = cpp17_output_iterator<const char*>;337    static_assert(!has_concat<It>(), "");338  }339  {340    static_assert(!has_concat<int>(0), "");341    // operator+=(int) is well formed since it converts to operator+=(value_type)342    // but concat(int) isn't valid because there is no concat(value_type).343    // This should probably be addressed by a LWG issue.344    static_assert(has_concat_op<int>(), "");345  }346  {347    static_assert(!has_concat<int*>(), "");348  }349}350 351int main(int, char**)352{353  using namespace fs;354  for (auto const & TC : Cases) {355    {356      path LHS((const char*)TC.lhs);357      path RHS((const char*)TC.rhs);358      path& Ref = (LHS += RHS);359      assert(LHS == (const char*)TC.expect);360      assert(&Ref == &LHS);361    }362    {363      path LHS((const char*)TC.lhs);364      std::basic_string_view<path::value_type> RHS((const path::value_type*)TC.rhs);365      path& Ref = (LHS += RHS);366      assert(LHS == (const char*)TC.expect);367      assert(&Ref == &LHS);368    }369    doConcatSourceTest<char>    (TC);370#ifndef TEST_HAS_NO_WIDE_CHARACTERS371    doConcatSourceTest<wchar_t> (TC);372#endif373    doConcatSourceTest<char16_t>(TC);374    doConcatSourceTest<char32_t>(TC);375  }376  for (auto const & TC : LongLHSCases) {377    // Do path test378    {379      path LHS((const char*)TC.lhs);380      path RHS((const char*)TC.rhs);381      const char* E = TC.expect;382      PathReserve(LHS, StrLen(E) + 5);383      {384        LIBCPP_ONLY(DisableAllocationGuard g);385        path& Ref = (LHS += RHS);386        assert(&Ref == &LHS);387      }388      assert(LHS == E);389    }390    {391      path LHS((const char*)TC.lhs);392      std::basic_string_view<path::value_type> RHS((const path::value_type*)TC.rhs);393      const char* E = TC.expect;394      PathReserve(LHS, StrLen(E) + 5);395      {396        LIBCPP_ONLY(DisableAllocationGuard g);397        path& Ref = (LHS += RHS);398        assert(&Ref == &LHS);399      }400      assert(LHS == E);401    }402    LIBCPP_ONLY(doConcatSourceAllocTest<char>(TC));403#ifndef TEST_HAS_NO_WIDE_CHARACTERS404    LIBCPP_ONLY(doConcatSourceAllocTest<wchar_t>(TC));405#endif406  }407  for (auto const& TC : CharTestCases) {408    doConcatECharTest<char>(TC);409#ifndef TEST_HAS_NO_WIDE_CHARACTERS410    doConcatECharTest<wchar_t>(TC);411#endif412    doConcatECharTest<char16_t>(TC);413    doConcatECharTest<char32_t>(TC);414  }415  test_sfinae();416 417  return 0;418}419