PP's Ndarray
Loading...
Searching...
No Matches
ndarray-11.hpp
Go to the documentation of this file.
1
8#ifndef __NDARRAY_HPP__
9#define __NDARRAY_HPP__
10
11#include <vector>
12#include <sstream>
13#include <initializer_list>
14#include <type_traits>
15#include <string>
16#include <regex>
17#include <array>
18
19namespace pp
20{
21
33 template<class...> struct conjunction : std::true_type {};
34 template<class B1> struct conjunction<B1> : B1 {};
35 template<class B1, class... Bn>
36 struct conjunction<B1, Bn...>
37 : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
44 template <std::size_t ...> struct index_sequence {};
45 template <std::size_t N, std::size_t ... Next>
46 struct indexSequenceHelper : public indexSequenceHelper<N-1U, N-1U, Next...> {};
47 template <std::size_t ... Next>
48 struct indexSequenceHelper<0U, Next ... >
49 { using type = index_sequence<Next ... >; };
50 template <std::size_t N>
51 using make_index_sequence = typename indexSequenceHelper<N>::type;
52
56 struct Range
57 {
58 int start;
59 int stop;
60 int step;
61 bool has_stop;
62
72 Range() : start(0), stop(0), step(1), has_stop(false) {}
73
74 Range(const std::string &str) : Range(parseRange(str))
75 {}
76
77 Range(int start, int stop, int step, bool has_stop=true) : start(start), stop(stop), step(step), has_stop(has_stop)
78 {}
79
80 static Range parseRange(const std::string &str)
81 {
82 std::smatch sm;
83 int start, stop, step;
84 bool has_stop;
85
86 if(std::regex_match(str, sm, std::regex("^\\s*(-?\\d+)?\\s*:\\s*(-?\\d+)?\\s*:\\s*(-?\\d+)?\\s*$")))
87 {
88 // for slice format like "1:2:3"
89 start = (sm[1] == "")? 0: std::stoi( sm[1] );
90 stop = (sm[2] == "")? 0: std::stoi( sm[2] );
91 step = (sm[3] == "")? 1: std::stoi( sm[3] );
92
93 has_stop = (sm[2] != "");
94 }
95 else if(std::regex_match(str, sm, std::regex("^\\s*(-?\\d+)?\\s*:\\s*(-?\\d+)?\\s*$")))
96 {
97 // for slice format like "1:2"
98 start = (sm[1] == "")? 0: std::stoi( sm[1] );
99 stop = (sm[2] == "")? 0: std::stoi( sm[2] );
100 step = 1;
101
102 has_stop = (sm[2] != "");
103 }
104 else
105 {
106 // not support slice format like "1"
107 throw std::invalid_argument("Invalid slice format");
108 }
109
110 return {start, stop, step, has_stop};
111 }
112 };
113
114
116 template< typename Dtype, typename Allocator = std::allocator<Dtype> >
117 struct BaseVector : public std::vector<Dtype, Allocator>
118 {
119 using std::vector<Dtype, Allocator>::vector;
120 ~BaseVector() = default;
121
122 // toString for types that are arithmetic or std::string
123 template <typename U = Dtype>
124 auto toString(int indentLevel = 0) const ->
125 typename std::enable_if<std::integral_constant<bool, std::is_arithmetic<U>::value || std::is_same<U, std::string>::value>::value, std::string>::type
126 {
127 if (this->empty()) return "[ ]";
128 std::stringstream ss;
129 for (size_t i = 0; i < this->size(); ++i) {
130 ss << (i==0? "[ ": "")
131 << this->at(i)
132 << (i != this->size()-1 ? ", " : " ]");
133 }
134 return ss.str();
135 }
136
137 // toString for types that have toString() method
138 template <typename U = Dtype>
139 auto toString(int indentLevel = 0) const ->
140 decltype(std::declval<U>().toString())
141 {
142 if (this->empty()) return "[ ]";
143 std::stringstream ss;
144 std::string indent(indentLevel * 2, ' ');
145 for (size_t i = 0; i < this->size(); ++i) {
146 // Recursive call for nested vectors
147 ss << (i==0? "[\n": "")
148 << indent
149 << " " << (*this)[i].toString(indentLevel + 1)
150 << (i != this->size()-1 ? "," : "")
151 << "\n";
152 }
153 ss << indent << "]";
154 return ss.str();
155 }
156
157 Dtype& at(int idx)
158 {
159 if (idx < 0 ) {
160 idx += this->size();
161 if (idx < 0) throw std::out_of_range("Index out of range");
162 }
163
164 return std::vector<Dtype>::at(idx);
165 }
166
167 const Dtype& at(int idx) const
168 {
169 if (idx < 0 ) {
170 idx += this->size();
171 if (idx < 0) throw std::out_of_range("Index out of range");
172 }
173
174 return std::vector<Dtype>::at(idx);
175 }
176
177 friend std::ostream& operator<<(std::ostream& os, const BaseVector<Dtype, Allocator>& vec)
178 {
179 return os << vec.toString();
180 }
181
182
183 };
184
192 // primary template
193 template<typename Dtype, std::size_t dim>
194 struct Inner : public BaseVector<Inner<Dtype, dim - 1>>
195 {
196 static_assert(dim >= 1, "Dimension must be greater than zero!");
197
198 // Construct in Recursive
199 template<typename... Args>
200 Inner(std::size_t n = 0, Args... args) : BaseVector<Inner<Dtype, dim - 1>>(n, Inner<Dtype, dim - 1>(args...))
201 {}
202
204 Inner(std::initializer_list<Inner<Dtype, dim - 1>> initList) : BaseVector<Inner<Dtype, dim - 1>>(initList)
205 {}
206
208 template<typename T, std::size_t M, typename = typename std::enable_if<(M < dim)>::type>
209 Inner(const Inner<T, M>& lowerDimInner)
210 {
211 this->push_back(Inner<T, dim - 1>(lowerDimInner));
212 }
213
221 template<typename... Indices,
222 typename std::enable_if<(sizeof...(Indices) > 0), int>::type = 0,
223 typename std::enable_if<conjunction<std::is_integral<Indices>...>::value, int>::type = 0>
224 auto operator()(int idx, Indices... indices) -> decltype(this->at(idx)(indices...))
225 {
226 return this->at(idx).operator()(indices...);
227 }
228
229 template<typename... Indices,
230 typename std::enable_if<(sizeof...(Indices) > 0), int>::type = 0,
231 typename std::enable_if<conjunction<std::is_integral<Indices>...>::value, int>::type = 0>
232 const Inner<Dtype, dim-1>& operator()(int idx, Indices... indices) const
233 {
234 return this->at(idx).operator()(indices...);
235 }
236
237 // For when there is only one index
238 Inner<Dtype, dim-1>& operator()(int idx)
239 {
240 return this->at(idx);
241 }
242
243 const Inner<Dtype, dim-1>& operator()(int idx) const
244 {
245 return this->at(idx);
246 }
247
255 Inner<Dtype, dim> operator[](const std::string& input) const
256 {
257 std::string str(input);
258
259 std::array<Range, dim> slices;
260 std::size_t i = 0;
261
262 std::regex re("\\s*,\\s*");
263 std::sregex_token_iterator first{str.begin(), str.end(), re, -1}, last;
264 for (; first != last; ++first) {
265 if(i >= dim) throw std::invalid_argument("Too many slices");
266 slices[i++] = Range::parseRange(*first);
267 }
268
269 return slice(slices, 0, i);
270 }
271
272
273 template<std::size_t length>
274 Inner<Dtype, dim> slice(const std::array<Range, length> slices, int start, const int& end) const
275 {
276 if(start == end) return *this;
277
278 Inner<Dtype, dim> result;
279
280 Range r = slices[start];
281 std::size_t stop = r.has_stop? r.stop: this->size();
282
283 for(int i = r.start; i < stop; i += r.step)
284 {
285 result.push_back(this->at(i).slice(slices, start + 1, end));
286 }
287
288 return result;
289 }
290 };
291
293 // partial specialization where dimension is 1
294 template<typename Dtype>
296 {
297 Inner(std::size_t n = 0, const Dtype& val = Dtype{}) : BaseVector<Dtype>(n, val)
298 {}
299
300 Inner(std::initializer_list<Dtype> initList) : BaseVector<Dtype>(initList)
301 {}
302
303 /* Indexing */
304 Dtype& operator()(int idx) {
305 return this->at(idx);
306 }
307
308 const Dtype& operator()(int idx) const {
309 return this->at(idx);
310 }
311
312 /* Slicing */
313 Inner<Dtype, 1> operator[](const std::string& input) const
314 {
315 std::string str(input);
316 std::array<Range, 1> slices;
317
318 Range range = Range::parseRange(str);
319 slices[0] = range;
320
321 return slice(slices);
322 }
323
324 template<std::size_t length>
325 Inner<Dtype, 1> slice(const std::array<Range, length> slices, int start, const int& end) const
326 {
327 if(start == end) return *this;
328
329 Inner<Dtype, 1> result;
330
331 Range s = slices[start];
332 std::size_t stop = s.has_stop? s.stop: this->size();
333
334 for(int i = s.start; i < stop; i += s.step)
335 {
336 result.push_back(this->at(i));
337 }
338
339 return result;
340 }
341
342 };
373 template<typename Dtype>
374 struct Ndarray
375 {
376 template<std::size_t dimention>
378 };
379
388 template<typename Dtype, std::size_t dim>
390 {
391 using Inner<Dtype, dim>::Inner;
392 };
393
395}
396
397#endif
Class with common methods.
Definition ndarray-11.hpp:118
Class for multi-dimensional array.
Definition ndarray-11.hpp:195
Inner(std::initializer_list< Inner< Dtype, dim - 1 > > initList)
Constructor to handle initializer list for nested lists.
Definition ndarray-11.hpp:204
An interface to create Ndarray.
Definition ndarray-11.hpp:375
Class for slicing index.
Definition ndarray-11.hpp:57
bool has_stop
Flag to check if stop is given.
Definition ndarray-11.hpp:61
Range()
Slicing constructor.
Definition ndarray-11.hpp:72
C++11 std::conjunction implementation.
Definition ndarray-11.hpp:33
C++11 std::index_sequence implementation. "
Definition ndarray-11.hpp:46
C++11 std::index_sequence implementation.
Definition ndarray-11.hpp:44