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,
57 RingImpl::CWriteDirection auto WriteDirection,
58 RingImpl::COperationMode auto OperationMode>
60
61 //==============================================================================
68
74
75 //==============================================================================
79 template<uint32_t MaxWindow,
80 RingImpl::CWriteDirection auto WriteDirection,
81 RingImpl::COperationMode auto OperationMode>
82 class AbstractRingIndex : private RingImpl::AbstarctRingBase<WriteDirection, OperationMode>
83 {
84 private:
86
87 public:
88 struct Index
89 {
90 uint32_t WriteIndex;
91 uint32_t MirrorIndex;
92 };
93
94 public:
95 explicit AbstractRingIndex(uint32_t minSize)
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
110 inline Index operator ++() requires(WriteDirection == RingImpl::EWriteDirection::Forward)
111 {
112 const uint32_t newWriteIndex = Base::IncrementIndex(mIndex.WriteIndex);
113 UpdateWriteIndex(newWriteIndex);
114 return mIndex;
115 }
116
117 inline Index operator ++(int) requires(WriteDirection == RingImpl::EWriteDirection::Forward)
118 {
119 const Index currentIndex = mIndex;
120 const uint32_t newWriteIndex = Base::IncrementIndex(mIndex.WriteIndex);
121 UpdateWriteIndex(newWriteIndex);
122 return currentIndex;
123 }
124
125 inline Index operator --() requires(WriteDirection == RingImpl::EWriteDirection::Backward)
126 {
127 const uint32_t newWriteIndex = Base::DecrementIndex(mIndex.WriteIndex);
128 UpdateWriteIndex(newWriteIndex);
129 return mIndex;
130 }
131
132 inline Index operator --(int) requires(WriteDirection == RingImpl::EWriteDirection::Backward)
133 {
134 const Index currentIndex = mIndex;
135 const uint32_t newWriteIndex = Base::DecrementIndex(mIndex.WriteIndex);
136 UpdateWriteIndex(newWriteIndex);
137 return currentIndex;
138 }
139
141 [[nodiscard]] inline uint32_t GetOffset(uint32_t offset) const
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;
151 mIndex.MirrorIndex = Base::GetMirrorIndex(newIndex, MaxWindow);
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)
163 class AbstractRingIndex<MaxWindow, WriteDirection, OperationMode> : private RingImpl::AbstarctRingBase<WriteDirection, OperationMode>
164 {
165 private:
167
168 public:
169 using Index = uint32_t;
170
171 public:
172 explicit AbstractRingIndex(uint32_t minSize)
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
213 [[nodiscard]] inline uint32_t GetOffset(int32_t offset) const
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 {
233 {
234 protected:
235 explicit AbstractRingWrap(uint32_t minSize) : mRing(std::bit_ceil(minSize)), mSizeMask(mRing - 1) {}
236
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
248 {
249 protected:
250 explicit AbstractRingWrap(uint32_t minSize) : mRing(minSize) {}
251
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:
268 explicit AbstarctRingBase(uint32_t minSize) : WrapBase(minSize) {}
269
272
273 inline uint32_t IncrementIndex(uint32_t index) const requires(WriteDirection == EWriteDirection::Forward)
274 {
275 return WrapBase::Wrap(index + 1u);
276 }
277
278 inline uint32_t DecrementIndex(uint32_t index) const requires(WriteDirection == EWriteDirection::Backward)
279 {
280 return WrapBase::Wrap((int32_t(index) - 1));
281 }
282
284 inline uint32_t GetOffset(uint32_t index, uint32_t offset) const
285 {
286 if constexpr (WriteDirection == EWriteDirection::Forward)
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 inline uint32_t GetMirrorIndex(uint32_t index, uint32_t maxWindow) const
299 {
300 // (branch version)
301 //if (index < maxWindow) // mirror only if inside first 'maxWindow'
302 // mirrorIndex = return mRing + index;
303
304 // (branch-less simple version)
305 // mirrorIndex = (index < maxWindow) * mRing + index;
306
307 // (branch-less clever version)
308 // This logic works for both, power of 2 mRing and non-power of 2 mRing.
309 const uint32_t mirrorOff = (int32_t(index - maxWindow) >> 31) & WrapBase::mRing; // 0 or mRing
310 return (index + mirrorOff);
311 }
312 };
313 } // namespace RingImpl
314} // 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:298
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
uint32_t Wrap(uint32_t index) const
Definition AbstractIndex.h:255
AbstractRingWrap(const AbstractRingWrap &)=default
AbstractRingWrap(uint32_t minSize)
Definition AbstractIndex.h:250
uint32_t mRing
Definition AbstractIndex.h:258
AbstractRingWrap & operator=(const AbstractRingWrap &)=default
AbstractRingWrap & operator=(const AbstractRingWrap &)=default
uint32_t Wrap(uint32_t index) const
Definition AbstractIndex.h:240
AbstractRingWrap(uint32_t minSize)
Definition AbstractIndex.h:235
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
Definition ChannelMap.h:272
Definition AbstractIndex.h:89
uint32_t MirrorIndex
Definition AbstractIndex.h:91
uint32_t WriteIndex
Definition AbstractIndex.h:90