summaryrefslogtreecommitdiff
path: root/c++/core/templates.h
blob: e2851a086140e78cdb853049172123124d3d3cb9 (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#pragma once

#include "string_literal.h"

namespace saw {

template <class T, class... TL> struct parameter_pack_index;

template <class T, class... TL> struct parameter_pack_index<T, T, TL...> {
	static constexpr size_t value = 0u;
};

template <class T, class TL0, class... TL>
struct parameter_pack_index<T, TL0, TL...> {
	static constexpr size_t value =
		1u + parameter_pack_index<T, TL...>::value;
};

template <size_t N, class... T> struct parameter_pack_type {
	static_assert(always_false<T...>, "Should've been caught by the specializations");
};

template <class TN, class... T> struct parameter_pack_type<0, TN, T...> {
	using type = TN;
};

template <size_t N, class TN, class... T>
struct parameter_pack_type<N, TN, T...> {
	static_assert(sizeof...(T) > 0, "Exhausted parameters");
	static_assert(N > 0, "Invalid number. Should've been caught");
	using type = typename parameter_pack_type<N - 1, T...>::type;
};
/*
 * Nightmare inducing compiler problems found here. Somehow non-type
 * string_literals cannot be resolved as non-type primitive template values can.
 * This is the workaround
 */
template <string_literal V, string_literal Key0, string_literal... Keys>
struct parameter_key_pack_index_helper {
	static constexpr size_t value =
		(V == Key0)
			? (0u)
			: (1u + parameter_key_pack_index_helper<V, Keys...>::value);
};

template <string_literal V, string_literal Key0>
struct parameter_key_pack_index_helper<V, Key0> {
	static constexpr size_t value = (V == Key0) ? (0u) : (1u);
};

template <string_literal V, string_literal... Keys>
struct parameter_key_pack_index {
	static constexpr size_t value =
		parameter_key_pack_index_helper<V, Keys...>::value;
	static_assert(value < sizeof...(Keys),
				  "Provided string_literal doesn't exist in searched list");
};

template <size_t i, size_t s, string_literal Key0, string_literal... Keys>
struct parameter_key_pack_type_helper {
	static constexpr string_literal literal = parameter_key_pack_type_helper<i, s+1, Keys...>::literal;
};

template <size_t i, string_literal Key0, string_literal... Keys>
struct parameter_key_pack_type_helper<i, i, Key0, Keys...> {
	static constexpr string_literal literal = Key0;
};

template <size_t i, string_literal... Keys>
struct parameter_key_pack_type {
	static constexpr string_literal literal = parameter_key_pack_type_helper<i, 0, Keys...>::literal;

	static_assert(i < sizeof...(Keys), "Provided index is too large for list");
};

template<std::size_t i, std::size_t s, typename T, T V0, T... VN>
struct parameter_pack_value_helper {
	static constexpr T value = parameter_pack_value_helper<i, s+1, T, VN...>::value;
};

template<std::size_t i, typename T, T V0, T... VN>
struct parameter_pack_value_helper<i, i, T, V0, VN...> {
	static constexpr T value = V0;
};

template<std::size_t i, typename T, T... Values>
struct parameter_pack_value {
	static constexpr T value = parameter_pack_value_helper<i, 0, T, Values...>::value;
	static_assert(i < sizeof...(Values), "Provided index is too large for list");
};

template<typename T, T... V>
struct ct_multiply;

template<typename T>
struct ct_multiply<T> {
	static constexpr T value = 1;
};

template<typename T, T V0, T... VN>
struct ct_multiply<T, V0, VN...> {
	static constexpr T value = V0 * ct_multiply<T,VN...>::value;
};

namespace impl {
template<typename T, size_t i>
struct ct_convert_digits_table_helper {
		static constexpr std::array<T, 16> table = {
				'0', '1', '2', '3',
				'4', '5', '6', '7',
				'8', '9', 'A', 'B',
				'C', 'D', 'E', 'F'
		};

		static constexpr T value = table[i];
};

template<uint64_t Num, uint64_t Base, uint64_t... Digs>
struct ct_convert_digits_helper {
		static constexpr size_t size = ct_convert_digits_helper<Num / Base, Base, Num % Base, Digs...>::size;
		static constexpr std::array<uint64_t, size> value = ct_convert_digits_helper<Num / Base, Base, Num % Base, Digs...>::value;
};

template<uint64_t Base, uint64_t... Digs>
struct ct_convert_digits_helper<0, Base, Digs...> {
		static constexpr size_t size = sizeof...(Digs);
		static constexpr std::array<uint64_t, size> value = {Digs...};
};

template<uint64_t Base>
struct ct_convert_digits_helper<0, Base> {
		static constexpr size_t size = 0;
		static constexpr std::array<uint64_t, 1> value = {0};
};
}

template<uint64_t Num, uint64_t Base>
struct ct_convert_to_digits {
		static_assert(Base <= 16, "Only conversion up to hex is supported");

		static constexpr size_t size = impl::ct_convert_digits_helper<Num, Base>::size;
		static constexpr std::array<uint64_t, size> value = impl::ct_convert_digits_helper<Num, Base>::value;
};
}