| /* | |
| * 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); | |
| } |