CANdevStudio
Development tool for CAN bus simulation
Loading...
Searching...
No Matches
typestring.hh
Go to the documentation of this file.
1/*~
2 * Copyright (C) 2015, 2016 George Makrydakis <george@irrequietus.eu>
3 *
4 * The 'typestring' header is a single header C++ library for creating types
5 * to use as type parameters in template instantiations, repository available
6 * at https://github.com/irrequietus/typestring. Conceptually stemming from
7 * own implementation of the same thing (but in a more complicated manner to
8 * be revised) in 'clause': https://github.com/irrequietus/clause.
9 *
10 * File subject to the terms and conditions of the Mozilla Public License v 2.0.
11 * If a copy of the MPLv2 license text was not distributed with this file, you
12 * can obtain it at: http://mozilla.org/MPL/2.0/.
13 */
14
15#ifndef IRQUS_TYPESTRING_HH_
16#define IRQUS_TYPESTRING_HH_
17
18namespace irqus {
19
20/*~
21 * @desc A class 'storing' strings into distinct, reusable compile-time types that
22 * can be used as type parameters in a template parameter list.
23 * @tprm C... : char non-type parameter pack whose ordered sequence results
24 * into a specific string.
25 * @note Could have wrapped up everything in a single class, eventually will,
26 * once some compilers fix their class scope lookups! I have added some
27 * utility functions because asides being a fun little project, it is of
28 * use in certain constructs related to template metaprogramming
29 * nonetheless.
30 */
31template<char... C>
32struct typestring final {
33private:
34 static constexpr char const vals[sizeof...(C)+1] = { C...,'\0' };
35 static constexpr unsigned int sval = sizeof...(C);
36public:
37
38 static constexpr char const * data() noexcept
39 { return &vals[0]; }
40
41 static constexpr unsigned int size() noexcept
42 { return sval; };
43
44 static constexpr char const * cbegin() noexcept
45 { return &vals[0]; }
46
47 static constexpr char const * cend() noexcept
48 { return &vals[sval]; }
49};
50
51template<char... C>
52constexpr char const typestring<C...>::vals[sizeof...(C)+1];
53
54//*~ part 1: preparing the ground, because function templates are awesome.
55
56/*~
57 * @note While it is easy to resort to constexpr strings for use in constexpr
58 * metaprogramming, what we want is to convert compile time string in situ
59 * definitions into reusable, distinct types, for use in advanced template
60 * metaprogramming techniques. We want such features because this kind of
61 * metaprogramming constitutes a pure, non-strict, untyped functional
62 * programming language with pattern matching where declarative semantics
63 * can really shine.
64 *
65 * Currently, there is no feature in C++ that offers the opportunity to
66 * use strings as type parameter types themselves, despite there are
67 * several, different library implementations. This implementation is a
68 * fast, short, single-header, stupid-proof solution that works with any
69 * C++11 compliant compiler and up, with the resulting type being easily
70 * reusable throughout the code.
71 *
72 * @usge Just include the header and enable -std=c++11 or -std=c++14 etc, use
73 * like in the following example:
74 *
75 * typestring_is("Hello!")
76 *
77 * is essentially identical to the following template instantiation:
78 *
79 * irqus::typestring<'H', 'e', 'l', 'l', 'o', '!'>
80 *
81 * By passing -DUSE_TYPESTRING=<power of 2> during compilation, you can
82 * set the maximum length of the 'typestring' from 1 to 1024 (2^0 to 2^10).
83 * Although all preprocessor implementations tested are capable of far
84 * more with this method, exceeding this limit may cause internal compiler
85 * errors in most, with at times rather hilarious results.
86 */
87
88template<int N, int M>
89constexpr char tygrab(char const(&c)[M]) noexcept
90{ return c[N < M ? N : M-1]; }
91
92//*~ part2: Function template type signatures for type deduction purposes. In
93// other words, exploiting the functorial nature of parameter packs
94// while mixing them with an obvious catamorphism through pattern
95// matching galore (partial ordering in this case in C++ "parlance").
96
97template<char... X>
98auto typoke(typestring<X...>) // as is...
99 -> typestring<X...>;
100
101template<char... X, char... Y>
103 -> typestring<X...>;
104
105template<char A, char... X, char... Y>
107 -> decltype(typoke(typestring<X...,A>(), typestring<Y>()...));
108
109template<char... C>
111 -> decltype(typoke(typestring<C>()...));
112
113template<char... A, char... B, typename... X>
115 -> decltype(tycat_(typestring<A..., B...>(), x...));
116
117template<char... X>
119 -> typestring<X...>;
120
121/*
122 * Some people actually using this header as is asked me to include
123 * a typestring "cat" utility given that it is easy enough to implement.
124 * I have added this functionality through the template alias below. For
125 * the obvious implementation, nothing more to say. All T... must be
126 * of course, "typestrings".
127 */
128template<typename... T>
129using tycat
130 = decltype(tycat_(T()...));
131
132} /* irqus */
133
134
135//*~ part3: some necessary code generation using preprocessor metaprogramming!
136// There is functional nature in preprocessor metaprogramming as well.
137
138/*~
139 * @note Code generation block. Undoubtedly, the preprocessor implementations
140 * of both clang++ and g++ are relatively competent in producing a
141 * relatively adequate amount of boilerplate for implementing features
142 * that the language itself will probably be having as features in a few
143 * years. At times, like herein, the preprocessor is able to generate
144 * boilerplate *extremely* fast, but over a certain limit the compiler is
145 * incapable of compiling it. For the record, only certain versions of
146 * g++ where capable of going beyond 4K, so I thought of going from base
147 * 16 to base 2 for USE_TYPESTRING power base. For the record, it takes
148 * a few milliseconds to generate boilerplate for several thousands worth
149 * of "string" length through such an 'fmap' like procedure.
150 */
151
152/* 2^0 = 1 */
153#define TYPESTRING1(n,x) irqus::tygrab<0x##n##0>(x)
154
155/* 2^1 = 2 */
156#define TYPESTRING2(n,x) irqus::tygrab<0x##n##0>(x), irqus::tygrab<0x##n##1>(x)
157
158/* 2^2 = 2 */
159#define TYPESTRING4(n,x) \
160 irqus::tygrab<0x##n##0>(x), irqus::tygrab<0x##n##1>(x) \
161 , irqus::tygrab<0x##n##2>(x), irqus::tygrab<0x##n##3>(x)
162
163/* 2^3 = 8 */
164#define TYPESTRING8(n,x) \
165 irqus::tygrab<0x##n##0>(x), irqus::tygrab<0x##n##1>(x) \
166 , irqus::tygrab<0x##n##2>(x), irqus::tygrab<0x##n##3>(x) \
167 , irqus::tygrab<0x##n##4>(x), irqus::tygrab<0x##n##5>(x) \
168 , irqus::tygrab<0x##n##6>(x), irqus::tygrab<0x##n##7>(x)
169
170/* 2^4 = 16 */
171#define TYPESTRING16(n,x) \
172 irqus::tygrab<0x##n##0>(x), irqus::tygrab<0x##n##1>(x) \
173 , irqus::tygrab<0x##n##2>(x), irqus::tygrab<0x##n##3>(x) \
174 , irqus::tygrab<0x##n##4>(x), irqus::tygrab<0x##n##5>(x) \
175 , irqus::tygrab<0x##n##6>(x), irqus::tygrab<0x##n##7>(x) \
176 , irqus::tygrab<0x##n##8>(x), irqus::tygrab<0x##n##9>(x) \
177 , irqus::tygrab<0x##n##A>(x), irqus::tygrab<0x##n##B>(x) \
178 , irqus::tygrab<0x##n##C>(x), irqus::tygrab<0x##n##D>(x) \
179 , irqus::tygrab<0x##n##E>(x), irqus::tygrab<0x##n##F>(x)
180
181/* 2^5 = 32 */
182#define TYPESTRING32(n,x) \
183 TYPESTRING16(n##0,x),TYPESTRING16(n##1,x)
184
185/* 2^6 = 64 */
186#define TYPESTRING64(n,x) \
187 TYPESTRING16(n##0,x), TYPESTRING16(n##1,x), TYPESTRING16(n##2,x) \
188 , TYPESTRING16(n##3,x)
189
190/* 2^7 = 128 */
191#define TYPESTRING128(n,x) \
192 TYPESTRING16(n##0,x), TYPESTRING16(n##1,x), TYPESTRING16(n##2,x) \
193 , TYPESTRING16(n##3,x), TYPESTRING16(n##4,x), TYPESTRING16(n##5,x) \
194 , TYPESTRING16(n##6,x), TYPESTRING16(n##7,x)
195
196/* 2^8 = 256 */
197#define TYPESTRING256(n,x) \
198 TYPESTRING16(n##0,x), TYPESTRING16(n##1,x), TYPESTRING16(n##2,x) \
199 , TYPESTRING16(n##3,x), TYPESTRING16(n##4,x), TYPESTRING16(n##5,x) \
200 , TYPESTRING16(n##6,x), TYPESTRING16(n##7,x), TYPESTRING16(n##8,x) \
201 , TYPESTRING16(n##9,x), TYPESTRING16(n##A,x), TYPESTRING16(n##B,x) \
202 , TYPESTRING16(n##C,x), TYPESTRING16(n##D,x), TYPESTRING16(n##E,x) \
203 , TYPESTRING16(n##F,x)
204
205/* 2^9 = 512 */
206#define TYPESTRING512(n,x) \
207 TYPESTRING256(n##0,x), TYPESTRING256(n##1,x)
208
209/* 2^10 = 1024 */
210#define TYPESTRING1024(n,x) \
211 TYPESTRING256(n##0,x), TYPESTRING256(n##1,x), TYPESTRING256(n##2,x) \
212 , TYPESTRING128(n##3,x), TYPESTRING16(n##38,x), TYPESTRING16(n##39,x) \
213 , TYPESTRING16(n##3A,x), TYPESTRING16(n##3B,x), TYPESTRING16(n##3C,x) \
214 , TYPESTRING16(n##3D,x), TYPESTRING16(n##3E,x), TYPESTRING16(n##3F,x)
215
216//*~ part4 : Let's give some logic with a -DUSE_TYPESTRING flag!
217
218#ifdef USE_TYPESTRING
219#if USE_TYPESTRING == 0
220#define typestring_is(x) \
221 decltype(irqus::typeek(irqus::typestring<TYPESTRING1(,x)>()))
222#elif USE_TYPESTRING == 1
223#define typestring_is(x) \
224 decltype(irqus::typeek(irqus::typestring<TYPESTRING2(,x)>()))
225#elif USE_TYPESTRING == 2
226#define typestring_is(x) \
227 decltype(irqus::typeek(irqus::typestring<TYPESTRING4(,x)>()))
228#elif USE_TYPESTRING == 3
229#define typestring_is(x) \
230 decltype(irqus::typeek(irqus::typestring<TYPESTRING8(,x)>()))
231#elif USE_TYPESTRING == 4
232#define typestring_is(x) \
233 decltype(irqus::typeek(irqus::typestring<TYPESTRING16(,x)>()))
234#elif USE_TYPESTRING == 5
235#define typestring_is(x) \
236 decltype(irqus::typeek(irqus::typestring<TYPESTRING32(,x)>()))
237#elif USE_TYPESTRING == 6
238#define typestring_is(x) \
239 decltype(irqus::typeek(irqus::typestring<TYPESTRING64(,x)>()))
240#elif USE_TYPESTRING == 7
241#define typestring_is(x) \
242 decltype(irqus::typeek(irqus::typestring<TYPESTRING128(,x)>()))
243#elif USE_TYPESTRING == 8
244#define typestring_is(x) \
245 decltype(irqus::typeek(irqus::typestring<TYPESTRING256(,x)>()))
246#elif USE_TYPESTRING == 9
247#define typestring_is(x) \
248 decltype(irqus::typeek(irqus::typestring<TYPESTRING512(,x)>()))
249#elif USE_TYPESTRING == 10
250#define typestring_is(x) \
251 decltype(irqus::typeek(irqus::typestring<TYPESTRING1024(,x)>()))
252#elif USE_TYPESTRING > 10
253
254#warning !!!: custom typestring length exceeded allowed (1024) !!!
255#warning !!!: all typestrings to default maximum typestring length of 64 !!!
256#warning !!!: you can use -DUSE_TYPESTRING=<power of two> to set length !!!
257
258#define typestring_is(x) \
259 decltype(irqus::typeek(irqus::typestring<TYPESTRING64(,x)>()))
260
261#elif USE_TYPESTRING < 0
262
263#warning !!!: You used USE_TYPESTRING with a negative size specified !!!
264#warning !!!: all typestrings to default maximum typestring length of 64 !!!
265#warning !!!: you can use -DUSE_TYPESTRING=<power of two> to set length !!!
266
267#define typestring_is(x) \
268 decltype(irqus::typeek(irqus::typestring<TYPESTRING64(,x)>()))
269
270#endif
271#else
272#define typestring_is(x) \
273 decltype(irqus::typeek(irqus::typestring<TYPESTRING64(,x)>()))
274#endif
275#endif /* IRQUS_TYPESTRING_HH_ */
Definition typestring.hh:18
auto tycat_(typestring< A... >, typestring< B... >, X... x) -> decltype(tycat_(typestring< A..., B... >(), x...))
decltype(tycat_(T()...)) tycat
Definition typestring.hh:130
auto typeek(typestring< C... >) -> decltype(typoke(typestring< C >()...))
auto typoke(typestring< X... >) -> typestring< X... >
constexpr char tygrab(char const(&c)[M]) noexcept
Definition typestring.hh:89
Definition typestring.hh:32
static constexpr unsigned int size() noexcept
Definition typestring.hh:41
static constexpr char const * cbegin() noexcept
Definition typestring.hh:44
static constexpr char const * data() noexcept
Definition typestring.hh:38
static constexpr char const * cend() noexcept
Definition typestring.hh:47