summaryrefslogtreecommitdiff
path: root/modules/codec-unit/c++/unit_transform.hpp
blob: 2e1ace44287100e54f9e6977c782abcd9bf4eb40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#pragma once

#include <forstio/common.hpp>

#include <type_traits>
#include "unit_schema.hpp"

namespace saw {
namespace impl {

template<typename T, typename U>
class unit_matching;

template<typename... T>
class unit_redux_list {
	static_assert(sizeof...(T) == 0u, "Template type not supported");

	using Type = unit_redux_list<>;
};

template<typename T0, int64_t E0, typename... TL, int64_t... EL>
struct unit_redux_list<schema::UnitElement<T0,E0>, schema::UnitElement<TL,EL>...> {
	using Type = typename unit_matching<unit_redux_list<schema::UnitElement<T0,E0>, schema::UnitElement<TL,EL>...>, unit_redux_list<>>::TypeList;
};

template<typename T, typename U, typename V>
class unit_matching_reduce {
public:
	static_assert(always_false<T,U,V>, "Template type not supported");
};

/**
 * Iterate over the left list to check against the left element.
 */
template<typename T, int64_t E, typename T0, int64_t E0, typename... TL, int64_t... EL, typename... TR, int64_t... ER>
class unit_matching_reduce<schema::UnitElement<T,E>, unit_redux_list<schema::UnitElement<T0,E0>,schema::UnitElement<TL,EL>...>, unit_redux_list<schema::UnitElement<TR,ER>...>> {
public:
	static constexpr bool is_same = std::is_same_v<T,T0>;

	// Match T,E against T0,E0
	using ReducedType = typename std::conditional<is_same, schema::UnitElement<T,E+E0>, schema::UnitElement<T,E>>::type;
	using ReducedTypeList = typename std::conditional<is_same, unit_redux_list<schema::UnitElement<TR,ER>...>, unit_redux_list<schema::UnitElement<TR,ER>..., schema::UnitElement<T0,E0>>>::type;

	using NextMatcher = unit_matching_reduce<ReducedType, unit_redux_list<schema::UnitElement<TL,EL>...>, ReducedTypeList>;
	using Type = typename NextMatcher::Type;
	using TypeList = typename NextMatcher::TypeList;
	static constexpr int64_t Num = NextMatcher::Num;
};

/**
 * Final step after going through the list. This contains the final match result.
 * On the left is the accumulated type and on the right its's a list of non matching types
 */
template<typename T, int64_t E, typename... TR, int64_t... ER>
class unit_matching_reduce<schema::UnitElement<T,E>, unit_redux_list<>, unit_redux_list<schema::UnitElement<TR,ER>...>> {
public:
	using Type = schema::UnitElement<T,E>;
	using TypeList = unit_redux_list<schema::UnitElement<TR,ER>...>;
	static constexpr int64_t Num = E;
};

template<typename LR, typename RR>
class unit_matching {
	static_assert(always_false<LR,RR>, "Template type not supported");
};

template<typename... Ele>
class unit_matching<unit_redux_list<>, unit_redux_list<Ele...>> {
public:
	using TypeList = unit_redux_list<Ele...>;
};

template<typename Ele0, typename... EleL, typename... EleR>
class unit_matching<unit_redux_list<Ele0, EleL...>, unit_redux_list<EleR...>> {
public:
	// static constexpr bool is_same = std::is_same_v<T,T0>;

	using MatchReducer = unit_matching_reduce<Ele0, unit_redux_list<EleL...>, unit_redux_list<>>;

	using ReducedType = typename MatchReducer::Type;
	using ReducedTypeList = typename MatchReducer::TypeList;
	static constexpr int64_t Num = MatchReducer::Num;

	using TypeRightList = typename std::conditional<Num == 0u, unit_redux_list<EleR...>, unit_redux_list<EleR..., ReducedType>>::type;
	using TypeList = typename unit_matching<ReducedTypeList, TypeRightList>::TypeList;
};

template<typename BaseSchema, typename List>
class unit_add_base {
	static_assert(always_false<BaseSchema,List>, "Template type not supported");
};

template<typename BaseSchema, typename... Ele>
class unit_add_base<BaseSchema, unit_redux_list<Ele...>> {
public:
	using Schema = schema::Unit<BaseSchema, Ele...>;
};
}

template<typename BaseSchema, typename... UE>
struct unit_element_reduction {
	using TypeList = typename impl::unit_matching<impl::unit_redux_list<UE...>, impl::unit_redux_list<>>::TypeList;
	using Schema = typename impl::unit_add_base<BaseSchema, TypeList>::Schema;
};

template<typename U0, typename U1>
struct unit_multiplication {
	static_assert(always_false<U0,U1>, "Template type not supported");
};

template<typename BaseSchema, typename... UnitT, int64_t... UnitE, typename... UnitRhsT, int64_t... UnitRhsE>
struct unit_multiplication<
	schema::Unit<BaseSchema, schema::UnitElement<UnitT,UnitE>...>,schema::Unit<BaseSchema, schema::UnitElement<UnitRhsT,UnitRhsE>...>
> {
	using Schema = typename unit_element_reduction<BaseSchema, schema::UnitElement<UnitT,UnitE>..., schema::UnitElement<UnitRhsT, UnitRhsE>...>::Schema;
};

template<typename U0, typename U1>
struct unit_division {
	static_assert(always_false<U0,U1>, "Template type not supported");
};

template<typename BaseSchema, typename... UnitT, int64_t... UnitE, typename... UnitRhsT, int64_t... UnitRhsE>
struct unit_division<
	schema::Unit<BaseSchema, schema::UnitElement<UnitT,UnitE>...>,schema::Unit<BaseSchema, schema::UnitElement<UnitRhsT,UnitRhsE>...>
> {
	using Schema = typename unit_element_reduction<BaseSchema, schema::UnitElement<UnitT,UnitE>..., schema::UnitElement<UnitRhsT, -UnitRhsE>...>::Schema;
};

}