Skip to content

Instantly share code, notes, and snippets.

@khuldraeseth
Created November 13, 2020 17:19
Show Gist options
  • Save khuldraeseth/e36b20b66d3ff5ccfe32fe0ccb0ad67c to your computer and use it in GitHub Desktop.
Save khuldraeseth/e36b20b66d3ff5ccfe32fe0ccb0ad67c to your computer and use it in GitHub Desktop.
A type-level prime checker for the GNU C++ Compiler
/*
This whole thing is a direct translation from Haskell of
https://gist.github.com/khuldraeseth/d82c8fa8946da845a7bbb57f2077122b
*/
struct F {};
struct T {};
struct Z {};
template <typename N> struct S {};
struct Nil {};
template <typename X, typename Xs> struct Cons {};
template <typename P, typename Q> struct And_;
template <typename P, typename Q> using And = And_<P,Q>::type;
template <typename Q> struct And_<F,Q> { using type = F; };
template <typename Q> struct And_<T,Q> { using type = Q; };
template <typename P, typename X, typename Y> struct IfThenElse_;
template <typename P, typename X, typename Y> using IfThenElse = IfThenElse_<P,X,Y>::type;
template <typename X, typename Y> struct IfThenElse_<F,X,Y> { using type = Y; };
template <typename X, typename Y> struct IfThenElse_<T,X,Y> { using type = X; };
template <typename M, typename N> struct NoLessThan_;
template <typename M, typename N> using NoLessThan = NoLessThan_<M,N>::type;
template <typename X> struct NoLessThan_<X,Z> { using type = T; };
template <typename Y> struct NoLessThan_<Z, S<Y>> { using type = F; };
template <typename X, typename Y> struct NoLessThan_<S<X>,S<Y>> { using type = NoLessThan<X,Y>; };
template <typename M, typename N> struct Equals_;
template <typename M, typename N> using Equals = Equals_<M,N>::type;
template <> struct Equals_<Z,Z> { using type = T; };
template <typename M> struct Equals_<S<M>,Z> { using type = F; };
template <typename N> struct Equals_<Z,S<N>> { using type = F; };
template <typename M, typename N> struct Equals_<S<M>,S<N>> { using type = Equals<M,N>; };
template <typename M, typename N> struct Minus_;
template <typename M, typename N> using Minus = Minus_<M,N>::type;
template <> struct Minus_<Z,Z> { using type = Z; };
template <typename M> struct Minus_<M,Z> { using type = M; };
template <typename N> struct Minus_<Z,N> { using type = Z; };
template <typename M, typename N> struct Minus_<S<M>,S<N>> { using type = Minus<M,N>; };
template <typename M, typename N> struct Divides_;
template <typename M, typename N> using Divides = Divides_<M,N>::type;
template <typename M> struct Divides_<M,Z> { using type = T; };
template <typename M, typename N> struct Divides_<M,S<N>> {
using type = And<NoLessThan<S<N>,M>,
Divides<M,Minus<S<N>,M>>>;
};
template <typename N> struct Range_;
template <typename N> using Range = Range_<N>::type;
template <> struct Range_<Z> { using type = Nil; };
template <typename N> struct Range_<S<N>> { using type = Cons<S<N>,Range<N>>; };
template <typename F, typename X> struct Apply_;
template <typename F, typename X> using Apply = Apply_<F,X>::type;
template <typename N> struct DividesFn {};
template <typename M, typename N> struct Apply_<DividesFn<N>,M> { using type = Divides<M,N>; };
template <typename F, typename Xs> struct CountIf_;
template <typename F, typename Xs> using CountIf = CountIf_<F,Xs>::type;
template <typename F> struct CountIf_<F,Nil> { using type = Z; };
template <typename F, typename X, typename Xs> struct CountIf_<F,Cons<X,Xs>> {
using type = IfThenElse<Apply<F,X>,
S<CountIf<F,Xs>>,
CountIf<F,Xs>>;
};
template <typename N> struct IsPrime_;
template <typename N> using IsPrime = IsPrime_<N>::type;
template <typename N> struct IsPrime_ {
using type = Equals<S<S<Z>>,
CountIf<DividesFn<N>, Range<N>>>;
};
template <typename P> bool constexpr asBool;
template <> bool constexpr asBool<F> {false};
template <> bool constexpr asBool<T> {true};
using One = S<Z>;
static_assert(!asBool<IsPrime<One>>);
using Two = S<One>;
static_assert(asBool<IsPrime<Two>>);
using Three = S<Two>;
static_assert(asBool<IsPrime<Three>>);
using Four = S<Three>;
static_assert(!asBool<IsPrime<Four>>);
using Five = S<Four>;
static_assert(asBool<IsPrime<Five>>);
using Six = S<Five>;
static_assert(!asBool<IsPrime<Six>>);
using Seven = S<Six>;
static_assert(asBool<IsPrime<Seven>>);
using Eight = S<Seven>;
static_assert(!asBool<IsPrime<Eight>>);
using Nine = S<Eight>;
static_assert(!asBool<IsPrime<Nine>>);
using Ten = S<Nine>;
static_assert(!asBool<IsPrime<Ten>>);
using Eleven = S<Ten>;
static_assert(asBool<IsPrime<Eleven>>);
using Twelve = S<Eleven>;
static_assert(!asBool<IsPrime<Twelve>>);
using Thirteen = S<Twelve>;
static_assert(asBool<IsPrime<Thirteen>>);
using Fourteen = S<Thirteen>;
static_assert(!asBool<IsPrime<Fourteen>>);
using Fifteen = S<Fourteen>;
static_assert(!asBool<IsPrime<Fifteen>>);
using Sixteen = S<Fifteen>;
static_assert(!asBool<IsPrime<Sixteen>>);
using Seventeen = S<Sixteen>;
static_assert(asBool<IsPrime<Seventeen>>);
using Eighteen = S<Seventeen>;
static_assert(!asBool<IsPrime<Eighteen>>);
using Nineteen = S<Eighteen>;
static_assert(asBool<IsPrime<Nineteen>>);
using Twenty = S<Nineteen>;
static_assert(!asBool<IsPrime<Twenty>>);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment