Last active
October 4, 2024 19:36
-
-
Save ericniebler/cba16cb75d27631327b7235ef4c1e9f9 to your computer and use it in GitHub Desktop.
meta-programming library
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
/* | |
* Copyright (c) 2021-2024 NVIDIA Corporation | |
* | |
* Licensed under the Apache License Version 2.0 with LLVM Exceptions | |
* (the "License"); you may not use this file except in compliance with | |
* the License. You may obtain a copy of the License at | |
* | |
* https://llvm.org/LICENSE.txt | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
#pragma once | |
#include <concepts> | |
#include <utility> | |
#define LBRACKET [[ | |
#define RBRACKET ]] | |
#if defined(_MSC_VER) && !defined(__clang__) | |
# define __ebo__ RBRACKET __declspec(empty_bases) LBRACKET | |
#else | |
# define __ebo__ | |
#endif | |
#if defined(_MSC_VER) && !defined(__clang__) | |
# define __always_inline__ RBRACKET __forceinline LBRACKET | |
#elif defined(__clang__) | |
# define __always_inline__ gnu::always_inline | |
#elif defined(__GNUC__) | |
# define __always_inline__ gnu::always_inline RBRACKET inline LBRACKET | |
#else | |
# define __always_inline__ | |
#endif | |
namespace meta | |
{ | |
template <class...> | |
concept mok = true; | |
using std::type_identity; | |
template <class T> | |
using _t = typename T::type; | |
template <class Fn, class... Ts> | |
using mcall = typename Fn::template call<Ts...>; | |
template <class Fn, class T> | |
using mcall1 = typename Fn::template call<T>; | |
template <class Fn, class T, class U> | |
using mcall2 = typename Fn::template call<T, U>; | |
template <template <class...> class C> | |
struct mquote | |
{ | |
template <class... Ts> | |
using call = C<Ts...>; | |
}; | |
template <template <class> class C> | |
struct mquote1 | |
{ | |
template <class T> | |
using call = C<T>; | |
}; | |
template <template <class, class> class C> | |
struct mquote2 | |
{ | |
template <class T, class U> | |
using call = C<T, U>; | |
}; | |
template <bool> | |
struct _mindirect | |
{ | |
template <class Fn, class... Ts> | |
using call = mcall<Fn, Ts...>; | |
template <template <class...> class Fn, class... Ts> | |
using quote_call = Fn<Ts...>; | |
}; | |
template <class Fn> | |
struct mindirect | |
{ | |
template <class... Ts> | |
using call = mcall<_mindirect<mok<Fn, Ts...>>, Fn, Ts...>; | |
}; | |
template <template <class...> class Fn> | |
struct mquote_indirect | |
{ | |
template <class... Ts> | |
using call = | |
typename _mindirect<mok<mquote_indirect, Ts...>>::template quote_call<Fn, Ts...>; | |
}; | |
template <class Fn, class... Ts> | |
using mcall_indirect = mcall<mindirect<Fn>, Ts...>; | |
template <bool B> | |
struct _mif | |
{ | |
template <class A, class...> | |
using call = A; | |
}; | |
template <> | |
struct _mif<false> | |
{ | |
template <class B, class C> | |
using call = C; | |
}; | |
template <bool B, class T = void, class... Us> | |
using mif_c = mcall<_mif<B>, T, Us...>; | |
template <size_t Size> | |
using msize_t = std::integral_constant<size_t, Size>; | |
template <class...> | |
struct mlist | |
{ | |
}; | |
template <class T> | |
using midentity = T; | |
template <class Fn, class... Ts> | |
struct mbind_front | |
{ | |
template <class... Us> | |
using call = mcall<Fn, Ts..., Us...>; | |
}; | |
template <bool> | |
struct _mconcat | |
{ | |
template <class Continuation, class... Ts> | |
static auto _call(mlist<Ts...>*) -> mcall<Continuation, Ts...>; | |
}; | |
template <class Continuation, class... Lists> | |
using _mconcat_result = | |
decltype(_mconcat<1 == sizeof...(Lists)>::template _call<Continuation>( | |
static_cast<Lists*>(nullptr)...)); | |
template <> | |
struct _mconcat<false> | |
{ | |
template < | |
class Continuation, | |
class... Ts, | |
template <class...> class C0 = mlist, | |
class... C0s, | |
template <class...> class C1 = mlist, | |
class... C1s, | |
template <class...> class C2 = mlist, | |
class... C2s, | |
template <class...> class C3 = mlist, | |
class... C3s, | |
class... Rest> | |
static auto _call( | |
mlist<Ts...>*, | |
C0<C0s...>* = nullptr, | |
C1<C1s...>* = nullptr, | |
C2<C2s...>* = nullptr, | |
C3<C3s...>* = nullptr, | |
Rest*...) | |
-> _mconcat_result<Continuation, mlist<Ts..., C0s..., C1s..., C2s..., C3s...>, Rest...>; | |
}; | |
template <class Continuation = mquote<mlist>> | |
struct mconcat | |
{ | |
template <class... Lists> | |
using call = _mconcat_result<Continuation, mlist<>, Lists...>; | |
}; | |
template <class Fn, class Continuation = mquote<mlist>> | |
struct mtransform | |
{ | |
template <class... Ts> | |
using call = mcall<Continuation, mcall1<Fn, Ts>...>; | |
}; | |
template <class... Ts> | |
struct mset; | |
template <> | |
struct mset<> | |
{ | |
}; | |
template <class Head, class... Tail> | |
struct mset<Head, Tail...> | |
: type_identity<Head> | |
, mset<Tail...> | |
{ | |
}; | |
template <class... Ts, class T> | |
auto operator+(mset<Ts...>&, type_identity<T>) | |
-> mif_c<std::derived_from<mset<Ts...>, type_identity<T>>, mset<Ts...>, mset<T, Ts...>>&; | |
template <class... Ts> | |
auto operator+(mset<Ts...>&) -> mset<Ts...>; | |
template <class Set, class... Ts> | |
using mset_insert = | |
decltype(+(*static_cast<Set*>(nullptr) + ... + type_identity<Ts>{})); | |
template <class... Ts> | |
using mmake_set = mset_insert<mset<>, Ts...>; | |
template <class Fn, class List> | |
using mapply = mcall<mconcat<Fn>, List>; | |
struct msize | |
{ | |
template <class... Ts> | |
using call = msize_t<sizeof...(Ts)>; | |
}; | |
template <class I> | |
static constexpr auto _v = I::value; | |
template <class T, T N> | |
static constexpr T _v<std::integral_constant<T, N>> = N; | |
template <class T, class... Us> | |
concept one_of = (std::same_as<T, Us> || ...); | |
template <bool B> | |
using mbool = std::bool_constant<B>; | |
template <class... Ts> | |
using mor_t = mbool<(Ts::value || ...)>; | |
template <template <class...> class C, class... Ts> | |
concept mvalid = requires { typename C<Ts...>; }; | |
template <class T, class...> | |
using mfront = T; | |
template <bool Empty> | |
struct _mfind_if | |
{ | |
template <class Fn, class Continuation, class Head, class... Tail> | |
using call = mcall< | |
mif_c< | |
mcall<Fn, Head>::value, | |
mbind_front<Continuation, Head>, | |
mbind_front<mindirect<_mfind_if<0 == sizeof...(Tail)>>, Fn, Continuation>>, | |
Tail...>; | |
}; | |
template <> | |
struct _mfind_if<true> | |
{ | |
template <class Fn, class Continuation, class...> | |
using mcall = mcall<Continuation>; | |
}; | |
template <class Fn, class Continuation = mquote<mlist>> | |
struct mfind_if | |
{ | |
template <class... Ts> | |
using call = mcall<mindirect<_mfind_if<0 == sizeof...(Ts)>>, Fn, Continuation, Ts...>; | |
}; | |
template <class T> | |
struct malways | |
{ | |
template <class...> | |
using call = T; | |
}; | |
template <class Fn, class Default, class... Args> | |
using mcall_or = | |
mcall<mif_c<mvalid<mcall, Fn, Args...>, Fn, malways<Default>>, Args...>; | |
template <bool B, class T> | |
using mconst_if = mif_c<B, T const, T>; | |
/// | |
/// basic utilities | |
/// | |
struct immovable | |
{ | |
immovable() = default; | |
immovable(immovable&&) = delete; | |
}; | |
template <class T, template <class...> class C> | |
constexpr bool _specialization_of = false; | |
template <class... Ts, template <class...> class C> | |
constexpr bool _specialization_of<C<Ts...>, C> = true; | |
template <class... Ts, template <class...> class C> | |
constexpr bool _specialization_of<C<Ts...> const, C> = true; | |
template <class T, template <class...> class C> | |
concept specialization_of = _specialization_of<T, C>; | |
template <class T, template <class...> class C> | |
concept not_specialization_of = !specialization_of<T, C>; | |
template <class T, class U> | |
concept not_same_as = !std::same_as<T, U>; | |
template <class... Ts> | |
struct [[__ebo__]] minherit : Ts... | |
{ | |
}; | |
template <class... Fns> | |
struct moverload : Fns... | |
{ | |
using Fns::operator()...; | |
}; | |
template <class... Fns> | |
moverload(Fns...) -> moverload<Fns...>; | |
template <class Fn, class... Args> | |
using call_result_t = decltype(std::declval<Fn>()(std::declval<Args>()...)); | |
template <class Fn, class... Args> | |
concept callable = requires { typename call_result_t<Fn, Args...>; }; | |
namespace detail | |
{ | |
template <class, class, class, class> | |
struct _minsert | |
{ | |
}; | |
template <class T, class... Ts, class Predicate> | |
struct _minsert<T, mlist<Ts...>, mlist<>, Predicate> | |
{ | |
using type = mlist<Ts..., T>; | |
}; | |
template <class T, class... Ts, class U, class... Us, class Predicate> | |
struct _minsert<T, mlist<Ts...>, mlist<U, Us...>, Predicate> | |
{ | |
using type = mif_c< | |
!_v<mcall2<Predicate, T, U>>, | |
_t<_minsert<T, mlist<Ts..., U>, mlist<Us...>, Predicate>>, | |
mlist<Ts..., T, U, Us...>>; | |
}; | |
template <class, class, class> | |
struct sort | |
{ | |
}; | |
template <class... Ts, class U, class... Us, class Predicate> | |
struct sort<mlist<Ts...>, mlist<U, Us...>, Predicate> | |
: sort<_t<_minsert<U, mlist<>, mlist<Ts...>, Predicate>>, mlist<Us...>, Predicate> | |
{ | |
}; | |
template <class... Ts, class Predicate> | |
struct sort<mlist<Ts...>, mlist<>, Predicate> | |
{ | |
using type = mlist<Ts...>; | |
}; | |
} // namespace detail | |
template <class List, class Predicate> | |
struct _sort : detail::sort<mlist<>, List, Predicate> | |
{ | |
}; | |
template <class Predicate, class Continuation = mquote<mlist>> | |
struct msort | |
{ | |
template <class... Ts> | |
using call = mapply<Continuation, _t<_sort<mlist<Ts...>, Predicate>>>; | |
}; | |
} // namespace meta |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment