Skip to content

Commit ab42d38

Browse files
committed
initial commit of old prototype
0 parents  commit ab42d38

File tree

5 files changed

+316
-0
lines changed

5 files changed

+316
-0
lines changed

.gitignore

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
build-*
2+
install-*
3+
.DS_Store
4+
.vscode
5+
# Prerequisites
6+
*.d
7+
# Compiled Object files
8+
*.slo
9+
*.lo
10+
*.o
11+
*.obj
12+
# Precompiled Headers
13+
*.gch
14+
*.pch
15+
# Compiled Dynamic libraries
16+
*.so
17+
*.dylib
18+
*.dll
19+
# Fortran module files
20+
*.mod
21+
*.smod
22+
# Compiled Static libraries
23+
*.lai
24+
*.la
25+
*.a
26+
*.lib
27+
# Executables
28+
*.exe
29+
*.out
30+
*.app

CMakeLists.txt

Whitespace-only changes.

LICENSE

Whitespace-only changes.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# UnitGuard

src/UnitGuard.hpp

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
#include <iostream>
2+
#include <type_traits>
3+
#include <tuple>
4+
#include <cxxabi.h>
5+
#include <typeinfo>
6+
#include <memory>
7+
#include <cstdlib>
8+
#include <string>
9+
10+
// Base unit struct for distinguishing different units
11+
struct BaseUnit {};
12+
13+
template<typename... Units>
14+
struct Unit {
15+
// Static assert to check all Units are derived from BaseUnit
16+
static_assert(std::conjunction<std::is_base_of<BaseUnit, Units>...>::value,
17+
"All units in Unit must be subclasses of BaseUnit");
18+
};
19+
20+
// Specific physical quantity tags
21+
struct Length : BaseUnit {};
22+
struct Mass : BaseUnit {};
23+
struct Time : BaseUnit {};
24+
25+
// Template to represent inverse units
26+
template<typename U>
27+
struct InverseUnit : BaseUnit
28+
{
29+
static_assert(std::is_base_of<BaseUnit, U>::value, "U must be a subclass of BaseUnit");
30+
};
31+
32+
template<typename U>
33+
struct Invert;
34+
35+
// Example of a compound unit: Length*Time^-1
36+
using VelocityUnit = Unit<Length, InverseUnit<Time>>;
37+
38+
template<typename U1, typename U2>
39+
struct CanMultiply : std::true_type {};
40+
41+
template<typename U1, typename U2>
42+
struct CanDivide : std::true_type {};
43+
44+
/// Unit Simplification Logic
45+
template <typename>
46+
struct SimplifyUnit;
47+
48+
template<>
49+
struct SimplifyUnit<Unit<>> {
50+
using type = Unit<>;
51+
};
52+
53+
54+
// Type trait to detect inverse units
55+
template<typename U>
56+
struct IsInverseUnit : std::false_type {};
57+
58+
template<typename U>
59+
struct IsInverseUnit<InverseUnit<U>> : std::true_type {};
60+
61+
62+
63+
64+
template<typename List, typename U>
65+
struct AppendUnit;
66+
67+
template<typename... Units, typename U>
68+
struct AppendUnit<Unit<Units...>, U> {
69+
using type = Unit<Units..., U>;
70+
};
71+
72+
73+
74+
// Base template for a single unit, enabled only when U is not an InverseUnit
75+
template<typename U>
76+
struct Invert {
77+
using type = InverseUnit<U>;
78+
};
79+
80+
// Specialization for an InverseUnit to strip one layer of inversion
81+
template<typename U>
82+
struct Invert<InverseUnit<U>> {
83+
using type = U; // Simplifies the double inversion
84+
};
85+
86+
// Helper to invert a unit pack
87+
template<typename... Units>
88+
struct InvertUnitPack;
89+
90+
template<typename U, typename... Us>
91+
struct InvertUnitPack<U, Us...> {
92+
using type = typename AppendUnit<typename InvertUnitPack<Us...>::type, typename Invert<U>::type>::type;
93+
};
94+
95+
template<>
96+
struct InvertUnitPack<> {
97+
using type = Unit<>;
98+
};
99+
100+
101+
template<typename List, typename U>
102+
struct RemoveUnit;
103+
104+
// Base case: When the list is empty
105+
template<typename U>
106+
struct RemoveUnit<Unit<>, U> {
107+
using type = Unit<>;
108+
};
109+
110+
// Recursive case: when the first type matches the type to remove
111+
template<typename First, typename... Rest>
112+
struct RemoveUnit<Unit<First, Rest...>, First> {
113+
using type = Unit<Rest...>; // Remove First and return the rest
114+
};
115+
116+
// Recursive case: when the first type does not match
117+
template<typename First, typename... Rest, typename U>
118+
struct RemoveUnit<Unit<First, Rest...>, U> {
119+
using type = typename AppendUnit<typename RemoveUnit<Unit<Rest...>, U>::type, First>::type;
120+
};
121+
122+
static_assert(std::is_same<typename RemoveUnit<Unit<Time>, Time>::type, Unit<>>::value, "Unit<Time> should be removed, leaving an empty list.");
123+
124+
template<typename List, typename T>
125+
struct CountType;
126+
127+
template<typename T>
128+
struct CountType<Unit<>, T> : std::integral_constant<int, 0> {};
129+
130+
// Recursive case: Increment count if First is the same type as T, then continue checking the rest.
131+
template<typename First, typename... Rest, typename T>
132+
struct CountType<Unit<First, Rest...>, T>
133+
: std::integral_constant<int, std::is_same<Unit<First>, Unit<T>>::value + CountType<Unit<Rest...>, T>::value> {};
134+
135+
136+
137+
template<typename Unit1, typename Unit2>
138+
struct Multiply;
139+
140+
template<typename... Units1, typename... Units2>
141+
struct Multiply<Unit<Units1...>, Unit<Units2...>> {
142+
using type = typename SimplifyUnit<Unit<Units1..., Units2...>>::type;
143+
};
144+
145+
146+
147+
template<typename Unit1, typename Unit2>
148+
struct Divide;
149+
150+
// Modified Divide to use InvertUnitPack for the second unit pack
151+
template<typename... Units1, typename... Units2>
152+
struct Divide<Unit<Units1...>, Unit<Units2...>> {
153+
using InvertedUnits2 = typename InvertUnitPack<Units2...>::type;
154+
using type = typename Multiply<Unit<Units1...>, InvertedUnits2>::type;
155+
};
156+
157+
158+
159+
template< typename List >
160+
struct CancelUnits;
161+
162+
template<>
163+
struct CancelUnits<Unit<>> {
164+
using type = Unit<>;
165+
};
166+
167+
template< typename U >
168+
struct CancelUnits<Unit<U>> {
169+
using type = Unit<U>;
170+
};
171+
172+
template<typename First, typename... Rest>
173+
struct CancelUnits<Unit<First, Rest...>> {
174+
using RestSimplified = typename CancelUnits<Unit<Rest...>>::type;
175+
// static_assert( std::is_same< RestSimplified, Unit<Time> >::value );
176+
177+
// Determine if the inverse of First exists in the simplified rest
178+
static constexpr bool hasInverse = CountType<RestSimplified, typename Invert<First>::type>::value > 0;
179+
// static_assert( CountType<RestSimplified, typename Invert<First>::type>::value == 1 );
180+
// static_assert( hasInverse );
181+
182+
// static_assert( std::is_same< typename Invert<First>::type, Time >::value );
183+
184+
// Type used to remove the inverse of First if found
185+
using RestWithoutInverse = typename std::conditional<
186+
hasInverse,
187+
typename RemoveUnit<RestSimplified, typename Invert<First>::type>::type,
188+
RestSimplified
189+
>::type;
190+
// static_assert( std::is_same< typename RemoveUnit<RestSimplified, typename Invert<First>::type>::type, Unit<Time> >::value );
191+
// static_assert( std::is_same< RestWithoutInverse, Unit<> >::value );
192+
193+
// Recurse on the potentially modified list after modification (removal of First and its inverse)
194+
using type = typename std::conditional<
195+
hasInverse,
196+
typename CancelUnits<RestWithoutInverse>::type, // Continue simplification without First and its inverse
197+
typename AppendUnit<RestWithoutInverse, First>::type // No inverse found, add First back to the list and continue
198+
>::type;
199+
};
200+
201+
template<typename... Units>
202+
struct SimplifyUnit<Unit<Units...>> {
203+
using type = typename CancelUnits<Unit<Units...>>::type;
204+
};
205+
206+
207+
template<typename List1, typename List2>
208+
struct EquivalentUnits;
209+
210+
template<typename... Types1, typename... Types2>
211+
struct EquivalentUnits<Unit<Types1...>, Unit<Types2...>> {
212+
static constexpr bool compare_each() {
213+
return (... && (CountType<Unit<Types1...>, Types2>::value == CountType<Unit<Types2...>, Types1>::value));
214+
}
215+
216+
static constexpr bool value = compare_each();
217+
};
218+
219+
220+
// template<typename T, typename U>
221+
// class Quantity {
222+
// public:
223+
// T value;
224+
225+
// explicit Quantity(T v) : value(v) {}
226+
227+
// operator T() const {
228+
// return value;
229+
// }
230+
231+
// operator std::string() const {
232+
// return std::to_string(value); // Removed demangle for simplification
233+
// }
234+
235+
// // Ensure units are the same for addition and subtraction
236+
// Quantity& operator+=(const Quantity& other) {
237+
// static_assert(std::is_same<U, U>::value, "Cannot add different units");
238+
// value += other.value;
239+
// return *this;
240+
// }
241+
242+
// Quantity& operator-=(const Quantity& other) {
243+
// static_assert(std::is_same<U, U>::value, "Cannot subtract different units");
244+
// value -= other.value;
245+
// return *this;
246+
// }
247+
248+
// Quantity operator+(const Quantity& other) const {
249+
// return Quantity(value + other.value);
250+
// }
251+
252+
// Quantity operator-(const Quantity& other) const {
253+
// return Quantity(value - other.value);
254+
// }
255+
256+
// // Multiplication (results in compound unit)
257+
// template<typename OU>
258+
// auto operator*(const Quantity<T, OU>& other) const {
259+
// static_assert(CanMultiply<U, OU>::value, "Cannot multiply these units");
260+
// using ResultUnit = typename SimplifyUnit< typename Multiply< U, OU >::type >::type;
261+
// return Quantity<T, ResultUnit>(value * other.value);
262+
// }
263+
264+
// // Division (results in unit ratio)
265+
// template<typename OU>
266+
// auto operator/(const Quantity<T, OU>& other) const {
267+
// static_assert(CanDivide<U, OU>::value, "Cannot divide these units");
268+
// using ResultUnit = typename SimplifyUnit< typename Divide< U, OU >::type >::type;
269+
// return Quantity<T, Unit<>>(value / other.value);
270+
// }
271+
// };
272+
273+
// Quantity< double, Length > operator "" _L( long double length ) { return Quantity< double, Length >( length ); }
274+
// Quantity< double, Length > operator "" _L( unsigned long long length ) { return Quantity< double, Length >( length ); }
275+
276+
277+
278+
template<typename T>
279+
void printTypeName() {
280+
const std::type_info& ti = typeid(T);
281+
int status = -1;
282+
std::unique_ptr<char, void(*)(void*)> demangled_name(
283+
abi::__cxa_demangle(ti.name(), nullptr, nullptr, &status), std::free);
284+
std::cout << "The type is: " << (status == 0 ? demangled_name.get() : ti.name()) << std::endl;
285+
}

0 commit comments

Comments
 (0)