summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/ruby/backward/cxxanyargs.hpp186
-rw-r--r--include/ruby/ruby.h12
2 files changed, 189 insertions, 9 deletions
diff --git a/include/ruby/backward/cxxanyargs.hpp b/include/ruby/backward/cxxanyargs.hpp
index 3585f678b8..b2491956d7 100644
--- a/include/ruby/backward/cxxanyargs.hpp
+++ b/include/ruby/backward/cxxanyargs.hpp
@@ -11,6 +11,8 @@
/// meant to be a backwards compatibility shim. Please stick to
/// C++ 98 and never use newer features, like `constexpr`.
+extern "C++" {
+
/// @brief The main namespace.
/// @note The name "ruby" might already be taken, but that must not be a
/// 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;
#endif // RUBY_BACKWARD_CXXANYARGS_HPP
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index e96ac40747..9b3a2bcf81 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -2654,12 +2654,8 @@ void ruby_sig_finalize(void);
RUBY_SYMBOL_EXPORT_END
#if defined(__cplusplus)
-#if 0
-{ /* satisfy cc-mode */
-#endif
-} /* extern "C" { */
-extern "C++" {
-#endif
+#include "backward/cxxanyargs.hpp"
+#else
#if defined(HAVE_BUILTIN___BUILTIN_TYPES_COMPATIBLE_P)
# 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 /* __cplusplus */
+
#if defined(RUBY_DEVEL) && RUBY_DEVEL && (!defined(__cplusplus) || defined(RB_METHOD_DEFINITION_DECL))
# define RUBY_METHOD_FUNC(func) (func)
#else
@@ -2944,8 +2942,6 @@ RB_METHOD_DEFINITION_DECL(rb_define_global_function, (1,2), (const char *name),
#endif
#ifdef __cplusplus
-#include "backward/cxxanyargs.hpp"
-
#if 0
{ /* satisfy cc-mode */
#endif