Class: IO::Buffer
- Includes:
- Comparable
- Defined in:
- io_buffer.c,
io_buffer.c
Overview
IO::Buffer is a efficient zero-copy buffer for input/output. There are typical use cases:
-
Create an empty buffer with ::new, fill it with buffer using #copy or #set_value, #set_string, get buffer with #get_string or write it directly to some file with #write.
-
Create a buffer mapped to some string with ::for, then it could be used both for reading with #get_string or #get_value, and writing (writing will change the source string, too).
-
Create a buffer mapped to some file with ::map, then it could be used for reading and writing the underlying file.
-
Create a string of a fixed size with ::string, then #read into it, or modify it using #set_value.
Interaction with string and file memory is performed by efficient low-level C mechanisms like ‘memcpy`.
The class is meant to be an utility for implementing more high-level mechanisms like Fiber::Scheduler#io_read and Fiber::Scheduler#io_write and parsing binary protocols.
Examples of Usage
Empty buffer:
buffer = IO::Buffer.new(8) # create empty 8-byte buffer
# =>
# #<IO::Buffer 0x0000555f5d1a5c50+8 INTERNAL>
# ...
buffer
# =>
# <IO::Buffer 0x0000555f5d156ab0+8 INTERNAL>
# 0x00000000 00 00 00 00 00 00 00 00
buffer.set_string('test', 2) # put there bytes of the "test" string, starting from offset 2
# => 4
buffer.get_string # get the result
# => "\x00\x00test\x00\x00"
Buffer from string:
string = 'buffer'
buffer = IO::Buffer.for(string)
# =>
# #<IO::Buffer 0x00007f3f02be9b18+4 SLICE>
# ...
buffer
# =>
# #<IO::Buffer 0x00007f3f02be9b18+4 SLICE>
# 0x00000000 64 61 74 61 buffer
buffer.get_string(2) # read content starting from offset 2
# => "ta"
buffer.set_string('---', 1) # write content, starting from offset 1
# => 3
buffer
# =>
# #<IO::Buffer 0x00007f3f02be9b18+4 SLICE>
# 0x00000000 64 2d 2d 2d d---
string # original string changed, too
# => "d---"
Buffer from file:
File.write('test.txt', 'test buffer')
# => 9
buffer = IO::Buffer.map(File.open('test.txt'))
# =>
# #<IO::Buffer 0x00007f3f0768c000+9 MAPPED IMMUTABLE>
# ...
buffer.get_string(5, 2) # read 2 bytes, starting from offset 5
# => "da"
buffer.set_string('---', 1) # attempt to write
# in `set_string': Buffer is not writable! (IO::Buffer::AccessError)
# To create writable file-mapped buffer
# Open file for read-write, pass size, offset, and flags=0
buffer = IO::Buffer.map(File.open('test.txt', 'r+'), 9, 0, 0)
buffer.set_string('---', 1)
# => 3 -- bytes written
File.read('test.txt')
# => "t--- buffer"
The class is experimental and the interface is subject to change, this is especially true of file mappings which may be removed entirely in the future.
Defined Under Namespace
Classes: AccessError, AllocationError, InvalidatedError, LockedError, MaskError
Constant Summary collapse
- PAGE_SIZE =
The operating system page size. Used for efficient page-aligned memory allocations.
SIZET2NUM(RUBY_IO_BUFFER_PAGE_SIZE)
- DEFAULT_SIZE =
The default buffer size, typically a (small) multiple of the PAGE_SIZE.
Can be explicitly specified by setting the RUBY_IO_BUFFER_DEFAULT_SIZE environment variable.
SIZET2NUM(RUBY_IO_BUFFER_DEFAULT_SIZE)
- EXTERNAL =
Indicates that the memory in the buffer is owned by someone else. See #external? for more details.
RB_INT2NUM(RB_IO_BUFFER_EXTERNAL)
- INTERNAL =
Indicates that the memory in the buffer is owned by the buffer. See #internal? for more details.
RB_INT2NUM(RB_IO_BUFFER_INTERNAL)
- MAPPED =
Indicates that the memory in the buffer is mapped by the operating system. See #mapped? for more details.
RB_INT2NUM(RB_IO_BUFFER_MAPPED)
- SHARED =
Indicates that the memory in the buffer is also mapped such that it can be shared with other processes. See #shared? for more details.
RB_INT2NUM(RB_IO_BUFFER_SHARED)
- LOCKED =
Indicates that the memory in the buffer is locked and cannot be resized or freed. See #locked? and #locked for more details.
RB_INT2NUM(RB_IO_BUFFER_LOCKED)
- PRIVATE =
Indicates that the memory in the buffer is mapped privately and changes won’t be replicated to the underlying file. See #private? for more details.
RB_INT2NUM(RB_IO_BUFFER_PRIVATE)
- READONLY =
Indicates that the memory in the buffer is read only, and attempts to modify it will fail. See #readonly? for more details.
RB_INT2NUM(RB_IO_BUFFER_READONLY)
- LITTLE_ENDIAN =
Refers to little endian byte order, where the least significant byte is stored first. See #get_value for more details.
RB_INT2NUM(RB_IO_BUFFER_LITTLE_ENDIAN)
- BIG_ENDIAN =
Refers to big endian byte order, where the most significant byte is stored first. See #get_value for more details.
RB_INT2NUM(RB_IO_BUFFER_BIG_ENDIAN)
- HOST_ENDIAN =
Refers to the byte order of the host machine. See #get_value for more details.
RB_INT2NUM(RB_IO_BUFFER_HOST_ENDIAN)
- NETWORK_ENDIAN =
Refers to network byte order, which is the same as big endian. See #get_value for more details.
RB_INT2NUM(RB_IO_BUFFER_NETWORK_ENDIAN)
Class Method Summary collapse
-
.for(string) ⇒ Object
Creates a zero-copy IO::Buffer from the given string’s memory.
-
.IO::Buffer.map(file, [size, [offset, [flags]]]) ⇒ Object
Create an IO::Buffer for reading from
file
by memory-mapping the file. -
.size_of(buffer_type) ⇒ Object
Returns the size of the given buffer type(s) in bytes.
-
.IO::Buffer.string(length) {|io_buffer| ... } ⇒ String
Creates a new string of the given length and yields a zero-copy IO::Buffer instance to the block which uses the string as a source.
Instance Method Summary collapse
-
#&(mask) ⇒ Object
Generate a new buffer the same size as the source by applying the binary AND operation to the source, using the mask, repeating as necessary.
- #<=> ⇒ Object
-
#^(mask) ⇒ Object
Generate a new buffer the same size as the source by applying the binary XOR operation to the source, using the mask, repeating as necessary.
-
#and!(mask) ⇒ Object
Modify the source buffer in place by applying the binary AND operation to the source, using the mask, repeating as necessary.
-
#clear(value = 0, [offset, [length]]) ⇒ self
Fill buffer with
value
, starting withoffset
and going forlength
bytes. -
#copy(source, [offset, [length, [source_offset]]]) ⇒ Object
Efficiently copy from a source IO::Buffer into the buffer, at
offset
usingmemcpy
. -
#each(*args) ⇒ Object
Iterates over the buffer, yielding each
value
ofbuffer_type
starting fromoffset
. -
#each_byte(*args) ⇒ Object
Iterates over the buffer, yielding each byte starting from
offset
. - #empty? ⇒ Boolean
- #external? ⇒ Boolean
- #free ⇒ Object
-
#get_string([offset, [length, [encoding]]]) ⇒ String
Read a chunk or all of the buffer into a string, in the specified
encoding
. -
#get_value(buffer_type, offset) ⇒ Numeric
Read from buffer a value of
type
atoffset
. -
#get_values(buffer_types, offset) ⇒ Array
Similar to #get_value, except that it can handle multiple buffer types and returns an array of values.
- #hexdump ⇒ Object
-
#IO::Buffer.new([size = DEFAULT_SIZE, [flags = 0]]) ⇒ Object
constructor
Create a new zero-filled IO::Buffer of
size
bytes. -
#initialize_copy(source) ⇒ Object
Make an internal copy of the source buffer.
- #inspect ⇒ Object
- #internal? ⇒ Boolean
-
#locked ⇒ Object
rb_define_method(rb_cIOBuffer, “unlock”, rb_io_buffer_unlock, 0);.
- #locked? ⇒ Boolean
- #mapped? ⇒ Boolean
-
#not! ⇒ Object
Modify the source buffer in place by applying the binary NOT operation to the source.
- #null? ⇒ Boolean
-
#or!(mask) ⇒ Object
Modify the source buffer in place by applying the binary OR operation to the source, using the mask, repeating as necessary.
-
#pread(io, from, [length, [offset]]) ⇒ Object
Read at least
length
bytes from theio
starting at the specifiedfrom
position, into the buffer starting atoffset
. - #private? ⇒ Boolean
-
#pwrite(io, from, [length, [offset]]) ⇒ Object
Write at least
length
bytes from the buffer starting atoffset
, into theio
starting at the specifiedfrom
position. -
#read(io, [length, [offset]]) ⇒ Object
Read at least
length
bytes from theio
, into the buffer starting atoffset
. - #readonly? ⇒ Boolean
- #resize ⇒ Object
-
#set_string(string, [offset, [length, [source_offset]]]) ⇒ Object
Efficiently copy from a source String into the buffer, at
offset
usingmemcpy
. -
#set_value(type, offset, value) ⇒ Object
Write to a buffer a
value
oftype
atoffset
. -
#set_values(buffer_types, offset, values) ⇒ Object
Write
values
ofbuffer_types
atoffset
to the buffer. - #shared? ⇒ Boolean
- #size ⇒ Object
-
#slice ⇒ Object
Manipulation:.
- #to_s ⇒ Object
- #transfer ⇒ Object
- #valid? ⇒ Boolean
-
#values(buffer_type, [offset, [count]]) ⇒ Array
Returns an array of values of
buffer_type
starting fromoffset
. -
#write(io, [length, [offset]]) ⇒ Object
Write at least
length
bytes from the buffer starting atoffset
, into theio
. -
#xor!(mask) ⇒ Object
Modify the source buffer in place by applying the binary XOR operation to the source, using the mask, repeating as necessary.
-
#|(mask) ⇒ Object
Generate a new buffer the same size as the source by applying the binary OR operation to the source, using the mask, repeating as necessary.
-
#~ ⇒ Object
Generate a new buffer the same size as the source by applying the binary NOT operation to the source.
Methods included from Comparable
#<, #<=, #==, #>, #>=, #between?, #clamp
Constructor Details
#IO::Buffer.new([size = DEFAULT_SIZE, [flags = 0]]) ⇒ Object
Create a new zero-filled IO::Buffer of size
bytes. By default, the buffer will be internal: directly allocated chunk of the memory. But if the requested size
is more than OS-specific IO::Buffer::PAGE_SIZE, the buffer would be allocated using the virtual memory mechanism (anonymous mmap
on Unix, VirtualAlloc
on Windows). The behavior can be forced by passing IO::Buffer::MAPPED as a second parameter.
buffer = IO::Buffer.new(4)
# =>
# #<IO::Buffer 0x000055b34497ea10+4 INTERNAL>
# 0x00000000 00 00 00 00 ....
buffer.get_string(0, 1) # => "\x00"
buffer.set_string("test")
buffer
# =>
# #<IO::Buffer 0x000055b34497ea10+4 INTERNAL>
# 0x00000000 74 65 73 74 test
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 |
# File 'io_buffer.c', line 749
VALUE
rb_io_buffer_initialize(int argc, VALUE *argv, VALUE self)
{
io_buffer_experimental();
rb_check_arity(argc, 0, 2);
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
size_t size;
if (argc > 0) {
size = io_buffer_extract_size(argv[0]);
}
else {
size = RUBY_IO_BUFFER_DEFAULT_SIZE;
}
enum rb_io_buffer_flags flags = 0;
if (argc >= 2) {
flags = io_buffer_extract_flags(argv[1]);
}
else {
flags |= io_flags_for_size(size);
}
io_buffer_initialize(self, buffer, NULL, size, flags, Qnil);
return self;
}
|
Class Method Details
.IO::Buffer.for(string) ⇒ Object .IO::Buffer.for(string) {|io_buffer| ... } ⇒ Object
Creates a zero-copy IO::Buffer from the given string’s memory. Without a block a frozen internal copy of the string is created efficiently and used as the buffer source. When a block is provided, the buffer is associated directly with the string’s internal buffer and updating the buffer will update the string.
Until #free is invoked on the buffer, either explicitly or via the garbage collector, the source string will be locked and cannot be modified.
If the string is frozen, it will create a read-only buffer which cannot be modified. If the string is shared, it may trigger a copy-on-write when using the block form.
string = 'test'
buffer = IO::Buffer.for(string)
buffer.external? #=> true
buffer.get_string(0, 1)
# => "t"
string
# => "best"
buffer.resize(100)
# in `resize': Cannot resize external buffer! (IO::Buffer::AccessError)
IO::Buffer.for(string) do |buffer|
buffer.set_string("T")
string
# => "Test"
end
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 |
# File 'io_buffer.c', line 551
VALUE
rb_io_buffer_type_for(VALUE klass, VALUE string)
{
StringValue(string);
// If the string is frozen, both code paths are okay.
// If the string is not frozen, if a block is not given, it must be frozen.
if (rb_block_given_p()) {
struct io_buffer_for_yield_instance_arguments arguments = {
.klass = klass,
.string = string,
.instance = Qnil,
.flags = 0,
};
return rb_ensure(io_buffer_for_yield_instance, (VALUE)&arguments, io_buffer_for_yield_instance_ensure, (VALUE)&arguments);
}
else {
// This internally returns the source string if it's already frozen.
string = rb_str_tmp_frozen_acquire(string);
return io_buffer_for_make_instance(klass, string, RB_IO_BUFFER_READONLY);
}
}
|
.IO::Buffer.map(file, [size, [offset, [flags]]]) ⇒ Object
Create an IO::Buffer for reading from file
by memory-mapping the file. file_io
should be a File
instance, opened for reading.
Optional size
and offset
of mapping can be specified.
By default, the buffer would be immutable (read only); to create a writable mapping, you need to open a file in read-write mode, and explicitly pass flags
argument without IO::Buffer::IMMUTABLE.
File.write('test.txt', 'test')
buffer = IO::Buffer.map(File.open('test.txt'), nil, 0, IO::Buffer::READONLY)
# => #<IO::Buffer 0x00000001014a0000+4 MAPPED READONLY>
buffer.readonly? # => true
buffer.get_string
# => "test"
buffer.set_string('b', 0)
# `set_string': Buffer is not writable! (IO::Buffer::AccessError)
# create read/write mapping: length 4 bytes, offset 0, flags 0
buffer = IO::Buffer.map(File.open('test.txt', 'r+'), 4, 0)
buffer.set_string('b', 0)
# => 1
# Check it
File.read('test.txt')
# => "best"
Note that some operating systems may not have cache coherency between mapped buffers and file reads.
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 |
# File 'io_buffer.c', line 671
static VALUE
io_buffer_map(int argc, VALUE *argv, VALUE klass)
{
rb_check_arity(argc, 1, 4);
// We might like to handle a string path?
VALUE io = argv[0];
size_t size;
if (argc >= 2 && !RB_NIL_P(argv[1])) {
size = io_buffer_extract_size(argv[1]);
}
else {
rb_off_t file_size = rb_file_size(io);
// Compiler can confirm that we handled file_size < 0 case:
if (file_size < 0) {
rb_raise(rb_eArgError, "Invalid negative file size!");
}
// Here, we assume that file_size is positive:
else if ((uintmax_t)file_size > SIZE_MAX) {
rb_raise(rb_eArgError, "File larger than address space!");
}
else {
// This conversion should be safe:
size = (size_t)file_size;
}
}
// This is the file offset, not the buffer offset:
rb_off_t offset = 0;
if (argc >= 3) {
offset = NUM2OFFT(argv[2]);
}
enum rb_io_buffer_flags flags = 0;
if (argc >= 4) {
flags = io_buffer_extract_flags(argv[3]);
}
return rb_io_buffer_map(io, size, offset, flags);
}
|
.size_of(buffer_type) ⇒ Object .size_of(arrayofbuffer_type) ⇒ Object
1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 |
# File 'io_buffer.c', line 1935
static VALUE
io_buffer_size_of(VALUE klass, VALUE buffer_type)
{
if (RB_TYPE_P(buffer_type, T_ARRAY)) {
size_t total = 0;
for (long i = 0; i < RARRAY_LEN(buffer_type); i++) {
total += io_buffer_buffer_type_size(RB_SYM2ID(RARRAY_AREF(buffer_type, i)));
}
return SIZET2NUM(total);
}
else {
return SIZET2NUM(io_buffer_buffer_type_size(RB_SYM2ID(buffer_type)));
}
}
|
.IO::Buffer.string(length) {|io_buffer| ... } ⇒ String
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 |
# File 'io_buffer.c', line 588
VALUE
rb_io_buffer_type_string(VALUE klass, VALUE length)
{
VALUE string = rb_str_new(NULL, RB_NUM2LONG(length));
struct io_buffer_for_yield_instance_arguments arguments = {
.klass = klass,
.string = string,
.instance = Qnil,
};
rb_ensure(io_buffer_for_yield_instance, (VALUE)&arguments, io_buffer_for_yield_instance_ensure, (VALUE)&arguments);
return string;
}
|
Instance Method Details
#&(mask) ⇒ Object
Generate a new buffer the same size as the source by applying the binary AND operation to the source, using the mask, repeating as necessary.
IO::Buffer.for("1234567890") & IO::Buffer.for("\xFF\x00\x00\xFF")
# =>
# #<IO::Buffer 0x00005589b2758480+4 INTERNAL>
# 0x00000000 31 00 00 34 35 00 00 38 39 00 1..45..89.
3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 |
# File 'io_buffer.c', line 3203
static VALUE
io_buffer_and(VALUE self, VALUE mask)
{
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
io_buffer_check_mask(mask_buffer);
VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
struct rb_io_buffer *output_buffer = NULL;
TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
memory_and(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
return output;
}
|
#<=> ⇒ Object
#^(mask) ⇒ Object
Generate a new buffer the same size as the source by applying the binary XOR operation to the source, using the mask, repeating as necessary.
IO::Buffer.for("1234567890") ^ IO::Buffer.for("\xFF\x00\x00\xFF")
# =>
# #<IO::Buffer 0x000055a2d5d10480+10 INTERNAL>
# 0x00000000 ce 32 33 cb ca 36 37 c7 c6 30 .23..67..0
3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 |
# File 'io_buffer.c', line 3283
static VALUE
io_buffer_xor(VALUE self, VALUE mask)
{
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
io_buffer_check_mask(mask_buffer);
VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
struct rb_io_buffer *output_buffer = NULL;
TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
memory_xor(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
return output;
}
|
#and!(mask) ⇒ Object
Modify the source buffer in place by applying the binary AND operation to the source, using the mask, repeating as necessary.
source = IO::Buffer.for("1234567890").dup # Make a read/write copy.
# =>
# #<IO::Buffer 0x000056307a0d0c20+10 INTERNAL>
# 0x00000000 31 32 33 34 35 36 37 38 39 30 1234567890
source.and!(IO::Buffer.for("\xFF\x00\x00\xFF"))
# =>
# #<IO::Buffer 0x000056307a0d0c20+10 INTERNAL>
# 0x00000000 31 00 00 34 35 00 00 38 39 00 1..45..89.
3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 |
# File 'io_buffer.c', line 3380
static VALUE
io_buffer_and_inplace(VALUE self, VALUE mask)
{
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
io_buffer_check_mask(mask_buffer);
io_buffer_check_overlaps(buffer, mask_buffer);
void *base;
size_t size;
io_buffer_get_bytes_for_writing(buffer, &base, &size);
memory_and_inplace(base, size, mask_buffer->base, mask_buffer->size);
return self;
}
|
#clear(value = 0, [offset, [length]]) ⇒ self
Fill buffer with value
, starting with offset
and going for length
bytes.
buffer = IO::Buffer.for('test')
# =>
# <IO::Buffer 0x00007fca40087c38+4 SLICE>
# 0x00000000 74 65 73 74 test
buffer.clear
# =>
# <IO::Buffer 0x00007fca40087c38+4 SLICE>
# 0x00000000 00 00 00 00 ....
buf.clear(1) # fill with 1
# =>
# <IO::Buffer 0x00007fca40087c38+4 SLICE>
# 0x00000000 01 01 01 01 ....
buffer.clear(2, 1, 2) # fill with 2, starting from offset 1, for 2 bytes
# =>
# <IO::Buffer 0x00007fca40087c38+4 SLICE>
# 0x00000000 01 02 02 01 ....
buffer.clear(2, 1) # fill with 2, starting from offset 1
# =>
# <IO::Buffer 0x00007fca40087c38+4 SLICE>
# 0x00000000 01 02 02 02 ....
2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 |
# File 'io_buffer.c', line 2618
static VALUE
io_buffer_clear(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 0, 3);
uint8_t value = 0;
if (argc >= 1) {
value = NUM2UINT(argv[0]);
}
size_t offset, length;
io_buffer_extract_offset_length(self, argc-1, argv+1, &offset, &length);
rb_io_buffer_clear(self, value, offset, length);
return self;
}
|
#copy(source, [offset, [length, [source_offset]]]) ⇒ Object
Efficiently copy from a source IO::Buffer into the buffer, at offset
using memcpy
. For copying String instances, see #set_string.
buffer = IO::Buffer.new(32)
# =>
# #<IO::Buffer 0x0000555f5ca22520+32 INTERNAL>
# 0x00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
# 0x00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ *
buffer.copy(IO::Buffer.for("test"), 8)
# => 4 -- size of buffer copied
buffer
# =>
# #<IO::Buffer 0x0000555f5cf8fe40+32 INTERNAL>
# 0x00000000 00 00 00 00 00 00 00 00 74 65 73 74 00 00 00 00 ........test....
# 0x00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ *
#copy can be used to put buffer into strings associated with buffer:
string= "buffer: "
# => "buffer: "
buffer = IO::Buffer.for(string)
buffer.copy(IO::Buffer.for("test"), 5)
# => 4
string
# => "buffer:test"
Attempt to copy into a read-only buffer will fail:
File.write('test.txt', 'test')
buffer = IO::Buffer.map(File.open('test.txt'), nil, 0, IO::Buffer::READONLY)
buffer.copy(IO::Buffer.for("test"), 8)
# in `copy': Buffer is not writable! (IO::Buffer::AccessError)
See ::map for details of creation of mutable file mappings, this will work:
buffer = IO::Buffer.map(File.open('test.txt', 'r+'))
buffer.copy(IO::Buffer.for("boom"), 0)
# => 4
File.read('test.txt')
# => "boom"
Attempt to copy the buffer which will need place outside of buffer’s bounds will fail:
buffer = IO::Buffer.new(2)
buffer.copy(IO::Buffer.for('test'), 0)
# in `copy': Specified offset+length is bigger than the buffer size! (ArgumentError)
2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 |
# File 'io_buffer.c', line 2477
static VALUE
io_buffer_copy(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 1, 4);
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
VALUE source = argv[0];
const void *source_base;
size_t source_size;
rb_io_buffer_get_bytes_for_reading(source, &source_base, &source_size);
return io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
}
|
#each(buffer_type, [offset, [count]]) {|offset, value| ... } ⇒ self #each(buffer_type, [offset, [count]]) ⇒ Object
2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 |
# File 'io_buffer.c', line 2111
static VALUE
io_buffer_each(int argc, VALUE *argv, VALUE self)
{
RETURN_ENUMERATOR_KW(self, argc, argv, RB_NO_KEYWORDS);
const void *base;
size_t size;
rb_io_buffer_get_bytes_for_reading(self, &base, &size);
ID buffer_type;
if (argc >= 1) {
buffer_type = RB_SYM2ID(argv[0]);
}
else {
buffer_type = RB_IO_BUFFER_DATA_TYPE_U8;
}
size_t offset, count;
io_buffer_extract_offset_count(buffer_type, size, argc-1, argv+1, &offset, &count);
for (size_t i = 0; i < count; i++) {
size_t current_offset = offset;
VALUE value = rb_io_buffer_get_value(base, size, buffer_type, &offset);
rb_yield_values(2, SIZET2NUM(current_offset), value);
}
return self;
}
|
#each_byte([offset, [count]]) {|offset, byte| ... } ⇒ self #each_byte([offset, [count]]) ⇒ Object
2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 |
# File 'io_buffer.c', line 2195
static VALUE
io_buffer_each_byte(int argc, VALUE *argv, VALUE self)
{
RETURN_ENUMERATOR_KW(self, argc, argv, RB_NO_KEYWORDS);
const void *base;
size_t size;
rb_io_buffer_get_bytes_for_reading(self, &base, &size);
size_t offset, count;
io_buffer_extract_offset_count(RB_IO_BUFFER_DATA_TYPE_U8, size, argc-1, argv+1, &offset, &count);
for (size_t i = 0; i < count; i++) {
unsigned char *value = (unsigned char *)base + i + offset;
rb_yield(RB_INT2FIX(*value));
}
return self;
}
|
#empty? ⇒ Boolean
#external? ⇒ Boolean
#free ⇒ Object
#get_string([offset, [length, [encoding]]]) ⇒ String
2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 |
# File 'io_buffer.c', line 2508
static VALUE
io_buffer_get_string(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 0, 3);
size_t offset, length;
struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
const void *base;
size_t size;
io_buffer_get_bytes_for_reading(buffer, &base, &size);
rb_encoding *encoding;
if (argc >= 3) {
encoding = rb_find_encoding(argv[2]);
}
else {
encoding = rb_ascii8bit_encoding();
}
io_buffer_validate_range(buffer, offset, length);
return rb_enc_str_new((const char*)base + offset, length, encoding);
}
|
#get_value(buffer_type, offset) ⇒ Numeric
Read from buffer a value of type
at offset
. buffer_type
should be one of symbols:
-
:U8
: unsigned integer, 1 byte -
:S8
: signed integer, 1 byte -
:u16
: unsigned integer, 2 bytes, little-endian -
:U16
: unsigned integer, 2 bytes, big-endian -
:s16
: signed integer, 2 bytes, little-endian -
:S16
: signed integer, 2 bytes, big-endian -
:u32
: unsigned integer, 4 bytes, little-endian -
:U32
: unsigned integer, 4 bytes, big-endian -
:s32
: signed integer, 4 bytes, little-endian -
:S32
: signed integer, 4 bytes, big-endian -
:u64
: unsigned integer, 8 bytes, little-endian -
:U64
: unsigned integer, 8 bytes, big-endian -
:s64
: signed integer, 8 bytes, little-endian -
:S64
: signed integer, 8 bytes, big-endian -
:f32
: float, 4 bytes, little-endian -
:F32
: float, 4 bytes, big-endian -
:f64
: double, 8 bytes, little-endian -
:F64
: double, 8 bytes, big-endian
A buffer type refers specifically to the type of binary buffer that is stored in the buffer. For example, a :u32
buffer type is a 32-bit unsigned integer in little-endian format.
string = [1.5].pack('f')
# => "\x00\x00\xC0?"
IO::Buffer.for(string).get_value(:f32, 0)
# => 1.5
2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 |
# File 'io_buffer.c', line 2015
static VALUE
io_buffer_get_value(VALUE self, VALUE type, VALUE _offset)
{
const void *base;
size_t size;
size_t offset = io_buffer_extract_offset(_offset);
rb_io_buffer_get_bytes_for_reading(self, &base, &size);
return rb_io_buffer_get_value(base, size, RB_SYM2ID(type), &offset);
}
|
#get_values(buffer_types, offset) ⇒ Array
2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 |
# File 'io_buffer.c', line 2037
static VALUE
io_buffer_get_values(VALUE self, VALUE buffer_types, VALUE _offset)
{
size_t offset = io_buffer_extract_offset(_offset);
const void *base;
size_t size;
rb_io_buffer_get_bytes_for_reading(self, &base, &size);
if (!RB_TYPE_P(buffer_types, T_ARRAY)) {
rb_raise(rb_eArgError, "Argument buffer_types should be an array!");
}
VALUE array = rb_ary_new_capa(RARRAY_LEN(buffer_types));
for (long i = 0; i < RARRAY_LEN(buffer_types); i++) {
VALUE type = rb_ary_entry(buffer_types, i);
VALUE value = rb_io_buffer_get_value(base, size, RB_SYM2ID(type), &offset);
rb_ary_push(array, value);
}
return array;
}
|
#hexdump ⇒ Object
#dup ⇒ Object #clone ⇒ Object
Make an internal copy of the source buffer. Updates to the copy will not affect the source buffer.
source = IO::Buffer.for("Hello World")
# =>
# #<IO::Buffer 0x00007fd598466830+11 EXTERNAL READONLY SLICE>
# 0x00000000 48 65 6c 6c 6f 20 57 6f 72 6c 64 Hello World
buffer = source.dup
# =>
# #<IO::Buffer 0x0000558cbec03320+11 INTERNAL>
# 0x00000000 48 65 6c 6c 6f 20 57 6f 72 6c 64 Hello World
2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 |
# File 'io_buffer.c', line 2407
static VALUE
rb_io_buffer_initialize_copy(VALUE self, VALUE source)
{
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
const void *source_base;
size_t source_size;
rb_io_buffer_get_bytes_for_reading(source, &source_base, &source_size);
io_buffer_initialize(self, buffer, NULL, source_size, io_flags_for_size(source_size), Qnil);
return io_buffer_copy_from(buffer, source_base, source_size, 0, NULL);
}
|
#inspect ⇒ Object
#internal? ⇒ Boolean
#locked ⇒ Object
rb_define_method(rb_cIOBuffer, “unlock”, rb_io_buffer_unlock, 0);
#locked? ⇒ Boolean
#mapped? ⇒ Boolean
#not! ⇒ Object
Modify the source buffer in place by applying the binary NOT operation to the source.
source = IO::Buffer.for("1234567890").dup # Make a read/write copy.
# =>
# #<IO::Buffer 0x000056307a33a450+10 INTERNAL>
# 0x00000000 31 32 33 34 35 36 37 38 39 30 1234567890
source.not!
# =>
# #<IO::Buffer 0x000056307a33a450+10 INTERNAL>
# 0x00000000 ce cd cc cb ca c9 c8 c7 c6 cf ..........
3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 |
# File 'io_buffer.c', line 3518
static VALUE
io_buffer_not_inplace(VALUE self)
{
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
void *base;
size_t size;
io_buffer_get_bytes_for_writing(buffer, &base, &size);
memory_not_inplace(base, size);
return self;
}
|
#null? ⇒ Boolean
#or!(mask) ⇒ Object
Modify the source buffer in place by applying the binary OR operation to the source, using the mask, repeating as necessary.
source = IO::Buffer.for("1234567890").dup # Make a read/write copy.
# =>
# #<IO::Buffer 0x000056307a272350+10 INTERNAL>
# 0x00000000 31 32 33 34 35 36 37 38 39 30 1234567890
source.or!(IO::Buffer.for("\xFF\x00\x00\xFF"))
# =>
# #<IO::Buffer 0x000056307a272350+10 INTERNAL>
# 0x00000000 ff 32 33 ff ff 36 37 ff ff 30 .23..67..0
3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 |
# File 'io_buffer.c', line 3426
static VALUE
io_buffer_or_inplace(VALUE self, VALUE mask)
{
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
io_buffer_check_mask(mask_buffer);
io_buffer_check_overlaps(buffer, mask_buffer);
void *base;
size_t size;
io_buffer_get_bytes_for_writing(buffer, &base, &size);
memory_or_inplace(base, size, mask_buffer->base, mask_buffer->size);
return self;
}
|
#pread(io, from, [length, [offset]]) ⇒ Object
Read at least length
bytes from the io
starting at the specified from
position, into the buffer starting at offset
. If an error occurs, return -errno
.
If length
is not given or nil
, it defaults to the size of the buffer minus the offset, i.e. the entire buffer.
If length
is zero, exactly one pread
operation will occur.
If offset
is not given, it defaults to zero, i.e. the beginning of the buffer.
IO::Buffer.for('test') do |buffer|
p buffer
# =>
# <IO::Buffer 0x00007fca40087c38+4 SLICE>
# 0x00000000 74 65 73 74 test
# take 2 bytes from the beginning of urandom,
# put them in buffer starting from position 2
buffer.pread(File.open('/dev/urandom', 'rb'), 0, 2, 2)
p buffer
# =>
# <IO::Buffer 0x00007f3bc65f2a58+4 EXTERNAL SLICE>
# 0x00000000 05 35 73 74 te.5
end
2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 |
# File 'io_buffer.c', line 2931
static VALUE
io_buffer_pread(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 2, 4);
VALUE io = argv[0];
rb_off_t from = NUM2OFFT(argv[1]);
size_t length, offset;
io_buffer_extract_length_offset(self, argc-2, argv+2, &length, &offset);
return rb_io_buffer_pread(self, io, from, length, offset);
}
|
#private? ⇒ Boolean
#pwrite(io, from, [length, [offset]]) ⇒ Object
Write at least length
bytes from the buffer starting at offset
, into the io
starting at the specified from
position. If an error occurs, return -errno
.
If length
is not given or nil
, it defaults to the size of the buffer minus the offset, i.e. the entire buffer.
If length
is zero, exactly one pwrite
operation will occur.
If offset
is not given, it defaults to zero, i.e. the beginning of the buffer.
If the from
position is beyond the end of the file, the gap will be filled with null (0 value) bytes.
out = File.open('output.txt', File::RDWR) # open for read/write, no truncation
IO::Buffer.for('1234567').pwrite(out, 2, 3, 1)
This leads to 234
(3 bytes, starting from position 1) being written into output.txt
, starting from file position 2.
3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 |
# File 'io_buffer.c', line 3162
static VALUE
io_buffer_pwrite(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 2, 4);
VALUE io = argv[0];
rb_off_t from = NUM2OFFT(argv[1]);
size_t length, offset;
io_buffer_extract_length_offset(self, argc-2, argv+2, &length, &offset);
return rb_io_buffer_pwrite(self, io, from, length, offset);
}
|
#read(io, [length, [offset]]) ⇒ Object
Read at least length
bytes from the io
, into the buffer starting at offset
. If an error occurs, return -errno
.
If length
is not given or nil
, it defaults to the size of the buffer minus the offset, i.e. the entire buffer.
If length
is zero, exactly one read
operation will occur.
If offset
is not given, it defaults to zero, i.e. the beginning of the buffer.
IO::Buffer.for('test') do |buffer|
p buffer
# =>
# <IO::Buffer 0x00007fca40087c38+4 SLICE>
# 0x00000000 74 65 73 74 test
buffer.read(File.open('/dev/urandom', 'rb'), 2)
p buffer
# =>
# <IO::Buffer 0x00007f3bc65f2a58+4 EXTERNAL SLICE>
# 0x00000000 05 35 73 74 .5st
end
2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 |
# File 'io_buffer.c', line 2809
static VALUE
io_buffer_read(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 1, 3);
VALUE io = argv[0];
size_t length, offset;
io_buffer_extract_length_offset(self, argc-1, argv+1, &length, &offset);
return rb_io_buffer_read(self, io, length, offset);
}
|
#readonly? ⇒ Boolean
#resize ⇒ Object
#set_string(string, [offset, [length, [source_offset]]]) ⇒ Object
Efficiently copy from a source String into the buffer, at offset
using memcpy
.
buf = IO::Buffer.new(8)
# =>
# #<IO::Buffer 0x0000557412714a20+8 INTERNAL>
# 0x00000000 00 00 00 00 00 00 00 00 ........
# set buffer starting from offset 1, take 2 bytes starting from string's
# second
buf.set_string('test', 1, 2, 1)
# => 2
buf
# =>
# #<IO::Buffer 0x0000557412714a20+8 INTERNAL>
# 0x00000000 00 65 73 00 00 00 00 00 .es.....
See also #copy for examples of how buffer writing might be used for changing associated strings and files.
2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 |
# File 'io_buffer.c', line 2556
static VALUE
io_buffer_set_string(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 1, 4);
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
VALUE string = rb_str_to_str(argv[0]);
const void *source_base = RSTRING_PTR(string);
size_t source_size = RSTRING_LEN(string);
return io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
}
|
#set_value(type, offset, value) ⇒ Object
Write to a buffer a value
of type
at offset
. type
should be one of symbols described in #get_value.
buffer = IO::Buffer.new(8)
# =>
# #<IO::Buffer 0x0000555f5c9a2d50+8 INTERNAL>
# 0x00000000 00 00 00 00 00 00 00 00
buffer.set_value(:U8, 1, 111)
# => 1
buffer
# =>
# #<IO::Buffer 0x0000555f5c9a2d50+8 INTERNAL>
# 0x00000000 00 6f 00 00 00 00 00 00 .o......
Note that if the type
is integer and value
is Float, the implicit truncation is performed:
buffer = IO::Buffer.new(8)
buffer.set_value(:U32, 0, 2.5)
buffer
# =>
# #<IO::Buffer 0x0000555f5c9a2d50+8 INTERNAL>
# 0x00000000 00 00 00 02 00 00 00 00
# ^^ the same as if we'd pass just integer 2
2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 |
# File 'io_buffer.c', line 2277
static VALUE
io_buffer_set_value(VALUE self, VALUE type, VALUE _offset, VALUE value)
{
void *base;
size_t size;
size_t offset = io_buffer_extract_offset(_offset);
rb_io_buffer_get_bytes_for_writing(self, &base, &size);
rb_io_buffer_set_value(base, size, RB_SYM2ID(type), &offset, value);
return SIZET2NUM(offset);
}
|
#set_values(buffer_types, offset, values) ⇒ Object
Write values
of buffer_types
at offset
to the buffer. buffer_types
should be an array of symbols as described in #get_value. values
should be an array of values to write.
buffer = IO::Buffer.new(8)
buffer.set_values([:U8, :U16], 0, [1, 2])
buffer
# =>
# #<IO::Buffer 0x696f717561746978+8 INTERNAL>
# 0x00000000 01 00 02 00 00 00 00 00 ........
2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 |
# File 'io_buffer.c', line 2305
static VALUE
io_buffer_set_values(VALUE self, VALUE buffer_types, VALUE _offset, VALUE values)
{
if (!RB_TYPE_P(buffer_types, T_ARRAY)) {
rb_raise(rb_eArgError, "Argument buffer_types should be an array!");
}
if (!RB_TYPE_P(values, T_ARRAY)) {
rb_raise(rb_eArgError, "Argument values should be an array!");
}
if (RARRAY_LEN(buffer_types) != RARRAY_LEN(values)) {
rb_raise(rb_eArgError, "Argument buffer_types and values should have the same length!");
}
size_t offset = io_buffer_extract_offset(_offset);
void *base;
size_t size;
rb_io_buffer_get_bytes_for_writing(self, &base, &size);
for (long i = 0; i < RARRAY_LEN(buffer_types); i++) {
VALUE type = rb_ary_entry(buffer_types, i);
VALUE value = rb_ary_entry(values, i);
rb_io_buffer_set_value(base, size, RB_SYM2ID(type), &offset, value);
}
return SIZET2NUM(offset);
}
|
#shared? ⇒ Boolean
#size ⇒ Object
#slice ⇒ Object
Manipulation:
#to_s ⇒ Object
#transfer ⇒ Object
#valid? ⇒ Boolean
#values(buffer_type, [offset, [count]]) ⇒ Array
2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 |
# File 'io_buffer.c', line 2151
static VALUE
io_buffer_values(int argc, VALUE *argv, VALUE self)
{
const void *base;
size_t size;
rb_io_buffer_get_bytes_for_reading(self, &base, &size);
ID buffer_type;
if (argc >= 1) {
buffer_type = RB_SYM2ID(argv[0]);
}
else {
buffer_type = RB_IO_BUFFER_DATA_TYPE_U8;
}
size_t offset, count;
io_buffer_extract_offset_count(buffer_type, size, argc-1, argv+1, &offset, &count);
VALUE array = rb_ary_new_capa(count);
for (size_t i = 0; i < count; i++) {
VALUE value = rb_io_buffer_get_value(base, size, buffer_type, &offset);
rb_ary_push(array, value);
}
return array;
}
|
#write(io, [length, [offset]]) ⇒ Object
Write at least length
bytes from the buffer starting at offset
, into the io
. If an error occurs, return -errno
.
If length
is not given or nil
, it defaults to the size of the buffer minus the offset, i.e. the entire buffer.
If length
is zero, exactly one write
operation will occur.
If offset
is not given, it defaults to zero, i.e. the beginning of the buffer.
out = File.open('output.txt', 'wb')
IO::Buffer.for('1234567').write(out, 3)
This leads to 123
being written into output.txt
3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 |
# File 'io_buffer.c', line 3039
static VALUE
io_buffer_write(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 1, 3);
VALUE io = argv[0];
size_t length, offset;
io_buffer_extract_length_offset(self, argc-1, argv+1, &length, &offset);
return rb_io_buffer_write(self, io, length, offset);
}
|
#xor!(mask) ⇒ Object
Modify the source buffer in place by applying the binary XOR operation to the source, using the mask, repeating as necessary.
source = IO::Buffer.for("1234567890").dup # Make a read/write copy.
# =>
# #<IO::Buffer 0x000056307a25b3e0+10 INTERNAL>
# 0x00000000 31 32 33 34 35 36 37 38 39 30 1234567890
source.xor!(IO::Buffer.for("\xFF\x00\x00\xFF"))
# =>
# #<IO::Buffer 0x000056307a25b3e0+10 INTERNAL>
# 0x00000000 ce 32 33 cb ca 36 37 c7 c6 30 .23..67..0
3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 |
# File 'io_buffer.c', line 3472
static VALUE
io_buffer_xor_inplace(VALUE self, VALUE mask)
{
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
io_buffer_check_mask(mask_buffer);
io_buffer_check_overlaps(buffer, mask_buffer);
void *base;
size_t size;
io_buffer_get_bytes_for_writing(buffer, &base, &size);
memory_xor_inplace(base, size, mask_buffer->base, mask_buffer->size);
return self;
}
|
#|(mask) ⇒ Object
Generate a new buffer the same size as the source by applying the binary OR operation to the source, using the mask, repeating as necessary.
IO::Buffer.for("1234567890") | IO::Buffer.for("\xFF\x00\x00\xFF")
# =>
# #<IO::Buffer 0x0000561785ae3480+10 INTERNAL>
# 0x00000000 ff 32 33 ff ff 36 37 ff ff 30 .23..67..0
3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 |
# File 'io_buffer.c', line 3243
static VALUE
io_buffer_or(VALUE self, VALUE mask)
{
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
struct rb_io_buffer *mask_buffer = NULL;
TypedData_Get_Struct(mask, struct rb_io_buffer, &rb_io_buffer_type, mask_buffer);
io_buffer_check_mask(mask_buffer);
VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
struct rb_io_buffer *output_buffer = NULL;
TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
memory_or(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
return output;
}
|
#~ ⇒ Object
3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 |
# File 'io_buffer.c', line 3323
static VALUE
io_buffer_not(VALUE self)
{
struct rb_io_buffer *buffer = NULL;
TypedData_Get_Struct(self, struct rb_io_buffer, &rb_io_buffer_type, buffer);
VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
struct rb_io_buffer *output_buffer = NULL;
TypedData_Get_Struct(output, struct rb_io_buffer, &rb_io_buffer_type, output_buffer);
memory_not(output_buffer->base, buffer->base, buffer->size);
return output;
}
|