Class: IO::Buffer::Storage
| Relationships & Source Files | |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
::IO::Buffer
|
|
|
Instance Chain:
self,
::IO::Buffer,
::Comparable
|
|
| Inherits: |
IO::Buffer
|
| Defined in: | io_buffer.c |
Overview
A buffer that manages backing storage, including internally allocated,
mapped, String-backed, and borrowed memory. Storage provides Buffer's
byte-access interface together with allocation resizing, #free, #transfer,
and storage-specific predicates. It need not own the bytes it references.
new, for, and map create Storage objects.
The Storage object is directly usable as a buffer; no separate view object
is needed unless a caller requests a slice. Duplicating Storage copies its
bytes into independent storage, unlike duplicating an Slice.
Constant Summary
::IO::Buffer - Inherited
BIG_ENDIAN, DEFAULT_SIZE, EXTERNAL, HOST_ENDIAN, INTERNAL, LITTLE_ENDIAN, MAPPED, MAP_ALIGNMENT, NETWORK_ENDIAN, PAGE_SIZE, PRIVATE, READONLY, SHARED, VERSION
Class Method Summary
-
IO::Buffer.new([size = DEFAULT_SIZE, [flags]]) ⇒ io_buffer
constructor
Create a new zero-filled
::IO::Bufferof #size bytes.
::IO::Buffer - Inherited
| .for | Creates a zero-copy |
| .map | Create an |
| .new | Creates an |
| .size_of | Returns the size of the given buffer type(s) in bytes. |
| .string | Creates a new string of the given length and yields a zero-copy |
Instance Attribute Summary
- #external? ⇒ Boolean readonly
- #internal? ⇒ Boolean readonly
- #mapped? ⇒ Boolean readonly
- #private? ⇒ Boolean readonly
- #shared? ⇒ Boolean readonly
::IO::Buffer - Inherited
Instance Method Summary
-
#free ⇒ self
If the buffer references memory, release it back to the operating system.
-
#dup ⇒ io_buffer
Make an internal copy of the source buffer.
-
#resize(new_size) ⇒ self
Resizes a buffer to a
new_sizebytes, preserving its content. -
#transfer ⇒ new_io_buffer
Transfers ownership of the underlying memory to a new buffer, causing the current buffer to become uninitialized.
::IO::Buffer - Inherited
| #& | 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. |
| #<=> | Returns a negative integer, zero, or a positive integer if the receiver is less than, equal to, or greater than |
| #^ | 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. |
| #advance | Advances the beginning of a non-owning buffer view by |
| #and! | Modify the source buffer in place by applying the binary AND operation to the source, using the mask, repeating as necessary. |
| #bit_count | Returns the number of set bits (1s) in the buffer, also known as the Hamming weight or population count. |
| #clear | Fill buffer with |
| #copy | Efficiently copy from a source |
| #get_string | Read a chunk or all of the buffer into a string, in the specified |
| #get_value | Read from buffer a value of |
| #get_values | Similar to #get_value, except that it can handle multiple buffer types and returns an array of values. |
| #hexdump | Returns a human-readable string representation of the buffer. |
| #not! | Modify the source buffer in place by applying the unary NOT operation to the source. |
| #or! | Modify the source buffer in place by applying the binary OR operation to the source, using the mask, repeating as necessary. |
| #read | Perform one read operation of at most |
| #set_string | Efficiently copy from a source |
| #set_value, | |
| #set_values | Write #values of |
| #size, | |
| #slice | Produce another |
| #source | Returns the object backing this view, or |
| #to_s, | |
| #values | Returns an array of values of |
| #write | Perform one write operation of at most |
| #xor! | Modify the source buffer in place by applying the binary XOR operation to the source, using the mask, repeating as necessary. |
| #| | 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. |
| #~ | Generate a new buffer the same size as the source by applying the unary NOT operation to the source. |
::Comparable - Included
| #< | Returns whether |
| #<= | Returns whether |
| #== | Compares two objects based on the receiver's #<=> method, returning true if it returns 0. |
| #> | Returns whether |
| #>= | Returns whether |
| #between? | |
| #clamp |
Constructor Details
IO::Buffer.new([size = DEFAULT_SIZE, [flags]]) ⇒ io_buffer
Create a new zero-filled ::IO::Buffer of IO::Buffer#size bytes.
By default, the buffer will be internal: directly allocated chunk
of the memory. But if the requested IO::Buffer#size is more than OS-specific
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 MAPPED
as a second parameter.
SHARED and PRIVATE imply MAPPED and are
mutually exclusive. Otherwise, if flags do not include an allocation
mode, INTERNAL or MAPPED is inferred from the
requested size. The two allocation modes are mutually exclusive.
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
# File 'io_buffer.c', line 1179
VALUE
rb_io_buffer_initialize(int argc, VALUE *argv, VALUE self)
{
rb_check_frozen(self);
rb_check_arity(argc, 0, 2);
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]);
}
flags = io_buffer_flags_for_new(flags, size);
struct rb_io_buffer_storage *buffer = get_io_buffer_storage(self);
if (buffer->lock_count) rb_raise(rb_eIOBufferLockedError, "Cannot initialize locked buffer!");
io_buffer_storage_release(buffer);
io_buffer_storage_initialize(self, buffer, NULL, size, flags, Qnil);
return self;
}
Instance Attribute Details
#external? ⇒ Boolean (readonly)
[ GitHub ]
#internal? ⇒ Boolean (readonly)
[ GitHub ]
#mapped? ⇒ Boolean (readonly)
[ GitHub ]
#private? ⇒ Boolean (readonly)
[ GitHub ]
Instance Method Details
#free ⇒ self
If the buffer references memory, release it back to the operating system.
- for a mapped buffer (e.g. from file): unmap.
- for a buffer created from scratch: free memory.
- for a buffer created from string: undo the association.
After releasing any referenced memory, the buffer is reset to a valid, empty, null state. It has no backing storage and its size is zero. Zero-length operations remain valid, while operations requiring bytes fail normal bounds checking.
Repeated calls on an unlocked, unfrozen Storage are harmless and return
self. You can resize the buffer to allocate new storage. This method is
not available on Slice, which never manages storage.
buffer = IO::Buffer.for('test')
buffer.free
# => #<IO::Buffer 0x0000000000000000+0 NULL>
buffer.null? # => true
buffer.empty? # => true
buffer.valid? # => true
buffer.get_string # => ""
buffer.get_value(:U8, 0) # raises ArgumentError
A frozen buffer cannot be freed, as that would release the memory its contents live in:
buffer = IO::Buffer.for('test').freeze
buffer.free
# in `free': can't modify frozen IO::Buffer (FrozenError)
# File 'io_buffer.c', line 2037
static VALUE
io_buffer_free(VALUE self)
{
rb_check_frozen(self);
return rb_io_buffer_free(self);
}
#dup ⇒ io_buffer
#clone ⇒ io_buffer
io_buffer
#clone ⇒ io_buffer
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
# File 'io_buffer.c', line 3492
static VALUE
rb_io_buffer_initialize_copy(VALUE self, VALUE source)
{
if (self == source) return self;
rb_check_frozen(self);
return rb_io_buffer_locked_for_reading(source, io_buffer_initialize_copy_from, self);
}
#resize(new_size) ⇒ self
Resizes a buffer to a new_size bytes, preserving its content.
Depending on the old and new size, the memory area associated with
the buffer might be either extended, or rellocated at different
address with content being copied.
buffer = IO::Buffer.new(4)
buffer.set_string("test", 0)
buffer.resize(8) # resize to 8 bytes
# =>
# #<IO::Buffer 0x0000555f5d1a1630+8 INTERNAL>
# 0x00000000 74 65 73 74 00 00 00 00 test....
When the buffer is a slice, resizing changes the size of the view without modifying the source buffer or allocating new storage. The resized view must remain within the source buffer. Growing the view exposes the existing bytes in the source; they are not cleared. Because the source allocation does not change, a slice can be resized while its source is locked.
External owning buffers (created with IO::Buffer.for), and locked owning buffers cannot be resized. Frozen buffers cannot be resized.
# File 'io_buffer.c', line 2546
static VALUE
io_buffer_resize(VALUE self, VALUE size)
{
rb_check_frozen(self);
rb_io_buffer_resize(self, io_buffer_extract_size(size));
return self;
}
#transfer ⇒ new_io_buffer
Transfers ownership of the underlying memory to a new buffer, causing the current buffer to become uninitialized.
buffer = IO::Buffer.for('test')
other = buffer.transfer
other
# =>
# #<IO::Buffer 0x00007f136a15f7b0+4 EXTERNAL READONLY SLICE>
# 0x00000000 74 65 73 74 test
buffer
# =>
# #<IO::Buffer 0x0000000000000000+0 NULL EXTERNAL READONLY>
buffer.null?
# => true
A frozen buffer cannot transfer ownership, as that would leave it uninitialized:
buffer = IO::Buffer.for('test').freeze
buffer.transfer
# in `transfer': can't modify frozen IO::Buffer (FrozenError)
# File 'io_buffer.c', line 2353
static VALUE
io_buffer_transfer(VALUE self)
{
rb_check_frozen(self);
return rb_io_buffer_transfer(self);
}