Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

completed Array refactoring, cleaned out a few things

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/trunk@3438 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information...
commit ae059217a4377b473b004f17ede394d0c3754b66 1 parent 67dca54
Laurent Sansonetti authored
View
1,510 NSArray.m
@@ -0,0 +1,1510 @@
+/*
+ * MacRuby extensions to NSArray.
+ *
+ * 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"
+#include "array.h"
+
+VALUE rb_cArray;
+VALUE rb_cNSArray;
+VALUE rb_cNSMutableArray;
+static VALUE rb_cCFArray;
+
+static id
+nsary_dup(id rcv, SEL sel)
+{
+ id dup = [rcv mutableCopy];
+ if (OBJ_TAINTED(rcv)) {
+ OBJ_TAINT(dup);
+ }
+ return dup;
+}
+
+static id
+nsary_clone(id rcv, SEL sel)
+{
+ id clone = nsary_dup(rcv, 0);
+ if (OBJ_FROZEN(rcv)) {
+ OBJ_FREEZE(clone);
+ }
+ return clone;
+}
+
+static id
+nsary_clear(id rcv, SEL sel)
+{
+ [rcv removeAllObjects];
+ return rcv;
+}
+
+static id
+nsary_inspect(id rcv, SEL sel)
+{
+ NSMutableString *str = [NSMutableString new];
+ [str appendString:@"["];
+ for (id item in rcv) {
+ if ([str length] > 1) {
+ [str appendString:@", "];
+ }
+ [str appendString:(NSString *)rb_inspect(OC2RB(item))];
+ }
+ [str appendString:@"]"];
+ return str;
+}
+
+static id
+nsary_to_a(id rcv, SEL sel)
+{
+ return rcv;
+}
+
+static VALUE
+nsary_equal(id rcv, SEL sel, id other)
+{
+ return [rcv isEqualToArray:other] ? Qtrue : Qfalse;
+}
+
+static VALUE
+nsary_subseq(id rcv, long beg, long len)
+{
+ if (beg < 0 || len < 0) {
+ return Qnil;
+ }
+ const long n = [rcv count];
+ if (beg > n) {
+ return Qnil;
+ }
+ if (n < len || n < beg + len) {
+ len = n - beg;
+ }
+ return (VALUE)[[rcv subarrayWithRange:NSMakeRange(beg, len)] mutableCopy];
+}
+
+static VALUE
+nsary_entry(id rcv, long offset)
+{
+ const long n = [rcv count];
+ if (n == 0) {
+ return Qnil;
+ }
+ if (offset < 0) {
+ offset += n;
+ }
+ if (offset < 0 || n <= offset) {
+ return Qnil;
+ }
+ return OC2RB([rcv objectAtIndex:offset]);
+}
+
+static VALUE
+nsary_aref(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ long beg, len;
+ if (argc == 2) {
+ beg = NUM2LONG(argv[0]);
+ len = NUM2LONG(argv[1]);
+ if (beg < 0) {
+ beg += [rcv count];
+ }
+ return nsary_subseq(rcv, beg, len);
+ }
+ if (argc != 1) {
+ rb_scan_args(argc, argv, "11", 0, 0);
+ }
+ VALUE arg = argv[0];
+ if (FIXNUM_P(arg)) {
+ return nsary_entry(rcv, FIX2LONG(arg));
+ }
+ // Check if Range.
+ switch (rb_range_beg_len(arg, &beg, &len, [rcv count], 0)) {
+ case Qfalse:
+ break;
+ case Qnil:
+ return Qnil;
+ default:
+ return nsary_subseq(rcv, beg, len);
+ }
+ return nsary_entry(rcv, NUM2LONG(arg));
+}
+
+static void
+nsary_splice(id ary, long beg, long len, VALUE rpl)
+{
+ const long n = [ary count];
+ if (len < 0) {
+ rb_raise(rb_eIndexError, "negative length (%ld)", len);
+ }
+ if (beg < 0) {
+ beg += n;
+ if (beg < 0) {
+ beg -= n;
+ rb_raise(rb_eIndexError, "index %ld out of array", beg);
+ }
+ }
+ if (n < len || n < beg + len) {
+ len = n - beg;
+ }
+
+ long rlen = 0;
+ if (rpl != Qundef) {
+ rpl = rb_ary_to_ary(rpl);
+ rlen = RARRAY_LEN(rpl);
+ }
+
+ if (beg >= n) {
+ for (long i = n; i < beg; i++) {
+ [ary addObject:[NSNull null]];
+ }
+ if (rlen > 0 && rpl != Qundef) {
+ [ary addObjectsFromArray:(id)rpl];
+ }
+ }
+ else {
+ if (rlen > 0 && rpl != Qundef) {
+ [ary replaceObjectsInRange:NSMakeRange(beg, len)
+ withObjectsFromArray:(id)rpl];
+ }
+ else {
+ [ary removeObjectsInRange:NSMakeRange(beg, len)];
+ }
+ }
+}
+
+static void
+nsary_store(id ary, long idx, VALUE val)
+{
+ const long len = [ary count];
+ if (idx < 0) {
+ idx += len;
+ if (idx < 0) {
+ rb_raise(rb_eIndexError, "index %ld out of array",
+ idx - len);
+ }
+ }
+ if (len <= idx) {
+ for (long i = len; i <= idx; i++) {
+ [ary addObject:[NSNull null]];
+ }
+ }
+ [ary replaceObjectAtIndex:idx withObject:RB2OC(val)];
+}
+
+static VALUE
+nsary_aset(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ if (argc == 3) {
+ nsary_splice(rcv, NUM2LONG(argv[0]), NUM2LONG(argv[1]), argv[2]);
+ return argv[2];
+ }
+ if (argc != 2) {
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc);
+ }
+
+ long offset;
+ if (FIXNUM_P(argv[0])) {
+ offset = FIX2LONG(argv[0]);
+ }
+ else {
+ long beg, len;
+ if (rb_range_beg_len(argv[0], &beg, &len, [rcv count], 1)) {
+ // Check if Range.
+ nsary_splice(rcv, beg, len, argv[1]);
+ return argv[1];
+ }
+ offset = NUM2LONG(argv[0]);
+ }
+ nsary_store(rcv, offset, argv[1]);
+ return argv[1];
+}
+
+static VALUE
+nsary_at(id rcv, SEL sel, VALUE pos)
+{
+ return nsary_entry(rcv, NUM2LONG(pos));
+}
+
+static VALUE
+nsary_fetch(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ VALUE pos, ifnone;
+ rb_scan_args(argc, argv, "11", &pos, &ifnone);
+
+ const bool block_given = rb_block_given_p();
+ if (block_given && argc == 2) {
+ rb_warn("block supersedes default value argument");
+ }
+
+ const long len = [rcv count];
+ long idx = NUM2LONG(pos);
+ if (idx < 0) {
+ idx += len;
+ }
+ if (idx < 0 || len <= idx) {
+ if (block_given) {
+ return rb_yield(pos);
+ }
+ if (argc == 1) {
+ rb_raise(rb_eIndexError, "index %ld out of array", idx);
+ }
+ return ifnone;
+ }
+ return OC2RB([rcv objectAtIndex:idx]);
+}
+
+static VALUE
+nsary_shared_first(int argc, VALUE *argv, id ary, bool last, bool remove)
+{
+ VALUE nv;
+ rb_scan_args(argc, argv, "1", &nv);
+ long n = NUM2LONG(nv);
+
+ const long ary_len = [ary count];
+ if (n > ary_len) {
+ n = ary_len;
+ }
+ else if (n < 0) {
+ rb_raise(rb_eArgError, "negative array size");
+ }
+
+ long offset = 0;
+ if (last) {
+ offset = ary_len - n;
+ }
+ id result = [NSMutableArray new];
+
+ for (long i = 0; i < n; i++) {
+ id item = [ary objectAtIndex:i + offset];
+ [result addObject:item];
+ }
+
+ if (remove) {
+ for (long i = 0; i < n; i++) {
+ [ary removeObjectAtIndex:offset];
+ }
+ }
+
+ return (VALUE)result;
+}
+
+static VALUE
+nsary_first(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ if (argc == 0) {
+ return [rcv count] == 0 ? Qnil : OC2RB([rcv objectAtIndex:0]);
+ }
+ return nsary_shared_first(argc, argv, rcv, false, false);
+
+}
+
+static VALUE
+nsary_last(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ if (argc == 0) {
+ const long len = [rcv count];
+ return len == 0 ? Qnil : OC2RB([rcv objectAtIndex:len - 1]);
+ }
+ return nsary_shared_first(argc, argv, rcv, true, false);
+}
+
+static id
+nsary_concat(id rcv, SEL sel, VALUE ary)
+{
+ ary = to_ary(ary);
+ [rcv addObjectsFromArray:(id)ary];
+ return rcv;
+}
+
+static id
+nsary_push(id rcv, SEL sel, VALUE elem)
+{
+ [rcv addObject:RB2OC(elem)];
+ return rcv;
+}
+
+static id
+nsary_push_m(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ for (int i = 0; i < argc; i++) {
+ nsary_push(rcv, 0, argv[i]);
+ }
+ return rcv;
+}
+
+static VALUE
+nsary_pop(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ if (argc == 0) {
+ const long len = [rcv count];
+ if (len > 0) {
+ id elem = [rcv objectAtIndex:len - 1];
+ [rcv removeObjectAtIndex:len - 1];
+ return OC2RB(elem);
+ }
+ return Qnil;
+ }
+ return nsary_shared_first(argc, argv, rcv, true, true);
+}
+
+static VALUE
+nsary_shift(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ if (argc == 0) {
+ const long len = [rcv count];
+ if (len > 0) {
+ id elem = [rcv objectAtIndex:0];
+ [rcv removeObjectAtIndex:0];
+ return OC2RB(elem);
+ }
+ return Qnil;
+ }
+ return nsary_shared_first(argc, argv, rcv, false, true);
+}
+
+static id
+nsary_unshift(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ for (int i = argc - 1; i >= 0; i--) {
+ [rcv insertObject:RB2OC(argv[i]) atIndex:0];
+ }
+ return rcv;
+}
+
+static void
+nsary_insert(id rcv, long idx, VALUE elem)
+{
+ const long len = [rcv count];
+ if (idx < 0) {
+ idx += len;
+ if (idx < 0) {
+ rb_raise(rb_eIndexError, "index %ld out of array", idx - len);
+ }
+ }
+ if (idx > len) {
+ for (long i = len; i < idx; i++) {
+ [rcv addObject:[NSNull null]];
+ }
+ }
+ [rcv insertObject:RB2OC(elem) atIndex:idx];
+}
+
+static id
+nsary_insert_m(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ if (argc < 1) {
+ rb_raise(rb_eArgError, "wrong number of arguments (at least 1)");
+ }
+ if (argc > 1) {
+ long pos = NUM2LONG(argv[0]);
+ if (pos == -1) {
+ pos = [rcv count];
+ }
+ if (pos < 0) {
+ pos++;
+ }
+ if (argc == 2) {
+ nsary_insert(rcv, pos, argv[1]);
+ }
+ else {
+ argc--;
+ argv++;
+ NSMutableArray *rpl = [NSMutableArray new];
+ for (int i = 0; i < argc; i++) {
+ [rpl addObject:RB2OC(argv[i])];
+ }
+ nsary_splice(rcv, pos, 0, (VALUE)rpl);
+ }
+ }
+ return rcv;
+}
+
+static VALUE
+nsary_each(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ for (id item in rcv) {
+ rb_yield(OC2RB(item));
+ RETURN_IF_BROKEN();
+ }
+ return (VALUE)rcv;
+}
+
+static VALUE
+nsary_each_index(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ for (long i = 0, count = [rcv count]; i < count; i++) {
+ rb_yield(LONG2NUM(i));
+ RETURN_IF_BROKEN();
+ }
+ return (VALUE)rcv;
+}
+
+static VALUE
+nsary_reverse_each(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ long len = [rcv count];
+ while (len--) {
+ rb_yield(OC2RB([rcv objectAtIndex:len]));
+ RETURN_IF_BROKEN();
+ const long n = [rcv count];
+ if (n < len) {
+ // Array was modified.
+ len = n;
+ }
+ }
+ return (VALUE)rcv;
+
+}
+
+static VALUE
+nsary_length(id rcv, SEL sel)
+{
+ return LONG2NUM([rcv count]);
+}
+
+static VALUE
+nsary_empty(id rcv, SEL sel)
+{
+ return [rcv count] == 0 ? Qtrue : Qfalse;
+}
+
+static VALUE
+nsary_index(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ const long len = [rcv count];
+
+ if (argc == 0) {
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ for (long i = 0; i < len; i++) {
+ VALUE test = rb_yield(OC2RB([rcv objectAtIndex:i]));
+ RETURN_IF_BROKEN();
+ if (RTEST(test)) {
+ return LONG2NUM(i);
+ }
+ }
+ }
+ else {
+ VALUE val;
+ rb_scan_args(argc, argv, "01", &val);
+ if (len > 0) {
+ NSUInteger index = [rcv indexOfObject:RB2OC(val)
+ inRange:NSMakeRange(0, len)];
+ if (index != NSNotFound) {
+ return LONG2NUM(index);
+ }
+ }
+ }
+ return Qnil;
+}
+
+static VALUE
+nsary_rindex(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ const long len = [rcv count];
+
+ if (argc == 0) {
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ long i = len;
+ while (i-- >= 0) {
+ VALUE test = rb_yield(OC2RB([rcv objectAtIndex:i]));
+ RETURN_IF_BROKEN();
+ if (RTEST(test)) {
+ return LONG2NUM(i);
+ }
+ }
+ }
+ else {
+ VALUE val;
+ rb_scan_args(argc, argv, "01", &val);
+ id ocval = RB2OC(val);
+ for (long i = len - 1; i >= 0; i--) {
+ id item = [rcv objectAtIndex:i];
+ if ([ocval isEqual:item]) {
+ return LONG2NUM(i);
+ }
+ }
+ }
+ return Qnil;
+}
+
+static id
+nsary_reverse_bang(id rcv, SEL sel)
+{
+ for (long i = 0, count = [rcv count]; i < (count / 2); i++) {
+ [rcv exchangeObjectAtIndex:i withObjectAtIndex:count - i - 1];
+ }
+ return rcv;
+}
+
+static id
+nsary_reverse(id rcv, SEL sel)
+{
+ return nsary_reverse_bang([rcv mutableCopy], 0);
+}
+
+static NSInteger
+sort_block(id x, id y, void *context)
+{
+ VALUE rbx = OC2RB(x);
+ VALUE rby = OC2RB(y);
+ VALUE ret = rb_yield_values(2, rbx, rby);
+ return rb_cmpint(ret, rbx, rby);
+}
+
+static id
+nsary_sort_bang(id rcv, SEL sel)
+{
+ if ([rcv count] > 1) {
+ if (rb_block_given_p()) {
+ [rcv sortUsingFunction:sort_block context:NULL];
+ }
+ else {
+ [rcv sortUsingSelector:@selector(compare:)];
+ }
+ }
+ return rcv;
+}
+
+static id
+nsary_sort(id rcv, SEL sel)
+{
+ return nsary_sort_bang([rcv mutableCopy], 0);
+}
+
+static VALUE
+collect(id rcv)
+{
+ for (long i = 0, count = [rcv count]; i < count; i++) {
+ id elem = [rcv objectAtIndex:i];
+ id newval = RB2OC(rb_yield(OC2RB(elem)));
+ RETURN_IF_BROKEN();
+ [rcv replaceObjectAtIndex:i withObject:newval];
+ }
+ return (VALUE)rcv;
+}
+
+static VALUE
+nsary_collect_bang(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ return collect(rcv);
+}
+
+static VALUE
+nsary_collect(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ return collect([rcv mutableCopy]);
+}
+
+static VALUE
+nsary_select(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ NSMutableArray *result = [NSMutableArray new];
+ for (id elem in rcv) {
+ VALUE test = rb_yield(OC2RB(elem));
+ RETURN_IF_BROKEN();
+ if (RTEST(test)) {
+ [result addObject:elem];
+ }
+ }
+ return (VALUE)result;
+}
+
+static id
+nsary_values_at(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ const long rcvlen = [rcv count];
+ NSMutableArray *result = [NSMutableArray new];
+ for (long i = 0; i < argc; i++) {
+ long beg, len;
+ switch (rb_range_beg_len(argv[i], &beg, &len, rcvlen, 0)) {
+ // Check if Range.
+ case Qfalse:
+ break;
+ case Qnil:
+ continue;
+ default:
+ for (long j = 0; j < len; j++) {
+ [result addObject:[rcv objectAtIndex:j + beg]];
+ }
+ continue;
+ }
+ [result addObject:[rcv objectAtIndex:NUM2LONG(argv[i])]];
+ }
+ return result;
+}
+
+static bool
+nsary_delete_element(id rcv, VALUE elem)
+{
+ id ocelem = RB2OC(elem);
+ long len = [rcv count];
+ NSRange range = NSMakeRange(0, len);
+ NSUInteger index;
+ bool changed = false;
+ while ((index = [rcv indexOfObject:ocelem inRange:range]) != NSNotFound) {
+ [rcv removeObjectAtIndex:index];
+ range.location = index;
+ range.length = --len - index;
+ changed = true;
+ }
+ return changed;
+}
+
+static VALUE
+nsary_delete(id rcv, SEL sel, VALUE elem)
+{
+ if (!nsary_delete_element(rcv, elem)) {
+ if (rb_block_given_p()) {
+ return rb_yield(elem);
+ }
+ return Qnil;
+ }
+ return elem;
+}
+
+static VALUE
+nsary_delete_at(id rcv, SEL sel, VALUE pos)
+{
+ long index = NUM2LONG(pos);
+ const long len = [rcv count];
+ if (index >= len) {
+ return Qnil;
+ }
+ if (index < 0) {
+ index += len;
+ if (index < 0) {
+ return Qnil;
+ }
+ }
+ VALUE elem = OC2RB([rcv objectAtIndex:index]);
+ [rcv removeObjectAtIndex:index];
+ return elem;
+}
+
+static VALUE
+reject(id rcv)
+{
+ bool changed = false;
+ for (long i = 0, n = [rcv count]; i < n; i++) {
+ VALUE elem = OC2RB([rcv objectAtIndex:i]);
+ VALUE test = rb_yield(elem);
+ RETURN_IF_BROKEN();
+ if (RTEST(test)) {
+ [rcv removeObjectAtIndex:i];
+ n--;
+ i--;
+ changed = true;
+ }
+ }
+ return changed ? (VALUE)rcv : Qnil;
+}
+
+static VALUE
+nsary_delete_if(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ return reject(rcv);
+}
+
+static VALUE
+nsary_reject(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ return reject([rcv mutableCopy]);
+}
+
+static VALUE
+nsary_reject_bang(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ return reject(rcv);
+}
+
+static id
+nsary_replace(id rcv, SEL sel, VALUE other)
+{
+ other = to_ary(other);
+ [rcv setArray:(id)other];
+ return rcv;
+}
+
+static VALUE
+nsary_includes(id rcv, SEL sel, VALUE obj)
+{
+ id elem = RB2OC(obj);
+ return [rcv containsObject:elem] ? Qtrue : Qfalse;
+}
+
+static VALUE
+nsary_slice_bang(id rcv, SEL sel, int argc, VALUE *argv)
+{
+ const long rcvlen = [rcv count];
+ VALUE arg1, arg2;
+ long pos, len;
+
+ if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) {
+ pos = NUM2LONG(arg1);
+ len = NUM2LONG(arg2);
+delete_pos_len:
+ if (pos < 0) {
+ pos = rcvlen + pos;
+ if (pos < 0) {
+ return Qnil;
+ }
+ }
+ if (rcvlen < len || rcvlen < pos + len) {
+ len = rcvlen - pos;
+ }
+ VALUE result = nsary_subseq(rcv, pos, len);
+ nsary_splice(rcv, pos, len, Qundef);
+ return result;
+ }
+
+ if (!FIXNUM_P(arg1)) {
+ switch (rb_range_beg_len(arg1, &pos, &len, rcvlen, 0)) {
+ case Qtrue:
+ // Valid range.
+ goto delete_pos_len;
+ case Qnil:
+ // invalid range.
+ return Qnil;
+ default:
+ // Not a range.
+ break;
+ }
+ }
+
+ return nsary_delete_at(rcv, 0, arg1);
+}
+
+static id
+nsary_plus(id rcv, SEL sel, VALUE other)
+{
+ other = to_ary(other);
+ NSMutableArray *ary = [NSMutableArray new];
+ [ary addObjectsFromArray:rcv];
+ [ary addObjectsFromArray:(id)other];
+ return ary;
+}
+
+static id
+nsary_times(id rcv, SEL sel, VALUE times)
+{
+ VALUE tmp = rb_check_string_type(times);
+ if (!NIL_P(tmp)) {
+ return (id)rb_ary_join((VALUE)rcv, tmp);
+ }
+
+ const long len = NUM2LONG(times);
+ if (len < 0) {
+ rb_raise(rb_eArgError, "negative argument");
+ }
+
+ NSMutableArray *result = [NSMutableArray new];
+ if (len > 0) {
+ const long n = [rcv count];
+ if (LONG_MAX/len < n) {
+ rb_raise(rb_eArgError, "argument too big");
+ }
+ for (long i = 0; i < len; i++) {
+ [result addObjectsFromArray:rcv];
+ }
+ }
+ return result;
+}
+
+static VALUE
+nsary_uniq_bang(id rcv, SEL sel)
+{
+ long len = [rcv count];
+ bool changed = false;
+ for (long i = 0; i < len; i++) {
+ id elem = [rcv objectAtIndex:i];
+ NSRange range = NSMakeRange(i + 1, len - i - 1);
+ NSUInteger index;
+ while ((index = [rcv indexOfObject:elem inRange:range]) != NSNotFound) {
+ [rcv removeObjectAtIndex:index];
+ range.location = index;
+ range.length = --len - index;
+ changed = true;
+ }
+ }
+ return changed ? (VALUE)rcv : Qnil;
+}
+
+static id
+nsary_uniq(id rcv, SEL sel)
+{
+ id result = [rcv mutableCopy];
+ nsary_uniq_bang(result, 0);
+ return result;
+}
+
+static VALUE
+nsary_compact_bang(id rcv, SEL sel)
+{
+ return nsary_delete_element(rcv, Qnil) ? (VALUE)rcv : Qnil;
+}
+
+static id
+nsary_compact(id rcv, SEL sel)
+{
+ id result = [rcv mutableCopy];
+ nsary_compact_bang(result, 0);
+ return result;
+}
+
+static VALUE
+nsary_drop(id rcv, SEL sel, VALUE n)
+{
+ const long pos = NUM2LONG(n);
+ if (pos < 0) {
+ rb_raise(rb_eArgError, "attempt to drop negative size");
+ }
+ return nsary_subseq(rcv, pos, [rcv count]);
+}
+
+static VALUE
+nsary_drop_while(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ long i = 0;
+ for (long count = [rcv count]; i < count; i++) {
+ VALUE v = rb_yield(OC2RB([rcv objectAtIndex:i]));
+ RETURN_IF_BROKEN();
+ if (!RTEST(v)) {
+ break;
+ }
+ }
+ return nsary_drop(rcv, 0, LONG2FIX(i));
+}
+
+static VALUE
+nsary_take(id rcv, SEL sel, VALUE n)
+{
+ const long len = NUM2LONG(n);
+ if (len < 0) {
+ rb_raise(rb_eArgError, "attempt to take negative size");
+ }
+ return nsary_subseq(rcv, 0, len);
+}
+
+static VALUE
+nsary_take_while(id rcv, SEL sel)
+{
+ RETURN_ENUMERATOR(rcv, 0, 0);
+ long i = 0;
+ for (long count = [rcv count]; i < count; i++) {
+ VALUE v = rb_yield(OC2RB([rcv objectAtIndex:i]));
+ RETURN_IF_BROKEN();
+ if (!RTEST(v)) {
+ break;
+ }
+ }
+ return nsary_take(rcv, 0, LONG2FIX(i));
+}
+
+static id
+nsary_shuffle_bang(id rcv, SEL sel)
+{
+ long i = [rcv count];
+ while (i > 0) {
+ const long j = rb_genrand_real() * i--;
+ [rcv exchangeObjectAtIndex:i withObjectAtIndex:j];
+ }
+ return rcv;
+}
+
+static id
+nsary_shuffle(id rcv, SEL sel)
+{
+ id result = [rcv mutableCopy];
+ nsary_shuffle_bang(result, 0);
+ return result;
+}
+
+void
+Init_NSArray(void)
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
+ rb_cCFArray = (VALUE)objc_getClass("NSCFArray");
+#else
+ rb_cCFArray = (VALUE)objc_getClass("__NSCFArray");
+#endif
+ assert(rb_cCFArray != 0);
+ rb_cNSArray = (VALUE)objc_getClass("NSArray");
+ assert(rb_cNSArray != 0);
+ rb_cArray = rb_cNSArray;
+ rb_cNSMutableArray = (VALUE)objc_getClass("NSMutableArray");
+ assert(rb_cNSMutableArray != 0);
+
+ rb_include_module(rb_cArray, rb_mEnumerable);
+
+ rb_objc_define_method(rb_cArray, "dup", nsary_dup, 0);
+ rb_objc_define_method(rb_cArray, "clone", nsary_clone, 0);
+ rb_objc_define_method(rb_cArray, "clear", nsary_clear, 0);
+ rb_objc_define_method(rb_cArray, "to_s", nsary_inspect, 0);
+ rb_objc_define_method(rb_cArray, "inspect", nsary_inspect, 0);
+ rb_objc_define_method(rb_cArray, "to_a", nsary_to_a, 0);
+ rb_objc_define_method(rb_cArray, "to_ary", nsary_to_a, 0);
+ rb_objc_define_method(rb_cArray, "==", nsary_equal, 1);
+ rb_objc_define_method(rb_cArray, "eql?", nsary_equal, 1);
+ rb_objc_define_method(rb_cArray, "[]", nsary_aref, -1);
+ rb_objc_define_method(rb_cArray, "[]=", nsary_aset, -1);
+ rb_objc_define_method(rb_cArray, "at", nsary_at, 1);
+ rb_objc_define_method(rb_cArray, "fetch", nsary_fetch, -1);
+ rb_objc_define_method(rb_cArray, "first", nsary_first, -1);
+ rb_objc_define_method(rb_cArray, "last", nsary_last, -1);
+ rb_objc_define_method(rb_cArray, "concat", nsary_concat, 1);
+ rb_objc_define_method(rb_cArray, "<<", nsary_push, 1);
+ rb_objc_define_method(rb_cArray, "push", nsary_push_m, -1);
+ rb_objc_define_method(rb_cArray, "pop", nsary_pop, -1);
+ rb_objc_define_method(rb_cArray, "shift", nsary_shift, -1);
+ rb_objc_define_method(rb_cArray, "unshift", nsary_unshift, -1);
+ rb_objc_define_method(rb_cArray, "insert", nsary_insert_m, -1);
+ rb_objc_define_method(rb_cArray, "each", nsary_each, 0);
+ rb_objc_define_method(rb_cArray, "each_index", nsary_each_index, 0);
+ rb_objc_define_method(rb_cArray, "reverse_each", nsary_reverse_each, 0);
+ rb_objc_define_method(rb_cArray, "length", nsary_length, 0);
+ rb_objc_define_method(rb_cArray, "size", nsary_length, 0);
+ rb_objc_define_method(rb_cArray, "empty?", nsary_empty, 0);
+ rb_objc_define_method(rb_cArray, "find_index", nsary_index, -1);
+ rb_objc_define_method(rb_cArray, "index", nsary_index, -1);
+ rb_objc_define_method(rb_cArray, "rindex", nsary_rindex, -1);
+ rb_objc_define_method(rb_cArray, "reverse", nsary_reverse, 0);
+ rb_objc_define_method(rb_cArray, "reverse!", nsary_reverse_bang, 0);
+ rb_objc_define_method(rb_cArray, "sort", nsary_sort, 0);
+ rb_objc_define_method(rb_cArray, "sort!", nsary_sort_bang, 0);
+ rb_objc_define_method(rb_cArray, "collect", nsary_collect, 0);
+ rb_objc_define_method(rb_cArray, "collect!", nsary_collect_bang, 0);
+ rb_objc_define_method(rb_cArray, "map", nsary_collect, 0);
+ rb_objc_define_method(rb_cArray, "map!", nsary_collect_bang, 0);
+ rb_objc_define_method(rb_cArray, "select", nsary_select, 0);
+ rb_objc_define_method(rb_cArray, "values_at", nsary_values_at, -1);
+ rb_objc_define_method(rb_cArray, "delete", nsary_delete, 1);
+ rb_objc_define_method(rb_cArray, "delete_at", nsary_delete_at, 1);
+ rb_objc_define_method(rb_cArray, "delete_if", nsary_delete_if, 0);
+ rb_objc_define_method(rb_cArray, "reject", nsary_reject, 0);
+ rb_objc_define_method(rb_cArray, "reject!", nsary_reject_bang, 0);
+ rb_objc_define_method(rb_cArray, "replace", nsary_replace, 1);
+ rb_objc_define_method(rb_cArray, "include?", nsary_includes, 1);
+ rb_objc_define_method(rb_cArray, "slice", nsary_aref, -1);
+ rb_objc_define_method(rb_cArray, "slice!", nsary_slice_bang, -1);
+ rb_objc_define_method(rb_cArray, "+", nsary_plus, 1);
+ rb_objc_define_method(rb_cArray, "*", nsary_times, 1);
+ rb_objc_define_method(rb_cArray, "uniq", nsary_uniq, 0);
+ rb_objc_define_method(rb_cArray, "uniq!", nsary_uniq_bang, 0);
+ rb_objc_define_method(rb_cArray, "compact", nsary_compact, 0);
+ rb_objc_define_method(rb_cArray, "compact!", nsary_compact_bang, 0);
+ rb_objc_define_method(rb_cArray, "shuffle!", nsary_shuffle_bang, 0);
+ rb_objc_define_method(rb_cArray, "shuffle", nsary_shuffle, 0);
+ rb_objc_define_method(rb_cArray, "take", nsary_take, 1);
+ rb_objc_define_method(rb_cArray, "take_while", nsary_take_while, 0);
+ rb_objc_define_method(rb_cArray, "drop", nsary_drop, 1);
+ rb_objc_define_method(rb_cArray, "drop_while", nsary_drop_while, 0);
+
+ // Implementation shared with RubyArray (and defined in array.c).
+ rb_objc_define_method(rb_cArray, "-", rary_diff, 1);
+ rb_objc_define_method(rb_cArray, "&", rary_and, 1);
+ rb_objc_define_method(rb_cArray, "|", rary_or, 1);
+ rb_objc_define_method(rb_cArray, "join", rary_join, -1);
+ rb_objc_define_method(rb_cArray, "zip", rary_zip, -1);
+ rb_objc_define_method(rb_cArray, "transpose", rary_transpose, 0);
+ rb_objc_define_method(rb_cArray, "fill", rary_fill, -1);
+ rb_objc_define_method(rb_cArray, "<=>", rary_cmp, 1);
+ rb_objc_define_method(rb_cArray, "assoc", rary_assoc, 1);
+ rb_objc_define_method(rb_cArray, "rassoc", rary_rassoc, 1);
+ rb_objc_define_method(rb_cArray, "flatten", rary_flatten, -1);
+ rb_objc_define_method(rb_cArray, "flatten!", rary_flatten_bang, -1);
+ rb_objc_define_method(rb_cArray, "product", rary_product, -1);
+ rb_objc_define_method(rb_cArray, "combination", rary_combination, 1);
+ rb_objc_define_method(rb_cArray, "permutation", rary_permutation, -1);
+ rb_objc_define_method(rb_cArray, "cycle", rary_cycle, -1);
+ rb_objc_define_method(rb_cArray, "sample", rary_sample, -1);
+}
+
+#define PREPARE_RCV(x) \
+ Class old = *(Class *)x; \
+ *(Class *)x = (Class)rb_cCFArray;
+
+#define RESTORE_RCV(x) \
+ *(Class *)x = old;
+
+static long
+imp_rb_array_count(id rcv, SEL sel)
+{
+ PREPARE_RCV(rcv);
+ const long count = [rcv count];
+ RESTORE_RCV(rcv);
+ return count;
+}
+
+static id
+imp_rb_array_objectAtIndex(id rcv, SEL sel, long idx)
+{
+ PREPARE_RCV(rcv);
+ id obj = [rcv objectAtIndex:idx];
+ RESTORE_RCV(rcv);
+ return obj;
+}
+
+static void
+imp_rb_array_insertObjectAtIndex(id rcv, SEL sel, id obj, long idx)
+{
+ PREPARE_RCV(rcv);
+ [rcv insertObject:obj atIndex:idx];
+ RESTORE_RCV(rcv);
+}
+
+static void
+imp_rb_array_removeObjectAtIndex(id rcv, SEL sel, long idx)
+{
+ PREPARE_RCV(rcv);
+ [rcv removeObjectAtIndex:idx];
+ RESTORE_RCV(rcv);
+}
+
+static void
+imp_rb_array_replaceObjectAtIndexWithObject(id rcv, SEL sel, long idx, id obj)
+{
+ PREPARE_RCV(rcv);
+ [rcv replaceObjectAtIndex:idx withObject:obj];
+ RESTORE_RCV(rcv);
+}
+
+static void
+imp_rb_array_addObject(id rcv, SEL sel, id obj)
+{
+ PREPARE_RCV(rcv);
+ [rcv addObject:obj];
+ RESTORE_RCV(rcv);
+}
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
+// This is to work around a bug where CF will try to call an non-existing
+// method.
+static CFIndex
+imp_rb_array_cfindexOfObjectInRange(void *rcv, SEL sel, void *obj,
+ CFRange range)
+{
+ CFIndex i;
+ PREPARE_RCV(rcv);
+ i = CFArrayGetFirstIndexOfValue((CFArrayRef)rcv, range, obj);
+ RESTORE_RCV(rcv);
+ return i;
+}
+#endif
+
+void
+rb_objc_install_array_primitives(Class klass)
+{
+ rb_objc_install_method2(klass, "count", (IMP)imp_rb_array_count);
+ rb_objc_install_method2(klass, "objectAtIndex:",
+ (IMP)imp_rb_array_objectAtIndex);
+
+ const bool is_mutable = class_getSuperclass(klass)
+ == (Class)rb_cNSMutableArray;
+
+ if (is_mutable) {
+ rb_objc_install_method2(klass, "insertObject:atIndex:",
+ (IMP)imp_rb_array_insertObjectAtIndex);
+ rb_objc_install_method2(klass, "removeObjectAtIndex:",
+ (IMP)imp_rb_array_removeObjectAtIndex);
+ rb_objc_install_method2(klass, "replaceObjectAtIndex:withObject:",
+ (IMP)imp_rb_array_replaceObjectAtIndexWithObject);
+ rb_objc_install_method2(klass, "addObject:",
+ (IMP)imp_rb_array_addObject);
+ }
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
+ // This is to work around a bug where CF will try to call an non-existing
+ // method.
+ rb_objc_install_method2(klass, "_cfindexOfObject:range:",
+ (IMP)imp_rb_array_cfindexOfObjectInRange);
+ Method m = class_getInstanceMethod(klass,
+ sel_registerName("_cfindexOfObject:range:"));
+ class_addMethod(klass, sel_registerName("_cfindexOfObject:inRange:"),
+ method_getImplementation(m), method_getTypeEncoding(m));
+#endif
+
+ //rb_objc_define_method(*(VALUE *)klass, "alloc", ary_alloc, 0);
+}
+
+// MRI compatibility API.
+
+VALUE
+rb_ary_freeze(VALUE ary)
+{
+ return OBJ_FREEZE(ary);
+}
+
+VALUE
+rb_ary_frozen_p(VALUE ary)
+{
+ return OBJ_FROZEN(ary) ? Qtrue : Qfalse;
+}
+
+long
+rb_ary_len(VALUE ary)
+{
+ if (IS_RARY(ary)) {
+ return RARY(ary)->len;
+ }
+ else {
+ return [(id)ary count];
+ }
+}
+
+VALUE
+rb_ary_elt(VALUE ary, long offset)
+{
+ if (offset >= 0) {
+ if (IS_RARY(ary)) {
+ if (offset < RARY(ary)->len) {
+ return rary_elt(ary, offset);
+ }
+ }
+ else {
+ if (offset < [(id)ary count]) {
+ return OC2RB([(id)ary objectAtIndex:offset]);
+ }
+ }
+ }
+ return Qnil;
+}
+
+VALUE
+rb_ary_replace(VALUE rcv, VALUE other)
+{
+ other = to_ary(other);
+ rb_ary_clear(rcv);
+ for (long i = 0, count = RARRAY_LEN(other); i < count; i++) {
+ rb_ary_push(rcv, RARRAY_AT(other, i));
+ }
+ return rcv;
+}
+
+VALUE
+rb_ary_clear(VALUE ary)
+{
+ if (IS_RARY(ary)) {
+ return rary_clear(ary, 0);
+ }
+ else {
+ return (VALUE)nsary_clear((id)ary, 0);
+ }
+}
+
+static VALUE
+recursive_join(VALUE ary, VALUE argp, int recur)
+{
+ VALUE *arg = (VALUE *)argp;
+ if (recur) {
+ return rb_usascii_str_new2("[...]");
+ }
+ return rb_ary_join(arg[0], arg[1]);
+}
+
+VALUE
+rb_ary_join(VALUE ary, VALUE sep)
+{
+ if (RARRAY_LEN(ary) == 0) {
+ return rb_str_new(0, 0);
+ }
+
+ bool taint = false;
+ if (OBJ_TAINTED(ary) || OBJ_TAINTED(sep)) {
+ taint = true;
+ }
+ bool untrust = false;
+ if (OBJ_UNTRUSTED(ary) || OBJ_UNTRUSTED(sep)) {
+ untrust = true;
+ }
+
+ VALUE result = rb_str_new(0, 0);
+
+ for (long i = 0, count = RARRAY_LEN(ary); i < count; i++) {
+ VALUE tmp = RARRAY_AT(ary, i);
+ switch (TYPE(tmp)) {
+ case T_STRING:
+ break;
+ case T_ARRAY:
+ {
+ VALUE args[2];
+
+ args[0] = tmp;
+ args[1] = sep;
+ tmp = rb_exec_recursive(recursive_join, ary, (VALUE)args);
+ }
+ break;
+ default:
+ tmp = rb_obj_as_string(tmp);
+ }
+ if (i > 0 && !NIL_P(sep)) {
+ rb_str_buf_append(result, sep);
+ }
+ rb_str_buf_append(result, tmp);
+
+ if (OBJ_TAINTED(tmp)) {
+ taint = true;
+ }
+ if (OBJ_UNTRUSTED(tmp)) {
+ untrust = true;
+ }
+ }
+
+ if (taint) {
+ OBJ_TAINT(result);
+ }
+ if (untrust) {
+ OBJ_UNTRUST(result);
+ }
+ return result;
+}
+
+VALUE
+rb_ary_dup(VALUE ary)
+{
+ if (IS_RARY(ary)) {
+ return rary_dup(ary, 0);
+ }
+ else {
+ return (VALUE)nsary_dup((id)ary, 0);
+ }
+}
+
+VALUE
+rb_ary_reverse(VALUE ary)
+{
+ if (IS_RARY(ary)) {
+ return rary_reverse_bang(ary, 0);
+ }
+ else {
+ return (VALUE)nsary_reverse_bang((id)ary, 0);
+ }
+}
+
+VALUE
+rb_ary_includes(VALUE ary, VALUE item)
+{
+ if (IS_RARY(ary)) {
+ return rary_includes(ary, 0, item);
+ }
+ else {
+ return nsary_includes((id)ary, 0, item);
+ }
+}
+
+VALUE
+rb_ary_delete(VALUE ary, VALUE item)
+{
+ if (IS_RARY(ary)) {
+ return rary_delete(ary, 0, item);
+ }
+ else {
+ return nsary_delete((id)ary, 0, item);
+ }
+}
+
+VALUE
+rb_ary_delete_at(VALUE ary, long pos)
+{
+ if (IS_RARY(ary)) {
+ return rary_delete_at(ary, 0, LONG2NUM(pos));
+ }
+ else {
+ return nsary_delete_at((id)ary, 0, LONG2NUM(pos));
+ }
+}
+
+VALUE
+rb_ary_pop(VALUE ary)
+{
+ if (IS_RARY(ary)) {
+ return rary_pop(ary, 0, 0, NULL);
+ }
+ else {
+ return nsary_pop((id)ary, 0, 0, NULL);
+ }
+}
+
+VALUE
+rb_ary_shift(VALUE ary)
+{
+ if (IS_RARY(ary)) {
+ return rary_shift(ary, 0, 0, NULL);
+ }
+ else {
+ return nsary_shift((id)ary, 0, 0, NULL);
+ }
+}
+
+VALUE
+rb_ary_subseq(VALUE ary, long beg, long len)
+{
+ if (IS_RARY(ary)) {
+ return rary_subseq(ary, beg, len);
+ }
+ else {
+ return nsary_subseq((id)ary, beg, len);
+ }
+}
+
+VALUE
+rb_ary_entry(VALUE ary, long offset)
+{
+ if (IS_RARY(ary)) {
+ return rary_entry(ary, offset);
+ }
+ else {
+ return nsary_entry((id)ary, offset);
+ }
+}
+
+VALUE
+rb_ary_aref(VALUE ary, SEL sel, int argc, VALUE *argv)
+{
+ if (IS_RARY(ary)) {
+ return rary_aref(ary, 0, argc, argv);
+ }
+ else {
+ return nsary_aref((id)ary, 0, argc, argv);
+ }
+}
+
+void
+rb_ary_store(VALUE ary, long idx, VALUE val)
+{
+ if (IS_RARY(ary)) {
+ rary_store(ary, idx, val);
+ }
+ else {
+ nsary_store((id)ary, idx, val);
+ }
+}
+
+void
+rb_ary_insert(VALUE ary, long idx, VALUE val)
+{
+ if (IS_RARY(ary)) {
+ rary_insert(ary, idx, val);
+ }
+ else {
+ nsary_insert((id)ary, idx, val);
+ }
+}
+
+VALUE
+rb_ary_concat(VALUE x, VALUE y)
+{
+ if (IS_RARY(x)) {
+ return rary_concat_m(x, 0, y);
+ }
+ else {
+ return (VALUE)nsary_concat((id)x, 0, y);
+ }
+}
+
+VALUE
+rb_ary_push(VALUE ary, VALUE item)
+{
+ if (IS_RARY(ary)) {
+ return rary_push_m(ary, 0, item);
+ }
+ else {
+ return (VALUE)nsary_push((id)ary, 0, item);
+ }
+}
+
+VALUE
+rb_ary_plus(VALUE x, VALUE y)
+{
+ if (IS_RARY(x)) {
+ return rary_plus(x, 0, y);
+ }
+ else {
+ return (VALUE)nsary_plus((id)x, 0, y);
+ }
+}
+
+VALUE
+rb_ary_unshift(VALUE ary, VALUE item)
+{
+ if (IS_RARY(ary)) {
+ return rary_unshift(ary, 0, 1, &item);
+ }
+ else {
+ return (VALUE)nsary_unshift((id)ary, 0, 1, &item);
+ }
+}
+
+VALUE
+rb_ary_each(VALUE ary)
+{
+ if (IS_RARY(ary)) {
+ return rary_each(ary, 0);
+ }
+ else {
+ return nsary_each((id)ary, 0);
+ }
+}
+
+VALUE
+rb_ary_sort(VALUE ary)
+{
+ if (IS_RARY(ary)) {
+ return rary_sort(ary, 0);
+ }
+ else {
+ return (VALUE)nsary_sort((id)ary, 0);
+ }
+}
+
+VALUE
+rb_ary_sort_bang(VALUE ary)
+{
+ if (IS_RARY(ary)) {
+ return rary_sort_bang(ary, 0);
+ }
+ else {
+ return (VALUE)nsary_sort_bang((id)ary, 0);
+ }
+}
+
+static void *nsary_cptr_key = NULL;
+
+const VALUE *
+rb_ary_ptr(VALUE ary)
+{
+ if (IS_RARY(ary)) {
+ return rary_ptr(ary);
+ }
+
+ id nsary = (id)ary;
+ const long len = [nsary count];
+ if (len == 0) {
+ return NULL;
+ }
+
+ VALUE *values = (VALUE *)xmalloc(sizeof(VALUE) * len);
+ for (long i = 0; i < len; i++) {
+ values[i] = OC2RB([nsary objectAtIndex:i]);
+ }
+
+ rb_objc_set_associative_ref((void *)nsary, &nsary_cptr_key, values);
+
+ return values;
+}
View
149 NSDictionary.m
@@ -12,6 +12,7 @@
#include "ruby/node.h"
#include "objc.h"
#include "vm.h"
+#include "hash.h"
VALUE rb_cHash;
VALUE rb_cNSHash;
@@ -98,10 +99,16 @@
return [rcv isEqualToDictionary:other] ? Qtrue : Qfalse;
}
+static inline VALUE
+nshash_lookup(id rcv, VALUE key)
+{
+ return OC2RB([rcv objectForKey:RB2OC(key)]);
+}
+
static VALUE
nshash_aref(id rcv, SEL sel, VALUE key)
{
- return OC2RB([rcv objectForKey:RB2OC(key)]);
+ return nshash_lookup(rcv, key);
}
static VALUE
@@ -191,6 +198,7 @@
RETURN_ENUMERATOR(rcv, 0, 0);
for (id key in rcv) {
rb_yield(OC2RB([rcv objectForKey:key]));
+ RETURN_IF_BROKEN();
}
return (VALUE)rcv;
}
@@ -201,6 +209,7 @@
RETURN_ENUMERATOR(rcv, 0, 0);
for (id key in rcv) {
rb_yield(OC2RB(key));
+ RETURN_IF_BROKEN();
}
return (VALUE)rcv;
}
@@ -212,6 +221,7 @@
for (id key in rcv) {
id value = [rcv objectForKey:key];
rb_yield(rb_assoc_new(OC2RB(key), OC2RB(value)));
+ RETURN_IF_BROKEN();
}
return (VALUE)rcv;
}
@@ -277,6 +287,7 @@
if (RTEST(rb_yield_values(2, OC2RB(key), OC2RB(value)))) {
[ary addObject:key];
}
+ RETURN_IF_BROKEN();
}
[rcv removeObjectsForKeys:ary];
return (VALUE)rcv;
@@ -292,6 +303,7 @@
if (RTEST(rb_yield_values(2, OC2RB(key), OC2RB(value)))) {
[dict setObject:value forKey:key];
}
+ RETURN_IF_BROKEN();
}
return (VALUE)dict;
}
@@ -608,3 +620,138 @@
//rb_objc_define_method(*(VALUE *)klass, "alloc", hash_alloc, 0);
}
+
+// MRI compatibility API.
+
+VALUE
+rb_hash_dup(VALUE rcv)
+{
+ if (IS_RHASH(rcv)) {
+ return rhash_dup(rcv, 0);
+ }
+ else {
+ return (VALUE)nshash_dup((id)rcv, 0);
+ }
+}
+
+void
+rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
+{
+ if (IS_RHASH(hash)) {
+ rhash_foreach(hash, func, farg);
+ }
+ else {
+ for (id key in (id)hash) {
+ id value = [(id)hash objectForKey:key];
+ if ((*func)(OC2RB(key), OC2RB(value), farg) == ST_STOP) {
+ break;
+ }
+ }
+ }
+}
+
+VALUE
+rb_hash_lookup(VALUE hash, VALUE key)
+{
+ if (IS_RHASH(hash)) {
+ VALUE val = rhash_lookup(hash, key);
+ return val == Qundef ? Qnil : val;
+ }
+ else {
+ return nshash_lookup((id)hash, key);
+ }
+}
+
+VALUE
+rb_hash_aref(VALUE hash, VALUE key)
+{
+ if (IS_RHASH(hash)) {
+ return rhash_aref(hash, 0, key);
+ }
+ else {
+ return nshash_lookup((id)hash, key);
+ }
+}
+
+VALUE
+rb_hash_delete_key(VALUE hash, VALUE key)
+{
+ if (IS_RHASH(hash)) {
+ rhash_modify(hash);
+ return rhash_delete_key(hash, key);
+ }
+ else {
+ id ockey = RB2OC(key);
+ id value = [(id)hash objectForKey:ockey];
+ if (value != nil) {
+ [(id)hash removeObjectForKey:ockey];
+ return OC2RB(value);
+ }
+ return Qundef;
+ }
+}
+
+VALUE
+rb_hash_delete(VALUE hash, VALUE key)
+{
+ VALUE val = rb_hash_delete_key(hash, key);
+ if (val != Qundef) {
+ return val;
+ }
+ return Qnil;
+}
+
+VALUE
+rb_hash_aset(VALUE hash, VALUE key, VALUE val)
+{
+ if (IS_RHASH(hash)) {
+ return rhash_aset(hash, 0, key, val);
+ }
+ else {
+ return nshash_aset((id)hash, 0, key, val);
+ }
+}
+
+long
+rb_hash_size(VALUE hash)
+{
+ if (IS_RHASH(hash)) {
+ return rhash_len(hash);
+ }
+ else {
+ return [(id)hash count];
+ }
+}
+
+VALUE
+rb_hash_keys(VALUE hash)
+{
+ if (IS_RHASH(hash)) {
+ return rhash_keys(hash, 0);
+ }
+ else {
+ return (VALUE)nshash_keys((id)hash, 0);
+ }
+}
+
+VALUE
+rb_hash_has_key(VALUE hash, VALUE key)
+{
+ if (IS_RHASH(hash)) {
+ return rhash_has_key(hash, 0, key);
+ }
+ else {
+ return nshash_has_key((id)hash, 0, key);
+ }
+}
+
+VALUE
+rb_hash_set_ifnone(VALUE hash, VALUE ifnone)
+{
+ if (IS_RHASH(hash)) {
+ return rhash_set_default(hash, 0, ifnone);
+ }
+ else {
+ return nshash_set_default((id)hash, 0, ifnone);
+ }
+}
View
2,509 array.c
@@ -16,186 +16,135 @@
#include "objc.h"
#include "ruby/node.h"
#include "vm.h"
+#include "array.h"
-VALUE rb_cArray;
-VALUE rb_cCFArray;
-VALUE rb_cNSArray;
-VALUE rb_cNSMutableArray;
VALUE rb_cRubyArray;
#define ARY_DEFAULT_SIZE 16
-typedef struct {
- struct RBasic basic;
- size_t beg;
- size_t len;
- size_t cap;
- VALUE *elements;
-} rb_ary_t;
-
// RubyArray primitives.
-static VALUE
-rary_elt(rb_ary_t *ary, size_t idx)
-{
-// assert(idx < ary->len);
- return ary->elements[ary->beg + idx];
-}
-
-static void
-rary_replace(rb_ary_t *ary, size_t idx, VALUE item)
-{
-// assert(idx < ary->len);
- GC_WB(&ary->elements[ary->beg + idx], item);
-}
-
-static VALUE *
-rary_ptr(rb_ary_t *ary)
-{
- return &ary->elements[ary->beg];
-}
-
-static void
-rary_reserve(rb_ary_t *ary, size_t newlen)
+void
+rary_reserve(VALUE ary, size_t newlen)
{
- if (ary->beg + newlen > ary->cap) {
- if (ary->beg > 0) {
- if (ary->beg > newlen) {
+ rb_ary_t *rary = RARY(ary);
+ if (rary->beg + newlen > rary->cap) {
+ if (rary->beg > 0) {
+ if (rary->beg > newlen) {
newlen = 0;
}
else {
- newlen -= ary->beg;
+ newlen -= rary->beg;
}
- for (size_t i = 0; i < ary->len; i++) {
- GC_WB(&ary->elements[i], ary->elements[ary->beg + i]);
+ for (size_t i = 0; i < rary->len; i++) {
+ GC_WB(&rary->elements[i], rary->elements[rary->beg + i]);
}
- ary->beg = 0;
+ rary->beg = 0;
}
- if (newlen > ary->cap) {
- if (ary->cap > 0) {
+ if (newlen > rary->cap) {
+ if (rary->cap > 0) {
newlen *= 2;
}
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
VALUE *new_elements = (VALUE *)xmalloc(sizeof(VALUE) * newlen);
- for (size_t i = 0; i < ary->len; i++) {
- GC_WB(&new_elements[i], ary->elements[i]);
+ for (size_t i = 0; i < rary->len; i++) {
+ GC_WB(&new_elements[i], rary->elements[i]);
}
GC_WB(&ary->elements, new_elements);
#else
-//printf("xrealloc %p (%ld -> %ld)\n", ary, ary->cap, newlen);
- VALUE *new_elements = xrealloc(ary->elements, sizeof(VALUE) * newlen);
- if (new_elements != ary->elements) {
- GC_WB(&ary->elements, new_elements);
+ VALUE *new_elements = xrealloc(rary->elements,
+ sizeof(VALUE) * newlen);
+ if (new_elements != rary->elements) {
+ GC_WB(&rary->elements, new_elements);
}
#endif
- ary->cap = newlen;
+ rary->cap = newlen;
}
}
}
-static void
-rary_append(rb_ary_t *ary, VALUE item)
-{
- rary_reserve(ary, ary->len + 1);
- rary_replace(ary, ary->len, item);
- ary->len++;
-}
-
-static void
-rary_insert(rb_ary_t *ary, size_t idx, VALUE item)
-{
- assert(idx <= ary->len);
- if (idx < ary->len) {
- rary_reserve(ary, ary->len + 1);
- for (size_t i = ary->len; i > idx; i--) {
- rary_replace(ary, i, rary_elt(ary, i - 1));
- }
- rary_replace(ary, idx, item);
- ary->len++;
- }
- else {
- rary_append(ary, item);
- }
-}
-
static VALUE
-rary_erase(rb_ary_t *ary, size_t idx, size_t len)
+rary_erase(VALUE ary, size_t idx, size_t len)
{
- assert(idx + len <= ary->len);
+ assert(idx + len <= RARY(ary)->len);
VALUE item = rary_elt(ary, idx);
if (idx == 0) {
for (size_t i = 0; i < len; i++) {
- rary_replace(ary, i, Qnil);
+ rary_elt_set(ary, i, Qnil);
}
- if (len < ary->len) {
- ary->beg += len;
+ if (len < RARY(ary)->len) {
+ RARY(ary)->beg += len;
}
else {
- ary->beg = 0;
+ RARY(ary)->beg = 0;
}
}
else {
- for (size_t i = idx; i < ary->len - len; i++) {
- rary_replace(ary, i, rary_elt(ary, i + len));
+ for (size_t i = idx; i < RARY(ary)->len - len; i++) {
+ rary_elt_set(ary, i, rary_elt(ary, i + len));
}
for (size_t i = 0; i < len; i++) {
- rary_replace(ary, ary->len - i - 1, Qnil);
+ rary_elt_set(ary, RARY(ary)->len - i - 1, Qnil);
}
}
- ary->len -= len;
+ RARY(ary)->len -= len;
return item;
}
-static void
-rary_store(rb_ary_t *ary, size_t idx, VALUE item)
+void
+rary_store(VALUE ary, long idx, VALUE item)
{
- if (idx >= ary->len) {
+ if (idx < 0) {
+ const long len = RARY(ary)->len;
+ idx += len;
+ if (idx < 0) {
+ rb_raise(rb_eIndexError, "index %ld out of array",
+ idx - len);
+ }
+ }
+ if (idx >= RARY(ary)->len) {
rary_reserve(ary, idx + 1);
- for (size_t i = ary->len; i < idx + 1; i++) {
- rary_replace(ary, i, Qnil);
+ for (size_t i = RARY(ary)->len; i < idx + 1; i++) {
+ rary_elt_set(ary, i, Qnil);
}
- ary->len = idx + 1;
+ RARY(ary)->len = idx + 1;
}
- rary_replace(ary, idx, item);
+ rary_elt_set(ary, idx, item);
}
static void
-rary_resize(rb_ary_t *ary, size_t newlen)
+rary_resize(VALUE ary, size_t newlen)
{
- if (newlen > ary->cap) {
+ if (newlen > RARY(ary)->cap) {
rary_reserve(ary, newlen);
}
- for (size_t i = ary->len; i < newlen; i++) {
- rary_replace(ary, i, Qnil);
+ for (size_t i = RARY(ary)->len; i < newlen; i++) {
+ rary_elt_set(ary, i, Qnil);
}
- ary->len = newlen;
+ RARY(ary)->len = newlen;
}
static void
-rary_concat(rb_ary_t *ary, rb_ary_t *other, size_t beg, size_t len)
+rary_concat(VALUE ary, VALUE other, size_t beg, size_t len)
{
- rary_reserve(ary, ary->len + len);
- for (size_t i = 0; i < len; i++) {
- rary_replace(ary, i + ary->len, rary_elt(other, beg + i));
+ rary_reserve(ary, RARY(ary)->len + len);
+ if (IS_RARY(other)) {
+ for (size_t i = 0; i < len; i++) {
+ rary_elt_set(ary, i + RARY(ary)->len,
+ rary_elt(other, beg + i));
+ }
}
- ary->len += len;
-}
-
-static void
-rary_reverse(rb_ary_t *ary)
-{
- if (ary->len > 1) {
- for (size_t i = 0; i < ary->len / 2; i++) {
- const size_t j = ary->len - i - 1;
- VALUE elem = rary_elt(ary, i);
- rary_replace(ary, i, rary_elt(ary, j));
- rary_replace(ary, j, elem);
+ else {
+ for (size_t i = 0; i < len; i++) {
+ rary_elt_set(ary, i + RARY(ary)->len,
+ rb_ary_elt(other, beg + i));
}
}
+ RARY(ary)->len += len;
}
static void
-rary_clear(rb_ary_t *ary)
+rary_remove_all(rb_ary_t *ary)
{
memset(ary->elements, 0, sizeof(VALUE) * ary->len);
ary->len = 0;
@@ -216,47 +165,6 @@ rb_equal_fast(VALUE x, VALUE y)
return rb_equal(x, y);
}
-#define NOT_FOUND LONG_MAX
-
-static size_t
-rary_index_of_item(rb_ary_t *ary, size_t origin, VALUE item)
-{
- assert(origin < ary->len);
- for (size_t i = origin; i < ary->len; i++) {
- VALUE item2 = rary_elt(ary, i);
- if (rb_equal_fast(item, item2) == Qtrue) {
- return i;
- }
- }
- return NOT_FOUND;
-}
-
-//#define IS_RARY(x) (*(VALUE *)x == rb_cRubyArray)
-// XXX temporary
-#define IS_RARY(x) __is_rary(*(VALUE *)x)
-#define RARY(x) ((rb_ary_t *)x)
-
-static force_inline bool
-__is_rary(VALUE k)
-{
- while (k != 0) {
- if (k == rb_cRubyArray) {
- return true;
- }
- if (k == rb_cCFArray) {
- return false;
- }
- k = RCLASS_SUPER(k);
- }
- return false;
-}
-
-bool
-rb_klass_is_rary(VALUE klass)
-{
- return __is_rary(klass);
-}
-
void
rb_mem_clear(register VALUE *mem, register long size)
{
@@ -265,123 +173,18 @@ rb_mem_clear(register VALUE *mem, register long size)
}
}
-bool _CFArrayIsMutable(void *);
-
-static inline void
-__rb_ary_modify(VALUE ary)
-{
- long mask;
- if (IS_RARY(ary)) {
- mask = RBASIC(ary)->flags;
- }
- else {
- mask = rb_objc_flag_get_mask((void *)ary);
-#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
- // XXX we shouldn't need to do that and follow the new hash refactoring
- if (!_CFArrayIsMutable((void *)ary)) {
- mask |= FL_FREEZE;
- }
-#endif
- }
- if ((mask & FL_FREEZE) == FL_FREEZE) {
- rb_raise(rb_eRuntimeError, "can't modify frozen/immutable array");
- }
- if ((mask & FL_TAINT) == FL_TAINT && rb_safe_level() >= 4) {
- rb_raise(rb_eSecurityError, "Insecure: can't modify array");
- }
-}
-
-#define rb_ary_modify(ary) \
- do { \
- if (!IS_RARY(ary) || RBASIC(ary)->flags != 0) { \
- __rb_ary_modify(ary); \
- } \
- } \
- while (0)
-
-extern void _CFArraySetCapacity(CFMutableArrayRef array, CFIndex cap);
-
-static inline void
-rb_ary_set_capacity(VALUE ary, long len)
-{
- if (RARRAY_LEN(ary) < len) {
- if (IS_RARY(ary)) {
- rary_reserve(RARY(ary), len);
- }
- else {
- _CFArraySetCapacity((CFMutableArrayRef)ary, len);
- }
- }
-}
-
-VALUE
-rb_ary_freeze(VALUE ary)
-{
- return rb_obj_freeze(ary);
-}
-
-/*
- * call-seq:
- * array.frozen? -> true or false
- *
- * Return <code>true</code> if this array is frozen (or temporarily frozen
- * while being sorted).
- */
-
-VALUE
-rb_ary_frozen_p(VALUE ary)
-{
- return OBJ_FROZEN(ary) ? Qtrue : Qfalse;
-}
-
-static VALUE
-rb_ary_frozen_imp(VALUE ary, SEL sel)
-{
- return rb_ary_frozen_p(ary);
-}
-
-void rb_ary_insert(VALUE ary, long idx, VALUE val);
-
static inline VALUE
-ary_alloc(VALUE klass)
-{
- if (rb_cRubyArray != 0 && (klass == 0 || __is_rary(klass))) {
- NEWOBJ(ary, rb_ary_t);
- ary->basic.flags = 0;
- ary->basic.klass = klass == 0 ? rb_cRubyArray : klass;
- ary->beg = ary->len = ary->cap = 0;
- ary->elements = NULL;
- return (VALUE)ary;
- }
- else {
- CFMutableArrayRef ary = CFArrayCreateMutable(NULL, 0,
- &kCFTypeArrayCallBacks);
- if (klass != 0 && klass != rb_cNSArray && klass != rb_cNSMutableArray) {
- *(Class *)ary = (Class)klass;
- }
- CFMakeCollectable(ary);
- return (VALUE)ary;
- }
-}
-
-VALUE
-rb_ary_new_fast(int argc, ...)
+rary_alloc(VALUE klass, SEL sel)
{
- VALUE ary = ary_alloc(0);
-
- if (argc > 0) {
- va_list ar;
-
- rary_reserve(RARY(ary), argc);
- va_start(ar, argc);
- for (int i = 0; i < argc; i++) {
- VALUE item = va_arg(ar, VALUE);
- rary_append(RARY(ary), item);
- }
- va_end(ar);
- }
+ assert(klass != 0);
+ assert(rb_klass_is_rary(klass));
- return ary;
+ NEWOBJ(ary, rb_ary_t);
+ ary->basic.flags = 0;
+ ary->basic.klass = klass;
+ ary->beg = ary->len = ary->cap = 0;
+ ary->elements = NULL;
+ return (VALUE)ary;
}
static inline void
@@ -395,31 +198,31 @@ assert_ary_len(const long len)
}
}
-static VALUE
-ary_new(VALUE klass, long len)
+VALUE
+rb_ary_new2(long len)
{
assert_ary_len(len);
- VALUE ary = ary_alloc(klass);
- if (IS_RARY(ary)) {
- rary_reserve(RARY(ary), len);
+ VALUE ary;
+ if (rb_cRubyArray != 0) {
+ ary = rary_alloc(rb_cRubyArray, 0);
+ rary_reserve(ary, len);
+ }
+ else {
+ // RubyArray does not exist yet... fallback on an CFArray.
+ ary = (VALUE)CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ CFMakeCollectable((void *)ary);
}
return ary;
}
VALUE
-rb_ary_new2(long len)
-{
- return ary_new(0, len);
-}
-
-VALUE
rb_ary_new(void)
{
return rb_ary_new2(ARY_DEFAULT_SIZE);
}
-#include <stdarg.h>
+static void rary_push(VALUE ary, VALUE item);
VALUE
rb_ary_new3(long n, ...)
@@ -429,9 +232,9 @@ rb_ary_new3(long n, ...)
if (n > 0) {
va_list ar;
va_start(ar, n);
- rary_reserve(RARY(ary), n);
+ rary_reserve(ary, n);
for (long i = 0; i < n; i++) {
- rary_append(RARY(ary), va_arg(ar, VALUE));
+ rary_push(ary, va_arg(ar, VALUE));
}
va_end(ar);
}
@@ -442,26 +245,12 @@ rb_ary_new3(long n, ...)
VALUE
rb_ary_new4(long n, const VALUE *elts)
{
- VALUE ary;
-
- ary = rb_ary_new2(n);
+ VALUE ary = rb_ary_new2(n);
if (n > 0 && elts != NULL) {
- if (IS_RARY(ary)) {
- for (long i = 0; i < n; i++) {
- rary_append(RARY(ary), elts[i]);
- }
- }
- else {
- void **vals = (void **)alloca(n * sizeof(void *));
-
- for (long i = 0; i < n; i++) {
- vals[i] = RB2OC(elts[i]);
- }
- CFArrayReplaceValues((CFMutableArrayRef)ary, CFRangeMake(0, 0),
- (const void **)vals, n);
+ for (long i = 0; i < n; i++) {
+ rary_push(ary, elts[i]);
}
}
-
return ary;
}
@@ -471,101 +260,12 @@ rb_assoc_new(VALUE car, VALUE cdr)
return rb_ary_new3(2, car, cdr);
}
-static VALUE
-to_ary(VALUE ary)
-{
- return rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
-}
-
VALUE
rb_check_array_type(VALUE ary)
{
return rb_check_convert_type(ary, T_ARRAY, "Array", "to_ary");
}
-long
-rb_ary_len(VALUE ary)
-{
- if (IS_RARY(ary)) {
- return RARY(ary)->len;
- }
- else {
- return CFArrayGetCount((CFArrayRef)ary);
- }
-}
-
-VALUE
-rb_ary_elt(VALUE ary, long offset)
-{
- if (IS_RARY(ary)) {
- if (offset < RARY(ary)->len) {
- return rary_elt(RARY(ary), offset);
- }
- }
- else {
- if (offset < CFArrayGetCount((CFArrayRef)ary)) {
- return OC2RB(CFArrayGetValueAtIndex((CFArrayRef)ary, offset));
- }
- }
- return Qnil;
-}
-
-VALUE
-rb_ary_erase(VALUE ary, long offset)
-{
- if (IS_RARY(ary)) {
- return rary_erase(RARY(ary), offset, 1);
- }
- else {
- VALUE item = OC2RB(CFArrayGetValueAtIndex((CFArrayRef)ary, offset));
- CFArrayRemoveValueAtIndex((CFMutableArrayRef)ary, offset);
- return item;
- }
-}
-
-VALUE
-rb_ary_push(VALUE ary, VALUE item)
-{
- rb_ary_modify(ary);
- if (IS_RARY(ary)) {
- rary_append(RARY(ary), item);
- }
- else {
- CFArrayAppendValue((CFMutableArrayRef)ary, (const void *)RB2OC(item));
- }
- return ary;
-}
-
-inline static void
-rb_ary_append(VALUE ary, int argc, VALUE *argv)
-{
- rb_ary_modify(ary);
- if (IS_RARY(ary)) {
- rary_reserve(RARY(ary), argc);
- for (int i = 0; i < argc; i++) {
- rary_append(RARY(ary), argv[i]);
- }
- }
- else {
- for (int i = 0; i < argc; i++) {
- CFArrayAppendValue((CFMutableArrayRef)ary,
- (const void *)RB2OC(argv[i]));
- }
- }
-}
-
-static inline void
-rb_ary_resize(VALUE ary, long new_len)
-{
- if (IS_RARY(ary)) {
- rary_resize(RARY(ary), new_len);
- }
- else {
- // TODO
- abort();
- }
-}
-
/*
* call-seq:
* Array.try_convert(obj) -> array or nil
@@ -587,7 +287,7 @@ rb_ary_resize(VALUE ary, long new_len)
*/
static VALUE
-rb_ary_s_try_convert(VALUE dummy, SEL sel, VALUE ary)
+rary_s_try_convert(VALUE dummy, SEL sel, VALUE ary)
{
return rb_check_array_type(ary);
}
@@ -630,16 +330,18 @@ rb_ary_s_try_convert(VALUE dummy, SEL sel, VALUE ary)
* copy = Array.new(squares)
*/
+static VALUE rary_replace(VALUE rcv, SEL sel, VALUE other);
+
static VALUE
-rb_ary_initialize(VALUE ary, SEL sel, int argc, VALUE *argv)
+rary_initialize(VALUE ary, SEL sel, int argc, VALUE *argv)
{
- //ary = (VALUE)objc_msgSend((id)ary, selInit);
+ rary_modify(ary);
if (argc == 0) {
if (rb_block_given_p()) {
rb_warning("given block not used");
}
- rb_ary_clear(ary);
+ rary_remove_all(RARY(ary));
return ary;
}
@@ -648,31 +350,28 @@ rb_ary_initialize(VALUE ary, SEL sel, int argc, VALUE *argv)
if (argc == 1 && !FIXNUM_P(size)) {
val = rb_check_array_type(size);
if (!NIL_P(val)) {
- rb_ary_replace(ary, val);
+ rary_replace(ary, 0, val);
return ary;
}
}
- long len = NUM2LONG(size);
+ const long len = NUM2LONG(size);
assert_ary_len(len);
-
- rb_ary_modify(ary);
-
if (rb_block_given_p()) {
if (argc == 2) {
rb_warn("block supersedes default value argument");
}
- rb_ary_clear(ary);
+ rary_remove_all(RARY(ary));
for (long i = 0; i < len; i++) {
VALUE v = rb_yield(LONG2NUM(i));
RETURN_IF_BROKEN();
- rb_ary_push(ary, v);
+ rary_push(ary, v);
}
}
else {
- rb_ary_resize(ary, len);
+ rary_resize(ary, len);
for (long i = 0; i < len; i++) {
- rb_ary_store(ary, i, val);
+ rary_store(ary, i, val);
}
}
return ary;
@@ -687,62 +386,43 @@ rb_ary_initialize(VALUE ary, SEL sel, int argc, VALUE *argv)
*/
static VALUE
-rb_ary_s_create(VALUE klass, SEL sel, int argc, VALUE *argv)
+rary_s_create(VALUE klass, SEL sel, int argc, VALUE *argv)
{
- VALUE ary = ary_alloc(klass);
-
+ VALUE ary = rary_alloc(klass, 0);
if (argc < 0) {
rb_raise(rb_eArgError, "negative array size");
}
-
- rb_ary_append(ary, argc, argv);
-
+ rary_reserve(ary, argc);
+ for (int i = 0; i < argc; i++) {
+ rary_push(ary, argv[i]);
+ }
return ary;
}
void
-rb_ary_insert(VALUE ary, long idx, VALUE val)
+rary_insert(VALUE ary, long idx, VALUE val)
{
if (idx < 0) {
- idx += RARRAY_LEN(ary);
+ idx += RARY(ary)->len;
if (idx < 0) {
rb_raise(rb_eIndexError, "index %ld out of array",
- idx - RARRAY_LEN(ary));
- }
- }
-
- if (IS_RARY(ary)) {
- if (idx > RARY(ary)->len) {
- rary_resize(RARY(ary), idx + 1);
- rary_store(RARY(ary), idx, val);
- }
- else {
- rary_insert(RARY(ary), idx, val);
+ idx - RARY(ary)->len);
}
}
- else {
- CFArrayInsertValueAtIndex((CFMutableArrayRef)ary, idx,
- (const void *)RB2OC(val));
+ if (idx > RARY(ary)->len) {
+ rary_resize(ary, idx + 1);
+ rary_store(ary, idx, val);
}
-}
-
-void
-rb_ary_store(VALUE ary, long idx, VALUE val)
-{
- if (idx < 0) {
- const long len = RARRAY_LEN(ary);
- idx += len;
- if (idx < 0) {
- rb_raise(rb_eIndexError, "index %ld out of array",
- idx - len);
+ else if (idx < RARY(ary)->len) {
+ rary_reserve(ary, RARY(ary)->len + 1);
+ for (size_t i = RARY(ary)->len; i > idx; i--) {
+ rary_elt_set(ary, i, rary_elt(ary, i - 1));
}
- }
- if (IS_RARY(ary)) {
- rary_store(RARY(ary), idx, val);
+ rary_elt_set(ary, idx, val);
+ RARY(ary)->len++;
}
else {
- CFArraySetValueAtIndex((CFMutableArrayRef)ary, idx,
- (const void *)RB2OC(val));
+ rary_push(ary, val);
}
}
@@ -753,7 +433,7 @@ ary_shared_first(int argc, VALUE *argv, VALUE ary, bool last, bool remove)
rb_scan_args(argc, argv, "1", &nv);
long n = NUM2LONG(nv);
- const long ary_len = RARRAY_LEN(ary);
+ const long ary_len = RARY(ary)->len;
if (n > ary_len) {
n = ary_len;
}
@@ -765,19 +445,17 @@ ary_shared_first(int argc, VALUE *argv, VALUE ary, bool last, bool remove)
if (last) {
offset = ary_len - n;
}
- VALUE result = rb_ary_new();
+ VALUE result = rb_ary_new();
for (long i = 0; i < n; i++) {
- VALUE item = rb_ary_elt(ary, i + offset);
- rary_append(RARY(result), item);
+ VALUE item = rary_elt(ary, i + offset);
+ rary_push(result, item);
}
-
if (remove) {
for (long i = 0; i < n; i++) {
- rb_ary_erase(ary, offset);
+ rary_erase(ary, offset, 1);
}
}
-
return result;
}
@@ -794,10 +472,12 @@ ary_shared_first(int argc, VALUE *argv, VALUE ary, bool last, bool remove)
*
*/
-static VALUE
-rb_ary_push_imp(VALUE ary, SEL sel, VALUE item)
+VALUE
+rary_push_m(VALUE ary, SEL sel, VALUE item)
{
- return rb_ary_push(ary, item);
+ rary_modify(ary);
+ rary_push(ary, item);
+ return ary;
}
/*
@@ -813,31 +493,22 @@ rb_ary_push_imp(VALUE ary, SEL sel, VALUE item)