summaryrefslogtreecommitdiff
path: root/include/ruby/internal/core
diff options
context:
space:
mode:
Diffstat (limited to 'include/ruby/internal/core')
-rw-r--r--include/ruby/internal/core/rarray.h341
-rw-r--r--include/ruby/internal/core/rbasic.h86
-rw-r--r--include/ruby/internal/core/rbignum.h33
-rw-r--r--include/ruby/internal/core/rclass.h62
-rw-r--r--include/ruby/internal/core/rdata.h225
-rw-r--r--include/ruby/internal/core/rfile.h21
-rw-r--r--include/ruby/internal/core/rhash.h101
-rw-r--r--include/ruby/internal/core/rmatch.h91
-rw-r--r--include/ruby/internal/core/robject.h104
-rw-r--r--include/ruby/internal/core/rregexp.h88
-rw-r--r--include/ruby/internal/core/rstring.h399
-rw-r--r--include/ruby/internal/core/rstruct.h58
-rw-r--r--include/ruby/internal/core/rtypeddata.h475
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)
{