[前][次][番号順一覧][スレッド一覧]

ruby-changes:59841

From: =E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3 <ko1@a...>
Date: Tue, 28 Jan 2020 15:43:28 +0900 (JST)
Subject: [ruby-changes:59841] 01825e8bff (master): template metaprogramming instead of macros

https://git.ruby-lang.org/ruby.git/commit/?id=01825e8bff

From 01825e8bffde9f4517e60878f8a829f91c361d68 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?=
 <shyouhei@r...>
Date: Tue, 28 Jan 2020 11:43:33 +0900
Subject: 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.

diff --git a/include/ruby/backward/cxxanyargs.hpp b/include/ruby/backward/cxxanyargs.hpp
index 3585f67..b249195 100644
--- a/include/ruby/backward/cxxanyargs.hpp
+++ b/include/ruby/backward/cxxanyargs.hpp
@@ -11,6 +11,8 @@ https://github.com/ruby/ruby/blob/trunk/include/ruby/backward/cxxanyargs.hpp#L11
 ///             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) https://github.com/ruby/ruby/blob/trunk/include/ruby/backward/cxxanyargs.hpp#L435
 }
 
 /// @}
-}}}
+
+/// @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(*)(V (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]