NDEVR
API Documentation
IndexMatchQueue.h
1#pragma once
2
3#include <cstdint>
4#include <type_traits>
5#include <utility>
6#include <limits>
7#include <functional>
8
9#include <NDEVR/QueueBuffer.h>
10
11namespace NDEVR
12{
26 template <class t_a, class t_b, class t_index = uint04>
28 {
29 public:
30 using A = t_a;
31 using B = t_b;
32 using Index = t_index;
33 using UIndex = std::make_unsigned_t<Index>;
34
35 using OnMatchFn = std::function<void(const A&, const B&)>;
36 using OnNearMatchFn = std::function<void(const A&, const B&)>;
37
41 IndexMatchQueue() = default;
42
48 IndexMatchQueue(OnMatchFn on_match, OnNearMatchFn on_near_match = {})
49 : m_on_match(std::move(on_match))
50 , m_on_near_match(std::move(on_near_match))
51 {}
52
57 void setOnMatch(OnMatchFn on_match)
58 {
59 m_on_match = std::move(on_match);
60 }
61
66 void setOnNearMatch(OnNearMatchFn on_near_match)
67 {
68 m_on_near_match = std::move(on_near_match);
69 }
70
74 void clear()
75 {
76 m_a.clear();
77 m_b.clear();
78 }
79
89 void pushA(Index idx, A a)
90 {
91 if (m_a.size() > 0 && m_a.last().index == idx)
92 {
93 m_a.last().value = a;
94 return;
95 }
96 m_a.push(NodeA{ idx, std::move(a) });
97 drain();
98 if (m_a.size() > HalfRange())
99 m_a.pop();
100 }
101
111 void pushB(Index idx, B b)
112 {
113 if (m_b.size() > 0 && m_b.last().index == idx)
114 {
115 m_b.last().value = b;
116 return;
117 }
118 m_b.push(NodeB{ idx, std::move(b) });
119 drain();
120 if (m_b.size() > HalfRange())
121 m_b.pop();
122 }
123
124 protected:
128 struct NodeA
129 {
132 };
133
136 struct NodeB
137 {
140 };
141
148 static constexpr UIndex HalfRange() noexcept
149 {
150 return (UIndex(~UIndex(0)) >> 1) + 1;
151 }
152
159 static constexpr bool seqLess(Index a, Index b) noexcept
160 {
161 const UIndex ua = static_cast<UIndex>(a);
162 const UIndex ub = static_cast<UIndex>(b);
163 const UIndex d = ub - ua;
164 return d != 0 && d < HalfRange();
165 }
166
173 static constexpr UIndex circularDistance(Index a, Index b) noexcept
174 {
175 const UIndex ua = static_cast<UIndex>(a);
176 const UIndex ub = static_cast<UIndex>(b);
177 const UIndex d1 = ub - ua;
178 const UIndex d2 = ua - ub;
179 return (d1 < d2) ? d1 : d2;
180 }
181
189 void drain()
190 {
191 static_assert(std::is_integral_v<Index>, "Index must be integral");
192
193 while (!m_a.empty() && !m_b.empty())
194 {
195 const Index ia = m_a.front().index;
196 const Index ib = m_b.front().index;
197
198 if (ia == ib)
199 {
200 if (m_on_match)
201 m_on_match(m_a.front().value, m_b.front().value);
202
203 m_a.pop();
204 m_b.pop();
205 continue;
206 }
207 if (seqLess(ia, ib))
208 {
209 m_a.pop();
210 while (m_a.size() > 0 && seqLess(m_a.front().index, ib))
211 m_a.pop();
212 }
213 else
214 {
215 const UIndex dist = circularDistance(ia, ib);
216 //lib_assert(dist <= distance_tolerance, "unmatched record");
217 if (dist <= distance_tolerance)
218 {
219 if (m_on_near_match)
220 m_on_near_match(m_a.front().value, m_b.front().value);
221 m_b.pop();
222 }
223 else
224 {
225 while (m_b.size() > 0 && !seqLess(ia, m_b.front().index))
226 m_b.pop();
227 }
228 //while (m_b.size() > 0 && !seqLess(ia, m_b.front().index))
229 //m_b.pop();
230 }
231 }
232
233 }
234
235 private:
236 uint04 distance_tolerance = 50U;
239
240 OnMatchFn m_on_match;
241 OnNearMatchFn m_on_near_match;
242 };
243}
void clear()
Clears both internal queues, discarding all pending elements.
std::function< void(const A &, const B &)> OnMatchFn
Callback type invoked when indices match exactly.
void pushA(Index idx, A a)
Pushes an element into the A stream with the given index.
std::make_unsigned_t< Index > UIndex
Unsigned version of the index type for circular arithmetic.
std::function< void(const A &, const B &)> OnNearMatchFn
Callback type invoked when indices are within the distance tolerance.
static constexpr UIndex circularDistance(Index a, Index b) noexcept
Computes the minimum circular distance between two indices.
void pushB(Index idx, B b)
Pushes an element into the B stream with the given index.
void setOnNearMatch(OnNearMatchFn on_near_match)
Sets the callback for near index matches.
void drain()
Processes the front of both queues, invoking callbacks for matched or near-matched pairs.
t_b B
Alias for the second element type.
t_index Index
Alias for the index type.
static constexpr UIndex HalfRange() noexcept
Computes half the total range of the unsigned index type.
t_a A
Alias for the first element type.
IndexMatchQueue()=default
Default constructor.
static constexpr bool seqLess(Index a, Index b) noexcept
Determines whether index a precedes index b in circular sequence order.
IndexMatchQueue(OnMatchFn on_match, OnNearMatchFn on_near_match={})
Constructs the queue with match callbacks.
void setOnMatch(OnMatchFn on_match)
Sets the callback for exact index matches.
Stores objects in a first-in, first out queue based Buffer with push and pop functions.
The primary namespace for the NDEVR SDK.
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
STL namespace.
Internal node storing an A-stream element and its associated index.
A value
The stored element value.
Index index
The sequence index for this element.
Internal node storing a B-stream element and its associated index.
Index index
The sequence index for this element.
B value
The stored element value.