Skip to content

Commit 9432399

Browse files
authored
inplace span support (#84)
Use `inplace' to explicitly specify calculations on the input data. - Add `inplace_span_t<T>` class; - Add `inplace` function; - Add some inplace functions; - Add inplace version of `solve` for `FftPlanC`; - Code refactoring; - Remove deprecated; - Enable cache for fftw (thread-safe problems);
1 parent 6813614 commit 9432399

File tree

24 files changed

+464
-329
lines changed

24 files changed

+464
-329
lines changed

CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ if (DSPLIB_FFT_BACKEND STREQUAL "fftw")
7171
endif()
7272
set(FFT_INCLUDES ${FFTW_INCLUDES})
7373
set(DSPLIB_EXCLUDE_FFT ON)
74-
set(DSPLIB_FFT_CACHE_SIZE 0) # FFTW has its own cache
7574
elseif (DSPLIB_FFT_BACKEND STREQUAL "ne10")
7675
find_package(NE10 REQUIRED)
7776
if (DSPLIB_USE_FLOAT32)

include/dsplib/czt.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@ class CztPlan : public FftPlanC
1818

1919
[[nodiscard]] int size() const noexcept final;
2020

21-
arr_cmplx operator()(span_t<cmplx_t> x) const {
22-
return this->solve(x);
23-
}
24-
2521
private:
2622
std::shared_ptr<CztPlanImpl> _d;
2723
};

include/dsplib/fft.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ class FftPlanC
2525
r = this->solve(x);
2626
}
2727

28+
//inplace FFT implementation
29+
virtual void solve(inplace_cmplx inp) const {
30+
//default non optimal implementation with temp array
31+
auto x = inp.get();
32+
const auto y = this->solve(x);
33+
x.assign(y);
34+
}
35+
2836
[[nodiscard]] virtual int size() const noexcept = 0;
2937
};
3038

include/dsplib/fir.h

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,22 @@ class FirFilter
1818
, _d(h.size() - 1) {
1919
}
2020

21-
//main processing
22-
base_array<T> process(const base_array<T>& s) {
23-
if (_h.size() == 1) {
24-
return s * _h[0];
25-
}
26-
27-
auto x = _d | s;
28-
auto r = FirFilter::conv(x, _h);
29-
int nd = _h.size() - 1;
30-
int nx = x.size();
31-
_d = x.slice((nx - nd), nx);
21+
base_array<T> process(const span_t<T>& s) {
22+
base_array<T> r(s);
23+
this->process(inplace(r));
3224
return r;
3325
}
3426

27+
void process(inplace_span_t<T> si) {
28+
auto s = si.get();
29+
auto x = concatenate(_d, s);
30+
FirFilter::conv(x, _h);
31+
s.assign(x.slice(0, s.size()));
32+
const int nd = _d.size();
33+
const int nx = x.size();
34+
_d.slice(0, nd) = x.slice((nx - nd), nx);
35+
}
36+
3537
//current impulse response
3638
[[nodiscard]] const base_array<T>& coeffs() const {
3739
return _h;
@@ -41,14 +43,13 @@ class FirFilter
4143
return _h;
4244
}
4345

44-
//convolution operation
45-
static base_array<T> conv(const base_array<T>& x, const base_array<T>& h);
46-
47-
base_array<T> operator()(const base_array<T>& x) {
46+
base_array<T> operator()(const span_t<T>& x) {
4847
return this->process(x);
4948
}
5049

5150
private:
51+
static void conv(mut_span_t<T> x, span_t<T> h);
52+
5253
base_array<T> _h; ///< impulse response
5354
base_array<T> _d; ///< filter delay
5455
};

include/dsplib/iterator.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,6 @@ struct SliceIterator
5555
return lhs.ptr_ != rhs.ptr_;
5656
};
5757

58-
friend bool operator>(const SliceIterator& lhs, const SliceIterator& rhs) noexcept {
59-
return lhs.ptr_ > rhs.ptr_;
60-
};
61-
62-
friend bool operator<(const SliceIterator& lhs, const SliceIterator& rhs) noexcept {
63-
return lhs.ptr_ < rhs.ptr_;
64-
};
65-
6658
private:
6759
pointer ptr_;
6860
int step_{1};

include/dsplib/math.h

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
namespace dsplib {
99

10+
//TODO: mark noexcept
11+
1012
//exponential
1113
arr_real exp(const arr_real& arr);
1214
real_t exp(real_t v);
@@ -53,20 +55,23 @@ int argmin(span_real arr);
5355
int argmin(span_cmplx arr);
5456

5557
//absolute value and complex magnitude
56-
arr_real abs(const arr_real& arr);
57-
real_t abs(real_t v);
58-
arr_real abs(const arr_cmplx& arr);
59-
real_t abs(cmplx_t v);
58+
arr_real abs(const arr_real& arr) noexcept;
59+
real_t abs(real_t v) noexcept;
60+
arr_real abs(const arr_cmplx& arr) noexcept;
61+
real_t abs(cmplx_t v) noexcept;
62+
void abs(inplace_real arr) noexcept;
6063

6164
//phase angle in the interval [-pi, pi] for each element of a complex array z
6265
arr_real angle(const arr_cmplx& arr);
6366
real_t angle(cmplx_t v);
6467

6568
//round
66-
real_t round(const real_t& x);
67-
cmplx_t round(const cmplx_t& x);
68-
arr_real round(const arr_real& arr);
69-
arr_cmplx round(const arr_cmplx& arr);
69+
real_t round(const real_t& x) noexcept;
70+
cmplx_t round(const cmplx_t& x) noexcept;
71+
arr_real round(const arr_real& arr) noexcept;
72+
arr_cmplx round(const arr_cmplx& arr) noexcept;
73+
void round(inplace_real arr) noexcept;
74+
void round(inplace_cmplx arr) noexcept;
7075

7176
//array sum
7277
real_t sum(const arr_real& arr);
@@ -113,7 +118,9 @@ arr_real imag(const arr_cmplx& x);
113118
real_t imag(const cmplx_t& x);
114119

115120
//complex pairing
116-
arr_cmplx conj(const arr_cmplx& x);
121+
arr_cmplx conj(const arr_cmplx& x) noexcept;
122+
123+
void conj(inplace_cmplx x) noexcept;
117124

118125
constexpr cmplx_t conj(const cmplx_t& x) noexcept {
119126
return x.conj();
@@ -181,8 +188,9 @@ arr_cmplx power(const arr_cmplx& x, int n);
181188

182189
//square root (only positive values)
183190
//TODO: add complex result for negative or complex input
184-
real_t sqrt(real_t x);
185-
arr_real sqrt(const arr_real& x);
191+
real_t sqrt(real_t x) noexcept;
192+
arr_real sqrt(const arr_real& arr) noexcept;
193+
void sqrt(inplace_real arr) noexcept;
186194

187195
//array log
188196
arr_real log(const arr_real& arr);
@@ -210,7 +218,7 @@ arr_real upsample(const arr_real& arr, int n, int phase = 0);
210218
arr_cmplx upsample(const arr_cmplx& arr, int n, int phase = 0);
211219

212220
//abs(x)^2
213-
arr_real abs2(const arr_cmplx& x);
221+
arr_real abs2(const arr_cmplx& x) noexcept;
214222

215223
constexpr real_t abs2(const cmplx_t& x) noexcept {
216224
return x.abs2();
@@ -269,16 +277,20 @@ inline cmplx_t sign(const cmplx_t& x) noexcept {
269277

270278
//----------------------------------------------------------------------------------------
271279
//convert power <-> decibels: db = 10 * log10(pow)
272-
real_t pow2db(real_t v);
273-
arr_real pow2db(const arr_real& v);
274-
real_t db2pow(real_t v);
275-
arr_real db2pow(const arr_real& v);
280+
real_t pow2db(real_t v) noexcept;
281+
arr_real pow2db(const arr_real& arr) noexcept;
282+
real_t db2pow(real_t v) noexcept;
283+
arr_real db2pow(const arr_real& arr) noexcept;
284+
void pow2db(inplace_real arr) noexcept;
285+
void db2pow(inplace_real arr) noexcept;
276286

277287
//convert magnitude <-> decibels: db = 20 * log10(mag)
278-
real_t mag2db(real_t v);
279-
arr_real mag2db(const arr_real& v);
280-
real_t db2mag(real_t v);
281-
arr_real db2mag(const arr_real& v);
288+
real_t mag2db(real_t v) noexcept;
289+
arr_real mag2db(const arr_real& arr) noexcept;
290+
real_t db2mag(real_t v) noexcept;
291+
arr_real db2mag(const arr_real& arr) noexcept;
292+
void mag2db(inplace_real arr) noexcept;
293+
void db2mag(inplace_real arr) noexcept;
282294

283295
//----------------------------------------------------------------------------------------
284296
//check that the number is prime

include/dsplib/slice.h

Lines changed: 53 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -120,17 +120,17 @@ class mut_slice_t
120120
}
121121

122122
mut_slice_t& operator=(const slice_t<T>& rhs) {
123-
this->copy(*this, rhs);
123+
this->assign(rhs);
124124
return *this;
125125
}
126126

127127
mut_slice_t& operator=(const mut_slice_t<T>& rhs) {
128-
*this = slice_t<T>(rhs);
128+
this->assign(slice_t<T>(rhs));
129129
return *this;
130130
}
131131

132132
mut_slice_t& operator=(const base_array<T>& rhs) {
133-
DSPLIB_ASSERT(!is_same_memory(rhs.slice(0, rhs.size()), *this), "Assigned array to same slice");
133+
DSPLIB_ASSERT(!is_same_memory(rhs.slice(0, rhs.size())), "Assigned array to same slice");
134134
*this = rhs.slice(0, rhs.size());
135135
return *this;
136136
}
@@ -165,19 +165,42 @@ class mut_slice_t
165165
return current;
166166
}
167167

168+
//TODO: replace to `copy` or `to_arr` function
168169
base_array<T> operator*() const noexcept {
169170
return base_array<T>(*this);
170171
}
171172

172-
static bool is_same_memory(slice_t<T> r1, slice_t<T> r2) noexcept {
173-
if (r1.empty() || r2.empty()) {
174-
return false;
173+
void assign(slice_t<T> rhs) {
174+
DSPLIB_ASSERT(size() == rhs.size(), "Slices size must be equal");
175+
const int count = size();
176+
177+
//empty slice assign
178+
if (count == 0) {
179+
return;
175180
}
176-
auto start1 = r1.begin();
177-
auto end1 = r1.end();
178-
auto start2 = r2.begin();
179-
auto end2 = r2.end();
180-
return (start1 < end2) && (start2 < end1);
181+
182+
//simple block copy/move (optimization)
183+
const bool is_same = is_same_memory(rhs);
184+
185+
//check all slices is span
186+
if ((stride() == 1) && (rhs.stride() == 1)) {
187+
const auto* src = rhs.data_;
188+
auto* dst = data_;
189+
if (!is_same) {
190+
std::memcpy(dst, src, count * sizeof(*src));
191+
} else {
192+
std::memmove(dst, src, count * sizeof(*src));
193+
}
194+
return;
195+
}
196+
197+
//same array, specific indexing
198+
if (is_same) {
199+
*this = base_array<T>(rhs);
200+
return;
201+
}
202+
203+
std::copy(rhs.begin(), rhs.end(), begin());
181204
}
182205

183206
static mut_slice_t make_slice(T* data, int size, int i1, int i2, int step) {
@@ -202,38 +225,6 @@ class mut_slice_t
202225
return mut_slice_t(data + i1, step, count);
203226
}
204227

205-
static void copy(mut_slice_t<T> lhs, slice_t<T> rhs) {
206-
DSPLIB_ASSERT(lhs.size() == rhs.size(), "Slices size must be equal");
207-
const int count = lhs.size();
208-
209-
//empty slice assign
210-
if (count == 0) {
211-
return;
212-
}
213-
214-
//simple block copy/move (optimization)
215-
const bool is_same = is_same_memory(rhs, slice_t(lhs));
216-
if ((lhs.stride() == 1) && (rhs.stride() == 1)) {
217-
const auto* src = &(*rhs.begin());
218-
auto* dst = &(*lhs.begin());
219-
if (!is_same) {
220-
std::memcpy(dst, src, count * sizeof(*src));
221-
} else {
222-
//overlapped
223-
std::memmove(dst, src, count * sizeof(*src));
224-
}
225-
return;
226-
}
227-
228-
//same array, specific indexing
229-
if (is_same) {
230-
lhs = base_array<T>(rhs);
231-
return;
232-
}
233-
234-
std::copy(rhs.begin(), rhs.end(), lhs.begin());
235-
}
236-
237228
protected:
238229
explicit mut_slice_t(T* data, int stride, int count)
239230
: data_{data}
@@ -242,6 +233,25 @@ class mut_slice_t
242233
DSPLIB_ASSERT(count >= 0, "Count of elements must be positive");
243234
}
244235

236+
bool is_same_memory(slice_t<T> rhs) noexcept {
237+
if (empty() || rhs.empty()) {
238+
return false;
239+
}
240+
auto start1 = rhs.data_;
241+
auto end1 = start1 + (rhs.count_ * rhs.stride_);
242+
if (start1 > end1) {
243+
std::swap(start1, end1);
244+
}
245+
246+
auto start2 = data_;
247+
auto end2 = start2 + (count_ * stride_);
248+
if (start2 > end2) {
249+
std::swap(start2, end2);
250+
}
251+
252+
return (start1 < end2) && (start2 < end1);
253+
}
254+
245255
T* data_{nullptr};
246256
int stride_{0};
247257
int count_{0};

0 commit comments

Comments
 (0)