//
// gapbind14
// Copyright (C) 2020-2022 James D. Mitchell
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef INCLUDE_GAPBIND14_CPP_FN_HPP_
#define INCLUDE_GAPBIND14_CPP_FN_HPP_
#include <cstddef>
// for size_t
#include <functional>
// for function
#include <tuple>
// for tuple, tuple_element_t
#include <type_traits>
// for true_type
#include "gap_include.hpp" // for UInt
#define GAPBIND14_TRY(something) \
try { \
something; \
}
catch (std::exception
const& e) { \
ErrorQuit(e.what(), 0L, 0L); \
}
namespace gapbind14 {
constexpr size_t MAX_FUNCTIONS = 96;
extern UInt T_GAPBIND14_OBJ;
////////////////////////////////////////////////////////////////////////
// Overloading
////////////////////////////////////////////////////////////////////////
template <
typename... TArgs>
struct overload_cast_impl {
constexpr overload_cast_impl() {}
template <
typename TReturn>
constexpr
auto operator()(TReturn (*pf)(TArgs...))
const noexcept
-> decltype(pf) {
return pf;
}
template <
typename TReturn,
typename TClass>
constexpr
auto operator()(TReturn (TClass::*pmf)(TArgs...),
std::false_type = {})
const noexcept
-> decltype(pmf) {
return pmf;
}
template <
typename TReturn,
typename TClass>
constexpr
auto operator()(TReturn (TClass::*pmf)(TArgs...)
const)
const noexcept -> decltype(pmf) {
return pmf;
}
};
template <
typename... TArgs>
static constexpr overload_cast_impl<TArgs...> overload_cast = {};
namespace detail {
template <
typename T>
class is_lambda {
private:
using no_ref = std::remove_reference_t<T>;
public:
static constexpr
bool value = !(std::is_pointer<no_ref>::value
|| std::is_member_pointer<no_ref>::value
|| std::is_function<no_ref>::value);
};
template <
typename T>
struct remove_class {};
template <
typename C,
typename R,
typename... A>
struct remove_class<R (C::*)(A...)> {
using type = R(A...);
};
template <
typename C,
typename R,
typename... A>
struct remove_class<R (C::*)(A...)
const> {
using type = R(A...);
};
template <
typename F>
struct strip_function_object {
using type =
typename remove_class<decltype(&F::
operator())>::type;
};
////////////////////////////////////////////////////////////////////////
// Function return type and parameter type info
////////////////////////////////////////////////////////////////////////
// For parameter packs . . .
template <
typename... TArgs>
struct Pack {
template <size_t i>
using get = std::tuple_element_t<i, std::tuple<TArgs...>>;
};
template <
typename TReturnType,
typename... TArgs>
struct CppFunctionBase {
using arg_count = std::integral_constant<
unsigned,
sizeof...(TArgs)>;
using return_type = TReturnType;
using params_type =
Pack<TArgs...>;
// Function pointers . . .
template <
typename SFINAE = TReturnType>
auto operator()(TReturnType (*f)(), TArgs... args)
-> std::enable_if_t<
sizeof...(TArgs) == 0, SFINAE> {
return f();
}
template <
typename SFINAE = TReturnType>
auto operator()(TReturnType (*f)(TArgs...), TArgs... args)
-> std::enable_if_t<
sizeof...(TArgs) != 0, SFINAE> {
return f(args...);
}
template <
typename SFINAE = TReturnType>
auto operator()(std::function<TReturnType(TArgs...)> f, TArgs... args)
-> std::enable_if_t<
sizeof...(TArgs) == 0, SFINAE> {
return f();
}
};
// Member functions . . .
template <
typename TClass,
typename TReturnType,
typename... TArgs>
struct CppMemFnBase {
using arg_count = std::integral_constant<
unsigned,
sizeof...(TArgs)>;
using return_type = TReturnType;
using params_type =
Pack<TArgs...>;
using class_type = TClass;
template <
typename SFINAE = TReturnType>
auto operator()(TReturnType (TClass::*mem_fn)(TArgs...),
TClass* ptr,
TArgs... args)
-> std::enable_if_t<
sizeof...(TArgs) != 0, SFINAE> {
return (ptr->*mem_fn)(args...);
}
template <
typename SFINAE = TReturnType>
auto operator()(TReturnType (TClass::*mem_fn)(TArgs...),
TClass* ptr,
TArgs... args)
-> std::enable_if_t<
sizeof...(TArgs) == 0, SFINAE> {
return (ptr->*mem_fn)();
}
template <
typename SFINAE = TReturnType>
auto operator()(TReturnType (TClass::*mem_fn)(TArgs...)
const,
TClass* ptr,
TArgs... args)
-> std::enable_if_t<
sizeof...(TArgs) != 0, SFINAE> {
return (ptr->*mem_fn)(args...);
}
template <
typename SFINAE = TReturnType>
auto operator()(TReturnType (TClass::*mem_fn)(TArgs...)
const,
TClass* ptr,
TArgs... args)
-> std::enable_if_t<
sizeof...(TArgs) == 0, SFINAE> {
return (ptr->*mem_fn)();
}
};
// Base declaration . . .
template <
typename TSignature,
typename =
void>
struct CppFunction {};
// Free functions . . .
template <
typename TReturnType,
typename... TArgs>
struct CppFunction<TReturnType(TArgs...)>
: CppFunctionBase<TReturnType, TArgs...> {};
// Function pointers . . .
template <
typename TReturnType,
typename... TArgs>
struct CppFunction<TReturnType (*)(TArgs...)>
: CppFunctionBase<TReturnType, TArgs...> {};
// Member functions . . .
template <
typename TClass,
typename TReturnType,
typename... TArgs>
struct CppFunction<TReturnType (TClass::*)(TArgs...)>
: CppMemFnBase<TClass, TReturnType, TArgs...> {};
// Const member functions
template <
typename TClass,
typename TReturnType,
typename... TArgs>
struct CppFunction<TReturnType (TClass::*)(TArgs...)
const>
: CppMemFnBase<TClass, TReturnType, TArgs...> {};
// std::function objects
template <
typename TReturnType,
typename... TArgs>
struct CppFunction<std::function<TReturnType(TArgs...)>>
: CppFunctionBase<TReturnType, TArgs...> {};
// Lambdas?
template <
typename Func>
struct CppFunction<Func, std::enable_if_t<detail::is_lambda<Func>::value>>
: CppFunction<
typename detail::strip_function_object<Func>::type> {};
// For convenience . . .
template <
typename TFunctionType>
using returns_void
= std::is_void<
typename CppFunction<TFunctionType>::return_type>;
template <
typename TFunctionType>
using arg_count =
typename CppFunction<TFunctionType>::arg_count;
}
// namespace detail
}
// namespace gapbind14
#endif // INCLUDE_GAPBIND14_CPP_FN_HPP_