1/*
2 * Copyright 2012-present Facebook, Inc.
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
23using namespace folly;
24
25TEST(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
78class 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
86class IntPaddedConstTest : public IntPaddedTestBase {
87 protected:
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
99TEST_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
107TEST_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
149class IntPaddedNonConstTest : public IntPaddedTestBase {};
150
151TEST_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
169class 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
182class StructPaddedConstTest : public StructPaddedTestBase {
183 protected:
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
198TEST_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
208class IntAdaptorTest : public IntPaddedConstTest {
209 protected:
210 typedef padded::Adaptor<IntNodeVec> IntAdaptor;
211 IntAdaptor a_;
212};
213
214TEST_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
235TEST_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
243TEST_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