dsplib 1.1.0
C++ DSP library for MATLAB-like coding
Loading...
Searching...
No Matches
span.h
1#pragma once
2
3#include <dsplib/assert.h>
4#include <dsplib/types.h>
5#include <dsplib/slice.h>
6#include <dsplib/traits.h>
7
8#include <cassert>
9#include <vector>
10
11namespace dsplib {
12
13template<class T>
14class mut_span_t;
15
16template<class T>
17class span_t;
18
19//span is a slice with a stride of 1
20//used to quickly access vector elements in functions (without memory allocation)
21
22//TODO: add concatenate syntax
23
24//mutable span
25template<typename T>
26class mut_span_t : public mut_slice_t<T>
27{
28public:
29 static_assert(!std::is_same_v<std::remove_cv_t<T>, bool>, "`bool` type is not supported");
30 static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable");
31
32 friend class span_t<T>;
33
34 explicit mut_span_t(T* data, int size)
35 : mut_slice_t<T>{data, 1, size} {
36 }
37
38 mut_span_t(const mut_span_t& v)
39 : mut_span_t(v.data_, v.count_) {
40 }
41
42 //disable for another trivially types (uint8_t, int16_t, long double etc)
43 template<typename U = T, std::enable_if_t<support_type_for_array<U>(), bool> = true>
45 : mut_span_t(v.data(), v.size()) {
46 }
47
48 mut_span_t(std::vector<T>& v)
49 : mut_span_t(v.data(), v.size()) {
50 }
51
52 [[nodiscard]] T* data() noexcept {
53 return this->data_;
54 }
55
56 [[nodiscard]] const T* data() const noexcept {
57 return this->data_;
58 }
59
60 [[nodiscard]] int size() const noexcept {
61 return this->count_;
62 }
63
64 T& operator[](size_t i) noexcept {
65 assert(i < size());
66 return this->data_[i];
67 }
68
69 //=mut_span<T>
70 mut_span_t& operator=(const mut_span_t& rhs) {
71 if (this == &rhs) {
72 return *this;
73 }
74 this->assign(rhs);
75 return *this;
76 }
77
78 //=mut_span<T2>
79 template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, bool> = true,
80 std::enable_if_t<is_scalar_v<T2>, bool> = true>
81 mut_span_t& operator=(const mut_span_t<T2>& rhs) {
82 this->assign(rhs);
83 return *this;
84 }
85
86 //=span_t<T>
87 mut_span_t& operator=(const span_t<T>& rhs) {
88 this->assign(rhs);
89 return *this;
90 }
91
92 //=span_t<T2>
93 template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, bool> = true,
94 std::enable_if_t<is_scalar_v<T2>, bool> = true>
95 mut_span_t& operator=(const span_t<T2>& rhs) {
96 this->assign(rhs);
97 return *this;
98 }
99
100 //=base_array<T2>
101 template<typename T2, std::enable_if_t<support_type_for_array<T2>(), bool> = true>
102 mut_span_t& operator=(const base_array<T2>& rhs) {
103 this->assign(make_span(rhs));
104 return *this;
105 }
106
107 mut_span_t& operator=(const T& rhs) {
108 std::fill(this->data_, (this->data_ + this->count_), rhs);
109 return *this;
110 }
111
112 template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, bool> = true,
113 std::enable_if_t<is_scalar_v<T2>, bool> = true>
114 mut_span_t& operator=(const T2& rhs) {
115 std::fill(this->data_, (this->data_ + this->count_), rhs);
116 return *this;
117 }
118
119 mut_span_t& operator=(const slice_t<T>& rhs) {
120 //TODO: override fast implementation for span
122 return *this;
123 }
124
125 mut_span_t& operator=(const mut_slice_t<T>& rhs) {
127 return *this;
128 }
129
130 mut_span_t& operator=(const std::initializer_list<T>& rhs) {
132 return *this;
133 }
134
135 using iterator = T*;
136 using const_iterator = const T*;
137
138 iterator begin() noexcept {
139 return this->data_;
140 }
141
142 iterator end() noexcept {
143 return this->data_ + this->count_;
144 }
145
146 const_iterator begin() const noexcept {
147 return this->data_;
148 }
149
150 const_iterator end() const noexcept {
151 return this->data_ + this->count_;
152 }
153
154 void assign(span_t<T> rhs) {
155 DSPLIB_ASSERT(this->size() == rhs.size(), "span size is not equal");
156 if (!is_same_memory(rhs)) {
157 std::memcpy(this->data(), rhs.data(), size() * sizeof(T));
158 } else {
159 std::memmove(this->data(), rhs.data(), size() * sizeof(T));
160 }
161 }
162
163 template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, bool> = true>
164 void assign(span_t<T2> rhs) {
165 DSPLIB_ASSERT(this->size() == rhs.size(), "span size is not equal");
166 auto* x = data();
167 const size_t n = size();
168 for (size_t i = 0; i < n; ++i) {
169 x[i] = rhs[i];
170 }
171 }
172
173 //TODO: add more checks
174 mut_span_t slice(int i1, int i2) const {
175 DSPLIB_ASSERT((i1 >= 0) && (i1 < this->count_), "invalid range");
176 DSPLIB_ASSERT((i2 > i1) && (i2 <= this->count_), "invalid range");
177 return mut_span_t(this->data_ + i1, (i2 - i1));
178 }
179
180 //---------------------------------------------------------------------------
181 //arithmetic operators
182 template<typename U = T, class T2, std::enable_if_t<is_scalar_v<U>, bool> = true>
183 mut_span_t& operator+=(const T2& rhs) noexcept(is_scalar_v<T2>) {
184 auto* x = data();
185 const size_t n = size();
186 using R = ResultType<T, T2>;
187 static_assert(std::is_same_v<T, R>, "The operation changes the type");
188 if constexpr (is_scalar_v<T2>) {
189 for (size_t i = 0; i < n; ++i) {
190 x[i] += rhs;
191 }
192 } else {
193 DSPLIB_ASSERT(n == rhs.size(), "Array lengths must be equal");
194 for (size_t i = 0; i < n; ++i) {
195 x[i] += rhs[i];
196 }
197 }
198 return *this;
199 }
200
201 template<typename U = T, class T2, std::enable_if_t<is_scalar_v<U>, bool> = true>
202 mut_span_t& operator-=(const T2& rhs) noexcept(is_scalar_v<T2>) {
203 auto* x = data();
204 const size_t n = size();
205 using R = ResultType<T, T2>;
206 static_assert(std::is_same_v<T, R>, "The operation changes the type");
207 if constexpr (is_scalar_v<T2>) {
208 for (size_t i = 0; i < n; ++i) {
209 x[i] -= rhs;
210 }
211 } else {
212 DSPLIB_ASSERT(n == rhs.size(), "Array lengths must be equal");
213 for (size_t i = 0; i < n; ++i) {
214 x[i] -= rhs[i];
215 }
216 }
217 return *this;
218 }
219
220 template<typename U = T, class T2, std::enable_if_t<is_scalar_v<U>, bool> = true>
221 mut_span_t& operator*=(const T2& rhs) noexcept(is_scalar_v<T2>) {
222 auto* x = data();
223 const size_t n = size();
224 using R = ResultType<T, T2>;
225 static_assert(std::is_same_v<T, R>, "The operation changes the type");
226 if constexpr (is_scalar_v<T2>) {
227 for (size_t i = 0; i < n; ++i) {
228 x[i] *= rhs;
229 }
230 } else {
231 DSPLIB_ASSERT(n == rhs.size(), "Array lengths must be equal");
232 for (size_t i = 0; i < n; ++i) {
233 x[i] *= rhs[i];
234 }
235 }
236 return *this;
237 }
238
239 template<typename U = T, class T2, std::enable_if_t<is_scalar_v<U>, bool> = true>
240 mut_span_t& operator/=(const T2& rhs) noexcept(is_scalar_v<T2>) {
241 auto* x = data();
242 const size_t n = size();
243 using R = ResultType<T, T2>;
244 static_assert(std::is_same_v<T, R>, "The operation changes the type");
245 if constexpr (is_scalar_v<T2>) {
246 for (size_t i = 0; i < n; ++i) {
247 x[i] /= rhs;
248 }
249 } else {
250 DSPLIB_ASSERT(n == rhs.size(), "Array lengths must be equal");
251 for (size_t i = 0; i < n; ++i) {
252 x[i] /= rhs[i];
253 }
254 }
255 return *this;
256 }
257
258 //---------------------------------------------------------------------------
259 template<class T2>
260 auto operator+(const T2& rhs) const {
261 return span_t<T>(*this) + rhs;
262 }
263
264 template<class T2>
265 auto operator-(const T2& rhs) const {
266 return span_t<T>(*this) - rhs;
267 }
268
269 template<class T2>
270 auto operator*(const T2& rhs) const {
271 return span_t<T>(*this) * rhs;
272 }
273
274 template<class T2>
275 auto operator/(const T2& rhs) const {
276 return span_t<T>(*this) / rhs;
277 }
278
279private:
280 bool is_same_memory(span_t<T> rhs) noexcept {
281 if (this->size() == 0 || rhs.size() == 0) {
282 return false;
283 }
284 auto start1 = this->data();
285 auto end1 = start1 + this->size();
286 auto start2 = rhs.data();
287 auto end2 = start2 + rhs.size();
288 return (start1 < end2) && (start2 < end1);
289 }
290};
291
292//immutable span
293template<typename T>
294class span_t : public slice_t<T>
295{
296public:
297 static_assert(!std::is_same_v<std::remove_cv_t<T>, bool>, "`bool` type is not supported");
298 static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable");
299
300 friend class mut_span_t<T>;
301
302 span_t() = default;
303
304 explicit span_t(const T* data, int size)
305 : slice_t<T>{data, 1, size} {
306 }
307
308 span_t(const mut_span_t<T>& v)
309 : span_t(v.data(), v.size()) {
310 }
311
312 template<typename U = T, std::enable_if_t<support_type_for_array<U>(), bool> = true>
313 span_t(const base_array<T>& v)
314 : span_t(v.data(), v.size()) {
315 }
316
317 span_t(const std::vector<T>& v)
318 : span_t(v.data(), v.size()) {
319 }
320
321 [[nodiscard]] const T* data() const noexcept {
322 return this->data_;
323 }
324
325 [[nodiscard]] int size() const noexcept {
326 return this->count_;
327 }
328
329 const T& operator[](size_t i) const noexcept {
330 assert(i < size());
331 return this->data_[i];
332 }
333
334 using const_iterator = const T*;
335
336 const_iterator begin() const noexcept {
337 return this->data_;
338 }
339
340 const_iterator end() const noexcept {
341 return this->data_ + this->count_;
342 }
343
344 span_t slice(int i1, int i2) const {
345 DSPLIB_ASSERT((i1 >= 0) && (i1 < this->count_), "invalid range");
346 DSPLIB_ASSERT((i2 > i1) && (i2 <= this->count_), "invalid range");
347 return span_t(this->data_ + i1, (i2 - i1));
348 }
349
350 //---------------------------------------------------------------------------
351 //arithmetic operators
352 template<class T2>
353 auto operator+(const T2& rhs) const {
354 auto* x = data();
355 const size_t n = size();
356 using R = ResultType<T, T2>;
357 base_array<R> res(n);
358 if constexpr (is_scalar_v<T2>) {
359 for (size_t i = 0; i < n; ++i) {
360 res[i] = x[i] + rhs;
361 }
362 } else {
363 DSPLIB_ASSERT(n == rhs.size(), "Array lengths must be equal");
364 for (size_t i = 0; i < n; ++i) {
365 res[i] = x[i] + rhs[i];
366 }
367 }
368 return res;
369 }
370
371 template<class T2>
372 auto operator-(const T2& rhs) const {
373 auto* x = data();
374 const size_t n = size();
375 using R = ResultType<T, T2>;
376 base_array<R> res(n);
377 if constexpr (is_scalar_v<T2>) {
378 for (size_t i = 0; i < n; ++i) {
379 res[i] = x[i] - rhs;
380 }
381 } else {
382 DSPLIB_ASSERT(n == rhs.size(), "Array lengths must be equal");
383 for (size_t i = 0; i < n; ++i) {
384 res[i] = x[i] - rhs[i];
385 }
386 }
387 return res;
388 }
389
390 template<class T2>
391 auto operator*(const T2& rhs) const {
392 auto* x = data();
393 const size_t n = size();
394 using R = ResultType<T, T2>;
395 base_array<R> res(n);
396 if constexpr (is_scalar_v<T2>) {
397 for (size_t i = 0; i < n; ++i) {
398 res[i] = x[i] * rhs;
399 }
400 } else {
401 DSPLIB_ASSERT(n == rhs.size(), "Array lengths must be equal");
402 for (size_t i = 0; i < n; ++i) {
403 res[i] = x[i] * rhs[i];
404 }
405 }
406 return res;
407 }
408
409 template<class T2>
410 auto operator/(const T2& rhs) const {
411 auto* x = data();
412 const size_t n = size();
413 using R = ResultType<T, T2>;
414 base_array<R> res(n);
415 if constexpr (is_scalar_v<T2>) {
416 for (size_t i = 0; i < n; ++i) {
417 res[i] = x[i] / rhs;
418 }
419 } else {
420 DSPLIB_ASSERT(n == rhs.size(), "Array lengths must be equal");
421 for (size_t i = 0; i < n; ++i) {
422 res[i] = x[i] / rhs[i];
423 }
424 }
425 return res;
426 }
427};
428
429//------------------------------------------------------------------------------------------------
430template<typename T>
431span_t<T> make_span(const T* x, size_t nx) noexcept {
432 return span_t<T>(x, nx);
433}
434
435template<typename T>
436mut_span_t<T> make_span(T* x, size_t nx) noexcept {
437 return mut_span_t<T>(x, nx);
438}
439
440template<typename T>
441span_t<T> make_span(const std::vector<T>& x) noexcept {
442 return span_t<T>(x.data(), x.size());
443}
444
445template<typename T>
446mut_span_t<T> make_span(std::vector<T>& x) noexcept {
447 return mut_span_t<T>(x.data(), x.size());
448}
449
450template<typename T>
451span_t<T> make_span(const base_array<T>& x) noexcept {
452 return span_t<T>(x.data(), x.size());
453}
454
455template<typename T>
456mut_span_t<T> make_span(base_array<T>& x) noexcept {
457 return mut_span_t<T>(x.data(), x.size());
458}
459
460using span_real = span_t<real_t>;
461using span_cmplx = span_t<cmplx_t>;
462
463template<typename T>
465{
466public:
467 explicit inplace_span_t(mut_span_t<T> v) noexcept
468 : d_{std::move(v)} {
469 }
470
471 mut_span_t<T> get() noexcept {
472 return d_;
473 }
474
475private:
476 mut_span_t<T> d_;
477};
478
479template<typename T>
481 return inplace_span_t(make_span(x));
482}
483
484template<typename T>
485inplace_span_t<T> inplace(std::vector<T>& x) {
486 return inplace_span_t(make_span(x));
487}
488
489template<typename T>
490inplace_span_t<T> inplace(mut_span_t<T> x) {
491 return inplace_span_t(x);
492}
493
494using inplace_real = inplace_span_t<real_t>;
495using inplace_cmplx = inplace_span_t<cmplx_t>;
496
497} // namespace dsplib
base dsplib array type
Definition array.h:25
Definition span.h:465
Mutable slice object.
Definition slice.h:100
Definition span.h:27
Non-mutable slice object.
Definition slice.h:27
Definition span.h:295