summaryrefslogtreecommitdiff
path: root/internal/hash.h
diff options
context:
space:
mode:
Diffstat (limited to 'internal/hash.h')
-rw-r--r--internal/hash.h210
1 files changed, 210 insertions, 0 deletions
diff --git a/internal/hash.h b/internal/hash.h
new file mode 100644
index 0000000000..0386a5009c
--- /dev/null
+++ b/internal/hash.h
@@ -0,0 +1,210 @@
+#ifndef INTERNAL_HASH_H /*-*-C-*-vi:se ft=c:*/
+#define INTERNAL_HASH_H
+/**
+ * @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.
+ * @brief Internal header for Hash.
+ */
+#include "ruby/internal/config.h"
+#include <stddef.h> /* for size_t */
+#include "ruby/internal/stdbool.h" /* for bool */
+#include "ruby/ruby.h" /* for struct RBasic */
+#include "ruby/st.h" /* for struct st_table */
+
+#define RHASH_AR_TABLE_MAX_SIZE SIZEOF_VALUE
+
+struct ar_table_struct;
+typedef unsigned char ar_hint_t;
+
+enum ruby_rhash_flags {
+ RHASH_PASS_AS_KEYWORDS = FL_USER1, /* FL 1 */
+ RHASH_PROC_DEFAULT = FL_USER2, /* FL 2 */
+ RHASH_ST_TABLE_FLAG = FL_USER3, /* FL 3 */
+ RHASH_AR_TABLE_SIZE_MASK = (FL_USER4|FL_USER5|FL_USER6|FL_USER7), /* FL 4..7 */
+ RHASH_AR_TABLE_SIZE_SHIFT = (FL_USHIFT+4),
+ RHASH_AR_TABLE_BOUND_MASK = (FL_USER8|FL_USER9|FL_USER10|FL_USER11), /* FL 8..11 */
+ RHASH_AR_TABLE_BOUND_SHIFT = (FL_USHIFT+8),
+
+ // we can not put it in "enum" because it can exceed "int" range.
+#define RHASH_LEV_MASK (FL_USER13 | FL_USER14 | FL_USER15 | /* FL 13..19 */ \
+ FL_USER16 | FL_USER17 | FL_USER18 | FL_USER19)
+
+ RHASH_LEV_SHIFT = (FL_USHIFT + 13),
+ RHASH_LEV_MAX = 127, /* 7 bits */
+};
+
+typedef struct ar_table_pair_struct {
+ VALUE key;
+ VALUE val;
+} ar_table_pair;
+
+typedef struct ar_table_struct {
+ union {
+ ar_hint_t ary[RHASH_AR_TABLE_MAX_SIZE];
+ VALUE word;
+ } ar_hint;
+ /* 64bit CPU: 8B * 2 * 8 = 128B */
+ ar_table_pair pairs[RHASH_AR_TABLE_MAX_SIZE];
+} ar_table;
+
+struct RHash {
+ struct RBasic basic;
+ const VALUE ifnone;
+};
+
+#define RHASH(obj) ((struct RHash *)(obj))
+
+#ifdef RHASH_IFNONE
+# undef RHASH_IFNONE
+#endif
+
+#ifdef RHASH_SIZE
+# undef RHASH_SIZE
+#endif
+
+#ifdef RHASH_EMPTY_P
+# undef RHASH_EMPTY_P
+#endif
+
+/* hash.c */
+VALUE rb_hash_default_value(VALUE hash, VALUE key);
+VALUE rb_hash_set_default(VALUE hash, VALUE ifnone);
+VALUE rb_hash_set_default_proc(VALUE hash, VALUE proc);
+long rb_dbl_long_hash(double d);
+st_table *rb_init_identtable(void);
+st_index_t rb_any_hash(VALUE a);
+int rb_any_cmp(VALUE a, VALUE b);
+VALUE rb_to_hash_type(VALUE obj);
+VALUE rb_hash_key_str(VALUE);
+VALUE rb_hash_values(VALUE hash);
+VALUE rb_hash_rehash(VALUE hash);
+int rb_hash_add_new_element(VALUE hash, VALUE key, VALUE val);
+VALUE rb_hash_set_pair(VALUE hash, VALUE pair);
+int rb_hash_stlike_delete(VALUE hash, st_data_t *pkey, st_data_t *pval);
+int rb_hash_stlike_foreach_with_replace(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg);
+int rb_hash_stlike_update(VALUE hash, st_data_t key, st_update_callback_func *func, st_data_t arg);
+bool rb_hash_default_unredefined(VALUE hash);
+VALUE rb_hash_alloc_fixed_size(VALUE klass, st_index_t size);
+VALUE rb_ident_hash_new_with_size(st_index_t size);
+void rb_hash_free(VALUE hash);
+RUBY_EXTERN VALUE rb_cHash_empty_frozen;
+
+static inline unsigned RHASH_AR_TABLE_SIZE_RAW(VALUE h);
+static inline VALUE RHASH_IFNONE(VALUE h);
+static inline size_t RHASH_SIZE(VALUE h);
+static inline bool RHASH_EMPTY_P(VALUE h);
+static inline bool RHASH_AR_TABLE_P(VALUE h);
+static inline bool RHASH_ST_TABLE_P(VALUE h);
+static inline struct ar_table_struct *RHASH_AR_TABLE(VALUE h);
+static inline st_table *RHASH_ST_TABLE(VALUE h);
+static inline size_t RHASH_ST_SIZE(VALUE h);
+static inline void RHASH_ST_CLEAR(VALUE h);
+
+RUBY_SYMBOL_EXPORT_BEGIN
+/* hash.c (export) */
+VALUE rb_hash_delete_entry(VALUE hash, VALUE key);
+VALUE rb_ident_hash_new(void);
+int rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg);
+RUBY_SYMBOL_EXPORT_END
+
+VALUE rb_hash_new_with_size(st_index_t size);
+VALUE rb_hash_new_with_bulk_insert(long argc, const VALUE *argv);
+VALUE rb_hash_resurrect(VALUE hash);
+int rb_hash_stlike_lookup(VALUE hash, st_data_t key, st_data_t *pval);
+VALUE rb_hash_keys(VALUE hash);
+VALUE rb_hash_has_key(VALUE hash, VALUE key);
+VALUE rb_hash_compare_by_id_p(VALUE hash);
+
+st_table *rb_hash_tbl_raw(VALUE hash, const char *file, int line);
+#define RHASH_TBL_RAW(h) rb_hash_tbl_raw(h, __FILE__, __LINE__)
+
+VALUE rb_hash_compare_by_id(VALUE hash);
+
+static inline bool
+RHASH_AR_TABLE_P(VALUE h)
+{
+ return ! FL_TEST_RAW(h, RHASH_ST_TABLE_FLAG);
+}
+
+RBIMPL_ATTR_RETURNS_NONNULL()
+static inline struct ar_table_struct *
+RHASH_AR_TABLE(VALUE h)
+{
+ return (struct ar_table_struct *)((uintptr_t)h + sizeof(struct RHash));
+}
+
+RBIMPL_ATTR_RETURNS_NONNULL()
+static inline st_table *
+RHASH_ST_TABLE(VALUE h)
+{
+ return (st_table *)((uintptr_t)h + sizeof(struct RHash));
+}
+
+static inline VALUE
+RHASH_IFNONE(VALUE h)
+{
+ return RHASH(h)->ifnone;
+}
+
+static inline size_t
+RHASH_SIZE(VALUE h)
+{
+ if (RHASH_AR_TABLE_P(h)) {
+ return RHASH_AR_TABLE_SIZE_RAW(h);
+ }
+ else {
+ return RHASH_ST_SIZE(h);
+ }
+}
+
+static inline bool
+RHASH_EMPTY_P(VALUE h)
+{
+ return RHASH_SIZE(h) == 0;
+}
+
+static inline bool
+RHASH_ST_TABLE_P(VALUE h)
+{
+ return ! RHASH_AR_TABLE_P(h);
+}
+
+static inline size_t
+RHASH_ST_SIZE(VALUE h)
+{
+ return RHASH_ST_TABLE(h)->num_entries;
+}
+
+static inline void
+RHASH_ST_CLEAR(VALUE h)
+{
+ memset(RHASH_ST_TABLE(h), 0, sizeof(st_table));
+}
+
+static inline unsigned
+RHASH_AR_TABLE_SIZE_RAW(VALUE h)
+{
+ VALUE ret = FL_TEST_RAW(h, RHASH_AR_TABLE_SIZE_MASK);
+ ret >>= RHASH_AR_TABLE_SIZE_SHIFT;
+ return (unsigned)ret;
+}
+
+#define RHASH_AR_TABLE_BOUND_RAW(h) \
+ ((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \
+ (RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT)))
+
+#define RHASH_TYPE(hash) (RHASH_AR_TABLE_P(hash) ? &objhash : RHASH_ST_TABLE(hash)->type)
+
+static inline unsigned int
+RHASH_AR_TABLE_BOUND(VALUE h)
+{
+ RUBY_ASSERT(RHASH_AR_TABLE_P(h));
+ const unsigned int bound = RHASH_AR_TABLE_BOUND_RAW(h);
+ RUBY_ASSERT(bound <= RHASH_AR_TABLE_MAX_SIZE);
+ return bound;
+}
+
+#endif /* INTERNAL_HASH_H */