DSA - Data Structures and Algorithms
Loading...
Searching...
No Matches
array.h
Go to the documentation of this file.
1
11
12#ifndef ARRAY_H
13#define ARRAY_H
14
15#include <cstddef>
16#include <iostream>
17#include <iterator>
18#include <type_traits>
19#include <utility>
20
21namespace dsa
22{
23
30 template<typename T, std::size_t N>
31 struct Array
32 {
38 using value_type = T;
39
45 using size_type = std::size_t;
46
52 using difference_type = std::ptrdiff_t;
53
60
66 using const_pointer = const value_type*;
67
74
81
86
90 using const_iterator = const value_type*;
91
95 using reverse_iterator = std::reverse_iterator<iterator>;
96
100 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
101
109 [[nodiscard]] constexpr auto at(size_type pos) -> reference
110 {
111 if (pos >= N)
112 {
113 throw std::out_of_range("Pos argument outside of container range");
114 }
115
116 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
117 return m_data[pos];
118 }
119
127 [[nodiscard]] constexpr auto at(size_type pos) const -> const_reference
128 {
129 if (pos >= N)
130 {
131 throw std::out_of_range("Pos argument outside of container range");
132 }
133
134 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
135 return m_data[pos];
136 }
137
145 [[nodiscard]] constexpr auto operator[](size_type pos) -> reference
146 {
147 // Same semantics as std::array::operator[], no bounds checking
148 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
149 return m_data[pos];
150 }
151
159 [[nodiscard]] constexpr auto operator[](size_type pos) const -> const_reference
160 {
161 // Same semantics as std::array::operator[], no bounds checking
162 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
163 return m_data[pos];
164 }
165
171 [[nodiscard]] constexpr auto front() -> reference
172 {
173 return m_data[0];
174 }
175
181 [[nodiscard]] constexpr auto front() const -> const_reference
182 {
183 return m_data[0];
184 }
185
191 [[nodiscard]] constexpr auto back() -> reference
192 {
193 return m_data[N - 1];
194 }
195
201 [[nodiscard]] constexpr auto back() const -> const_reference
202 {
203 return m_data[N - 1];
204 }
205
211 [[nodiscard]] constexpr auto data() noexcept -> pointer
212 {
213 return &m_data[0];
214 }
215
221 [[nodiscard]] constexpr auto data() const noexcept -> const_pointer
222 {
223 return &m_data[0];
224 }
225
233 [[nodiscard]] constexpr auto begin() noexcept -> iterator
234 {
235 return &m_data[0];
236 }
237
245 [[nodiscard]] constexpr auto begin() const noexcept -> const_iterator
246 {
247 return &m_data[0];
248 }
249
257 [[nodiscard]] constexpr auto cbegin() const noexcept -> const_iterator
258 {
259 return &m_data[0];
260 }
261
269 [[nodiscard]] constexpr auto end() noexcept -> iterator
270 {
271 return &m_data[N];
272 }
273
281 [[nodiscard]] constexpr auto end() const noexcept -> const_iterator
282 {
283 return &(m_data[N]);
284 }
285
293 [[nodiscard]] constexpr auto cend() const noexcept -> const_iterator
294 {
295 return &(m_data[N]);
296 }
297
305 [[nodiscard]] constexpr auto rbegin() noexcept -> reverse_iterator
306 {
307 return reverse_iterator(end());
308 }
309
317 [[nodiscard]] constexpr auto rbegin() const noexcept -> const_reverse_iterator
318 {
319 return const_reverse_iterator(end());
320 }
321
329 [[nodiscard]] constexpr auto crbegin() const noexcept -> const_reverse_iterator
330 {
331 return const_reverse_iterator(end());
332 }
333
341 [[nodiscard]] constexpr auto rend() noexcept -> reverse_iterator
342 {
343 return reverse_iterator(begin());
344 }
345
353 [[nodiscard]] constexpr auto rend() const noexcept -> const_reverse_iterator
354 {
356 }
357
365 [[nodiscard]] constexpr auto crend() const noexcept -> const_reverse_iterator
366 {
368 }
369
376 [[nodiscard]] constexpr auto empty() const noexcept -> bool
377 {
378 return N == 0;
379 }
380
386 [[nodiscard]] constexpr auto size() const noexcept -> size_type
387 {
388 return N;
389 }
390
396 [[nodiscard]] constexpr auto max_size() const noexcept -> size_type
397 {
398 return N;
399 }
400
406 void fill(const value_type& value)
407 {
408 for (size_type i = 0; i < size(); i++)
409 {
410 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
411 m_data[i] = value;
412 }
413 }
414
420 constexpr void swap(Array<T, N>& other) noexcept(std::is_nothrow_swappable_v<T>)
421 {
422 if (*this != other)
423 {
424 std::swap(m_data, other.m_data);
425 }
426 }
427
432 // Public for aggregate initialization, same as std::array
433 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays, misc-non-private-member-variables-in-classes)
434 value_type m_data[N == 0 ? 1 : N]{};
435 };
436
446 template<std::size_t I, typename T, std::size_t N>
447 [[nodiscard]] constexpr auto get(Array<T, N>& array) noexcept -> T&
448 {
449 static_assert(I < N, "Index out of range in dsa::Array::get");
450 return array[I];
451 }
452
462 template<std::size_t I, typename T, std::size_t N>
463 [[nodiscard]] constexpr auto get(const Array<T, N>& array) noexcept -> const T&
464 {
465 static_assert(I < N, "Index out of range in dsa::Array::get");
466 return array[I];
467 }
468
483 template<std::size_t I, typename T, std::size_t N>
484 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
485 [[nodiscard]] constexpr auto get(Array<T, N>&& array) noexcept -> T&&
486 {
487 static_assert(I < N, "Index out of range in dsa::Array::get");
488 return std::move(array[I]);
489 }
490
500 template<std::size_t I, typename T, std::size_t N>
501 [[nodiscard]] constexpr auto get(const Array<T, N>&& array) noexcept -> const T&&
502 {
503 static_assert(I < N, "Index out of range in dsa::Array::get");
504 return std::move(array[I]);
505 }
506
515 template<typename T, std::size_t N>
516 void swap(Array<T, N>& lhs, Array<T, N>& rhs) noexcept(noexcept(lhs.swap(rhs)))
517 {
518 lhs.swap(rhs);
519 }
520
528 template<typename T, std::size_t N>
529 requires(!std::is_array_v<T>)
530 // Intentional use of C-style array: the array bound must be part of the type
531 // to enable compile-time size deduction
532 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
533 [[nodiscard]] constexpr auto to_array(T(&array)[N]) -> Array<std::remove_cv_t<T>, N>
534 {
535 return[&]<std::size_t... I>(std::index_sequence<I...>)
536 {
537 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
538 return dsa::Array<std::remove_cv_t<T>, N>{array[I]...};
539 }(std::make_index_sequence<N>{});
540 }
541
549 template<typename T, std::size_t N>
550 requires(!std::is_array_v<T> && !std::is_const_v<T>)
551 // Intentional use of C-style array: the array bound must be part of the type
552 // to enable compile-time size deduction
553 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-rvalue-reference-param-not-moved)
554 [[nodiscard]] constexpr auto to_array(T(&& array)[N]) -> Array<std::remove_cv_t<T>, N>
555 {
556 return[&]<std::size_t... I>(std::index_sequence<I...>)
557 {
558 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays)
559 return dsa::Array<std::remove_cv_t<T>, N>{std::move(array[I])...};
560 }(std::make_index_sequence<N>{});
561 }
562
571 template<typename T, std::size_t N>
572 auto operator<<(std::ostream& out, const Array<T, N>& array) -> std::ostream&
573 {
574 for (size_t i = 0; i < N; i++)
575 {
576 out << array[i] << ' ';
577 }
578
579 return out;
580 }
581
590 template<typename T, std::size_t N>
591 [[nodiscard]] constexpr auto operator==(const Array<T, N>& lhs, const Array<T, N>& rhs)
592 noexcept(noexcept(*lhs.begin() == *rhs.begin())) -> bool
593 {
594 auto lhs_iter = lhs.cbegin();
595 auto rhs_iter = rhs.cbegin();
596
597 for (size_t i = 0; i < N; i++)
598 {
599 if (*lhs_iter != *rhs_iter)
600 {
601 return false;
602 }
603
604 lhs_iter++;
605 rhs_iter++;
606 }
607
608 return true;
609 }
610
624 template<typename T, std::size_t N>
625 [[nodiscard]] constexpr auto operator<=>(const Array<T, N>& lhs, const Array<T, N>& rhs)
626 noexcept(noexcept(*lhs.begin() == *rhs.begin())) -> std::compare_three_way_result_t<T>
627 {
628 auto lhs_iter = lhs.cbegin();
629 auto rhs_iter = rhs.cbegin();
630
631 for (size_t i = 0; i < N; i++)
632 {
633 auto cmp = *lhs_iter <=> *rhs_iter;
634 if (cmp != 0)
635 {
636 return cmp;
637 }
638
639 lhs_iter++;
640 rhs_iter++;
641 }
642
643 return std::compare_three_way_result_t<T>::equivalent;
644 }
645}
646
647namespace std
648{
649 /*
650 * These are explicit specializations of standard templates 'tuple_size' and 'tuple_element'
651 * for a user-defined type dsa::Array. This is allowed by C++ standard and required
652 * to enable structured bindings and tuple-like behaviour.
653 *
654 * No new symbols or modification of standard library behaviour was introduced,
655 * only providing valid specialization for user-defined type.
656 */
657 // NOLINTBEGIN(cert-dcl58-cpp)
658
660
668 template<typename T, std::size_t N>
669 struct tuple_size <dsa::Array<T, N>> : std::integral_constant<std::size_t, N>
670 {
671 };
673
675
684 template<std::size_t I, typename T, std::size_t N>
685 struct tuple_element<I, dsa::Array<T, N>>
686 {
691 using type = T;
692 };
694
695 namespace ranges
696 {
697 /*
698 * These are explicit specializations of range semantics for a user-defined type dsa::Array
699 * specifically to be recognized as 'borrowed range' or 'view'
700 */
701
703
714 template<typename T, std::size_t N>
715 inline constexpr bool enable_borrowed_range<dsa::Array<T, N>> = true;
717
719
729 template<typename T, std::size_t N>
730 inline constexpr bool enable_view<dsa::Array<T, N>> = true;
732
734
744 template<typename T, std::size_t N>
745 inline constexpr bool enable_view<const dsa::Array<T, N>> = true;
747 }
748
749 // NOLINTEND(cert-dcl58-cpp)
750}
751
752#endif // !ARRAY_H
constexpr auto operator==(const Array< T, N > &lhs, const Array< T, N > &rhs) noexcept(noexcept(*lhs.begin()== *rhs.begin())) -> bool
The relational operator compares two Array objects.
Definition array.h:591
constexpr auto operator<=>(const Array< T, N > &lhs, const Array< T, N > &rhs) noexcept(noexcept(*lhs.begin()== *rhs.begin())) -> std::compare_three_way_result_t< T >
The relational operator compares two Array objects.
Definition array.h:625
void swap(Array< T, N > &lhs, Array< T, N > &rhs) noexcept(noexcept(lhs.swap(rhs)))
Exchanges content of two Array containers.
Definition array.h:516
auto operator<<(std::ostream &out, const Array< T, N > &array) -> std::ostream &
Overloads operator to print all elements of Array.
Definition array.h:572
constexpr auto get(Array< T, N > &array) noexcept -> T &
Provide access to Ith element of an array.
Definition array.h:447
constexpr auto to_array(T(&array)[N]) -> Array< std::remove_cv_t< T >, N >
Creates Array from one dimensional C-style array using copy semantics.
Definition array.h:533
Implements Array class template for fixed size container.
Definition array.h:32
constexpr auto operator[](size_type pos) const -> const_reference
Returns a const_reference to Array element at pos index. If pos is outside of container range,...
Definition array.h:159
void fill(const value_type &value)
Assigns value to all elements of the container.
Definition array.h:406
constexpr auto crbegin() const noexcept -> const_reverse_iterator
Returns const_reverse_iterator to the first element of reversed underlaying array structure.
Definition array.h:329
constexpr auto front() -> reference
Returns reference to first Arary element.
Definition array.h:171
constexpr auto begin() const noexcept -> const_iterator
Returns const_iterator to first element.
Definition array.h:245
constexpr auto back() const -> const_reference
Returns const_reference to last Arary element.
Definition array.h:201
std::reverse_iterator< iterator > reverse_iterator
Alias for reverse_iterator to data type used in class.
Definition array.h:95
const value_type & const_reference
Alias for const reference to data type used in class.
Definition array.h:80
constexpr auto max_size() const noexcept -> size_type
Returns maximum number of elements container can hold.
Definition array.h:396
T value_type
Alias for data type used in class.
Definition array.h:38
constexpr auto at(size_type pos) const -> const_reference
Returns a const_reference to Array element at pos index. If pos is outside of container range,...
Definition array.h:127
constexpr auto size() const noexcept -> size_type
Returns number of elements in container.
Definition array.h:386
std::reverse_iterator< const_iterator > const_reverse_iterator
Alias for const reverse_iterator to data type used in class.
Definition array.h:100
constexpr auto rend() noexcept -> reverse_iterator
Returns reverse_iterator past the last element of reversed underlaying array structure.
Definition array.h:341
constexpr auto rbegin() const noexcept -> const_reverse_iterator
Returns const_reverse_iterator to the first element of reversed underlaying array structure.
Definition array.h:317
constexpr auto front() const -> const_reference
Returns const_reference to first Arary element.
Definition array.h:181
constexpr auto cend() const noexcept -> const_iterator
Returns const_iterator past last element of underlaying array structure.
Definition array.h:293
const value_type * const_iterator
Alias for const iterator to data type used in class.
Definition array.h:90
constexpr auto end() const noexcept -> const_iterator
Returns const_iterator past last element of underlaying array structure.
Definition array.h:281
value_type * pointer
Alias for pointer to data type used in class.
Definition array.h:59
constexpr auto back() -> reference
Returns reference to last Arary element.
Definition array.h:191
value_type * iterator
Alias for iterator to data type used in class.
Definition array.h:85
constexpr auto crend() const noexcept -> const_reverse_iterator
Returns const_reverse_iterator past the last element of reversed underlaying array structure.
Definition array.h:365
constexpr auto rend() const noexcept -> const_reverse_iterator
Returns const_reverse_iterator past the last element of reversed underlaying array structure.
Definition array.h:353
constexpr auto end() noexcept -> iterator
Returns iterator past last element of underlaying array structure.
Definition array.h:269
constexpr auto operator[](size_type pos) -> reference
Returns a reference to Array element at pos index. If pos is outside of container range,...
Definition array.h:145
value_type & reference
Alias for reference to data type used in class.
Definition array.h:73
constexpr auto rbegin() noexcept -> reverse_iterator
Returns reverse_iterator to the first element of reversed underlaying array structure.
Definition array.h:305
constexpr auto data() const noexcept -> const_pointer
Returns const_pointer to underlying array container.
Definition array.h:221
constexpr auto data() noexcept -> pointer
Returns pointer to underlying array container.
Definition array.h:211
std::size_t size_type
Alias for size type used in class.
Definition array.h:45
value_type m_data[N==0 ? 1 :N]
Underlaying fixed size array containing all elements Conditional size is used to handle zero sized ar...
Definition array.h:434
std::ptrdiff_t difference_type
Alias for pointer difference type.
Definition array.h:52
constexpr auto empty() const noexcept -> bool
Checks if container has elements.
Definition array.h:376
constexpr auto at(size_type pos) -> reference
Returns a reference to Array element at pos index. If pos is outside of container range,...
Definition array.h:109
constexpr auto begin() noexcept -> iterator
Returns iterator to first element.
Definition array.h:233
constexpr void swap(Array< T, N > &other) noexcept(std::is_nothrow_swappable_v< T >)
Exchanges content of current container with other container.
Definition array.h:420
constexpr auto cbegin() const noexcept -> const_iterator
Returns const_iterator to first element.
Definition array.h:257
const value_type * const_pointer
Alias for const pointer to data type used in class.
Definition array.h:66