View difference between Paste ID: Ac0j8m1T and X4jzhmfK
SHOW: | | - or go back to the newest paste.
1
#include <cstddef>
2
#include <type_traits>
3
#include <utility>
4
#include <ostream>
5
6
namespace fizzbuzz {
7
	template< typename... T >
8
	struct typelist {
9
		static constexpr std::size_t size = sizeof...( T );
10
	};
11
12
	namespace detail {
13
		template< typename... T >
14
		struct concat_impl {
15
		};
16
		template<>
17
		struct concat_impl<> {
18
			using t = typelist<>;
19
		};
20
		template< typename... head, typename... tail >
21
		struct concat_impl< typelist< head... >, typelist< tail... > > {
22
			using t = typelist< head..., tail... >;
23
		};
24
		template< typename... head, typename... tail >
25
		struct concat_impl< typelist< head... >, tail... > {
26
			using t = typename concat_impl< typelist< head... >, typename concat_impl< tail... >::t >::t;
27
		};
28
		template< typename head, typename... tail >
29
		struct concat_impl< head, tail... > {
30
			using t = typename concat_impl< typelist< head >, tail... >::t;
31
		};
32
	}
33
	template< typename... T >
34
	using concat = typename detail::concat_impl< T... >::t;
35
36
	template< char c >
37
	struct char_ {
38
		static constexpr auto v = c;
39
	};
40
	template< int i >
41
	struct int_ {
42
		static constexpr auto v = i;
43
	};
44
45
	namespace detail {
46
		template< typename list >
47
		struct discard_trailing_zeroes {
48
		};
49
		template< typename head, typename... tail >
50
		struct discard_trailing_zeroes< typelist< head, tail... > > {
51
			using t = concat< head, typename discard_trailing_zeroes< typelist< tail... > >::t >;
52
		};
53
		template< typename... tail >
54
		struct discard_trailing_zeroes< typelist< char_< '\0' >, tail... > > {
55
			using t = typelist<>;
56
		};
57
		template<>
58
		struct discard_trailing_zeroes< typelist<> > {
59
			using t = typelist<>;
60
		};
61
	}
62
#define LITERAL2LIST_1( str, i )	\
63
	::fizzbuzz::char_< ( sizeof( str ) / sizeof( *str ) > ( i ) ? str[ ( i ) ] : '\0' ) >
64
#define LITERAL2LIST_2( str, i )	\
65
	LITERAL2LIST_1( str, i + 0 ),	\
66
	LITERAL2LIST_1( str, i + 1 )
67
#define LITERAL2LIST_4( str, i )	\
68
	LITERAL2LIST_2( str, i + 0 ),	\
69
	LITERAL2LIST_2( str, i + 2 )
70
#define LITERAL2LIST_8( str, i )	\
71
	LITERAL2LIST_4( str, i + 0 ),	\
72
	LITERAL2LIST_4( str, i + 4 )
73
#define LITERAL2LIST_16( str, i )	\
74
	LITERAL2LIST_8( str, i + 0 ),	\
75
	LITERAL2LIST_8( str, i + 8 )
76
#define LITERAL2LIST( str ) std::enable_if_t< ( sizeof( str ) - 1 < 16 ), ::fizzbuzz::detail::discard_trailing_zeroes< ::fizzbuzz::typelist< LITERAL2LIST_16( str, 0 ) > >::t >
77
78
	inline std::ostream& operator<<( std::ostream& stream, typelist<> ) {
79
		return stream;
80
	}
81
	template< char... c >
82
	std::ostream& operator<<( std::ostream& stream, typelist< char_< c >... > ) {
83
		constexpr char s[] = { c... };
84
		return stream.write( s, sizeof( s ) / sizeof( *s ) );
85
	}
86
	template< int head, int... tail >
87
	std::ostream& operator<<( std::ostream& stream, typelist< int_< head >, int_< tail >... > ) {
88
		return stream << head << ' ' << typelist< int_< tail >... >{};
89
	}
90
	template< int head >
91
	std::ostream& operator<<( std::ostream& stream, typelist< int_< head > > ) {
92
		return stream << head;
93
	}
94
95
	namespace detail {
96
		template< std::size_t n, int a0, int d >
97
		struct arithmetic_progression_impl {
98
			using t = concat< typename arithmetic_progression_impl< n / 2, a0, d >::t, typename arithmetic_progression_impl< n - n / 2, a0 + n / 2 * d, d >::t >;
99
		};
100
		template< int d, int a0 >
101
		struct arithmetic_progression_impl< 0, a0, d > {
102
			using t = typelist<>;
103
		};
104
		template< int d, int a0 >
105
		struct arithmetic_progression_impl< 1, a0, d > {
106
			using t = typelist< int_< a0 > >;
107
		};
108
	}
109
	template< std::size_t n, int a0 = 0, int d = 1 >
110
	using arithmetic_progression = typename detail::arithmetic_progression_impl< n, a0, d >::t;
111
112
	namespace detail {
113
		template< typename list, typename separator >
114
		struct separate_impl {
115
		};
116
		template< typename head, typename... tail, typename separator >
117
		struct separate_impl< typelist< head, tail... >, separator > {
118
			using t = concat< head, separator, typename separate_impl< typelist< tail... >, separator >::t >;
119
		};
120
		template< typename head, typename separator >
121
		struct separate_impl< typelist< head >, separator > {
122
			using t = typelist< head >;
123
		};
124
	}
125
	template< typename list, typename separator >
126
	using separate = typename detail::separate_impl< list, separator >::t;
127
128
	namespace detail {
129
		template< typename list, template< typename > class meta_functor >
130
		struct transform_impl {
131
		};
132
		template< typename head, typename... tail, template< typename > class meta_functor >
133
		struct transform_impl< typelist< head, tail... >, meta_functor > {
134
			using t = concat< typename meta_functor< head >::t, typename transform_impl< typelist< tail... >, meta_functor >::t >;
135
		};
136
		template< template< typename > class meta_functor >
137
		struct transform_impl< typelist<>, meta_functor > {
138
			using t = typelist<>;
139
		};
140
	}
141
	template< typename list, template< typename > class meta_functor >
142
	using transform = typename detail::transform_impl< list, meta_functor >::t;
143
144
	namespace detail {
145
		template< unsigned i >
146
		struct log10_impl {
147
			static constexpr int v = 1 + log10_impl< i / 10 >::v;
148
		};
149
		template<>
150
		struct log10_impl< 0 > {
151
			static constexpr int v = -1;
152
		};
153
	}
154
	template< unsigned i >
155
	static constexpr int log10 = detail::log10_impl< i >::v;
156
157
	namespace detail {
158
		template< unsigned i >
159
		struct pow10_impl {
160
			static constexpr unsigned v = pow10_impl< i / 2 >::v * pow10_impl< i - i / 2 >::v;
161
		};
162
		template<>
163
		struct pow10_impl< 1 > {
164
			static constexpr unsigned v = 10;
165
		};
166
		template<>
167
		struct pow10_impl< 0 > {
168
			static constexpr unsigned v = 1;
169
		};
170
	}
171
	template< unsigned i >
172
	static constexpr unsigned pow10 = detail::pow10_impl< i >::v;
173
174
	namespace detail {
175
		template< int i, typename = std::make_integer_sequence< int, 1 + log10< i > > >
176
		struct int2str_impl_impl {
177
		};
178
		template< int i, int... indices >
179
		struct int2str_impl_impl< i, std::integer_sequence< int, indices... > > {
180
			using t = typelist< char_< '0' + i / pow10< sizeof...( indices ) - 1 - indices > % 10 >... >;
181
		};
182
183
		template< int i, bool neg = ( i < 0 ) >
184
		struct int2str_impl {
185
			using t = concat< char_< '-' >, typename int2str_impl< -i >::t >;
186
		};
187
		template< int i >
188
		struct int2str_impl< i, false > {
189
			using t = typename int2str_impl_impl< i >::t;
190
		};
191
		template<>
192
		struct int2str_impl< 0, false > {
193
			using t = typelist< char_< '0' > >;
194
		};
195
	}
196
	template< typename T >
197
	struct int2str {
198
		using t = T;
199
	};
200
	template< int i >
201
	struct int2str< int_< i > > {
202
		using t = typename detail::int2str_impl< i >::t;
203
	};
204
205
	template< int i, typename T >
206
	struct divisibility_replacement_rule {
207
		static constexpr auto v = i;
208
		using t = T;
209
	};
210
	template< typename ruleset >
211
	struct divisibility_replacer {
212
		template< int x, typename = ruleset >
213
		struct match {
214
		};
215
		template< int x, typename head, int... i, typename... tail >
216
		struct match< x, typelist< head, divisibility_replacement_rule< i, tail >... > > {
217
			using tail_rec = match< x, typelist< divisibility_replacement_rule< i, tail >... > >;
218
			static constexpr bool matched_here = ( x % head::v == 0 );
219
			static constexpr bool matched = matched_here || tail_rec::matched;
220
			using t_here = std::conditional_t< matched_here, typename head::t, typelist<> >;
221
			using t = concat< t_here, typename tail_rec::t >;
222
		};
223
		template< int x >
224
		struct match< x, typelist<> > {
225
			static constexpr bool matched = false;
226
			using t = typelist<>;
227
		};
228
229
		template< typename U >
230
		struct functor {
231
			using t = U;
232
		};
233
		template< int x >
234
		struct functor< int_< x > > {
235
			using match_result = match< x >;
236
			using t = std::conditional_t< match_result::matched, typename match_result::t, int_< x > >;
237
		};
238
	};
239
240
	struct fizzbuzz_replacer :
241
		divisibility_replacer<
242
			typelist<
243
				divisibility_replacement_rule< 3, LITERAL2LIST( "Fizz" ) >,
244
				divisibility_replacement_rule< 5, LITERAL2LIST( "Buzz" ) >
245
			>
246
		>
247
	{
248
	};
249
250
	template< int min = 1, int max = 100, typename = std::enable_if_t< ( min < max ) > >
251
	using fizzbuzz = transform< transform< separate< arithmetic_progression< max - min + 1, min, 1 >, LITERAL2LIST( ", " ) >, fizzbuzz_replacer::functor >, int2str >;
252
}
253
254
#include <iostream>
255
256
int main() {
257
	std::cout << fizzbuzz::fizzbuzz<>{} << '\n';
258
}