1fd751375bffbbc556cfbca320382687c5cbb395
[folly.git] / folly / test / PaddedTest.cpp
1 /*
2  * Copyright 2014 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 #include <gtest/gtest.h>
21
22 using namespace folly;
23
24 TEST(NodeTest, Padding) {
25   typedef padded::Node<int32_t, 64> IntNode;
26   EXPECT_EQ(16, IntNode::kElementCount);
27   EXPECT_EQ(0, IntNode::kPaddingBytes);
28   EXPECT_EQ(alignof(int32_t), alignof(IntNode));
29   EXPECT_EQ(64, sizeof(IntNode));
30   EXPECT_EQ(0, IntNode::nodeCount(0));
31   EXPECT_EQ(0, IntNode::paddedByteSize(0));
32   EXPECT_EQ(0, IntNode::unpaddedByteSize(0));
33   EXPECT_EQ(1, IntNode::nodeCount(1));
34   EXPECT_EQ(64, IntNode::paddedByteSize(1));
35   EXPECT_EQ(4, IntNode::unpaddedByteSize(1));
36   EXPECT_EQ(1, IntNode::nodeCount(16));
37   EXPECT_EQ(64, IntNode::paddedByteSize(16));
38   EXPECT_EQ(64, IntNode::unpaddedByteSize(16));
39   EXPECT_EQ(2, IntNode::nodeCount(17));
40   EXPECT_EQ(128, IntNode::paddedByteSize(17));
41   EXPECT_EQ(68, IntNode::unpaddedByteSize(17));
42   EXPECT_EQ(128, IntNode::paddedByteSize(32));
43   EXPECT_EQ(128, IntNode::unpaddedByteSize(32));
44   EXPECT_EQ(3, IntNode::nodeCount(33));
45   EXPECT_EQ(192, IntNode::paddedByteSize(33));
46   EXPECT_EQ(132, IntNode::unpaddedByteSize(33));
47
48   struct SevenBytes {
49     char c[7];
50   };
51   EXPECT_EQ(1, alignof(SevenBytes));
52   typedef padded::Node<SevenBytes, 64> SevenByteNode;
53   EXPECT_EQ(9, SevenByteNode::kElementCount);  // 64 / 7
54   EXPECT_EQ(1, SevenByteNode::kPaddingBytes);  // 64 % 7
55   EXPECT_EQ(1, alignof(SevenByteNode));
56   EXPECT_EQ(64, sizeof(SevenByteNode));
57   EXPECT_EQ(0, SevenByteNode::nodeCount(0));
58   EXPECT_EQ(0, SevenByteNode::paddedByteSize(0));
59   EXPECT_EQ(0, SevenByteNode::unpaddedByteSize(0));
60   EXPECT_EQ(1, SevenByteNode::nodeCount(1));
61   EXPECT_EQ(64, SevenByteNode::paddedByteSize(1));
62   EXPECT_EQ(7, SevenByteNode::unpaddedByteSize(1));
63   EXPECT_EQ(1, SevenByteNode::nodeCount(9));
64   EXPECT_EQ(64, SevenByteNode::paddedByteSize(9));
65   EXPECT_EQ(63, SevenByteNode::unpaddedByteSize(9));
66   EXPECT_EQ(2, SevenByteNode::nodeCount(10));
67   EXPECT_EQ(128, SevenByteNode::paddedByteSize(10));
68   EXPECT_EQ(71, SevenByteNode::unpaddedByteSize(10));
69   EXPECT_EQ(2, SevenByteNode::nodeCount(18));
70   EXPECT_EQ(128, SevenByteNode::paddedByteSize(18));
71   EXPECT_EQ(127, SevenByteNode::unpaddedByteSize(18));
72   EXPECT_EQ(3, SevenByteNode::nodeCount(19));
73   EXPECT_EQ(192, SevenByteNode::paddedByteSize(19));
74   EXPECT_EQ(135, SevenByteNode::unpaddedByteSize(19));
75 }
76
77 class IntPaddedTestBase : public ::testing::Test {
78  protected:
79   typedef padded::Node<uint32_t, 64> IntNode;
80   typedef std::vector<IntNode> IntNodeVec;
81   IntNodeVec v_;
82   int n_;
83 };
84
85 class IntPaddedConstTest : public IntPaddedTestBase {
86  protected:
87   void SetUp() {
88     v_.resize(4);
89     n_ = 0;
90     for (int i = 0; i < 4; i++) {
91       for (int j = 0; j < IntNode::kElementCount; ++j, ++n_) {
92         v_[i].data()[j] = n_;
93       }
94     }
95   }
96 };
97
98 TEST_F(IntPaddedConstTest, Iteration) {
99   int k = 0;
100   for (auto it = padded::cbegin(v_); it != padded::cend(v_); ++it, ++k) {
101     EXPECT_EQ(k, *it);
102   }
103   EXPECT_EQ(n_, k);
104 }
105
106 TEST_F(IntPaddedConstTest, Arithmetic) {
107   EXPECT_EQ(64, padded::cend(v_) - padded::cbegin(v_));
108   // Play around block boundaries
109   auto it = padded::cbegin(v_);
110   EXPECT_EQ(0, *it);
111   {
112     auto i2 = it;
113     EXPECT_EQ(0, i2 - it);
114     i2 += 1;
115     EXPECT_EQ(1, *i2);
116     EXPECT_EQ(1, i2 - it);
117     EXPECT_EQ(-1, it - i2);
118   }
119   it += 15;
120   EXPECT_EQ(15, *it);
121   {
122     auto i2 = it;
123     i2 += 1;
124     EXPECT_EQ(16, *i2);
125     EXPECT_EQ(1, i2 - it);
126     EXPECT_EQ(-1, it - i2);
127   }
128   ++it;
129   EXPECT_EQ(16, *it);
130   {
131     auto i2 = it;
132     i2 -= 1;
133     EXPECT_EQ(15, *i2);
134     EXPECT_EQ(-1, i2 - it);
135     EXPECT_EQ(1, it - i2);
136   }
137   --it;
138   EXPECT_EQ(15, *it);
139   {
140     auto i2 = it;
141     i2 -= 1;
142     EXPECT_EQ(14, *i2);
143     EXPECT_EQ(-1, i2 - it);
144     EXPECT_EQ(1, it - i2);
145   }
146 }
147
148 class IntPaddedNonConstTest : public IntPaddedTestBase {
149 };
150
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 (int 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:
184   void SetUp() {
185     v_.resize(4);
186     n_ = 0;
187     for (int i = 0; i < 4; i++) {
188       for (int 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
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
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
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