Skip to content

Commit d7e6f37

Browse files
committed
Add initializer list
1 parent a6ee90c commit d7e6f37

File tree

2 files changed

+116
-9
lines changed

2 files changed

+116
-9
lines changed

src/ystdlib/container/Array.hpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <concepts>
55
#include <cstddef>
66
#include <cstring>
7+
#include <initializer_list>
78
#include <memory>
89
#include <stdexcept>
910
#include <type_traits>
@@ -12,7 +13,8 @@ namespace ystdlib::container {
1213
/**
1314
* Class for a runtime fix-sized array.
1415
* @tparam T The type of elements in the array. The type must be default initializable so that this
15-
* class doesn't need to implement a constructor which takes an initializer list.
16+
* class doesn't need to implement special memory allocation procedure for std::unique_ptr<T[]>.
17+
* Note that when using constructor that takes an initializer list, T must be copy constructable.
1618
*/
1719
template <typename T>
1820
requires(std::is_fundamental_v<T> || std::default_initializable<T>)
@@ -30,6 +32,17 @@ class Array {
3032
}
3133
}
3234

35+
Array(std::initializer_list<T> list)
36+
// NOLINTNEXTLINE(*-avoid-c-arrays)
37+
: m_data{std::make_unique<T[]>(list.size())},
38+
m_size{list.size()} {
39+
size_t idx{0};
40+
for (auto const& data : list) {
41+
m_data[idx] = T(data);
42+
++idx;
43+
}
44+
}
45+
3346
// Disable copy constructor and assignment operator
3447
Array(Array const&) = delete;
3548
auto operator=(Array const&) -> Array& = delete;
@@ -97,6 +110,7 @@ class Array {
97110
*/
98111
auto assert_is_in_range(size_t idx) const -> void {
99112
if (idx >= m_size) {
113+
// TODO: Add ErrorCode class for `stdexcept` errors and switch to use TraceableException
100114
throw std::out_of_range("ystdlib::container::Array out-of-range access.");
101115
}
102116
}
Lines changed: 101 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,135 @@
11
#include <algorithm>
22
#include <cstddef>
3-
#include <vector>
3+
#include <ranges>
4+
#include <string>
5+
#include <string_view>
6+
#include <type_traits>
47
#include <utility>
8+
#include <vector>
59

610
#include <ystdlib/container/Array.hpp>
711

812
#include <catch2/catch_test_macros.hpp>
913

14+
namespace {
15+
constexpr size_t cBufferSize{1024};
16+
17+
class NoDefault {
18+
public:
19+
NoDefault(size_t n) : m_n{n} {}
20+
21+
[[nodiscard]] auto get() const -> size_t { return m_n; }
22+
23+
private:
24+
size_t m_n;
25+
};
26+
27+
class VarietyConstructors {
28+
public:
29+
static constexpr size_t cDefault = 3190;
30+
31+
VarietyConstructors() = default;
32+
33+
VarietyConstructors(size_t n) : m_n{n} {}
34+
35+
VarietyConstructors(std::string const& s) : m_n{s.size()} {}
36+
37+
VarietyConstructors(NoDefault const& nd) : m_n{nd.get()} {}
38+
39+
[[nodiscard]] auto get() const -> size_t { return m_n; }
40+
41+
private:
42+
size_t m_n{cDefault};
43+
};
44+
45+
void test_function_argument_list_initialization(
46+
ystdlib::container::Array<VarietyConstructors> const& arr,
47+
std::vector<size_t> const& data
48+
) {
49+
REQUIRE(std::ranges::equal(
50+
arr | std::views::transform([](auto const& obj) { return obj.get(); }),
51+
data
52+
));
53+
}
54+
} // namespace
55+
1056
namespace ystdlib::container::test {
1157
TEST_CASE("test_empty_array", "[container][Array]") {
12-
Array<int> arr{0};
58+
Array<int> arr(0);
1359
REQUIRE(arr.empty());
1460
// NOLINTNEXTLINE(readability-container-size-empty)
1561
REQUIRE((0 == arr.size()));
1662
REQUIRE((arr.begin() == arr.end()));
1763
}
1864

1965
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
20-
TEST_CASE("test_array_fundamental", "[container][Array]") {
21-
constexpr size_t cBufferSize{1024};
22-
66+
TEST_CASE("test_array_basic", "[container][Array]") {
2367
std::vector<int> vec;
2468
for (int i{0}; i < cBufferSize; ++i) {
2569
vec.push_back(i);
2670
}
2771

28-
Array<int> arr{cBufferSize};
72+
Array<int> arr(cBufferSize);
2973
auto const& arr_const_ref = arr;
30-
std::ranges::for_each(arr_const_ref, [](int i) -> void { REQUIRE((0 == i)); });
31-
3274
std::ranges::copy(vec, arr.begin());
75+
3376
REQUIRE(std::ranges::equal(vec, arr));
3477
REQUIRE(std::ranges::equal(vec, arr_const_ref));
78+
3579
REQUIRE_THROWS(arr.at(cBufferSize));
3680
REQUIRE_THROWS(arr_const_ref.at(cBufferSize));
3781

3882
auto const arr_moved{std::move(arr)};
3983
REQUIRE(std::ranges::equal(vec, arr_moved));
4084
REQUIRE_THROWS(arr_moved.at(cBufferSize));
4185
}
86+
87+
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
88+
TEST_CASE("test_array_default_initialization", "[container][Array]") {
89+
Array<int> int_arr(cBufferSize);
90+
auto const& int_arr_const_ref = int_arr;
91+
92+
REQUIRE(std::is_fundamental_v<int>);
93+
std::ranges::for_each(int_arr, [](auto const& i) -> void { REQUIRE((0 == i)); });
94+
std::ranges::for_each(int_arr_const_ref, [](auto const& i) -> void { REQUIRE((0 == i)); });
95+
96+
Array<std::nullptr_t> ptr_arr(cBufferSize);
97+
auto const& ptr_arr_const_ref = ptr_arr;
98+
99+
REQUIRE(std::is_fundamental_v<std::nullptr_t>);
100+
std::ranges::for_each(ptr_arr, [](auto const& p) -> void { REQUIRE((nullptr == p)); });
101+
std::ranges::for_each(ptr_arr_const_ref, [](auto const& p) -> void {
102+
REQUIRE((nullptr == p));
103+
});
104+
}
105+
106+
TEST_CASE("test_array_list_initialization_basic", "[container][Array]") {
107+
std::vector<std::string> const
108+
vec{"yscope", "clp", "ystdlib", "ystdlib::container::Array", "default_initializable"};
109+
Array<std::string> const
110+
arr0{"yscope", "clp", "ystdlib", "ystdlib::container::Array", "default_initializable"};
111+
Array<std::string> const arr1
112+
= {"yscope", "clp", "ystdlib", "ystdlib::container::Array", "default_initializable"};
113+
REQUIRE(std::ranges::equal(vec, arr0));
114+
REQUIRE(std::ranges::equal(vec, arr1));
115+
}
116+
117+
TEST_CASE("test_array_list_initialization_variety_constructors", "[container][Array]") {
118+
constexpr size_t cTestNum0{344};
119+
constexpr size_t cTestNum1{454};
120+
constexpr std::string_view cTestStr{"yscope"};
121+
122+
Array<VarietyConstructors> const arr
123+
= {VarietyConstructors{}, cTestNum0, std::string{cTestStr}, NoDefault{cTestNum1}};
124+
std::vector<size_t> const data
125+
= {VarietyConstructors::cDefault, cTestNum0, cTestStr.size(), cTestNum1};
126+
REQUIRE(std::ranges::equal(
127+
arr | std::views::transform([](auto const& obj) { return obj.get(); }),
128+
data
129+
));
130+
test_function_argument_list_initialization(
131+
{VarietyConstructors{}, cTestNum0, std::string{cTestStr}, NoDefault{cTestNum1}},
132+
data
133+
);
134+
}
42135
} // namespace ystdlib::container::test

0 commit comments

Comments
 (0)