wrenpp/include/wrenpp/detail/has_method.hpp
King_DuckZ 09530e15c9 Use a better ID for identifying classes.
Upon testing (and reading), getting the address of a static
is safe even across .so boundaries. Moreover it doesn't incur
into the risk of collisions, unlike hashes, and also works
with different classes with the same name (for example from
two different unnamed namespaces). At this point the crc32
stuff is pretty much redundant, I'll try to remove it next.
2022-06-03 09:39:43 +02:00

82 lines
2.9 KiB
C++

/* Copyright 2020-2022, Michele Santullo
* This file is part of wrenpp.
*
* Wrenpp 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.
*
* Wrenpp 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 wrenpp. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <type_traits>
//see https://stackoverflow.com/a/10707822
#define define_method_info(method_name, pretty_name, ret_type, ...) \
class method_ ## pretty_name { \
typedef std::integral_constant<int, 0> no_method_t; \
typedef std::integral_constant<int, 1> has_method_t; \
typedef std::integral_constant<int, 2> has_static_method_t; \
template<typename A, typename... Args> \
static has_method_t test(ret_type (A::*)(Args...)) { \
return {}; \
} \
template <typename A, typename... Args> \
static has_static_method_t test(ret_type (*)(Args...)) { \
return {}; \
} \
template <typename A, typename... Args> \
static auto test(decltype(std::declval<A>().method_name(std::declval<Args>()...))*,void *) { \
typedef decltype(test<A, Args...>(&A::method_name)) return_type; \
return return_type{}; \
} \
template<typename A, typename... Args> \
static no_method_t test(...) { \
return {}; \
} \
public: \
template< typename T> \
class exists { \
typedef decltype(test<T, __VA_ARGS__>(0,0)) found_t; \
public: \
static const constexpr bool value = (found_t::value != no_method_t::value); \
}; \
template <typename T> \
class is_static { \
typedef decltype(test<T, __VA_ARGS__>(0,0)) found_t; \
public: \
static const constexpr bool value = (found_t::value == has_static_method_t::value); \
}; \
template <typename T> struct static_ptr { \
typedef ret_type (*type)(__VA_ARGS__); \
}; \
template <typename T> struct nonstatic_ptr { \
typedef ret_type (T::*type)(__VA_ARGS__); \
}; \
template <typename T> struct ptr { \
typedef typename std::conditional<is_static<T>::value, typename static_ptr<T>::type, typename std::conditional<exists<T>::value, typename nonstatic_ptr<T>::type, void>::type>::type type; \
}; \
}
#define define_has_typedef(typedef_name,pretty_name) \
template <typename T> \
struct Has ## pretty_name ## Typedef { \
private: \
struct TrueType { int a[2]; }; \
typedef int FalseType; \
template <typename C> static TrueType has_typedef ( const typename C::typedef_name* ); \
template <typename C> static FalseType has_typedef ( ... ); \
public: \
enum { value = sizeof(has_typedef<T>(nullptr)) == sizeof(TrueType) }; \
}
namespace wren {
} //namespace wren