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 | } |