[前][次][番号順一覧][スレッド一覧]

ruby-changes:18958

From: naruse <ko1@a...>
Date: Tue, 1 Mar 2011 10:39:56 +0900 (JST)
Subject: [ruby-changes:18958] Ruby:r30991 (trunk): * string.c (rb_str_byteslice): Add String#byteslice.

naruse	2011-03-01 10:35:17 +0900 (Tue, 01 Mar 2011)

  New Revision: 30991

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=30991

  Log:
    * string.c (rb_str_byteslice): Add String#byteslice. [ruby-core:35376]

  Modified files:
    trunk/ChangeLog
    trunk/NEWS
    trunk/string.c
    trunk/test/ruby/test_string.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 30990)
+++ ChangeLog	(revision 30991)
@@ -1,3 +1,7 @@
+Tue Mar  1 10:34:39 2011  NARUSE, Yui  <naruse@r...>
+
+	* string.c (rb_str_byteslice): Add String#byteslice. [ruby-core:35376]
+
 Tue Mar  1 00:12:49 2011  Tajima Akio <artonx@y...>
 
 	* include/ruby/win32.h: define WIN32 if neither _WIN64 nor WIN32 
Index: string.c
===================================================================
--- string.c	(revision 30990)
+++ string.c	(revision 30991)
@@ -3987,8 +3987,110 @@
     return value;
 }
 
+static VALUE
+str_byte_substr(VALUE str, long beg, long len)
+{
+	char *p, *s = RSTRING_PTR(str), *e = s + RSTRING_LEN(str);
+	VALUE str2;
+	if (beg > RSTRING_LEN(str)) return Qnil;
+	if (beg < 0) {
+	    beg += RSTRING_LEN(str);
+	    if (beg < 0) return Qnil;
+	}
+	if (beg + len > RSTRING_LEN(str))
+	    len = RSTRING_LEN(str) - beg;
+	if (len <= 0) {
+	    len = 0;
+	    p = 0;
+	}
+	else
+	    p = s + beg;
+
+	if (len > RSTRING_EMBED_LEN_MAX && beg + len == RSTRING_LEN(str)) {
+	    str2 = rb_str_new4(str);
+	    str2 = str_new3(rb_obj_class(str2), str2);
+	    RSTRING(str2)->as.heap.ptr += RSTRING(str2)->as.heap.len - len;
+	    RSTRING(str2)->as.heap.len = len;
+	}
+	else {
+	    str2 = rb_str_new5(str, p, len);
+	    OBJ_INFECT(str2, str);
+	}
+
+	return str2;
+}
+
+static VALUE
+str_byte_aref(VALUE str, VALUE indx)
+{
+    long idx;
+    switch (TYPE(indx)) {
+      case T_FIXNUM:
+	idx = FIX2LONG(indx);
+
+      num_index:
+	str = str_byte_substr(str, idx, 1);
+	if (!NIL_P(str) && RSTRING_LEN(str) == 0) return Qnil;
+	return str;
+
+      default:
+	/* check if indx is Range */
+	{
+	    long beg, len = RSTRING_LEN(str);
+	    VALUE tmp;
+
+	    switch (rb_range_beg_len(indx, &beg, &len, len, 0)) {
+	      case Qfalse:
+		break;
+	      case Qnil:
+		return Qnil;
+	      default:
+		tmp = str_byte_substr(str, beg, len);
+		return tmp;
+	    }
+	}
+	idx = NUM2LONG(indx);
+	goto num_index;
+    }
+    return Qnil;		/* not reached */
+}
+
 /*
  *  call-seq:
+ *     str.byteslice(fixnum)           -> new_str or nil
+ *     str.byteslice(fixnum, fixnum)   -> new_str or nil
+ *     str.byteslice(range)            -> new_str or nil
+ *
+ *  Byte Reference---If passed a single <code>Fixnum</code>, returns a
+ *  substring of one byte at that position. If passed two <code>Fixnum</code>
+ *  objects, returns a substring starting at the offset given by the first, and
+ *  a length given by the second. If given a range, a substring containing
+ *  bytes at offsets given by the range is returned. In all three cases, if
+ *  an offset is negative, it is counted from the end of <i>str</i>. Returns
+ *  <code>nil</code> if the initial offset falls outside the string, the length
+ *  is negative, or the beginning of the range is greater than the end.
+ *
+ *     "hello".byteslice(1)     #=> "e"
+ *     "hello".byteslice(-1)    #=> "o"
+ *     "hello".byteslice(1, 2)  #=> "el"
+ *     "\u3042".byteslice(1, 2) #=> "\x81\x82"
+ *     "\u3042".byteslice(1..3) #=> "\x81\x82"
+ */
+
+static VALUE
+rb_str_byteslice(int argc, VALUE *argv, VALUE str)
+{
+    if (argc == 2) {
+	return str_byte_substr(str, NUM2LONG(argv[0]), NUM2LONG(argv[1]));
+    }
+    if (argc != 1) {
+	rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..2)", argc);
+    }
+    return str_byte_aref(str, argv[0]);
+}
+
+/*
+ *  call-seq:
  *     str.reverse   -> new_str
  *
  *  Returns a new string with the characters from <i>str</i> in reverse order.
@@ -7649,6 +7751,7 @@
     rb_define_method(rb_cString, "chr", rb_str_chr, 0);
     rb_define_method(rb_cString, "getbyte", rb_str_getbyte, 1);
     rb_define_method(rb_cString, "setbyte", rb_str_setbyte, 2);
+    rb_define_method(rb_cString, "byteslice", rb_str_byteslice, -1);
 
     rb_define_method(rb_cString, "to_i", rb_str_to_i, -1);
     rb_define_method(rb_cString, "to_f", rb_str_to_f, 0);
Index: NEWS
===================================================================
--- NEWS	(revision 30990)
+++ NEWS	(revision 30991)
@@ -72,6 +72,7 @@
       * String#unpack supports endian modifiers
     * new method:
       * String#prepend
+      * String#byteslice
 
   * Time
     * extended method:
Index: test/ruby/test_string.rb
===================================================================
--- test/ruby/test_string.rb	(revision 30990)
+++ test/ruby/test_string.rb	(revision 30991)
@@ -1944,4 +1944,33 @@
     assert_equal(S("hello world"), a)
     assert_equal(S("hello "), b)
   end
+
+  def b(str)
+    str.force_encoding(Encoding::ASCII_8BIT)
+  end
+
+  def test_byteslice
+    assert_equal(b("h"), "hello".byteslice(0))
+    assert_equal(nil, "hello".byteslice(5))
+    assert_equal(b("o"), "hello".byteslice(-1))
+    assert_equal(nil, "hello".byteslice(-6))
+
+    assert_equal(b(""), "hello".byteslice(0, 0))
+    assert_equal(b("hello"), "hello".byteslice(0, 6))
+    assert_equal(b("hello"), "hello".byteslice(0, 6))
+    assert_equal(b(""), "hello".byteslice(5, 1))
+    assert_equal(b("o"), "hello".byteslice(-1, 6))
+    assert_equal(nil, "hello".byteslice(-6, 1))
+
+    assert_equal(b("h"), "hello".byteslice(0..0))
+    assert_equal(b(""), "hello".byteslice(5..0))
+    assert_equal(b("o"), "hello".byteslice(4..5))
+    assert_equal(nil, "hello".byteslice(6..0))
+    assert_equal(b(""), "hello".byteslice(-1..0))
+    assert_equal(b("llo"), "hello".byteslice(-3..5))
+
+    assert_equal(b("\x81"), "\u3042".byteslice(1))
+    assert_equal(b("\x81\x82"), "\u3042".byteslice(1, 2))
+    assert_equal(b("\x81\x82"), "\u3042".byteslice(1..2))
+  end
 end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]