|
| 1 | +#pragma once |
| 2 | + |
| 3 | +#include <array> |
| 4 | +#include <cstddef> |
| 5 | +#include <stdexcept> |
| 6 | + |
| 7 | +namespace vtr { |
| 8 | + |
| 9 | +/** |
| 10 | + * @brief A std::array wrapper that can be indexed by a vtr::StrongId. |
| 11 | + * |
| 12 | + * @tparam K Key type (e.g., vtr::StrongId) |
| 13 | + * @tparam V Value type |
| 14 | + * @tparam N Number of elements |
| 15 | + */ |
| 16 | +template<typename K, typename V, std::size_t N> |
| 17 | +class array { |
| 18 | + public: |
| 19 | + using key_type = K; |
| 20 | + using value_type = V; |
| 21 | + using size_type = std::size_t; |
| 22 | + using reference = V&; |
| 23 | + using const_reference = const V&; |
| 24 | + using iterator = typename std::array<V, N>::iterator; |
| 25 | + using const_iterator = typename std::array<V, N>::const_iterator; |
| 26 | + |
| 27 | + /** |
| 28 | + * @brief Construct a vtr::array from a list of values. |
| 29 | + * |
| 30 | + * This constructor allows direct brace-initialization of the array: |
| 31 | + * @code |
| 32 | + * vtr::array<MyId, int, 3> arr{1, 2, 3}; |
| 33 | + * @endcode |
| 34 | + * |
| 35 | + * @tparam Args Types of the values being passed. All must be convertible to V. |
| 36 | + * @param args The values to initialize the array with. Must match the array size. |
| 37 | + *//** |
| 38 | + * @brief Construct a vtr::array from a list of values. |
| 39 | + * |
| 40 | + * This constructor allows direct brace-initialization of the array: |
| 41 | + * @code |
| 42 | + * vtr::array<MyId, int, 3> arr{1, 2, 3}; |
| 43 | + * @endcode |
| 44 | + * |
| 45 | + * @tparam Args Types of the values being passed. All must be convertible to V. |
| 46 | + * @param args The values to initialize the array with. Must match the array size. |
| 47 | + */ |
| 48 | + template<typename... Args, |
| 49 | + typename = std::enable_if_t<sizeof...(Args) == N && |
| 50 | + std::conjunction_v<std::is_convertible<Args, V>...>>> |
| 51 | + constexpr array(Args&&... args) |
| 52 | + : data_{ { std::forward<Args>(args)... } } {} |
| 53 | + |
| 54 | + |
| 55 | + |
| 56 | + ///@brief Access element with strong ID |
| 57 | + reference operator[](K id) { |
| 58 | + return data_[static_cast<size_type>(id)]; |
| 59 | + } |
| 60 | + |
| 61 | + ///@brief Access element with strong ID (const) |
| 62 | + const_reference operator[](K id) const { |
| 63 | + return data_[static_cast<size_type>(id)]; |
| 64 | + } |
| 65 | + |
| 66 | + ///@brief Access element with bounds checking |
| 67 | + reference at(K id) { |
| 68 | + return data_.at(static_cast<size_type>(id)); |
| 69 | + } |
| 70 | + |
| 71 | + ///@brief Access element with bounds checking (const) |
| 72 | + const_reference at(K id) const { |
| 73 | + return data_.at(static_cast<size_type>(id)); |
| 74 | + } |
| 75 | + |
| 76 | + // Iterators |
| 77 | + iterator begin() { return data_.begin(); } |
| 78 | + iterator end() { return data_.end(); } |
| 79 | + const_iterator begin() const { return data_.begin(); } |
| 80 | + const_iterator end() const { return data_.end(); } |
| 81 | + const_iterator cbegin() const { return data_.cbegin(); } |
| 82 | + const_iterator cend() const { return data_.cend(); } |
| 83 | + |
| 84 | + // Size |
| 85 | + constexpr size_type size() const { return N; } |
| 86 | + constexpr bool empty() const { return N == 0; } |
| 87 | + |
| 88 | + // Data |
| 89 | + V* data() { return data_.data(); } |
| 90 | + const V* data() const { return data_.data(); } |
| 91 | + |
| 92 | + // Front/Back |
| 93 | + reference front() { return data_.front(); } |
| 94 | + const_reference front() const { return data_.front(); } |
| 95 | + reference back() { return data_.back(); } |
| 96 | + const_reference back() const { return data_.back(); } |
| 97 | + |
| 98 | + // Fill |
| 99 | + void fill(const V& value) { data_.fill(value); } |
| 100 | + |
| 101 | + private: |
| 102 | + std::array<V, N> data_; |
| 103 | +}; |
| 104 | + |
| 105 | +} // namespace vtr |
0 commit comments