Skip to content

Instantly share code, notes, and snippets.

@ericniebler
Last active October 4, 2024 19:36
Show Gist options
  • Save ericniebler/cba16cb75d27631327b7235ef4c1e9f9 to your computer and use it in GitHub Desktop.
Save ericniebler/cba16cb75d27631327b7235ef4c1e9f9 to your computer and use it in GitHub Desktop.
meta-programming library
/*
* 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