mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
template metaprogramming instead of macros
C++ (and myself) hates macros. If we could do the same thing in both preprocessor and template, we shall choose template. This particular part of the ruby header is one of such situations.
This commit is contained in:
parent
ab33b3d691
commit
01825e8bff
Notes:
git
2020-01-28 15:43:29 +09:00
2 changed files with 189 additions and 9 deletions
|
@ -11,6 +11,8 @@
|
||||||
/// meant to be a backwards compatibility shim. Please stick to
|
/// meant to be a backwards compatibility shim. Please stick to
|
||||||
/// C++ 98 and never use newer features, like `constexpr`.
|
/// C++ 98 and never use newer features, like `constexpr`.
|
||||||
|
|
||||||
|
extern "C++" {
|
||||||
|
|
||||||
/// @brief The main namespace.
|
/// @brief The main namespace.
|
||||||
/// @note The name "ruby" might already be taken, but that must not be a
|
/// @note The name "ruby" might already be taken, but that must not be a
|
||||||
/// problem because namespaces are allowed to reopen.
|
/// problem because namespaces are allowed to reopen.
|
||||||
|
@ -433,7 +435,189 @@ rb_ivar_foreach(VALUE q, int_type *w, VALUE e)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
}}}
|
|
||||||
|
/// @brief Driver for *_define_method
|
||||||
|
///
|
||||||
|
/// ::rb_define_method function for instance takes a pointer to ANYARGS-ed
|
||||||
|
/// functions, which in fact varies 18 different prototypes. We still need to
|
||||||
|
/// preserve ANYARGS for storages but why not check the consistencies if
|
||||||
|
/// possible. In C++ a function has its own prototype, which is a compile-time
|
||||||
|
/// constant (static type) by nature. We can list up all the possible input
|
||||||
|
/// types and provide warnings for other cases. This is such attempt.
|
||||||
|
namespace define_method {
|
||||||
|
|
||||||
|
/// @brief Template metaprogramming to generate function prototypes.
|
||||||
|
/// @tparam T Type of method id (`ID` or `const char*` in practice).
|
||||||
|
/// @tparam F Definition driver e.g. ::rb_define_method.
|
||||||
|
template<typename T, void (*F)(VALUE klass, T mid, type *func, int arity)>
|
||||||
|
struct driver {
|
||||||
|
|
||||||
|
/// @brief Defines a method
|
||||||
|
/// @tparam N Arity of the function.
|
||||||
|
/// @tparam U The function in question
|
||||||
|
template<int N, typename U>
|
||||||
|
struct engine {
|
||||||
|
|
||||||
|
/* :TODO: Following deprecation attribute renders tons of warnings (one
|
||||||
|
* per every method definitions), which is annoying. Of course
|
||||||
|
* annoyance is the core feature of deprecation warnings... But that
|
||||||
|
* could be too much, especially when the warnings happen inside of
|
||||||
|
* machine-generated programs. And SWIG is known to do such thing.
|
||||||
|
* The new (granular) API was introduced in API version 2.7. As of
|
||||||
|
* this writing the version is 2.8. Let's warn this later, some time
|
||||||
|
* during 3.x. Hopefully codes in old (ANYARGS-ed) format should be
|
||||||
|
* less than now. */
|
||||||
|
#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) >= 301
|
||||||
|
RUBY_CXX_DEPRECATED("use of ANYARGS is deprecated")
|
||||||
|
#endif
|
||||||
|
/// @brief Defines klass#mid as func, whose arity is N.
|
||||||
|
/// @param[in] klass Where the method lives.
|
||||||
|
/// @param[in] mid Name of the method to define.
|
||||||
|
/// @param[in] func Function that implements klass#mid.
|
||||||
|
/// @deprecated Pass corrctly typed function instead.
|
||||||
|
static inline void
|
||||||
|
define(VALUE klass, T mid, type func)
|
||||||
|
{
|
||||||
|
F(klass, mid, func, N);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Defines klass#mid as func, whose arity is N.
|
||||||
|
/// @param[in] klass Where the method lives.
|
||||||
|
/// @param[in] mid Name of the method to define.
|
||||||
|
/// @param[in] func Function that implements klass#mid.
|
||||||
|
static inline void
|
||||||
|
define(VALUE klass, T mid, U func)
|
||||||
|
{
|
||||||
|
F(klass, mid, reinterpret_cast<type *>(func), N);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @cond INTERNAL_MACRO
|
||||||
|
template<int N, bool = false> struct specific : public engine<N, type *> {};
|
||||||
|
template<bool b> struct specific<15, b> : public engine<15, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific<14, b> : public engine<14, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific<13, b> : public engine<13, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific<12, b> : public engine<12, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific<11, b> : public engine<11, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific<10, b> : public engine<10, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 9, b> : public engine< 9, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 8, b> : public engine< 8, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 7, b> : public engine< 7, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 6, b> : public engine< 6, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 5, b> : public engine< 5, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 4, b> : public engine< 4, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 3, b> : public engine< 3, VALUE(*)(VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 2, b> : public engine< 2, VALUE(*)(VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 1, b> : public engine< 1, VALUE(*)(VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 0, b> : public engine< 0, VALUE(*)(VALUE)> {};
|
||||||
|
template<bool b> struct specific<-1, b> : public engine<-1, VALUE(*)(int argc, VALUE argv, VALUE self)> {
|
||||||
|
using engine<-1, VALUE(*)(int argc, VALUE argv, VALUE self)>::define;
|
||||||
|
static inline void define(VALUE c, T m, VALUE(*f)(int argc, VALUE *argv, VALUE self)) { F(c, m, reinterpret_cast<type *>(f), -1); }
|
||||||
|
static inline void define(VALUE c, T m, VALUE(*f)(int argc, const VALUE *argv, VALUE self)) { F(c, m, reinterpret_cast<type *>(f), -1); }
|
||||||
|
static inline void define(VALUE c, T m, VALUE(*f)(int argc, const VALUE *argv, VALUE self, VALUE)) { F(c, m, reinterpret_cast<type *>(f), -1); }
|
||||||
|
};
|
||||||
|
template<bool b> struct specific<-2, b> : public engine<-2, VALUE(*)(VALUE, VALUE)> {};
|
||||||
|
/// @endcond
|
||||||
|
};
|
||||||
|
|
||||||
|
/* We could perhaps merge this struct into the one above using variadic
|
||||||
|
* template parameters if we could assume C++11, but sadly we cannot. */
|
||||||
|
template<typename T, void (*F)(T mid, type func, int arity)>
|
||||||
|
struct driver0 {
|
||||||
|
template<int N, typename U>
|
||||||
|
struct engine {
|
||||||
|
RUBY_CXX_DEPRECATED("use of ANYARGS is deprecated")
|
||||||
|
static inline void
|
||||||
|
define(T mid, type func)
|
||||||
|
{
|
||||||
|
F(mid, func, N);
|
||||||
|
}
|
||||||
|
static inline void
|
||||||
|
define(T mid, U func)
|
||||||
|
{
|
||||||
|
F(mid, reinterpret_cast<type *>(func), N);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/// @cond INTERNAL_MACRO
|
||||||
|
template<int N, bool = false> struct specific : public engine<N, type *> {};
|
||||||
|
template<bool b> struct specific<15, b> : public engine<15, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific<14, b> : public engine<14, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific<13, b> : public engine<13, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific<12, b> : public engine<12, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific<11, b> : public engine<11, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific<10, b> : public engine<10, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 9, b> : public engine< 9, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 8, b> : public engine< 8, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 7, b> : public engine< 7, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 6, b> : public engine< 6, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 5, b> : public engine< 5, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 4, b> : public engine< 4, VALUE(*)(VALUE, VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 3, b> : public engine< 3, VALUE(*)(VALUE, VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 2, b> : public engine< 2, VALUE(*)(VALUE, VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 1, b> : public engine< 1, VALUE(*)(VALUE, VALUE)> {};
|
||||||
|
template<bool b> struct specific< 0, b> : public engine< 0, VALUE(*)(VALUE)> {};
|
||||||
|
template<bool b> struct specific<-1, b> : public engine<-1, VALUE(*)(int argc, VALUE argv, VALUE self)> {
|
||||||
|
using engine<-1, VALUE(*)(int argc, VALUE argv, VALUE self)>::define;
|
||||||
|
static inline void define(T m, VALUE(*f)(int argc, VALUE *argv, VALUE self)) { F(m, reinterpret_cast<type *>(f), -1); }
|
||||||
|
static inline void define(T m, VALUE(*f)(int argc, const VALUE *argv, VALUE self)) { F(m, reinterpret_cast<type *>(f), -1); }
|
||||||
|
static inline void define(T m, VALUE(*f)(int argc, const VALUE *argv, VALUE self, VALUE)) { F(m, reinterpret_cast<type *>(f), -1); }
|
||||||
|
};
|
||||||
|
template<bool b> struct specific<-2, b> : public engine<-2, VALUE(*)(VALUE, VALUE)> {};
|
||||||
|
/// @endcond
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Dispatches appropriate driver for ::rb_define_method
|
||||||
|
struct rb_define_method : public driver <const char *, ::rb_define_method> {};
|
||||||
|
|
||||||
|
/// @brief Dispatches appropriate driver for ::rb_define_method_id
|
||||||
|
struct rb_define_method_id : public driver <ID, ::rb_define_method_id> {};
|
||||||
|
|
||||||
|
/// @brief Dispatches appropriate driver for ::rb_define_private_method
|
||||||
|
struct rb_define_private_method : public driver <const char *, ::rb_define_private_method> {};
|
||||||
|
|
||||||
|
/// @brief Dispatches appropriate driver for ::rb_define_protected_method
|
||||||
|
struct rb_define_protected_method : public driver <const char *, ::rb_define_protected_method> {};
|
||||||
|
|
||||||
|
/// @brief Dispatches appropriate driver for ::rb_define_singleton_method
|
||||||
|
struct rb_define_singleton_method : public driver <const char *, ::rb_define_singleton_method> {};
|
||||||
|
|
||||||
|
/// @brief Dispatches appropriate driver for ::rb_define_module_function
|
||||||
|
struct rb_define_module_function : public driver <const char *, ::rb_define_module_function> {};
|
||||||
|
|
||||||
|
/// @brief Dispatches appropriate driver for ::rb_define_global_function
|
||||||
|
struct rb_define_global_function : public driver0<const char *, ::rb_define_global_function> {};
|
||||||
|
|
||||||
|
/// @brief Defines klass\#mid.
|
||||||
|
/// @param klass Where the method lives.
|
||||||
|
/// @copydetails #rb_define_global_function
|
||||||
|
#define rb_define_method(klass, mid, func, arity) ruby::backward::cxxanyargs::define_method::rb_define_method::specific<arity>::define(klass, mid, func)
|
||||||
|
|
||||||
|
/// @copydoc #rb_define_method
|
||||||
|
#define rb_define_method_id(klass, mid, func, arity) ruby::backward::cxxanyargs::define_method::rb_define_method_id::specific<arity>::define(klass, mid, func)
|
||||||
|
|
||||||
|
/// @brief Defines klass\#mid and makes it private.
|
||||||
|
/// @copydetails #rb_define_method
|
||||||
|
#define rb_define_private_method(klass, mid, func, arity) ruby::backward::cxxanyargs::define_method::rb_define_private_method::specific<arity>::define(klass, mid, func)
|
||||||
|
|
||||||
|
/// @brief Defines klass\#mid and makes it protected.
|
||||||
|
/// @copydetails #rb_define_method
|
||||||
|
#define rb_define_protected_method(klass, mid, func, arity) ruby::backward::cxxanyargs::define_method::rb_define_protected_method::specific<arity>::define(klass, mid, func)
|
||||||
|
|
||||||
|
/// @brief Defines klass.mid.
|
||||||
|
/// @copydetails #rb_define_method
|
||||||
|
#define rb_define_singleton_method(klass, mid, func, arity) ruby::backward::cxxanyargs::define_method::rb_define_singleton_method::specific<arity>::define(klass, mid, func)
|
||||||
|
|
||||||
|
/// @brief Defines klass\#mid and makes it a module function.
|
||||||
|
/// @copydetails #rb_define_method
|
||||||
|
#define rb_define_module_function(klass, mid, func, arity) ruby::backward::cxxanyargs::define_method::rb_define_module_function::specific<arity>::define(klass, mid, func)
|
||||||
|
|
||||||
|
/// @brief Defines ::rb_cKerbel \#mid.
|
||||||
|
/// @param mid Name of the defining method.
|
||||||
|
/// @param func Implementation of \#mid.
|
||||||
|
/// @param arity Arity of \#mid.
|
||||||
|
#define rb_define_global_function(mid, func, arity) ruby::backward::cxxanyargs::define_method::rb_define_global_function::specific<arity>::define(mid, func)
|
||||||
|
|
||||||
|
}}}}}
|
||||||
|
|
||||||
using namespace ruby::backward::cxxanyargs;
|
using namespace ruby::backward::cxxanyargs;
|
||||||
#endif // RUBY_BACKWARD_CXXANYARGS_HPP
|
#endif // RUBY_BACKWARD_CXXANYARGS_HPP
|
||||||
|
|
|
@ -2654,12 +2654,8 @@ void ruby_sig_finalize(void);
|
||||||
RUBY_SYMBOL_EXPORT_END
|
RUBY_SYMBOL_EXPORT_END
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
#if 0
|
#include "backward/cxxanyargs.hpp"
|
||||||
{ /* satisfy cc-mode */
|
#else
|
||||||
#endif
|
|
||||||
} /* extern "C" { */
|
|
||||||
extern "C++" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(HAVE_BUILTIN___BUILTIN_TYPES_COMPATIBLE_P)
|
#if defined(HAVE_BUILTIN___BUILTIN_TYPES_COMPATIBLE_P)
|
||||||
# define rb_f_notimplement_p(f) __builtin_types_compatible_p(__typeof__(f),__typeof__(rb_f_notimplement))
|
# define rb_f_notimplement_p(f) __builtin_types_compatible_p(__typeof__(f),__typeof__(rb_f_notimplement))
|
||||||
|
@ -2937,6 +2933,8 @@ RB_METHOD_DEFINITION_DECL(rb_define_global_function, (1,2), (const char *name),
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
#if defined(RUBY_DEVEL) && RUBY_DEVEL && (!defined(__cplusplus) || defined(RB_METHOD_DEFINITION_DECL))
|
#if defined(RUBY_DEVEL) && RUBY_DEVEL && (!defined(__cplusplus) || defined(RB_METHOD_DEFINITION_DECL))
|
||||||
# define RUBY_METHOD_FUNC(func) (func)
|
# define RUBY_METHOD_FUNC(func) (func)
|
||||||
#else
|
#else
|
||||||
|
@ -2944,8 +2942,6 @@ RB_METHOD_DEFINITION_DECL(rb_define_global_function, (1,2), (const char *name),
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#include "backward/cxxanyargs.hpp"
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
{ /* satisfy cc-mode */
|
{ /* satisfy cc-mode */
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue