Issue #9889 has been reported by Shyouhei Urabe.

----------------------------------------
Feature #9889: Hide Hash internal
https://bugs.ruby-lang.org/issues/9889

* Author: Shyouhei Urabe
* Status: Open
* Priority: Normal
* Assignee: 
* Category: core
* Target version: current: 2.2.0
----------------------------------------
~~~Patch
From b042711f88b74c9b260a8a6d82d3e040174c01d2 Mon Sep 17 00:00:00 2001
From: "Urabe, Shyouhei" <shyouhei / ruby-lang.org>
Date: Sat, 31 May 2014 22:13:24 +0900
Subject: [PATCH] Hide Hash internal

I chose struct RHash for several reasons:

- I'm farmiliar with its internals so I'm 100% sure with this patch.
- At least Ko1, Eric, and myself think current hash implementation needs improvements.  So hiding its internal is urgent.
- Hash is a relatively complex data strcture compared to Strings and Arrays, so its internals are seldom touched.

Signed-off-by: Urabe, Shyouhei <shyouhei / ruby-lang.org>
---
 ChangeLog             | 14 ++++++++++++++
 hash.c                | 29 ++++++++++++++++++++++++++---
 include/ruby/intern.h |  3 +++
 include/ruby/ruby.h   | 13 +++----------
 internal.h            |  9 +++++++++
 5 files changed, 55 insertions(+), 13 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 8381daa..ea789cf 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+Sat May 31 22:10:32 2014  URABE Shyouhei  <shyouhei / ruby-lang.org>
+
+	* include/ruby/ruby.h (struct RHash): no longer.
+
+	* internal.h (struct RHash): moved here.
+
+	* hash.c (rb_hash_ifnone): compatibilty accessor function.
+
+	* hash.c (rb_hash_iter_lev): ditto.
+
+	* hash.c (rb_hash_size_): ditto.
+
+	  (note) rb_hash_size() already exists.
+
 Sat May 31 21:15:43 2014  URABE Shyouhei  <shyouhei / ruby-lang.org>
 
 	* thread.c (rb_thread_atfork_internal): My compiler complains
diff --git a/hash.c b/hash.c
index 93efde7..59f79a9 100644
--- a/hash.c
+++ b/hash.c
@@ -235,14 +235,14 @@ hash_foreach_iter(st_data_t key, st_data_t value, st_data_t argp, int error)
 static VALUE
 hash_foreach_ensure_rollback(VALUE hash)
 {
-    RHASH_ITER_LEV(hash)++;
+    RHASH(hash)->iter_lev++;
     return 0;
 }
 
 static VALUE
 hash_foreach_ensure(VALUE hash)
 {
-    if (--RHASH_ITER_LEV(hash) == 0) {
+    if (--RHASH(hash)->iter_lev == 0) {
 	if (FL_TEST(hash, HASH_DELETED)) {
 	    st_cleanup_safe(RHASH(hash)->ntbl, (st_data_t)Qundef);
 	    FL_UNSET(hash, HASH_DELETED);
@@ -268,7 +268,7 @@ rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
 
     if (!RHASH(hash)->ntbl)
         return;
-    RHASH_ITER_LEV(hash)++;
+    RHASH(hash)->iter_lev++;
     arg.hash = hash;
     arg.func = (rb_foreach_func *)func;
     arg.arg  = farg;
@@ -354,6 +354,29 @@ rb_hash_tbl_raw(VALUE hash)
     return hash_tbl(hash);
 }
 
+VALUE
+rb_hash_ifnone(VALUE hash)
+{
+    return RHASH(hash)->ifnone;
+}
+
+int
+rb_hash_iter_lev(VALUE hash)
+{
+    return RHASH(hash)->iter_lev;
+}
+
+st_index_t
+rb_hash_size_(VALUE hash)
+{
+    if (RHASH(hash)->ntbl) {
+        return RHASH(hash)->ntbl->num_entries;
+    }
+    else {
+        return 0;
+    }
+}
+
 static void
 rb_hash_modify(VALUE hash)
 {
diff --git a/include/ruby/intern.h b/include/ruby/intern.h
index 387f000..4758533 100644
--- a/include/ruby/intern.h
+++ b/include/ruby/intern.h
@@ -503,6 +503,9 @@ VALUE rb_hash_set_ifnone(VALUE hash, VALUE ifnone);
 typedef VALUE rb_hash_update_func(VALUE newkey, VALUE oldkey, VALUE value);
 VALUE rb_hash_update_by(VALUE hash1, VALUE hash2, rb_hash_update_func *func);
 struct st_table *rb_hash_tbl(VALUE);
+VALUE rb_hash_ifnone(VALUE);
+int rb_hash_iter_lev(VALUE);
+st_index_t rb_hash_size_(VALUE);
 int rb_path_check(const char*);
 int rb_env_path_tainted(void);
 VALUE rb_env_clear(void);
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index 7c7cb67..f033f46 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -924,17 +924,11 @@ struct RRegexp {
 #define RREGEXP_SRC_LEN(r) RSTRING_LEN(RREGEXP(r)->src)
 #define RREGEXP_SRC_END(r) RSTRING_END(RREGEXP(r)->src)
 
-struct RHash {
-    struct RBasic basic;
-    struct st_table *ntbl;      /* possibly 0 */
-    int iter_lev;
-    const VALUE ifnone;
-};
 /* RHASH_TBL allocates st_table if not available. */
 #define RHASH_TBL(h) rb_hash_tbl(h)
-#define RHASH_ITER_LEV(h) (RHASH(h)->iter_lev)
-#define RHASH_IFNONE(h) (RHASH(h)->ifnone)
-#define RHASH_SIZE(h) (RHASH(h)->ntbl ? (st_index_t)RHASH(h)->ntbl->num_entries : 0)
+#define RHASH_ITER_LEV(h) rb_hash_iter_lev(h)
+#define RHASH_IFNONE(h) rb_hash_ifnone(h)
+#define RHASH_SIZE(h) rb_hash_size_(h)
 #define RHASH_EMPTY_P(h) (RHASH_SIZE(h) == 0)
 #define RHASH_SET_IFNONE(h, ifnone) rb_hash_set_ifnone((VALUE)h, ifnone)
 
@@ -1081,7 +1075,6 @@ struct RStruct {
 #define RSTRING(obj) (R_CAST(RString)(obj))
 #define RREGEXP(obj) (R_CAST(RRegexp)(obj))
 #define RARRAY(obj)  (R_CAST(RArray)(obj))
-#define RHASH(obj)   (R_CAST(RHash)(obj))
 #define RDATA(obj)   (R_CAST(RData)(obj))
 #define RTYPEDDATA(obj)   (R_CAST(RTypedData)(obj))
 #define RSTRUCT(obj) (R_CAST(RStruct)(obj))
diff --git a/internal.h b/internal.h
index 2c1c6a3..854d9d9 100644
--- a/internal.h
+++ b/internal.h
@@ -420,6 +420,15 @@ struct RSymbol {
 
 #define RSYMBOL(obj) (R_CAST(RSymbol)(obj))
 
+struct RHash {
+    struct RBasic basic;
+    struct st_table *ntbl;      /* possibly 0 */
+    int iter_lev;
+    const VALUE ifnone;
+};
+
+#define RHASH(obj)   (R_CAST(RHash)(obj))
+
 /* class.c */
 void rb_class_subclass_add(VALUE super, VALUE klass);
 void rb_class_remove_from_super_subclasses(VALUE);
-- 
1.9.1
~~~



-- 
https://bugs.ruby-lang.org/