ruby-changes:73736
From: Samuel <ko1@a...>
Date: Mon, 26 Sep 2022 14:06:37 +0900 (JST)
Subject: [ruby-changes:73736] 025b8701c0 (master): Add several new methods for getting and setting buffer contents. (#6434)
https://git.ruby-lang.org/ruby.git/commit/?id=025b8701c0 From 025b8701c09813c40339bd8fa1c75e0e5eaf7120 Mon Sep 17 00:00:00 2001 From: Samuel Williams <samuel.williams@o...> Date: Mon, 26 Sep 2022 18:06:12 +1300 Subject: Add several new methods for getting and setting buffer contents. (#6434) --- benchmark/buffer_each.yml | 27 +++ benchmark/buffer_get.yml | 25 ++- common.mk | 1 + io_buffer.c | 509 +++++++++++++++++++++++++++++++++++--------- test/ruby/test_io_buffer.rb | 50 ++++- 5 files changed, 500 insertions(+), 112 deletions(-) create mode 100644 benchmark/buffer_each.yml diff --git a/benchmark/buffer_each.yml b/benchmark/buffer_each.yml new file mode 100644 index 0000000000..417941104e --- /dev/null +++ b/benchmark/buffer_each.yml @@ -0,0 +1,27 @@ https://github.com/ruby/ruby/blob/trunk/benchmark/buffer_each.yml#L1 +prelude: | + # frozen_string_literal: true + Warning[:experimental] = false + string = "The quick brown fox jumped over the lazy dog." + array = string.bytes + buffer = IO::Buffer.for(string) +benchmark: + string.each_byte: | + upcased = String.new + string.each_byte do |byte| + upcased << (byte ^ 32) + end + array.each: | + upcased = String.new + array.each do |byte| + upcased << (byte ^ 32) + end + buffer.each: | + upcased = String.new + buffer.each(:U8) do |offset, byte| + upcased << (byte ^ 32) + end + buffer.each_byte: | + upcased = String.new + buffer.each_byte do |byte| + upcased << (byte ^ 32) + end diff --git a/benchmark/buffer_get.yml b/benchmark/buffer_get.yml index bb9ca7e94a..9e1f99d64e 100644 --- a/benchmark/buffer_get.yml +++ b/benchmark/buffer_get.yml @@ -1,10 +1,25 @@ https://github.com/ruby/ruby/blob/trunk/benchmark/buffer_get.yml#L1 prelude: | # frozen_string_literal: true Warning[:experimental] = false - buffer = IO::Buffer.new(32, IO::Buffer::MAPPED) - string = "\0" * 32 + string = "The quick brown fox jumped over the lazy dog." + buffer = IO::Buffer.for(string) + format = [:U32, :U32, :U32, :U32] benchmark: - buffer.get_value: | - buffer.get_value(:U32, 0) string.unpack1: | - string.unpack1("N") + [ + string.unpack1("N"), + string.unpack1("N", offset: 4), + string.unpack1("N", offset: 8), + string.unpack1("N", offset: 12), + ] + buffer.get_value: | + [ + buffer.get_value(:U32, 0), + buffer.get_value(:U32, 4), + buffer.get_value(:U32, 8), + buffer.get_value(:U32, 12), + ] + buffer.get_values: | + buffer.get_values(format, 0) + string.unpack: | + string.unpack("NNNN") diff --git a/common.mk b/common.mk index 4678fd8940..51adabc783 100644 --- a/common.mk +++ b/common.mk @@ -7669,6 +7669,7 @@ io.$(OBJEXT): {$(VPATH)}util.h https://github.com/ruby/ruby/blob/trunk/common.mk#L7669 io.$(OBJEXT): {$(VPATH)}vm_core.h io.$(OBJEXT): {$(VPATH)}vm_opts.h io_buffer.$(OBJEXT): $(hdrdir)/ruby/ruby.h +io_buffer.$(OBJEXT): $(top_srcdir)/internal/array.h io_buffer.$(OBJEXT): $(top_srcdir)/internal/bits.h io_buffer.$(OBJEXT): $(top_srcdir)/internal/compilers.h io_buffer.$(OBJEXT): $(top_srcdir)/internal/error.h diff --git a/io_buffer.c b/io_buffer.c index 98f1da1fc1..8ec5dc984b 100644 --- a/io_buffer.c +++ b/io_buffer.c @@ -6,6 +6,7 @@ https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L6 **********************************************************************/ +#include "internal/array.h" #include "ruby/io.h" #include "ruby/io/buffer.h" #include "ruby/fiber/scheduler.h" @@ -461,7 +462,6 @@ rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer_flags https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L462 * * Note that some operating systems may not have cache coherency between mapped * buffers and file reads. - * */ static VALUE io_buffer_map(int argc, VALUE *argv, VALUE klass) @@ -543,7 +543,6 @@ io_flags_for_size(size_t size) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L543 * # => * # #<IO::Buffer 0x000055b34497ea10+4 INTERNAL> * # 0x00000000 74 65 73 74 test - * */ VALUE rb_io_buffer_initialize(int argc, VALUE *argv, VALUE self) @@ -628,7 +627,6 @@ io_buffer_validate(struct rb_io_buffer *data) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L627 * * puts IO::Buffer.new(4) # uses to_s internally * # #<IO::Buffer 0x000055769f41b1a0+4 INTERNAL> - * */ VALUE rb_io_buffer_to_s(VALUE self) @@ -756,7 +754,6 @@ rb_io_buffer_inspect(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L754 * * Returns the size of the buffer that was explicitly set (on creation with ::new * or on #resize), or deduced on buffer's creation from string or file. - * */ VALUE rb_io_buffer_size(VALUE self) @@ -774,7 +771,6 @@ rb_io_buffer_size(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L771 * * A buffer becomes invalid if it is a slice of another buffer which has been * freed. - * */ static VALUE rb_io_buffer_valid_p(VALUE self) @@ -790,7 +786,6 @@ rb_io_buffer_valid_p(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L786 * * If the buffer was freed with #free or was never allocated in the first * place. - * */ static VALUE rb_io_buffer_null_p(VALUE self) @@ -807,7 +802,6 @@ rb_io_buffer_null_p(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L802 * If the buffer has 0 size: it is created by ::new with size 0, or with ::for * from an empty string. (Note that empty files can't be mapped, so the buffer * created with ::map will never be empty.) - * */ static VALUE rb_io_buffer_empty_p(VALUE self) @@ -828,7 +822,6 @@ rb_io_buffer_empty_p(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L822 * memory. * * External buffer can't be resized. - * */ static VALUE rb_io_buffer_external_p(VALUE self) @@ -854,7 +847,6 @@ rb_io_buffer_external_p(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L847 * * Internal buffers can be resized, and such an operation will typically * invalidate all slices, but not always. - * */ static VALUE rb_io_buffer_internal_p(VALUE self) @@ -877,7 +869,6 @@ rb_io_buffer_internal_p(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L869 * * Mapped buffers can usually be resized, and such an operation will typically * invalidate all slices, but not always. - * */ static VALUE rb_io_buffer_mapped_p(VALUE self) @@ -901,7 +892,6 @@ rb_io_buffer_mapped_p(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L892 * buffer.locked do * buffer.write(io) # theoretical system call interface * end - * */ static VALUE rb_io_buffer_locked_p(VALUE self) @@ -928,7 +918,6 @@ rb_io_buffer_readonly_p(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L918 * #set_value, #set_string or #copy and similar. * * Frozen strings and read-only files create read-only buffers. - * */ static VALUE io_buffer_readonly_p(VALUE self) @@ -1053,7 +1042,6 @@ rb_io_buffer_locked(VALUE self) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L1042 * # => true * * You can resize a freed buffer to re-allocate it. - * */ VALUE rb_io_buffer_free(VALUE self) @@ -1115,7 +1103,6 @@ io_buffer_validate_range(struct rb_io_buffer *data, size_t offset, size_t length https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L1103 * # ...and original string * string * # => tost - * */ VALUE rb_io_buffer_slice(VALUE self, VALUE _offset, VALUE _length) @@ -1166,7 +1153,7 @@ rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L1153 return 0; } -static void +inline static void io_buffer_get_bytes_for_writing(struct rb_io_buffer *data, void **base, size_t *size) { if (data->flags & RB_IO_BUFFER_READONLY) { @@ -1238,7 +1225,6 @@ rb_io_buffer_get_bytes_for_reading(VALUE self, const void **base, size_t *size) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L1225 * # #<IO::Buffer 0x0000000000000000+0 NULL> * buffer.null? * # => true - * */ VALUE rb_io_buffer_transfer(VALUE self) @@ -1358,7 +1344,6 @@ rb_io_buffer_resize(VALUE self, size_t size) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L1344 * * External buffer (created with ::for), and locked buffer * can not be resized. - * */ static VALUE io_buffer_resize(VALUE self, VALUE size) @@ -1373,7 +1358,6 @@ io_buffer_resize(VALUE self, VALUE size) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L1358 * * Buffers are compared by size and exact contents of the memory they are * referencing using +memcmp+. - * */ static VALUE rb_io_buffer_compare(VALUE self, VALUE other) @@ -1399,7 +1383,7 @@ static void https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L1383 io_buffer_validate_type(size_t size, size_t offset) { if (offset > size) { - rb_raise(rb_eArgError, "Type extends beyond end of buffer!"); + rb_raise(rb_eArgError, "Type extends beyond end of buffer! (offset=%ld > size=%ld)", offset, size); } } @@ -1449,8 +1433,8 @@ ruby_swapf64(double value) https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L1433 return swap.value; } -#define DECLARE_TYPE(name, type, endian, wrap, unwrap, swap) \ -static ID RB_IO_BUFFER_TYPE_##name; \ +#define IO_BUFFER_DECLARE_TYPE(name, type, endian, wrap, unwrap, swap) \ +static ID RB_IO_BUFFER_DATA_TYPE_##name; \ \ static VALUE \ io_buffer_read_##name(const void* base, size_t size, size_t *offset) \ @@ -1471,67 +1455,123 @@ io_buffer_write_##name(const void* base, size_t size, size_t *offset, VALUE _val https://github.com/ruby/ruby/blob/trunk/io_buffer.c#L1455 if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \ memcpy((char*)base + *offset, &value, sizeof(type)); \ *offset += sizeof(type); \ -} - -DECLARE_TYPE(U8, uint8_t, RB_IO_BUFFE (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/