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 "parallel_hashmap/phmap.h"
16 
17 #include <cstdint>
18 #include <tuple>
19 #include <utility>
20 
21 #if PHMAP_HAVE_STD_STRING_VIEW
22     #include <string_view>
23 #endif
24 
25 #include "gmock/gmock.h"
26 #include "gtest/gtest.h"
27 
28 namespace phmap {
29 namespace priv {
30 namespace {
31 
32 using ::testing::Pair;
33 
TEST(Memory,AlignmentLargerThanBase)34 TEST(Memory, AlignmentLargerThanBase) {
35   std::allocator<int8_t> alloc;
36   void* mem = Allocate<2>(&alloc, 3);
37   EXPECT_EQ(0, reinterpret_cast<uintptr_t>(mem) % 2);
38   memcpy(mem, "abc", 3);
39   Deallocate<2>(&alloc, mem, 3);
40 }
41 
TEST(Memory,AlignmentSmallerThanBase)42 TEST(Memory, AlignmentSmallerThanBase) {
43   std::allocator<int64_t> alloc;
44   void* mem = Allocate<2>(&alloc, 3);
45   EXPECT_EQ(0, reinterpret_cast<uintptr_t>(mem) % 2);
46   memcpy(mem, "abc", 3);
47   Deallocate<2>(&alloc, mem, 3);
48 }
49 
50 class Fixture : public ::testing::Test {
51   using Alloc = std::allocator<std::string>;
52 
53  public:
Fixture()54   Fixture() { ptr_ = std::allocator_traits<Alloc>::allocate(*alloc(), 1); }
~Fixture()55   ~Fixture() override {
56     std::allocator_traits<Alloc>::destroy(*alloc(), ptr_);
57     std::allocator_traits<Alloc>::deallocate(*alloc(), ptr_, 1);
58   }
ptr()59   std::string* ptr() { return ptr_; }
alloc()60   Alloc* alloc() { return &alloc_; }
61 
62  private:
63   Alloc alloc_;
64   std::string* ptr_;
65 };
66 
TEST_F(Fixture,ConstructNoArgs)67 TEST_F(Fixture, ConstructNoArgs) {
68   ConstructFromTuple(alloc(), ptr(), std::forward_as_tuple());
69   EXPECT_EQ(*ptr(), "");
70 }
71 
TEST_F(Fixture,ConstructOneArg)72 TEST_F(Fixture, ConstructOneArg) {
73   ConstructFromTuple(alloc(), ptr(), std::forward_as_tuple("abcde"));
74   EXPECT_EQ(*ptr(), "abcde");
75 }
76 
TEST_F(Fixture,ConstructTwoArg)77 TEST_F(Fixture, ConstructTwoArg) {
78   ConstructFromTuple(alloc(), ptr(), std::forward_as_tuple(5, 'a'));
79   EXPECT_EQ(*ptr(), "aaaaa");
80 }
81 
TEST(PairArgs,NoArgs)82 TEST(PairArgs, NoArgs) {
83   EXPECT_THAT(PairArgs(),
84               Pair(std::forward_as_tuple(), std::forward_as_tuple()));
85 }
86 
TEST(PairArgs,TwoArgs)87 TEST(PairArgs, TwoArgs) {
88   EXPECT_EQ(
89       std::make_pair(std::forward_as_tuple(1), std::forward_as_tuple('A')),
90       PairArgs(1, 'A'));
91 }
92 
TEST(PairArgs,Pair)93 TEST(PairArgs, Pair) {
94   EXPECT_EQ(
95       std::make_pair(std::forward_as_tuple(1), std::forward_as_tuple('A')),
96       PairArgs(std::make_pair(1, 'A')));
97 }
98 
TEST(PairArgs,Piecewise)99 TEST(PairArgs, Piecewise) {
100   EXPECT_EQ(
101       std::make_pair(std::forward_as_tuple(1), std::forward_as_tuple('A')),
102       PairArgs(std::piecewise_construct, std::forward_as_tuple(1),
103                std::forward_as_tuple('A')));
104 }
105 
106 #if PHMAP_HAVE_STD_STRING_VIEW
TEST(WithConstructed,Simple)107 TEST(WithConstructed, Simple) {
108   EXPECT_EQ(1, WithConstructed<std::string_view>(
109                    std::make_tuple(std::string("a")),
110                    [](std::string_view str) { return str.size(); }));
111 }
112 #endif
113 
114 template <class F, class Arg>
DecomposeValue(std::declval<F> (),std::declval<Arg> ())115 decltype(DecomposeValue(std::declval<F>(), std::declval<Arg>()))
116 DecomposeValueImpl(int, F&& f, Arg&& arg) {
117   return DecomposeValue(std::forward<F>(f), std::forward<Arg>(arg));
118 }
119 
120 template <class F, class Arg>
DecomposeValueImpl(char,F &&,Arg &&)121 const char* DecomposeValueImpl(char, F&& , Arg&& ) {
122   return "not decomposable";
123 }
124 
125 template <class F, class Arg>
126 decltype(DecomposeValueImpl(0, std::declval<F>(), std::declval<Arg>()))
TryDecomposeValue(F && f,Arg && arg)127 TryDecomposeValue(F&& f, Arg&& arg) {
128   return DecomposeValueImpl(0, std::forward<F>(f), std::forward<Arg>(arg));
129 }
130 
TEST(DecomposeValue,Decomposable)131 TEST(DecomposeValue, Decomposable) {
132   auto f = [](const int& x, int&& y) {
133     EXPECT_EQ(&x, &y);
134     EXPECT_EQ(42, x);
135     return 'A';
136   };
137   EXPECT_EQ('A', TryDecomposeValue(f, 42));
138 }
139 
TEST(DecomposeValue,NotDecomposable)140 TEST(DecomposeValue, NotDecomposable) {
141   auto f = [](void*) {
142     ADD_FAILURE() << "Must not be called";
143     return 'A';
144   };
145   EXPECT_STREQ("not decomposable", TryDecomposeValue(f, 42));
146 }
147 
148 template <class F, class... Args>
DecomposePair(std::declval<F> (),std::declval<Args> ()...)149 decltype(DecomposePair(std::declval<F>(), std::declval<Args>()...))
150 DecomposePairImpl(int, F&& f, Args&&... args) {
151   return DecomposePair(std::forward<F>(f), std::forward<Args>(args)...);
152 }
153 
154 template <class F, class... Args>
DecomposePairImpl(char,F &&,Args &&...)155 const char* DecomposePairImpl(char, F&& , Args&&... ) {
156   return "not decomposable";
157 }
158 
159 template <class F, class... Args>
160 decltype(DecomposePairImpl(0, std::declval<F>(), std::declval<Args>()...))
TryDecomposePair(F && f,Args &&...args)161 TryDecomposePair(F&& f, Args&&... args) {
162   return DecomposePairImpl(0, std::forward<F>(f), std::forward<Args>(args)...);
163 }
164 
TEST(DecomposePair,Decomposable)165 TEST(DecomposePair, Decomposable) {
166   auto f = [](const int& x, std::piecewise_construct_t, std::tuple<int&&> k,
167               std::tuple<double>&& v) {
168     EXPECT_EQ(&x, &std::get<0>(k));
169     EXPECT_EQ(42, x);
170     EXPECT_EQ(0.5, std::get<0>(v));
171     return 'A';
172   };
173   EXPECT_EQ('A', TryDecomposePair(f, 42, 0.5));
174   EXPECT_EQ('A', TryDecomposePair(f, std::make_pair(42, 0.5)));
175   EXPECT_EQ('A', TryDecomposePair(f, std::piecewise_construct,
176                                   std::make_tuple(42), std::make_tuple(0.5)));
177 }
178 
TEST(DecomposePair,NotDecomposable)179 TEST(DecomposePair, NotDecomposable) {
180   auto f = [](...) {
181     ADD_FAILURE() << "Must not be called";
182     return 'A';
183   };
184   EXPECT_STREQ("not decomposable",
185                TryDecomposePair(f));
186   EXPECT_STREQ("not decomposable",
187                TryDecomposePair(f, std::piecewise_construct, std::make_tuple(),
188                                 std::make_tuple(0.5)));
189 }
190 
191 }  // namespace
192 }  // namespace priv
193 }  // namespace phmap
194