Created
November 13, 2020 17:19
-
-
Save khuldraeseth/e36b20b66d3ff5ccfe32fe0ccb0ad67c to your computer and use it in GitHub Desktop.
A type-level prime checker for the GNU C++ Compiler
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
/* | |
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