blob: 132c10a3a0b30f954e41f0210b87815ccd69b2b5 [file] [log] [blame]
/*
* Copyright 2022 Rive
*/
#include <rive/simple_array.hpp>
#include <catch.hpp>
#include <rive/text_engine.hpp>
using namespace rive;
TEST_CASE("array initializes as expected", "[simple array]")
{
SimpleArray<int> array;
REQUIRE(array.empty());
REQUIRE(array.size() == 0);
REQUIRE(array.size_bytes() == 0);
REQUIRE(array.begin() == array.end());
}
TEST_CASE("simple array can be created", "[simple array]")
{
std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
SimpleArray<int> array(v);
REQUIRE(!array.empty());
REQUIRE(array.size() == 10);
REQUIRE(array.size_bytes() == 10 * sizeof(int));
REQUIRE(array.begin() + array.size() == array.end());
int counter = 0;
int sum = 0;
for (auto s : array)
{
counter += 1;
sum += s;
}
REQUIRE(counter == 10);
REQUIRE(sum == 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9);
}
TEST_CASE("can iterate simple array", "[simple array]")
{
const int carray[] = {2, 4, 8, 16};
SimpleArray<int> array(carray, 4);
int expect = 2;
for (auto value : array)
{
REQUIRE(value == expect);
expect *= 2;
}
}
TEST_CASE("can build up a simple array", "[simple array]")
{
SimpleArrayBuilder<int> builder;
builder.add(1);
builder.add(2);
REQUIRE(builder.size() == 2);
REQUIRE(builder.capacity() == 2);
builder.add(3);
REQUIRE(builder.size() == 3);
REQUIRE(builder.capacity() == 4);
int iterationCount = 0;
int expect = 1;
for (auto value : builder)
{
REQUIRE(value == expect++);
iterationCount++;
}
// Should only iterate what's been written so far.
REQUIRE(iterationCount == 3);
int reallocCountBeforeMove = SimpleArrayTesting::reallocCount;
SimpleArray<int> array = std::move(builder);
REQUIRE(array[0] == 1);
REQUIRE(array[1] == 2);
REQUIRE(array[2] == 3);
REQUIRE(array.size() == 3);
REQUIRE(SimpleArrayTesting::reallocCount == reallocCountBeforeMove + 1);
}
struct StructA
{
rive::SimpleArray<uint32_t> numbers;
};
static SimpleArray<StructA> buildStructs()
{
SimpleArrayTesting::resetCounters();
std::vector<uint32_t> vA{33, 22, 44, 66};
SimpleArray<uint32_t> numbersA(vA);
StructA dataA = {std::move(numbersA)};
// We moved the data so expect only one alloc and 0 reallocs.
REQUIRE(SimpleArrayTesting::mallocCount == 1);
REQUIRE(SimpleArrayTesting::reallocCount == 0);
REQUIRE(dataA.numbers.size() == 4);
REQUIRE(numbersA.size() == 0);
std::vector<uint32_t> vB{1, 2, 3};
SimpleArray<uint32_t> numbersB(vB);
StructA dataB = {std::move(numbersB)};
REQUIRE(SimpleArrayTesting::mallocCount == 2);
REQUIRE(SimpleArrayTesting::reallocCount == 0);
REQUIRE(dataB.numbers.size() == 3);
REQUIRE(numbersB.size() == 0);
SimpleArray<StructA> structs(2);
structs[0] = std::move(dataA);
structs[1] = std::move(dataB);
// Should've alloc one more time to create the structs object.
REQUIRE(SimpleArrayTesting::mallocCount == 3);
REQUIRE(SimpleArrayTesting::reallocCount == 0);
REQUIRE(structs.size() == 2);
REQUIRE(structs[0].numbers.size() == 4);
REQUIRE(structs[1].numbers.size() == 3);
return structs;
}
TEST_CASE("arrays of arrays work", "[simple array]")
{
auto structs = buildStructs();
REQUIRE(SimpleArrayTesting::mallocCount == 3);
REQUIRE(SimpleArrayTesting::reallocCount == 0);
REQUIRE(structs.size() == 2);
REQUIRE(structs[0].numbers.size() == 4);
REQUIRE(structs[1].numbers.size() == 3);
}
static SimpleArray<StructA> buildStructsWithBuilder()
{
SimpleArrayTesting::resetCounters();
SimpleArrayBuilder<StructA> structs(2);
REQUIRE(SimpleArrayTesting::mallocCount == 1);
for (int i = 0; i < 3; i++)
{
SimpleArray<uint32_t> numbers({33, 22, 44, 66});
StructA data = {std::move(numbers)};
structs.add(std::move(data));
}
REQUIRE(SimpleArrayTesting::mallocCount == 4);
// Realloc once because we'd reserved 2 and actually added 3.
REQUIRE(SimpleArrayTesting::reallocCount == 1);
return std::move(structs);
}
TEST_CASE("builder arrays of arrays work", "[simple array]")
{
auto structs = buildStructsWithBuilder();
// alloc counters should still be the same
REQUIRE(SimpleArrayTesting::mallocCount == 4);
// Realloc one more time as we sized down.
REQUIRE(SimpleArrayTesting::reallocCount == 2);
}
TEST_CASE("builders can be reset", "[simple array]")
{
SimpleArrayTesting::resetCounters();
SimpleArrayBuilder<uint32_t> builder(3);
builder.add(1);
builder.add(2);
builder.add(3);
REQUIRE(SimpleArrayTesting::mallocCount == 1);
REQUIRE(SimpleArrayTesting::freeCount == 0);
REQUIRE(SimpleArrayTesting::reallocCount == 0);
builder = SimpleArrayBuilder<uint32_t>(4);
// Previous builder got freed.
REQUIRE(SimpleArrayTesting::freeCount == 1);
// We allocated more memory.
REQUIRE(SimpleArrayTesting::mallocCount == 2);
REQUIRE(SimpleArrayTesting::reallocCount == 0);
builder.add(3);
builder.add(2);
SimpleArrayTesting::resetCounters();
SimpleArray<uint32_t> array = std::move(builder);
// Realloc'd down
REQUIRE(SimpleArrayTesting::reallocCount == 1);
// Free and malloc counts didn't move.
REQUIRE(SimpleArrayTesting::freeCount == 0);
REQUIRE(SimpleArrayTesting::mallocCount == 0);
REQUIRE(array.size() == 2);
}