summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <[email protected]>2021-10-18 16:23:54 +0200
committerJean Boussier <[email protected]>2021-10-26 22:27:30 +0200
commite5319dc9856298f38aa9cdc6ed55e39ad0e8e070 ()
tree7c1d685ae65979ce2ae3bee4ccce54507d3f49f8
parent717ab0bb2ee63dfe76076e0c9f91fbac3a0de4fd (diff)
pack.c: add an offset argument to unpack and unpack1
[Feature #18254] This is useful to avoid repeteadly copying strings when parsing binary formats
-rw-r--r--pack.c19
-rw-r--r--pack.rb31
-rw-r--r--spec/ruby/core/string/unpack/shared/basic.rb20
-rw-r--r--spec/ruby/core/string/unpack1_spec.rb20
-rw-r--r--test/ruby/test_pack.rb26
5 files changed, 103 insertions, 13 deletions
@@ -944,7 +944,7 @@ hex2num(char c)
#define UNPACK_1 2
static VALUE
-pack_unpack_internal(VALUE str, VALUE fmt, int mode)
{
#define hexdigits ruby_hexdigits
char *s, *send;
@@ -973,8 +973,15 @@ pack_unpack_internal(VALUE str, VALUE fmt, int mode)
StringValue(str);
StringValue(fmt);
s = RSTRING_PTR(str);
- send = s + RSTRING_LEN(str);
p = RSTRING_PTR(fmt);
pend = p + RSTRING_LEN(fmt);
@@ -1614,16 +1621,16 @@ pack_unpack_internal(VALUE str, VALUE fmt, int mode)
}
static VALUE
-pack_unpack(rb_execution_context_t *ec, VALUE str, VALUE fmt)
{
int mode = rb_block_given_p() ? UNPACK_BLOCK : UNPACK_ARRAY;
- return pack_unpack_internal(str, fmt, mode);
}
static VALUE
-pack_unpack1(rb_execution_context_t *ec, VALUE str, VALUE fmt)
{
- return pack_unpack_internal(str, fmt, UNPACK_1);
}
int
@@ -148,10 +148,11 @@ end
class String
# call-seq:
# str.unpack(format) -> anArray
#
# Decodes <i>str</i> (which may contain binary data) according to the
- # format string, returning an array of each value extracted. The
- # format string consists of a sequence of single-character directives,
# summarized in the table at the end of this entry.
# Each directive may be followed
# by a number, indicating the number of times to repeat with this
@@ -161,7 +162,15 @@ class String
# exclamation mark (``<code>!</code>'') to use the underlying
# platform's native size for the specified type; otherwise, it uses a
# platform-independent consistent size. Spaces are ignored in the
- # format string. See also String#unpack1, Array#pack.
#
# "abc \0\0abc \0\0".unpack('A6Z6') #=> ["abc", "abc "]
# "abc \0\0".unpack('a3a3') #=> ["abc", " \000\000"]
@@ -263,15 +272,23 @@ class String
# * J, J! j, and j! are available since Ruby 2.3.
# * Q_, Q!, q_, and q! are available since Ruby 2.1.
# * I!<, i!<, I!>, and i!> are available since Ruby 1.9.3.
- def unpack(fmt)
- Primitive.pack_unpack(fmt)
end
# call-seq:
# str.unpack1(format) -> obj
#
# Decodes <i>str</i> (which may contain binary data) according to the
# format string, returning the first value extracted.
# See also String#unpack, Array#pack.
#
# Contrast with String#unpack:
@@ -287,7 +304,7 @@ class String
#
# Thus unpack1 is convenient, makes clear the intention and signals
# the expected return value to those reading the code.
- def unpack1(fmt)
- Primitive.pack_unpack1(fmt)
end
end
@@ -16,6 +16,12 @@ describe :string_unpack_basic, shared: true do
it "raises a TypeError when passed an Integer" do
-> { "abc".unpack(1) }.should raise_error(TypeError)
end
end
describe :string_unpack_no_platform, shared: true do
@@ -26,4 +32,18 @@ describe :string_unpack_no_platform, shared: true do
it "raises an ArgumentError when the format modifier is '!'" do
-> { "abcdefgh".unpack(unpack_format("!")) }.should raise_error(ArgumentError)
end
end
@@ -7,4 +7,24 @@ describe "String#unpack1" do
"aG9nZWZ1Z2E=".unpack1("m").should == "hogefuga"
"A".unpack1("B*").should == "01000001"
end
end
@@ -869,4 +869,30 @@ EXPECTED
assert_equal "hogefuga", "aG9nZWZ1Z2E=".unpack1("m")
assert_equal "01000001", "A".unpack1("B*")
end
end