mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Supports buffer
and offset
in Array#pack
* pack.c (pack_pack): Supports `buffer` and `offset` in `Array#pack`. [Feature #12754] [ruby-dev:49798] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56957 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
74495cfa11
commit
0dd9c302d9
3 changed files with 94 additions and 5 deletions
4
NEWS
4
NEWS
|
@ -41,6 +41,10 @@ with all sufficient information, see the ChangeLog file or Redmine
|
||||||
* Array#concat [Feature #12333]
|
* Array#concat [Feature #12333]
|
||||||
Now takes multiple arguments.
|
Now takes multiple arguments.
|
||||||
|
|
||||||
|
* Array#pack [Feature #12754]
|
||||||
|
Now takes optional arguments `buffer' and `offset' to reuse already
|
||||||
|
allocated buffer.
|
||||||
|
|
||||||
* Comparable
|
* Comparable
|
||||||
|
|
||||||
* Comparable#clamp. [Feature #10594]
|
* Comparable#clamp. [Feature #10594]
|
||||||
|
|
57
pack.c
57
pack.c
|
@ -141,6 +141,8 @@ rb_str_associated(VALUE str)
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* arr.pack( aTemplateString ) -> aBinaryString
|
* arr.pack( aTemplateString ) -> aBinaryString
|
||||||
|
* arr.pack( aTemplateString, buffer: aBufferString ) -> aBufferString
|
||||||
|
* arr.pack( aTemplateString, buffer: aBufferString, offset: offsetOfBuffer ) -> aBufferString
|
||||||
*
|
*
|
||||||
* Packs the contents of <i>arr</i> into a binary sequence according to
|
* Packs the contents of <i>arr</i> into a binary sequence according to
|
||||||
* the directives in <i>aTemplateString</i> (see the table below)
|
* the directives in <i>aTemplateString</i> (see the table below)
|
||||||
|
@ -162,6 +164,18 @@ rb_str_associated(VALUE str)
|
||||||
* a.pack("a3a3a3") #=> "a\000\000b\000\000c\000\000"
|
* a.pack("a3a3a3") #=> "a\000\000b\000\000c\000\000"
|
||||||
* n.pack("ccc") #=> "ABC"
|
* n.pack("ccc") #=> "ABC"
|
||||||
*
|
*
|
||||||
|
* If <i>aBufferString</i> is specified and its capacity is enough,
|
||||||
|
* +pack+ uses it as the buffer and returns it.
|
||||||
|
* User can also specify <i>offsetOfBuffer</i>, then the result of +pack+
|
||||||
|
* is filled after <i>offsetOfBuffer</i> bytes.
|
||||||
|
* If original contents of <i>aBufferString</i> exists and it's longer than
|
||||||
|
* <i>offsetOfBuffer</i>, the rest of <i>offsetOfBuffer</i> are cut.
|
||||||
|
* If it's shorter, the gap is filled with ``<code>\0</code>''.
|
||||||
|
*
|
||||||
|
* Note that ``buffer:'' option does not guarantee not to allocate memory
|
||||||
|
* in +pack+. If the capacity of <i>aBufferString</i> is not enough,
|
||||||
|
* +pack+ allocates memory.
|
||||||
|
*
|
||||||
* Directives for +pack+.
|
* Directives for +pack+.
|
||||||
*
|
*
|
||||||
* Integer | Array |
|
* Integer | Array |
|
||||||
|
@ -255,12 +269,12 @@ rb_str_associated(VALUE str)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
pack_pack(VALUE ary, VALUE fmt)
|
pack_pack(int argc, VALUE *argv, VALUE ary)
|
||||||
{
|
{
|
||||||
static const char nul10[] = "\0\0\0\0\0\0\0\0\0\0";
|
static const char nul10[] = "\0\0\0\0\0\0\0\0\0\0";
|
||||||
static const char spc10[] = " ";
|
static const char spc10[] = " ";
|
||||||
const char *p, *pend;
|
const char *p, *pend;
|
||||||
VALUE res, from, associates = 0;
|
VALUE fmt, opt = Qnil, res, from, associates = 0, buffer = 0;
|
||||||
char type;
|
char type;
|
||||||
long len, idx, plen;
|
long len, idx, plen;
|
||||||
const char *ptr;
|
const char *ptr;
|
||||||
|
@ -270,9 +284,46 @@ pack_pack(VALUE ary, VALUE fmt)
|
||||||
#endif
|
#endif
|
||||||
int integer_size, bigendian_p;
|
int integer_size, bigendian_p;
|
||||||
|
|
||||||
|
rb_scan_args(argc, argv, "10:", &fmt, &opt);
|
||||||
|
|
||||||
StringValue(fmt);
|
StringValue(fmt);
|
||||||
p = RSTRING_PTR(fmt);
|
p = RSTRING_PTR(fmt);
|
||||||
pend = p + RSTRING_LEN(fmt);
|
pend = p + RSTRING_LEN(fmt);
|
||||||
|
if (!NIL_P(opt)) {
|
||||||
|
static ID keyword_ids[2];
|
||||||
|
VALUE kwargs[2];
|
||||||
|
VALUE voff;
|
||||||
|
long offset;
|
||||||
|
|
||||||
|
if (!keyword_ids[0]) {
|
||||||
|
CONST_ID(keyword_ids[0], "buffer");
|
||||||
|
CONST_ID(keyword_ids[1], "offset");
|
||||||
|
}
|
||||||
|
|
||||||
|
rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs);
|
||||||
|
buffer = kwargs[0];
|
||||||
|
voff = kwargs[1];
|
||||||
|
|
||||||
|
if (buffer == Qundef && !NIL_P(voff))
|
||||||
|
rb_raise(rb_eArgError, "offset is specified without buffer");
|
||||||
|
if (buffer != Qundef) {
|
||||||
|
long len;
|
||||||
|
if (!RB_TYPE_P(buffer, T_STRING))
|
||||||
|
rb_raise(rb_eTypeError, "buffer must be String, not %s", rb_obj_classname(buffer));
|
||||||
|
if (voff != Qundef) {
|
||||||
|
offset = NUM2LONG(voff);
|
||||||
|
if (rb_str_capacity(buffer) < offset)
|
||||||
|
rb_raise(rb_eArgError, "buffer is too small for offset");
|
||||||
|
len = RSTRING_LEN(buffer);
|
||||||
|
rb_str_set_len(buffer, offset);
|
||||||
|
if (len < offset)
|
||||||
|
memset(RSTRING_PTR(buffer) + len, '\0', offset - len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buffer)
|
||||||
|
res = buffer;
|
||||||
|
else
|
||||||
res = rb_str_buf_new(0);
|
res = rb_str_buf_new(0);
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
|
@ -1948,7 +1999,7 @@ utf8_to_uv(const char *p, long *lenp)
|
||||||
void
|
void
|
||||||
Init_pack(void)
|
Init_pack(void)
|
||||||
{
|
{
|
||||||
rb_define_method(rb_cArray, "pack", pack_pack, 1);
|
rb_define_method(rb_cArray, "pack", pack_pack, -1);
|
||||||
rb_define_method(rb_cString, "unpack", pack_unpack, 1);
|
rb_define_method(rb_cString, "unpack", pack_unpack, 1);
|
||||||
|
|
||||||
id_associated = rb_make_internal_id();
|
id_associated = rb_make_internal_id();
|
||||||
|
|
|
@ -812,4 +812,38 @@ EXPECTED
|
||||||
assert_raise_with_message(ArgumentError, /too few/) {ary.pack("AA")}
|
assert_raise_with_message(ArgumentError, /too few/) {ary.pack("AA")}
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_pack_with_buffer
|
||||||
|
buf = String.new(capacity: 100)
|
||||||
|
|
||||||
|
assert_raise_with_message(ArgumentError, /without buffer/) {
|
||||||
|
[0xDEAD_BEEF].pack('N', offset: 10)
|
||||||
|
}
|
||||||
|
assert_raise_with_message(ArgumentError, /too small/) {
|
||||||
|
[0xDEAD_BEEF].pack('N', buffer: buf, offset: 200)
|
||||||
|
}
|
||||||
|
assert_raise_with_message(RuntimeError, /frozen/) {
|
||||||
|
[0xDEAD_BEEF].pack('N', buffer: 'foo'.freeze)
|
||||||
|
}
|
||||||
|
assert_raise_with_message(TypeError, /into Integer/) {
|
||||||
|
[0xDEAD_BEEF].pack('N', buffer: buf, offset: '10')
|
||||||
|
}
|
||||||
|
assert_raise_with_message(TypeError, /must be String/) {
|
||||||
|
[0xDEAD_BEEF].pack('N', buffer: Object.new)
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = [buf].pack('p')
|
||||||
|
|
||||||
|
[0xDEAD_BEEF].pack('N', buffer: buf)
|
||||||
|
assert_equal "\xDE\xAD\xBE\xEF", buf
|
||||||
|
|
||||||
|
[0xBABE_F00D].pack('N', buffer: buf, offset: 4)
|
||||||
|
assert_equal "\xDE\xAD\xBE\xEF\xBA\xBE\xF0\x0D", buf
|
||||||
|
assert_equal addr, [buf].pack('p')
|
||||||
|
|
||||||
|
[0xBAAD_FACE].pack('N', buffer: buf, offset: 10)
|
||||||
|
assert_equal "\xDE\xAD\xBE\xEF\xBA\xBE\xF0\x0D\0\0\xBA\xAD\xFA\xCE", buf
|
||||||
|
|
||||||
|
assert_equal addr, [buf].pack('p')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue