You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
242 lines
6.1 KiB
242 lines
6.1 KiB
/*
|
|
* Copyright 2014 Google Inc. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#ifndef FRUIT_META_BASICS_H
|
|
#define FRUIT_META_BASICS_H
|
|
|
|
#include <functional>
|
|
|
|
namespace fruit {
|
|
namespace impl {
|
|
namespace meta {
|
|
|
|
template <typename T>
|
|
struct Type {
|
|
using type = T;
|
|
};
|
|
|
|
template <bool b>
|
|
struct Bool {
|
|
static constexpr bool value = b;
|
|
};
|
|
|
|
template <int n>
|
|
struct Int {
|
|
static constexpr int value = n;
|
|
};
|
|
|
|
// This was added to workaround a bug in MSVC 2017 15.5, that crashes when expanding Indexes::value... in some cases
|
|
// (where Indexes is a template parameter pack of Int<...> types).
|
|
// TODO: Remove this once MSVC 2017 is fixed and the fix has been out for some time.
|
|
template <typename N>
|
|
constexpr int getIntValue() {
|
|
return N::value;
|
|
}
|
|
|
|
// None is used as "the nullptr of metaprogramming". E.g. when a function has no meaningful value to
|
|
// return, it can return None instead.
|
|
struct None {};
|
|
|
|
struct If {};
|
|
|
|
// PropagateError(E, X) evaluates E then X. The result is X's result, but if E returns an error,
|
|
// that's the result instead.
|
|
struct PropagateError {};
|
|
|
|
// Used to propagate an ErrorTag::apply<ErrorArgs...> up the instantiation chain, but without instantiating it right
|
|
// away, to allow shorter error stacktraces.
|
|
// Instantiating ErrorTag::apply<ErrorArgs...> must result in a static_assert error.
|
|
template <typename ErrorTag, typename... ErrorArgs>
|
|
struct Error {};
|
|
|
|
// Use as Catch(ExpressionThatMightThrow, ErrorTag, Handler)
|
|
// Handler(Error<ErrorTag, ErrorArgs...>) is called if ExpressionThatMightThrow throws ErrorTag.
|
|
struct Catch {};
|
|
|
|
// Use as CatchAll(ExpressionThatMightThrow, Handler)
|
|
// Handler(Error<ErrorTag, ErrorArgs...>) is called if ExpressionThatMightThrow throws any error.
|
|
struct CatchAll {};
|
|
|
|
// Call(F, Args...) is equivalent to F(Args...) in a metaexpression, except that Call(F, Args...)
|
|
// also works when F is a metaexpression.
|
|
struct Call {
|
|
template <typename F, typename... Args>
|
|
struct apply : public F::template apply<Args...> {};
|
|
};
|
|
|
|
// UnwrapType<Type<T>> is T.
|
|
template <typename WrappedType>
|
|
using UnwrapType = typename WrappedType::type;
|
|
|
|
// MSVC 14 has trouble specializing alias templates using expanded pack elements.
|
|
// This is a known issue:
|
|
// https://stackoverflow.com/questions/43411542/metaprogramming-failed-to-specialize-alias-template
|
|
// The workaround is just to use a struct directly.
|
|
// typename TypeUnwrapper<Type<T>>::type is T.
|
|
template <typename WrappedType>
|
|
struct TypeUnwrapper {
|
|
using type = UnwrapType<WrappedType>;
|
|
};
|
|
|
|
// Logical And with short-circuit evaluation.
|
|
struct And {
|
|
template <typename... MetaExprs>
|
|
struct apply {
|
|
using type = Bool<true>;
|
|
};
|
|
|
|
template <typename MetaExpr>
|
|
struct apply<MetaExpr> {
|
|
using type = MetaExpr;
|
|
};
|
|
|
|
template <typename MetaExpr, typename MetaExpr2>
|
|
struct apply<MetaExpr, MetaExpr2> {
|
|
using type = If(MetaExpr, MetaExpr2, Bool<false>);
|
|
};
|
|
|
|
template <typename MetaExpr, typename MetaExpr2, typename... MetaExprs>
|
|
struct apply<MetaExpr, MetaExpr2, MetaExprs...> {
|
|
using type = If(MetaExpr, If(MetaExpr2, And(MetaExprs...), Bool<false>), Bool<false>);
|
|
};
|
|
};
|
|
|
|
// Logical Or with short-circuit evaluation.
|
|
struct Or {
|
|
template <typename... MetaExprs>
|
|
struct apply {
|
|
using type = Bool<false>;
|
|
};
|
|
|
|
template <typename MetaExpr>
|
|
struct apply<MetaExpr> {
|
|
using type = MetaExpr;
|
|
};
|
|
|
|
template <typename MetaExpr, typename MetaExpr2>
|
|
struct apply<MetaExpr, MetaExpr2> {
|
|
using type = If(MetaExpr, Bool<true>, MetaExpr2);
|
|
};
|
|
|
|
template <typename MetaExpr, typename MetaExpr2, typename... MetaExprs>
|
|
struct apply<MetaExpr, MetaExpr2, MetaExprs...> {
|
|
using type = If(MetaExpr, Bool<true>, If(MetaExpr2, Bool<true>, Or(MetaExprs...)));
|
|
};
|
|
};
|
|
|
|
// Call(Call(DeferArgs(F), Args...), MoreArgs...)
|
|
//
|
|
// is equivalent to:
|
|
// Result = F(Args..., MoreArgs...)
|
|
//
|
|
// Note that you can't write:
|
|
// DeferArgs(F)(Args...)(MoreArgs...)
|
|
//
|
|
// Because Call must be used to call metafunctions that are metaexpressions.
|
|
struct DeferArgs {
|
|
template <typename F>
|
|
struct apply {
|
|
struct type {
|
|
template <typename... Args>
|
|
struct apply {
|
|
struct type {
|
|
template <typename... MoreArgs>
|
|
struct apply {
|
|
using type = F(Args..., MoreArgs...);
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
// Call(PartialCall(F, Args...), MoreArgs...)
|
|
//
|
|
// is equivalent to:
|
|
// Result = F(Args..., MoreArgs...)
|
|
//
|
|
// Note that you can't write:
|
|
// PartialCall(F, Args...)(MoreArgs...)
|
|
//
|
|
// Because Call must be used to call metafunctions that are metaexpressions.
|
|
struct PartialCall {
|
|
template <typename F, typename... Args>
|
|
struct apply {
|
|
struct type {
|
|
template <typename... MoreArgs>
|
|
struct apply {
|
|
using type = F(Args..., MoreArgs...);
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
struct IsSame {
|
|
template <typename T, typename U>
|
|
struct apply {
|
|
using type = Bool<false>;
|
|
};
|
|
|
|
template <typename T>
|
|
struct apply<T, T> {
|
|
using type = Bool<true>;
|
|
};
|
|
};
|
|
|
|
struct Not {
|
|
template <typename B>
|
|
struct apply {
|
|
using type = Bool<!B::value>;
|
|
};
|
|
};
|
|
|
|
struct IsNone {
|
|
template <typename T>
|
|
struct apply {
|
|
using type = Bool<false>;
|
|
};
|
|
};
|
|
|
|
template <>
|
|
struct IsNone::apply<None> {
|
|
using type = Bool<true>;
|
|
};
|
|
|
|
template <typename T>
|
|
using Id = T;
|
|
|
|
struct Identity {
|
|
template <typename T>
|
|
struct apply {
|
|
using type = T;
|
|
};
|
|
};
|
|
|
|
template <typename T>
|
|
struct DebugTypeHelper {
|
|
static_assert(sizeof(T*) * 0 != 0, "");
|
|
using type = T;
|
|
};
|
|
|
|
template <typename T>
|
|
using DebugType = typename DebugTypeHelper<T>::type;
|
|
|
|
} // namespace meta
|
|
} // namespace impl
|
|
} // namespace fruit
|
|
|
|
#endif // FRUIT_META_BASICS_H
|