[macruby-changes] [3345] MacRuby/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Tue Jan 26 15:21:44 PST 2010
Revision: 3345
http://trac.macosforge.org/projects/ruby/changeset/3345
Author: lsansonetti at apple.com
Date: 2010-01-26 15:21:44 -0800 (Tue, 26 Jan 2010)
Log Message:
-----------
finished Hash refactoring
Modified Paths:
--------------
MacRuby/trunk/hash.c
MacRuby/trunk/include/ruby/intern.h
MacRuby/trunk/include/ruby/ruby.h
MacRuby/trunk/rakelib/builder.rb
MacRuby/trunk/spec/macruby/tags/macruby/core/hash_tags.txt
Added Paths:
-----------
MacRuby/trunk/NSDictionary.m
Added: MacRuby/trunk/NSDictionary.m
===================================================================
--- MacRuby/trunk/NSDictionary.m (rev 0)
+++ MacRuby/trunk/NSDictionary.m 2010-01-26 23:21:44 UTC (rev 3345)
@@ -0,0 +1,610 @@
+/*
+ * MacRuby extensions to NSDictionary.
+ *
+ * This file is covered by the Ruby license. See COPYING for more details.
+ *
+ * Copyright (C) 2010, Apple Inc. All rights reserved.
+ */
+
+#import <Foundation/Foundation.h>
+
+#include "ruby/ruby.h"
+#include "ruby/node.h"
+#include "objc.h"
+#include "vm.h"
+
+VALUE rb_cHash;
+VALUE rb_cNSHash;
+VALUE rb_cNSMutableHash;
+static VALUE rb_cCFHash;
+
+static id
+to_hash(id hash)
+{
+ return (id)rb_convert_type((VALUE)hash, T_HASH, "Hash", "to_hash");
+}
+
+static id
+nshash_dup(id rcv, SEL sel)
+{
+ id dup = [rcv mutableCopy];
+ if (OBJ_TAINTED(rcv)) {
+ OBJ_TAINT(dup);
+ }
+ return dup;
+}
+
+static id
+nshash_clone(id rcv, SEL sel)
+{
+ id clone = nshash_dup(rcv, 0);
+ if (OBJ_FROZEN(rcv)) {
+ OBJ_FREEZE(clone);
+ }
+ return clone;
+}
+
+static id
+nshash_rehash(id rcv, SEL sel)
+{
+ NSArray *keys = [rcv allKeys];
+ NSArray *values = [rcv allValues];
+ assert([keys count] == [values count]);
+ [rcv removeAllObjects];
+ for (unsigned i = 0, count = [keys count]; i < count; i++) {
+ [rcv setObject:[values objectAtIndex:i] forKey:[keys objectAtIndex:i]];
+ }
+ return rcv;
+}
+
+static id
+nshash_to_hash(id rcv, SEL sel)
+{
+ return rcv;
+}
+
+static id
+nshash_to_a(id rcv, SEL sel)
+{
+ NSMutableArray *ary = [NSMutableArray new];
+ for (id key in rcv) {
+ id value = [rcv objectForKey:key];
+ [ary addObject:[NSArray arrayWithObjects:key, value, nil]];
+ }
+ return ary;
+}
+
+static id
+nshash_inspect(id rcv, SEL sel)
+{
+ NSMutableString *str = [NSMutableString new];
+ [str appendString:@"{"];
+ for (id key in rcv) {
+ if ([str length] > 1) {
+ [str appendString:@", "];
+ }
+ id value = [rcv objectForKey:key];
+ [str appendString:(NSString *)rb_inspect(OC2RB(key))];
+ [str appendString:@"=>"];
+ [str appendString:(NSString *)rb_inspect(OC2RB(value))];
+ }
+ [str appendString:@"}"];
+ return str;
+}
+
+static VALUE
+nshash_equal(id rcv, SEL sel, id other)
+{
+ return [rcv isEqualToDictionary:other] ? Qtrue : Qfalse;
+}
+
+static VALUE
+nshash_aref(id rcv, SEL sel, VALUE key)
+{
+ return OC2RB([rcv objectForKey:RB2OC(key)]);
+}
+
+static VALUE
+nshash_aset(id rcv, SEL sel, VALUE key, VALUE val)
+{
+ [rcv setObject:RB2OC(val) forKey:RB2OC(key)];
+ return val;
+}
+
+static VALUE
+nshash_fetch(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ VALUE key, if_none;
+ rb_scan_args(argc, argv, "11", &key, &if_none);
+
+ const bool block_given = rb_block_given_p();
+ if (block_given && argc == 2) {
+ rb_warn("block supersedes default value argument");
+ }
+
+ id value = [rcv objectForKey:RB2OC(key)];
+ if (value != nil) {
+ return OC2RB(value);
+ }
+ if (block_given) {
+ return rb_yield(key);
+ }
+ if (argc == 1) {
+ rb_raise(rb_eKeyError, "key not found");
+ }
+ return if_none;
+}
+
+static VALUE
+nshash_default(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ // TODO
+ return Qnil;
+}
+
+static VALUE
+nshash_set_default(id rcv, SEL sel, VALUE default_value)
+{
+ // TODO
+ return Qnil;
+}
+
+static VALUE
+nshash_default_proc(id rcv, SEL sel)
+{
+ // Default procs are never possible with NSDictionaries.
+ return Qnil;
+}
+
+static VALUE
+nshash_key(id rcv, SEL sel, VALUE value)
+{
+ NSArray *keys = [rcv allKeysForObject:RB2OC(value)];
+ if ([keys count] > 0) {
+ return OC2RB([keys objectAtIndex:0]);
+ }
+ return Qnil;
+}
+
+static VALUE
+nshash_index(id rcv, SEL sel, VALUE value)
+{
+ rb_warn("Hash#index is deprecated; use Hash#key");
+ return nshash_key(rcv, 0, value);
+}
+
+static VALUE
+nshash_size(id rcv, SEL sel)
+{
+ return LONG2FIX([rcv count]);
+}
+
+static VALUE
+nshash_empty(id rcv, SEL sel)
+{
+ return [rcv count] == 0 ? Qtrue : Qfalse;
+}
+
+static VALUE
+nshash_each_value(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ for (id key in rcv) {
+ rb_yield(OC2RB([rcv objectForKey:key]));
+ }
+ return (VALUE)rcv;
+}
+
+static VALUE
+nshash_each_key(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ for (id key in rcv) {
+ rb_yield(OC2RB(key));
+ }
+ return (VALUE)rcv;
+}
+
+static VALUE
+nshash_each_pair(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ for (id key in rcv) {
+ id value = [rcv objectForKey:key];
+ rb_yield(rb_assoc_new(OC2RB(key), OC2RB(value)));
+ }
+ return (VALUE)rcv;
+}
+
+static id
+nshash_keys(id rcv, SEL sel)
+{
+ return [[rcv allKeys] mutableCopy];
+}
+
+static id
+nshash_values(id rcv, SEL sel)
+{
+ return [[rcv allValues] mutableCopy];
+}
+
+static id
+nshash_values_at(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ NSMutableArray *ary = [NSMutableArray new];
+ for (int i = 0; i < argc; i++) {
+ id value = [rcv objectForKey:RB2OC(argv[i])];
+ [ary addObject:value];
+ }
+ return ary;
+}
+
+static VALUE
+nshash_shift(id rcv, SEL sel)
+{
+ if ([rcv count] > 0) {
+ id key = [[rcv keyEnumerator] nextObject];
+ assert(key != NULL);
+ id value = [rcv objectForKey:key];
+ [rcv removeObjectForKey:key];
+ return rb_assoc_new(OC2RB(key), OC2RB(value));
+ }
+ return nshash_default(rcv, 0, 0, NULL);
+}
+
+static VALUE
+nshash_delete(id rcv, SEL sel, VALUE key)
+{
+ id ockey = RB2OC(key);
+ id value = [rcv objectForKey:ockey];
+ if (value != nil) {
+ [rcv removeObjectForKey:ockey];
+ return OC2RB(value);
+ }
+ if (rb_block_given_p()) {
+ return rb_yield(key);
+ }
+ return Qnil;
+}
+
+static VALUE
+nshash_delete_if(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ NSMutableArray *ary = [NSMutableArray new];
+ for (id key in rcv) {
+ id value = [rcv objectForKey:key];
+ if (RTEST(rb_yield_values(2, OC2RB(key), OC2RB(value)))) {
+ [ary addObject:key];
+ }
+ }
+ [rcv removeObjectsForKeys:ary];
+ return (VALUE)rcv;
+}
+
+static VALUE
+nshash_select(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ NSMutableDictionary *dict = [NSMutableDictionary new];
+ for (id key in rcv) {
+ id value = [rcv objectForKey:key];
+ if (RTEST(rb_yield_values(2, OC2RB(key), OC2RB(value)))) {
+ [dict setObject:value forKey:key];
+ }
+ }
+ return (VALUE)dict;
+}
+
+static VALUE
+nshash_reject(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ return nshash_delete_if([rcv mutableCopy], 0);
+}
+
+static VALUE
+nshash_reject_bang(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ unsigned size = [rcv count];
+ nshash_delete_if(rcv, 0);
+ return size != [rcv count] ? (VALUE)rcv : Qnil;
+}
+
+static id
+nshash_clear(id rcv, SEL sel)
+{
+ [rcv removeAllObjects];
+ return rcv;
+}
+
+static id
+nshash_update(id rcv, SEL sel, id hash)
+{
+ hash = to_hash(hash);
+ if (rb_block_given_p()) {
+ for (id key in hash) {
+ id value = [hash objectForKey:key];
+ id old_value = [rcv objectForKey:key];
+ if (old_value != nil) {
+ value = RB2OC(rb_yield_values(3, OC2RB(key), OC2RB(old_value),
+ OC2RB(value)));
+ }
+ [rcv setObject:value forKey:key];
+ }
+ }
+ else {
+ for (id key in hash) {
+ id value = [hash objectForKey:key];
+ [rcv setObject:value forKey:key];
+ }
+ }
+ return rcv;
+}
+
+static id
+nshash_merge(id rcv, SEL sel, id hash)
+{
+ return nshash_update([rcv mutableCopy], 0, hash);
+}
+
+static id
+nshash_replace(id rcv, SEL sel, id hash)
+{
+ hash = to_hash(hash);
+ [rcv setDictionary:hash];
+ return rcv;
+}
+
+static VALUE
+nshash_assoc(id rcv, SEL sel, VALUE obj)
+{
+ for (id key in rcv) {
+ if (rb_equal(OC2RB(key), obj)) {
+ id value = [rcv objectForKey:key];
+ return rb_assoc_new(obj, OC2RB(value));
+ }
+ }
+ return Qnil;
+}
+
+static VALUE
+nshash_rassoc(id rcv, SEL sel, VALUE obj)
+{
+ for (id key in rcv) {
+ id value = [rcv objectForKey:key];
+ if (rb_equal(OC2RB(value), obj)) {
+ return rb_assoc_new(OC2RB(key), obj);
+ }
+ }
+ return Qnil;
+}
+
+static id
+nshash_flatten(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ id ary = nshash_to_a(rcv, 0);
+ VALUE tmp;
+ if (argc == 0) {
+ argc = 1;
+ tmp = INT2FIX(1);
+ argv = &tmp;
+ }
+ rb_vm_call((VALUE)ary, sel_registerName("flatten!:"), argc, argv, false);
+ return ary;
+}
+
+static VALUE
+nshash_has_key(id rcv, SEL sel, VALUE key)
+{
+ return [rcv objectForKey:RB2OC(key)] == nil ? Qfalse : Qtrue;
+}
+
+static VALUE
+nshash_has_value(id rcv, SEL sel, VALUE value)
+{
+ return [[rcv allKeysForObject:RB2OC(value)] count] == 0 ? Qfalse : Qtrue;
+}
+
+static id
+nshash_compare_by_id(id rcv, SEL sel)
+{
+ // Not implemented.
+ return rcv;
+}
+
+static VALUE
+nshash_compare_by_id_p(id rcv, SEL sel)
+{
+ // Not implemented.
+ return Qfalse;
+}
+
+void
+Init_NSDictionary(void)
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
+ rb_cCFHash = (VALUE)objc_getClass("NSCFDictionary");
+#else
+ rb_cCFHash = (VALUE)objc_getClass("__NSCFDictionary");
+#endif
+ assert(rb_cCFHash != 0);
+ rb_cNSHash = (VALUE)objc_getClass("NSDictionary");
+ assert(rb_cNSHash != 0);
+ rb_cHash = rb_cNSHash;
+ rb_cNSMutableHash = (VALUE)objc_getClass("NSMutableDictionary");
+ assert(rb_cNSMutableHash != 0);
+
+ rb_include_module(rb_cHash, rb_mEnumerable);
+
+ rb_objc_define_method(rb_cHash, "dup", nshash_dup, 0);
+ rb_objc_define_method(rb_cHash, "clone", nshash_clone, 0);
+ rb_objc_define_method(rb_cHash, "rehash", nshash_rehash, 0);
+ rb_objc_define_method(rb_cHash, "to_hash", nshash_to_hash, 0);
+ rb_objc_define_method(rb_cHash, "to_a", nshash_to_a, 0);
+ rb_objc_define_method(rb_cHash, "to_s", nshash_inspect, 0);
+ rb_objc_define_method(rb_cHash, "inspect", nshash_inspect, 0);
+ rb_objc_define_method(rb_cHash, "==", nshash_equal, 1);
+ rb_objc_define_method(rb_cHash, "eql?", nshash_equal, 1);
+ rb_objc_define_method(rb_cHash, "[]", nshash_aref, 1);
+ rb_objc_define_method(rb_cHash, "[]=", nshash_aset, 2);
+ rb_objc_define_method(rb_cHash, "fetch", nshash_fetch, -1);
+ rb_objc_define_method(rb_cHash, "store", nshash_aset, 2);
+ rb_objc_define_method(rb_cHash, "default", nshash_default, -1);
+ rb_objc_define_method(rb_cHash, "default=", nshash_set_default, 1);
+ rb_objc_define_method(rb_cHash, "default_proc", nshash_default_proc, 0);
+ rb_objc_define_method(rb_cHash, "key", nshash_key, 1);
+ rb_objc_define_method(rb_cHash, "index", nshash_index, 1);
+ rb_objc_define_method(rb_cHash, "size", nshash_size, 0);
+ rb_objc_define_method(rb_cHash, "length", nshash_size, 0);
+ rb_objc_define_method(rb_cHash, "empty?", nshash_empty, 0);
+ rb_objc_define_method(rb_cHash, "each_value", nshash_each_value, 0);
+ rb_objc_define_method(rb_cHash, "each_key", nshash_each_key, 0);
+ rb_objc_define_method(rb_cHash, "each_pair", nshash_each_pair, 0);
+ rb_objc_define_method(rb_cHash, "each", nshash_each_pair, 0);
+ rb_objc_define_method(rb_cHash, "keys", nshash_keys, 0);
+ rb_objc_define_method(rb_cHash, "values", nshash_values, 0);
+ rb_objc_define_method(rb_cHash, "values_at", nshash_values_at, -1);
+ rb_objc_define_method(rb_cHash, "shift", nshash_shift, 0);
+ rb_objc_define_method(rb_cHash, "delete", nshash_delete, 1);
+ rb_objc_define_method(rb_cHash, "delete_if", nshash_delete_if, 0);
+ rb_objc_define_method(rb_cHash, "select", nshash_select, 0);
+ rb_objc_define_method(rb_cHash, "reject", nshash_reject, 0);
+ rb_objc_define_method(rb_cHash, "reject!", nshash_reject_bang, 0);
+ rb_objc_define_method(rb_cHash, "clear", nshash_clear, 0);
+ // XXX: #invert is a private method on NSMutableDictionary, so to not
+ // break things we do not implement it.
+ rb_objc_define_method(rb_cHash, "update", nshash_update, 1);
+ rb_objc_define_method(rb_cHash, "merge!", nshash_update, 1);
+ rb_objc_define_method(rb_cHash, "merge", nshash_merge, 1);
+ rb_objc_define_method(rb_cHash, "replace", nshash_replace, 1);
+ rb_objc_define_method(rb_cHash, "assoc", nshash_assoc, 1);
+ rb_objc_define_method(rb_cHash, "rassoc", nshash_rassoc, 1);
+ rb_objc_define_method(rb_cHash, "flatten", nshash_flatten, -1);
+ rb_objc_define_method(rb_cHash, "include?", nshash_has_key, 1);
+ rb_objc_define_method(rb_cHash, "member?", nshash_has_key, 1);
+ rb_objc_define_method(rb_cHash, "key?", nshash_has_key, 1);
+ rb_objc_define_method(rb_cHash, "has_key?", nshash_has_key, 1);
+ rb_objc_define_method(rb_cHash, "value?", nshash_has_value, 1);
+ rb_objc_define_method(rb_cHash, "has_value?", nshash_has_value, 1);
+ rb_objc_define_method(rb_cHash, "compare_by_identity",
+ nshash_compare_by_id, 0);
+ rb_objc_define_method(rb_cHash, "compare_by_identity?",
+ nshash_compare_by_id_p, 0);
+}
+
+// NSDictionary + NSMutableDictionary primitives. These are added automatically
+// on singleton classes of pure NSDictionaries. Our implementation just calls
+// the original methods, by tricking the receiver's class.
+
+#define PREPARE_RCV(x) \
+ Class __old = *(Class *)x; \
+ *(Class *)x = (Class)rb_cCFHash;
+
+#define RESTORE_RCV(x) \
+ *(Class *)x = __old;
+
+static unsigned
+nshash_count(id rcv, SEL sel)
+{
+ PREPARE_RCV(rcv);
+ const unsigned count = [rcv count];
+ RESTORE_RCV(rcv);
+ return count;
+}
+
+static id
+nshash_keyEnumerator(id rcv, SEL sel)
+{
+ PREPARE_RCV(rcv);
+ id keys = [rcv allKeys];
+ RESTORE_RCV(rcv);
+ return [keys objectEnumerator];
+}
+
+static id
+nshash_objectForKey(id rcv, SEL sel, id key)
+{
+ PREPARE_RCV(rcv);
+ id value = [rcv objectForKey:key];
+ RESTORE_RCV(rcv);
+ return value;
+}
+
+static void
+nshash_setObjectForKey(id rcv, SEL sel, id value, id key)
+{
+ PREPARE_RCV(rcv);
+ [rcv setObject:value forKey:key];
+ RESTORE_RCV(rcv);
+}
+
+static void
+nshash_getObjectsAndKeys(id rcv, SEL sel, id *objs, id *keys)
+{
+ PREPARE_RCV(rcv);
+ [rcv getObjects:objs andKeys:keys];
+ RESTORE_RCV(rcv);
+}
+
+static void
+nshash_removeObjectForKey(id rcv, SEL sel, id key)
+{
+ PREPARE_RCV(rcv);
+ [rcv removeObjectForKey:key];
+ RESTORE_RCV(rcv);
+}
+
+static void
+nshash_removeAllObjects(id rcv, SEL sel)
+{
+ PREPARE_RCV(rcv);
+ [rcv removeAllObjects];
+ RESTORE_RCV(rcv);
+}
+
+static bool
+nshash_isEqual(id rcv, SEL sel, id other)
+{
+ PREPARE_RCV(rcv);
+ const bool res = [rcv isEqualToDictionary:other];
+ RESTORE_RCV(rcv);
+ return res;
+}
+
+static bool
+nshash_containsObject(id rcv, SEL sel, id value)
+{
+ PREPARE_RCV(rcv);
+ const bool res = [[rcv allKeysForObject:value] count] > 0;
+ RESTORE_RCV(rcv);
+ return res;
+}
+
+void
+rb_objc_install_hash_primitives(Class klass)
+{
+ rb_objc_install_method2(klass, "count", (IMP)nshash_count);
+ rb_objc_install_method2(klass, "keyEnumerator", (IMP)nshash_keyEnumerator);
+ rb_objc_install_method2(klass, "objectForKey:", (IMP)nshash_objectForKey);
+ rb_objc_install_method2(klass, "getObjects:andKeys:",
+ (IMP)nshash_getObjectsAndKeys);
+ rb_objc_install_method2(klass, "isEqual:", (IMP)nshash_isEqual);
+ rb_objc_install_method2(klass, "containsObject:",
+ (IMP)nshash_containsObject);
+
+ const bool mutable =
+ class_getSuperclass(klass) == (Class)rb_cNSMutableHash;
+
+ if (mutable) {
+ rb_objc_install_method2(klass, "setObject:forKey:",
+ (IMP)nshash_setObjectForKey);
+ rb_objc_install_method2(klass, "removeObjectForKey:",
+ (IMP)nshash_removeObjectForKey);
+ rb_objc_install_method2(klass, "removeAllObjects",
+ (IMP)nshash_removeAllObjects);
+ }
+
+ //rb_objc_define_method(*(VALUE *)klass, "alloc", hash_alloc, 0);
+}
Modified: MacRuby/trunk/hash.c
===================================================================
--- MacRuby/trunk/hash.c 2010-01-26 23:20:58 UTC (rev 3344)
+++ MacRuby/trunk/hash.c 2010-01-26 23:21:44 UTC (rev 3345)
@@ -20,7 +20,7 @@
#include <crt_externs.h>
-static VALUE rb_hash_s_try_convert(VALUE, SEL, VALUE);
+static VALUE rhash_try_convert(VALUE, SEL, VALUE);
VALUE
rb_hash_freeze(VALUE hash)
@@ -28,10 +28,6 @@
return rb_obj_freeze(hash);
}
-VALUE rb_cHash;
-VALUE rb_cCFHash;
-VALUE rb_cNSHash;
-VALUE rb_cNSMutableHash;
VALUE rb_cRubyHash;
typedef struct {
@@ -41,19 +37,17 @@
bool has_proc_default;
} rb_hash_t;
-//#define IS_RHASH(x) (*(VALUE *)x == rb_cRubyHash)
-// XXX temporary
-#define IS_RHASH(x) __is_rhash(*(VALUE *)x)
+#define IS_RHASH(x) __klass_is_rhash(*(VALUE *)x)
#define RHASH(x) ((rb_hash_t *)x)
-static force_inline bool
-__is_rhash(VALUE k)
+static inline bool
+__klass_is_rhash(VALUE k)
{
while (k != 0) {
if (k == rb_cRubyHash) {
return true;
}
- if (k == rb_cCFHash) {
+ if (k == rb_cNSHash) {
return false;
}
k = RCLASS_SUPER(k);
@@ -64,7 +58,7 @@
bool
rb_klass_is_rhash(VALUE klass)
{
- return __is_rhash(klass);
+ return __klass_is_rhash(klass);
}
static VALUE envtbl;
@@ -72,9 +66,16 @@
static void *defaultCache = NULL;
static void *hashCache = NULL;
+static SEL selFlattenBang = 0;
static SEL selDefault = 0;
static SEL selHash = 0;
+static inline long
+rhash_len(VALUE hash)
+{
+ return RHASH(hash)->tbl->num_entries;
+}
+
VALUE
rb_hash(VALUE obj)
{
@@ -123,11 +124,19 @@
st_foreach(table, foreach_safe_i, (st_data_t)&arg);
}
+static void
+rhash_iterate(VALUE hash, int (*func)(ANYARGS), VALUE farg)
+{
+ st_foreach_safe(RHASH(hash)->tbl, func, (st_data_t)farg);
+}
+
+#define rhash_foreach rhash_iterate
+
void
rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
{
if (IS_RHASH(hash)) {
- st_foreach_safe(RHASH(hash)->tbl, func, (st_data_t)farg);
+ rhash_foreach(hash, func, farg);
}
else {
CFIndex count = CFDictionaryGetCount((CFDictionaryRef)hash);
@@ -163,7 +172,7 @@
rb_hash_iterate(VALUE hash, int (*func)(ANYARGS), VALUE farg)
{
if (IS_RHASH(hash)) {
- st_foreach_safe(RHASH(hash)->tbl, func, (st_data_t)farg);
+ rhash_iterate(hash, func, farg);
}
else {
struct rb_cfhash_iterate_context ctx = {func, farg};
@@ -210,8 +219,6 @@
return CFHash((CFTypeRef)a);
}
- // XXX optimize for string
-
return (int)FIX2LONG(rb_hash(a));
}
@@ -221,108 +228,87 @@
};
static VALUE
-hash_alloc(VALUE klass)
+rhash_alloc(VALUE klass, SEL sel)
{
- if (rb_cRubyHash != 0 && (klass == 0 || __is_rhash(klass))) {
- NEWOBJ(hash, rb_hash_t);
- hash->basic.flags = 0;
- hash->basic.klass = klass == 0 ? rb_cRubyHash : klass;
- GC_WB(&hash->tbl, st_init_table(&objhash));
- hash->ifnone = Qnil;
- hash->has_proc_default = false;
- return (VALUE)hash;
+ NEWOBJ(hash, rb_hash_t);
+ hash->basic.flags = 0;
+ hash->basic.klass = klass;
+ GC_WB(&hash->tbl, st_init_table(&objhash));
+ hash->ifnone = Qnil;
+ hash->has_proc_default = false;
+ return (VALUE)hash;
+}
+
+static VALUE
+rhash_dup(VALUE rcv, SEL sel)
+{
+ NEWOBJ(dup, rb_hash_t);
+ dup->basic.flags = 0;
+ dup->basic.klass = rb_cRubyHash;
+ GC_WB(&dup->tbl, st_copy(RHASH(rcv)->tbl));
+ GC_WB(&dup->ifnone, RHASH(rcv)->ifnone);
+ dup->has_proc_default = RHASH(rcv)->has_proc_default;
+ if (OBJ_TAINTED(rcv)) {
+ OBJ_TAINT(dup);
}
- else {
- CFMutableDictionaryRef hash = CFDictionaryCreateMutable(NULL, 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- if (klass != 0 && klass != rb_cNSHash && klass != rb_cNSMutableHash) {
- *(Class *)hash = (Class)klass;
- }
- CFMakeCollectable(hash);
- return (VALUE)hash;
+ return (VALUE)dup;
+}
+
+static VALUE
+rhash_clone(VALUE rcv, SEL sel)
+{
+ VALUE clone = rhash_dup(rcv, 0);
+ if (OBJ_FROZEN(rcv)) {
+ OBJ_FREEZE(clone);
}
+ return clone;
}
VALUE
rb_hash_dup(VALUE rcv)
{
if (IS_RHASH(rcv)) {
- NEWOBJ(dup, rb_hash_t);
- dup->basic.flags = 0;
- dup->basic.klass = rb_cRubyHash;
- GC_WB(&dup->tbl, st_copy(RHASH(rcv)->tbl));
- GC_WB(&dup->ifnone, RHASH(rcv)->ifnone);
- dup->has_proc_default = RHASH(rcv)->has_proc_default;
- return (VALUE)dup;
+ return rhash_dup(rcv, 0);
}
else {
VALUE dup = (VALUE)CFDictionaryCreateMutableCopy(NULL, 0,
(CFDictionaryRef)rcv);
CFMakeCollectable((CFTypeRef)dup);
- if (OBJ_TAINTED(rcv)) {
- OBJ_TAINT(dup);
- }
return dup;
}
}
-static VALUE
-rb_hash_dup_imp(VALUE rcv, SEL sel)
-{
- return rb_hash_dup(rcv);
-}
-
-static VALUE
-rb_hash_clone(VALUE rcv, SEL sel)
-{
- VALUE clone = rb_hash_dup(rcv);
- if (OBJ_FROZEN(rcv)) {
- OBJ_FREEZE(clone);
- }
- return clone;
-}
-
VALUE
rb_hash_new(void)
{
- return hash_alloc(0);
+ return rhash_alloc(rb_cRubyHash, 0);
}
+static VALUE rhash_aset(VALUE hash, SEL sel, VALUE key, VALUE val);
+
VALUE
rb_hash_new_fast(int argc, ...)
{
assert(argc % 2 == 0);
- VALUE hash = hash_alloc(0);
+ VALUE hash = rhash_alloc(rb_cRubyHash, 0);
va_list ar;
va_start(ar, argc);
for (int i = 0; i < argc; i += 2) {
VALUE key = va_arg(ar, VALUE);
VALUE val = va_arg(ar, VALUE);
- rb_hash_aset(hash, key, val);
+ rhash_aset(hash, 0, key, val);
}
va_end(ar);
return hash;
}
-bool _CFDictionaryIsMutable(void *);
-
static inline void
-rb_hash_modify_check(VALUE hash)
+rhash_modify(VALUE hash)
{
- long mask;
- if (IS_RHASH(hash)) {
- mask = RBASIC(hash)->flags;
- }
- else {
- mask = rb_objc_flag_get_mask((const void *)hash);
- if (!_CFDictionaryIsMutable((void *)hash)) {
- mask |= FL_FREEZE;
- }
- }
+ const long mask = RBASIC(hash)->flags;
if ((mask & FL_FREEZE) == FL_FREEZE) {
rb_raise(rb_eRuntimeError, "can't modify frozen/immutable hash");
}
@@ -331,8 +317,6 @@
}
}
-#define rb_hash_modify rb_hash_modify_check
-
/*
* call-seq:
* Hash.new => hash
@@ -369,42 +353,54 @@
*/
static VALUE
-rb_hash_initialize(VALUE hash, SEL sel, int argc, const VALUE *argv)
+rhash_initialize(VALUE hash, SEL sel, int argc, const VALUE *argv)
{
- rb_hash_modify(hash);
-
- //hash = (VALUE)objc_msgSend((id)hash, selInit);
-
- if (IS_RHASH(hash)) {
- if (rb_block_given_p()) {
- if (argc > 0) {
- rb_raise(rb_eArgError, "wrong number of arguments");
- }
- GC_WB(&RHASH(hash)->ifnone, rb_block_proc());
- RHASH(hash)->has_proc_default = true;
+ rhash_modify(hash);
+ if (rb_block_given_p()) {
+ if (argc > 0) {
+ rb_raise(rb_eArgError, "wrong number of arguments");
}
- else {
- VALUE ifnone;
- rb_scan_args(argc, argv, "01", &ifnone);
- if (ifnone != Qnil) {
- GC_WB(&RHASH(hash)->ifnone, ifnone);
- }
+ GC_WB(&RHASH(hash)->ifnone, rb_block_proc());
+ RHASH(hash)->has_proc_default = true;
+ }
+ else {
+ VALUE ifnone;
+ rb_scan_args(argc, argv, "01", &ifnone);
+ if (ifnone != Qnil) {
+ GC_WB(&RHASH(hash)->ifnone, ifnone);
}
}
-
return hash;
}
VALUE
rb_hash_new2(int argc, const VALUE *argv)
{
- VALUE h = hash_alloc(0);
- rb_hash_initialize(h, 0, argc, argv);
+ VALUE h = rhash_alloc(rb_cRubyHash, 0);
+ rhash_initialize(h, 0, argc, argv);
return h;
}
/*
* call-seq:
+ * Hash.try_convert(obj) -> hash or nil
+ *
+ * Try to convert <i>obj</i> into a hash, using to_hash method.
+ * Returns converted hash or nil if <i>obj</i> cannot be converted
+ * for any reason.
+ *
+ * Hash.try_convert({1=>2}) # => {1=>2}
+ * Hash.try_convert("1=>2") # => nil
+ */
+
+static VALUE
+rhash_try_convert(VALUE dummy, SEL sel, VALUE hash)
+{
+ return rb_check_convert_type(hash, T_HASH, "Hash", "to_hash");
+}
+
+/*
+ * call-seq:
* Hash[ [key =>|, value]* ] => hash
*
* Creates a new hash populated with the given objects. Equivalent to
@@ -417,12 +413,12 @@
*/
static VALUE
-rb_hash_s_create(VALUE klass, SEL sel, int argc, VALUE *argv)
+rhash_create(VALUE klass, SEL sel, int argc, VALUE *argv)
{
if (argc == 1) {
- VALUE tmp = rb_hash_s_try_convert(Qnil, 0, argv[0]);
+ VALUE tmp = rhash_try_convert(Qnil, 0, argv[0]);
if (!NIL_P(tmp)) {
- VALUE hash = hash_alloc(klass);
+ VALUE hash = rhash_alloc(klass, 0);
if (IS_RHASH(hash) && IS_RHASH(tmp)) {
GC_WB(&RHASH(hash)->tbl, st_copy(RHASH(tmp)->tbl));
}
@@ -451,13 +447,14 @@
tmp = rb_check_array_type(argv[0]);
if (!NIL_P(tmp)) {
- VALUE hash = hash_alloc(klass);
+ VALUE hash = rhash_alloc(klass, 0);
for (int i = 0; i < RARRAY_LEN(tmp); ++i) {
VALUE v = rb_check_array_type(RARRAY_AT(tmp, i));
if (NIL_P(v)) {
continue;
}
- if (RARRAY_LEN(v) < 1 || 2 < RARRAY_LEN(v)) {
+ const long len = RARRAY_LEN(v);
+ if (len < 1 || 2 < len) {
continue;
}
rb_hash_aset(hash, RARRAY_AT(v, 0), RARRAY_AT(v, 1));
@@ -469,7 +466,7 @@
rb_raise(rb_eArgError, "odd number of arguments for Hash");
}
- VALUE hash = hash_alloc(klass);
+ VALUE hash = rhash_alloc(klass, 0);
for (int i = 0; i < argc; i += 2) {
rb_hash_aset(hash, argv[i], argv[i + 1]);
}
@@ -485,23 +482,6 @@
/*
* call-seq:
- * Hash.try_convert(obj) -> hash or nil
- *
- * Try to convert <i>obj</i> into a hash, using to_hash method.
- * Returns converted hash or nil if <i>obj</i> cannot be converted
- * for any reason.
- *
- * Hash.try_convert({1=>2}) # => {1=>2}
- * Hash.try_convert("1=>2") # => nil
- */
-static VALUE
-rb_hash_s_try_convert(VALUE dummy, SEL sel, VALUE hash)
-{
- return rb_check_convert_type(hash, T_HASH, "Hash", "to_hash");
-}
-
-/*
- * call-seq:
* hsh.rehash -> hsh
*
* Rebuilds the hash based on the current hash values for each key. If
@@ -521,7 +501,7 @@
*/
static int
-rb_hash_rehash_i(VALUE key, VALUE value, VALUE arg)
+rhash_rehash_i(VALUE key, VALUE value, VALUE arg)
{
st_table *tbl = (st_table *)arg;
if (key != Qundef) {
@@ -531,33 +511,14 @@
}
static VALUE
-rb_hash_rehash(VALUE hash, SEL sel)
+rhash_rehash(VALUE hash, SEL sel)
{
- rb_hash_modify_check(hash);
- if (IS_RHASH(hash)) {
- st_table *tbl = st_init_table_with_size(RHASH(hash)->tbl->type,
- RHASH(hash)->tbl->num_entries);
- rb_hash_foreach(hash, rb_hash_rehash_i, (VALUE)tbl);
- //st_free_table(RHASH(hash)->tbl);
- GC_WB(&RHASH(hash)->tbl, tbl);
- }
- else {
- CFIndex count = CFDictionaryGetCount((CFDictionaryRef)hash);
- if (count == 0) {
- return hash;
- }
-
- const void **keys = (const void **)alloca(sizeof(void *) * count);
- const void **values = (const void **)alloca(sizeof(void *) * count);
-
- CFDictionaryGetKeysAndValues((CFDictionaryRef)hash, keys, values);
- CFDictionaryRemoveAllValues((CFMutableDictionaryRef)hash);
-
- for (CFIndex i = 0; i < count; i++) {
- CFDictionarySetValue((CFMutableDictionaryRef)hash,
- (const void *)keys[i], (const void *)values[i]);
- }
- }
+ rhash_modify(hash);
+ st_table *tbl = st_init_table_with_size(RHASH(hash)->tbl->type,
+ RHASH(hash)->tbl->num_entries);
+ rb_hash_foreach(hash, rhash_rehash_i, (VALUE)tbl);
+ //st_free_table(RHASH(hash)->tbl);
+ GC_WB(&RHASH(hash)->tbl, tbl);
return hash;
}
@@ -575,63 +536,63 @@
*
*/
+static inline VALUE
+rhash_lookup(VALUE hash, VALUE key)
+{
+ VALUE val;
+ if (st_lookup(RHASH(hash)->tbl, key, &val)) {
+ return val;
+ }
+ return Qundef;
+}
+
VALUE
-rb_hash_aref(VALUE hash, VALUE key)
+rb_hash_lookup(VALUE hash, VALUE key)
{
+ VALUE val;
if (IS_RHASH(hash)) {
- VALUE val;
- if (!st_lookup(RHASH(hash)->tbl, key, &val)) {
- if (*(VALUE *)hash == rb_cRubyHash
- && RHASH(hash)->ifnone == Qnil) {
- return Qnil;
- }
- return rb_vm_call_with_cache(defaultCache, hash, selDefault,
- 1, &key);
- }
- return val;
+ val = rhash_lookup(hash, key);
}
else {
- VALUE val;
if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)hash,
(const void *)RB2OC(key), (const void **)&val)) {
- return Qnil;
+ val = Qundef;
}
- return OC2RB(val);
}
+ return val == Qundef ? Qnil : val;
}
static VALUE
-rb_hash_aref_imp(VALUE hash, SEL sel, VALUE key)
+rhash_aref(VALUE hash, SEL sel, VALUE key)
{
- return rb_hash_aref(hash, key);
+ VALUE val = rhash_lookup(hash, key);
+ if (val == Qundef) {
+ if (*(VALUE *)hash == rb_cRubyHash
+ && RHASH(hash)->ifnone == Qnil) {
+ return Qnil;
+ }
+ return rb_vm_call_with_cache(defaultCache, hash, selDefault,
+ 1, &key);
+ }
+ return val;
}
-static VALUE
-rb_hash_lookup0(VALUE hash, VALUE key)
+VALUE
+rb_hash_aref(VALUE hash, VALUE key)
{
if (IS_RHASH(hash)) {
- VALUE val;
- if (st_lookup(RHASH(hash)->tbl, key, &val)) {
- return val;
- }
+ return rhash_aref(hash, 0, key);
}
else {
VALUE val;
- if (CFDictionaryGetValueIfPresent((CFDictionaryRef)hash,
+ if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)hash,
(const void *)RB2OC(key), (const void **)&val)) {
- return OC2RB(val);
+ return Qnil;
}
+ return OC2RB(val);
}
- return Qundef;
}
-VALUE
-rb_hash_lookup(VALUE hash, VALUE key)
-{
- VALUE v = rb_hash_lookup0(hash, key);
- return v == Qundef ? Qnil : v;
-}
-
/*
* call-seq:
* hsh.fetch(key [, default] ) => obj
@@ -662,7 +623,7 @@
*/
static VALUE
-rb_hash_fetch(VALUE hash, SEL sel, int argc, VALUE *argv)
+rhash_fetch(VALUE hash, SEL sel, int argc, VALUE *argv)
{
VALUE key, if_none;
rb_scan_args(argc, argv, "11", &key, &if_none);
@@ -672,7 +633,7 @@
rb_warn("block supersedes default value argument");
}
- VALUE v = rb_hash_lookup0(hash, key);
+ VALUE v = rhash_lookup(hash, key);
if (v != Qundef) {
return v;
}
@@ -707,21 +668,18 @@
*/
static VALUE
-rb_hash_default(VALUE hash, SEL sel, int argc, VALUE *argv)
+rhash_default(VALUE hash, SEL sel, int argc, VALUE *argv)
{
VALUE key;
rb_scan_args(argc, argv, "01", &key);
- if (IS_RHASH(hash)) {
- if (RHASH(hash)->has_proc_default) {
- if (argc == 0) {
- return Qnil;
- }
- return rb_funcall(RHASH(hash)->ifnone, id_yield, 2, hash, key);
+ if (RHASH(hash)->has_proc_default) {
+ if (argc == 0) {
+ return Qnil;
}
- return RHASH(hash)->ifnone;
+ return rb_funcall(RHASH(hash)->ifnone, id_yield, 2, hash, key);
}
- return Qnil;
+ return RHASH(hash)->ifnone;
}
/*
@@ -745,20 +703,21 @@
*/
static VALUE
-rb_hash_set_default(VALUE hash, SEL sel, VALUE ifnone)
+rhash_set_default(VALUE hash, SEL sel, VALUE ifnone)
{
- rb_hash_modify(hash);
- if (IS_RHASH(hash)) {
- GC_WB(&RHASH(hash)->ifnone, ifnone);
- RHASH(hash)->has_proc_default = false;
- }
+ rhash_modify(hash);
+ GC_WB(&RHASH(hash)->ifnone, ifnone);
+ RHASH(hash)->has_proc_default = false;
return ifnone;
}
VALUE
rb_hash_set_ifnone(VALUE hash, VALUE ifnone)
{
- return rb_hash_set_default(hash, 0, ifnone);
+ if (IS_RHASH(hash)) {
+ rhash_set_default(hash, 0, ifnone);
+ }
+ return ifnone;
}
/*
@@ -775,26 +734,12 @@
* a #=> [nil, nil, 4]
*/
-
static VALUE
-rb_hash_default_proc(VALUE hash, SEL sel)
+rhash_default_proc(VALUE hash, SEL sel)
{
- if (IS_RHASH(hash)) {
- return RHASH(hash)->has_proc_default ? RHASH(hash)->ifnone : Qnil;
- }
- return Qnil;
+ return RHASH(hash)->has_proc_default ? RHASH(hash)->ifnone : Qnil;
}
-static int
-key_i(VALUE key, VALUE value, VALUE *args)
-{
- if (rb_equal(value, args[0])) {
- args[1] = key;
- return ST_STOP;
- }
- return ST_CONTINUE;
-}
-
/*
* call-seq:
* hsh.key(value) => key
@@ -807,30 +752,66 @@
*
*/
+static int
+key_i(VALUE key, VALUE value, VALUE *args)
+{
+ if (rb_equal(value, args[0])) {
+ args[1] = key;
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
static VALUE
-rb_hash_key(VALUE hash, SEL sel, VALUE value)
+rhash_key(VALUE hash, SEL sel, VALUE value)
{
VALUE args[2] = {value, Qnil};
- rb_hash_iterate(hash, key_i, (st_data_t)args);
+ rhash_iterate(hash, key_i, (st_data_t)args);
return args[1];
}
/* :nodoc: */
static VALUE
-rb_hash_index(VALUE hash, SEL sel, VALUE value)
+rhash_index(VALUE hash, SEL sel, VALUE value)
{
rb_warn("Hash#index is deprecated; use Hash#key");
- return rb_hash_key(hash, 0, value);
+ return rhash_key(hash, 0, value);
}
+/*
+ * call-seq:
+ * hsh.delete(key) => value
+ * hsh.delete(key) {| key | block } => value
+ *
+ * Deletes and returns the value from <i>hsh</i> whose key is
+ * equal to <i>key</i>. If the key is not found, returns nil.
+ * If the optional code block is given and the
+ * key is not found, pass in the key and return the result of
+ * <i>block</i>.
+ *
+ * h = { "a" => 100, "b" => 200 }
+ * h.delete("a") #=> 100
+ * h.delete("z") #=> nil
+ * h.delete("z") { |el| "#{el} not found" } #=> "z not found"
+ *
+ */
+
+static inline VALUE
+rhash_delete_key(VALUE hash, VALUE key)
+{
+ VALUE val;
+ if (st_delete(RHASH(hash)->tbl, &key, &val)) {
+ return val;
+ }
+ return Qundef;
+}
+
VALUE
rb_hash_delete_key(VALUE hash, VALUE key)
{
if (IS_RHASH(hash)) {
- VALUE val;
- if (st_delete(RHASH(hash)->tbl, &key, &val)) {
- return val;
- }
+ rhash_modify(hash);
+ return rhash_delete_key(hash, key);
}
else {
VALUE val;
@@ -841,46 +822,32 @@
(const void *)ockey);
return OC2RB(val);
}
+ return Qundef;
}
- return Qundef;
}
-/*
- * call-seq:
- * hsh.delete(key) => value
- * hsh.delete(key) {| key | block } => value
- *
- * Deletes and returns a key-value pair from <i>hsh</i> whose key is
- * equal to <i>key</i>. If the key is not found, returns the
- * <em>default value</em>. If the optional code block is given and the
- * key is not found, pass in the key and return the result of
- * <i>block</i>.
- *
- * h = { "a" => 100, "b" => 200 }
- * h.delete("a") #=> 100
- * h.delete("z") #=> nil
- * h.delete("z") { |el| "#{el} not found" } #=> "z not found"
- *
- */
-
VALUE
rb_hash_delete(VALUE hash, VALUE key)
{
- rb_hash_modify(hash);
VALUE val = rb_hash_delete_key(hash, key);
if (val != Qundef) {
return val;
}
- if (rb_block_given_p()) {
- return rb_yield(key);
- }
return Qnil;
}
static VALUE
-rb_hash_delete_imp(VALUE hash, SEL sel, VALUE key)
+rhash_delete(VALUE hash, SEL sel, VALUE key)
{
- return rb_hash_delete(hash, key);
+ rhash_modify(hash);
+ VALUE val = rhash_delete_key(hash, key);
+ if (val != Qundef) {
+ return val;
+ }
+ if (rb_block_given_p()) {
+ return rb_yield(key);
+ }
+ return Qnil;
}
/*
@@ -896,42 +863,37 @@
* h #=> {2=>"b", 3=>"c"}
*/
-static VALUE rb_hash_keys_imp(VALUE, SEL);
-
-static VALUE
-rb_hash_shift(VALUE hash, SEL sel)
+static int
+shift_i(VALUE key, VALUE value, VALUE arg)
{
- VALUE keys = rb_hash_keys_imp(hash, 0);
- if (RARRAY_LEN(keys) == 0) {
- if (IS_RHASH(hash)) {
- if (RHASH(hash)->ifnone != Qnil) {
- if (RHASH(hash)->has_proc_default) {
- return rb_funcall(RHASH(hash)->ifnone, id_yield, 2, hash,
- Qnil);
- }
- return RHASH(hash)->ifnone;
- }
- }
- return Qnil;
+ VALUE *ret = (VALUE *)arg;
+ if (key != Qundef) {
+ ret[0] = key;
+ ret[1] = value;
+ return ST_STOP;
}
-
- VALUE key = RARRAY_AT(keys, 0);
- VALUE val = rb_hash_aref(hash, key);
- rb_hash_delete(hash, key);
-
- return rb_assoc_new(key, val);
+ return ST_CONTINUE;
}
-static int
-delete_if_i(VALUE key, VALUE value, VALUE ary)
+static VALUE
+rhash_shift(VALUE hash, SEL sel)
{
- if (key == Qundef) {
- return ST_CONTINUE;
+ VALUE args[2] = {0, 0};
+ rhash_iterate(hash, shift_i, (st_data_t)args);
+ if (args[0] != 0 && args[1] != 0) {
+ rhash_modify(hash);
+ rhash_delete_key(hash, args[0]);
+ return rb_assoc_new(args[0], args[1]);
}
- if (RTEST(rb_yield_values(2, key, value))) {
- rb_ary_push(ary, key);
+
+ if (RHASH(hash)->ifnone != Qnil) {
+ if (RHASH(hash)->has_proc_default) {
+ return rb_funcall(RHASH(hash)->ifnone, id_yield, 2, hash,
+ Qnil);
+ }
+ return RHASH(hash)->ifnone;
}
- return ST_CONTINUE;
+ return Qnil;
}
/*
@@ -946,16 +908,27 @@
*
*/
+static int
+delete_if_i(VALUE key, VALUE value, VALUE ary)
+{
+ if (key != Qundef) {
+ if (RTEST(rb_yield_values(2, key, value))) {
+ rb_ary_push(ary, key);
+ }
+ }
+ return ST_CONTINUE;
+}
+
static VALUE
-rb_hash_delete_if(VALUE hash, SEL sel)
+rhash_delete_if(VALUE hash, SEL sel)
{
RETURN_ENUMERATOR(hash, 0, 0);
- rb_hash_modify(hash);
+ rhash_modify(hash);
VALUE ary = rb_ary_new();
- rb_hash_foreach(hash, delete_if_i, ary);
+ rhash_foreach(hash, delete_if_i, ary);
for (int i = 0, count = RARRAY_LEN(ary); i < count; i++) {
VALUE key = RARRAY_AT(ary, i);
- rb_hash_delete_key(hash, key);
+ rhash_delete_key(hash, key);
}
return hash;
}
@@ -969,12 +942,12 @@
*/
static VALUE
-rb_hash_reject_bang(VALUE hash, SEL sel)
+rhash_reject_bang(VALUE hash, SEL sel)
{
RETURN_ENUMERATOR(hash, 0, 0);
- const long n = RHASH_SIZE(hash);
- rb_hash_delete_if(hash, 0);
- return n == RHASH_SIZE(hash) ? Qnil : hash;
+ const long n = rhash_len(hash);
+ rhash_delete_if(hash, 0);
+ return n == rhash_len(hash) ? Qnil : hash;
}
/*
@@ -988,9 +961,9 @@
*/
static VALUE
-rb_hash_reject(VALUE hash, SEL sel)
+rhash_reject(VALUE hash, SEL sel)
{
- return rb_hash_delete_if(rb_hash_dup(hash), 0);
+ return rhash_delete_if(rhash_dup(hash, 0), 0);
}
/*
@@ -1005,27 +978,15 @@
*/
static VALUE
-rb_hash_values_at(VALUE hash, SEL sel, int argc, VALUE *argv)
+rhash_values_at(VALUE hash, SEL sel, int argc, VALUE *argv)
{
VALUE result = rb_ary_new2(argc);
for (int i = 0; i < argc; i++) {
- rb_ary_push(result, rb_hash_aref(hash, argv[i]));
+ rb_ary_push(result, rhash_aref(hash, 0, argv[i]));
}
return result;
}
-static int
-select_i(VALUE key, VALUE value, VALUE result)
-{
- if (key == Qundef) {
- return ST_CONTINUE;
- }
- if (RTEST(rb_yield_values(2, key, value))) {
- rb_hash_aset(result, key, value);
- }
- return ST_CONTINUE;
-}
-
/*
* call-seq:
* hsh.select {|key, value| block} => a_hash
@@ -1037,12 +998,23 @@
* h.select {|k,v| v < 200} #=> {"a" => 100}
*/
+static int
+select_i(VALUE key, VALUE value, VALUE result)
+{
+ if (key != Qundef) {
+ if (RTEST(rb_yield_values(2, key, value))) {
+ rb_hash_aset(result, key, value);
+ }
+ }
+ return ST_CONTINUE;
+}
+
static VALUE
-rb_hash_select(VALUE hash, SEL sel)
+rhash_select(VALUE hash, SEL sel)
{
RETURN_ENUMERATOR(hash, 0, 0);
VALUE result = rb_hash_new();
- rb_hash_iterate(hash, select_i, result);
+ rhash_iterate(hash, select_i, result);
return result;
}
@@ -1058,15 +1030,10 @@
*/
static VALUE
-rb_hash_clear(VALUE hash, SEL sel)
+rhash_clear(VALUE hash, SEL sel)
{
- rb_hash_modify_check(hash);
- if (IS_RHASH(hash)) {
- st_clear(RHASH(hash)->tbl);
- }
- else {
- CFDictionaryRemoveAllValues((CFMutableDictionaryRef)hash);
- }
+ rhash_modify(hash);
+ st_clear(RHASH(hash)->tbl);
return hash;
}
@@ -1088,12 +1055,19 @@
*
*/
+static VALUE
+rhash_aset(VALUE hash, SEL sel, VALUE key, VALUE val)
+{
+ rhash_modify(hash);
+ st_insert(RHASH(hash)->tbl, key, val);
+ return val;
+}
+
VALUE
rb_hash_aset(VALUE hash, VALUE key, VALUE val)
{
- rb_hash_modify(hash);
if (IS_RHASH(hash)) {
- st_insert(RHASH(hash)->tbl, key, val);
+ rhash_aset(hash, 0, key, val);
}
else {
CFDictionarySetValue((CFMutableDictionaryRef)hash,
@@ -1103,12 +1077,6 @@
return val;
}
-static VALUE
-rb_hash_aset_imp(VALUE hash, SEL sel, VALUE key, VALUE val)
-{
- return rb_hash_aset(hash, key, val);
-}
-
static int
replace_i(VALUE key, VALUE val, VALUE hash)
{
@@ -1131,17 +1099,18 @@
*/
static VALUE
-rb_hash_replace(VALUE hash, SEL sel, VALUE hash2)
+rhash_replace(VALUE hash, SEL sel, VALUE hash2)
{
- rb_hash_modify(hash);
+ rhash_modify(hash);
hash2 = to_hash(hash2);
if (hash == hash2) {
return hash;
}
- rb_hash_clear(hash, 0);
+
+ rhash_clear(hash, 0);
rb_hash_foreach(hash2, replace_i, hash);
- if (IS_RHASH(hash) && IS_RHASH(hash2)) {
+ if (IS_RHASH(hash2)) {
GC_WB(&RHASH(hash)->ifnone, RHASH(hash2)->ifnone);
RHASH(hash)->has_proc_default = RHASH(hash2)->has_proc_default;
}
@@ -1161,21 +1130,21 @@
* h.length #=> 3
*/
+static VALUE
+rhash_size(VALUE hash, SEL sel)
+{
+ return LONG2NUM(rhash_len(hash));
+}
+
long
rb_hash_size(VALUE hash)
{
if (IS_RHASH(hash)) {
- return RHASH(hash)->tbl->num_entries;
+ return rhash_len(hash);
}
return CFDictionaryGetCount((CFDictionaryRef)hash);
}
-static VALUE
-rb_hash_size_imp(VALUE hash, SEL sel)
-{
- return LONG2NUM(rb_hash_size(hash));
-}
-
/*
* call-seq:
* hsh.empty? => true or false
@@ -1187,21 +1156,11 @@
*/
static VALUE
-rb_hash_empty_p(VALUE hash, SEL sel)
+rhash_empty(VALUE hash, SEL sel)
{
- return RHASH_EMPTY_P(hash) ? Qtrue : Qfalse;
+ return rhash_len(hash) == 0 ? Qtrue : Qfalse;
}
-static int
-each_value_i(VALUE key, VALUE value)
-{
- if (key == Qundef) {
- return ST_CONTINUE;
- }
- rb_yield(value);
- return ST_CONTINUE;
-}
-
/*
* call-seq:
* hsh.each_value {| value | block } -> hsh
@@ -1218,24 +1177,23 @@
* 200
*/
-static VALUE
-rb_hash_each_value(VALUE hash, SEL sel)
-{
- RETURN_ENUMERATOR(hash, 0, 0);
- rb_hash_iterate(hash, each_value_i, 0);
- return hash;
-}
-
static int
-each_key_i(VALUE key, VALUE value)
+each_value_i(VALUE key, VALUE value)
{
- if (key == Qundef) {
- return ST_CONTINUE;
+ if (key != Qundef) {
+ rb_yield(value);
}
- rb_yield(key);
return ST_CONTINUE;
}
+static VALUE
+rhash_each_value(VALUE hash, SEL sel)
+{
+ RETURN_ENUMERATOR(hash, 0, 0);
+ rhash_iterate(hash, each_value_i, 0);
+ return hash;
+}
+
/*
* call-seq:
* hsh.each_key {| key | block } -> hsh
@@ -1251,24 +1209,24 @@
* a
* b
*/
-static VALUE
-rb_hash_each_key(VALUE hash, SEL sel)
-{
- RETURN_ENUMERATOR(hash, 0, 0);
- rb_hash_iterate(hash, each_key_i, 0);
- return hash;
-}
static int
-each_pair_i(VALUE key, VALUE value)
+each_key_i(VALUE key, VALUE value)
{
- if (key == Qundef) {
- return ST_CONTINUE;
+ if (key != Qundef) {
+ rb_yield(key);
}
- rb_yield(rb_assoc_new(key, value));
return ST_CONTINUE;
}
+static VALUE
+rhash_each_key(VALUE hash, SEL sel)
+{
+ RETURN_ENUMERATOR(hash, 0, 0);
+ rhash_iterate(hash, each_key_i, 0);
+ return hash;
+}
+
/*
* call-seq:
* hsh.each {| key, value | block } -> hsh
@@ -1287,24 +1245,23 @@
*
*/
-static VALUE
-rb_hash_each_pair(VALUE hash, SEL sel)
-{
- RETURN_ENUMERATOR(hash, 0, 0);
- rb_hash_iterate(hash, each_pair_i, 0);
- return hash;
-}
-
static int
-to_a_i(VALUE key, VALUE value, VALUE ary)
+each_pair_i(VALUE key, VALUE value)
{
- if (key == Qundef) {
- return ST_CONTINUE;
+ if (key != Qundef) {
+ rb_yield(rb_assoc_new(key, value));
}
- rb_ary_push(ary, rb_assoc_new(key, value));
return ST_CONTINUE;
}
+static VALUE
+rhash_each_pair(VALUE hash, SEL sel)
+{
+ RETURN_ENUMERATOR(hash, 0, 0);
+ rhash_iterate(hash, each_pair_i, 0);
+ return hash;
+}
+
/*
* call-seq:
* hsh.to_a -> array
@@ -1316,31 +1273,50 @@
* h.to_a #=> [["c", 300], ["a", 100], ["d", 400]]
*/
+static int
+to_a_i(VALUE key, VALUE value, VALUE ary)
+{
+ if (key != Qundef) {
+ rb_ary_push(ary, rb_assoc_new(key, value));
+ }
+ return ST_CONTINUE;
+}
+
static VALUE
-rb_hash_to_a(VALUE hash, SEL sel)
+rhash_to_a(VALUE hash, SEL sel)
{
VALUE ary = rb_ary_new();
- rb_hash_iterate(hash, to_a_i, ary);
+ rhash_iterate(hash, to_a_i, ary);
if (OBJ_TAINTED(hash)) {
OBJ_TAINT(ary);
}
return ary;
}
+/*
+ * call-seq:
+ * hsh.to_s => string
+ * hsh.inspect => string
+ *
+ * Return the contents of this hash as a string.
+ *
+ * h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300 }
+ * h.to_s #=> "{\"c\"=>300, \"a\"=>100, \"d\"=>400}"
+ */
+
static int
inspect_i(VALUE key, VALUE value, VALUE str)
{
- if (key == Qundef) {
- return ST_CONTINUE;
+ if (key != Qundef) {
+ if (RSTRING_LEN(str) > 1) {
+ rb_str_cat2(str, ", ");
+ }
+ VALUE str2 = rb_inspect(key);
+ rb_str_buf_append(str, str2);
+ rb_str_buf_cat2(str, "=>");
+ str2 = rb_inspect(value);
+ rb_str_buf_append(str, str2);
}
- if (RSTRING_LEN(str) > 1) {
- rb_str_cat2(str, ", ");
- }
- VALUE str2 = rb_inspect(key);
- rb_str_buf_append(str, str2);
- rb_str_buf_cat2(str, "=>");
- str2 = rb_inspect(value);
- rb_str_buf_append(str, str2);
return ST_CONTINUE;
}
@@ -1351,25 +1327,14 @@
return rb_usascii_str_new2("{...}");
}
VALUE str = rb_str_buf_new2("{");
- rb_hash_iterate(hash, inspect_i, str);
+ rhash_iterate(hash, inspect_i, str);
rb_str_buf_cat2(str, "}");
OBJ_INFECT(str, hash);
return str;
}
-/*
- * call-seq:
- * hsh.to_s => string
- * hsh.inspect => string
- *
- * Return the contents of this hash as a string.
- *
- * h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300 }
- * h.to_s #=> "{\"c\"=>300, \"a\"=>100, \"d\"=>400}"
- */
-
static VALUE
-rb_hash_inspect(VALUE hash, SEL sel)
+rhash_inspect(VALUE hash, SEL sel)
{
if (RHASH_EMPTY_P(hash)) {
return rb_usascii_str_new2("{}");
@@ -1385,21 +1350,11 @@
*/
static VALUE
-rb_hash_to_hash(VALUE hash, SEL sel)
+rhash_to_hash(VALUE hash, SEL sel)
{
return hash;
}
-static int
-keys_i(VALUE key, VALUE value, VALUE ary)
-{
- if (key == Qundef) {
- return ST_CONTINUE;
- }
- rb_ary_push(ary, key);
- return ST_CONTINUE;
-}
-
/*
* call-seq:
* hsh.keys => array
@@ -1412,30 +1367,31 @@
*
*/
+static int
+keys_i(VALUE key, VALUE value, VALUE ary)
+{
+ if (key != Qundef) {
+ rb_ary_push(ary, key);
+ }
+ return ST_CONTINUE;
+}
+
static VALUE
-rb_hash_keys_imp(VALUE hash, SEL sel)
+rhash_keys(VALUE hash, SEL sel)
{
VALUE ary = rb_ary_new();
- rb_hash_iterate(hash, keys_i, ary);
+ rhash_iterate(hash, keys_i, ary);
return ary;
}
VALUE
rb_hash_keys(VALUE hash)
{
- return rb_hash_keys_imp(hash, 0);
+ VALUE ary = rb_ary_new();
+ rb_hash_iterate(hash, keys_i, ary);
+ return ary;
}
-static int
-values_i(VALUE key, VALUE value, VALUE ary)
-{
- if (key == Qundef) {
- return ST_CONTINUE;
- }
- rb_ary_push(ary, value);
- return ST_CONTINUE;
-}
-
/*
* call-seq:
* hsh.values => array
@@ -1448,11 +1404,20 @@
*
*/
+static int
+values_i(VALUE key, VALUE value, VALUE ary)
+{
+ if (key != Qundef) {
+ rb_ary_push(ary, value);
+ }
+ return ST_CONTINUE;
+}
+
static VALUE
-rb_hash_values(VALUE hash, SEL sel)
+rhash_values(VALUE hash, SEL sel)
{
VALUE ary = rb_ary_new();
- rb_hash_iterate(hash, values_i, ary);
+ rhash_iterate(hash, values_i, ary);
return ary;
}
@@ -1472,10 +1437,16 @@
*/
static VALUE
-rb_hash_has_key_imp(VALUE hash, SEL sel, VALUE key)
+rhash_has_key(VALUE hash, SEL sel, VALUE key)
{
+ return st_lookup(RHASH(hash)->tbl, key, 0) ? Qtrue : Qfalse;
+}
+
+VALUE
+rb_hash_has_key(VALUE hash, VALUE key)
+{
if (IS_RHASH(hash)) {
- return st_lookup(RHASH(hash)->tbl, key, 0) ? Qtrue : Qfalse;
+ return rhash_has_key(hash, 0, key);
}
else {
return CFDictionaryContainsKey((CFDictionaryRef)hash,
@@ -1483,12 +1454,6 @@
}
}
-VALUE
-rb_hash_has_key(VALUE hash, VALUE key)
-{
- return rb_hash_has_key_imp(hash, 0, key);
-}
-
/*
* call-seq:
* hsh.has_value?(value) => true or false
@@ -1503,33 +1468,45 @@
*/
static int
-rb_hash_search_value(VALUE key, VALUE value, VALUE arg)
+search_value(VALUE key, VALUE value, VALUE arg)
{
VALUE *data = (VALUE *)arg;
- if (key == Qundef) {
- return ST_CONTINUE;
+ if (key != Qundef) {
+ if (rb_equal(value, data[1])) {
+ data[0] = Qtrue;
+ return ST_STOP;
+ }
}
- if (rb_equal(value, data[1])) {
- data[0] = Qtrue;
- return ST_STOP;
- }
return ST_CONTINUE;
}
static VALUE
-rb_hash_has_value(VALUE hash, SEL sel, VALUE val)
+rhash_has_value(VALUE hash, SEL sel, VALUE val)
{
- if (IS_RHASH(hash)) {
- VALUE data[2] = {Qfalse, val};
- rb_hash_foreach(hash, rb_hash_search_value, (VALUE)data);
- return data[0];
- }
- else {
- return CFDictionaryContainsValue((CFDictionaryRef)hash,
- (const void *)RB2OC(val)) ? Qtrue : Qfalse;
- }
+ VALUE data[2] = {Qfalse, val};
+ rhash_foreach(hash, search_value, (VALUE)data);
+ return data[0];
}
+/*
+ * call-seq:
+ * hsh == other_hash => true or false
+ *
+ * Equality---Two hashes are equal if they each contain the same number
+ * of keys and if each key-value pair is equal to (according to
+ * <code>Object#==</code>) the corresponding elements in the other
+ * hash.
+ *
+ * h1 = { "a" => 1, "c" => 2 }
+ * h2 = { 7 => 35, "c" => 2, "a" => 1 }
+ * h3 = { "a" => 1, "c" => 2, 7 => 35 }
+ * h4 = { "a" => 1, "d" => 2, "f" => 35 }
+ * h1 == h2 #=> false
+ * h2 == h3 #=> true
+ * h3 == h4 #=> false
+ *
+ */
+
struct equal_data {
VALUE result;
st_table *tbl;
@@ -1595,7 +1572,7 @@
if (RHASH_SIZE(hash1) != RHASH_SIZE(hash2)) {
return Qfalse;
}
- if (IS_RHASH(hash1) && IS_RHASH(hash2)) {
+ if (IS_RHASH(hash2)) {
struct equal_data data;
data.tbl = RHASH(hash2)->tbl;
data.eql = eql;
@@ -1606,27 +1583,8 @@
}
}
-/*
- * call-seq:
- * hsh == other_hash => true or false
- *
- * Equality---Two hashes are equal if they each contain the same number
- * of keys and if each key-value pair is equal to (according to
- * <code>Object#==</code>) the corresponding elements in the other
- * hash.
- *
- * h1 = { "a" => 1, "c" => 2 }
- * h2 = { 7 => 35, "c" => 2, "a" => 1 }
- * h3 = { "a" => 1, "c" => 2, 7 => 35 }
- * h4 = { "a" => 1, "d" => 2, "f" => 35 }
- * h1 == h2 #=> false
- * h2 == h3 #=> true
- * h3 == h4 #=> false
- *
- */
-
static VALUE
-rb_hash_equal_imp(VALUE hash1, SEL sel, VALUE hash2)
+rhash_equal(VALUE hash1, SEL sel, VALUE hash2)
{
return hash_equal(hash1, hash2, false);
}
@@ -1646,21 +1604,11 @@
*/
static VALUE
-rb_hash_eql(VALUE hash1, SEL sel, VALUE hash2)
+rhash_eql(VALUE hash1, SEL sel, VALUE hash2)
{
return hash_equal(hash1, hash2, true);
}
-static int
-rb_hash_invert_i(VALUE key, VALUE value, VALUE hash)
-{
- if (key == Qundef) {
- return ST_CONTINUE;
- }
- rb_hash_aset(hash, value, key);
- return ST_CONTINUE;
-}
-
/*
* call-seq:
* hsh.invert -> aHash
@@ -1673,35 +1621,21 @@
*
*/
-static VALUE
-rb_hash_invert(VALUE hash, SEL sel)
-{
- VALUE h = rb_hash_new();
- rb_hash_foreach(hash, rb_hash_invert_i, h);
- return h;
-}
-
static int
-rb_hash_update_i(VALUE key, VALUE value, VALUE hash)
+invert_i(VALUE key, VALUE value, VALUE hash)
{
- if (key == Qundef) {
- return ST_CONTINUE;
+ if (key != Qundef) {
+ rhash_aset(hash, 0, value, key);
}
- rb_hash_aset(hash, key, value);
return ST_CONTINUE;
}
-static int
-rb_hash_update_block_i(VALUE key, VALUE value, VALUE hash)
+static VALUE
+rhash_invert(VALUE hash, SEL sel)
{
- if (key == Qundef) {
- return ST_CONTINUE;
- }
- if (rb_hash_has_key_imp(hash, 0, key)) {
- value = rb_yield_values(3, key, rb_hash_aref(hash, key), value);
- }
- rb_hash_aset(hash, key, value);
- return ST_CONTINUE;
+ VALUE h = rb_hash_new();
+ rhash_foreach(hash, invert_i, h);
+ return h;
}
/*
@@ -1727,15 +1661,36 @@
* #=> {"a"=>100, "b"=>200, "c"=>300}
*/
+static int
+update_i(VALUE key, VALUE value, VALUE hash)
+{
+ if (key != Qundef) {
+ rhash_aset(hash, 0, key, value);
+ }
+ return ST_CONTINUE;
+}
+
+static int
+update_block_i(VALUE key, VALUE value, VALUE hash)
+{
+ if (key != Qundef) {
+ if (rhash_has_key(hash, 0, key)) {
+ value = rb_yield_values(3, key, rhash_aref(hash, 0, key), value);
+ }
+ rhash_aset(hash, 0, key, value);
+ }
+ return ST_CONTINUE;
+}
+
static VALUE
-rb_hash_update(VALUE hash1, SEL sel, VALUE hash2)
+rhash_update(VALUE hash1, SEL sel, VALUE hash2)
{
hash2 = to_hash(hash2);
if (rb_block_given_p()) {
- rb_hash_foreach(hash2, rb_hash_update_block_i, hash1);
+ rb_hash_foreach(hash2, update_block_i, hash1);
}
else {
- rb_hash_foreach(hash2, rb_hash_update_i, hash1);
+ rb_hash_foreach(hash2, update_i, hash1);
}
return hash1;
}
@@ -1757,24 +1712,11 @@
*/
static VALUE
-rb_hash_merge(VALUE hash1, SEL sel, VALUE hash2)
+rhash_merge(VALUE hash1, SEL sel, VALUE hash2)
{
- return rb_hash_update(rb_hash_dup(hash1), 0, hash2);
+ return rhash_update(rhash_dup(hash1, 0), 0, hash2);
}
-static int
-assoc_i(VALUE key, VALUE val, VALUE *args)
-{
- if (key == Qundef) {
- return ST_CONTINUE;
- }
- if (RTEST(rb_equal(args[0], key))) {
- args[1] = rb_assoc_new(key, val);
- return ST_STOP;
- }
- return ST_CONTINUE;
-}
-
/*
* call-seq:
* hash.assoc(obj) -> an_array or nil
@@ -1789,27 +1731,26 @@
* h.assoc("foo") #=> nil
*/
-VALUE
-rb_hash_assoc(VALUE hash, SEL sel, VALUE obj)
-{
- VALUE args[2] = {obj, Qnil};
- rb_hash_foreach(hash, assoc_i, (st_data_t)args);
- return args[1];
-}
-
static int
-rassoc_i(VALUE key, VALUE val, VALUE *args)
+assoc_i(VALUE key, VALUE val, VALUE *args)
{
- if (key == Qundef) {
- return ST_CONTINUE;
+ if (key != Qundef) {
+ if (RTEST(rb_equal(args[0], key))) {
+ args[1] = rb_assoc_new(key, val);
+ return ST_STOP;
+ }
}
- if (RTEST(rb_equal(args[0], val))) {
- args[1] = rb_assoc_new(key, val);
- return ST_STOP;
- }
return ST_CONTINUE;
}
+static VALUE
+rhash_assoc(VALUE hash, SEL sel, VALUE obj)
+{
+ VALUE args[2] = {obj, Qnil};
+ rhash_foreach(hash, assoc_i, (st_data_t)args);
+ return args[1];
+}
+
/*
* call-seq:
* hash.rassoc(key) -> an_array or nil
@@ -1823,11 +1764,23 @@
* a.rassoc("four") #=> nil
*/
+static int
+rassoc_i(VALUE key, VALUE val, VALUE *args)
+{
+ if (key != Qundef) {
+ if (RTEST(rb_equal(args[0], val))) {
+ args[1] = rb_assoc_new(key, val);
+ return ST_STOP;
+ }
+ }
+ return ST_CONTINUE;
+}
+
VALUE
-rb_hash_rassoc(VALUE hash, SEL sel, VALUE obj)
+rhash_rassoc(VALUE hash, SEL sel, VALUE obj)
{
VALUE args[2] = {obj, Qnil};
- rb_hash_foreach(hash, rassoc_i, (st_data_t)args);
+ rhash_foreach(hash, rassoc_i, (st_data_t)args);
return args[1];
}
@@ -1848,15 +1801,15 @@
*/
static VALUE
-rb_hash_flatten(VALUE hash, SEL sel, int argc, VALUE *argv)
+rhash_flatten(VALUE hash, SEL sel, int argc, VALUE *argv)
{
- VALUE tmp, ary = rb_hash_to_a(hash, 0);
+ VALUE tmp, ary = rhash_to_a(hash, 0);
if (argc == 0) {
argc = 1;
tmp = INT2FIX(1);
argv = &tmp;
}
- rb_funcall2(ary, rb_intern("flatten!"), argc, argv);
+ rb_vm_call(ary, selFlattenBang, argc, argv, false);
return ary;
}
@@ -1877,9 +1830,9 @@
*/
static VALUE
-rb_hash_compare_by_id(VALUE hash, SEL sel)
+rhash_compare_by_id(VALUE hash, SEL sel)
{
- rb_hash_modify(hash);
+ rhash_modify(hash);
// TODO
return hash;
}
@@ -1894,7 +1847,7 @@
*/
static VALUE
-rb_hash_compare_by_id_p(VALUE hash, SEL sel)
+rhash_compare_by_id_p(VALUE hash, SEL sel)
{
// TODO
return Qfalse;
@@ -2522,7 +2475,7 @@
static VALUE
env_reject(VALUE rcv, SEL sel)
{
- return rb_hash_delete_if(env_to_hash(Qnil, 0), 0);
+ return rhash_delete_if(env_to_hash(Qnil, 0), 0);
}
static VALUE
@@ -2548,7 +2501,7 @@
static VALUE
env_invert(VALUE rcv, SEL sel)
{
- return rb_hash_invert(env_to_hash(Qnil, 0), 0);
+ return rhash_invert(env_to_hash(Qnil, 0), 0);
}
static int
@@ -2603,13 +2556,6 @@
return env;
}
-#define PREPARE_RCV(x) \
- Class old = *(Class *)x; \
- *(Class *)x = (Class)rb_cCFHash;
-
-#define RESTORE_RCV(x) \
- *(Class *)x = old;
-
bool
rb_objc_hash_is_pure(VALUE hash)
{
@@ -2629,125 +2575,6 @@
return true;
}
-static CFIndex
-imp_rb_hash_count(void *rcv, SEL sel)
-{
- CFIndex count;
- PREPARE_RCV(rcv);
- count = CFDictionaryGetCount((CFDictionaryRef)rcv);
- RESTORE_RCV(rcv);
- return count;
-}
-
-static void *
-imp_rb_hash_keyEnumerator(void *rcv, SEL sel)
-{
- static SEL objectEnumerator = 0;
- PREPARE_RCV(rcv);
- void *keys = (void *)rb_hash_keys_imp((VALUE)rcv, 0);
- RESTORE_RCV(rcv);
- if (objectEnumerator == 0) {
- objectEnumerator = sel_registerName("objectEnumerator");
- }
- return objc_msgSend(keys, objectEnumerator);
-}
-
-static void *
-imp_rb_hash_objectForKey(void *rcv, SEL sel, void *key)
-{
- void *obj;
- PREPARE_RCV(rcv);
- if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)rcv, (const void *)key,
- (const void **)&obj)) {
- obj = NULL;
- }
- RESTORE_RCV(rcv);
- return obj;
-}
-
-static void
-imp_rb_hash_setObjectForKey(void *rcv, SEL sel, void *obj, void *key)
-{
- PREPARE_RCV(rcv);
- CFDictionarySetValue((CFMutableDictionaryRef)rcv, (const void *)key,
- (const void *)obj);
- RESTORE_RCV(rcv);
-}
-
-static void
-imp_rb_hash_getObjectsAndKeys(void *rcv, SEL sel, void **objs, void **keys)
-{
- PREPARE_RCV(rcv);
- CFDictionaryGetKeysAndValues((CFDictionaryRef)rcv, (const void **)keys,
- (const void **)objs);
- RESTORE_RCV(rcv);
-}
-
-static void
-imp_rb_hash_removeObjectForKey(void *rcv, SEL sel, void *key)
-{
- PREPARE_RCV(rcv);
- CFDictionaryRemoveValue((CFMutableDictionaryRef)rcv, (const void *)key);
- RESTORE_RCV(rcv);
-}
-
-static void
-imp_rb_hash_removeAllObjects(void *rcv, SEL sel)
-{
- PREPARE_RCV(rcv);
- CFDictionaryRemoveAllValues((CFMutableDictionaryRef)rcv);
- RESTORE_RCV(rcv);
-}
-
-static bool
-imp_rb_hash_isEqual(void *rcv, SEL sel, void *other)
-{
- bool res;
- PREPARE_RCV(rcv);
- res = CFEqual((CFTypeRef)rcv, (CFTypeRef)other);
- RESTORE_RCV(rcv);
- return res;
-}
-
-static bool
-imp_rb_hash_containsObject(void *rcv, SEL sel, void *obj)
-{
- bool res;
- PREPARE_RCV(rcv);
- res = CFDictionaryContainsValue((CFTypeRef)rcv, (const void *)obj);
- RESTORE_RCV(rcv);
- return res;
-}
-
-void
-rb_objc_install_hash_primitives(Class klass)
-{
- rb_objc_install_method2(klass, "count", (IMP)imp_rb_hash_count);
- rb_objc_install_method2(klass, "keyEnumerator",
- (IMP)imp_rb_hash_keyEnumerator);
- rb_objc_install_method2(klass, "objectForKey:",
- (IMP)imp_rb_hash_objectForKey);
- rb_objc_install_method2(klass, "getObjects:andKeys:",
- (IMP)imp_rb_hash_getObjectsAndKeys);
- rb_objc_install_method2(klass, "isEqual:", (IMP)imp_rb_hash_isEqual);
- rb_objc_install_method2(klass, "containsObject:",
- (IMP)imp_rb_hash_containsObject);
-
- const bool mutable = class_getSuperclass(klass)
- == (Class)rb_cNSMutableHash;
-
- if (mutable) {
- rb_objc_install_method2(klass, "setObject:forKey:",
- (IMP)imp_rb_hash_setObjectForKey);
- rb_objc_install_method2(klass, "removeObjectForKey:",
- (IMP)imp_rb_hash_removeObjectForKey);
- rb_objc_install_method2(klass, "removeAllObjects",
- (IMP)imp_rb_hash_removeAllObjects);
- }
-
- rb_objc_define_method(*(VALUE *)klass, "alloc", hash_alloc, 0);
-}
-
static VALUE rb_cRubyHashKeyEnumerator;
typedef struct {
@@ -2831,15 +2658,14 @@
*
*/
-#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
-# define NSCFDICTIONARY_CNAME "NSCFDictionary"
-#else
-# define NSCFDICTIONARY_CNAME "__NSCFDictionary"
-#endif
+void Init_NSDictionary(void);
void
Init_Hash(void)
{
+ Init_NSDictionary();
+
+ selFlattenBang = sel_registerName("flatten!:");
selDefault = sel_registerName("default:");
selHash = sel_registerName("hash");
defaultCache = rb_vm_get_call_cache(selDefault);
@@ -2847,86 +2673,70 @@
id_yield = rb_intern("yield");
- rb_cCFHash = (VALUE)objc_getClass(NSCFDICTIONARY_CNAME);
- assert(rb_cCFHash != 0);
- rb_cHash = rb_cNSHash = (VALUE)objc_getClass("NSDictionary");
- rb_cNSMutableHash = (VALUE)objc_getClass("NSMutableDictionary");
-
- rb_include_module(rb_cHash, rb_mEnumerable);
-
- /* to return mutable copies */
- rb_objc_define_method(rb_cHash, "dup", rb_hash_dup_imp, 0);
- rb_objc_define_method(rb_cHash, "clone", rb_hash_clone, 0);
-
- rb_objc_define_method(*(VALUE *)rb_cHash, "[]", rb_hash_s_create, -1);
- rb_objc_define_method(*(VALUE *)rb_cHash, "try_convert", rb_hash_s_try_convert, 1);
- rb_objc_define_method(rb_cHash, "initialize", rb_hash_initialize, -1);
- rb_objc_define_method(rb_cHash, "initialize_copy", rb_hash_replace, 1);
- rb_objc_define_method(rb_cHash, "rehash", rb_hash_rehash, 0);
-
- rb_objc_define_method(rb_cHash, "to_hash", rb_hash_to_hash, 0);
- rb_objc_define_method(rb_cHash, "to_a", rb_hash_to_a, 0);
- rb_objc_define_method(rb_cHash, "to_s", rb_hash_inspect, 0);
- rb_objc_define_method(rb_cHash, "inspect", rb_hash_inspect, 0);
-
- rb_objc_define_method(rb_cHash, "==", rb_hash_equal_imp, 1);
- rb_objc_define_method(rb_cHash, "[]", rb_hash_aref_imp, 1);
- rb_objc_define_method(rb_cHash, "eql?", rb_hash_eql, 1);
- rb_objc_define_method(rb_cHash, "fetch", rb_hash_fetch, -1);
- rb_objc_define_method(rb_cHash, "[]=", rb_hash_aset_imp, 2);
- rb_objc_define_method(rb_cHash, "store", rb_hash_aset_imp, 2);
- rb_objc_define_method(rb_cHash, "default", rb_hash_default, -1);
- rb_objc_define_method(rb_cHash, "default=", rb_hash_set_default, 1);
- rb_objc_define_method(rb_cHash, "default_proc", rb_hash_default_proc, 0);
- rb_objc_define_method(rb_cHash, "key", rb_hash_key, 1);
- rb_objc_define_method(rb_cHash, "index", rb_hash_index, 1);
- rb_objc_define_method(rb_cHash, "size", rb_hash_size_imp, 0);
- rb_objc_define_method(rb_cHash, "length", rb_hash_size_imp, 0);
- rb_objc_define_method(rb_cHash, "empty?", rb_hash_empty_p, 0);
-
- rb_objc_define_method(rb_cHash, "each_value", rb_hash_each_value, 0);
- rb_objc_define_method(rb_cHash, "each_key", rb_hash_each_key, 0);
- rb_objc_define_method(rb_cHash, "each_pair", rb_hash_each_pair, 0);
- rb_objc_define_method(rb_cHash, "each", rb_hash_each_pair, 0);
-
- rb_objc_define_method(rb_cHash, "keys", rb_hash_keys_imp, 0);
- rb_objc_define_method(rb_cHash, "values", rb_hash_values, 0);
- rb_objc_define_method(rb_cHash, "values_at", rb_hash_values_at, -1);
-
- rb_objc_define_method(rb_cHash, "shift", rb_hash_shift, 0);
- rb_objc_define_method(rb_cHash, "delete", rb_hash_delete_imp, 1);
- rb_objc_define_method(rb_cHash, "delete_if", rb_hash_delete_if, 0);
- rb_objc_define_method(rb_cHash, "select", rb_hash_select, 0);
- rb_objc_define_method(rb_cHash, "reject", rb_hash_reject, 0);
- rb_objc_define_method(rb_cHash, "reject!", rb_hash_reject_bang, 0);
- rb_objc_define_method(rb_cHash, "clear", rb_hash_clear, 0);
- rb_objc_define_method(rb_cHash, "invert", rb_hash_invert, 0);
-
- /* to override the private -[NSMutableDictionary invert] method */
- rb_objc_define_method(rb_cNSMutableHash, "invert", rb_hash_invert, 0);
-
- rb_objc_define_method(rb_cHash, "update", rb_hash_update, 1);
- rb_objc_define_method(rb_cHash, "replace", rb_hash_replace, 1);
- rb_objc_define_method(rb_cHash, "merge!", rb_hash_update, 1);
- rb_objc_define_method(rb_cHash, "merge", rb_hash_merge, 1);
- rb_objc_define_method(rb_cHash, "assoc", rb_hash_assoc, 1);
- rb_objc_define_method(rb_cHash, "rassoc", rb_hash_rassoc, 1);
- rb_objc_define_method(rb_cHash, "flatten", rb_hash_flatten, -1);
-
- rb_objc_define_method(rb_cHash, "include?", rb_hash_has_key_imp, 1);
- rb_objc_define_method(rb_cHash, "member?", rb_hash_has_key_imp, 1);
- rb_objc_define_method(rb_cHash, "has_key?", rb_hash_has_key_imp, 1);
- rb_objc_define_method(rb_cHash, "has_value?", rb_hash_has_value, 1);
- rb_objc_define_method(rb_cHash, "key?", rb_hash_has_key_imp, 1);
- rb_objc_define_method(rb_cHash, "value?", rb_hash_has_value, 1);
-
- rb_objc_define_method(rb_cHash, "compare_by_identity", rb_hash_compare_by_id, 0);
- rb_objc_define_method(rb_cHash, "compare_by_identity?", rb_hash_compare_by_id_p, 0);
-
rb_cRubyHash = rb_define_class("Hash", rb_cNSMutableHash);
rb_objc_define_method(*(VALUE *)rb_cRubyHash, "new",
rb_class_new_instance_imp, -1);
- rb_objc_define_method(*(VALUE *)rb_cRubyHash, "alloc", hash_alloc, 0);
+ rb_objc_define_method(*(VALUE *)rb_cRubyHash, "alloc", rhash_alloc, 0);
+ rb_objc_define_method(*(VALUE *)rb_cRubyHash, "[]", rhash_create, -1);
+ rb_objc_define_method(*(VALUE *)rb_cRubyHash, "try_convert",
+ rhash_try_convert, 1);
+ rb_objc_define_method(rb_cRubyHash, "initialize", rhash_initialize, -1);
+ rb_objc_define_method(rb_cRubyHash, "initialize_copy", rhash_replace, 1);
+ rb_objc_define_method(rb_cRubyHash, "dup", rhash_dup, 0);
+ rb_objc_define_method(rb_cRubyHash, "clone", rhash_clone, 0);
+ rb_objc_define_method(rb_cRubyHash, "rehash", rhash_rehash, 0);
+ rb_objc_define_method(rb_cRubyHash, "to_hash", rhash_to_hash, 0);
+ rb_objc_define_method(rb_cRubyHash, "to_a", rhash_to_a, 0);
+ rb_objc_define_method(rb_cRubyHash, "to_s", rhash_inspect, 0);
+ rb_objc_define_method(rb_cRubyHash, "inspect", rhash_inspect, 0);
+ rb_objc_define_method(rb_cRubyHash, "==", rhash_equal, 1);
+ rb_objc_define_method(rb_cRubyHash, "[]", rhash_aref, 1);
+ rb_objc_define_method(rb_cRubyHash, "eql?", rhash_eql, 1);
+ rb_objc_define_method(rb_cRubyHash, "fetch", rhash_fetch, -1);
+ rb_objc_define_method(rb_cRubyHash, "[]=", rhash_aset, 2);
+ rb_objc_define_method(rb_cRubyHash, "store", rhash_aset, 2);
+ rb_objc_define_method(rb_cRubyHash, "default", rhash_default, -1);
+ rb_objc_define_method(rb_cRubyHash, "default=", rhash_set_default, 1);
+ rb_objc_define_method(rb_cRubyHash, "default_proc",
+ rhash_default_proc, 0);
+ rb_objc_define_method(rb_cRubyHash, "key", rhash_key, 1);
+ rb_objc_define_method(rb_cRubyHash, "index", rhash_index, 1);
+ rb_objc_define_method(rb_cRubyHash, "size", rhash_size, 0);
+ rb_objc_define_method(rb_cRubyHash, "length", rhash_size, 0);
+ rb_objc_define_method(rb_cRubyHash, "empty?", rhash_empty, 0);
+ rb_objc_define_method(rb_cRubyHash, "each_value", rhash_each_value, 0);
+ rb_objc_define_method(rb_cRubyHash, "each_key", rhash_each_key, 0);
+ rb_objc_define_method(rb_cRubyHash, "each_pair", rhash_each_pair, 0);
+ rb_objc_define_method(rb_cRubyHash, "each", rhash_each_pair, 0);
+ rb_objc_define_method(rb_cRubyHash, "keys", rhash_keys, 0);
+ rb_objc_define_method(rb_cRubyHash, "values", rhash_values, 0);
+ rb_objc_define_method(rb_cRubyHash, "values_at", rhash_values_at, -1);
+ rb_objc_define_method(rb_cRubyHash, "shift", rhash_shift, 0);
+ rb_objc_define_method(rb_cRubyHash, "delete", rhash_delete, 1);
+ rb_objc_define_method(rb_cRubyHash, "delete_if", rhash_delete_if, 0);
+ rb_objc_define_method(rb_cRubyHash, "select", rhash_select, 0);
+ rb_objc_define_method(rb_cRubyHash, "reject", rhash_reject, 0);
+ rb_objc_define_method(rb_cRubyHash, "reject!", rhash_reject_bang, 0);
+ rb_objc_define_method(rb_cRubyHash, "clear", rhash_clear, 0);
+ rb_objc_define_method(rb_cRubyHash, "invert", rhash_invert, 0);
+ rb_objc_define_method(rb_cRubyHash, "update", rhash_update, 1);
+ rb_objc_define_method(rb_cRubyHash, "replace", rhash_replace, 1);
+ rb_objc_define_method(rb_cRubyHash, "merge!", rhash_update, 1);
+ rb_objc_define_method(rb_cRubyHash, "merge", rhash_merge, 1);
+ rb_objc_define_method(rb_cRubyHash, "assoc", rhash_assoc, 1);
+ rb_objc_define_method(rb_cRubyHash, "rassoc", rhash_rassoc, 1);
+ rb_objc_define_method(rb_cRubyHash, "flatten", rhash_flatten, -1);
+ rb_objc_define_method(rb_cRubyHash, "include?", rhash_has_key, 1);
+ rb_objc_define_method(rb_cRubyHash, "member?", rhash_has_key, 1);
+ rb_objc_define_method(rb_cRubyHash, "has_key?", rhash_has_key, 1);
+ rb_objc_define_method(rb_cRubyHash, "has_value?", rhash_has_value, 1);
+ rb_objc_define_method(rb_cRubyHash, "key?", rhash_has_key, 1);
+ rb_objc_define_method(rb_cRubyHash, "value?", rhash_has_value, 1);
+ rb_objc_define_method(rb_cRubyHash, "compare_by_identity",
+ rhash_compare_by_id, 0);
+ rb_objc_define_method(rb_cRubyHash, "compare_by_identity?",
+ rhash_compare_by_id_p, 0);
+
rb_objc_install_method2((Class)rb_cRubyHash, "count",
(IMP)imp_rhash_count);
rb_objc_install_method2((Class)rb_cRubyHash, "objectForKey:",
Modified: MacRuby/trunk/include/ruby/intern.h
===================================================================
--- MacRuby/trunk/include/ruby/intern.h 2010-01-26 23:20:58 UTC (rev 3344)
+++ MacRuby/trunk/include/ruby/intern.h 2010-01-26 23:21:44 UTC (rev 3345)
@@ -197,7 +197,7 @@
VALUE rb_enumeratorize(VALUE, SEL, int, VALUE *);
#define RETURN_ENUMERATOR(obj, argc, argv) do { \
if (!rb_block_given_p()) \
- return rb_enumeratorize(obj, sel, argc, argv); \
+ return rb_enumeratorize((VALUE)obj, sel, argc, argv); \
} while (0)
/* error.c */
VALUE rb_f_notimplement(VALUE rcv, SEL sel);
Modified: MacRuby/trunk/include/ruby/ruby.h
===================================================================
--- MacRuby/trunk/include/ruby/ruby.h 2010-01-26 23:20:58 UTC (rev 3344)
+++ MacRuby/trunk/include/ruby/ruby.h 2010-01-26 23:21:44 UTC (rev 3345)
@@ -1137,7 +1137,6 @@
RUBY_EXTERN VALUE rb_cNSArray;
RUBY_EXTERN VALUE rb_cNSMutableArray;
RUBY_EXTERN VALUE rb_cRubyArray;
-RUBY_EXTERN VALUE rb_cCFHash;
RUBY_EXTERN VALUE rb_cNSHash;
RUBY_EXTERN VALUE rb_cNSMutableHash;
RUBY_EXTERN VALUE rb_cRubyHash;
Modified: MacRuby/trunk/rakelib/builder.rb
===================================================================
--- MacRuby/trunk/rakelib/builder.rb 2010-01-26 23:20:58 UTC (rev 3344)
+++ MacRuby/trunk/rakelib/builder.rb 2010-01-26 23:21:44 UTC (rev 3345)
@@ -102,7 +102,8 @@
LDFLAGS << " -lpthread -ldl -lxml2 -lobjc -lauto -framework Foundation"
DLDFLAGS = "-dynamiclib -undefined suppress -flat_namespace -install_name #{INSTALL_NAME} -current_version #{MACRUBY_VERSION} -compatibility_version #{MACRUBY_VERSION}"
DLDFLAGS << " -unexported_symbols_list #{UNEXPORTED_SYMBOLS_LIST}" if UNEXPORTED_SYMBOLS_LIST
-CFLAGS << " -std=c99" # we add this one later to not conflict with ObjC/C++ flags
+CFLAGS << " -std=c99" # we add this one later to not conflict with C++ flags
+OBJC_CFLAGS << " -std=c99"
OBJS = %w{
array bignum class compar complex enum enumerator error eval file load proc
@@ -115,7 +116,7 @@
ruby signal sprintf st string struct time transcode util variable version
thread id objc bs encoding main dln dmyext marshal gcd
vm_eval prelude miniprelude gc-stub bridgesupport compiler dispatcher vm
- debugger MacRuby MacRubyDebuggerConnector
+ debugger MacRuby MacRubyDebuggerConnector NSDictionary
}
OBJS_CFLAGS = {
Modified: MacRuby/trunk/spec/macruby/tags/macruby/core/hash_tags.txt
===================================================================
--- MacRuby/trunk/spec/macruby/tags/macruby/core/hash_tags.txt 2010-01-26 23:20:58 UTC (rev 3344)
+++ MacRuby/trunk/spec/macruby/tags/macruby/core/hash_tags.txt 2010-01-26 23:21:44 UTC (rev 3345)
@@ -1,2 +1,3 @@
critical:The NSDictionary class can be subclassed and later instantiated
critical:An NSDictionary object can have a singleton class
+fails:An NSDictionary object is immutable
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100126/bdbb18bc/attachment-0001.html>
More information about the macruby-changes
mailing list