[macruby-changes] [3669] MacRuby/branches/icu/string.c

source_changes at macosforge.org source_changes at macosforge.org
Tue Mar 2 17:32:00 PST 2010


Revision: 3669
          http://trac.macosforge.org/projects/ruby/changeset/3669
Author:   lsansonetti at apple.com
Date:     2010-03-02 17:31:59 -0800 (Tue, 02 Mar 2010)
Log Message:
-----------
added #succ, #next, #upto + fixed a bug in #<=>

Modified Paths:
--------------
    MacRuby/branches/icu/string.c

Modified: MacRuby/branches/icu/string.c
===================================================================
--- MacRuby/branches/icu/string.c	2010-03-02 23:57:21 UTC (rev 3668)
+++ MacRuby/branches/icu/string.c	2010-03-03 01:31:59 UTC (rev 3669)
@@ -875,7 +875,7 @@
 	return self->length_in_bytes > str->length_in_bytes
 	    ? 1 : -1;
     }
-    return res > 1 ? 1 : -1;
+    return res > 0 ? 1 : -1;
 }
 
 static long
@@ -3599,6 +3599,166 @@
     return str;
 }
 
+static VALUE
+rstr_succ(VALUE str, SEL sel)
+{
+    if (rb_str_chars_len(str) == 0) {
+	return str;
+    }
+
+    if (!str_try_making_data_uchars(RSTR(str))) {
+	rb_raise(rb_eArgError,
+		"cannot make receiver data as Unicode characters");
+    }
+
+    UChar *chars_buf = (UChar *)malloc(RSTR(str)->length_in_bytes);
+    UChar *chars_ptr = &chars_buf[1];
+
+    memcpy(chars_ptr, RSTR(str)->data.uchars, RSTR(str)->length_in_bytes);
+
+    long len = BYTES_TO_UCHARS(RSTR(str)->length_in_bytes);
+    UChar carry = 0;
+    bool modified = false;
+
+    for (long i = len - 1; i >= 0; i--) {
+	UChar c = chars_ptr[i];
+	if (isdigit(c)) {
+	    modified = true;
+	    if (c != '9') {
+		chars_ptr[i]++;
+		carry = 0;
+		break;
+	    }
+	    else {
+		chars_ptr[i] = '0';
+		carry = '1';
+	    }
+	}
+	else if (isalpha(c)) {
+	    const bool lower = islower(c);
+	    UChar e = lower ? 'z' : 'Z';
+	    modified = true;
+	    if (c != e) {
+		chars_ptr[i]++;
+		carry = 0;
+		break;
+	    }
+	    else {
+		carry = chars_ptr[i] = lower ? 'a' : 'A';
+	    }
+	}
+#if 0 // TODO: this requires more love
+	else if (!isascii(c)) {
+	    modified = true;
+	    chars_ptr[i]++;
+	    carry = 0;
+	    break;
+	}
+#endif
+    }
+
+    if (!modified) {
+	chars_ptr[len - 1]++;
+    }
+    else if (carry != 0) {
+	chars_ptr = chars_buf;
+	chars_ptr[0] = carry;
+	len++;
+    }
+
+    VALUE newstr = rb_unicode_str_new(chars_ptr, len);
+    free(chars_buf);
+    return newstr;
+}
+
+static VALUE
+rstr_succ_bang(VALUE str, SEL sel)
+{
+    rstr_replace(str, 0, rstr_succ(str, 0));
+    return str;
+}
+
+/*
+ *  call-seq:
+ *     str.upto(other_str, exclusive=false) {|s| block }   => str
+ *  
+ *  Iterates through successive values, starting at <i>str</i> and
+ *  ending at <i>other_str</i> inclusive, passing each value in turn to
+ *  the block. The <code>String#succ</code> method is used to generate
+ *  each value.  If optional second argument exclusive is omitted or is <code>false</code>,
+ *  the last value will be included; otherwise it will be excluded.
+ *     
+ *     "a8".upto("b6") {|s| print s, ' ' }
+ *     for s in "a8".."b6"
+ *       print s, ' '
+ *     end
+ *     
+ *  <em>produces:</em>
+ *     
+ *     a8 a9 b0 b1 b2 b3 b4 b5 b6
+ *     a8 a9 b0 b1 b2 b3 b4 b5 b6
+ */
+
+static VALUE
+rstr_upto(VALUE str, SEL sel, int argc, VALUE *argv)
+{
+    VALUE beg = str;
+    VALUE end, exclusive;
+    rb_scan_args(argc, argv, "11", &end, &exclusive);
+
+    bool excl = RTEST(exclusive);
+    StringValue(end);
+
+    if (rb_str_chars_len(beg) == 1 && rb_str_chars_len(end) == 1) {
+	UChar begc = rb_str_get_uchar(beg, 0);
+	UChar endc = rb_str_get_uchar(end, 0);
+
+	if (begc > endc || (excl && begc == endc)) {
+	    return beg;
+	}
+	while (true) {
+	    rb_yield(rb_unicode_str_new(&begc, 1));
+	    RETURN_IF_BROKEN();
+	    if (!excl && begc == endc) {
+		break;
+	    }
+	    begc++;
+	    if (excl && begc == endc) {
+		break;
+	    }
+	}
+	return beg;
+    }
+
+    const int cmp = rb_str_cmp(beg, end);
+    if (cmp > 0 || (excl && cmp == 0)) {
+	return beg;
+    }
+
+    SEL succ_sel = sel_registerName("succ");
+
+    VALUE current = beg;
+    VALUE after_end = rb_vm_call(end, succ_sel, 0, NULL, false);
+    StringValue(after_end);
+    while (!rb_str_equal(current, after_end)) {
+	rb_yield(current);
+	RETURN_IF_BROKEN();
+	if (!excl && rb_str_equal(current, end)) {
+	    break;
+	}
+	current = rb_vm_call(current, succ_sel, 0, NULL, false);
+	StringValue(current);
+	if (excl && rb_str_equal(current, end)) {
+	    break;
+	}
+	if (rb_str_chars_len(current) > rb_str_chars_len(end)
+		|| rb_str_chars_len(current) == 0) {
+	    break;
+	}
+    }
+    return beg;
+}
+
 // NSString primitives.
 
 static void
@@ -3751,6 +3911,11 @@
     rb_objc_define_method(rb_cRubyString, "each_line", rstr_each_line, -1);
     rb_objc_define_method(rb_cRubyString, "chars", rstr_each_char, 0);
     rb_objc_define_method(rb_cRubyString, "each_char", rstr_each_char, 0);
+    rb_objc_define_method(rb_cRubyString, "succ", rstr_succ, 0);
+    rb_objc_define_method(rb_cRubyString, "succ!", rstr_succ_bang, 0);
+    rb_objc_define_method(rb_cRubyString, "next", rstr_succ, 0);
+    rb_objc_define_method(rb_cRubyString, "next!", rstr_succ_bang, 0);
+    rb_objc_define_method(rb_cRubyString, "upto", rstr_upto, -1);
 
     // Added for MacRuby (debugging).
     rb_objc_define_method(rb_cRubyString, "__chars_count__",
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100302/567d457c/attachment.html>


More information about the macruby-changes mailing list