Skip to content

Commit 17a74a7

Browse files
committed
inplace span support
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;
1 parent bae23cf commit 17a74a7

File tree

10 files changed

+257
-116
lines changed

10 files changed

+257
-116
lines changed

include/dsplib/fft.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ class FftPlanC
2323
*/
2424
virtual void solve(span_t<cmplx_t> x, mut_span_t<cmplx_t> r) const = 0;
2525

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

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: 29 additions & 19 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);
@@ -181,8 +186,9 @@ arr_cmplx power(const arr_cmplx& x, int n);
181186

182187
//square root (only positive values)
183188
//TODO: add complex result for negative or complex input
184-
real_t sqrt(real_t x);
185-
arr_real sqrt(const arr_real& x);
189+
real_t sqrt(real_t x) noexcept;
190+
arr_real sqrt(const arr_real& arr) noexcept;
191+
void sqrt(inplace_real arr) noexcept;
186192

187193
//array log
188194
arr_real log(const arr_real& arr);
@@ -210,7 +216,7 @@ arr_real upsample(const arr_real& arr, int n, int phase = 0);
210216
arr_cmplx upsample(const arr_cmplx& arr, int n, int phase = 0);
211217

212218
//abs(x)^2
213-
arr_real abs2(const arr_cmplx& x);
219+
arr_real abs2(const arr_cmplx& x) noexcept;
214220

215221
constexpr real_t abs2(const cmplx_t& x) noexcept {
216222
return x.abs2();
@@ -269,16 +275,20 @@ inline cmplx_t sign(const cmplx_t& x) noexcept {
269275

270276
//----------------------------------------------------------------------------------------
271277
//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);
278+
real_t pow2db(real_t v) noexcept;
279+
arr_real pow2db(const arr_real& arr) noexcept;
280+
real_t db2pow(real_t v) noexcept;
281+
arr_real db2pow(const arr_real& arr) noexcept;
282+
void pow2db(inplace_real arr) noexcept;
283+
void db2pow(inplace_real arr) noexcept;
276284

277285
//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);
286+
real_t mag2db(real_t v) noexcept;
287+
arr_real mag2db(const arr_real& arr) noexcept;
288+
real_t db2mag(real_t v) noexcept;
289+
arr_real db2mag(const arr_real& arr) noexcept;
290+
void mag2db(inplace_real arr) noexcept;
291+
void db2mag(inplace_real arr) noexcept;
282292

283293
//----------------------------------------------------------------------------------------
284294
//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};

include/dsplib/span.h

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,12 @@ class mut_span_t : public mut_slice_t<T>
6868
if (this == &rhs) {
6969
return *this;
7070
}
71-
mut_slice_t<T>::operator=(slice_t<T>(rhs));
71+
this->assign(rhs);
72+
return *this;
73+
}
74+
75+
mut_span_t& operator=(const span_t<T>& rhs) {
76+
this->assign(rhs);
7277
return *this;
7378
}
7479

@@ -84,7 +89,7 @@ class mut_span_t : public mut_slice_t<T>
8489
}
8590

8691
mut_span_t& operator=(const base_array<T>& rhs) {
87-
*this = span_t<T>(rhs.data(), rhs.size());
92+
this->assign(rhs);
8893
return *this;
8994
}
9095

@@ -117,12 +122,33 @@ class mut_span_t : public mut_slice_t<T>
117122
return this->data_ + this->count_;
118123
}
119124

125+
void assign(span_t<T> rhs) {
126+
DSPLIB_ASSERT(this->size() == rhs.size(), "Span size is not equal");
127+
if (!is_same_memory(rhs)) {
128+
std::memcpy(this->data(), rhs.data(), size() * sizeof(T));
129+
} else {
130+
std::memmove(this->data(), rhs.data(), size() * sizeof(T));
131+
}
132+
}
133+
120134
//TODO: add more checks
121135
mut_span_t slice(int i1, int i2) const {
122136
DSPLIB_ASSERT((i1 >= 0) && (i1 < this->count_), "invalid range");
123137
DSPLIB_ASSERT((i2 > i1) && (i2 <= this->count_), "invalid range");
124138
return mut_span_t(this->data_ + i1, (i2 - i1));
125139
}
140+
141+
private:
142+
bool is_same_memory(span_t<T> rhs) noexcept {
143+
if (this->size() == 0 || rhs.size() == 0) {
144+
return false;
145+
}
146+
auto start1 = this->data();
147+
auto end1 = start1 + this->size();
148+
auto start2 = rhs.data();
149+
auto end2 = start2 + rhs.size();
150+
return (start1 < end2) && (start2 < end1);
151+
}
126152
};
127153

128154
//immutable span
@@ -216,4 +242,38 @@ mut_span_t<T> make_span(base_array<T>& x) noexcept {
216242
using span_real = span_t<real_t>;
217243
using span_cmplx = span_t<cmplx_t>;
218244

245+
template<typename T>
246+
class inplace_span_t
247+
{
248+
public:
249+
explicit inplace_span_t(mut_span_t<T> v) noexcept
250+
: d_{std::move(v)} {
251+
}
252+
253+
mut_span_t<T> get() noexcept {
254+
return d_;
255+
}
256+
257+
private:
258+
mut_span_t<T> d_;
259+
};
260+
261+
template<typename T>
262+
inplace_span_t<T> inplace(base_array<T>& x) {
263+
return inplace_span_t(make_span(x));
264+
}
265+
266+
template<typename T>
267+
inplace_span_t<T> inplace(std::vector<T>& x) {
268+
return inplace_span_t(make_span(x));
269+
}
270+
271+
template<typename T>
272+
inplace_span_t<T> inplace(mut_span_t<T> x) {
273+
return inplace_span_t(x);
274+
}
275+
276+
using inplace_real = inplace_span_t<real_t>;
277+
using inplace_cmplx = inplace_span_t<cmplx_t>;
278+
219279
} // namespace dsplib

lib/fft/fact-fft.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,7 @@ void _facfft(const PlanTree* plan, cmplx_t* restrict x, cmplx_t* restrict mem, c
131131
const int n = plan->size();
132132

133133
if (!plan->has_next()) {
134-
//TODO: inplace fft
135-
plan->solver()->solve(make_span(x, n), make_span(mem, n));
136-
std::memcpy(x, mem, n * sizeof(cmplx_t));
134+
plan->solver()->solve(inplace(make_span(x, n)));
137135
return;
138136
}
139137

@@ -188,11 +186,16 @@ FactorFFTPlan::FactorFFTPlan(int n)
188186
}
189187

190188
void FactorFFTPlan::solve(span_t<cmplx_t> x, mut_span_t<cmplx_t> r) const {
191-
DSPLIB_ASSERT(x.size() == _n, "input array size is not equal fft size");
192189
DSPLIB_ASSERT(x.size() == r.size(), "output array size error");
190+
r.assign(x);
191+
this->solve(inplace(r));
192+
}
193+
194+
void FactorFFTPlan::solve(inplace_span_t<cmplx_t> r) const {
195+
auto x = r.get();
196+
DSPLIB_ASSERT(x.size() == _n, "input array size is not equal fft size");
193197
arr_cmplx tmp(_n);
194-
r = x; //TODO: remove copy
195-
_facfft(_plan.get(), r.data(), tmp.data(), _twiddle.data(), _n);
198+
_facfft(_plan.get(), x.data(), tmp.data(), _twiddle.data(), _n);
196199
}
197200

198201
[[nodiscard]] int FactorFFTPlan::size() const noexcept {

lib/fft/fact-fft.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class FactorFFTPlan : public FftPlanC
1818

1919
[[nodiscard]] arr_cmplx solve(span_t<cmplx_t> x) const final;
2020
void solve(span_t<cmplx_t> x, mut_span_t<cmplx_t> r) const final;
21+
void solve(inplace_span_t<cmplx_t> r) const final;
2122
[[nodiscard]] int size() const noexcept final;
2223

2324
private:

0 commit comments

Comments
 (0)