Skip to content

Commit 3c9697e

Browse files
committed
Add runtime duplicate types handling
1 parent 59beae9 commit 3c9697e

File tree

6 files changed

+248
-183
lines changed

6 files changed

+248
-183
lines changed

cfg/base.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <vector>
1111
#include <limits>
1212
#include "cfg/containers.h"
13+
#include "cfg/helpers_runtime.h"
1314

1415

1516
template<class VStr>

cfg/containers.h

Lines changed: 28 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -241,132 +241,9 @@ template<std::size_t N>
241241
}
242242

243243

244-
template<class TChar, TChar start, TChar end>
245-
constexpr void lexical_range(auto func)
246-
{
247-
return cfg_helpers::do_lexical_range<0, TChar, start, end>(func);
248-
}
249-
250-
251-
/**
252-
* @brief Check if a char is in range [start, end]
253-
*/
254-
template<class TChar>
255-
constexpr bool in_lexical_range(TChar c, TChar start, TChar end)
256-
{
257-
return (start <= c) && (c <= end);
258-
}
259-
260-
/**
261-
* @brief Check if a char is in range (start, end)
262-
*/
263-
template<class TChar>
264-
constexpr bool in_lexical_range_strict(TChar c, TChar start, TChar end)
265-
{
266-
return (start < c) && (c < end);
267-
}
268-
269-
/**
270-
* @brief For a range [start..., c, ...end] lexical_intersect returns ranges [start, c), (c, end]. Does not handle cases when start or end is equal to c
271-
*/
272-
template<class TChar>
273-
constexpr auto lexical_intersect(TChar c, TChar start, TChar end)
274-
{
275-
return std::make_pair(std::make_pair(start, static_cast<TChar>(static_cast<std::size_t>(c) - 1)), std::make_pair(static_cast<TChar>(static_cast<std::size_t>(c) + 1), end));
276-
}
277-
278-
/**
279-
* @brief For a range [start, end] and c=start OR c=end lexical_intersect_edge returns (start, end] OR [start, end)
280-
*/
281-
template<class TChar>
282-
constexpr auto lexical_intersect_edge(TChar c, TChar start, TChar end)
283-
{
284-
if (c == start)
285-
return std::make_pair(static_cast<TChar>(static_cast<std::size_t>(start) + 1), end);
286-
return std::make_pair(start, static_cast<TChar>(static_cast<std::size_t>(end) - 1));
287-
}
288-
289-
290-
/**
291-
* @brief Check if ranges [start_lhs, end_lhs], [start_rhs, end_rhs] intersect
292-
*/
293-
template<class TChar>
294-
constexpr bool in_lexical_range(TChar a_start, TChar a_end, TChar b_start, TChar b_end)
295-
{
296-
// [ ( ] ) or [ ( ) ]
297-
//return (b_start <= a_end && b_end >= a_start) || (a_start <= b_end || a_end >= b_start);
298-
return (a_start > b_start ? a_start : b_start) <= (a_end < b_end ? a_end : b_end);
299-
}
300-
301-
302-
/**
303-
* @brief Enum for lexical_ranges_intersect return type. [ ] - range A, ( ) - range B
304-
*/
305-
enum class RangesIntersect
306-
{
307-
Partial, /** [ ( ] ) */
308-
AInB, /** ( [ ] ) Note: 1st and 3rd ranges are of the same type (B) */
309-
BInA, /** [ ( ) ] Note: 1st and 3rd ranges are of the same type (A) */
310-
OnlyA, /** [( ) ] Note: first range is empty */
311-
OnlyB, /** ([ ] ) Note: third range is empty */
312-
};
313-
314-
315-
/**
316-
* @brief For ranges [start_lhs, end_lhs] and [start_rhs, end_rhs] lexical_ranges_intersect returns a tuple of 3 ranges: [lhs, intersect, rhs]. Any resulting range may be a singleton (c, c)
317-
*/
318-
template<class TChar>
319-
constexpr auto lexical_ranges_intersect(TChar a_start, TChar a_end, TChar b_start, TChar b_end)
320-
{
321-
using range_type = std::pair<TChar, TChar>;
322-
323-
// Calculate intersection boundaries
324-
const TChar intersect_start = a_start > b_start ? a_start : b_start; // std::max(a_start, b_start)
325-
const TChar intersect_end = a_end < b_end ? a_end : b_end; // std::min(a_end, b_end )
326-
const auto i_decr = static_cast<TChar>(static_cast<std::size_t>(intersect_start) - 1);
327-
const auto i_incr = static_cast<TChar>(static_cast<std::size_t>(intersect_end) + 1);
328-
329-
const range_type intersect = range_type(intersect_start, intersect_end);
330-
331-
332-
// [ ( ) ] or [( ) ] (any combination)
333-
if ((intersect_start == a_start && intersect_end == a_end) || (intersect_start == b_start && intersect_end == b_end))
334-
{
335-
if (a_start == b_start)
336-
return (a_end < b_end ?
337-
// ([ ] )
338-
std::make_pair(RangesIntersect::OnlyB, std::make_tuple(range_type(), intersect, range_type(i_incr, b_end))) :
339-
// [( ) ]
340-
std::make_pair(RangesIntersect::OnlyA, std::make_tuple(range_type(a_start, i_decr), intersect, range_type())));
341-
else if (a_end == b_end)
342-
return (b_start < a_start ?
343-
// ([ ] )
344-
std::make_pair(RangesIntersect::OnlyB, std::make_tuple(range_type(), intersect, range_type(i_incr, b_end))) :
345-
// [ ( )]
346-
std::make_pair(RangesIntersect::OnlyA, std::make_tuple(range_type(a_start, i_decr), intersect, range_type())));
347-
else {
348-
// [ ( ) ]
349-
// Note: 1st and 3rd ranges are of the same type
350-
return (a_start == intersect_start ?
351-
// ( [ ] )
352-
std::make_pair(RangesIntersect::AInB, std::make_tuple(range_type(b_start, i_decr), intersect, range_type(i_incr, b_end))) :
353-
// [ ( ) ]
354-
std::make_pair(RangesIntersect::BInA, std::make_tuple(range_type(a_start, i_decr), intersect, range_type(i_incr, a_end))));
355-
}
356-
}
357-
358-
return (a_start < intersect_start ?
359-
// [ ( ] )
360-
std::make_pair(RangesIntersect::Partial, std::make_tuple(range_type(a_start, i_decr), intersect, range_type(i_incr, b_end))) :
361-
// ( [ ) ]
362-
std::make_pair(RangesIntersect::Partial, std::make_tuple(range_type(i_incr, a_end), intersect, range_type(b_start, i_decr))));
363-
}
364-
365-
366244
/**
367245
* @brief Map enum to its index in increasing order
368246
* @tparam Max Maximum (last) value of enum
369-
* @tparam TArg List of enum arguments of the same type
370247
*/
371248
template<class T, T Max>
372249
class EnumMap
@@ -422,8 +299,11 @@ class ConstVec
422299
// Lazy init
423300
constexpr ConstVec() : _st(), _n(0), _cap(0) {}
424301

302+
// Empty init
303+
constexpr ConstVec(std::size_t size, std::size_t cap) : _st(new T[cap]), _n(size), _cap(cap) {}
304+
425305
// Copy ctor
426-
constexpr ConstVec(const ConstVec<T>& rhs) : _st(new T[rhs.size()]), _n(rhs.size()), _cap(rhs.size()) { deepcopy(rhs); }
306+
constexpr ConstVec(const ConstVec<T>& rhs) : _st(new T[rhs.size()]), _cap(rhs.size()) { deepcopy(rhs); }
427307

428308
// Initialize a singleton
429309
constexpr explicit ConstVec(const T& elem) : _st(new T[1]), _n(1), _cap(1) { _st[0] = elem; }
@@ -470,7 +350,13 @@ class ConstVec
470350
_st.reset(new T[rhs.size()]);
471351
deepcopy(rhs);
472352
_cap = rhs.size();
473-
_n = rhs.size();
353+
}
354+
355+
void init(std::size_t size, std::size_t cap)
356+
{
357+
_st.reset(new T[cap]);
358+
_cap = cap;
359+
_n = size;
474360
}
475361

476362
[[nodiscard]] std::size_t size() const noexcept { return _n; }
@@ -481,6 +367,16 @@ class ConstVec
481367

482368
constexpr const T& operator[](std::size_t i) const { return _st[i]; }
483369

370+
/**
371+
* @brief Copy rhs.size() elements from rhs and set array size to rhs.size(). Buffer must be allocated beforehand
372+
*/
373+
void deepcopy(const ConstVec<T>& rhs)
374+
{
375+
// Perform a deepcopy of the rhs array up to rhs.size elements
376+
_n = rhs.size();
377+
std::copy_n(rhs._st.get(), rhs.size(), _st.get());
378+
}
379+
484380
/**
485381
* @brief Replace array with a single element
486382
* @param elem
@@ -505,6 +401,13 @@ class ConstVec
505401
return *this;
506402
}
507403

404+
ConstVec<T>& operator+=(const T& rhs)
405+
{
406+
_st[_n] = rhs;
407+
_n++;
408+
return *this;
409+
}
410+
508411
friend std::ostream& operator<<(std::ostream& os, const ConstVec<T>& lhs)
509412
{
510413
for (std::size_t i = 0; i < lhs.size(); i++)
@@ -519,12 +422,6 @@ class ConstVec
519422
// return std::make_unique<T>(T(std::get<N>(src))...);
520423
return new T[std::tuple_size_v<std::decay_t<SrcTuple>>]{ T(std::get<N>(src))... };
521424
}
522-
523-
void deepcopy(const ConstVec<T>& rhs)
524-
{
525-
// Perform a deepcopy of the rhs array up to rhs.size elements
526-
std::copy_n(rhs._st.get(), rhs.size(), _st.get());
527-
}
528425
};
529426

530427

cfg/helpers_runtime.h

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
//
2+
// Created by Flynn on 23.04.2025.
3+
//
4+
5+
#ifndef HELPERS_RUNTIME_H
6+
#define HELPERS_RUNTIME_H
7+
8+
#include "cfg/containers.h"
9+
10+
11+
// LEXICAL HELPERS
12+
// ===============
13+
14+
15+
template<class TChar, TChar start, TChar end>
16+
constexpr void lexical_range(auto func)
17+
{
18+
return cfg_helpers::do_lexical_range<0, TChar, start, end>(func);
19+
}
20+
21+
22+
/**
23+
* @brief Check if a char is in range [start, end]
24+
*/
25+
template<class TChar>
26+
constexpr bool in_lexical_range(TChar c, TChar start, TChar end)
27+
{
28+
return (start <= c) && (c <= end);
29+
}
30+
31+
/**
32+
* @brief Check if a char is in range (start, end)
33+
*/
34+
template<class TChar>
35+
constexpr bool in_lexical_range_strict(TChar c, TChar start, TChar end)
36+
{
37+
return (start < c) && (c < end);
38+
}
39+
40+
/**
41+
* @brief For a range [start..., c, ...end] lexical_intersect returns ranges [start, c), (c, end]. Does not handle cases when start or end is equal to c
42+
*/
43+
template<class TChar>
44+
constexpr auto lexical_intersect(TChar c, TChar start, TChar end)
45+
{
46+
return std::make_pair(std::make_pair(start, static_cast<TChar>(static_cast<std::size_t>(c) - 1)), std::make_pair(static_cast<TChar>(static_cast<std::size_t>(c) + 1), end));
47+
}
48+
49+
/**
50+
* @brief For a range [start, end] and c=start OR c=end lexical_intersect_edge returns (start, end] OR [start, end)
51+
*/
52+
template<class TChar>
53+
constexpr auto lexical_intersect_edge(TChar c, TChar start, TChar end)
54+
{
55+
if (c == start)
56+
return std::make_pair(static_cast<TChar>(static_cast<std::size_t>(start) + 1), end);
57+
return std::make_pair(start, static_cast<TChar>(static_cast<std::size_t>(end) - 1));
58+
}
59+
60+
61+
/**
62+
* @brief Check if ranges [start_lhs, end_lhs], [start_rhs, end_rhs] intersect
63+
*/
64+
template<class TChar>
65+
constexpr bool in_lexical_range(TChar a_start, TChar a_end, TChar b_start, TChar b_end)
66+
{
67+
// [ ( ] ) or [ ( ) ]
68+
//return (b_start <= a_end && b_end >= a_start) || (a_start <= b_end || a_end >= b_start);
69+
return (a_start > b_start ? a_start : b_start) <= (a_end < b_end ? a_end : b_end);
70+
}
71+
72+
73+
/**
74+
* @brief Enum for lexical_ranges_intersect return type. [ ] - range A, ( ) - range B
75+
*/
76+
enum class RangesIntersect
77+
{
78+
Partial, /** [ ( ] ) */
79+
AInB, /** ( [ ] ) Note: 1st and 3rd ranges are of the same type (B) */
80+
BInA, /** [ ( ) ] Note: 1st and 3rd ranges are of the same type (A) */
81+
OnlyA, /** [( ) ] Note: first range is empty */
82+
OnlyB, /** ([ ] ) Note: third range is empty */
83+
};
84+
85+
86+
/**
87+
* @brief For ranges [start_lhs, end_lhs] and [start_rhs, end_rhs] lexical_ranges_intersect returns a tuple of 3 ranges: [lhs, intersect, rhs]. Any resulting range may be a singleton (c, c)
88+
*/
89+
template<class TChar>
90+
constexpr auto lexical_ranges_intersect(TChar a_start, TChar a_end, TChar b_start, TChar b_end)
91+
{
92+
using range_type = std::pair<TChar, TChar>;
93+
94+
// Calculate intersection boundaries
95+
const TChar intersect_start = a_start > b_start ? a_start : b_start; // std::max(a_start, b_start)
96+
const TChar intersect_end = a_end < b_end ? a_end : b_end; // std::min(a_end, b_end )
97+
const auto i_decr = static_cast<TChar>(static_cast<std::size_t>(intersect_start) - 1);
98+
const auto i_incr = static_cast<TChar>(static_cast<std::size_t>(intersect_end) + 1);
99+
100+
const range_type intersect = range_type(intersect_start, intersect_end);
101+
102+
103+
// [ ( ) ] or [( ) ] (any combination)
104+
if ((intersect_start == a_start && intersect_end == a_end) || (intersect_start == b_start && intersect_end == b_end))
105+
{
106+
if (a_start == b_start)
107+
return (a_end < b_end ?
108+
// ([ ] )
109+
std::make_pair(RangesIntersect::OnlyB, std::make_tuple(range_type(), intersect, range_type(i_incr, b_end))) :
110+
// [( ) ]
111+
std::make_pair(RangesIntersect::OnlyA, std::make_tuple(range_type(a_start, i_decr), intersect, range_type())));
112+
else if (a_end == b_end)
113+
return (b_start < a_start ?
114+
// ([ ] )
115+
std::make_pair(RangesIntersect::OnlyB, std::make_tuple(range_type(), intersect, range_type(i_incr, b_end))) :
116+
// [ ( )]
117+
std::make_pair(RangesIntersect::OnlyA, std::make_tuple(range_type(a_start, i_decr), intersect, range_type())));
118+
else {
119+
// [ ( ) ]
120+
// Note: 1st and 3rd ranges are of the same type
121+
return (a_start == intersect_start ?
122+
// ( [ ] )
123+
std::make_pair(RangesIntersect::AInB, std::make_tuple(range_type(b_start, i_decr), intersect, range_type(i_incr, b_end))) :
124+
// [ ( ) ]
125+
std::make_pair(RangesIntersect::BInA, std::make_tuple(range_type(a_start, i_decr), intersect, range_type(i_incr, a_end))));
126+
}
127+
}
128+
129+
return (a_start < intersect_start ?
130+
// [ ( ] )
131+
std::make_pair(RangesIntersect::Partial, std::make_tuple(range_type(a_start, i_decr), intersect, range_type(i_incr, b_end))) :
132+
// ( [ ) ]
133+
std::make_pair(RangesIntersect::Partial, std::make_tuple(range_type(i_incr, a_end), intersect, range_type(b_start, i_decr))));
134+
}
135+
136+
137+
// VECTOR OPERATIONS
138+
// =================
139+
140+
141+
/**
142+
* @brief Calculate union between 2 vectors. It is assumed that lhs and rhs do not contain duplicates
143+
*/
144+
template<class T>
145+
auto vec_union(const ConstVec<T>& lhs, const ConstVec<T>& rhs)
146+
{
147+
const auto n = lhs.size() + rhs.size(); // Max size
148+
ConstVec<T> res(0, n);
149+
res.deepcopy(lhs);
150+
for (std::size_t i = 0; i < lhs.size(); i++)
151+
{
152+
for (std::size_t j = 0; j < rhs.size(); j++)
153+
{
154+
if (lhs[i] != rhs[i])
155+
res += rhs[i];
156+
}
157+
}
158+
return res;
159+
}
160+
161+
162+
#endif //HELPERS_RUNTIME_H

0 commit comments

Comments
 (0)