/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/Padded.h>
#include <glog/logging.h>
#include <folly/portability/GTest.h>
using namespace folly;
TEST(NodeTest, Padding) {
typedef padded::Node<int32_t, 64> IntNode;
EXPECT_EQ(16, IntNode::kElementCount);
EXPECT_EQ(0, IntNode::kPaddingBytes);
EXPECT_EQ(alignof(int32_t), alignof(IntNode));
EXPECT_EQ(64, sizeof(IntNode));
EXPECT_EQ(0, IntNode::nodeCount(0));
EXPECT_EQ(0, IntNode::paddedByteSize(0));
EXPECT_EQ(0, IntNode::unpaddedByteSize(0));
EXPECT_EQ(1, IntNode::nodeCount(1));
EXPECT_EQ(64, IntNode::paddedByteSize(1));
EXPECT_EQ(4, IntNode::unpaddedByteSize(1));
EXPECT_EQ(1, IntNode::nodeCount(16));
EXPECT_EQ(64, IntNode::paddedByteSize(16));
EXPECT_EQ(64, IntNode::unpaddedByteSize(16));
EXPECT_EQ(2, IntNode::nodeCount(17));
EXPECT_EQ(128, IntNode::paddedByteSize(17));
EXPECT_EQ(68, IntNode::unpaddedByteSize(17));
EXPECT_EQ(128, IntNode::paddedByteSize(32));
EXPECT_EQ(128, IntNode::unpaddedByteSize(32));
EXPECT_EQ(3, IntNode::nodeCount(33));
EXPECT_EQ(192, IntNode::paddedByteSize(33));
EXPECT_EQ(132, IntNode::unpaddedByteSize(33));
struct SevenBytes {
char c[7];
};
EXPECT_EQ(1, alignof(SevenBytes));
typedef padded::Node<SevenBytes, 64> SevenByteNode;
EXPECT_EQ(9, SevenByteNode::kElementCount); // 64 / 7
EXPECT_EQ(1, SevenByteNode::kPaddingBytes); // 64 % 7
EXPECT_EQ(1, alignof(SevenByteNode));
EXPECT_EQ(64, sizeof(SevenByteNode));
EXPECT_EQ(0, SevenByteNode::nodeCount(0));
EXPECT_EQ(0, SevenByteNode::paddedByteSize(0));
EXPECT_EQ(0, SevenByteNode::unpaddedByteSize(0));
EXPECT_EQ(1, SevenByteNode::nodeCount(1));
EXPECT_EQ(64, SevenByteNode::paddedByteSize(1));
EXPECT_EQ(7, SevenByteNode::unpaddedByteSize(1));
EXPECT_EQ(1, SevenByteNode::nodeCount(9));
EXPECT_EQ(64, SevenByteNode::paddedByteSize(9));
EXPECT_EQ(63, SevenByteNode::unpaddedByteSize(9));
EXPECT_EQ(2, SevenByteNode::nodeCount(10));
EXPECT_EQ(128, SevenByteNode::paddedByteSize(10));
EXPECT_EQ(71, SevenByteNode::unpaddedByteSize(10));
EXPECT_EQ(2, SevenByteNode::nodeCount(18));
EXPECT_EQ(128, SevenByteNode::paddedByteSize(18));
EXPECT_EQ(127, SevenByteNode::unpaddedByteSize(18));
EXPECT_EQ(3, SevenByteNode::nodeCount(19));
EXPECT_EQ(192, SevenByteNode::paddedByteSize(19));
EXPECT_EQ(135, SevenByteNode::unpaddedByteSize(19));
}
class IntPaddedTestBase : public ::testing::Test {
protected:
typedef padded::Node<uint32_t, 64> IntNode;
typedef std::vector<IntNode> IntNodeVec;
IntNodeVec v_;
int n_;
};
class IntPaddedConstTest : public IntPaddedTestBase {
protected:
void SetUp() override {
v_.resize(4);
n_ = 0;
for (int i = 0; i < 4; i++) {
for (size_t j = 0; j < IntNode::kElementCount; ++j, ++n_) {
v_[i].data()[j] = n_;
}
}
}
};
TEST_F(IntPaddedConstTest, Iteration) {
int k = 0;
for (auto it = padded::cbegin(v_); it != padded::cend(v_); ++it, ++k) {
EXPECT_EQ(k, *it);
}
EXPECT_EQ(n_, k);
}
TEST_F(IntPaddedConstTest, Arithmetic) {
EXPECT_EQ(64, padded::cend(v_) - padded::cbegin(v_));
// Play around block boundaries
auto it = padded::cbegin(v_);
EXPECT_EQ(0, *it);
{
auto i2 = it;
EXPECT_EQ(0, i2 - it);
i2 += 1;
EXPECT_EQ(1, *i2);
EXPECT_EQ(1, i2 - it);
EXPECT_EQ(-1, it - i2);
}
it += 15;
EXPECT_EQ(15, *it);
{
auto i2 = it;
i2 += 1;
EXPECT_EQ(16, *i2);
EXPECT_EQ(1, i2 - it);
EXPECT_EQ(-1, it - i2);
}
++it;
EXPECT_EQ(16, *it);
{
auto i2 = it;
i2 -= 1;
EXPECT_EQ(15, *i2);
EXPECT_EQ(-1, i2 - it);
EXPECT_EQ(1, it - i2);
}
--it;
EXPECT_EQ(15, *it);
{
auto i2 = it;
i2 -= 1;
EXPECT_EQ(14, *i2);
EXPECT_EQ(-1, i2 - it);
EXPECT_EQ(1, it - i2);
}
}
class IntPaddedNonConstTest : public IntPaddedTestBase {};
TEST_F(IntPaddedNonConstTest, Iteration) {
v_.resize(4);
n_ = 64;
int k = 0;
for (auto it = padded::begin(v_); it != padded::end(v_); ++it, ++k) {
*it = k;
}
EXPECT_EQ(n_, k);
k = 0;
for (int i = 0; i < 4; i++) {
for (size_t j = 0; j < IntNode::kElementCount; ++j, ++k) {
EXPECT_EQ(k, v_[i].data()[j]);
}
}
}
class StructPaddedTestBase : public ::testing::Test {
protected:
struct Point {
uint8_t x;
uint8_t y;
uint8_t z;
};
typedef padded::Node<Point, 64> PointNode;
typedef std::vector<PointNode> PointNodeVec;
PointNodeVec v_;
int n_;
};
class StructPaddedConstTest : public StructPaddedTestBase {
protected:
void SetUp() override {
v_.resize(4);
n_ = 0;
for (int i = 0; i < 4; i++) {
for (size_t j = 0; j < PointNode::kElementCount; ++j, ++n_) {
auto& point = v_[i].data()[j];
point.x = n_;
point.y = n_ + 1;
point.z = n_ + 2;
}
}
}
};
TEST_F(StructPaddedConstTest, Iteration) {
int k = 0;
for (auto it = padded::cbegin(v_); it != padded::cend(v_); ++it, ++k) {
EXPECT_EQ(k, it->x);
EXPECT_EQ(k + 1, it->y);
EXPECT_EQ(k + 2, it->z);
}
EXPECT_EQ(n_, k);
}
class IntAdaptorTest : public IntPaddedConstTest {
protected:
typedef padded::Adaptor<IntNodeVec> IntAdaptor;
IntAdaptor a_;
};
TEST_F(IntAdaptorTest, Simple) {
for (int i = 0; i < n_; ++i) {
EXPECT_EQ((i == 0), a_.empty());
EXPECT_EQ(i, a_.size());
a_.push_back(i);
}
EXPECT_EQ(n_, a_.size());
int k = 0;
for (auto it = a_.begin(); it != a_.end(); ++it, ++k) {
EXPECT_EQ(k, a_[k]);
EXPECT_EQ(k, *it);
}
EXPECT_EQ(n_, k);
auto p = a_.move();
EXPECT_TRUE(a_.empty());
EXPECT_EQ(16, p.second);
EXPECT_TRUE(v_ == p.first);
}
TEST_F(IntAdaptorTest, ResizeConstructor) {
IntAdaptor a(n_, 42);
EXPECT_EQ(n_, a.size());
for (int i = 0; i < n_; ++i) {
EXPECT_EQ(42, a[i]);
}
}
TEST_F(IntAdaptorTest, SimpleEmplaceBack) {
for (int i = 0; i < n_; ++i) {
EXPECT_EQ((i == 0), a_.empty());
EXPECT_EQ(i, a_.size());
a_.emplace_back(i);
}
EXPECT_EQ(n_, a_.size());
int k = 0;
for (auto it = a_.begin(); it != a_.end(); ++it, ++k) {
EXPECT_EQ(k, a_[k]);
EXPECT_EQ(k, *it);
}
EXPECT_EQ(n_, k);
auto p = a_.move();
EXPECT_TRUE(a_.empty());
EXPECT_EQ(16, p.second);
EXPECT_TRUE(v_ == p.first);
}