Skip to content

Commit b2f0a58

Browse files
committed
minimum viable functionality, tests passing, generic constexpr template sort
1 parent 45d5d9a commit b2f0a58

File tree

9 files changed

+362
-107
lines changed

9 files changed

+362
-107
lines changed

cmake/Macros.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
macro(untiguard_add_code_checks)
1+
macro(unitguard_add_code_checks)
22

33
set(options)
44
set(singleValueArgs PREFIX UNCRUSTIFY_CFG_FILE )
@@ -69,4 +69,4 @@ macro(untiguard_add_code_checks)
6969
RUNNER ctest -E 'blt_gtest_smoke|testCppCheck|testClangTidy|testUncrustifyCheck|testDoxygenCheck|testCppCheck|testClangTidy'
7070
SOURCE_DIRECTORIES ${PROJECT_SOURCE_DIR}/src )
7171
endif()
72-
endmacro(untiguard_add_code_checks)
72+
endmacro(unitguard_add_code_checks)

scripts/config-build.py

100644100755
File mode changed.

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
set( unitguard_headers
3+
ConstexprAlgorithms.hpp
34
UnitGuard.hpp
45
)
56

src/ConstexprAlgorithms.hpp

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
2+
namespace UnitGuard
3+
{
4+
5+
// Prepend -----------------------------------------------------------------------------
6+
7+
// Forward declaration
8+
template< template< typename... > class VariadicTemplate, typename VariadicInstance, typename Head >
9+
struct Prepend;
10+
11+
// Partial specialization for the instance = `VariadicTemplate<...>`
12+
template< template <typename... > class VariadicTemplate, typename Head, typename... Ts >
13+
struct Prepend< VariadicTemplate, VariadicTemplate< Ts... >, Head >
14+
{
15+
using type = VariadicTemplate< Head, Ts... >;
16+
};
17+
18+
// InsertSorted -----------------------------------------------------------------------------
19+
20+
// Forward declaration
21+
template<
22+
template<typename...> class VariadicTemplate,
23+
typename Comparator,
24+
typename SortedList,
25+
typename Element
26+
>
27+
struct InsertSorted;
28+
29+
// Base case: SortedList is empty
30+
template< template<typename...> class VariadicTemplate, typename Comparator, typename Element >
31+
struct InsertSorted< VariadicTemplate, Comparator, VariadicTemplate<>, Element >
32+
{
33+
using type = VariadicTemplate< Element >;
34+
};
35+
36+
// Recursive case
37+
template<
38+
template<typename...> class VariadicTemplate,
39+
typename Comparator,
40+
typename First,
41+
typename... Rest,
42+
typename Element
43+
>
44+
struct InsertSorted< VariadicTemplate, Comparator, VariadicTemplate< First, Rest... >, Element >
45+
{
46+
private:
47+
// Compare using our user-supplied comparator
48+
static constexpr bool insertHere = Comparator::template compare< Element, First >::value;
49+
50+
// If we don't insert here, we recursively insert into the tail
51+
using TailInsertion = typename InsertSorted< VariadicTemplate, Comparator, VariadicTemplate< Rest... >, Element >::type;
52+
53+
public:
54+
using type = std::conditional_t<
55+
insertHere,
56+
// Insert Element before First
57+
VariadicTemplate< Element, First, Rest... >,
58+
// Keep First, then insert Element into the tail
59+
typename Prepend<
60+
VariadicTemplate,
61+
TailInsertion,
62+
First
63+
>::type
64+
>;
65+
};
66+
67+
// SortPack -----------------------------------------------------------------------------
68+
69+
// Forward declaration
70+
template<
71+
template< typename... > class VariadicTemplate,
72+
typename Comparator,
73+
typename UnsortedList
74+
>
75+
struct SortPack;
76+
77+
// Base case: empty pack is already sorted
78+
template< template<typename...> class VariadicTemplate, typename Comparator >
79+
struct SortPack< VariadicTemplate, Comparator, VariadicTemplate<> >
80+
{
81+
using type = VariadicTemplate<>;
82+
};
83+
84+
// Sort the tail, then insert the head
85+
template<
86+
template<typename...> class VariadicTemplate,
87+
typename Comparator,
88+
typename First,
89+
typename... Rest
90+
>
91+
struct SortPack< VariadicTemplate, Comparator, VariadicTemplate< First, Rest... > >
92+
{
93+
private:
94+
using SortedTail = typename SortPack< VariadicTemplate, Comparator, VariadicTemplate< Rest... > >::type;
95+
96+
public:
97+
using type = typename InsertSorted< VariadicTemplate, Comparator, SortedTail, First >::type;
98+
};
99+
100+
}

src/UnitGuard.hpp

Lines changed: 40 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "ConstexprAlgorithms.hpp"
12

23
namespace UnitGuard
34
{
@@ -12,7 +13,7 @@ struct Power
1213
using base_type = Base;
1314
static constexpr int exponent = Exp;
1415

15-
static_assert( std::is_base_of< BaseUnit, Base >::value, "Power: Base must inherit from AtomTag" );
16+
static_assert( std::is_base_of< AtomTag, Base >::value, "Power: Base must inherit from AtomTag" );
1617
};
1718

1819
// all Units we enforce compile-time constraints on are instantiations of "Unit", even non-composite units
@@ -34,38 +35,43 @@ struct Negate< Unit< Ps... > >
3435

3536
// Merge.hpp -----------------------------------------------------------------------------
3637

37-
// Forward declaration for internal helper that merges a single Power<B,E> into a Unit< Power<B_i, E_i>... >
38-
template < typename UnitT, typename Pow >
39-
struct MergePow;
38+
template < typename UnsortedUnit, typename Head >
39+
using PrependUnit = Prepend< Unit, UnsortedUnit, Head >;
4040

41-
// MergePow when the Unit is empty -> just place the new Power
41+
template < typename UnitInstance, typename Pow >
42+
struct MergeUnits;
43+
44+
// 1) Base case, the base unit was not already present in the `Unit`s pack
4245
template < typename Pow >
43-
struct MergePow< Unit< >, Pow >
46+
struct MergeUnits< Unit< >, Pow >
4447
{
4548
using type = Unit< Pow >;
4649
};
4750

48-
// MergePow when the first element has the same base -> add exponents
51+
// 2) When the first element shares the same base unit -> sum their exponents
4952
template < typename Base, int E1, int E2, typename... Rest >
50-
struct MergePow< Unit< Power< Base, E1 >, Rest... >, Power< Base, E2 > >
53+
struct MergeUnits< Unit< Power< Base, E1 >, Rest... >, Power< Base, E2 > >
5154
{
5255
private:
5356
static constexpr int newExp = E1 + E2;
54-
// If the sum is zero, we drop that base unit from the list
55-
using merged_tail = std::conditional_t< newExp == 0, Unit< Rest... >, Unit< Power< Base, newExp >, Rest... > >;
57+
// If the sum is zero, remove that base unit entirely
58+
using merged_tail = std::conditional_t<
59+
newExp == 0,
60+
Unit< Rest... >,
61+
Unit< Power< Base, newExp >, Rest... >
62+
>;
5663
public:
5764
using type = merged_tail;
5865
};
5966

60-
// MergePow when the first element has a different base -> keep going
67+
// 3) When the first element doesn't share the same base unit -> keep the head, recurse on the tail
6168
template < typename FirstPow, typename Pow, typename... Rest >
62-
struct MergePow< Unit< FirstPow, Rest... >, Pow >
69+
struct MergeUnits< Unit< FirstPow, Rest... >, Pow >
6370
{
6471
private:
65-
using submerge = typename MergePow< Unit< Rest... >, Pow >::type;
72+
using submerge = typename MergeUnits< Unit< Rest... >, Pow >::type;
6673
public:
67-
// Reinsert `FirstPow` at the front
68-
using type = Unit< FirstPow, typename submerge::Powers... >;
74+
using type = typename PrependUnit< submerge, FirstPow >::type;
6975
};
7076

7177
// -----------------------------------------------------------------------------
@@ -82,11 +88,11 @@ struct AddPack< U1, Unit< > >
8288
};
8389

8490
// Recursively add each Power from second to the first
85-
template < typename U1, typename Pow, typename... Tail >
86-
struct AddPack< U1, Unit< Pow, Tail... > >
91+
template < typename P1, typename Pow, typename... Tail >
92+
struct AddPack< P1, Unit< Pow, Tail... > >
8793
{
8894
private:
89-
using merged = typename MergePow< U1, Pow >::type;
95+
using merged = typename MergeUnits< P1, Pow >::type;
9096
public:
9197
using type = typename AddPack< merged, Unit< Tail... > >::type;
9298
};
@@ -111,85 +117,29 @@ struct SubPack< U1, Unit< Pow, Tail... > >
111117
private:
112118
// Subtracting Power<Base, E> is the same as adding Power<Base, -E>
113119
using NegativePow = Power< typename Pow::base_type, -Pow::exponent >;
114-
using merged = typename MergePow< U1, NegativePow >::type;
120+
using merged = typename MergeUnits< U1, NegativePow >::type;
115121
public:
116122
using type = typename SubPack< merged, Unit< Tail... > >::type;
117123
};
118124

119125
// Comparison.hpp -----------------------------------------------------------------------------
120126

121-
122-
123-
// Appends `Head` in front of `Unit<Powers...>`
124-
template<typename UnitT, typename Head>
125-
struct Prepend;
126-
127-
template<typename Head, typename... Powers>
128-
struct Prepend<Unit<Powers...>, Head>
129-
{
130-
using type = Unit<Head, Powers...>;
131-
};
132-
133-
134127
// A simple trait that assigns each base type an integer “rank.”
135128
template< typename Tag >
136129
struct CanonicalOrder;
137130

138-
template< typename P1, typename P2 >
139-
struct LessThan
131+
// The comparator uses CanonicalOrder< T >::value to compare.
132+
struct CanonicalUnitComparitor
140133
{
141-
// P1 and P2 are each PowUnit<SomeBase, Exp>.
142-
static constexpr bool value = ( CanonicalOrder< typename P1::base_type >::value < CanonicalOrder< typename P2::base_type >::value );
143-
};
144-
145-
// A minimal compile-time insertion sort:
146-
template< typename SortedList, typename Element >
147-
struct InsertSorted; // forward declaration
148-
149-
// Base case: Insert into an empty list
150-
template< typename Element >
151-
struct InsertSorted< Unit< >, Element >
152-
{
153-
using type = Unit< Element >;
154-
};
155-
156-
// Recursive: Compare with the first item of SortedList
157-
template< typename First, typename... Rest, typename Element >
158-
struct InsertSorted< Unit< First, Rest... >, Element >
159-
{
160-
// Compare base orders: if Element < First, put Element in front
161-
static constexpr bool insertHere = LessThan< Element, First >::value;
162-
using TailSortedInsertion = typename InsertSorted< Unit< Rest... >, Element >::type;
163-
164-
using type = std::conditional_t<
165-
insertHere,
166-
// If we insert here: [Element, First, Rest...]
167-
Unit< Element, First, Rest... >,
168-
// Keep First, then insert Element into the tail
169-
typename Prepend< TailSortedInsertion, First >::type
170-
>;
171-
};
172-
173-
template < typename UnsortedList >
174-
struct SortPowers;
175-
176-
// Empty list is already sorted
177-
template < >
178-
struct SortPowers< Unit< > >
179-
{
180-
using type = Unit< >;
134+
template< typename P1, typename P2 >
135+
struct compare
136+
{
137+
static constexpr bool value = ( CanonicalOrder< typename P1::base_type >::value < CanonicalOrder< typename P2::base_type >::value );
138+
};
181139
};
182140

183-
// If there's at least one power: sort the tail, then insert the head
184-
template< typename First, typename... Rest >
185-
struct SortPowers< Unit< First, Rest... > >
186-
{
187-
private:
188-
using SortedTail = typename SortPowers< Unit< Rest... > >::type;
189-
190-
public:
191-
using type = typename InsertSorted< SortedTail, First >::type;
192-
};
141+
template < typename UnsortedUnit >
142+
using CanonicalUnit = typename SortPack< Unit, CanonicalUnitComparitor, UnsortedUnit >::type;
193143

194144
/// are_same_units< U1, U2> : check if two Unit<...> have the same (Base,Exp) pairs
195145
template < typename U1, typename U2 >
@@ -200,10 +150,10 @@ struct are_same_units< Unit< P1s... >, Unit< P2s... > >
200150
{
201151
private:
202152
// Sort both packs to canonical order
203-
using U1Sorted = typename SortPowers< U1 >::type;
204-
using U2Sorted = typename SortPowers< U2 >::type;
153+
using CanonicalU1 = typename CanonicalUnit< Unit< P1s... > >::type;
154+
using CanonicalU2 = typename CanonicalUnit< Unit< P2s... > >::type;
205155
public:
206-
static constexpr bool value = std::is_same< U1Sorted, U2Sorted >::value;
156+
static constexpr bool value = std::is_same< CanonicalU1, CanonicalU2 >::value;
207157
};
208158

209159
// -----------------------------------------------------------------------------
@@ -222,16 +172,16 @@ struct Divide
222172
using type = typename SubPack< U1, U2 >::type;
223173
};
224174

225-
/// Invert<U> -> NegatePack
175+
/// Invert<U> -> Negate
226176
template< typename U >
227177
struct Invert
228178
{
229-
using type = typename NegatePack< U >::type;
179+
using type = typename Negate< U >::type;
230180
};
231181

232182
// -----------------------------------------------------------------------------
233183

234-
#define ENABLE_UNITGUARD 1;
184+
#define ENABLE_UNITGUARD 1
235185
#if ENABLE_UNITGUARD == 1
236186
template < typename T, typename U >
237187
class Quantity

src/UnitGuardConfig.hpp.in

Whitespace-only changes.

src/unitTests/CMakeLists.txt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#
2+
# Specify list of tests
3+
#
4+
5+
set( unit_tests_sources
6+
testConstexprAlgorithms.cpp
7+
testUnitGuard.cpp
8+
)
9+
10+
set( dependencyList gtest unitguard )
11+
12+
if( ENABLE_HIP )
13+
list( APPEND dependencyList blt::hip )
14+
endif()
15+
16+
if( ENABLE_CUDA )
17+
list( APPEND dependencyList cuda )
18+
endif()
19+
20+
#
21+
# Add gtest C++ based tests
22+
#
23+
foreach(test ${unit_tests_sources})
24+
message(DEBUG "test is ${test}")
25+
set( header ${test} )
26+
string(REPLACE "test" "../" header ${header})
27+
string(REPLACE ".cpp" ".hpp" header ${header})
28+
message(DEBUG "header is ${header}")
29+
30+
get_filename_component( test_name ${test} NAME_WE )
31+
blt_add_executable( NAME ${test_name}
32+
SOURCES ${test}
33+
HEADERS ${header}
34+
OUTPUT_DIR ${TEST_OUTPUT_DIRECTORY}
35+
DEPENDS_ON ${dependencyList}
36+
)
37+
38+
blt_add_test( NAME ${test_name}
39+
COMMAND ${test_name}
40+
)
41+
endforeach()

0 commit comments

Comments
 (0)