diff options
Diffstat (limited to 'include/ruby/internal/core')
-rw-r--r-- | include/ruby/internal/core/rarray.h | 341 | ||||
-rw-r--r-- | include/ruby/internal/core/rbasic.h | 86 | ||||
-rw-r--r-- | include/ruby/internal/core/rbignum.h | 33 | ||||
-rw-r--r-- | include/ruby/internal/core/rclass.h | 62 | ||||
-rw-r--r-- | include/ruby/internal/core/rdata.h | 225 | ||||
-rw-r--r-- | include/ruby/internal/core/rfile.h | 21 | ||||
-rw-r--r-- | include/ruby/internal/core/rhash.h | 101 | ||||
-rw-r--r-- | include/ruby/internal/core/rmatch.h | 91 | ||||
-rw-r--r-- | include/ruby/internal/core/robject.h | 104 | ||||
-rw-r--r-- | include/ruby/internal/core/rregexp.h | 88 | ||||
-rw-r--r-- | include/ruby/internal/core/rstring.h | 399 | ||||
-rw-r--r-- | include/ruby/internal/core/rstruct.h | 58 | ||||
-rw-r--r-- | include/ruby/internal/core/rtypeddata.h | 475 |
13 files changed, 1818 insertions, 266 deletions
diff --git a/include/ruby/internal/core/rarray.h b/include/ruby/internal/core/rarray.h index 938e2dc897..90690fe794 100644 --- a/include/ruby/internal/core/rarray.h +++ b/include/ruby/internal/core/rarray.h @@ -17,7 +17,7 @@ * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of - * extension libraries. They could be written in C++98. + * extension libraries. They could be written in C++98. * @brief Defines struct ::RArray. */ #include "ruby/internal/arithmetic/long.h" @@ -29,29 +29,27 @@ #include "ruby/internal/core/rbasic.h" #include "ruby/internal/dllexport.h" #include "ruby/internal/fl_type.h" -#include "ruby/internal/rgengc.h" +#include "ruby/internal/gc.h" #include "ruby/internal/stdbool.h" #include "ruby/internal/value.h" #include "ruby/internal/value_type.h" #include "ruby/assert.h" -#ifndef USE_TRANSIENT_HEAP -# define USE_TRANSIENT_HEAP 1 -#endif - +/** + * Convenient casting macro. + * + * @param obj An object, which is in fact an ::RArray. + * @return The passed object casted to ::RArray. + */ #define RARRAY(obj) RBIMPL_CAST((struct RArray *)(obj)) +/** @cond INTERNAL_MACRO */ #define RARRAY_EMBED_FLAG RARRAY_EMBED_FLAG #define RARRAY_EMBED_LEN_MASK RARRAY_EMBED_LEN_MASK #define RARRAY_EMBED_LEN_MAX RARRAY_EMBED_LEN_MAX #define RARRAY_EMBED_LEN_SHIFT RARRAY_EMBED_LEN_SHIFT -#if USE_TRANSIENT_HEAP -# define RARRAY_TRANSIENT_FLAG RARRAY_TRANSIENT_FLAG -#else -# define RARRAY_TRANSIENT_FLAG 0 -#endif -#define RARRAY_LEN rb_array_len -#define RARRAY_CONST_PTR rb_array_const_ptr -#define RARRAY_CONST_PTR_TRANSIENT rb_array_const_ptr_transient +/** @endcond */ +#define RARRAY_LEN rb_array_len /**< @alias{rb_array_len} */ +#define RARRAY_CONST_PTR rb_array_const_ptr /**< @alias{rb_array_const_ptr} */ /** @cond INTERNAL_MACRO */ #if defined(__fcc__) || defined(__fcc_version) || \ @@ -64,33 +62,102 @@ #define RARRAY_EMBED_LEN RARRAY_EMBED_LEN #define RARRAY_LENINT RARRAY_LENINT -#define RARRAY_TRANSIENT_P RARRAY_TRANSIENT_P #define RARRAY_ASET RARRAY_ASET #define RARRAY_PTR RARRAY_PTR /** @endcond */ +/** + * @private + * + * Bits that you can set to ::RBasic::flags. + * + * @warning These enums are not the only bits we use for arrays. + * + * @internal + * + * Unlike strings, flag usages for arrays are scattered across the entire + * source codes. @shyouhei doesn't know the complete list. But what is listed + * here is at least incomplete. + */ enum ruby_rarray_flags { + /** + * This flag has something to do with memory footprint. If the array is + * "small" enough, ruby tries to be creative to abuse padding bits of + * struct ::RArray for storing its contents. This flag denotes that + * situation. + * + * @warning This bit has to be considered read-only. Setting/clearing + * this bit without corresponding fix up must cause immediate + * SEGV. Also, internal structures of an array change + * dynamically and transparently throughout of its lifetime. + * Don't assume it being persistent. + * + * @internal + * + * 3rd parties must not be aware that there even is more than one way to + * store array elements. It was a bad idea to expose this to them. + */ RARRAY_EMBED_FLAG = RUBY_FL_USER1, + /* RUBY_FL_USER2 is for ELTS_SHARED */ - RARRAY_EMBED_LEN_MASK = RUBY_FL_USER4 | RUBY_FL_USER3 -#if USE_TRANSIENT_HEAP - , - RARRAY_TRANSIENT_FLAG = RUBY_FL_USER13 -#endif + + /** + * When an array employs embedded strategy (see ::RARRAY_EMBED_FLAG), these + * bits are used to store the number of elements actually filled into + * ::RArray::ary. + * + * @internal + * + * 3rd parties must not be aware that there even is more than one way to + * store array elements. It was a bad idea to expose this to them. + */ + RARRAY_EMBED_LEN_MASK = RUBY_FL_USER9 | RUBY_FL_USER8 | RUBY_FL_USER7 | RUBY_FL_USER6 | + RUBY_FL_USER5 | RUBY_FL_USER4 | RUBY_FL_USER3 }; +/** + * This is an enum because GDB wants it (rather than a macro). People need not + * bother. + */ enum ruby_rarray_consts { - RARRAY_EMBED_LEN_SHIFT = RUBY_FL_USHIFT + 3, - RARRAY_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(VALUE) + /** Where ::RARRAY_EMBED_LEN_MASK resides. */ + RARRAY_EMBED_LEN_SHIFT = RUBY_FL_USHIFT + 3 }; +/** Ruby's array. */ struct RArray { + + /** Basic part, including flags and class. */ struct RBasic basic; + + /** Array's specific fields. */ union { + + /** + * Arrays that use separated memory region for elements use this + * pattern. + */ struct { + + /** Number of elements of the array. */ long len; + + /** Auxiliary info. */ union { + + /** + * Capacity of `*ptr`. A continuous memory region of at least + * `capa` elements is expected to exist at `*ptr`. This can be + * bigger than `len`. + */ long capa; + + /** + * Parent of the array. Nowadays arrays can share their + * backend memory regions each other, constructing gigantic + * nest of objects. This situation is called "shared", and + * this is the field to control such properties. + */ #if defined(__clang__) /* <- clang++ is sane */ || \ !defined(__cplusplus) /* <- C99 is sane */ || \ (__cplusplus > 199711L) /* <- C++11 is sane */ @@ -98,22 +165,72 @@ struct RArray { #endif VALUE shared_root; } aux; + + /** + * Pointer to the C array that holds the elements of the array. In + * the old days each array had dedicated memory regions. That is + * no longer true today, but there still are arrays of such + * properties. This field could be used to point such things. + */ const VALUE *ptr; } heap; - const VALUE ary[RARRAY_EMBED_LEN_MAX]; + + /** + * Embedded elements. When an array is short enough, it uses this area + * to store its elements. In this case the length is encoded into the + * flags. + */ + /* This is a length 1 array because: + * 1. GCC has a bug that does not optimize C flexible array members + * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452) + * 2. Zero length arrays are not supported by all compilers + */ + const VALUE ary[1]; } as; }; RBIMPL_SYMBOL_EXPORT_BEGIN() +/** + * @private + * + * Declares a section of code where raw pointers are used. This is an + * implementation detail of #RARRAY_PTR_USE. People don't use it directly. + * + * @param[in] ary An object of ::RArray. + * @return `ary`'s backend C array. + */ VALUE *rb_ary_ptr_use_start(VALUE ary); + +/** + * @private + * + * Declares an end of a section formerly started by rb_ary_ptr_use_start(). + * This is an implementation detail of #RARRAY_PTR_USE. People don't use it + * directly. + * + * @param[in] a An object of ::RArray. + */ void rb_ary_ptr_use_end(VALUE a); -#if USE_TRANSIENT_HEAP -void rb_ary_detransient(VALUE a); -#endif + RBIMPL_SYMBOL_EXPORT_END() RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() +/** + * Queries the length of the array. + * + * @param[in] ary Array in question. + * @return Its number of elements. + * @pre `ary` must be an instance of ::RArray, and must has its + * ::RARRAY_EMBED_FLAG flag set. + * + * @internal + * + * This was a macro before. It was inevitable to be public, since macros are + * global constructs. But should it be forever? Now that it is a function, + * @shyouhei thinks it could just be eliminated, hidden into implementation + * details. + */ static inline long RARRAY_EMBED_LEN(VALUE ary) { @@ -127,6 +244,13 @@ RARRAY_EMBED_LEN(VALUE ary) } RBIMPL_ATTR_PURE_UNLESS_DEBUG() +/** + * Queries the length of the array. + * + * @param[in] a Array in question. + * @return Its number of elements. + * @pre `a` must be an instance of ::RArray. + */ static inline long rb_array_len(VALUE a) { @@ -141,6 +265,18 @@ rb_array_len(VALUE a) } RBIMPL_ATTR_ARTIFICIAL() +/** + * Identical to rb_array_len(), except it differs for the return type. + * + * @param[in] ary Array in question. + * @exception rb_eRangeError Too long. + * @return Its number of elements. + * @pre `ary` must be an instance of ::RArray. + * + * @internal + * + * This API seems redundant but has actual usages. + */ static inline int RARRAY_LENINT(VALUE ary) { @@ -148,23 +284,17 @@ RARRAY_LENINT(VALUE ary) } RBIMPL_ATTR_PURE_UNLESS_DEBUG() -RBIMPL_ATTR_ARTIFICIAL() -static inline bool -RARRAY_TRANSIENT_P(VALUE ary) -{ - RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY); - -#if USE_TRANSIENT_HEAP - return RB_FL_ANY_RAW(ary, RARRAY_TRANSIENT_FLAG); -#else - return false; -#endif -} - -RBIMPL_ATTR_PURE_UNLESS_DEBUG() -/* internal function. do not use this function */ +/** + * @private + * + * This is an implementation detail of RARRAY_PTR(). People do not use it + * directly. + * + * @param[in] a An object of ::RArray. + * @return Its backend storage. + */ static inline const VALUE * -rb_array_const_ptr_transient(VALUE a) +rb_array_const_ptr(VALUE a) { RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY); @@ -176,70 +306,62 @@ rb_array_const_ptr_transient(VALUE a) } } -#if ! USE_TRANSIENT_HEAP -RBIMPL_ATTR_PURE_UNLESS_DEBUG() -#endif -/* internal function. do not use this function */ -static inline const VALUE * -rb_array_const_ptr(VALUE a) -{ - RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY); - -#if USE_TRANSIENT_HEAP - if (RARRAY_TRANSIENT_P(a)) { - rb_ary_detransient(a); - } -#endif - return rb_array_const_ptr_transient(a); -} - -/* internal function. do not use this function */ -static inline VALUE * -rb_array_ptr_use_start(VALUE a, - RBIMPL_ATTR_MAYBE_UNUSED() - int allow_transient) -{ - RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY); - -#if USE_TRANSIENT_HEAP - if (!allow_transient) { - if (RARRAY_TRANSIENT_P(a)) { - rb_ary_detransient(a); - } - } -#endif - - return rb_ary_ptr_use_start(a); -} - -/* internal function. do not use this function */ -static inline void -rb_array_ptr_use_end(VALUE a, - RBIMPL_ATTR_MAYBE_UNUSED() - int allow_transient) -{ - RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY); - rb_ary_ptr_use_end(a); -} - -#define RBIMPL_RARRAY_STMT(flag, ary, var, expr) do { \ +/** + * @private + * + * This is an implementation detail of #RARRAY_PTR_USE. People do not use it + * directly. + */ +#define RBIMPL_RARRAY_STMT(ary, var, expr) do { \ RBIMPL_ASSERT_TYPE((ary), RUBY_T_ARRAY); \ const VALUE rbimpl_ary = (ary); \ - VALUE *var = rb_array_ptr_use_start(rbimpl_ary, (flag)); \ + VALUE *var = rb_ary_ptr_use_start(rbimpl_ary); \ expr; \ - rb_array_ptr_use_end(rbimpl_ary, (flag)); \ + rb_ary_ptr_use_end(rbimpl_ary); \ } while (0) -#define RARRAY_PTR_USE_START(a) rb_array_ptr_use_start(a, 0) -#define RARRAY_PTR_USE_END(a) rb_array_ptr_use_end(a, 0) -#define RARRAY_PTR_USE(ary, ptr_name, expr) \ - RBIMPL_RARRAY_STMT(0, ary, ptr_name, expr) - -#define RARRAY_PTR_USE_START_TRANSIENT(a) rb_array_ptr_use_start(a, 1) -#define RARRAY_PTR_USE_END_TRANSIENT(a) rb_array_ptr_use_end(a, 1) -#define RARRAY_PTR_USE_TRANSIENT(ary, ptr_name, expr) \ - RBIMPL_RARRAY_STMT(1, ary, ptr_name, expr) +/** + * Declares a section of code where raw pointers are used. In case you need to + * touch the raw C array instead of polite CAPIs, then that operation shall be + * wrapped using this macro. + * + * ```CXX + * const auto ary = rb_eval_string("[...]"); + * const auto len = RARRAY_LENINT(ary); + * const auto symwrite = rb_intern("write"); + * + * RARRAY_PTR_USE(ary, ptr, { + * rb_funcallv(rb_stdout, symwrite, len, ptr); + * }); + * ``` + * + * @param ary An object of ::RArray. + * @param ptr_name A variable name which points the C array in `expr`. + * @param expr The expression that touches `ptr_name`. + * + * @internal + * + * For historical reasons use of this macro is not enforced. There are + * extension libraries in the wild which call RARRAY_PTR() without it. We want + * them use it... Maybe some transition path can be implemented later. + */ +#define RARRAY_PTR_USE(ary, ptr_name, expr) \ + RBIMPL_RARRAY_STMT(ary, ptr_name, expr) +/** + * Wild use of a C pointer. This function accesses the backend storage + * directly. This is slower than #RARRAY_PTR_USE. It exercises + * extra manoeuvres to protect our generational GC. Use of this function is + * considered archaic. Use a modern way instead. + * + * @param[in] ary An object of ::RArray. + * @return The backend C array. + * + * @internal + * + * That said... there are extension libraries in the wild who uses it. We + * cannot but continue supporting. + */ static inline VALUE * RARRAY_PTR(VALUE ary) { @@ -249,14 +371,27 @@ RARRAY_PTR(VALUE ary) return RBIMPL_CAST((VALUE *)RARRAY_CONST_PTR(tmp)); } +/** + * Assigns an object in an array. + * + * @param[out] ary Destination array object. + * @param[in] i Index of `ary`. + * @param[in] v Arbitrary ruby object. + * @pre `ary` must be an instance of ::RArray. + * @pre `ary`'s length must be longer than or equal to `i`. + * @pre `i` must be greater than or equal to zero. + * @post `ary`'s `i`th element is set to `v`. + */ static inline void RARRAY_ASET(VALUE ary, long i, VALUE v) { - RARRAY_PTR_USE_TRANSIENT(ary, ptr, + RARRAY_PTR_USE(ary, ptr, RB_OBJ_WRITE(ary, &ptr[i], v)); } -/* +/** + * @deprecated + * * :FIXME: we want to convert RARRAY_AREF into an inline function (to add rooms * for more sanity checks). However there were situations where the address of * this macro is taken i.e. &RARRAY_AREF(...). They cannot be possible if this @@ -265,6 +400,6 @@ RARRAY_ASET(VALUE ary, long i, VALUE v) * remains as it is due to that. If we could warn such usages we can set a * transition path, but currently no way is found to do so. */ -#define RARRAY_AREF(a, i) RARRAY_CONST_PTR_TRANSIENT(a)[i] +#define RARRAY_AREF(a, i) RARRAY_CONST_PTR(a)[i] #endif /* RBIMPL_RARRAY_H */ diff --git a/include/ruby/internal/core/rbasic.h b/include/ruby/internal/core/rbasic.h index aafec2422f..a1477e2600 100644 --- a/include/ruby/internal/core/rbasic.h +++ b/include/ruby/internal/core/rbasic.h @@ -17,7 +17,7 @@ * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of - * extension libraries. They could be written in C++98. + * extension libraries. They could be written in C++98. * @brief Defines struct ::RBasic. */ #include "ruby/internal/attr/artificial.h" @@ -31,22 +31,58 @@ #include "ruby/internal/value.h" #include "ruby/assert.h" -#define RBASIC(obj) RBIMPL_CAST((struct RBasic *)(obj)) -#define RBASIC_CLASS RBASIC_CLASS -#define RVALUE_EMBED_LEN_MAX RVALUE_EMBED_LEN_MAX - +/** + * Convenient casting macro. + * + * @param obj Arbitrary Ruby object. + * @return The passed object casted to ::RBasic. + */ +#define RBASIC(obj) RBIMPL_CAST((struct RBasic *)(obj)) /** @cond INTERNAL_MACRO */ +#define RBASIC_CLASS RBASIC_CLASS +#define RBIMPL_RVALUE_EMBED_LEN_MAX 3 +#define RVALUE_EMBED_LEN_MAX RVALUE_EMBED_LEN_MAX #define RBIMPL_EMBED_LEN_MAX_OF(T) \ RBIMPL_CAST((int)(sizeof(VALUE[RBIMPL_RVALUE_EMBED_LEN_MAX]) / (sizeof(T)))) /** @endcond */ -#define RBIMPL_RVALUE_EMBED_LEN_MAX 3 -enum ruby_rvalue_flags { RVALUE_EMBED_LEN_MAX = RBIMPL_RVALUE_EMBED_LEN_MAX }; +/** + * This is an enum because GDB wants it (rather than a macro). People need not + * bother. + */ +enum ruby_rvalue_flags { + /** Max possible number of objects that can be embedded. */ + RVALUE_EMBED_LEN_MAX = RBIMPL_RVALUE_EMBED_LEN_MAX +}; +/** + * Ruby object's base components. All Ruby objects have them in common. + */ struct RUBY_ALIGNAS(SIZEOF_VALUE) RBasic { - VALUE flags; /**< @see enum ::ruby_fl_type. */ + + /** + * Per-object flags. Each Ruby object has its own characteristics apart + * from its class. For instance, whether an object is frozen or not is not + * controlled by its class. This is where such properties are stored. + * + * @see enum ::ruby_fl_type + * + * @note This is ::VALUE rather than an enum for alignment purposes. Back + * in the 1990s there were no such thing like `_Alignas` in C. + */ + VALUE flags; + + /** + * Class of an object. Every object has its class. Also, everything is an + * object in Ruby. This means classes are also objects. Classes have + * their own classes, classes of classes have their classes too, and it + * recursively continues forever. + * + * Also note the `const` qualifier. In Ruby, an object cannot "change" its + * class. + */ const VALUE klass; #ifdef __cplusplus @@ -70,12 +106,46 @@ RBasic { }; RBIMPL_SYMBOL_EXPORT_BEGIN() +/** + * Make the object invisible from Ruby code. + * + * It is useful to let Ruby's GC manage your internal data structure -- The + * object keeps being managed by GC, but `ObjectSpace.each_object` never yields + * the object. + * + * Note that the object also lose a way to call a method on it. + * + * @param[out] obj A Ruby object. + * @return The passed object. + * @post The object is destructively modified to be invisible. + * @see rb_obj_reveal + */ VALUE rb_obj_hide(VALUE obj); + +/** + * Make a hidden object visible again. + * + * It is the caller's responsibility to pass the right `klass` which `obj` + * originally used to belong to. + * + * @param[out] obj A Ruby object. + * @param[in] klass Class of `obj`. + * @return Passed `obj`. + * @pre `obj` was previously hidden. + * @post `obj`'s class is `klass`. + * @see rb_obj_hide + */ VALUE rb_obj_reveal(VALUE obj, VALUE klass); /* do not use this API to change klass information */ RBIMPL_SYMBOL_EXPORT_END() RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() +/** + * Queries the class of an object. + * + * @param[in] obj An object. + * @return Its class. + */ static inline VALUE RBASIC_CLASS(VALUE obj) { diff --git a/include/ruby/internal/core/rbignum.h b/include/ruby/internal/core/rbignum.h index 3cd7d19850..1d31743235 100644 --- a/include/ruby/internal/core/rbignum.h +++ b/include/ruby/internal/core/rbignum.h @@ -17,15 +17,16 @@ * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of - * extension libraries. They could be written in C++98. - * @brief Routines to manipulate struct ::RBignum. + * extension libraries. They could be written in C++98. + * @brief Routines to manipulate struct RBignum. + * @note The struct RBignum itself is opaque. */ #include "ruby/internal/dllexport.h" #include "ruby/internal/value.h" #include "ruby/internal/value_type.h" #include "ruby/internal/stdbool.h" -#define RBIGNUM_SIGN rb_big_sign +#define RBIGNUM_SIGN rb_big_sign /**< @alias{rb_big_sign} */ /** @cond INTERNAL_MACRO */ #define RBIGNUM_POSITIVE_P RBIGNUM_POSITIVE_P @@ -33,9 +34,29 @@ /** @endcond */ RBIMPL_SYMBOL_EXPORT_BEGIN() +/** + * The "sign" of a bignum. + * + * @param[in] num An object of RBignum. + * @retval 1 It is greater than or equal to zero. + * @retval 0 It is less than zero. + * + * @internal + * + * Implementation wise, unlike fixnums (which are 2's complement), bignums are + * signed magnitude system. Theoretically it could be possible to have + * negative zero instances. But in reality there is no way to create such + * thing. Nobody ever needed that kind of insanity. + */ int rb_big_sign(VALUE num); RBIMPL_SYMBOL_EXPORT_END() +/** + * Checks if the bignum is positive. + * @param[in] b An object of RBignum. + * @retval false `b` is less than zero. + * @retval true Otherwise. + */ static inline bool RBIGNUM_POSITIVE_P(VALUE b) { @@ -43,6 +64,12 @@ RBIGNUM_POSITIVE_P(VALUE b) return RBIGNUM_SIGN(b); } +/** + * Checks if the bignum is negative. + * @param[in] b An object of RBignum. + * @retval true `b` is less than zero. + * @retval false Otherwise. + */ static inline bool RBIGNUM_NEGATIVE_P(VALUE b) { diff --git a/include/ruby/internal/core/rclass.h b/include/ruby/internal/core/rclass.h index 0aa6b1290e..b0b6bfc80c 100644 --- a/include/ruby/internal/core/rclass.h +++ b/include/ruby/internal/core/rclass.h @@ -17,31 +17,77 @@ * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of - * extension libraries. They could be written in C++98. - * @brief Routines to manipulate struct ::RClass. + * extension libraries. They could be written in C++98. + * @brief Routines to manipulate struct RClass. + * @note The struct RClass itself is opaque. */ #include "ruby/internal/dllexport.h" #include "ruby/internal/value.h" #include "ruby/internal/cast.h" -#define RMODULE_IS_OVERLAID RMODULE_IS_OVERLAID +/** @cond INTERNAL_MACRO */ #define RMODULE_IS_REFINEMENT RMODULE_IS_REFINEMENT -#define RMODULE_INCLUDED_INTO_REFINEMENT RMODULE_INCLUDED_INTO_REFINEMENT +/** @endcond */ +/** + * Convenient casting macro. + * + * @param obj An object, which is in fact an RClass. + * @return The passed object casted to RClass. + */ #define RCLASS(obj) RBIMPL_CAST((struct RClass *)(obj)) + +/** @alias{RCLASS} */ #define RMODULE RCLASS + +/** @alias{rb_class_get_superclass} */ #define RCLASS_SUPER rb_class_get_superclass +/** + * @private + * + * Bits that you can set to ::RBasic::flags. + * + * @internal + * + * Why is it here, given RClass itself is not? + */ enum ruby_rmodule_flags { - RMODULE_IS_OVERLAID = RUBY_FL_USER2, - RMODULE_IS_REFINEMENT = RUBY_FL_USER3, - RMODULE_INCLUDED_INTO_REFINEMENT = RUBY_FL_USER4 + /** + * This flag has something to do with refinements. A module created using + * rb_mod_refine() has this flag set. This is the bit which controls + * difference between normal inclusion versus refinements. + */ + RMODULE_IS_REFINEMENT = RUBY_FL_USER3 }; struct RClass; /* Opaque, declared here for RCLASS() macro. */ RBIMPL_SYMBOL_EXPORT_BEGIN() -VALUE rb_class_get_superclass(VALUE); +/** + * Returns the superclass of a class. + * @param[in] klass An object of RClass. + * @retval RUBY_Qfalse `klass` has no super class. + * @retval otherwise Raw superclass of `klass` + * @see rb_class_superclass + * + * ### Q&A ### + * + * - Q: How can a class have no super class? + * + * - A: `klass` could be a module. Or it could be ::rb_cBasicObject. + * + * - Q: What do you mean by "raw" superclass? + * + * - A: This is a really good question. The answer is that this function + * returns something different from what you would normally expect. On + * occasions ruby inserts hidden classes in a hierarchy of class + * inheritance behind-the-scene. Such classes are called "iclass"es and + * distinguished using ::RUBY_T_ICLASS in C level. They are truly + * transparent from Ruby level but can be accessed from C, by using this + * API. + */ +VALUE rb_class_get_superclass(VALUE klass); RBIMPL_SYMBOL_EXPORT_END() #endif /* RBIMPL_RCLASS_H */ diff --git a/include/ruby/internal/core/rdata.h b/include/ruby/internal/core/rdata.h index 9432b2ed7a..43ab3c01e7 100644 --- a/include/ruby/internal/core/rdata.h +++ b/include/ruby/internal/core/rdata.h @@ -17,7 +17,7 @@ * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of - * extension libraries. They could be written in C++98. + * extension libraries. They could be written in C++98. * @brief Defines struct ::RData. */ #include "ruby/internal/config.h" @@ -36,6 +36,7 @@ #include "ruby/internal/value_type.h" #include "ruby/defines.h" +/** @cond INTERNAL_MACRO */ #ifdef RUBY_UNTYPED_DATA_WARNING # /* Take that. */ #elif defined(RUBY_EXPORT) @@ -44,39 +45,160 @@ # define RUBY_UNTYPED_DATA_WARNING 0 #endif -/** @cond INTERNAL_MACRO */ #define RBIMPL_DATA_FUNC(f) RBIMPL_CAST((void (*)(void *))(f)) #define RBIMPL_ATTRSET_UNTYPED_DATA_FUNC() \ RBIMPL_ATTR_WARNING(("untyped Data is unsafe; use TypedData instead")) \ RBIMPL_ATTR_DEPRECATED(("by TypedData")) + +#define RBIMPL_MACRO_SELECT(x, y) x ## y +#define RUBY_MACRO_SELECT(x, y) RBIMPL_MACRO_SELECT(x, y) /** @endcond */ +/** + * Convenient casting macro. + * + * @param obj An object, which is in fact an ::RData. + * @return The passed object casted to ::RData. + */ #define RDATA(obj) RBIMPL_CAST((struct RData *)(obj)) + +/** + * Convenient getter macro. + * + * @param obj An object, which is in fact an ::RData. + * @return The passed object's ::RData::data field. + */ #define DATA_PTR(obj) RDATA(obj)->data -#define RBIMPL_MACRO_SELECT(x, y) x ## y -#define RUBY_MACRO_SELECT(x, y) RBIMPL_MACRO_SELECT(x, y) + +/** + * This is a value you can set to ::RData::dfree. Setting this means the data + * was allocated using ::ruby_xmalloc() (or variants), and shall be freed using + * ::ruby_xfree(). + * + * @warning Do not use this if you want to use system malloc, because the + * system and Ruby might or might not share the same malloc + * implementation. + */ #define RUBY_DEFAULT_FREE RBIMPL_DATA_FUNC(-1) + +/** + * This is a value you can set to ::RData::dfree. Setting this means the data + * is managed by someone else, like, statically allocated. Of course you are + * on your own then. + */ #define RUBY_NEVER_FREE RBIMPL_DATA_FUNC(0) + +/** + * @private + * + * @deprecated This macro once was a thing in the old days, but makes no sense + * any longer today. Exists here for backwards compatibility + * only. You can safely forget about it. + */ #define RUBY_UNTYPED_DATA_FUNC(f) f RBIMPL_ATTRSET_UNTYPED_DATA_FUNC() /* #define RUBY_DATA_FUNC(func) ((void (*)(void*))(func)) */ + +/** + * This is the type of callbacks registered to ::RData. The argument is the + * `data` field. + */ typedef void (*RUBY_DATA_FUNC)(void*); +/** + * @deprecated + * + * Old "untyped" user data. It has roughly the same usage as struct + * ::RTypedData, but lacked several features such as support for compaction GC. + * Use of this struct is not recommended any longer. If it is dead necessary, + * please inform the core devs about your usage. + * + * @internal + * + * @shyouhei tried to add RBIMPL_ATTR_DEPRECATED for this type but that yielded + * too many warnings in the core. Maybe we want to retry later... Just add + * deprecated document for now. + */ struct RData { + + /** Basic part, including flags and class. */ struct RBasic basic; + + /** + * This function is called when the object is experiencing GC marks. If it + * contains references to other Ruby objects, you need to mark them also. + * Otherwise GC will smash your data. + * + * @see rb_gc_mark() + * @warning This is called during GC runs. Object allocations are + * impossible at that moment (that is why GC runs). + */ RUBY_DATA_FUNC dmark; + + /** + * This function is called when the object is no longer used. You need to + * do whatever necessary to avoid memory leaks. + * + * @warning This is called during GC runs. Object allocations are + * impossible at that moment (that is why GC runs). + */ RUBY_DATA_FUNC dfree; + + /** Pointer to the actual C level struct that you want to wrap. */ void *data; }; RBIMPL_SYMBOL_EXPORT_BEGIN() + +/** + * This is the primitive way to wrap an existing C struct into ::RData. + * + * @param[in] klass Ruby level class of the returning object. + * @param[in] datap Pointer to the target C struct. + * @param[in] dmark Mark function. + * @param[in] dfree Free function. + * @exception rb_eTypeError `klass` is not a class. + * @exception rb_eNoMemError Out of memory. + * @return An allocated object that wraps `datap`. + */ VALUE rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree); + +/** + * Identical to rb_data_object_wrap(), except it allocates a new data region + * internally instead of taking an existing one. The allocation is done using + * ruby_calloc(). Hence it makes no sense to pass anything other than + * ::RUBY_DEFAULT_FREE to the last argument. + * + * @param[in] klass Ruby level class of the returning object. + * @param[in] size Requested size of memory to allocate. + * @param[in] dmark Mark function. + * @param[in] dfree Free function. + * @exception rb_eTypeError `klass` is not a class. + * @exception rb_eNoMemError Out of memory. + * @return An allocated object that wraps a new `size` byte region. + */ VALUE rb_data_object_zalloc(VALUE klass, size_t size, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree); + +/** + * @private + * Documented in include/ruby/internal/globals.h + */ RUBY_EXTERN VALUE rb_cObject; RBIMPL_SYMBOL_EXPORT_END() +/** + * Converts sval, a pointer to your struct, into a Ruby object. + * + * @param klass A ruby level class. + * @param mark Mark function. + * @param free Free function. + * @param sval A pointer to your struct. + * @exception rb_eTypeError `klass` is not a class. + * @exception rb_eNoMemError Out of memory. + * @return A created Ruby object. + */ #define Data_Wrap_Struct(klass, mark, free, sval) \ rb_data_object_wrap( \ (klass), \ @@ -84,6 +206,20 @@ RBIMPL_SYMBOL_EXPORT_END() RBIMPL_DATA_FUNC(mark), \ RBIMPL_DATA_FUNC(free)) +/** + * @private + * + * This is an implementation detail of #Data_Make_Struct. People don't use it + * directly. + * + * @param result Variable name of created Ruby object. + * @param klass Ruby level class of the object. + * @param type Type name of the C struct. + * @param size Size of the C struct. + * @param mark Mark function. + * @param free Free function. + * @param sval Variable name of created C struct. + */ #define Data_Make_Struct0(result, klass, type, size, mark, free, sval) \ VALUE result = rb_data_object_zalloc( \ (klass), \ @@ -93,6 +229,21 @@ RBIMPL_SYMBOL_EXPORT_END() (sval) = RBIMPL_CAST((type *)DATA_PTR(result)); \ RBIMPL_CAST(/*suppress unused variable warnings*/(void)(sval)) +/** + * Identical to #Data_Wrap_Struct, except it allocates a new data region + * internally instead of taking an existing one. The allocation is done using + * ruby_calloc(). Hence it makes no sense to pass anything other than + * ::RUBY_DEFAULT_FREE to the `free` argument. + * + * @param klass Ruby level class of the returning object. + * @param type Type name of the C struct. + * @param mark Mark function. + * @param free Free function. + * @param sval Variable name of created C struct. + * @exception rb_eTypeError `klass` is not a class. + * @exception rb_eNoMemError Out of memory. + * @return A created Ruby object. + */ #ifdef HAVE_STMT_AND_DECL_IN_EXPR #define Data_Make_Struct(klass, type, mark, free, sval) \ RB_GNUC_EXTENSION({ \ @@ -116,16 +267,47 @@ RBIMPL_SYMBOL_EXPORT_END() sizeof(type)) #endif +/** + * Obtains a C struct from inside of a wrapper Ruby object. + * + * @param obj An instance of ::RData. + * @param type Type name of the C struct. + * @param sval Variable name of obtained C struct. + * @return Unwrapped C struct that `obj` holds. + */ #define Data_Get_Struct(obj, type, sval) \ ((sval) = RBIMPL_CAST((type*)rb_data_object_get(obj))) RBIMPL_ATTRSET_UNTYPED_DATA_FUNC() +/** + * @private + * + * This is an implementation detail of rb_data_object_wrap(). People don't use + * it directly. + * + * @param[in] klass Ruby level class of the returning object. + * @param[in] ptr Pointer to the target C struct. + * @param[in] mark Mark function. + * @param[in] free Free function. + * @exception rb_eTypeError `klass` is not a class. + * @exception rb_eNoMemError Out of memory. + * @return An allocated object that wraps `datap`. + */ static inline VALUE rb_data_object_wrap_warning(VALUE klass, void *ptr, RUBY_DATA_FUNC mark, RUBY_DATA_FUNC free) { return rb_data_object_wrap(klass, ptr, mark, free); } +/** + * @private + * + * This is an implementation detail of #Data_Get_Struct. People don't use it + * directly. + * + * @param[in] obj An instance of ::RData. + * @return Unwrapped C struct that `obj` holds. + */ static inline void * rb_data_object_get(VALUE obj) { @@ -134,6 +316,15 @@ rb_data_object_get(VALUE obj) } RBIMPL_ATTRSET_UNTYPED_DATA_FUNC() +/** + * @private + * + * This is an implementation detail of #Data_Get_Struct. People don't use it + * directly. + * + * @param[in] obj An instance of ::RData. + * @return Unwrapped C struct that `obj` holds. + */ static inline void * rb_data_object_get_warning(VALUE obj) { @@ -149,6 +340,20 @@ rb_data_object_get_warning(VALUE obj) (rb_data_object_wrap_warning)(klass, ptr, mark, free))) #endif +/** + * This is an implementation detail of #Data_Make_Struct. People don't use it + * directly. + * + * @param[in] klass Ruby level class of the returning object. + * @param[in] mark_func Mark function. + * @param[in] free_func Free function. + * @param[in] datap Variable of created C struct. + * @param[in] size Requested size of allocation. + * @exception rb_eTypeError `klass` is not a class. + * @exception rb_eNoMemError Out of memory. + * @return A created Ruby object. + * @post `*datap` holds the created C struct. + */ static inline VALUE rb_data_object_make(VALUE klass, RUBY_DATA_FUNC mark_func, RUBY_DATA_FUNC free_func, void **datap, size_t size) { @@ -157,21 +362,14 @@ rb_data_object_make(VALUE klass, RUBY_DATA_FUNC mark_func, RUBY_DATA_FUNC free_f } RBIMPL_ATTR_DEPRECATED(("by: rb_data_object_wrap")) +/** @deprecated This function was renamed to rb_data_object_wrap(). */ static inline VALUE rb_data_object_alloc(VALUE klass, void *data, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree) { return rb_data_object_wrap(klass, data, dmark, dfree); } -RBIMPL_ATTR_DEPRECATED(("by: rb_cObject. Will be removed in 3.1.")) -RBIMPL_ATTR_PURE() -static inline VALUE -rb_cData(void) -{ - return rb_cObject; -} -#define rb_cData rb_cData() - +/** @cond INTERNAL_MACRO */ #define rb_data_object_wrap_0 rb_data_object_wrap #define rb_data_object_wrap_1 rb_data_object_wrap_warning #define rb_data_object_wrap_2 rb_data_object_wrap_ /* Used here vvvv */ @@ -184,4 +382,5 @@ rb_cData(void) #define rb_data_object_make_1 rb_data_object_make_warning #define rb_data_object_make_2 rb_data_object_make_ /* Used here vvvv */ #define rb_data_object_make RUBY_MACRO_SELECT(rb_data_object_make_2, RUBY_UNTYPED_DATA_WARNING) +/** @endcond */ #endif /* RBIMPL_RDATA_H */ diff --git a/include/ruby/internal/core/rfile.h b/include/ruby/internal/core/rfile.h index 464625b2bd..a0eb8cb833 100644 --- a/include/ruby/internal/core/rfile.h +++ b/include/ruby/internal/core/rfile.h @@ -17,7 +17,7 @@ * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of - * extension libraries. They could be written in C++98. + * extension libraries. They could be written in C++98. * @brief Defines struct ::RFile. */ #include "ruby/internal/core/rbasic.h" @@ -25,12 +25,27 @@ /* rb_io_t is in ruby/io.h. The header file has historically not been included * into ruby/ruby.h. We follow that tradition. */ -struct rb_io_t; +struct rb_io; +/** + * Ruby's File and IO. Ruby's IO are not just file descriptors. They have + * buffers. They also have encodings. Various information are controlled + * using this struct. + */ struct RFile { + + /** Basic part, including flags and class. */ struct RBasic basic; - struct rb_io_t *fptr; + + /** IO's specific fields. */ + struct rb_io *fptr; }; +/** + * Convenient casting macro. + * + * @param obj An object, which is in fact an ::RFile. + * @return The passed object casted to ::RFile. + */ #define RFILE(obj) RBIMPL_CAST((struct RFile *)(obj)) #endif /* RBIMPL_RFILE_H */ diff --git a/include/ruby/internal/core/rhash.h b/include/ruby/internal/core/rhash.h index cffd0b28ce..897c570794 100644 --- a/include/ruby/internal/core/rhash.h +++ b/include/ruby/internal/core/rhash.h @@ -17,20 +17,9 @@ * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of - * extension libraries. They could be written in C++98. - * @brief Routines to manipulate struct ::RHash. - * - * Shyouhei really suffered agnish over placement of macros in this file. They - * are half-broken. The situation (as of writing) is: - * - * - #RHASH_TBL: works. - * - #RHASH_ITER_LEV: compile-time error. - * - #RHASH_IFNONE: compile-time error. - * - #RHASH_SIZE: works. - * - #RHASH_EMPTY_P: works. - * - #RHASH_SET_IFNONE: works (why... given you cannot query). - * - * Shyouhei stopped thinking. Let them be as is. + * extension libraries. They could be written in C++98. + * @brief Routines to manipulate struct RHash. + * @note The struct RHash itself is opaque. */ #include "ruby/internal/config.h" @@ -44,18 +33,98 @@ # include "ruby/backward.h" #endif +/** + * Retrieves the internal table. + * + * @param[in] h An instance of RHash. + * @pre `h` must be of ::RUBY_T_HASH. + * @return A struct st_table which has the contents of this hash. + * @note Nowadays as Ruby evolved over ages, RHash has multiple backend + * storage engines. `h`'s backend is not guaranteed to be a + * st_table. This function creates one when necessary. + */ #define RHASH_TBL(h) rb_hash_tbl(h, __FILE__, __LINE__) -#define RHASH_ITER_LEV(h) rb_hash_iter_lev(h) + +/** + * @private + * + * @deprecated This macro once was a thing in the old days, but makes no sense + * any longer today. Exists here for backwards compatibility + * only. You can safely forget about it. + * + * @internal + * + * Declaration of rb_hash_ifnone() is at include/ruby/backward.h. + */ #define RHASH_IFNONE(h) rb_hash_ifnone(h) + +/** + * Queries the size of the hash. Size here means the number of keys that the + * hash stores. + * + * @param[in] h An instance of RHash. + * @pre `h` must be of ::RUBY_T_HASH. + * @return The size of the hash. + */ #define RHASH_SIZE(h) rb_hash_size_num(h) + +/** + * Checks if the hash is empty. + * + * @param[in] h An instance of RHash. + * @pre `h` must be of ::RUBY_T_HASH. + * @retval true It is. + * @retval false It isn't. + */ #define RHASH_EMPTY_P(h) (RHASH_SIZE(h) == 0) + +/** + * Destructively updates the default value of the hash. + * + * @param[out] h An instance of RHash. + * @param[in] ifnone Arbitrary default value. + * @pre `h` must be of ::RUBY_T_HASH. + * + * @internal + * + * But why you can set this, given rb_hash_ifnone() doesn't exist? + */ #define RHASH_SET_IFNONE(h, ifnone) rb_hash_set_ifnone((VALUE)h, ifnone) struct st_table; /* in ruby/st.h */ RBIMPL_SYMBOL_EXPORT_BEGIN() + +/** + * This is the implementation detail of #RHASH_SIZE. People don't call this + * directly. + * + * @param[in] hash An instance of RHash. + * @pre `hash` must be of ::RUBY_T_HASH. + * @return The size of the hash. + */ size_t rb_hash_size_num(VALUE hash); -struct st_table *rb_hash_tbl(VALUE, const char *file, int line); + +/** + * This is the implementation detail of #RHASH_TBL. People don't call this + * directly. + * + * @param[in] hash An instance of RHash. + * @param[in] file The `__FILE__`. + * @param[in] line The `__LINE__`. + * @pre `hash` must be of ::RUBY_T_HASH. + * @return Table that has the contents of the hash. + */ +struct st_table *rb_hash_tbl(VALUE hash, const char *file, int line); + +/** + * This is the implementation detail of #RHASH_SET_IFNONE. People don't call + * this directly. + * + * @param[out] hash An instance of RHash. + * @param[in] ifnone Arbitrary default value. + * @pre `hash` must be of ::RUBY_T_HASH. + */ VALUE rb_hash_set_ifnone(VALUE hash, VALUE ifnone); RBIMPL_SYMBOL_EXPORT_END() diff --git a/include/ruby/internal/core/rmatch.h b/include/ruby/internal/core/rmatch.h index 03ab5e5d82..a528c2999e 100644 --- a/include/ruby/internal/core/rmatch.h +++ b/include/ruby/internal/core/rmatch.h @@ -17,18 +17,23 @@ * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of - * extension libraries. They could be written in C++98. + * extension libraries. They could be written in C++98. * @brief Defines struct ::RMatch. */ #include "ruby/internal/attr/artificial.h" #include "ruby/internal/attr/pure.h" -#include "ruby/internal/attr/returns_nonnull.h" #include "ruby/internal/cast.h" #include "ruby/internal/core/rbasic.h" #include "ruby/internal/value.h" #include "ruby/internal/value_type.h" #include "ruby/assert.h" +/** + * Convenient casting macro. + * + * @param obj An object, which is in fact an ::RMatch. + * @return The passed object casted to ::RMatch. + */ #define RMATCH(obj) RBIMPL_CAST((struct RMatch *)(obj)) /** @cond INTERNAL_MACRO */ #define RMATCH_REGS RMATCH_REGS @@ -37,37 +42,103 @@ struct re_patter_buffer; /* a.k.a. OnigRegexType, defined in onigmo.h */ struct re_registers; /* Also in onigmo.h */ -/* @shyouhei wonders: is anyone actively using this typedef ...? */ +/** + * @old{re_pattern_buffer} + * + * @internal + * + * @shyouhei wonders: is anyone actively using this typedef ...? + */ typedef struct re_pattern_buffer Regexp; +/** + * Represents the region of a capture group. This is basically for caching + * purpose. re_registers have similar concepts (`beg` and `end`) but they are + * in `ptrdiff_t*`. In order for us to implement `MatchData#offset` that info + * has to be converted to offset integers. This is the struct to hold such + * things. + * + * @internal + * + * But why on earth it has to be visible from extension libraries? + */ struct rmatch_offset { - long beg; - long end; + long beg; /**< Beginning of a group. */ + long end; /**< End of a group. */ }; -struct rmatch { +/** Represents a match. */ +struct rb_matchext_struct { + /** + * "Registers" of a match. This is a quasi-opaque struct that holds + * execution result of a match. Roughly resembles `&~`. + */ struct re_registers regs; + /** Capture group offsets, in C array. */ struct rmatch_offset *char_offset; + + /** Number of ::rmatch_offset that ::rmatch::char_offset holds. */ int char_offset_num_allocated; }; +typedef struct rb_matchext_struct rb_matchext_t; + +/** + * Regular expression execution context. When a regular expression "matches" + * to a string, it generates capture groups etc. This struct holds that info. + * Visible from Ruby as an instance of `MatchData`. + * + * @note There is no way for extension libraries to manually generate this + * struct except by actually exercising the match operation of a regular + * expression. + */ struct RMatch { + + /** Basic part, including flags and class. */ struct RBasic basic; + + /** + * The target string that the match was made against. + */ VALUE str; - struct rmatch *rmatch; + + /** + * The expression of this match. + */ VALUE regexp; /* RRegexp */ }; +#define RMATCH_EXT(m) ((rb_matchext_t *)((char *)(m) + sizeof(struct RMatch))) + RBIMPL_ATTR_PURE_UNLESS_DEBUG() -RBIMPL_ATTR_RETURNS_NONNULL() RBIMPL_ATTR_ARTIFICIAL() +/** + * Queries the raw ::re_registers. + * + * @param[in] match A match object + * @pre `match` must be of ::RMatch. + * @return Its execution result. + * @note Good. So you are aware of the fact that it could return NULL. + * Yes. It actually does. This is a really bizarre thing. The + * situation is about `String#gsub` and its family. They take + * strings as arguments, like `"foo".sub("bar", "baz")`. On such + * situations, in order to optimise memory allocations, these + * methods do not involve regular expressions at all. They just + * sequentially scan the receiver. Okay. The story begins here. + * Even when they do not kick our regexp engine, there must be + * backref objects e.g. `$&`. But how? You know what? Ruby fakes + * them. It allocates an empty ::RMatch and behaves as if there + * were execution contexts. In reality there weren't. No + * ::re_registers are allocated then. There is no way for this + * function but to return NULL for those fake ::RMatch. This is + * the reason for the nullability of this function. + */ static inline struct re_registers * RMATCH_REGS(VALUE match) { RBIMPL_ASSERT_TYPE(match, RUBY_T_MATCH); - RBIMPL_ASSERT_OR_ASSUME(RMATCH(match)->rmatch != NULL); - return &RMATCH(match)->rmatch->regs; + return &RMATCH_EXT(match)->regs; } #endif /* RBIMPL_RMATCH_H */ diff --git a/include/ruby/internal/core/robject.h b/include/ruby/internal/core/robject.h index c352c87a40..c2bcae6306 100644 --- a/include/ruby/internal/core/robject.h +++ b/include/ruby/internal/core/robject.h @@ -17,7 +17,7 @@ * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of - * extension libraries. They could be written in C++98. + * extension libraries. They could be written in C++98. * @brief Defines struct ::RObject. */ #include "ruby/internal/config.h" @@ -34,50 +34,104 @@ #include "ruby/internal/value.h" #include "ruby/internal/value_type.h" +/** + * Convenient casting macro. + * + * @param obj An object, which is in fact an ::RObject. + * @return The passed object casted to ::RObject. + */ #define ROBJECT(obj) RBIMPL_CAST((struct RObject *)(obj)) +/** @cond INTERNAL_MACRO */ #define ROBJECT_EMBED_LEN_MAX ROBJECT_EMBED_LEN_MAX #define ROBJECT_EMBED ROBJECT_EMBED -/** @cond INTERNAL_MACRO */ -#define ROBJECT_NUMIV ROBJECT_NUMIV +#define ROBJECT_IV_CAPACITY ROBJECT_IV_CAPACITY #define ROBJECT_IVPTR ROBJECT_IVPTR -#define ROBJECT_IV_INDEX_TBL ROBJECT_IV_INDEX_TBL /** @endcond */ -enum ruby_robject_flags { ROBJECT_EMBED = RUBY_FL_USER1 }; - -enum ruby_robject_consts { ROBJECT_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(VALUE) }; +/** + * @private + * + * Bits that you can set to ::RBasic::flags. + */ +enum ruby_robject_flags { + /** + * This flag has something to do with memory footprint. If the object is + * "small" enough, ruby tries to be creative to abuse padding bits of + * struct ::RObject for storing instance variables. This flag denotes that + * situation. + * + * @warning This bit has to be considered read-only. Setting/clearing + * this bit without corresponding fix up must cause immediate + * SEGV. Also, internal structures of an object change + * dynamically and transparently throughout of its lifetime. + * Don't assume it being persistent. + * + * @internal + * + * 3rd parties must not be aware that there even is more than one way to + * store instance variables. Might better be hidden. + */ + ROBJECT_EMBED = RUBY_FL_USER1 +}; struct st_table; +/** + * Ruby's ordinal objects. Unless otherwise special cased, all predefined and + * user-defined classes share this struct to hold their instances. + */ struct RObject { + + /** Basic part, including flags and class. */ struct RBasic basic; + + /** Object's specific fields. */ union { + + /** + * Object that use separated memory region for instance variables use + * this pattern. + */ struct { - uint32_t numiv; + /** Pointer to a C array that holds instance variables. */ VALUE *ivptr; - struct st_table *iv_index_tbl; /* shortcut for RCLASS_IV_INDEX_TBL(rb_obj_class(obj)) */ + + /** + * This is a table that holds instance variable name to index + * mapping. Used when accessing instance variables using names. + * + * @internal + * + * This is a shortcut for `RCLASS_IV_INDEX_TBL(rb_obj_class(obj))`. + */ + struct rb_id_table *iv_index_tbl; } heap; - VALUE ary[ROBJECT_EMBED_LEN_MAX]; + + /* Embedded instance variables. When an object is small enough, it + * uses this area to store the instance variables. + * + * This is a length 1 array because: + * 1. GCC has a bug that does not optimize C flexible array members + * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452) + * 2. Zero length arrays are not supported by all compilers + */ + VALUE ary[1]; } as; }; RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() -static inline uint32_t -ROBJECT_NUMIV(VALUE obj) -{ - RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); - - if (RB_FL_ANY_RAW(obj, ROBJECT_EMBED)) { - return ROBJECT_EMBED_LEN_MAX; - } - else { - return ROBJECT(obj)->as.heap.numiv; - } -} - -RBIMPL_ATTR_PURE_UNLESS_DEBUG() -RBIMPL_ATTR_ARTIFICIAL() +/** + * Queries the instance variables. + * + * @param[in] obj Object in question. + * @return Its instance variables, in C array. + * @pre `obj` must be an instance of ::RObject. + * + * @internal + * + * @shyouhei finds no reason for this to be visible from extension libraries. + */ static inline VALUE * ROBJECT_IVPTR(VALUE obj) { diff --git a/include/ruby/internal/core/rregexp.h b/include/ruby/internal/core/rregexp.h index f289ee1dda..cf54a399f1 100644 --- a/include/ruby/internal/core/rregexp.h +++ b/include/ruby/internal/core/rregexp.h @@ -17,7 +17,7 @@ * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of - * extension libraries. They could be written in C++98. + * extension libraries. They could be written in C++98. * @brief Defines struct ::RRegexp. */ #include "ruby/internal/attr/artificial.h" @@ -28,7 +28,20 @@ #include "ruby/internal/value.h" #include "ruby/internal/value_type.h" +/** + * Convenient casting macro. + * + * @param obj An object, which is in fact an ::RRegexp. + * @return The passed object casted to ::RRegexp. + */ #define RREGEXP(obj) RBIMPL_CAST((struct RRegexp *)(obj)) + +/** + * Convenient accessor macro. + * + * @param obj An object, which is in fact an ::RRegexp. + * @return The passed object's pattern buffer. + */ #define RREGEXP_PTR(obj) (RREGEXP(obj)->ptr) /** @cond INTERNAL_MACRO */ #define RREGEXP_SRC RREGEXP_SRC @@ -37,17 +50,55 @@ #define RREGEXP_SRC_END RREGEXP_SRC_END /** @endcond */ -struct re_patter_buffer; /* a.k.a. OnigRegexType, defined in onigmo.h */ +struct re_patter_buffer; /* a.k.a. OnigRegexType, defined in onigmo.h */ +/** + * Ruby's regular expression. A regexp is compiled into its own intermediate + * representation. This one holds that info. Regexp "match" operation then + * executes that IR. + */ struct RRegexp { + + /** Basic part, including flags and class. */ struct RBasic basic; + + /** + * The pattern buffer. This is a quasi-opaque struct that holds compiled + * intermediate representation of the regular expression. + * + * @note Compilation of a regexp could be delayed until actual match. + */ struct re_pattern_buffer *ptr; + + /** Source code of this expression. */ const VALUE src; + + /** + * Reference count. A regexp match can take extraordinarily long time to + * run. Ruby's regular expression is heavily extended and not a regular + * language any longer; runs in NP-time in practice. Now, Ruby also has + * threads and GVL. In order to prevent long GVL lockup, our regexp engine + * can release it on occasions. This means that multiple threads can touch + * a regular expressions at once. That itself is okay. But their cleanup + * phase shall wait for all the concurrent runs, to prevent use-after-free + * situation. This field is used to count such threads that are executing + * this particular pattern buffer. + * + * @warning Of course, touching this field from extension libraries causes + * catastrophic effects. Just leave it. + */ unsigned long usecnt; }; RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() +/** + * Convenient getter function. + * + * @param[in] rexp The regular expression in question. + * @return The source code of the regular expression. + * @pre `rexp` must be of ::RRegexp. + */ static inline VALUE RREGEXP_SRC(VALUE rexp) { @@ -59,6 +110,17 @@ RREGEXP_SRC(VALUE rexp) RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() +/** + * Convenient getter function. + * + * @param[in] rexp The regular expression in question. + * @return The source code of the regular expression, in C's string. + * @pre `rexp` must be of ::RRegexp. + * + * @internal + * + * It seems nobody uses this function in the wild. Subject to hide? + */ static inline char * RREGEXP_SRC_PTR(VALUE rexp) { @@ -67,6 +129,17 @@ RREGEXP_SRC_PTR(VALUE rexp) RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() +/** + * Convenient getter function. + * + * @param[in] rexp The regular expression in question. + * @return The length of the source code of the regular expression. + * @pre `rexp` must be of ::RRegexp. + * + * @internal + * + * It seems nobody uses this function in the wild. Subject to hide? + */ static inline long RREGEXP_SRC_LEN(VALUE rexp) { @@ -75,6 +148,17 @@ RREGEXP_SRC_LEN(VALUE rexp) RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() +/** + * Convenient getter function. + * + * @param[in] rexp The regular expression in question. + * @return The end of the source code of the regular expression. + * @pre `rexp` must be of ::RRegexp. + * + * @internal + * + * It seems nobody uses this function in the wild. Subject to hide? + */ static inline char * RREGEXP_SRC_END(VALUE rexp) { diff --git a/include/ruby/internal/core/rstring.h b/include/ruby/internal/core/rstring.h index d073da1d2c..0bca74e688 100644 --- a/include/ruby/internal/core/rstring.h +++ b/include/ruby/internal/core/rstring.h @@ -17,7 +17,7 @@ * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of - * extension libraries. They could be written in C++98. + * extension libraries. They could be written in C++98. * @brief Defines struct ::RString. */ #include "ruby/internal/config.h" @@ -32,84 +32,341 @@ #include "ruby/internal/warning_push.h" #include "ruby/assert.h" +/** + * Convenient casting macro. + * + * @param obj An object, which is in fact an ::RString. + * @return The passed object casted to ::RString. + */ #define RSTRING(obj) RBIMPL_CAST((struct RString *)(obj)) -#define RSTRING_NOEMBED RSTRING_NOEMBED -#define RSTRING_EMBED_LEN_MASK RSTRING_EMBED_LEN_MASK -#define RSTRING_EMBED_LEN_SHIFT RSTRING_EMBED_LEN_SHIFT -#define RSTRING_EMBED_LEN_MAX RSTRING_EMBED_LEN_MAX -#define RSTRING_FSTR RSTRING_FSTR /** @cond INTERNAL_MACRO */ -#define RSTRING_EMBED_LEN RSTRING_EMBED_LEN +#define RSTRING_NOEMBED RSTRING_NOEMBED +#define RSTRING_FSTR RSTRING_FSTR #define RSTRING_LEN RSTRING_LEN #define RSTRING_LENINT RSTRING_LENINT #define RSTRING_PTR RSTRING_PTR #define RSTRING_END RSTRING_END /** @endcond */ +/** + * @name Conversion of Ruby strings into C's + * + * @{ + */ + +/** + * Ensures that the parameter object is a String. This is done by calling its + * `to_str` method. + * + * @param[in,out] v Arbitrary Ruby object. + * @exception rb_eTypeError No implicit conversion defined. + * @post `v` is a String. + */ #define StringValue(v) rb_string_value(&(v)) + +/** + * Identical to #StringValue, except it returns a `char*`. + * + * @param[in,out] v Arbitrary Ruby object. + * @exception rb_eTypeError No implicit conversion defined. + * @return Converted Ruby string's backend C string. + * @post `v` is a String. + */ #define StringValuePtr(v) rb_string_value_ptr(&(v)) + +/** + * Identical to #StringValuePtr, except it additionally checks for the contents + * for viability as a C string. Ruby can accept wider range of contents as + * strings, compared to C. This function is to check that. + * + * @param[in,out] v Arbitrary Ruby object. + * @exception rb_eTypeError No implicit conversion defined. + * @exception rb_eArgError String is not C-compatible. + * @return Converted Ruby string's backend C string. + * @post `v` is a String. + */ #define StringValueCStr(v) rb_string_value_cstr(&(v)) + +/** + * @private + * + * @deprecated This macro once was a thing in the old days, but makes no sense + * any longer today. Exists here for backwards compatibility + * only. You can safely forget about it. + */ #define SafeStringValue(v) StringValue(v) + +/** + * Identical to #StringValue, except it additionally converts the string's + * encoding to default external encoding. Ruby has a concept called encodings. + * A string can have different encoding than the environment expects. Someone + * has to make sure its contents be converted to something suitable. This is + * that routine. Call it when necessary. + * + * @param[in,out] v Arbitrary Ruby object. + * @exception rb_eTypeError No implicit conversion defined. + * @return Converted Ruby string's backend C string. + * @post `v` is a String. + * + * @internal + * + * Not sure but it seems this macro does not raise on encoding + * incompatibilities? Doesn't sound right to @shyouhei. + */ #define ExportStringValue(v) do { \ StringValue(v); \ (v) = rb_str_export(v); \ } while (0) +/** @} */ + +/** + * @private + * + * Bits that you can set to ::RBasic::flags. + * + * @warning These enums are not the only bits we use for strings. + * + * @internal + * + * Actually all bits through FL_USER1 to FL_USER19 are used for strings. Why + * only this tiny part of them are made public here? @shyouhei can find no + * reason. + */ enum ruby_rstring_flags { + + /** + * This flag has something to do with memory footprint. If the string is + * short enough, ruby tries to be creative to abuse padding bits of struct + * ::RString for storing contents. If this flag is set that string does + * _not_ do that, to resort to good old fashioned external allocation + * strategy instead. + * + * @warning This bit has to be considered read-only. Setting/clearing + * this bit without corresponding fix up must cause immediate + * SEGV. Also, internal structures of a string change + * dynamically and transparently throughout of its lifetime. + * Don't assume it being persistent. + * + * @internal + * + * 3rd parties must not be aware that there even is more than one way to + * store a string. Might better be hidden. + */ RSTRING_NOEMBED = RUBY_FL_USER1, - RSTRING_EMBED_LEN_MASK = RUBY_FL_USER2 | RUBY_FL_USER3 | RUBY_FL_USER4 | - RUBY_FL_USER5 | RUBY_FL_USER6, + /* Actually, string encodings are also encoded into the flags, using * remaining bits.*/ - RSTRING_FSTR = RUBY_FL_USER17 -}; -enum ruby_rstring_consts { - RSTRING_EMBED_LEN_SHIFT = RUBY_FL_USHIFT + 2, - RSTRING_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(char) - 1 + /** + * This flag has something to do with infamous "f"string. What is a + * fstring? Well it is a special subkind of strings that is immutable, + * deduped globally, and managed by our GC. It is much like a Symbol (in + * fact Symbols are dynamic these days and are backended using fstrings). + * This concept has been silently introduced at some point in 2.x era. + * Since then it gained wider acceptance in the core. But extension + * libraries could not know that until very recently. Strings of this flag + * live in a special Limbo deep inside of the interpreter. Never try to + * manipulate it by hand. + * + * @internal + * + * Fstrings are not the only variant strings that we implement today. + * Other things are behind-the-scene. This is the only one that is visible + * from extension library. There is no clear reason why it has to be. + * Given there are more "polite" ways to create fstrings, it seems this bit + * need not be exposed to extension libraries. Might better be hidden. + */ + RSTRING_FSTR = RUBY_FL_USER17 }; +/** + * Ruby's String. A string in ruby conceptually has these information: + * + * - Encoding of the string. + * - Length of the string. + * - Contents of the string. + * + * It is worth noting that a string is _not_ an array of characters in ruby. + * It has never been. In 1.x a string was an array of integers. Since 2.x a + * string is no longer an array of anything. A string is a string -- just like + * a Time is not an integer. + */ struct RString { + + /** Basic part, including flags and class. */ struct RBasic basic; + + /** + * Length of the string, not including terminating NUL character. + * + * @note This is in bytes. + */ + long len; + + /** String's specific fields. */ union { + + /** + * Strings that use separated memory region for contents use this + * pattern. + */ struct { - long len; + /** + * Pointer to the contents of the string. In the old days each + * string had dedicated memory regions. That is no longer true + * today, but there still are strings of such properties. This + * field could be used to point such things. + */ char *ptr; + + /** Auxiliary info. */ union { + + /** + * Capacity of `*ptr`. A continuous memory region of at least + * `capa` bytes is expected to exist at `*ptr`. This can be + * bigger than `len`. + */ long capa; + + /** + * Parent of the string. Nowadays strings can share their + * contents each other, constructing gigantic nest of objects. + * This situation is called "shared", and this is the field to + * control such properties. + */ VALUE shared; } aux; } heap; - char ary[RSTRING_EMBED_LEN_MAX + 1]; + + /** Embedded contents. */ + struct { + /* This is a length 1 array because: + * 1. GCC has a bug that does not optimize C flexible array members + * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452) + * 2. Zero length arrays are not supported by all compilers + */ + char ary[1]; + } embed; } as; }; RBIMPL_SYMBOL_EXPORT_BEGIN() -VALUE rb_str_to_str(VALUE); -VALUE rb_string_value(volatile VALUE*); -char *rb_string_value_ptr(volatile VALUE*); -char *rb_string_value_cstr(volatile VALUE*); -VALUE rb_str_export(VALUE); -VALUE rb_str_export_locale(VALUE); +/** + * Identical to rb_check_string_type(), except it raises exceptions in case of + * conversion failures. + * + * @param[in] obj Target object. + * @exception rb_eTypeError No implicit conversion to String. + * @return Return value of `obj.to_str`. + * @see rb_io_get_io + * @see rb_ary_to_ary + */ +VALUE rb_str_to_str(VALUE obj); + +/** + * Identical to rb_str_to_str(), except it fills the passed pointer with the + * converted object. + * + * @param[in,out] ptr Pointer to a variable of target object. + * @exception rb_eTypeError No implicit conversion to String. + * @return Return value of `obj.to_str`. + * @post `*ptr` is the return value. + */ +VALUE rb_string_value(volatile VALUE *ptr); + +/** + * Identical to rb_str_to_str(), except it returns the converted string's + * backend memory region. + * + * @param[in,out] ptr Pointer to a variable of target object. + * @exception rb_eTypeError No implicit conversion to String. + * @post `*ptr` is the return value of `obj.to_str`. + * @return Pointer to the contents of the return value. + */ +char *rb_string_value_ptr(volatile VALUE *ptr); + +/** + * Identical to rb_string_value_ptr(), except it additionally checks for the + * contents for viability as a C string. Ruby can accept wider range of + * contents as strings, compared to C. This function is to check that. + * + * @param[in,out] ptr Pointer to a variable of target object. + * @exception rb_eTypeError No implicit conversion to String. + * @exception rb_eArgError String is not C-compatible. + * @post `*ptr` is the return value of `obj.to_str`. + * @return Pointer to the contents of the return value. + */ +char *rb_string_value_cstr(volatile VALUE *ptr); + +/** + * Identical to rb_str_to_str(), except it additionally converts the string + * into default external encoding. Ruby has a concept called encodings. A + * string can have different encoding than the environment expects. Someone + * has to make sure its contents be converted to something suitable. This is + * that routine. Call it when necessary. + * + * @param[in] obj Target object. + * @exception rb_eTypeError No implicit conversion to String. + * @return Converted ruby string of default external encoding. + */ +VALUE rb_str_export(VALUE obj); + +/** + * Identical to rb_str_export(), except it converts into the locale encoding + * instead. + * + * @param[in] obj Target object. + * @exception rb_eTypeError No implicit conversion to String. + * @return Converted ruby string of locale encoding. + */ +VALUE rb_str_export_locale(VALUE obj); RBIMPL_ATTR_ERROR(("rb_check_safe_str() and Check_SafeStr() are obsolete; use StringValue() instead")) +/** + * @private + * + * @deprecated This function once was a thing in the old days, but makes no + * sense any longer today. Exists here for backwards + * compatibility only. You can safely forget about it. + */ void rb_check_safe_str(VALUE); + +/** + * @private + * + * @deprecated This macro once was a thing in the old days, but makes no sense + * any longer today. Exists here for backwards compatibility + * only. You can safely forget about it. + */ #define Check_SafeStr(v) rb_check_safe_str(RBIMPL_CAST((VALUE)(v))) + +/** + * @private + * + * Prints diagnostic message to stderr when RSTRING_PTR or RSTRING_END + * is NULL. + * + * @param[in] func The function name where encountered NULL pointer. + */ +void rb_debug_rstring_null_ptr(const char *func); RBIMPL_SYMBOL_EXPORT_END() RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() +/** + * Queries the length of the string. + * + * @param[in] str String in question. + * @return Its length, in bytes. + * @pre `str` must be an instance of ::RString. + */ static inline long -RSTRING_EMBED_LEN(VALUE str) +RSTRING_LEN(VALUE str) { - RBIMPL_ASSERT_TYPE(str, RUBY_T_STRING); - RBIMPL_ASSERT_OR_ASSUME(! RB_FL_ANY_RAW(str, RSTRING_NOEMBED)); - - VALUE f = RBASIC(str)->flags; - f &= RSTRING_EMBED_LEN_MASK; - f >>= RSTRING_EMBED_LEN_SHIFT; - return RBIMPL_CAST((long)f); + return RSTRING(str)->len; } RBIMPL_WARNING_PUSH() @@ -119,6 +376,15 @@ RBIMPL_WARNING_IGNORED(413) RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() +/** + * @private + * + * "Expands" an embedded string into an ordinal one. This is a function that + * returns aggregated type. The returned struct always has its `as.heap.len` + * an `as.heap.ptr` fields set appropriately. + * + * This is an implementation detail that 3rd parties should never bother. + */ static inline struct RString rbimpl_rstring_getmem(VALUE str) { @@ -130,82 +396,93 @@ rbimpl_rstring_getmem(VALUE str) else { /* Expecting compilers to optimize this on-stack struct away. */ struct RString retval; - retval.as.heap.len = RSTRING_EMBED_LEN(str); - retval.as.heap.ptr = RSTRING(str)->as.ary; + retval.len = RSTRING_LEN(str); + retval.as.heap.ptr = RSTRING(str)->as.embed.ary; return retval; } } RBIMPL_WARNING_POP() -RBIMPL_ATTR_PURE_UNLESS_DEBUG() -RBIMPL_ATTR_ARTIFICIAL() -static inline long -RSTRING_LEN(VALUE str) -{ - return rbimpl_rstring_getmem(str).as.heap.len; -} - RBIMPL_ATTR_ARTIFICIAL() +/** + * Queries the contents pointer of the string. + * + * @param[in] str String in question. + * @return Pointer to its contents. + * @pre `str` must be an instance of ::RString. + */ static inline char * RSTRING_PTR(VALUE str) { char *ptr = rbimpl_rstring_getmem(str).as.heap.ptr; - if (RB_UNLIKELY(! ptr)) { + if (RUBY_DEBUG && RB_UNLIKELY(! ptr)) { /* :BEWARE: @shyouhei thinks that currently, there are rooms for this - * function to return NULL. In the 20th century that was a pointless - * concern. However struct RString can hold fake strings nowadays. It - * seems no check against NULL are exercised around handling of them - * (one of such usages is located in marshal.c, which scares - * @shyouhei). Better check here for maximum safety. + * function to return NULL. Better check here for maximum safety. * * Also, this is not rb_warn() because RSTRING_PTR() can be called * during GC (see what obj_info() does). rb_warn() needs to allocate * Ruby objects. That is not possible at this moment. */ - fprintf(stderr, "%s\n", - "RSTRING_PTR is returning NULL!! " - "SIGSEGV is highly expected to follow immediately. " - "If you could reproduce, attach your debugger here, " - "and look at the passed string." - ); + rb_debug_rstring_null_ptr("RSTRING_PTR"); } return ptr; } RBIMPL_ATTR_ARTIFICIAL() +/** + * Queries the end of the contents pointer of the string. + * + * @param[in] str String in question. + * @return Pointer to its end of contents. + * @pre `str` must be an instance of ::RString. + */ static inline char * RSTRING_END(VALUE str) { struct RString buf = rbimpl_rstring_getmem(str); - if (RB_UNLIKELY(! buf.as.heap.ptr)) { + if (RUBY_DEBUG && RB_UNLIKELY(! buf.as.heap.ptr)) { /* Ditto. */ - fprintf(stderr, "%s\n", - "RSTRING_END is returning NULL!! " - "SIGSEGV is highly expected to follow immediately. " - "If you could reproduce, attach your debugger here, " - "and look at the passed string." - ); + rb_debug_rstring_null_ptr("RSTRING_END"); } - return &buf.as.heap.ptr[buf.as.heap.len]; + return &buf.as.heap.ptr[buf.len]; } RBIMPL_ATTR_ARTIFICIAL() +/** + * Identical to RSTRING_LEN(), except it differs for the return type. + * + * @param[in] str String in question. + * @exception rb_eRangeError Too long. + * @return Its length, in bytes. + * @pre `str` must be an instance of ::RString. + * + * @internal + * + * This API seems redundant but has actual usages. + */ static inline int RSTRING_LENINT(VALUE str) { return rb_long2int(RSTRING_LEN(str)); } +/** + * Convenient macro to obtain the contents and length at once. + * + * @param str String in question. + * @param ptrvar Variable where its contents is stored. + * @param lenvar Variable where its length is stored. + */ #ifdef HAVE_STMT_AND_DECL_IN_EXPR # define RSTRING_GETMEM(str, ptrvar, lenvar) \ __extension__ ({ \ struct RString rbimpl_str = rbimpl_rstring_getmem(str); \ (ptrvar) = rbimpl_str.as.heap.ptr; \ - (lenvar) = rbimpl_str.as.heap.len; \ + (lenvar) = rbimpl_str.len; \ }) #else # define RSTRING_GETMEM(str, ptrvar, lenvar) \ diff --git a/include/ruby/internal/core/rstruct.h b/include/ruby/internal/core/rstruct.h index 17454f7cbe..69be487b59 100644 --- a/include/ruby/internal/core/rstruct.h +++ b/include/ruby/internal/core/rstruct.h @@ -17,8 +17,9 @@ * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of - * extension libraries. They could be written in C++98. - * @brief Routines to manipulate struct ::RStruct. + * extension libraries. They could be written in C++98. + * @brief Routines to manipulate struct RStruct. + * @note The struct RStruct itself is opaque. */ #include "ruby/internal/attr/artificial.h" #include "ruby/internal/dllexport.h" @@ -30,6 +31,17 @@ # include "ruby/backward.h" #endif +/** + * @private + * + * @deprecated This macro once was a thing in the old days, but makes no sense + * any longer today. Exists here for backwards compatibility + * only. You can safely forget about it. + * + * @internal + * + * Declaration of rb_struct_ptr() is at include/ruby/backward.h. + */ #define RSTRUCT_PTR(st) rb_struct_ptr(st) /** @cond INTERNAL_MACRO */ #define RSTRUCT_LEN RSTRUCT_LEN @@ -38,12 +50,46 @@ /** @endcond */ RBIMPL_SYMBOL_EXPORT_BEGIN() -VALUE rb_struct_size(VALUE s); -VALUE rb_struct_aref(VALUE, VALUE); -VALUE rb_struct_aset(VALUE, VALUE, VALUE); +/** + * Returns the number of struct members. + * + * @param[in] st An instance of RStruct. + * @return The number of members of `st`. + * @pre `st` must be of ::RUBY_T_STRUCT. + */ +VALUE rb_struct_size(VALUE st); + +/** + * Resembles `Struct#[]`. + * + * @param[in] st An instance of RStruct. + * @param[in] k Index a.k.a. key of the struct. + * @exception rb_eTypeError `k` is neither Numeric, Symbol, nor String. + * @exception rb_eIndexError Numerical index out of range. + * @exception rb_eNameError No such key. + * @return The member stored at `k` in `st`. + * @pre `st` must be of ::RUBY_T_STRUCT. + */ +VALUE rb_struct_aref(VALUE st, VALUE k); + +/** + * Resembles `Struct#[]=`. + * + * @param[out] st An instance of RStruct. + * @param[in] k Index a.k.a. key of the struct. + * @param[in] v Value to store. + * @exception rb_eTypeError `k` is neither Numeric, Symbol, nor String. + * @exception rb_eIndexError Numerical index out of range. + * @exception rb_eNameError No such key. + * @return Passed `v`. + * @pre `st` must be of ::RUBY_T_STRUCT. + * @post `v` is stored at `k` in `st`. + */ +VALUE rb_struct_aset(VALUE st, VALUE k, VALUE v); RBIMPL_SYMBOL_EXPORT_END() RBIMPL_ATTR_ARTIFICIAL() +/** @copydoc rb_struct_size() */ static inline long RSTRUCT_LEN(VALUE st) { @@ -53,6 +99,7 @@ RSTRUCT_LEN(VALUE st) } RBIMPL_ATTR_ARTIFICIAL() +/** @copydoc rb_struct_aset() */ static inline VALUE RSTRUCT_SET(VALUE st, int k, VALUE v) { @@ -62,6 +109,7 @@ RSTRUCT_SET(VALUE st, int k, VALUE v) } RBIMPL_ATTR_ARTIFICIAL() +/** @copydoc rb_struct_aref() */ static inline VALUE RSTRUCT_GET(VALUE st, int k) { diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h index c038e6f2b8..6c19576c20 100644 --- a/include/ruby/internal/core/rtypeddata.h +++ b/include/ruby/internal/core/rtypeddata.h @@ -17,7 +17,7 @@ * recursively included from extension libraries written in C++. * Do not expect for instance `__VA_ARGS__` is always available. * We assume C99 for ruby itself but we don't assume languages of - * extension libraries. They could be written in C++98. + * extension libraries. They could be written in C++98. * @brief Defines struct ::RTypedData. */ #include "ruby/internal/config.h" @@ -28,6 +28,8 @@ #include "ruby/internal/assume.h" #include "ruby/internal/attr/artificial.h" +#include "ruby/internal/attr/flag_enum.h" +#include "ruby/internal/attr/nonnull.h" #include "ruby/internal/attr/pure.h" #include "ruby/internal/cast.h" #include "ruby/internal/core/rbasic.h" @@ -38,13 +40,68 @@ #include "ruby/internal/stdbool.h" #include "ruby/internal/value_type.h" +/** + * @private + * + * @deprecated This macro once was a thing in the old days, but makes no sense + * any longer today. Exists here for backwards compatibility + * only. You can safely forget about it. + */ #define HAVE_TYPE_RB_DATA_TYPE_T 1 + +/** + * @private + * + * @deprecated This macro once was a thing in the old days, but makes no sense + * any longer today. Exists here for backwards compatibility + * only. You can safely forget about it. + */ #define HAVE_RB_DATA_TYPE_T_FUNCTION 1 + +/** + * @private + * + * @deprecated This macro once was a thing in the old days, but makes no sense + * any longer today. Exists here for backwards compatibility + * only. You can safely forget about it. + */ #define HAVE_RB_DATA_TYPE_T_PARENT 1 + +/** + * This is a value you can set to ::rb_data_type_struct::dfree. Setting this + * means the data was allocated using ::ruby_xmalloc() (or variants), and shall + * be freed using ::ruby_xfree(). + * + * @warning Do not use this if you want to use system malloc, because the + * system and Ruby might or might not share the same malloc + * implementation. + */ #define RUBY_TYPED_DEFAULT_FREE RUBY_DEFAULT_FREE + +/** + * This is a value you can set to ::rb_data_type_struct::dfree. Setting this + * means the data is managed by someone else, like, statically allocated. Of + * course you are on your own then. + */ #define RUBY_TYPED_NEVER_FREE RUBY_NEVER_FREE + +/** + * Convenient casting macro. + * + * @param obj An object, which is in fact an ::RTypedData. + * @return The passed object casted to ::RTypedData. + */ #define RTYPEDDATA(obj) RBIMPL_CAST((struct RTypedData *)(obj)) + +/** + * Convenient getter macro. + * + * @param v An object, which is in fact an ::RTypedData. + * @return The passed object's ::RTypedData::data field. + */ #define RTYPEDDATA_DATA(v) (RTYPEDDATA(v)->data) + +/** @old{rb_check_typeddata} */ #define Check_TypedStruct(v, t) \ rb_check_typeddata(RBIMPL_CAST((VALUE)(v)), (t)) @@ -57,55 +114,373 @@ #define RUBY_TYPED_PROMOTED1 RUBY_TYPED_PROMOTED1 /** @endcond */ -/* bits for rb_data_type_struct::flags */ -enum rbimpl_typeddata_flags { +#define TYPED_DATA_EMBEDDED 2 + +/** + * @private + * + * Bits for rb_data_type_struct::flags. + */ +enum +RBIMPL_ATTR_FLAG_ENUM() +rbimpl_typeddata_flags { + /** + * This flag has something to do with Ruby's global interpreter lock. For + * maximum safety, Ruby locks the entire VM during GC. However your + * callback functions could unintentionally unlock it, for instance when + * they try to flush an IO buffer. Such operations are dangerous (threads + * then run alongside of GC). By default, to prevent those scenario, + * callbacks are deferred until the GC engine is 100% sure threads can run. + * This flag skips that; structs with it are deallocated during the sweep + * phase. + * + * Using this flag needs deep understanding of both GC and threads. You + * would better leave it unspecified. + */ RUBY_TYPED_FREE_IMMEDIATELY = 1, + + RUBY_TYPED_EMBEDDABLE = 2, + + /** + * This flag has something to do with Ractor. Multiple Ractors run without + * protecting each other. Sharing an object among Ractors is basically + * dangerous, disabled by default. This flag is used to bypass that + * restriction. but setting it is not enough. In addition to do so, an + * object also has to be frozen, and be passed to + * rb_ractor_make_shareable() before being actually shareable. Of course, + * you have to manually prevent race conditions then. + * + * Using this flag needs deep understanding of multithreaded programming. + * You would better leave it unspecified. + */ RUBY_TYPED_FROZEN_SHAREABLE = RUBY_FL_SHAREABLE, + + /** + * This flag has something to do with our garbage collector. These days + * ruby objects are "generational". There are those who are young and + * those who are old. Young objects are prone to die; monitored relatively + * extensively by the garbage collector. OTOH old objects tend to live + * longer. They are relatively rarely considered. This basically works. + * But there is one tweak that has to be exercised. When an elder object + * has reference(s) to younger one(s), that referenced objects must not + * die. In order to detect additions of such references, old generations + * are protected by write barriers. It is a very difficult hack to + * appropriately insert write barriers everywhere. This mechanism is + * disabled by default for 3rd party extensions (they never get aged). By + * specifying this flag you can enable the generational feature to your + * data structure. Of course, you have to manually insert write barriers + * then. + * + * Using this flag needs deep understanding of GC internals, often at the + * level of source code. You would better leave it unspecified. + */ RUBY_TYPED_WB_PROTECTED = RUBY_FL_WB_PROTECTED, /* THIS FLAG DEPENDS ON Ruby version */ - RUBY_TYPED_PROMOTED1 = RUBY_FL_PROMOTED1 /* THIS FLAG DEPENDS ON Ruby version */ + + /** + * This flag no longer in use + */ + RUBY_TYPED_UNUSED = RUBY_FL_UNUSED6, + + /** + * This flag determines whether marking and compaction should be carried out + * using the dmark/dcompact callback functions or whether we should mark + * declaratively using a list of references defined inside the data struct we're wrapping + */ + RUBY_TYPED_DECL_MARKING = RUBY_FL_USER2 }; +/** + * This is the struct that holds necessary info for a struct. It roughly + * resembles a Ruby level class; multiple objects can share a ::rb_data_type_t + * instance. + */ typedef struct rb_data_type_struct rb_data_type_t; +/** @copydoc rb_data_type_t */ struct rb_data_type_struct { + + /** + * Name of structs of this kind. This is used for diagnostic purposes. + * This has to be unique in the process, but doesn't has to be a valid + * C/Ruby identifier. + */ const char *wrap_struct_name; + + /** Function pointers. Resembles C++ `vtbl`.*/ struct { + + /** + * This function is called when the object is experiencing GC marks. + * If it contains references to other Ruby objects, you need to mark + * them also. Otherwise GC will smash your data. + * + * @see rb_gc_mark() + * @warning This is called during GC runs. Object allocations are + * impossible at that moment (that is why GC runs). + */ RUBY_DATA_FUNC dmark; + + /** + * This function is called when the object is no longer used. You need + * to do whatever necessary to avoid memory leaks. + * + * @warning This is called during GC runs. Object allocations are + * impossible at that moment (that is why GC runs). + */ RUBY_DATA_FUNC dfree; + + /** + * This function is to query the size of the underlying memory regions. + * + * @internal + * + * This function has only one usage, which is form inside of + * `ext/objspace`. + */ size_t (*dsize)(const void *); + + /** + * This function is called when the object is relocated. Like + * ::rb_data_type_struct::dmark, you need to update references to Ruby + * objects inside of your structs. + * + * @see rb_gc_location() + * @warning This is called during GC runs. Object allocations are + * impossible at that moment (that is why GC runs). + */ RUBY_DATA_FUNC dcompact; + + /** + * This field is reserved for future extension. For now, it must be + * filled with zeros. + */ void *reserved[1]; /* For future extension. This array *must* be filled with ZERO. */ } function; + + /** + * Parent of this class. Sometimes C structs have inheritance-like + * relationships. An example is `struct sockaddr` and its family. If you + * design such things, make ::rb_data_type_t for each of them and connect + * using this field. Ruby can then transparently cast your data back and + * forth when you call #TypedData_Get_Struct(). + * + * ```CXX + * struct parent { }; + * static inline const rb_data_type_t parent_type = { + * .wrap_struct_name = "parent", + * }; + * + * struct child: public parent { }; + * static inline const rb_data_type_t child_type = { + * .wrap_struct_name = "child", + * .parent = &parent_type, + * }; + * + * // This function can take both parent_class and child_class. + * static inline struct parent * + * get_parent(VALUE v) + * { + * struct parent *p; + * TypedData_Get_Struct(v, parent_type, struct parent, p); + * return p; + * } + * ``` + */ const rb_data_type_t *parent; + + /** + * Type-specific static data. This area can be used for any purpose by a + * programmer who define the type. Ruby does not manage this at all. + */ void *data; /* This area can be used for any purpose by a programmer who define the type. */ + + /** + * Type-specific behavioural characteristics. This is a bitfield. It is + * an EXTREMELY WISE IDEA to leave this field blank. It is designed so + * that setting zero is the safest thing to do. If you risk to set any + * bits on, you have to know exactly what you are doing. + * + * @internal + * + * Why it has to be a ::VALUE? @shyouhei doesn't understand the design. + */ VALUE flags; /* RUBY_FL_WB_PROTECTED */ }; +/** + * "Typed" user data. By using this, extension libraries can wrap a C struct + * to make it visible from Ruby. For instance if you have a `struct timeval`, + * and you want users to use it, + * + * ```CXX + * static inline const rb_data_type_t timeval_type = { + * // Note that unspecified fields are 0-filled by default. + * .wrap_struct_name = "timeval", + * .function = { + * .dmark = nullptr, // no need to mark + * .dfree = RUBY_TYPED_DEFAULT_FREE, // use ruby_xfree() + * .dsize = [](auto) { + * return sizeof(struct timeval); + * }, + * }, + * }; + * + * extern "C" void + * Init_timeval(void) + * { + * auto klass = rb_define_class("YourName", rb_cObject); + * + * rb_define_alloc_func(klass, [](auto klass) { + * struct timeval *t; + * auto ret = TypedData_Make_Struct( + * klass, struct timeval, &timeval_type, t); + * + * if (auto i = gettimeofday(t, nullptr); i == -1) { + * rb_sys_fail("gettimeofday(3)"); + * } + * else { + * return ret; + * } + * }); + * } + * ``` + */ struct RTypedData { + + /** The part that all ruby objects have in common. */ struct RBasic basic; - const rb_data_type_t *type; - VALUE typed_flag; /* 1 or not */ + + /** + * This field stores various information about how Ruby should handle a + * data. This roughly resembles a Ruby level class (apart from method + * definition etc.) + */ + const rb_data_type_t *const type; + + /** + * This has to be always 1. + * + * @internal + */ + const VALUE typed_flag; + + /** Pointer to the actual C level struct that you want to wrap. */ void *data; }; RBIMPL_SYMBOL_EXPORT_BEGIN() -VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *); +RBIMPL_ATTR_NONNULL((3)) +/** + * This is the primitive way to wrap an existing C struct into ::RTypedData. + * + * @param[in] klass Ruby level class of the returning object. + * @param[in] datap Pointer to the target C struct. + * @param[in] type The characteristics of the passed data. + * @exception rb_eTypeError `klass` is not a class. + * @exception rb_eNoMemError Out of memory. + * @return An allocated object that wraps `datap`. + */ +VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type); + +/** + * Identical to rb_data_typed_object_wrap(), except it allocates a new data + * region internally instead of taking an existing one. The allocation is done + * using ruby_calloc(). Hence it makes no sense for `type->function.dfree` to + * be anything other than ::RUBY_TYPED_DEFAULT_FREE. + * + * @param[in] klass Ruby level class of the returning object. + * @param[in] size Requested size of memory to allocate. + * @param[in] type The characteristics of the passed data. + * @exception rb_eTypeError `klass` is not a class. + * @exception rb_eNoMemError Out of memory. + * @return An allocated object that wraps a new `size` byte region. + */ VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type); + +/** + * Checks for the domestic relationship between the two. + * + * @param[in] child A data type supposed to be a child of `parent`. + * @param[in] parent A data type supposed to be a parent of `child`. + * @retval true `child` is a descendent of `parent`. + * @retval false Otherwise. + * + * @internal + * + * You can path NULL to both arguments, don't know what that means though. + */ int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *parent); + +/** + * Checks if the given object is of given kind. + * + * @param[in] obj An instance of ::RTypedData. + * @param[in] data_type Expected data type of `obj`. + * @retval true `obj` is of `data_type`. + * @retval false Otherwise. + */ int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type); + +/** + * Identical to rb_typeddata_is_kind_of(), except it raises exceptions instead + * of returning false. + * + * @param[in] obj An instance of ::RTypedData. + * @param[in] data_type Expected data type of `obj`. + * @exception rb_eTypeError obj is not of `data_type`. + * @return Unwrapped C struct that `obj` holds. + * @post Upon successful return `obj`'s type is guaranteed `data_type`. + */ void *rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type); RBIMPL_SYMBOL_EXPORT_END() +/** + * Converts sval, a pointer to your struct, into a Ruby object. + * + * @param klass A ruby level class. + * @param data_type The type of `sval`. + * @param sval A pointer to your struct. + * @exception rb_eTypeError `klass` is not a class. + * @exception rb_eNoMemError Out of memory. + * @return A created Ruby object. + */ #define TypedData_Wrap_Struct(klass,data_type,sval)\ rb_data_typed_object_wrap((klass),(sval),(data_type)) +/** + * @private + * + * This is an implementation detail of #TypedData_Make_Struct. People don't + * use it directly. + * + * @param result Variable name of created Ruby object. + * @param klass Ruby level class of the object. + * @param type Type name of the C struct. + * @param size Size of the C struct. + * @param data_type The data type describing `type`. + * @param sval Variable name of created C struct. + */ #define TypedData_Make_Struct0(result, klass, type, size, data_type, sval) \ VALUE result = rb_data_typed_object_zalloc(klass, size, data_type); \ - (sval) = RBIMPL_CAST((type *)RTYPEDDATA_DATA(result)); \ + (sval) = (type *)RTYPEDDATA_GET_DATA(result); \ RBIMPL_CAST(/*suppress unused variable warnings*/(void)(sval)) +/** + * Identical to #TypedData_Wrap_Struct, except it allocates a new data region + * internally instead of taking an existing one. The allocation is done using + * ruby_calloc(). Hence it makes no sense for `data_type->function.dfree` to + * be anything other than ::RUBY_TYPED_DEFAULT_FREE. + * + * @param klass Ruby level class of the object. + * @param type Type name of the C struct. + * @param data_type The data type describing `type`. + * @param sval Variable name of created C struct. + * @exception rb_eTypeError `klass` is not a class. + * @exception rb_eNoMemError Out of memory. + * @return A created Ruby object. + */ #ifdef HAVE_STMT_AND_DECL_IN_EXPR #define TypedData_Make_Struct(klass, type, data_type, sval) \ RB_GNUC_EXTENSION({ \ @@ -127,19 +502,79 @@ RBIMPL_SYMBOL_EXPORT_END() sizeof(type)) #endif +/** + * Obtains a C struct from inside of a wrapper Ruby object. + * + * @param obj An instance of ::RTypedData. + * @param type Type name of the C struct. + * @param data_type The data type describing `type`. + * @param sval Variable name of obtained C struct. + * @exception rb_eTypeError `obj` is not a kind of `data_type`. + * @return Unwrapped C struct that `obj` holds. + */ #define TypedData_Get_Struct(obj,type,data_type,sval) \ ((sval) = RBIMPL_CAST((type *)rb_check_typeddata((obj), (data_type)))) +static inline bool +RTYPEDDATA_EMBEDDED_P(VALUE obj) +{ +#if RUBY_DEBUG + if (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) { + Check_Type(obj, RUBY_T_DATA); + RBIMPL_UNREACHABLE_RETURN(false); + } +#endif + + return RTYPEDDATA(obj)->typed_flag & TYPED_DATA_EMBEDDED; +} + +static inline void * +RTYPEDDATA_GET_DATA(VALUE obj) +{ +#if RUBY_DEBUG + if (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) { + Check_Type(obj, RUBY_T_DATA); + RBIMPL_UNREACHABLE_RETURN(false); + } +#endif + + /* We reuse the data pointer in embedded TypedData. We can't use offsetof + * since RTypedData a non-POD type in C++. */ + const size_t embedded_typed_data_size = sizeof(struct RTypedData) - sizeof(void *); + + return RTYPEDDATA_EMBEDDED_P(obj) ? (char *)obj + embedded_typed_data_size : RTYPEDDATA(obj)->data; +} + RBIMPL_ATTR_PURE() RBIMPL_ATTR_ARTIFICIAL() +/** + * @private + * + * This is an implementation detail of Check_Type(). People don't use it + * directly. + * + * @param[in] obj Object in question + * @retval true `obj` is an instance of ::RTypedData. + * @retval false `obj` is an instance of ::RData. + * @pre `obj` must be a Ruby object of ::RUBY_T_DATA. + */ static inline bool rbimpl_rtypeddata_p(VALUE obj) { - return RTYPEDDATA(obj)->typed_flag == 1; + VALUE typed_flag = RTYPEDDATA(obj)->typed_flag; + return typed_flag != 0 && typed_flag <= 3; } RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() +/** + * Checks whether the passed object is ::RTypedData or ::RData. + * + * @param[in] obj Object in question + * @retval true `obj` is an instance of ::RTypedData. + * @retval false `obj` is an instance of ::RData. + * @pre `obj` must be a Ruby object of ::RUBY_T_DATA. + */ static inline bool RTYPEDDATA_P(VALUE obj) { @@ -156,6 +591,13 @@ RTYPEDDATA_P(VALUE obj) RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() /* :TODO: can this function be __attribute__((returns_nonnull)) or not? */ +/** + * Queries for the type of given object. + * + * @param[in] obj Object in question + * @return Data type struct that corresponds to `obj`. + * @pre `obj` must be an instance of ::RTypedData. + */ static inline const struct rb_data_type_struct * RTYPEDDATA_TYPE(VALUE obj) { @@ -169,6 +611,20 @@ RTYPEDDATA_TYPE(VALUE obj) return RTYPEDDATA(obj)->type; } +/** + * While we don't stop you from using this function, it seems to be an + * implementation detail of #TypedData_Make_Struct, which is preferred over + * this one. + * + * @param[in] klass Ruby level class of the returning object. + * @param[in] type The data type + * @param[out] datap Return pointer. + * @param[in] size Size of the C struct. + * @exception rb_eTypeError `klass` is not a class. + * @exception rb_eNoMemError Out of memory. + * @return A created Ruby object. + * @post `*datap` points to the C struct wrapped by the returned object. + */ static inline VALUE rb_data_typed_object_make(VALUE klass, const rb_data_type_t *type, void **datap, size_t size) { @@ -177,6 +633,7 @@ rb_data_typed_object_make(VALUE klass, const rb_data_type_t *type, void **datap, } RBIMPL_ATTR_DEPRECATED(("by: rb_data_typed_object_wrap")) +/** @deprecated This function was renamed to rb_data_typed_object_wrap(). */ static inline VALUE rb_data_typed_object_alloc(VALUE klass, void *datap, const rb_data_type_t *type) { |