|
1 | 1 | //---------------------------------------------------------------------------------- |
2 | 2 | // Name: xarray.h |
3 | | -// Purpose: Definition of vector of xnodes. |
| 3 | +// Purpose: Custom array class for xnode objects. |
4 | 4 | // Author: Piotr Likus |
5 | 5 | // Created: 01/09/2015 |
6 | | -// Last change: |
| 6 | +// Last change: 15/05/2025 |
7 | 7 | // License: BSD |
8 | 8 | //---------------------------------------------------------------------------------- |
9 | 9 |
|
10 | 10 | #ifndef __XNODE_ARRAY_H__ |
11 | 11 | #define __XNODE_ARRAY_H__ |
12 | 12 |
|
13 | 13 | #include <vector> |
| 14 | +#include <initializer_list> |
| 15 | +#include <cassert> |
14 | 16 | #include "xnode.h" |
15 | 17 |
|
16 | | -typedef std::vector<xnode> xarray; |
| 18 | +// Forward declaration |
| 19 | +class xarray; |
17 | 20 |
|
| 21 | +// Type code registration for xarray |
18 | 22 | template<> |
19 | 23 | struct xnode_type_code<xarray> { |
20 | 24 | enum { value = 16 }; // Ensure this doesn't conflict with other type codes |
21 | 25 | }; |
22 | 26 |
|
23 | | -#endif |
| 27 | +/** |
| 28 | + * Custom array class for xnode objects. |
| 29 | + * Provides a limited array interface with static initializer "of" that accepts variable number of xnode objects. |
| 30 | + */ |
| 31 | +class xarray { |
| 32 | +public: |
| 33 | + // Type definitions |
| 34 | + using value_type = xnode; |
| 35 | + using container_type = std::vector<value_type>; |
| 36 | + using reference = container_type::reference; |
| 37 | + using const_reference = container_type::const_reference; |
| 38 | + using iterator = container_type::iterator; |
| 39 | + using const_iterator = container_type::const_iterator; |
| 40 | + using size_type = container_type::size_type; |
| 41 | + using difference_type = container_type::difference_type; |
| 42 | + |
| 43 | + // Constructors |
| 44 | + xarray() = default; |
| 45 | + |
| 46 | + // Copy constructor |
| 47 | + xarray(const xarray& other) = default; |
| 48 | + |
| 49 | + // Move constructor |
| 50 | + xarray(xarray&& other) noexcept = default; |
| 51 | + |
| 52 | + // Construct from initializer list of xnodes |
| 53 | + xarray(std::initializer_list<value_type> init) : data_(init) {} |
| 54 | + |
| 55 | + // Assignment operators |
| 56 | + xarray& operator=(const xarray& other) = default; |
| 57 | + xarray& operator=(xarray&& other) noexcept = default; |
| 58 | + |
| 59 | + // Basic functions |
| 60 | + bool empty() const { return data_.empty(); } |
| 61 | + size_type size() const { return data_.size(); } |
| 62 | + |
| 63 | + // Element access |
| 64 | + reference at(size_type pos) { return data_.at(pos); } |
| 65 | + const_reference at(size_type pos) const { return data_.at(pos); } |
| 66 | + |
| 67 | + reference operator[](size_type pos) { return data_[pos]; } |
| 68 | + const_reference operator[](size_type pos) const { return data_[pos]; } |
| 69 | + |
| 70 | + // Iterators |
| 71 | + iterator begin() { return data_.begin(); } |
| 72 | + const_iterator begin() const { return data_.begin(); } |
| 73 | + const_iterator cbegin() const { return data_.cbegin(); } |
| 74 | + |
| 75 | + iterator end() { return data_.end(); } |
| 76 | + const_iterator end() const { return data_.end(); } |
| 77 | + const_iterator cend() const { return data_.cend(); } |
| 78 | + |
| 79 | + // Capacity manipulation |
| 80 | + void reserve(size_type new_cap) { data_.reserve(new_cap); } |
| 81 | + size_type capacity() const { return data_.capacity(); } |
| 82 | + |
| 83 | + // Modifiers |
| 84 | + void clear() { data_.clear(); } |
| 85 | + void push_back(const value_type& value) { data_.push_back(value); } |
| 86 | + void push_back(value_type&& value) { data_.push_back(std::move(value)); } |
| 87 | + iterator insert(const_iterator pos, const value_type& value) { return data_.insert(pos, value); } |
| 88 | + iterator insert(const_iterator pos, value_type&& value) { return data_.insert(pos, std::move(value)); } |
| 89 | + iterator erase(const_iterator pos) { return data_.erase(pos); } |
| 90 | + void resize(size_type count, const value_type& value = value_type()) { data_.resize(count, value); } |
| 91 | + // C++17 and above: Static factory function that accepts variable number of arguments |
| 92 | + // and converts them directly to xnode objects |
| 93 | + |
| 94 | + #if __cplusplus >= 201703L |
| 95 | + // C++17 version that auto-converts values to xnode objects |
| 96 | + template <typename... Args> |
| 97 | + static xarray of(Args&&... args) { |
| 98 | + xarray result; |
| 99 | + result.reserve(sizeof...(args)); |
| 100 | + (result.push_back(xnode::value_of(std::forward<Args>(args))), ...); // Fold expression (C++17) |
| 101 | + return result; |
| 102 | + } |
| 103 | + |
| 104 | + // C++17 version for direct xnode objects (to avoid unnecessary conversion) |
| 105 | + template <typename... Args> |
| 106 | + static xarray of_nodes(const xnode& first, Args&&... args) { |
| 107 | + xarray result; |
| 108 | + result.reserve(sizeof...(args) + 1); |
| 109 | + result.push_back(first); |
| 110 | + (result.push_back(std::forward<Args>(args)), ...); // Fold expression (C++17) |
| 111 | + return result; |
| 112 | + } |
| 113 | + |
| 114 | + // Specialization for empty array |
| 115 | + static xarray of_nodes() { |
| 116 | + return xarray(); |
| 117 | + } |
| 118 | + #else |
| 119 | + // Pre-C++17: Recursive variadic template implementations |
| 120 | + |
| 121 | + // Version that requires explicit xnode arguments |
| 122 | + static xarray of() { |
| 123 | + return xarray(); |
| 124 | + } |
| 125 | + |
| 126 | + template <typename... Args> |
| 127 | + static xarray of(const xnode& first, const Args&... rest) { |
| 128 | + xarray result; |
| 129 | + result.reserve(sizeof...(rest) + 1); |
| 130 | + result.push_back(first); |
| 131 | + appendToArray(result, rest...); |
| 132 | + return result; |
| 133 | + } |
| 134 | + |
| 135 | + // Alias for consistency with the C++17 version |
| 136 | + static xarray of_nodes() { |
| 137 | + return xarray(); |
| 138 | + } |
| 139 | + |
| 140 | + template <typename... Args> |
| 141 | + static xarray of_nodes(const xnode& first, const Args&... rest) { |
| 142 | + return of(first, rest...); |
| 143 | + } |
| 144 | + |
| 145 | + // Helper function for pre-C++17 implementation |
| 146 | + private: |
| 147 | + static void appendToArray(xarray& /* array */) { |
| 148 | + // Base case: no more elements to add |
| 149 | + } |
| 150 | + |
| 151 | + template <typename... Args> |
| 152 | + static void appendToArray(xarray& array, const xnode& first, const Args&... rest) { |
| 153 | + array.push_back(first); |
| 154 | + appendToArray(array, rest...); |
| 155 | + } |
| 156 | + public: |
| 157 | + #endif |
| 158 | + |
| 159 | + // Compatibility with algorithms that expect STL containers |
| 160 | + bool operator==(const xarray& other) const { return data_ == other.data_; } |
| 161 | + bool operator!=(const xarray& other) const { return data_ != other.data_; } |
| 162 | + bool operator<(const xarray& other) const { return data_ < other.data_; } |
| 163 | + |
| 164 | +private: |
| 165 | + container_type data_; |
| 166 | +}; |
| 167 | + |
| 168 | +#endif // __XNODE_ARRAY_H__ |
24 | 169 |
|
0 commit comments