blob: 8b35b0a4d4c210df56550f83558817c147e50e7c [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <ostream>
#include <set>
#include <string>
#include <vector>
#include <fbl/static_vector.h>
#include <zxtest/zxtest.h>
namespace {
class Obj;
static constexpr int kSize = 5;
static constexpr int kDefaultValue = 42;
static std::set<Obj*> global_constructed_objects;
static int dtor_count = 0;
class Obj {
public:
~Obj() {
dtor_count++;
global_constructed_objects.erase(this);
}
Obj() { AssertDoesNotExist(); }
explicit Obj(int v) : value_(v) { AssertDoesNotExist(); }
Obj(const Obj& rhs) {
AssertDoesNotExist();
*this = rhs;
}
Obj(Obj&& rhs) {
AssertDoesNotExist();
*this = std::move(rhs);
}
Obj& operator=(const Obj& rhs) = default;
Obj& operator=(Obj&& rhs) {
value_ = rhs.value_;
rhs.value_ = 0;
return *this;
}
int value() const { return value_; }
bool operator==(const Obj& rhs) { return rhs.value_ == value_; }
bool operator!=(const Obj& rhs) { return rhs.value_ == value_; }
private:
void AssertDoesNotExist() {
ASSERT_TRUE(global_constructed_objects.count(this) == 0 && "object constructed twice?");
global_constructed_objects.insert(this);
}
int value_ = kDefaultValue;
};
static constexpr fbl::static_vector<int, kSize> MakeConstexprWithPushPop() {
fbl::static_vector<int, kSize> v;
v.push_back(0);
v.push_back(1);
v.push_back(9);
v.pop_back();
v.push_back(2);
return v;
}
TEST(StaticVectorTest, ZeroCapacity) {
static_assert(std::is_empty_v<fbl::static_vector<int, 0>>);
static_assert(std::is_empty_v<fbl::static_vector<double, 0>>);
fbl::static_vector<int, 0> v;
EXPECT_EQ(v.size(), 0);
}
TEST(StaticVectorTest, ConstexprFromEmpty) {
constexpr fbl::static_vector<int, kSize> v;
static_assert(v.size() == 0);
}
TEST(StaticVectorTest, ConstexprFromDefaultValues) {
constexpr fbl::static_vector<int, kSize> v(3);
static_assert(v.size() == 3);
static_assert(v[0] == 0);
static_assert(v[1] == 0);
static_assert(v[2] == 0);
}
TEST(StaticVectorTest, ConstexprFromInitializerList) {
constexpr fbl::static_vector<int, kSize> v{0, 1, 2};
static_assert(v.size() == 3);
static_assert(v[0] == 0);
static_assert(v[1] == 1);
static_assert(v[2] == 2);
}
TEST(StaticVectorTest, ConstexprFromFunctionWithPushPop) {
constexpr auto v = MakeConstexprWithPushPop();
static_assert(v.size() == 3);
static_assert(v[0] == 0);
static_assert(v[1] == 1);
static_assert(v[2] == 2);
}
TEST(StaticVectorTest, ConstexprIterators) {
constexpr fbl::static_vector<int, kSize> v{0, 1, 2, 3, 4};
static_assert(v.size() == 5);
static_assert(v.begin() + 5 == v.end());
static_assert(v.cbegin() + 5 == v.cend());
static_assert(*(v.begin() + 0) == 0);
static_assert(*(v.begin() + 1) == 1);
static_assert(*(v.cbegin() + 0) == 0);
static_assert(*(v.cbegin() + 1) == 1);
static_assert(v.rbegin() + 5 == v.rend());
static_assert(v.crbegin() + 5 == v.crend());
static_assert(*(v.rbegin() + 0) == 4);
static_assert(*(v.rbegin() + 1) == 3);
static_assert(*(v.crbegin() + 0) == 4);
static_assert(*(v.crbegin() + 1) == 3);
}
TEST(StaticVectorTest, DefaultCtorIsEmpty) {
fbl::static_vector<Obj, kSize> v;
EXPECT_TRUE(v.empty());
EXPECT_EQ(v.size(), 0);
}
TEST(StaticVectorTest, CtorFromDefaultValues) {
{
fbl::static_vector<Obj, kSize> v(0);
EXPECT_EQ(v.size(), 0);
}
{
fbl::static_vector<Obj, kSize> v(3);
ASSERT_EQ(v.size(), 3);
EXPECT_EQ(v[0].value(), kDefaultValue);
EXPECT_EQ(v[1].value(), kDefaultValue);
EXPECT_EQ(v[2].value(), kDefaultValue);
}
{
fbl::static_vector<Obj, kSize> v(5);
ASSERT_EQ(v.size(), 5);
EXPECT_EQ(v[0].value(), kDefaultValue);
EXPECT_EQ(v[1].value(), kDefaultValue);
EXPECT_EQ(v[2].value(), kDefaultValue);
EXPECT_EQ(v[3].value(), kDefaultValue);
EXPECT_EQ(v[4].value(), kDefaultValue);
}
}
TEST(StaticVectorTest, CtorFromCopiedValue) {
{
fbl::static_vector<Obj, kSize> v(0, Obj(9));
EXPECT_EQ(v.size(), 0);
}
{
fbl::static_vector<Obj, kSize> v(3, Obj(9));
ASSERT_EQ(v.size(), 3);
EXPECT_EQ(v[0].value(), 9);
EXPECT_EQ(v[1].value(), 9);
EXPECT_EQ(v[2].value(), 9);
}
{
fbl::static_vector<Obj, kSize> v(5, Obj(9));
ASSERT_EQ(v.size(), 5);
EXPECT_EQ(v[0].value(), 9);
EXPECT_EQ(v[1].value(), 9);
EXPECT_EQ(v[2].value(), 9);
EXPECT_EQ(v[3].value(), 9);
EXPECT_EQ(v[4].value(), 9);
}
}
TEST(StaticVectorTest, CtorFromIterator) {
{
std::vector<Obj> in;
fbl::static_vector<Obj, kSize> v(in.begin(), in.end());
EXPECT_EQ(v.size(), 0);
}
{
std::vector<Obj> in{Obj(0), Obj(1), Obj(2)};
fbl::static_vector<Obj, kSize> v(in.begin(), in.end());
ASSERT_EQ(v.size(), 3);
EXPECT_EQ(v[0].value(), 0);
EXPECT_EQ(v[1].value(), 1);
EXPECT_EQ(v[2].value(), 2);
}
{
std::vector<Obj> in{Obj(0), Obj(1), Obj(2), Obj(3), Obj(4)};
fbl::static_vector<Obj, kSize> v(in.begin(), in.end());
ASSERT_EQ(v.size(), 5);
EXPECT_EQ(v[0].value(), 0);
EXPECT_EQ(v[1].value(), 1);
EXPECT_EQ(v[2].value(), 2);
EXPECT_EQ(v[3].value(), 3);
EXPECT_EQ(v[4].value(), 4);
}
}
TEST(StaticVectorTest, CtorFromInitializerList) {
{
fbl::static_vector<Obj, kSize> v{};
EXPECT_EQ(v.size(), 0);
}
{
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1), Obj(2)};
ASSERT_EQ(v.size(), 3);
EXPECT_EQ(v[0].value(), 0);
EXPECT_EQ(v[1].value(), 1);
EXPECT_EQ(v[2].value(), 2);
}
{
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1), Obj(2), Obj(3), Obj(4)};
ASSERT_EQ(v.size(), 5);
EXPECT_EQ(v[0].value(), 0);
EXPECT_EQ(v[1].value(), 1);
EXPECT_EQ(v[2].value(), 2);
EXPECT_EQ(v[3].value(), 3);
EXPECT_EQ(v[4].value(), 4);
}
}
TEST(StaticVectorTest, AssignOpCopy) {
{
fbl::static_vector<Obj, kSize> v;
fbl::static_vector<Obj, kSize> rhs{Obj(0), Obj(1), Obj(2)};
v = rhs;
ASSERT_EQ(v.size(), 3);
EXPECT_EQ(v[0].value(), 0);
EXPECT_EQ(v[1].value(), 1);
EXPECT_EQ(v[2].value(), 2);
ASSERT_EQ(rhs.size(), 3);
EXPECT_EQ(rhs[0].value(), 0);
EXPECT_EQ(rhs[1].value(), 1);
EXPECT_EQ(rhs[2].value(), 2);
}
{
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1), Obj(2)};
fbl::static_vector<Obj, kSize> rhs;
v = rhs;
ASSERT_EQ(v.size(), 0);
ASSERT_EQ(rhs.size(), 0);
}
}
TEST(StaticVectorTest, AssignOpMove) {
{
fbl::static_vector<Obj, kSize> v(4, Obj(9));
fbl::static_vector<Obj, kSize> rhs(3, Obj(9));
dtor_count = 0;
v = std::move(rhs);
EXPECT_EQ(dtor_count, 4); // clear v before the move
ASSERT_EQ(v.size(), 3);
EXPECT_EQ(v[0].value(), 9);
EXPECT_EQ(v[1].value(), 9);
EXPECT_EQ(v[2].value(), 9);
ASSERT_EQ(rhs.size(), 3);
EXPECT_EQ(rhs[0].value(), 0); // Obj's move ctor sets rhs.value = 0
EXPECT_EQ(rhs[1].value(), 0);
EXPECT_EQ(rhs[2].value(), 0);
}
{
fbl::static_vector<Obj, kSize> v(4, Obj(9));
fbl::static_vector<Obj, kSize> rhs;
dtor_count = 0;
v = rhs;
EXPECT_EQ(dtor_count, 4);
ASSERT_EQ(v.size(), 0);
ASSERT_EQ(rhs.size(), 0);
}
{
fbl::static_vector<Obj, kSize> v;
fbl::static_vector<Obj, kSize> rhs(3, Obj(9));
dtor_count = 0;
v = std::move(rhs);
EXPECT_EQ(dtor_count, 0);
ASSERT_EQ(v.size(), 3);
EXPECT_EQ(v[0].value(), 9);
EXPECT_EQ(v[1].value(), 9);
EXPECT_EQ(v[2].value(), 9);
ASSERT_EQ(rhs.size(), 3);
EXPECT_EQ(rhs[0].value(), 0); // Obj's move ctor sets rhs.value = 0
EXPECT_EQ(rhs[1].value(), 0);
EXPECT_EQ(rhs[2].value(), 0);
}
}
TEST(StaticVectorTest, AssignFromIterator) {
{
std::vector<Obj> in;
fbl::static_vector<Obj, kSize> v;
v.assign(in.begin(), in.end());
EXPECT_EQ(v.size(), 0);
}
{
std::vector<Obj> in{Obj(0), Obj(1), Obj(2)};
fbl::static_vector<Obj, kSize> v;
v.assign(in.begin(), in.end());
ASSERT_EQ(v.size(), 3);
EXPECT_EQ(v[0].value(), 0);
EXPECT_EQ(v[1].value(), 1);
EXPECT_EQ(v[2].value(), 2);
}
{
std::vector<Obj> in{Obj(0), Obj(1), Obj(2), Obj(3), Obj(4)};
fbl::static_vector<Obj, kSize> v;
v.assign(in.begin(), in.end());
ASSERT_EQ(v.size(), 5);
EXPECT_EQ(v[0].value(), 0);
EXPECT_EQ(v[1].value(), 1);
EXPECT_EQ(v[2].value(), 2);
EXPECT_EQ(v[3].value(), 3);
EXPECT_EQ(v[4].value(), 4);
}
}
TEST(StaticVectorTest, AssignFromCopiedValue) {
{
fbl::static_vector<Obj, kSize> v;
v.assign(0, Obj(9));
EXPECT_EQ(v.size(), 0);
}
{
fbl::static_vector<Obj, kSize> v;
v.assign(3, Obj(9));
ASSERT_EQ(v.size(), 3);
EXPECT_EQ(v[0].value(), 9);
EXPECT_EQ(v[1].value(), 9);
EXPECT_EQ(v[2].value(), 9);
}
{
fbl::static_vector<Obj, kSize> v;
v.assign(5, Obj(9));
ASSERT_EQ(v.size(), 5);
EXPECT_EQ(v[0].value(), 9);
EXPECT_EQ(v[1].value(), 9);
EXPECT_EQ(v[2].value(), 9);
EXPECT_EQ(v[3].value(), 9);
EXPECT_EQ(v[4].value(), 9);
}
}
TEST(StaticVectorTest, AssignFromInitializerList) {
{
fbl::static_vector<Obj, kSize> v(3);
v.assign({});
EXPECT_EQ(v.size(), 0);
}
{
fbl::static_vector<Obj, kSize> v;
v.assign({Obj(0), Obj(1), Obj(2)});
ASSERT_EQ(v.size(), 3);
EXPECT_EQ(v[0].value(), 0);
EXPECT_EQ(v[1].value(), 1);
EXPECT_EQ(v[2].value(), 2);
}
{
fbl::static_vector<Obj, kSize> v;
v.assign({Obj(0), Obj(1), Obj(2), Obj(3), Obj(4)});
ASSERT_EQ(v.size(), 5);
EXPECT_EQ(v[0].value(), 0);
EXPECT_EQ(v[1].value(), 1);
EXPECT_EQ(v[2].value(), 2);
EXPECT_EQ(v[3].value(), 3);
EXPECT_EQ(v[4].value(), 4);
}
}
TEST(StaticVectorTest, Iterators) {
{
fbl::static_vector<Obj, kSize> v{};
ASSERT_EQ(v.begin(), v.end());
ASSERT_EQ(v.rbegin(), v.rend());
ASSERT_EQ(v.cbegin(), v.cend());
ASSERT_EQ(v.crbegin(), v.crend());
}
{
fbl::static_vector<Obj, kSize> v{Obj(0)};
ASSERT_EQ(v.begin() + 1, v.end());
ASSERT_EQ(v.cbegin() + 1, v.cend());
EXPECT_EQ(v.begin()->value(), 0);
EXPECT_EQ(v.cbegin()->value(), 0);
ASSERT_EQ(v.rbegin() + 1, v.rend());
ASSERT_EQ(v.crbegin() + 1, v.crend());
EXPECT_EQ(v.rbegin()->value(), 0);
EXPECT_EQ(v.crbegin()->value(), 0);
}
{
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1), Obj(2), Obj(3), Obj(4)};
ASSERT_EQ(v.begin() + 5, v.end());
ASSERT_EQ(v.cbegin() + 5, v.cend());
EXPECT_EQ((v.begin() + 0)->value(), 0);
EXPECT_EQ((v.begin() + 1)->value(), 1);
EXPECT_EQ((v.cbegin() + 0)->value(), 0);
EXPECT_EQ((v.cbegin() + 1)->value(), 1);
ASSERT_EQ(v.rbegin() + 5, v.rend());
ASSERT_EQ(v.crbegin() + 5, v.crend());
EXPECT_EQ((v.rbegin() + 0)->value(), 4);
EXPECT_EQ((v.rbegin() + 1)->value(), 3);
EXPECT_EQ((v.crbegin() + 0)->value(), 4);
EXPECT_EQ((v.crbegin() + 1)->value(), 3);
}
}
TEST(StaticVectorTest, Empty) {
{
fbl::static_vector<Obj, kSize> v(0);
EXPECT_EQ(v.size(), 0);
EXPECT_TRUE(v.empty());
}
{
fbl::static_vector<Obj, kSize> v(3);
EXPECT_EQ(v.size(), 3);
EXPECT_FALSE(v.empty());
}
}
TEST(StaticVectorTest, StaticMethods) {
using T = fbl::static_vector<Obj, kSize>;
EXPECT_EQ(T::max_size(), kSize);
EXPECT_EQ(T::capacity(), kSize);
}
TEST(StaticVectorTest, Resize) {
// Size gets bigger.
{
fbl::static_vector<Obj, kSize> v{};
dtor_count = 0;
v.resize(1);
EXPECT_EQ(dtor_count, 0);
ASSERT_EQ(v.size(), 1);
EXPECT_EQ(v[0].value(), kDefaultValue);
}
{
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1)};
dtor_count = 0;
v.resize(5);
EXPECT_EQ(dtor_count, 0);
ASSERT_EQ(v.size(), 5);
EXPECT_EQ(v[0].value(), 0);
EXPECT_EQ(v[1].value(), 1);
EXPECT_EQ(v[2].value(), kDefaultValue);
EXPECT_EQ(v[3].value(), kDefaultValue);
EXPECT_EQ(v[4].value(), kDefaultValue);
}
// Size gets smaller.
{
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1)};
dtor_count = 0;
v.resize(1);
EXPECT_EQ(dtor_count, 1);
ASSERT_EQ(v.size(), 1);
EXPECT_EQ(v[0].value(), 0);
}
{
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1)};
dtor_count = 0;
v.resize(0);
EXPECT_EQ(dtor_count, 2);
ASSERT_EQ(v.size(), 0);
}
}
TEST(StaticVectorTest, ResizeWithDefaultValue) {
Obj obj(9);
// Size gets bigger.
{
fbl::static_vector<Obj, kSize> v{};
dtor_count = 0;
v.resize(1, obj);
EXPECT_EQ(dtor_count, 0);
ASSERT_EQ(v.size(), 1);
EXPECT_EQ(v[0].value(), 9);
}
{
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1)};
dtor_count = 0;
v.resize(5, obj);
EXPECT_EQ(dtor_count, 0);
ASSERT_EQ(v.size(), 5);
EXPECT_EQ(v[0].value(), 0);
EXPECT_EQ(v[1].value(), 1);
EXPECT_EQ(v[2].value(), 9);
EXPECT_EQ(v[3].value(), 9);
EXPECT_EQ(v[4].value(), 9);
}
// Size gets smaller.
{
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1)};
dtor_count = 0;
v.resize(1, obj);
EXPECT_EQ(dtor_count, 1);
ASSERT_EQ(v.size(), 1);
EXPECT_EQ(v[0].value(), 0);
}
{
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1)};
dtor_count = 0;
v.resize(0, obj);
EXPECT_EQ(dtor_count, 2);
ASSERT_EQ(v.size(), 0);
}
}
TEST(StaticVectorTest, Indexing) {
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1), Obj(2)};
ASSERT_EQ(v.size(), 3);
EXPECT_EQ(v[0].value(), 0);
EXPECT_EQ(v[1].value(), 1);
EXPECT_EQ(v[2].value(), 2);
}
TEST(StaticVectorTest, FrontBack) {
{
fbl::static_vector<Obj, kSize> v{Obj(0)};
ASSERT_EQ(v.size(), 1);
EXPECT_EQ(v.front().value(), 0);
EXPECT_EQ(v.back().value(), 0);
}
{
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1), Obj(2)};
ASSERT_EQ(v.size(), 3);
EXPECT_EQ(v.front().value(), 0);
EXPECT_EQ(v.back().value(), 2);
}
{
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1), Obj(2), Obj(3), Obj(4)};
ASSERT_EQ(v.size(), 5);
EXPECT_EQ(v.front().value(), 0);
EXPECT_EQ(v.back().value(), 4);
}
}
TEST(StaticVectorTest, Data) {
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1), Obj(2)};
ASSERT_EQ(v.size(), 3);
EXPECT_EQ(v.data(), &v[0]);
}
TEST(StaticVectorTest, PushFromCopy) {
fbl::static_vector<Obj, kSize> v{};
v.push_back(Obj(9));
ASSERT_EQ(v.size(), 1);
EXPECT_EQ(v[0].value(), 9);
}
TEST(StaticVectorTest, PushFromMove) {
Obj obj(9);
fbl::static_vector<Obj, kSize> v{};
v.push_back(std::move(obj));
EXPECT_EQ(obj.value(), 0);
ASSERT_EQ(v.size(), 1);
EXPECT_EQ(v[0].value(), 9);
}
TEST(StaticVectorTest, Pop) {
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1), Obj(2)};
dtor_count = 0;
v.pop_back();
EXPECT_EQ(dtor_count, 1);
ASSERT_EQ(v.size(), 2);
EXPECT_EQ(v[0].value(), 0);
EXPECT_EQ(v[1].value(), 1);
}
TEST(StaticVectorTest, Clear) {
{
fbl::static_vector<Obj, kSize> v{};
dtor_count = 0;
v.clear();
EXPECT_EQ(dtor_count, 0);
EXPECT_EQ(v.size(), 0);
}
{
fbl::static_vector<Obj, kSize> v{Obj(0), Obj(1), Obj(2), Obj(3), Obj(4)};
dtor_count = 0;
v.clear();
EXPECT_EQ(dtor_count, 5);
EXPECT_EQ(v.size(), 0);
}
}
struct NotDefaultConstructible {
int value;
constexpr explicit NotDefaultConstructible(int value) : value(value) {}
NotDefaultConstructible(const NotDefaultConstructible&) = default;
NotDefaultConstructible& operator=(const NotDefaultConstructible&) = default;
~NotDefaultConstructible() = default;
// In C++20, comparison can be defaulted.
constexpr bool operator==(const NotDefaultConstructible& rhs) const { return value == rhs.value; }
constexpr bool operator!=(const NotDefaultConstructible& rhs) const { return value != rhs.value; }
};
TEST(StaticVectorTest, ClearNonDefaultConstructible) {
fbl::static_vector<NotDefaultConstructible, kSize> v;
v.push_back(NotDefaultConstructible(0));
v.push_back(NotDefaultConstructible(1));
v.push_back(NotDefaultConstructible(2));
v.push_back(NotDefaultConstructible(3));
v.push_back(NotDefaultConstructible(4));
v.clear();
EXPECT_EQ(v.size(), 0);
}
TEST(StaticVectorTest, ClearNonDefaultConstructibleIdempotent) {
fbl::static_vector<NotDefaultConstructible, kSize> v;
v.clear();
EXPECT_EQ(v.size(), 0);
}
TEST(StaticVectorTest, PopNonDefaultConstructible) {
fbl::static_vector<NotDefaultConstructible, kSize> v = {
NotDefaultConstructible(0),
NotDefaultConstructible(1),
NotDefaultConstructible(2),
};
v.pop_back();
ASSERT_EQ(v.size(), 2);
EXPECT_EQ(v[0].value, 0);
EXPECT_EQ(v[1].value, 1);
}
} // namespace