1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <folly/Padded.h>
18 
19 #include <glog/logging.h>
20 
21 #include <folly/portability/GTest.h>
22 
23 using namespace folly;
24 
TEST(NodeTest,Padding)25 TEST(NodeTest, Padding) {
26   typedef padded::Node<int32_t, 64> IntNode;
27   EXPECT_EQ(16, IntNode::kElementCount);
28   EXPECT_EQ(0, IntNode::kPaddingBytes);
29   EXPECT_EQ(alignof(int32_t), alignof(IntNode));
30   EXPECT_EQ(64, sizeof(IntNode));
31   EXPECT_EQ(0, IntNode::nodeCount(0));
32   EXPECT_EQ(0, IntNode::paddedByteSize(0));
33   EXPECT_EQ(0, IntNode::unpaddedByteSize(0));
34   EXPECT_EQ(1, IntNode::nodeCount(1));
35   EXPECT_EQ(64, IntNode::paddedByteSize(1));
36   EXPECT_EQ(4, IntNode::unpaddedByteSize(1));
37   EXPECT_EQ(1, IntNode::nodeCount(16));
38   EXPECT_EQ(64, IntNode::paddedByteSize(16));
39   EXPECT_EQ(64, IntNode::unpaddedByteSize(16));
40   EXPECT_EQ(2, IntNode::nodeCount(17));
41   EXPECT_EQ(128, IntNode::paddedByteSize(17));
42   EXPECT_EQ(68, IntNode::unpaddedByteSize(17));
43   EXPECT_EQ(128, IntNode::paddedByteSize(32));
44   EXPECT_EQ(128, IntNode::unpaddedByteSize(32));
45   EXPECT_EQ(3, IntNode::nodeCount(33));
46   EXPECT_EQ(192, IntNode::paddedByteSize(33));
47   EXPECT_EQ(132, IntNode::unpaddedByteSize(33));
48 
49   struct SevenBytes {
50     char c[7];
51   };
52   EXPECT_EQ(1, alignof(SevenBytes));
53   typedef padded::Node<SevenBytes, 64> SevenByteNode;
54   EXPECT_EQ(9, SevenByteNode::kElementCount); // 64 / 7
55   EXPECT_EQ(1, SevenByteNode::kPaddingBytes); // 64 % 7
56   EXPECT_EQ(1, alignof(SevenByteNode));
57   EXPECT_EQ(64, sizeof(SevenByteNode));
58   EXPECT_EQ(0, SevenByteNode::nodeCount(0));
59   EXPECT_EQ(0, SevenByteNode::paddedByteSize(0));
60   EXPECT_EQ(0, SevenByteNode::unpaddedByteSize(0));
61   EXPECT_EQ(1, SevenByteNode::nodeCount(1));
62   EXPECT_EQ(64, SevenByteNode::paddedByteSize(1));
63   EXPECT_EQ(7, SevenByteNode::unpaddedByteSize(1));
64   EXPECT_EQ(1, SevenByteNode::nodeCount(9));
65   EXPECT_EQ(64, SevenByteNode::paddedByteSize(9));
66   EXPECT_EQ(63, SevenByteNode::unpaddedByteSize(9));
67   EXPECT_EQ(2, SevenByteNode::nodeCount(10));
68   EXPECT_EQ(128, SevenByteNode::paddedByteSize(10));
69   EXPECT_EQ(71, SevenByteNode::unpaddedByteSize(10));
70   EXPECT_EQ(2, SevenByteNode::nodeCount(18));
71   EXPECT_EQ(128, SevenByteNode::paddedByteSize(18));
72   EXPECT_EQ(127, SevenByteNode::unpaddedByteSize(18));
73   EXPECT_EQ(3, SevenByteNode::nodeCount(19));
74   EXPECT_EQ(192, SevenByteNode::paddedByteSize(19));
75   EXPECT_EQ(135, SevenByteNode::unpaddedByteSize(19));
76 }
77 
78 class IntPaddedTestBase : public ::testing::Test {
79  protected:
80   typedef padded::Node<uint32_t, 64> IntNode;
81   typedef std::vector<IntNode> IntNodeVec;
82   IntNodeVec v_;
83   int n_;
84 };
85 
86 class IntPaddedConstTest : public IntPaddedTestBase {
87  protected:
SetUp()88   void SetUp() override {
89     v_.resize(4);
90     n_ = 0;
91     for (int i = 0; i < 4; i++) {
92       for (size_t j = 0; j < IntNode::kElementCount; ++j, ++n_) {
93         v_[i].data()[j] = n_;
94       }
95     }
96   }
97 };
98 
TEST_F(IntPaddedConstTest,Iteration)99 TEST_F(IntPaddedConstTest, Iteration) {
100   int k = 0;
101   for (auto it = padded::cbegin(v_); it != padded::cend(v_); ++it, ++k) {
102     EXPECT_EQ(k, *it);
103   }
104   EXPECT_EQ(n_, k);
105 }
106 
TEST_F(IntPaddedConstTest,Arithmetic)107 TEST_F(IntPaddedConstTest, Arithmetic) {
108   EXPECT_EQ(64, padded::cend(v_) - padded::cbegin(v_));
109   // Play around block boundaries
110   auto it = padded::cbegin(v_);
111   EXPECT_EQ(0, *it);
112   {
113     auto i2 = it;
114     EXPECT_EQ(0, i2 - it);
115     i2 += 1;
116     EXPECT_EQ(1, *i2);
117     EXPECT_EQ(1, i2 - it);
118     EXPECT_EQ(-1, it - i2);
119   }
120   it += 15;
121   EXPECT_EQ(15, *it);
122   {
123     auto i2 = it;
124     i2 += 1;
125     EXPECT_EQ(16, *i2);
126     EXPECT_EQ(1, i2 - it);
127     EXPECT_EQ(-1, it - i2);
128   }
129   ++it;
130   EXPECT_EQ(16, *it);
131   {
132     auto i2 = it;
133     i2 -= 1;
134     EXPECT_EQ(15, *i2);
135     EXPECT_EQ(-1, i2 - it);
136     EXPECT_EQ(1, it - i2);
137   }
138   --it;
139   EXPECT_EQ(15, *it);
140   {
141     auto i2 = it;
142     i2 -= 1;
143     EXPECT_EQ(14, *i2);
144     EXPECT_EQ(-1, i2 - it);
145     EXPECT_EQ(1, it - i2);
146   }
147 }
148 
149 class IntPaddedNonConstTest : public IntPaddedTestBase {};
150 
TEST_F(IntPaddedNonConstTest,Iteration)151 TEST_F(IntPaddedNonConstTest, Iteration) {
152   v_.resize(4);
153   n_ = 64;
154 
155   int k = 0;
156   for (auto it = padded::begin(v_); it != padded::end(v_); ++it, ++k) {
157     *it = k;
158   }
159   EXPECT_EQ(n_, k);
160 
161   k = 0;
162   for (int i = 0; i < 4; i++) {
163     for (size_t j = 0; j < IntNode::kElementCount; ++j, ++k) {
164       EXPECT_EQ(k, v_[i].data()[j]);
165     }
166   }
167 }
168 
169 class StructPaddedTestBase : public ::testing::Test {
170  protected:
171   struct Point {
172     uint8_t x;
173     uint8_t y;
174     uint8_t z;
175   };
176   typedef padded::Node<Point, 64> PointNode;
177   typedef std::vector<PointNode> PointNodeVec;
178   PointNodeVec v_;
179   int n_;
180 };
181 
182 class StructPaddedConstTest : public StructPaddedTestBase {
183  protected:
SetUp()184   void SetUp() override {
185     v_.resize(4);
186     n_ = 0;
187     for (int i = 0; i < 4; i++) {
188       for (size_t j = 0; j < PointNode::kElementCount; ++j, ++n_) {
189         auto& point = v_[i].data()[j];
190         point.x = n_;
191         point.y = n_ + 1;
192         point.z = n_ + 2;
193       }
194     }
195   }
196 };
197 
TEST_F(StructPaddedConstTest,Iteration)198 TEST_F(StructPaddedConstTest, Iteration) {
199   int k = 0;
200   for (auto it = padded::cbegin(v_); it != padded::cend(v_); ++it, ++k) {
201     EXPECT_EQ(k, it->x);
202     EXPECT_EQ(k + 1, it->y);
203     EXPECT_EQ(k + 2, it->z);
204   }
205   EXPECT_EQ(n_, k);
206 }
207 
208 class IntAdaptorTest : public IntPaddedConstTest {
209  protected:
210   typedef padded::Adaptor<IntNodeVec> IntAdaptor;
211   IntAdaptor a_;
212 };
213 
TEST_F(IntAdaptorTest,Simple)214 TEST_F(IntAdaptorTest, Simple) {
215   for (int i = 0; i < n_; ++i) {
216     EXPECT_EQ((i == 0), a_.empty());
217     EXPECT_EQ(i, a_.size());
218     a_.push_back(i);
219   }
220   EXPECT_EQ(n_, a_.size());
221 
222   int k = 0;
223   for (auto it = a_.begin(); it != a_.end(); ++it, ++k) {
224     EXPECT_EQ(k, a_[k]);
225     EXPECT_EQ(k, *it);
226   }
227   EXPECT_EQ(n_, k);
228 
229   auto p = a_.move();
230   EXPECT_TRUE(a_.empty());
231   EXPECT_EQ(16, p.second);
232   EXPECT_TRUE(v_ == p.first);
233 }
234 
TEST_F(IntAdaptorTest,ResizeConstructor)235 TEST_F(IntAdaptorTest, ResizeConstructor) {
236   IntAdaptor a(n_, 42);
237   EXPECT_EQ(n_, a.size());
238   for (int i = 0; i < n_; ++i) {
239     EXPECT_EQ(42, a[i]);
240   }
241 }
242 
TEST_F(IntAdaptorTest,SimpleEmplaceBack)243 TEST_F(IntAdaptorTest, SimpleEmplaceBack) {
244   for (int i = 0; i < n_; ++i) {
245     EXPECT_EQ((i == 0), a_.empty());
246     EXPECT_EQ(i, a_.size());
247     a_.emplace_back(i);
248   }
249   EXPECT_EQ(n_, a_.size());
250 
251   int k = 0;
252   for (auto it = a_.begin(); it != a_.end(); ++it, ++k) {
253     EXPECT_EQ(k, a_[k]);
254     EXPECT_EQ(k, *it);
255   }
256   EXPECT_EQ(n_, k);
257 
258   auto p = a_.move();
259   EXPECT_TRUE(a_.empty());
260   EXPECT_EQ(16, p.second);
261   EXPECT_TRUE(v_ == p.first);
262 }
263