Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
a quick and dirty fizzbuzz attempt, with the goal of only one 'call' instruction at runtime (the write)
#include <type_traits>
#include <unistd.h>
/*
* std::string is not very friendly to constexpr, so we need to roll our own
* mechansim if we want the magic to work
*/
template<size_t n>
struct ct_string
{
char s[n];
};
/*
* "simple" concatenation
*/
template<size_t n1, size_t n2>
static constexpr auto operator+(const ct_string<n1> &s1, const ct_string<n2> &s2)
{
ct_string<n1 + n2> result = {{'\0'}};
for(size_t i = 0; i < n1; i++) result.s[i] = s1.s[i];
for(size_t i = 0; i < n2; i++) result.s[i + n1] = s2.s[i];
return result;
}
/*
* need a bit of magic to convert integers to strings at compile time
*
* note: apologies for the copy-pasta; I'm sure there's a much better way to do
* this, but I hacked this together quickly
*/
template<int n,
typename std::enable_if<n >= 10 && n < 100>::type* = nullptr>
static constexpr auto itoa()
{
return ct_string<2>{n/10 + '0', n%10 + '0'};
}
template<int n,
typename std::enable_if<n < 10>::type* = nullptr>
static constexpr auto itoa()
{
return ct_string<1>{n + '0'};
}
/*
* of course, we'll need a nice, minimalistic way to print our strings when
* they're done
*/
template<size_t n>
static inline void write(const ct_string<n> &s)
{
write(1, s.s, n);
}
/*
* pre-declare a few handy literals, since they're not very readable
*/
static constexpr ct_string<4> fizz = {{'F', 'i', 'z', 'z'}};
static constexpr ct_string<4> buzz = {{'B', 'u', 'z', 'z'}};
static constexpr ct_string<1> newline = {{'\n'}};
/*
* the business logic of how to display a number
*/
template<int n,
typename std::enable_if<n % 15 == 0>::type* = nullptr>
static constexpr auto fizzle()
{
return fizz + buzz;
}
template<int n,
typename std::enable_if<n % 5 == 0 && n % 15>::type* = nullptr>
static constexpr auto fizzle()
{
return buzz;
}
template<int n,
typename std::enable_if<n % 3 == 0 && n % 15>::type* = nullptr>
static constexpr auto fizzle()
{
return fizz;
}
template<int n,
typename std::enable_if<n % 3 && n % 5>::type* = nullptr>
static constexpr auto fizzle()
{
return itoa<n>();
}
/*
* a quick and dirty recursive version for doing the iteration
*/
template<int i, int end,
typename std::enable_if<i >= end>::type* = nullptr>
static constexpr auto build_output()
{
return ct_string<0>();
}
template<int i, int end,
typename std::enable_if<i < end>::type* = nullptr>
static constexpr auto build_output()
{
return fizzle<i>() + newline + build_output<i+1, end>();
}
/*
* build the entire string at compile time
*/
static constexpr auto output = build_output<1, 101>();
int main()
{
// runtime should just be a single call
write(output);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment