tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

container_memory_test.cc (9646B)


      1 // Copyright 2018 The Abseil Authors.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "absl/container/internal/container_memory.h"
     16 
     17 #include <cstddef>
     18 #include <cstdint>
     19 #include <memory>
     20 #include <tuple>
     21 #include <type_traits>
     22 #include <typeindex>
     23 #include <typeinfo>
     24 #include <utility>
     25 
     26 #include "gmock/gmock.h"
     27 #include "gtest/gtest.h"
     28 #include "absl/base/no_destructor.h"
     29 #include "absl/container/internal/test_instance_tracker.h"
     30 #include "absl/meta/type_traits.h"
     31 #include "absl/strings/string_view.h"
     32 
     33 namespace absl {
     34 ABSL_NAMESPACE_BEGIN
     35 namespace container_internal {
     36 namespace {
     37 
     38 using ::absl::test_internal::CopyableMovableInstance;
     39 using ::absl::test_internal::InstanceTracker;
     40 using ::testing::_;
     41 using ::testing::ElementsAre;
     42 using ::testing::Gt;
     43 using ::testing::Pair;
     44 
     45 TEST(Memory, AlignmentLargerThanBase) {
     46  std::allocator<int8_t> alloc;
     47  void* mem = Allocate<2>(&alloc, 3);
     48  EXPECT_EQ(0, reinterpret_cast<uintptr_t>(mem) % 2);
     49  memcpy(mem, "abc", 3);
     50  Deallocate<2>(&alloc, mem, 3);
     51 }
     52 
     53 TEST(Memory, AlignmentSmallerThanBase) {
     54  std::allocator<int64_t> alloc;
     55  void* mem = Allocate<2>(&alloc, 3);
     56  EXPECT_EQ(0, reinterpret_cast<uintptr_t>(mem) % 2);
     57  memcpy(mem, "abc", 3);
     58  Deallocate<2>(&alloc, mem, 3);
     59 }
     60 
     61 std::map<std::type_index, int>& AllocationMap() {
     62  static absl::NoDestructor<std::map<std::type_index, int>> map;
     63  return *map;
     64 }
     65 
     66 template <typename T>
     67 struct TypeCountingAllocator {
     68  TypeCountingAllocator() = default;
     69  template <typename U>
     70  TypeCountingAllocator(const TypeCountingAllocator<U>&) {}  // NOLINT
     71 
     72  using value_type = T;
     73 
     74  T* allocate(size_t n, const void* = nullptr) {
     75    AllocationMap()[typeid(T)] += n;
     76    return std::allocator<T>().allocate(n);
     77  }
     78  void deallocate(T* p, std::size_t n) {
     79    AllocationMap()[typeid(T)] -= n;
     80    return std::allocator<T>().deallocate(p, n);
     81  }
     82 };
     83 
     84 TEST(Memory, AllocateDeallocateMatchType) {
     85  TypeCountingAllocator<int> alloc;
     86  void* mem = Allocate<1>(&alloc, 1);
     87  // Verify that it was allocated
     88  EXPECT_THAT(AllocationMap(), ElementsAre(Pair(_, Gt(0))));
     89  Deallocate<1>(&alloc, mem, 1);
     90  // Verify that the deallocation matched.
     91  EXPECT_THAT(AllocationMap(), ElementsAre(Pair(_, 0)));
     92 }
     93 
     94 class Fixture : public ::testing::Test {
     95  using Alloc = std::allocator<std::string>;
     96 
     97 public:
     98  Fixture() { ptr_ = std::allocator_traits<Alloc>::allocate(*alloc(), 1); }
     99  ~Fixture() override {
    100    std::allocator_traits<Alloc>::destroy(*alloc(), ptr_);
    101    std::allocator_traits<Alloc>::deallocate(*alloc(), ptr_, 1);
    102  }
    103  std::string* ptr() { return ptr_; }
    104  Alloc* alloc() { return &alloc_; }
    105 
    106 private:
    107  Alloc alloc_;
    108  std::string* ptr_;
    109 };
    110 
    111 TEST_F(Fixture, ConstructNoArgs) {
    112  ConstructFromTuple(alloc(), ptr(), std::forward_as_tuple());
    113  EXPECT_EQ(*ptr(), "");
    114 }
    115 
    116 TEST_F(Fixture, ConstructOneArg) {
    117  ConstructFromTuple(alloc(), ptr(), std::forward_as_tuple("abcde"));
    118  EXPECT_EQ(*ptr(), "abcde");
    119 }
    120 
    121 TEST_F(Fixture, ConstructTwoArg) {
    122  ConstructFromTuple(alloc(), ptr(), std::forward_as_tuple(5, 'a'));
    123  EXPECT_EQ(*ptr(), "aaaaa");
    124 }
    125 
    126 TEST(PairArgs, NoArgs) {
    127  EXPECT_THAT(PairArgs(),
    128              Pair(std::forward_as_tuple(), std::forward_as_tuple()));
    129 }
    130 
    131 TEST(PairArgs, TwoArgs) {
    132  EXPECT_EQ(
    133      std::make_pair(std::forward_as_tuple(1), std::forward_as_tuple('A')),
    134      PairArgs(1, 'A'));
    135 }
    136 
    137 TEST(PairArgs, Pair) {
    138  EXPECT_EQ(
    139      std::make_pair(std::forward_as_tuple(1), std::forward_as_tuple('A')),
    140      PairArgs(std::make_pair(1, 'A')));
    141 }
    142 
    143 TEST(PairArgs, Piecewise) {
    144  EXPECT_EQ(
    145      std::make_pair(std::forward_as_tuple(1), std::forward_as_tuple('A')),
    146      PairArgs(std::piecewise_construct, std::forward_as_tuple(1),
    147               std::forward_as_tuple('A')));
    148 }
    149 
    150 TEST(WithConstructed, Simple) {
    151  EXPECT_EQ(1, WithConstructed<absl::string_view>(
    152                   std::make_tuple(std::string("a")),
    153                   [](absl::string_view str) { return str.size(); }));
    154 }
    155 
    156 template <class F, class Arg>
    157 decltype(DecomposeValue(std::declval<F>(), std::declval<Arg>()))
    158 DecomposeValueImpl(int, F&& f, Arg&& arg) {
    159  return DecomposeValue(std::forward<F>(f), std::forward<Arg>(arg));
    160 }
    161 
    162 template <class F, class Arg>
    163 const char* DecomposeValueImpl(char, F&& f, Arg&& arg) {
    164  return "not decomposable";
    165 }
    166 
    167 template <class F, class Arg>
    168 decltype(DecomposeValueImpl(0, std::declval<F>(), std::declval<Arg>()))
    169 TryDecomposeValue(F&& f, Arg&& arg) {
    170  return DecomposeValueImpl(0, std::forward<F>(f), std::forward<Arg>(arg));
    171 }
    172 
    173 TEST(DecomposeValue, Decomposable) {
    174  auto f = [](const int& x, int&& y) {  // NOLINT
    175    EXPECT_EQ(&x, &y);
    176    EXPECT_EQ(42, x);
    177    return 'A';
    178  };
    179  EXPECT_EQ('A', TryDecomposeValue(f, 42));
    180 }
    181 
    182 TEST(DecomposeValue, NotDecomposable) {
    183  auto f = [](void*) {
    184    ADD_FAILURE() << "Must not be called";
    185    return 'A';
    186  };
    187  EXPECT_STREQ("not decomposable", TryDecomposeValue(f, 42));
    188 }
    189 
    190 template <class F, class... Args>
    191 decltype(DecomposePair(std::declval<F>(), std::declval<Args>()...))
    192 DecomposePairImpl(int, F&& f, Args&&... args) {
    193  return DecomposePair(std::forward<F>(f), std::forward<Args>(args)...);
    194 }
    195 
    196 template <class F, class... Args>
    197 const char* DecomposePairImpl(char, F&& f, Args&&... args) {
    198  return "not decomposable";
    199 }
    200 
    201 template <class F, class... Args>
    202 decltype(DecomposePairImpl(0, std::declval<F>(), std::declval<Args>()...))
    203 TryDecomposePair(F&& f, Args&&... args) {
    204  return DecomposePairImpl(0, std::forward<F>(f), std::forward<Args>(args)...);
    205 }
    206 
    207 TEST(DecomposePair, Decomposable) {
    208  auto f = [](const int& x,  // NOLINT
    209              std::piecewise_construct_t, std::tuple<int&&> k,
    210              std::tuple<double>&& v) {
    211    EXPECT_EQ(&x, &std::get<0>(k));
    212    EXPECT_EQ(42, x);
    213    EXPECT_EQ(0.5, std::get<0>(v));
    214    return 'A';
    215  };
    216  EXPECT_EQ('A', TryDecomposePair(f, 42, 0.5));
    217  EXPECT_EQ('A', TryDecomposePair(f, std::make_pair(42, 0.5)));
    218  EXPECT_EQ('A', TryDecomposePair(f, std::piecewise_construct,
    219                                  std::make_tuple(42), std::make_tuple(0.5)));
    220 }
    221 
    222 TEST(DecomposePair, NotDecomposable) {
    223  auto f = [](...) {
    224    ADD_FAILURE() << "Must not be called";
    225    return 'A';
    226  };
    227  EXPECT_STREQ("not decomposable", TryDecomposePair(f));
    228  EXPECT_STREQ("not decomposable",
    229               TryDecomposePair(f, std::piecewise_construct, std::make_tuple(),
    230                                std::make_tuple(0.5)));
    231 }
    232 
    233 TEST(MapSlotPolicy, ConstKeyAndValue) {
    234  using slot_policy = map_slot_policy<const CopyableMovableInstance,
    235                                      const CopyableMovableInstance>;
    236  using slot_type = typename slot_policy::slot_type;
    237 
    238  union Slots {
    239    Slots() {}
    240    ~Slots() {}
    241    slot_type slots[100];
    242  } slots;
    243 
    244  std::allocator<
    245      std::pair<const CopyableMovableInstance, const CopyableMovableInstance>>
    246      alloc;
    247  InstanceTracker tracker;
    248  slot_policy::construct(&alloc, &slots.slots[0], CopyableMovableInstance(1),
    249                         CopyableMovableInstance(1));
    250  for (int i = 0; i < 99; ++i) {
    251    slot_policy::transfer(&alloc, &slots.slots[i + 1], &slots.slots[i]);
    252  }
    253  slot_policy::destroy(&alloc, &slots.slots[99]);
    254 
    255  EXPECT_EQ(tracker.copies(), 0);
    256 }
    257 
    258 TEST(MapSlotPolicy, TransferReturnsTrue) {
    259  {
    260    using slot_policy = map_slot_policy<int, float>;
    261    EXPECT_TRUE(
    262        (std::is_same<decltype(slot_policy::transfer<std::allocator<char>>(
    263                          nullptr, nullptr, nullptr)),
    264                      std::true_type>::value));
    265  }
    266  {
    267    struct NonRelocatable {
    268      NonRelocatable() = default;
    269      NonRelocatable(NonRelocatable&&) {}
    270      NonRelocatable& operator=(NonRelocatable&&) { return *this; }
    271      void* self = nullptr;
    272    };
    273 
    274    EXPECT_FALSE(absl::is_trivially_relocatable<NonRelocatable>::value);
    275    using slot_policy = map_slot_policy<int, NonRelocatable>;
    276    EXPECT_TRUE(
    277        (std::is_same<decltype(slot_policy::transfer<std::allocator<char>>(
    278                          nullptr, nullptr, nullptr)),
    279                      std::false_type>::value));
    280  }
    281 }
    282 
    283 TEST(MapSlotPolicy, DestroyReturnsTrue) {
    284  {
    285    using slot_policy = map_slot_policy<int, float>;
    286    EXPECT_TRUE(
    287        (std::is_same<decltype(slot_policy::destroy<std::allocator<char>>(
    288                          nullptr, nullptr)),
    289                      std::true_type>::value));
    290  }
    291  {
    292    EXPECT_FALSE(std::is_trivially_destructible<std::unique_ptr<int>>::value);
    293    using slot_policy = map_slot_policy<int, std::unique_ptr<int>>;
    294    EXPECT_TRUE(
    295        (std::is_same<decltype(slot_policy::destroy<std::allocator<char>>(
    296                          nullptr, nullptr)),
    297                      std::false_type>::value));
    298  }
    299 }
    300 
    301 TEST(ApplyTest, TypeErasedApplyToSlotFn) {
    302  size_t x = 7;
    303  auto fn = [](size_t v) { return v * 2; };
    304  EXPECT_EQ((TypeErasedApplyToSlotFn<decltype(fn), size_t>(&fn, &x)), 14);
    305 }
    306 
    307 TEST(ApplyTest, TypeErasedDerefAndApplyToSlotFn) {
    308  size_t x = 7;
    309  auto fn = [](size_t v) { return v * 2; };
    310  size_t* x_ptr = &x;
    311  EXPECT_EQ(
    312      (TypeErasedDerefAndApplyToSlotFn<decltype(fn), size_t>(&fn, &x_ptr)), 14);
    313 }
    314 
    315 }  // namespace
    316 }  // namespace container_internal
    317 ABSL_NAMESPACE_END
    318 }  // namespace absl