Line data Source code
1 : #pragma once
2 :
3 : #include <functional>
4 : #include <limits>
5 : #include <optional>
6 : #include <stdexcept>
7 :
8 : namespace containers {
9 :
10 : template <typename T, std::size_t element_count>
11 : class array {
12 : public:
13 : using iterator = T*;
14 : using const_iterator = const T*;
15 :
16 11 : array() {
17 11 : m_data = new T[m_size];
18 :
19 13 : for (size_t i = 0; i < m_size; ++i) {
20 2 : m_data[i] = 0;
21 : }
22 11 : }
23 :
24 22 : array(const std::initializer_list<T>& args) {
25 22 : m_size = args.size();
26 22 : m_data = new T[m_size];
27 :
28 22 : auto current = args.begin();
29 22 : int index = 0;
30 :
31 132 : while (current != args.end()) {
32 110 : m_data[index] = *current;
33 110 : index++;
34 110 : current++;
35 : }
36 22 : }
37 :
38 : array(const array<T, element_count>& other) {
39 : m_data = new T[m_size];
40 :
41 : for (size_t i = 0; i < m_size; ++i) {
42 : m_data[i] = other.m_data[i];
43 : }
44 : }
45 :
46 : array(const array<T, element_count>&& other) {
47 : m_data = std::move(other.m_data);
48 : m_size = std::move(other.m_size);
49 : }
50 :
51 33 : ~array() noexcept { delete[] m_data; }
52 :
53 1 : array<T, element_count>& operator=(const array<T, element_count>& other) {
54 1 : m_size = other.m_size;
55 1 : delete[] m_data;
56 1 : m_data = new int[m_size];
57 :
58 6 : for (size_t i = 0; i < m_size; ++i) {
59 5 : m_data[i] = other.m_data[i];
60 : }
61 :
62 1 : return *this;
63 : }
64 :
65 4 : friend bool operator==(const array<T, element_count>& lhs, const array<T, element_count>& rhs) {
66 14 : for (size_t i = 0; i < element_count; ++i) {
67 10 : if (lhs.m_data[i] != rhs.m_data[i]) {
68 0 : return false;
69 : }
70 : }
71 :
72 4 : return true;
73 : }
74 :
75 : friend bool operator!=(const array<T, element_count>& lhs, const array<T, element_count>& rhs) {
76 : return not(lhs==rhs);
77 : }
78 :
79 16 : T& operator[](size_t index) const { return m_data[index]; }
80 :
81 3 : T& at(size_t index) const {
82 3 : if (not m_data or m_size == 0) {
83 1 : throw std::out_of_range("There are no data to access!");
84 : }
85 :
86 2 : return m_data[index];
87 : }
88 :
89 2 : T* data() const {
90 2 : if (not m_data or m_size == 0) {
91 1 : return nullptr;
92 : }
93 :
94 1 : return m_data;
95 : }
96 :
97 1 : iterator begin() const noexcept { return m_data; }
98 :
99 1 : iterator end() const noexcept { return m_data + m_size; }
100 :
101 1 : const_iterator cbegin() const noexcept { return m_data; }
102 :
103 1 : const_iterator cend() const noexcept { return m_data + m_size; }
104 :
105 3 : std::optional<std::reference_wrapper<T>> front() const {
106 3 : if (not m_data or m_size == 0) {
107 1 : throw std::out_of_range("There is no data to access");
108 : }
109 :
110 2 : return m_data[0];
111 : }
112 :
113 3 : std::optional<std::reference_wrapper<T>> back() const {
114 3 : if (not m_data or m_size == 0) {
115 1 : throw std::out_of_range("There is no data to access");
116 : }
117 :
118 2 : return m_data[m_size - 1];
119 : }
120 :
121 11 : size_t size() const { return m_size; }
122 :
123 2 : size_t max_size() const { return std::numeric_limits<size_t>::max(); }
124 :
125 2 : bool empty() const { return m_size == 0; }
126 :
127 2 : void fill(T value) {
128 7 : for (size_t i = 0; i < m_size; ++i) {
129 5 : m_data[i] = value;
130 : }
131 2 : }
132 :
133 2 : void swap(array& other) {
134 2 : T* temp = new T[other.m_size];
135 2 : size_t temp_size = other.m_size;
136 :
137 7 : for (size_t i = 0; i < temp_size; ++i) {
138 5 : temp[i] = other.m_data[i];
139 : }
140 :
141 2 : delete[] other.m_data;
142 2 : other.m_size = m_size;
143 2 : other.m_data = new T[m_size];
144 :
145 7 : for (size_t i = 0; i < m_size; ++i) {
146 5 : other.m_data[i] = m_data[i];
147 : }
148 :
149 2 : delete[] m_data;
150 2 : m_data = temp;
151 2 : m_size = temp_size;
152 2 : }
153 :
154 : private:
155 : T* m_data = nullptr;
156 : size_t m_size = element_count;
157 : };
158 :
159 : } // namespace containers
|