Last active
November 16, 2018 00:59
-
-
Save MaxXSoft/45ca7d0266c7c16e30129f24d228fc05 to your computer and use it in GitHub Desktop.
Generate an array containing the first 1000 terms of Fibonacci sequence, at compile time.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <utility> | |
#include <type_traits> | |
#include <cstdint> | |
#include <cstddef> | |
using namespace std; | |
// compile time string | |
template <char c, size_t n, char ...suffix> | |
struct CharRepeat : public CharRepeat<c, n - 1, c, suffix...> {}; | |
template <char c, char ...suffix> | |
struct CharRepeat<c, 0, suffix...> { | |
static constexpr const char value[] = {suffix..., '\0'}; | |
}; | |
template <uint64_t num, uint64_t ...digits> | |
struct IntToString : public IntToString<num / 10, num % 10, digits...> {}; | |
template <uint64_t ...digits> | |
struct IntToString<0, digits...> { | |
static constexpr const char value[] = {('0' + digits)..., '\0'}; | |
}; | |
constexpr size_t StringSize(const char *str) { | |
int i = 0; | |
while (*str++) ++i; | |
return i; | |
} | |
template <const char *s1, typename T1, const char *s2, typename T2> | |
struct StrConcatImpl; | |
template <const char *s1, size_t ...i1, const char *s2, size_t ...i2> | |
struct StrConcatImpl<s1, index_sequence<i1...>, s2, index_sequence<i2...>> { | |
static constexpr const char value[] = {s1[i1]..., s2[i2]..., '\0'}; | |
}; | |
template <const char *s1, const char *s2> | |
using StringConcat = StrConcatImpl< | |
s1, make_index_sequence<StringSize(s1)>, | |
s2, make_index_sequence<StringSize(s2)> | |
>; | |
// single digit | |
constexpr uint64_t kDigitLimit = 1e18; | |
constexpr uint64_t kDigitLen = 18; | |
template <uint64_t n, typename T> | |
struct Digit; | |
using ZeroDigit = Digit<0, nullptr_t>; | |
template <uint64_t n, typename T = ZeroDigit> | |
struct Digit { | |
public: | |
static_assert(n < kDigitLimit, "input parameter n is too big"); | |
static constexpr uint64_t digit = n; | |
static constexpr uint64_t length = T::length + 1; | |
private: | |
using DigitString = IntToString<digit>; | |
using ExtendedString = StringConcat< | |
CharRepeat<'0', kDigitLen - StringSize(DigitString::value)>::value, | |
DigitString::value | |
>; | |
using FinalString = typename conditional< | |
is_same<T, ZeroDigit>{}(), DigitString, ExtendedString | |
>::type; | |
public: | |
static constexpr auto str = StringConcat< | |
T::str, FinalString::value | |
>::value; | |
}; | |
template <> | |
struct Digit<0, nullptr_t> { | |
static constexpr uint64_t digit = 0; | |
static constexpr uint64_t length = 0; | |
static constexpr const char str[] = ""; | |
}; | |
// addition | |
template <typename A, typename B> | |
struct Sum; | |
template <> | |
struct Sum<ZeroDigit, ZeroDigit> { | |
using Result = ZeroDigit; | |
static constexpr uint64_t carry = 0; | |
}; | |
template <uint64_t n, typename T> | |
struct Sum<ZeroDigit, Digit<n, T>> { | |
using Result = Digit<n, T>; | |
static constexpr uint64_t carry = 0; | |
}; | |
template <uint64_t n, typename T> | |
struct Sum<Digit<n, T>, ZeroDigit> { | |
using Result = Digit<n, T>; | |
static constexpr uint64_t carry = 0; | |
}; | |
template <uint64_t a, uint64_t b, typename Ta, typename Tb> | |
struct Sum<Digit<a, Ta>, Digit<b, Tb>> { | |
static constexpr uint64_t carry = a + b >= kDigitLimit ? | |
(a + b) / kDigitLimit : 0; | |
using Result = Digit<(a + b) % kDigitLimit, | |
typename Sum< | |
typename Sum<Ta, Tb>::Result, | |
typename conditional<carry == 0, ZeroDigit, Digit<carry>>::type | |
>::Result | |
>; | |
}; | |
// fibonacci | |
template <uint64_t n> | |
struct Fib { | |
using Result = typename Sum< | |
typename Fib<n - 1>::Result, typename Fib<n - 2>::Result | |
>::Result; | |
}; | |
template <> | |
struct Fib<1> { | |
using Result = Digit<1>; | |
}; | |
template <> | |
struct Fib<2> { | |
using Result = Digit<1>; | |
}; | |
template <uint64_t ...i> | |
using IntSeq = integer_sequence<uint64_t, i...>; | |
template <uint64_t n> | |
using MakeIntSeq = make_integer_sequence<uint64_t, n>; | |
template <typename T> | |
struct FibListImpl; | |
template <uint64_t ...n> | |
struct FibListImpl<IntSeq<n...>> { | |
static constexpr const char *fib_list[] = {(Fib<n + 1>::Result::str)...}; | |
}; | |
template <uint64_t len> | |
using FibList = FibListImpl<MakeIntSeq<len>>; | |
// main procedure | |
int main(int argc, const char *argv[]) { | |
constexpr auto fib_list = FibList<1000>::fib_list; | |
int i; | |
while (cin >> i) { | |
cout << fib_list[i] << endl; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment