summaryrefslogtreecommitdiff
path: root/include/ruby/internal/value_type.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/ruby/internal/value_type.h')
-rw-r--r--include/ruby/internal/value_type.h354
1 files changed, 354 insertions, 0 deletions
diff --git a/include/ruby/internal/value_type.h b/include/ruby/internal/value_type.h
new file mode 100644
index 0000000000..be1b3559b6
--- /dev/null
+++ b/include/ruby/internal/value_type.h
@@ -0,0 +1,354 @@
+#ifndef RBIMPL_VALUE_TYPE_H /*-*-C++-*-vi:se ft=cpp:*/
+#define RBIMPL_VALUE_TYPE_H
+/**
+ * @file
+ * @author Ruby developers <ruby-core@ruby-lang.org>
+ * @copyright This file is a part of the programming language Ruby.
+ * Permission is hereby granted, to either redistribute and/or
+ * modify this file, provided that the conditions mentioned in the
+ * file COPYING are met. Consult the file for details.
+ * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
+ * implementation details. Don't take them as canon. They could
+ * rapidly appear then vanish. The name (path) of this header file
+ * is also an implementation detail. Do not expect it to persist
+ * at the place it is now. Developers are free to move it anywhere
+ * anytime at will.
+ * @note To ruby-core: remember that this header can be possibly
+ * 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 Defines enum ::ruby_value_type.
+ */
+#include "ruby/impl/assume.h"
+#include "ruby/impl/attr/artificial.h"
+#include "ruby/impl/attr/cold.h"
+#include "ruby/impl/attr/enum_extensibility.h"
+#include "ruby/impl/attr/forceinline.h"
+#include "ruby/impl/attr/pure.h"
+#include "ruby/impl/cast.h"
+#include "ruby/impl/constant_p.h"
+#include "ruby/impl/core/rbasic.h"
+#include "ruby/impl/dllexport.h"
+#include "ruby/impl/has/builtin.h"
+#include "ruby/impl/special_consts.h"
+#include "ruby/impl/stdbool.h"
+#include "ruby/impl/value.h"
+#include "ruby/assert.h"
+
+#if defined(T_DATA)
+/*
+ * :!BEWARE!: (Recent?) Solaris' <nfs/nfs.h> have conflicting definition of
+ * T_DATA. Let us stop here. Please have a workaround like this:
+ *
+ * ```C
+ * #include <ruby/ruby.h> // <- Include this one first.
+ * #undef T_DATA // <- ... and stick to RUBY_T_DATA forever.
+ * #include <nfs/nfs.h> // <- OS-provided T_DATA introduced.
+ * ```
+ *
+ * See also [ruby-core:4261]
+ */
+# error Bail out due to conflicting definition of T_DATA.
+#endif
+
+#define T_ARRAY RUBY_T_ARRAY
+#define T_BIGNUM RUBY_T_BIGNUM
+#define T_CLASS RUBY_T_CLASS
+#define T_COMPLEX RUBY_T_COMPLEX
+#define T_DATA RUBY_T_DATA
+#define T_FALSE RUBY_T_FALSE
+#define T_FILE RUBY_T_FILE
+#define T_FIXNUM RUBY_T_FIXNUM
+#define T_FLOAT RUBY_T_FLOAT
+#define T_HASH RUBY_T_HASH
+#define T_ICLASS RUBY_T_ICLASS
+#define T_IMEMO RUBY_T_IMEMO
+#define T_MASK RUBY_T_MASK
+#define T_MATCH RUBY_T_MATCH
+#define T_MODULE RUBY_T_MODULE
+#define T_MOVED RUBY_T_MOVED
+#define T_NIL RUBY_T_NIL
+#define T_NODE RUBY_T_NODE
+#define T_NONE RUBY_T_NONE
+#define T_OBJECT RUBY_T_OBJECT
+#define T_RATIONAL RUBY_T_RATIONAL
+#define T_REGEXP RUBY_T_REGEXP
+#define T_STRING RUBY_T_STRING
+#define T_STRUCT RUBY_T_STRUCT
+#define T_SYMBOL RUBY_T_SYMBOL
+#define T_TRUE RUBY_T_TRUE
+#define T_UNDEF RUBY_T_UNDEF
+#define T_ZOMBIE RUBY_T_ZOMBIE
+
+#define BUILTIN_TYPE RB_BUILTIN_TYPE
+#define DYNAMIC_SYM_P RB_DYNAMIC_SYM_P
+#define RB_INTEGER_TYPE_P rb_integer_type_p
+#define SYMBOL_P RB_SYMBOL_P
+#define rb_type_p RB_TYPE_P
+
+/** @cond INTERNAL_MACRO */
+#define RB_BUILTIN_TYPE RB_BUILTIN_TYPE
+#define RB_DYNAMIC_SYM_P RB_DYNAMIC_SYM_P
+#define RB_FLOAT_TYPE_P RB_FLOAT_TYPE_P
+#define RB_SYMBOL_P RB_SYMBOL_P
+#define RB_TYPE_P RB_TYPE_P
+#define Check_Type Check_Type
+
+#if RUBY_NDEBUG
+# define RBIMPL_ASSERT_TYPE(v, t) RBIMPL_ASSERT_OR_ASSUME(RB_TYPE_P((v), (t)))
+#else
+# define RBIMPL_ASSERT_TYPE Check_Type
+#endif
+/** @endcond */
+
+#define TYPE(_) RBIMPL_CAST((int)rb_type(_))
+
+/** C-level type of an object. */
+enum
+RBIMPL_ATTR_ENUM_EXTENSIBILITY(closed)
+ruby_value_type {
+ RUBY_T_NONE = 0x00, /**< Non-object (sweeped etc.) */
+
+ RUBY_T_OBJECT = 0x01, /**< @see struct ::RObject */
+ RUBY_T_CLASS = 0x02, /**< @see struct ::RClass and ::rb_cClass */
+ RUBY_T_MODULE = 0x03, /**< @see struct ::RClass and ::rb_cModule */
+ RUBY_T_FLOAT = 0x04, /**< @see struct ::RFloat */
+ RUBY_T_STRING = 0x05, /**< @see struct ::RString */
+ RUBY_T_REGEXP = 0x06, /**< @see struct ::RRegexp */
+ RUBY_T_ARRAY = 0x07, /**< @see struct ::RArray */
+ RUBY_T_HASH = 0x08, /**< @see struct ::RHash */
+ RUBY_T_STRUCT = 0x09, /**< @see struct ::RStruct */
+ RUBY_T_BIGNUM = 0x0a, /**< @see struct ::RBignum */
+ RUBY_T_FILE = 0x0b, /**< @see struct ::RFile */
+ RUBY_T_DATA = 0x0c, /**< @see struct ::RTypedData */
+ RUBY_T_MATCH = 0x0d, /**< @see struct ::RMatch */
+ RUBY_T_COMPLEX = 0x0e, /**< @see struct ::RComplex */
+ RUBY_T_RATIONAL = 0x0f, /**< @see struct ::RRational */
+
+ RUBY_T_NIL = 0x11, /**< @see ::RUBY_Qnil */
+ RUBY_T_TRUE = 0x12, /**< @see ::RUBY_Qfalse */
+ RUBY_T_FALSE = 0x13, /**< @see ::RUBY_Qtrue */
+ RUBY_T_SYMBOL = 0x14, /**< @see struct ::RSymbol */
+ RUBY_T_FIXNUM = 0x15, /**< Integers formerly known as Fixnums. */
+ RUBY_T_UNDEF = 0x16, /**< @see ::RUBY_Qundef */
+
+ RUBY_T_IMEMO = 0x1a, /**< @see struct ::RIMemo */
+ RUBY_T_NODE = 0x1b, /**< @see struct ::RNode */
+ RUBY_T_ICLASS = 0x1c, /**< Hidden classes known as IClasses. */
+ RUBY_T_ZOMBIE = 0x1d, /**< @see struct ::RZombie */
+ RUBY_T_MOVED = 0x1e, /**< @see struct ::RMoved */
+
+ RUBY_T_MASK = 0x1f
+};
+
+RBIMPL_SYMBOL_EXPORT_BEGIN()
+RBIMPL_ATTR_COLD()
+void rb_check_type(VALUE obj, int t);
+RBIMPL_SYMBOL_EXPORT_END()
+
+RBIMPL_ATTR_PURE_ON_NDEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+static inline enum ruby_value_type
+RB_BUILTIN_TYPE(VALUE obj)
+{
+ RBIMPL_ASSERT_OR_ASSUME(! RB_SPECIAL_CONST_P(obj));
+
+ VALUE ret = RBASIC(obj)->flags & RUBY_T_MASK;
+ return RBIMPL_CAST((enum ruby_value_type)ret);
+}
+
+RBIMPL_ATTR_PURE_ON_NDEBUG()
+static inline bool
+rb_integer_type_p(VALUE obj)
+{
+ if (RB_FIXNUM_P(obj)) {
+ return true;
+ }
+ else if (RB_SPECIAL_CONST_P(obj)) {
+ return false;
+ }
+ else {
+ return RB_BUILTIN_TYPE(obj) == RUBY_T_BIGNUM;
+ }
+}
+
+RBIMPL_ATTR_PURE_ON_NDEBUG()
+static inline enum ruby_value_type
+rb_type(VALUE obj)
+{
+ if (! RB_SPECIAL_CONST_P(obj)) {
+ return RB_BUILTIN_TYPE(obj);
+ }
+ else if (obj == RUBY_Qfalse) {
+ return RUBY_T_FALSE;
+ }
+ else if (obj == RUBY_Qnil) {
+ return RUBY_T_NIL;
+ }
+ else if (obj == RUBY_Qtrue) {
+ return RUBY_T_TRUE;
+ }
+ else if (obj == RUBY_Qundef) {
+ return RUBY_T_UNDEF;
+ }
+ else if (RB_FIXNUM_P(obj)) {
+ return RUBY_T_FIXNUM;
+ }
+ else if (RB_STATIC_SYM_P(obj)) {
+ return RUBY_T_SYMBOL;
+ }
+ else {
+ RBIMPL_ASSUME(RB_FLONUM_P(obj));
+ return RUBY_T_FLOAT;
+ }
+}
+
+RBIMPL_ATTR_PURE_ON_NDEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+static inline bool
+RB_FLOAT_TYPE_P(VALUE obj)
+{
+ if (RB_FLONUM_P(obj)) {
+ return true;
+ }
+ else if (RB_SPECIAL_CONST_P(obj)) {
+ return false;
+ }
+ else {
+ return RB_BUILTIN_TYPE(obj) == RUBY_T_FLOAT;
+ }
+}
+
+RBIMPL_ATTR_PURE_ON_NDEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+static inline bool
+RB_DYNAMIC_SYM_P(VALUE obj)
+{
+ if (RB_SPECIAL_CONST_P(obj)) {
+ return false;
+ }
+ else {
+ return RB_BUILTIN_TYPE(obj) == RUBY_T_SYMBOL;
+ }
+}
+
+RBIMPL_ATTR_PURE_ON_NDEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+static inline bool
+RB_SYMBOL_P(VALUE obj)
+{
+ return RB_STATIC_SYM_P(obj) || RB_DYNAMIC_SYM_P(obj);
+}
+
+RBIMPL_ATTR_PURE_ON_NDEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_FORCEINLINE()
+static bool
+rbimpl_RB_TYPE_P_fastpath(VALUE obj, enum ruby_value_type t)
+{
+ if (t == RUBY_T_TRUE) {
+ return obj == RUBY_Qtrue;
+ }
+ else if (t == RUBY_T_FALSE) {
+ return obj == RUBY_Qfalse;
+ }
+ else if (t == RUBY_T_NIL) {
+ return obj == RUBY_Qnil;
+ }
+ else if (t == RUBY_T_UNDEF) {
+ return obj == RUBY_Qundef;
+ }
+ else if (t == RUBY_T_FIXNUM) {
+ return RB_FIXNUM_P(obj);
+ }
+ else if (t == RUBY_T_SYMBOL) {
+ return RB_SYMBOL_P(obj);
+ }
+ else if (t == RUBY_T_FLOAT) {
+ return RB_FLOAT_TYPE_P(obj);
+ }
+ else if (RB_SPECIAL_CONST_P(obj)) {
+ return false;
+ }
+ else if (t == RB_BUILTIN_TYPE(obj)) {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+RBIMPL_ATTR_PURE_ON_NDEBUG()
+RBIMPL_ATTR_ARTIFICIAL()
+static inline bool
+RB_TYPE_P(VALUE obj, enum ruby_value_type t)
+{
+ if (RBIMPL_CONSTANT_P(t)) {
+ return rbimpl_RB_TYPE_P_fastpath(obj, t);
+ }
+ else {
+ return t == rb_type(obj);
+ }
+}
+
+/** @cond INTERNAL_MACRO */
+/* Clang, unlike GCC, cannot propagate __builtin_constant_p beyond function
+ * boundary. */
+#if defined(__clang__)
+# undef RB_TYPE_P
+# define RB_TYPE_P(obj, t) \
+ (RBIMPL_CONSTANT_P(t) ? \
+ rbimpl_RB_TYPE_P_fastpath((obj), (t)) : \
+ (RB_TYPE_P)((obj), (t)))
+#endif
+
+/* clang 3.x (4.2 compatible) can't eliminate CSE of RB_BUILTIN_TYPE
+ * in inline function and caller function
+ * See also 8998c06461ea0bef11b3aeb30b6d2ab71c8762ba
+ */
+#if RBIMPL_COMPILER_BEFORE(Clang, 4, 0, 0)
+# undef rb_integer_type_p
+# define rb_integer_type_p(obj) \
+ __extension__ ({ \
+ const VALUE integer_type_obj = (obj); \
+ (RB_FIXNUM_P(integer_type_obj) || \
+ (!RB_SPECIAL_CONST_P(integer_type_obj) && \
+ RB_BUILTIN_TYPE(integer_type_obj) == RUBY_T_BIGNUM)); \
+ })
+#endif
+/** @endcond */
+
+RBIMPL_ATTR_PURE()
+RBIMPL_ATTR_ARTIFICIAL()
+/* Defined in ruby/impl/core/rtypeddata.h */
+static inline bool rbimpl_rtypeddata_p(VALUE obj);
+
+RBIMPL_ATTR_ARTIFICIAL()
+static inline void
+Check_Type(VALUE v, enum ruby_value_type t)
+{
+ if (RB_UNLIKELY(! RB_TYPE_P(v, t))) {
+ goto slowpath;
+ }
+ else if (t != RUBY_T_DATA) {
+ goto fastpath;
+ }
+ else if (rbimpl_rtypeddata_p(v)) {
+ /* The intention itself is not necessarily clear to me, but at least it
+ * is intentional to rule out typed data here. See commit
+ * a7c32bf81d3391cfb78cfda278f469717d0fb794. */
+ goto slowpath;
+ }
+ else {
+ goto fastpath;
+ }
+
+ fastpath:
+ return;
+
+ slowpath: /* <- :TODO: mark this label as cold. */
+ rb_check_type(v, t);
+}
+
+#endif /* RBIMPL_VALUE_TYPE_H */