JPL Spatial
Sound spatialization and propagation library
Loading...
Searching...
No Matches
AbstractIndex.h
Go to the documentation of this file.
1//
2// ██╗██████╗ ██╗ ██╗██████╗ ███████╗
3// ██║██╔══██╗ ██║ ██║██╔══██╗██╔════╝ ** JPLSpatial **
4// ██║██████╔╝ ██║ ██║██████╔╝███████╗
5// ██ ██║██╔═══╝ ██║ ██║██╔══██╗╚════██║ https://github.com/Jaytheway/JPLSpatial
6// ╚█████╔╝██║ ███████╗██║██████╔╝███████║
7// ╚════╝ ╚═╝ ╚══════╝╚═╝╚═════╝ ╚══════╝
8//
9// Copyright Jaroslav Pevno, JPLSpatial is offered under the terms of the ISC license:
10//
11// Permission to use, copy, modify, and/or distribute this software for any purpose with or
12// without fee is hereby granted, provided that the above copyright notice and this permission
13// notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
14// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
16// CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
17// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
18// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20#pragma once
21
22#include <bit>
23#include <concepts>
24#include <stdint.h>
25
26namespace JPL
27{
28 namespace RingImpl
29 {
30 enum class EOperationMode
31 {
32 Modulo, // wrap Ring using modulo % operator, ring can be any size
33 Pow2BitManip, // wrap Ring using bit manipulation, requires Ring size to be power of 2
34 };
35
36 enum class EWriteDirection
37 {
38 Forward, // increment index on write
39 Backward, // decrement index on write
40 };
41
42 template<class T> concept COperationMode = std::same_as<T, EOperationMode>;
43 template<class T> concept CWriteDirection = std::same_as<T, EWriteDirection>;
44
46 template<COperationMode auto OperationMode>
48
50 template<CWriteDirection auto WriteDirection, COperationMode auto OperationMode>
51 class AbstarctRingBase;
52 }
53
54 //==============================================================================
56 template<uint32_t MaxWindow,
60
61 //==============================================================================
68
74
75 //==============================================================================
79 template<uint32_t MaxWindow,
82 class AbstractRingIndex : private RingImpl::AbstarctRingBase<WriteDirection, OperationMode>
83 {
84 private:
86
87 public:
93
94 public:
96 : Base(minSize)
97 , mIndex(0, Base::GetMirrorIndex(0, MaxWindow))
98 {
99 }
100
103
105 [[nodiscard]] inline uint32_t GetTotalSize() const { return Base::mRing + MaxWindow; }
106 [[nodiscard]] inline uint32_t GetRingSize() const { return Base::mRing; }
107 [[nodiscard]] inline Index GetCurrent() const { return mIndex; }
108 inline void Reset() { UpdateWriteIndex(0); }
109
111 {
113 UpdateWriteIndex(newWriteIndex);
114 return mIndex;
115 }
116
118 {
119 const Index currentIndex = mIndex;
121 UpdateWriteIndex(newWriteIndex);
122 return currentIndex;
123 }
124
126 {
128 UpdateWriteIndex(newWriteIndex);
129 return mIndex;
130 }
131
133 {
134 const Index currentIndex = mIndex;
136 UpdateWriteIndex(newWriteIndex);
137 return currentIndex;
138 }
139
142 {
143 // start of contiguous `MaxWindow` window at an offset from the WriteIndex
144 return Base::GetOffset(mIndex.WriteIndex, offset);
145 }
146
147 private:
148 inline void UpdateWriteIndex(uint32_t newIndex)
149 {
150 mIndex.WriteIndex = newIndex;
152 }
153
154 private:
155 Index mIndex;
156 };
157
158 //==============================================================================
160 template<uint32_t MaxWindow,
161 RingImpl::CWriteDirection auto WriteDirection,
162 RingImpl::COperationMode auto OperationMode> requires(MaxWindow <= 1)
164 {
165 private:
167
168 public:
170
171 public:
173 : Base(minSize)
174 , mIndex(0)
175 {
176 }
177
180
182 [[nodiscard]] inline uint32_t GetTotalSize() const { return Base::mRing; }
183 [[nodiscard]] inline uint32_t GetRingSize() const { return Base::mRing; }
184 [[nodiscard]] inline Index GetCurrent() const { return mIndex; }
185 inline void Reset() { mIndex = { 0 }; }
186
187 inline Index operator ++()
188 {
189 mIndex = Base::IncrementIndex(mIndex);
190 return mIndex;
191 }
192
193 inline Index operator ++(int)
194 {
195 const Index currentIndex = mIndex;
196 mIndex = Base::IncrementIndex(mIndex);
197 return currentIndex;
198 }
199
200 inline Index operator --()
201 {
202 mIndex = Base::DecrementIndex(mIndex);
203 return mIndex;
204 }
205
206 inline Index operator --(int)
207 {
208 const Index currentIndex = mIndex;
209 mIndex = Base::DecrementIndex(mIndex);
210 return currentIndex;
211 }
212
214 {
215 return Base::GetOffset(mIndex, offset);
216 }
217
218 private:
219 Index mIndex;
220 };
221} // namespace JPL
222
223//==============================================================================
224//
225// Code beyond this point is implementation detail...
226//
227//==============================================================================
228namespace JPL
229{
230 namespace RingImpl
231 {
232 template<> class AbstractRingWrap<EOperationMode::Pow2BitManip>
233 {
234 protected:
235 explicit AbstractRingWrap(uint32_t minSize) : mRing(std::bit_ceil(minSize)), mSizeMask(mRing - 1) {}
236
237 AbstractRingWrap(const AbstractRingWrap&) = default;
238 AbstractRingWrap& operator=(const AbstractRingWrap&) = default;
239
240 inline uint32_t Wrap(uint32_t index) const { return (index & mSizeMask); }
241
242 protected:
243 uint32_t mRing;
244 uint32_t mSizeMask;
245 };
246
247 template<> class AbstractRingWrap<EOperationMode::Modulo>
248 {
249 protected:
250 explicit AbstractRingWrap(uint32_t minSize) : mRing(minSize) {}
251
252 AbstractRingWrap(const AbstractRingWrap&) = default;
253 AbstractRingWrap& operator=(const AbstractRingWrap&) = default;
254
255 inline uint32_t Wrap(uint32_t index) const { return (index % mRing); }
256
257 protected:
258 uint32_t mRing;
259 };
260
261 template<CWriteDirection auto WriteDirection, COperationMode auto OperationMode>
262 class AbstarctRingBase : protected AbstractRingWrap<OperationMode>
263 {
264 private:
266
267 protected:
269
272
274 {
275 return WrapBase::Wrap(index + 1u);
276 }
277
279 {
280 return WrapBase::Wrap((int32_t(index) - 1));
281 }
282
285 {
287 {
288 return WrapBase::Wrap(index + WrapBase::mRing - offset);
289 }
290 else
291 {
292 return WrapBase::Wrap(index + WrapBase::mRing + offset);
293 }
294 }
295
298 {
299 // (branch version)
300 //if (index < maxWindow) // mirror only if inside first 'maxWindow'
301 // mirrorIndex = return mRing + index;
302
303 // (branch-less simple version)
304 // mirrorIndex = (index < maxWindow) * mRing + index;
305
306 // (branch-less clever version)
307 // This logic works for both, power of 2 mRing and non-power of 2 mRing.
308 const uint32_t mirrorOff = (int32_t(index - maxWindow) >> 31) & WrapBase::mRing; // 0 or mRing
309 return (index + mirrorOff);
310 }
311 };
312 } // namespace RingImpl
313} // namespace JPL
uint32_t GetOffset(int32_t offset) const
Definition AbstractIndex.h:213
uint32_t GetRingSize() const
Definition AbstractIndex.h:183
AbstractRingIndex(uint32_t minSize)
Definition AbstractIndex.h:172
Index GetCurrent() const
Definition AbstractIndex.h:184
uint32_t GetTotalSize() const
Get total size of the ring buffer.
Definition AbstractIndex.h:182
AbstractRingIndex & operator=(const AbstractRingIndex &)=default
Forward declaration.
Definition AbstractIndex.h:83
Index operator++()
Definition AbstractIndex.h:110
uint32_t GetRingSize() const
Definition AbstractIndex.h:106
AbstractRingIndex(uint32_t minSize)
Definition AbstractIndex.h:95
void Reset()
Definition AbstractIndex.h:108
uint32_t GetOffset(uint32_t offset) const
Get the index of the sample at an offset from the WriteIndex.
Definition AbstractIndex.h:141
Index GetCurrent() const
Definition AbstractIndex.h:107
Index operator--()
Definition AbstractIndex.h:125
uint32_t GetTotalSize() const
Get total size of the ring buffer including MaxWindow mirror length.
Definition AbstractIndex.h:105
AbstractRingIndex(const AbstractRingIndex &)=default
AbstractRingIndex & operator=(const AbstractRingIndex &)=default
Base class for Ring-like indexing operations.
Definition AbstractIndex.h:263
AbstarctRingBase & operator=(const AbstarctRingBase &)=default
uint32_t GetOffset(uint32_t index, uint32_t offset) const
Get the index of the sample at an offset from the WriteIndex.
Definition AbstractIndex.h:284
uint32_t GetMirrorIndex(uint32_t index, uint32_t maxWindow) const
Definition AbstractIndex.h:297
uint32_t IncrementIndex(uint32_t index) const
Definition AbstractIndex.h:273
AbstarctRingBase(const AbstarctRingBase &)=default
AbstarctRingBase(uint32_t minSize)
Definition AbstractIndex.h:268
uint32_t DecrementIndex(uint32_t index) const
Definition AbstractIndex.h:278
Base class that implements the wrap around logic for the OperationMode.
Definition AbstractIndex.h:47
Definition AbstractIndex.h:42
Definition AbstractIndex.h:43
EWriteDirection
Definition AbstractIndex.h:37
EOperationMode
Definition AbstractIndex.h:31
Definition AcousticMaterial.h:36
JPL_INLINE simd min(const simd &a, const simd &b) noexcept
Element-wise min.
Definition SIMD.h:1813
Definition ChannelMap.h:268
Definition AbstractIndex.h:89
uint32_t MirrorIndex
Definition AbstractIndex.h:91
uint32_t WriteIndex
Definition AbstractIndex.h:90