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.

184 lines
4.5 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_METAPROGRAMMING_H
#define FRUIT_META_METAPROGRAMMING_H
#include <fruit/impl/meta/basics.h>
#include <fruit/impl/meta/vector.h>
#include <fruit/impl/fruit_assert.h>
#include <fruit/impl/fruit_internal_forward_decls.h>
#include <fruit/impl/injection_errors.h>
#include <fruit/impl/meta/errors.h>
#include <memory>
namespace fruit {
namespace impl {
namespace meta {
struct IsConstructible {
template <typename C, typename... Args>
struct apply;
template <typename C, typename... Args>
struct apply<Type<C>, Type<Args>...> {
using type = Bool<std::is_constructible<C, Args...>::value>;
};
};
struct IsConstructibleWithVector {
template <typename C, typename V>
struct apply;
template <typename C, typename... Types>
struct apply<Type<C>, Vector<Type<Types>...>> {
using type = Bool<std::is_constructible<C, Types...>::value>;
};
};
struct AddPointer {
template <typename T>
struct apply;
template <typename T>
struct apply<Type<T>> {
using type = Type<T*>;
};
};
struct IsCallable {
template <typename T>
struct apply;
template <typename C>
struct apply<Type<C>> {
template <typename C1>
static Bool<true> test(decltype(&C1::operator()));
template <typename>
static Bool<false> test(...);
using type = decltype(test<C>(nullptr));
};
};
struct GetCallOperatorSignature {
template <typename T>
struct apply;
template <typename C>
struct apply<Type<C>> {
using type = Type<decltype(&C::operator())>;
};
};
struct AddPointerToVector {
template <typename V>
struct apply;
template <typename... Ts>
struct apply<Vector<Type<Ts>...>> {
using type = Vector<Type<Ts*>...>;
};
};
struct GetNthTypeHelper {
template <typename N, typename... Ts>
struct apply;
template <typename T, typename... Ts>
struct apply<Int<0>, T, Ts...> {
using type = T;
};
template <int n, typename T, typename... Ts>
struct apply<Int<n>, T, Ts...> {
using type = GetNthTypeHelper(Int<n - 1>, Ts...);
};
};
struct GetNthType {
template <typename N, typename V>
struct apply;
template <typename N, typename... Ts>
struct apply<N, Vector<Ts...>> {
using type = GetNthTypeHelper(N, Ts...);
};
};
struct FunctorResultHelper {
template <typename MethodSignature>
struct apply;
template <typename Result, typename Functor, typename... Args>
struct apply<Type<Result (Functor::*)(Args...)>> {
using type = Type<Result>;
};
};
struct FunctorResult {
template <typename F>
struct apply;
template <typename F>
struct apply<Type<F>> {
using type = FunctorResultHelper(Type<decltype(&F::operator())>);
};
};
struct FunctionSignatureHelper {
template <typename LambdaMethod>
struct apply;
template <typename Result, typename LambdaObject, typename... Args>
struct apply<Type<Result (LambdaObject::*)(Args...) const>> {
using type = Type<Result(Args...)>;
};
};
// Function is either a plain function type of the form T(*)(Args...) or a lambda.
struct FunctionSignature {
template <typename Function>
struct apply;
template <typename Function>
struct apply<Type<Function>> {
using CandidateSignature = FunctionSignatureHelper(GetCallOperatorSignature(Type<Function>));
using type = If(Not(IsCallable(Type<Function>)), ConstructError(NotALambdaErrorTag, Type<Function>),
If(Not(IsConstructible(AddPointer(CandidateSignature), Type<Function>)),
ConstructError(FunctorUsedAsProviderErrorTag, Type<Function>), CandidateSignature));
};
template <typename Result, typename... Args>
struct apply<Type<Result(Args...)>> {
using type = Type<Result(Args...)>;
};
template <typename Result, typename... Args>
struct apply<Type<Result (*)(Args...)>> {
using type = Type<Result(Args...)>;
};
};
} // namespace meta
} // namespace impl
} // namespace fruit
#endif // FRUIT_META_METAPROGRAMMING_H