17#include "internal/array.h"
18#include "internal/bits.h"
19#include "internal/error.h"
20#include "internal/gc.h"
21#include "internal/numeric.h"
22#include "internal/string.h"
23#include "internal/io.h"
24#include "internal/io_buffer.h"
27VALUE rb_eIOBufferLockedError;
28VALUE rb_eIOBufferAllocationError;
29VALUE rb_eIOBufferAccessError;
30VALUE rb_eIOBufferInvalidatedError;
31VALUE rb_eIOBufferMaskError;
33size_t RUBY_IO_BUFFER_PAGE_SIZE;
34size_t RUBY_IO_BUFFER_MAP_ALIGNMENT;
35size_t RUBY_IO_BUFFER_DEFAULT_SIZE;
44 RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH = 16,
45 RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH = 1024,
47 RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE = 256,
48 RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH = 16,
51 RB_IO_BUFFER_FLAGS_MASK = RB_IO_BUFFER_EXTERNAL | RB_IO_BUFFER_INTERNAL | RB_IO_BUFFER_MAPPED | RB_IO_BUFFER_SHARED | RB_IO_BUFFER_PRIVATE | RB_IO_BUFFER_READONLY,
53 RB_IO_BUFFER_ALLOCATION_FLAGS = RB_IO_BUFFER_INTERNAL | RB_IO_BUFFER_MAPPED,
54 RB_IO_BUFFER_MAPPING_FLAGS = RB_IO_BUFFER_SHARED | RB_IO_BUFFER_PRIVATE,
56 RB_IO_BUFFER_DEBUG = 0,
62 enum rb_io_buffer_flags flags;
74io_buffer_map_memory(
size_t size,
int flags)
77 void * base = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
80 rb_sys_fail(
"io_buffer_map_memory:VirtualAlloc");
83 int mmap_flags = MAP_ANONYMOUS;
84 if (flags & RB_IO_BUFFER_SHARED) {
85 mmap_flags |= MAP_SHARED;
88 mmap_flags |= MAP_PRIVATE;
91 void * base = mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
93 if (base == MAP_FAILED) {
94 rb_sys_fail(
"io_buffer_map_memory:mmap");
97 ruby_annotate_mmap(base, size,
"Ruby:io_buffer_map_memory");
104io_buffer_map_file(
struct rb_io_buffer *buffer,
int descriptor,
size_t size, rb_off_t offset,
enum rb_io_buffer_flags flags)
107 HANDLE file = (HANDLE)_get_osfhandle(descriptor);
108 if (!file) rb_sys_fail(
"io_buffer_map_descriptor:_get_osfhandle");
110 DWORD protect = PAGE_READONLY, access = FILE_MAP_READ;
112 if (flags & RB_IO_BUFFER_READONLY) {
113 buffer->flags |= RB_IO_BUFFER_READONLY;
116 protect = PAGE_READWRITE;
117 access = FILE_MAP_WRITE;
120 if (flags & RB_IO_BUFFER_PRIVATE) {
121 protect = PAGE_WRITECOPY;
122 access = FILE_MAP_COPY;
123 buffer->flags |= RB_IO_BUFFER_PRIVATE;
127 buffer->flags |= RB_IO_BUFFER_EXTERNAL;
128 buffer->flags |= RB_IO_BUFFER_SHARED;
131 HANDLE mapping = CreateFileMapping(file, NULL, protect, 0, 0, NULL);
132 if (RB_IO_BUFFER_DEBUG) fprintf(stderr,
"io_buffer_map_file:CreateFileMapping -> %p\n", mapping);
133 if (!mapping) rb_sys_fail(
"io_buffer_map_descriptor:CreateFileMapping");
135 void *base = MapViewOfFile(mapping, access, (DWORD)(offset >> 32), (DWORD)(offset & 0xFFFFFFFF), size);
138 CloseHandle(mapping);
139 rb_sys_fail(
"io_buffer_map_file:MapViewOfFile");
142 buffer->mapping = mapping;
144 int protect = PROT_READ, access = 0;
146 if (flags & RB_IO_BUFFER_READONLY) {
147 buffer->flags |= RB_IO_BUFFER_READONLY;
150 protect |= PROT_WRITE;
153 if (flags & RB_IO_BUFFER_PRIVATE) {
154 buffer->flags |= RB_IO_BUFFER_PRIVATE;
155 access |= MAP_PRIVATE;
159 buffer->flags |= RB_IO_BUFFER_EXTERNAL;
160 buffer->flags |= RB_IO_BUFFER_SHARED;
161 access |= MAP_SHARED;
164 void *base = mmap(NULL, size, protect, access, descriptor, offset);
166 if (base == MAP_FAILED) {
167 rb_sys_fail(
"io_buffer_map_file:mmap");
174 buffer->flags |= RB_IO_BUFFER_MAPPED;
175 buffer->flags |= RB_IO_BUFFER_FILE;
179io_buffer_experimental(
void)
181 static int warned = 0;
189 "IO::Buffer is experimental and both the Ruby and C interface may change in the future!"
200 buffer->lock_count = 0;
202 buffer->mapping = NULL;
204 buffer->source =
Qnil;
208io_buffer_initialize(
VALUE self,
struct rb_io_buffer *buffer,
void *base,
size_t size,
enum rb_io_buffer_flags flags,
VALUE source)
215 if (flags & RB_IO_BUFFER_INTERNAL) {
216 base = calloc(size, 1);
218 else if (flags & RB_IO_BUFFER_MAPPED) {
219 base = io_buffer_map_memory(size, flags);
223 rb_raise(rb_eIOBufferAllocationError,
"Could not allocate buffer!");
233 buffer->flags = flags;
234 buffer->lock_count = 0;
238 buffer->mapping = NULL;
246 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
250 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
252 if (buffer->flags & RB_IO_BUFFER_FILE) {
253 UnmapViewOfFile(buffer->base);
256 VirtualFree(buffer->base, 0, MEM_RELEASE);
259 munmap(buffer->base, buffer->size);
271 if (buffer->mapping) {
272 if (RB_IO_BUFFER_DEBUG) fprintf(stderr,
"io_buffer_release:CloseHandle -> %p\n", buffer->mapping);
273 if (!CloseHandle(buffer->mapping)) {
274 fprintf(stderr,
"io_buffer_release:GetLastError -> %lu\n", GetLastError());
276 buffer->mapping = NULL;
280 io_buffer_zero(buffer);
284rb_io_buffer_type_mark(
void *_buffer)
287 if (buffer->source !=
Qnil) {
291 rb_gc_mark(buffer->source);
293 rb_gc_mark_movable(buffer->source);
299rb_io_buffer_type_compact(
void *_buffer)
302 if (buffer->source !=
Qnil) {
307 rb_gc_update_moved(&buffer->source);
313rb_io_buffer_type_free(
void *_buffer)
317 io_buffer_release(buffer);
321rb_io_buffer_type_size(
const void *_buffer)
327 total += buffer->size;
336 .dmark = rb_io_buffer_type_mark,
337 .dfree = rb_io_buffer_type_free,
338 .dsize = rb_io_buffer_type_size,
339 .dcompact = rb_io_buffer_type_compact,
342 .flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
346get_io_buffer(
VALUE self)
356 return rb_typeddata_is_kind_of(buffer->source, &rb_io_buffer_type);
365 if (io_buffer_slice_p(buffer)) {
366 return get_io_buffer(buffer->source);
375 return io_buffer_lock_owner(buffer)->lock_count > 0;
378static inline enum rb_io_buffer_flags
379io_buffer_extract_flags(
VALUE argument)
381 if (rb_int_negative_p(argument)) {
382 rb_raise(rb_eArgError,
"Flags can't be negative!");
385 enum rb_io_buffer_flags flags =
RB_NUM2UINT(argument);
388 return flags & RB_IO_BUFFER_FLAGS_MASK;
391static inline enum rb_io_buffer_flags
392io_buffer_flags_for_map(
enum rb_io_buffer_flags flags)
394 if (flags & RB_IO_BUFFER_INTERNAL) {
395 rb_raise(rb_eArgError,
"IO::Buffer::INTERNAL can't be used with IO::Buffer.map!");
398 if (flags & RB_IO_BUFFER_EXTERNAL) {
399 rb_raise(rb_eArgError,
"IO::Buffer::EXTERNAL can't be used with IO::Buffer.map!");
402 if ((flags & RB_IO_BUFFER_MAPPING_FLAGS) == RB_IO_BUFFER_MAPPING_FLAGS) {
403 rb_raise(rb_eArgError,
"Flags can't include both IO::Buffer::SHARED and IO::Buffer::PRIVATE!");
411io_buffer_extract_offset(
VALUE argument)
413 if (rb_int_negative_p(argument)) {
414 rb_raise(rb_eArgError,
"Offset can't be negative!");
424io_buffer_extract_length(
VALUE argument)
426 if (rb_int_negative_p(argument)) {
427 rb_raise(rb_eArgError,
"Length can't be negative!");
436io_buffer_extract_size(
VALUE argument)
438 if (rb_int_negative_p(argument)) {
439 rb_raise(rb_eArgError,
"Size can't be negative!");
448io_buffer_extract_width(
VALUE argument,
size_t minimum)
450 if (rb_int_negative_p(argument)) {
451 rb_raise(rb_eArgError,
"Width can't be negative!");
456 if (width < minimum) {
457 rb_raise(rb_eArgError,
"Width must be at least %" PRIuSIZE
"!", minimum);
460 if (width > RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH) {
461 rb_raise(rb_eArgError,
"Width must be at most %" PRIuSIZE
"!", (
size_t)RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH);
472io_buffer_default_length(
const struct rb_io_buffer *buffer,
size_t offset)
474 if (offset > buffer->size) {
475 rb_raise(rb_eArgError,
"The given offset is bigger than the buffer size!");
479 return buffer->size - offset;
487io_buffer_extract_offset_length(
VALUE self,
int argc,
VALUE argv[],
size_t *offset,
size_t *length)
491 if (argc >= 1 && !
NIL_P(argv[0])) {
492 *offset = io_buffer_extract_offset(argv[0]);
498 if (argc >= 2 && !
NIL_P(argv[1])) {
499 *length = io_buffer_extract_length(argv[1]);
502 *length = io_buffer_default_length(buffer, *offset);
509rb_io_buffer_type_allocate(
VALUE self)
511 io_buffer_experimental();
516 io_buffer_zero(buffer);
521static VALUE io_buffer_for_make_instance(
VALUE klass,
VALUE string,
enum rb_io_buffer_flags flags)
523 VALUE instance = rb_io_buffer_type_allocate(klass);
527 flags |= RB_IO_BUFFER_EXTERNAL;
530 flags |= RB_IO_BUFFER_READONLY;
532 if (!(flags & RB_IO_BUFFER_READONLY))
533 rb_str_modify(
string);
535 io_buffer_initialize(instance, buffer, RSTRING_PTR(
string), RSTRING_LEN(
string), flags,
string);
544 enum rb_io_buffer_flags flags;
548io_buffer_for_yield_instance(
VALUE _arguments)
552 arguments->instance = io_buffer_for_make_instance(arguments->klass, arguments->string, arguments->flags);
558 return rb_yield(arguments->instance);
562io_buffer_for_yield_instance_ensure(
VALUE _arguments)
566 if (arguments->instance !=
Qnil) {
567 rb_io_buffer_free(arguments->instance);
581 enum rb_io_buffer_flags flags;
587static VALUE rb_io_buffer_locked_ensure(
VALUE self);
596io_buffer_for_locked_callback_call(
VALUE _arguments)
600 return arguments->callback(arguments->buffer, arguments->argument);
608 .callback = callback,
609 .argument = argument,
612 rb_io_buffer_lock(buffer);
613 return rb_ensure(io_buffer_for_locked_callback_call, (
VALUE)&arguments, rb_io_buffer_locked_ensure, buffer);
617io_buffer_for_callback_call(
VALUE _arguments)
621 arguments->instance = io_buffer_for_make_instance(arguments->klass, arguments->string, arguments->flags);
625 arguments->locked = 1;
628 return io_buffer_for_locked_callback(arguments->instance, arguments->callback, arguments->argument);
632io_buffer_for_callback_ensure(
VALUE _arguments)
636 if (arguments->instance !=
Qnil) {
637 rb_io_buffer_free(arguments->instance);
640 if (arguments->locked) {
651 return io_buffer_for_locked_callback(string_or_buffer, callback, argument);
656 .klass = rb_cIOBuffer,
657 .string = string_or_buffer,
659 .flags = RB_IO_BUFFER_READONLY,
661 .callback = callback,
662 .argument = argument,
665 io_buffer_for_callback_ensure, (
VALUE)&arguments);
668 rb_raise(
rb_eTypeError,
"expected String or IO::Buffer, not %"PRIsVALUE,
674static int io_buffer_readonly_p(
struct rb_io_buffer *buffer);
680 struct rb_io_buffer *buffer = get_io_buffer(string_or_buffer);
681 if (io_buffer_readonly_p(buffer)) {
682 rb_raise(rb_eArgError,
"buffer is read-only");
684 return io_buffer_for_locked_callback(string_or_buffer, callback, argument);
689 .klass = rb_cIOBuffer,
690 .string = string_or_buffer,
694 .callback = callback,
695 .argument = argument,
698 io_buffer_for_callback_ensure, (
VALUE)&arguments);
701 rb_raise(
rb_eTypeError,
"expected String or IO::Buffer, not %"PRIsVALUE,
743rb_io_buffer_type_for(
VALUE klass,
VALUE string)
757 return rb_ensure(io_buffer_for_yield_instance, (
VALUE)&arguments, io_buffer_for_yield_instance_ensure, (
VALUE)&arguments);
761 string = rb_str_tmp_frozen_acquire(
string);
762 return io_buffer_for_make_instance(klass,
string, RB_IO_BUFFER_READONLY);
780rb_io_buffer_type_string(
VALUE klass,
VALUE length)
790 rb_ensure(io_buffer_for_yield_instance, (
VALUE)&arguments, io_buffer_for_yield_instance_ensure, (
VALUE)&arguments);
796rb_io_buffer_new(
void *base,
size_t size,
enum rb_io_buffer_flags flags)
798 VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
802 io_buffer_initialize(instance, buffer, base, size, flags,
Qnil);
808rb_io_buffer_new_locked(
void *base,
size_t size,
enum rb_io_buffer_flags flags)
810 VALUE instance = rb_io_buffer_new(base, size, flags);
812 rb_io_buffer_lock(instance);
818rb_io_buffer_map(
VALUE io,
size_t size, rb_off_t offset,
enum rb_io_buffer_flags flags)
820 if (UNLIKELY(offset < 0)) {
821 rb_raise(rb_eArgError,
822 "Offset (%" PRIsVALUE
") can't be negative!",
826 if (UNLIKELY((uintmax_t)offset % RUBY_IO_BUFFER_MAP_ALIGNMENT != 0)) {
827 rb_raise(rb_eArgError,
828 "Offset (%" PRIsVALUE
") must be a multiple of IO::Buffer::MAP_ALIGNMENT (%" PRIuSIZE
")!",
830 RUBY_IO_BUFFER_MAP_ALIGNMENT);
833 VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
839 io_buffer_map_file(buffer, descriptor, size, offset, flags);
896io_buffer_map(
int argc,
VALUE *argv,
VALUE klass)
903 rb_off_t file_size = rb_file_size(io);
905 if (UNLIKELY(file_size <= 0)) {
906 rb_raise(rb_eArgError,
"Invalid negative or zero file size!");
909 else if (UNLIKELY((uintmax_t)file_size > SIZE_MAX)) {
910 rb_raise(rb_eArgError,
"File larger than address space!");
914 if (argc >= 2 && !
RB_NIL_P(argv[1])) {
915 size = io_buffer_extract_size(argv[1]);
916 if (UNLIKELY(size == 0)) {
917 rb_raise(rb_eArgError,
"Size can't be zero!");
919 if (UNLIKELY(size > (
size_t)file_size)) {
920 rb_raise(rb_eArgError,
921 "Size (%" PRIuSIZE
") can't be larger than "
922 "file size (%" PRIuSIZE
")",
929 size = (size_t)file_size;
936 if (UNLIKELY(offset < 0)) {
937 rb_raise(rb_eArgError,
938 "Offset (%" PRIsVALUE
") can't be negative!",
941 if (UNLIKELY(offset >= file_size)) {
942 rb_raise(rb_eArgError,
943 "Offset (%" PRIsVALUE
") can't be larger than "
944 "file size (%" PRIuSIZE
")",
950 size = (size_t)(file_size - offset);
952 else if (UNLIKELY((
size_t)(file_size - offset) < size)) {
953 size_t maximum_offset =
954 (file_size - size) / RUBY_IO_BUFFER_MAP_ALIGNMENT *
955 RUBY_IO_BUFFER_MAP_ALIGNMENT;
956 rb_raise(rb_eArgError,
957 "Offset (%" PRIsVALUE
") can't be larger than "
958 "%" PRIuSIZE
" for requested size (%" PRIuSIZE
")",
965 enum rb_io_buffer_flags flags = 0;
967 flags = io_buffer_extract_flags(argv[3]);
969 flags = io_buffer_flags_for_map(flags);
971 return rb_io_buffer_map(io, size, offset, flags);
975static inline enum rb_io_buffer_flags
976io_flags_for_size(
size_t size)
978 if (size >= RUBY_IO_BUFFER_PAGE_SIZE) {
979 return RB_IO_BUFFER_MAPPED;
982 return RB_IO_BUFFER_INTERNAL;
985static inline enum rb_io_buffer_flags
986io_buffer_flags_for_new(
enum rb_io_buffer_flags flags,
size_t size)
993 if (!(flags & RB_IO_BUFFER_ALLOCATION_FLAGS)) {
994 if (flags & RB_IO_BUFFER_MAPPING_FLAGS) {
996 flags |= RB_IO_BUFFER_MAPPED;
1000 flags |= io_flags_for_size(size);
1004 enum rb_io_buffer_flags allocation = flags & RB_IO_BUFFER_ALLOCATION_FLAGS;
1007 if ((
unsigned int)allocation == RB_IO_BUFFER_ALLOCATION_FLAGS) {
1008 rb_raise(rb_eArgError,
"Flags can't include both IO::Buffer::INTERNAL and IO::Buffer::MAPPED!");
1011 if (flags & RB_IO_BUFFER_EXTERNAL) {
1012 rb_raise(rb_eArgError,
"IO::Buffer::EXTERNAL can't be used with IO::Buffer.new!");
1015 if ((flags & RB_IO_BUFFER_MAPPING_FLAGS) && allocation != RB_IO_BUFFER_MAPPED) {
1016 rb_raise(rb_eArgError,
"IO::Buffer::SHARED and IO::Buffer::PRIVATE require IO::Buffer::MAPPED!");
1019 if ((flags & RB_IO_BUFFER_MAPPING_FLAGS) == RB_IO_BUFFER_MAPPING_FLAGS) {
1020 rb_raise(rb_eArgError,
"Flags can't include both IO::Buffer::SHARED and IO::Buffer::PRIVATE!");
1056rb_io_buffer_initialize(
int argc,
VALUE *argv,
VALUE self)
1064 size = io_buffer_extract_size(argv[0]);
1067 size = RUBY_IO_BUFFER_DEFAULT_SIZE;
1070 enum rb_io_buffer_flags flags = 0;
1072 flags = io_buffer_extract_flags(argv[1]);
1074 flags = io_buffer_flags_for_new(flags, size);
1076 io_buffer_initialize(self, buffer, NULL, size, flags,
Qnil);
1082io_buffer_validate_slice(
VALUE source,
void *base,
size_t size)
1084 void *source_base = NULL;
1085 size_t source_size = 0;
1091 rb_io_buffer_get_bytes(source, &source_base, &source_size);
1094 uintptr_t source_address = (uintptr_t)source_base;
1095 uintptr_t address = (uintptr_t)base;
1098 if (address < source_address)
return 0;
1100 uintptr_t offset = address - source_address;
1103 if (offset > source_size)
return 0;
1106 if (size > source_size - (
size_t)offset)
return 0;
1115 if (buffer->source !=
Qnil) {
1117 return io_buffer_validate_slice(buffer->source, buffer->base, buffer->size);
1124enum rb_io_buffer_flags
1125rb_io_buffer_get_bytes(
VALUE self,
void **base,
size_t *size)
1129 if (io_buffer_validate(buffer)) {
1131 *base = buffer->base;
1132 *size = buffer->size;
1134 return buffer->flags;
1146io_buffer_validate_for_writing(
struct rb_io_buffer *buffer)
1148 if (buffer->flags & RB_IO_BUFFER_READONLY ||
1150 rb_raise(rb_eIOBufferAccessError,
"Buffer is not writable!");
1153 if (!io_buffer_validate(buffer)) {
1154 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer is invalid!");
1159get_io_buffer_for_writing(
VALUE self)
1161 rb_check_frozen(self);
1164 io_buffer_validate_for_writing(buffer);
1169io_buffer_get_bytes_for_writing(
struct rb_io_buffer *buffer,
void **base,
size_t *size)
1171 io_buffer_validate_for_writing(buffer);
1174 *base = buffer->base;
1175 *size = buffer->size;
1183rb_io_buffer_get_bytes_for_writing(
VALUE self,
void **base,
size_t *size)
1187 io_buffer_get_bytes_for_writing(buffer, base, size);
1191io_buffer_validate_for_reading(
struct rb_io_buffer *buffer)
1193 if (!io_buffer_validate(buffer)) {
1194 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer has been invalidated!");
1199io_buffer_get_bytes_for_reading(
struct rb_io_buffer *buffer,
const void **base,
size_t *size)
1201 io_buffer_validate_for_reading(buffer);
1204 *base = buffer->base;
1205 *size = buffer->size;
1213rb_io_buffer_get_bytes_for_reading(
VALUE self,
const void **base,
size_t *size)
1217 io_buffer_get_bytes_for_reading(buffer, base, size);
1230rb_io_buffer_to_s(
VALUE self)
1237 rb_str_catf(result,
" %p+%"PRIdSIZE, buffer->base, buffer->size);
1239 if (buffer->base == NULL) {
1243 if (buffer->flags & RB_IO_BUFFER_EXTERNAL) {
1247 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
1251 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
1255 if (buffer->flags & RB_IO_BUFFER_FILE) {
1259 if (buffer->flags & RB_IO_BUFFER_SHARED) {
1263 if (io_buffer_locked(buffer)) {
1267 if (buffer->flags & RB_IO_BUFFER_PRIVATE) {
1271 if (buffer->flags & RB_IO_BUFFER_READONLY) {
1275 if (buffer->source !=
Qnil) {
1279 if (!io_buffer_validate(buffer)) {
1289io_buffer_hexdump_output_size(
size_t width,
size_t size,
int first)
1292 size_t total = size;
1294 size_t whole_lines = (size / width);
1295 size_t partial_line = (size % width) ? 1 : 0;
1300 total += (whole_lines + partial_line) * (1 + 10 + width*3 + 1 + 1);
1303 if (size && first) total -= 1;
1312io_buffer_hexdump(
VALUE string,
size_t width,
const char *base,
size_t length,
size_t offset,
int first)
1314 char *text = alloca(width+1);
1317 for (; offset < length; offset += width) {
1318 memset(text,
'\0', width);
1320 rb_str_catf(
string,
"0x%08" PRIxSIZE
" ", offset);
1324 rb_str_catf(
string,
"\n0x%08" PRIxSIZE
" ", offset);
1327 for (
size_t i = 0; i < width; i += 1) {
1328 if (offset+i < length) {
1329 unsigned char value = ((
unsigned char*)base)[offset+i];
1331 if (value < 127 && isprint(value)) {
1332 text[i] = (char)value;
1338 rb_str_catf(
string,
" %02x", value);
1345 rb_str_catf(
string,
" %s", text);
1364rb_io_buffer_inspect(
VALUE self)
1368 VALUE result = rb_io_buffer_to_s(self);
1370 if (io_buffer_validate(buffer)) {
1372 size_t size = buffer->size;
1375 if (size > RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE) {
1376 size = RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE;
1380 io_buffer_hexdump(result, RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH, buffer->base, size, 0, 0);
1383 rb_str_catf(result,
"\n(and %" PRIuSIZE
" more bytes not printed)", buffer->size - size);
1397rb_io_buffer_size(
VALUE self)
1420rb_io_buffer_valid_p(
VALUE self)
1424 return RBOOL(io_buffer_validate(buffer));
1445rb_io_buffer_null_p(
VALUE self)
1449 return RBOOL(buffer->base == NULL);
1462rb_io_buffer_empty_p(
VALUE self)
1466 return RBOOL(buffer->size == 0);
1481rb_io_buffer_external_p(
VALUE self)
1485 return RBOOL(buffer->flags & RB_IO_BUFFER_EXTERNAL);
1505rb_io_buffer_internal_p(
VALUE self)
1509 return RBOOL(buffer->flags & RB_IO_BUFFER_INTERNAL);
1526rb_io_buffer_mapped_p(
VALUE self)
1530 return RBOOL(buffer->flags & RB_IO_BUFFER_MAPPED);
1557rb_io_buffer_shared_p(
VALUE self)
1561 return RBOOL(buffer->flags & RB_IO_BUFFER_SHARED);
1578rb_io_buffer_locked_p(
VALUE self)
1582 return RBOOL(io_buffer_locked(buffer));
1608rb_io_buffer_private_p(
VALUE self)
1612 return RBOOL(buffer->flags & RB_IO_BUFFER_PRIVATE);
1618 return buffer->flags & RB_IO_BUFFER_READONLY;
1631rb_io_buffer_readonly_p(
VALUE self)
1635 return RBOOL(io_buffer_readonly_p(buffer));
1641 struct rb_io_buffer *owner = io_buffer_lock_owner(buffer);
1643 if (owner->lock_count == SIZE_MAX) {
1644 rb_raise(rb_eIOBufferLockedError,
"It's locks all the way down!");
1647 owner->lock_count += 1;
1651rb_io_buffer_lock(
VALUE self)
1655 io_buffer_lock(buffer);
1663 struct rb_io_buffer *owner = io_buffer_lock_owner(buffer);
1665 if (owner->lock_count == 0) {
1666 rb_raise(rb_eIOBufferLockedError,
"Buffer not locked!");
1669 owner->lock_count -= 1;
1673rb_io_buffer_unlock(
VALUE self)
1677 io_buffer_unlock(buffer);
1683rb_io_buffer_try_unlock(
VALUE self)
1686 struct rb_io_buffer *owner = io_buffer_lock_owner(buffer);
1688 if (owner->lock_count > 0) {
1689 owner->lock_count -= 1;
1698rb_io_buffer_locked_ensure(
VALUE self)
1702 io_buffer_unlock(buffer);
1709 VALUE (*callback)(
const void *base,
size_t size,
VALUE argument);
1714io_buffer_readable_bytes_call(
VALUE _arguments)
1720 rb_io_buffer_get_bytes_for_reading(arguments->self, &base, &size);
1722 return arguments->callback(base, size, arguments->argument);
1726rb_io_buffer_locked_for_reading(
VALUE self,
VALUE (*callback)(
const void *base,
size_t size,
VALUE argument),
VALUE argument)
1729 io_buffer_validate_for_reading(buffer);
1733 .callback = callback,
1734 .argument = argument,
1737 rb_io_buffer_lock(self);
1738 return rb_ensure(io_buffer_readable_bytes_call, (
VALUE)&arguments, rb_io_buffer_locked_ensure, self);
1743 VALUE (*callback)(
void *base,
size_t size,
VALUE argument);
1748io_buffer_writable_bytes_call(
VALUE _arguments)
1754 rb_io_buffer_get_bytes_for_writing(arguments->self, &base, &size);
1756 return arguments->callback(base, size, arguments->argument);
1760rb_io_buffer_locked_for_writing(
VALUE self,
VALUE (*callback)(
void *base,
size_t size,
VALUE argument),
VALUE argument)
1762 get_io_buffer_for_writing(self);
1766 .callback = callback,
1767 .argument = argument,
1770 rb_io_buffer_lock(self);
1771 return rb_ensure(io_buffer_writable_bytes_call, (
VALUE)&arguments, rb_io_buffer_locked_ensure, self);
1802rb_io_buffer_locked(
VALUE self)
1808 io_buffer_validate_for_reading(buffer);
1810 io_buffer_lock(buffer);
1816rb_io_buffer_free(
VALUE self)
1820 if (io_buffer_locked(buffer)) {
1821 rb_raise(rb_eIOBufferLockedError,
"Buffer is locked!");
1824 io_buffer_release(buffer);
1863io_buffer_free(
VALUE self)
1865 rb_check_frozen(self);
1867 return rb_io_buffer_free(self);
1873 struct rb_io_buffer *owner = io_buffer_lock_owner(buffer);
1878 if (owner->lock_count != 1) {
1879 rb_bug(
"rb_io_buffer_free_locked: expected lock count 1, got %" PRIuSIZE, owner->lock_count);
1882 io_buffer_unlock(buffer);
1883 io_buffer_release(buffer);
1889size_sum_is_bigger_than(
size_t a,
size_t b,
size_t x)
1891 struct rbimpl_size_overflow_tag size = rbimpl_size_add_overflow(a, b);
1892 return size.overflowed || size.result > x;
1898io_buffer_validate_range(
struct rb_io_buffer *buffer,
size_t offset,
size_t length)
1900 io_buffer_validate_for_reading(buffer);
1902 if (size_sum_is_bigger_than(offset, length, buffer->size)) {
1903 rb_raise(rb_eArgError,
"Specified offset+length is bigger than the buffer size!");
1927rb_io_buffer_hexdump(
int argc,
VALUE *argv,
VALUE self)
1931 size_t offset, length;
1932 struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
1934 size_t width = RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH;
1936 width = io_buffer_extract_width(argv[2], 1);
1940 io_buffer_validate_range(buffer, offset, length);
1944 if (io_buffer_validate(buffer) && buffer->base) {
1945 result =
rb_str_buf_new(io_buffer_hexdump_output_size(width, length, 1));
1947 io_buffer_hexdump(result, width, buffer->base, offset+length, offset, 1);
1954rb_io_buffer_slice(
struct rb_io_buffer *buffer,
VALUE self,
size_t offset,
size_t length)
1956 io_buffer_validate_range(buffer, offset, length);
1961 slice->flags |= (buffer->flags & RB_IO_BUFFER_READONLY);
1962 slice->base = buffer->base ? (
char*)buffer->base + offset : NULL;
1963 slice->size = length;
1967 if (io_buffer_slice_p(buffer)) {
1968 RB_OBJ_WRITE(instance, &slice->source, buffer->source);
2029io_buffer_slice(
int argc,
VALUE *argv,
VALUE self)
2033 size_t offset, length;
2034 struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
2036 return rb_io_buffer_slice(buffer, self, offset, length);
2040rb_io_buffer_transfer(
VALUE self)
2044 if (io_buffer_locked(buffer)) {
2045 rb_raise(rb_eIOBufferLockedError,
"Cannot transfer ownership of locked buffer!");
2052 *transferred = *buffer;
2053 io_buffer_zero(buffer);
2084io_buffer_transfer(
VALUE self)
2086 rb_check_frozen(self);
2088 return rb_io_buffer_transfer(self);
2092io_buffer_resize_clear(
struct rb_io_buffer *buffer,
void* base,
size_t size)
2094 if (size > buffer->size) {
2095 memset((
unsigned char*)base+buffer->size, 0, size - buffer->size);
2104 enum rb_io_buffer_flags flags = io_flags_for_size(size) | (buffer->flags & RB_IO_BUFFER_READONLY);
2105 io_buffer_initialize(self, &resized, NULL, size, flags,
Qnil);
2108 size_t preserve = buffer->size;
2109 if (preserve > size) preserve = size;
2110 memcpy(resized.base, buffer->base, preserve);
2112 io_buffer_resize_clear(buffer, resized.base, size);
2115 io_buffer_release(buffer);
2120io_buffer_resize_slice(
struct rb_io_buffer *slice,
size_t size)
2122 struct rb_io_buffer *source = get_io_buffer(slice->source);
2124 if (!io_buffer_validate(source)) {
2125 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer is invalid!");
2128 if (source->base == NULL || slice->base == NULL) {
2129 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer is invalid!");
2132 uintptr_t source_address = (uintptr_t)source->base;
2133 uintptr_t slice_address = (uintptr_t)slice->base;
2135 if (slice_address < source_address) {
2136 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer is invalid!");
2139 uintptr_t offset = slice_address - source_address;
2141 if (offset > source->size) {
2142 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer is invalid!");
2145 if (size > source->size - (
size_t)offset) {
2146 rb_raise(rb_eArgError,
"Resized slice exceeds its source buffer!");
2155rb_io_buffer_resize(
VALUE self,
size_t size)
2159 if (io_buffer_slice_p(buffer)) {
2161 io_buffer_resize_slice(buffer, size);
2165 io_buffer_validate_for_reading(buffer);
2167 if (io_buffer_locked(buffer)) {
2168 rb_raise(rb_eIOBufferLockedError,
"Cannot resize locked buffer!");
2171 if (buffer->base == NULL) {
2172 io_buffer_initialize(self, buffer, NULL, size, io_flags_for_size(size),
Qnil);
2176 if (buffer->flags & RB_IO_BUFFER_EXTERNAL) {
2177 rb_raise(rb_eIOBufferAccessError,
"Cannot resize external buffer!");
2181 io_buffer_release(buffer);
2185#if defined(HAVE_MREMAP) && defined(MREMAP_MAYMOVE)
2186 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
2187 void *base = mremap(buffer->base, buffer->size, size, MREMAP_MAYMOVE);
2189 if (base == MAP_FAILED) {
2190 rb_sys_fail(
"rb_io_buffer_resize:mremap");
2193 io_buffer_resize_clear(buffer, base, size);
2195 buffer->base = base;
2196 buffer->size = size;
2202 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
2203 void *base = realloc(buffer->base, size);
2206 rb_sys_fail(
"rb_io_buffer_resize:realloc");
2209 io_buffer_resize_clear(buffer, base, size);
2211 buffer->base = base;
2212 buffer->size = size;
2217 io_buffer_resize_copy(self, buffer, size);
2247 rb_check_frozen(self);
2249 rb_io_buffer_resize(self, io_buffer_extract_size(size));
2271 const void *ptr1, *ptr2;
2272 size_t size1, size2;
2274 rb_io_buffer_get_bytes_for_reading(self, &ptr1, &size1);
2275 rb_io_buffer_get_bytes_for_reading(other, &ptr2, &size2);
2277 if (size1 < size2) {
2281 if (size1 > size2) {
2291 return RB_INT2NUM(memcmp(ptr1, ptr2, size1));
2295io_buffer_validate_type(
size_t size,
size_t offset,
size_t extend)
2297 if (size_sum_is_bigger_than(offset, extend, size)) {
2298 rb_raise(rb_eArgError,
"Type extends beyond end of buffer! (offset=%"PRIdSIZE
" > size=%"PRIdSIZE
")", offset, size);
2323#define ruby_swap8(value) value
2331ruby_swapf32(
float value)
2333 union swapf32 swap = {.value = value};
2334 swap.integral = ruby_swap32(swap.integral);
2344ruby_swapf64(
double value)
2346 union swapf64 swap = {.value = value};
2347 swap.integral = ruby_swap64(swap.integral);
2359#ifdef HAVE_UINT128_T
2360#if __has_builtin(__builtin_bswap128)
2361 result.value = __builtin_bswap128(x.value);
2364 uint64_t low = (uint64_t)x.value;
2365 uint64_t high = (uint64_t)(x.value >> 64);
2366 low = ruby_swap64(low);
2367 high = ruby_swap64(high);
2368 result.value = ((uint128_t)low << 64) | high;
2375 result.parts.low = ruby_swap64(x.parts.high);
2376 result.parts.high = ruby_swap64(x.parts.low);
2387 conversion.uint128 = ruby_swap128_uint(conversion.uint128);
2388 return conversion.int128;
2391#define IO_BUFFER_VALIDATE_TYPE_FOR_WRITING(buffer, base, size, offset, type) \
2392 (io_buffer_get_bytes_for_writing(buffer, &(base), &(size)), \
2393 io_buffer_validate_type(size, offset, sizeof(type)))
2395#define IO_BUFFER_DECLARE_TYPE(name, type, endian, wrap, unwrap, swap) \
2396static ID RB_IO_BUFFER_DATA_TYPE_##name; \
2399io_buffer_read_##name(const void* base, size_t size, size_t *offset) \
2401 io_buffer_validate_type(size, *offset, sizeof(type)); \
2403 memcpy(&value, (char*)base + *offset, sizeof(type)); \
2404 if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
2405 *offset += sizeof(type); \
2406 return wrap(value); \
2410io_buffer_write_##name(struct rb_io_buffer* buffer, size_t *offset, VALUE _value) \
2412 void* base; size_t size; \
2413 IO_BUFFER_VALIDATE_TYPE_FOR_WRITING(buffer, base, size, *offset, type); \
2414 type value = unwrap(_value); \
2415 IO_BUFFER_VALIDATE_TYPE_FOR_WRITING(buffer, base, size, *offset, type); \
2416 if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
2417 memcpy((char*)base + *offset, &value, sizeof(type)); \
2418 *offset += sizeof(type); \
2422 RB_IO_BUFFER_DATA_TYPE_##name##_SIZE = sizeof(type) \
2430IO_BUFFER_DECLARE_TYPE(s16, int16_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap16)
2431IO_BUFFER_DECLARE_TYPE(S16, int16_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap16)
2435IO_BUFFER_DECLARE_TYPE(s32, int32_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap32)
2436IO_BUFFER_DECLARE_TYPE(S32, int32_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap32)
2438IO_BUFFER_DECLARE_TYPE(u64, uint64_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_ULL2NUM,
RB_NUM2ULL, ruby_swap64)
2439IO_BUFFER_DECLARE_TYPE(U64, uint64_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_ULL2NUM,
RB_NUM2ULL, ruby_swap64)
2440IO_BUFFER_DECLARE_TYPE(s64, int64_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_LL2NUM,
RB_NUM2LL, ruby_swap64)
2441IO_BUFFER_DECLARE_TYPE(S64, int64_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_LL2NUM,
RB_NUM2LL, ruby_swap64)
2443IO_BUFFER_DECLARE_TYPE(u128,
rb_uint128_t, RB_IO_BUFFER_LITTLE_ENDIAN, rb_uint128_to_numeric, rb_numeric_to_uint128, ruby_swap128_uint)
2444IO_BUFFER_DECLARE_TYPE(U128,
rb_uint128_t, RB_IO_BUFFER_BIG_ENDIAN, rb_uint128_to_numeric, rb_numeric_to_uint128, ruby_swap128_uint)
2445IO_BUFFER_DECLARE_TYPE(s128,
rb_int128_t, RB_IO_BUFFER_LITTLE_ENDIAN, rb_int128_to_numeric, rb_numeric_to_int128, ruby_swap128_int)
2446IO_BUFFER_DECLARE_TYPE(S128,
rb_int128_t, RB_IO_BUFFER_BIG_ENDIAN, rb_int128_to_numeric, rb_numeric_to_int128, ruby_swap128_int)
2448IO_BUFFER_DECLARE_TYPE(f32,
float, RB_IO_BUFFER_LITTLE_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf32)
2449IO_BUFFER_DECLARE_TYPE(F32,
float, RB_IO_BUFFER_BIG_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf32)
2450IO_BUFFER_DECLARE_TYPE(f64,
double, RB_IO_BUFFER_LITTLE_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf64)
2451IO_BUFFER_DECLARE_TYPE(F64,
double, RB_IO_BUFFER_BIG_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf64)
2452#undef IO_BUFFER_DECLARE_TYPE
2455io_buffer_buffer_type_size(
ID buffer_type)
2457#define IO_BUFFER_DATA_TYPE_SIZE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) return RB_IO_BUFFER_DATA_TYPE_##name##_SIZE;
2458 IO_BUFFER_DATA_TYPE_SIZE(U8)
2459 IO_BUFFER_DATA_TYPE_SIZE(S8)
2460 IO_BUFFER_DATA_TYPE_SIZE(u16)
2461 IO_BUFFER_DATA_TYPE_SIZE(U16)
2462 IO_BUFFER_DATA_TYPE_SIZE(s16)
2463 IO_BUFFER_DATA_TYPE_SIZE(S16)
2464 IO_BUFFER_DATA_TYPE_SIZE(u32)
2465 IO_BUFFER_DATA_TYPE_SIZE(U32)
2466 IO_BUFFER_DATA_TYPE_SIZE(s32)
2467 IO_BUFFER_DATA_TYPE_SIZE(S32)
2468 IO_BUFFER_DATA_TYPE_SIZE(u64)
2469 IO_BUFFER_DATA_TYPE_SIZE(U64)
2470 IO_BUFFER_DATA_TYPE_SIZE(s64)
2471 IO_BUFFER_DATA_TYPE_SIZE(S64)
2472 IO_BUFFER_DATA_TYPE_SIZE(u128)
2473 IO_BUFFER_DATA_TYPE_SIZE(U128)
2474 IO_BUFFER_DATA_TYPE_SIZE(s128)
2475 IO_BUFFER_DATA_TYPE_SIZE(S128)
2476 IO_BUFFER_DATA_TYPE_SIZE(f32)
2477 IO_BUFFER_DATA_TYPE_SIZE(F32)
2478 IO_BUFFER_DATA_TYPE_SIZE(f64)
2479 IO_BUFFER_DATA_TYPE_SIZE(F64)
2480#undef IO_BUFFER_DATA_TYPE_SIZE
2482 rb_raise(rb_eArgError,
"Invalid type name!");
2486io_buffer_type_id(
VALUE name)
2492#define TYPE_ID(name) io_buffer_type_id(name)
2505io_buffer_size_of(
VALUE klass,
VALUE buffer_type)
2509 for (
long i = 0; i <
RARRAY_LEN(buffer_type); i++) {
2510 total += io_buffer_buffer_type_size(TYPE_ID(
RARRAY_AREF(buffer_type, i)));
2515 return SIZET2NUM(io_buffer_buffer_type_size(TYPE_ID(buffer_type)));
2520rb_io_buffer_get_value(
const void* base,
size_t size,
ID buffer_type,
size_t *offset)
2522#define IO_BUFFER_GET_VALUE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) return io_buffer_read_##name(base, size, offset);
2523 IO_BUFFER_GET_VALUE(U8)
2524 IO_BUFFER_GET_VALUE(S8)
2526 IO_BUFFER_GET_VALUE(u16)
2527 IO_BUFFER_GET_VALUE(U16)
2528 IO_BUFFER_GET_VALUE(s16)
2529 IO_BUFFER_GET_VALUE(S16)
2531 IO_BUFFER_GET_VALUE(u32)
2532 IO_BUFFER_GET_VALUE(U32)
2533 IO_BUFFER_GET_VALUE(s32)
2534 IO_BUFFER_GET_VALUE(S32)
2536 IO_BUFFER_GET_VALUE(u64)
2537 IO_BUFFER_GET_VALUE(U64)
2538 IO_BUFFER_GET_VALUE(s64)
2539 IO_BUFFER_GET_VALUE(S64)
2541 IO_BUFFER_GET_VALUE(u128)
2542 IO_BUFFER_GET_VALUE(U128)
2543 IO_BUFFER_GET_VALUE(s128)
2544 IO_BUFFER_GET_VALUE(S128)
2546 IO_BUFFER_GET_VALUE(f32)
2547 IO_BUFFER_GET_VALUE(F32)
2548 IO_BUFFER_GET_VALUE(f64)
2549 IO_BUFFER_GET_VALUE(F64)
2550#undef IO_BUFFER_GET_VALUE
2552 rb_raise(rb_eArgError,
"Invalid type name!");
2598 size_t offset = io_buffer_extract_offset(_offset);
2600 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2602 return rb_io_buffer_get_value(base, size, TYPE_ID(
type), &offset);
2618 size_t offset = io_buffer_extract_offset(_offset);
2622 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2625 rb_raise(rb_eArgError,
"Argument buffer_types should be an array!");
2630 for (
long i = 0; i <
RARRAY_LEN(buffer_types); i++) {
2632 VALUE value = rb_io_buffer_get_value(base, size, TYPE_ID(
type), &offset);
2642io_buffer_extract_count(
VALUE argument)
2644 if (rb_int_negative_p(argument)) {
2645 rb_raise(rb_eArgError,
"Count can't be negative!");
2652io_buffer_extract_offset_count(
ID buffer_type,
size_t size,
int argc,
VALUE *argv,
size_t *offset,
size_t *count)
2655 *offset = io_buffer_extract_offset(argv[0]);
2662 *count = io_buffer_extract_count(argv[1]);
2665 if (*offset > size) {
2666 rb_raise(rb_eArgError,
"The given offset is bigger than the buffer size!");
2669 *count = (size - *offset) / io_buffer_buffer_type_size(buffer_type);
2680io_buffer_each_locked(
VALUE _arguments)
2683 VALUE self = arguments->self;
2684 int argc = arguments->argc;
2685 VALUE *argv = arguments->argv;
2690 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2694 buffer_type = TYPE_ID(argv[0]);
2697 buffer_type = RB_IO_BUFFER_DATA_TYPE_U8;
2700 size_t offset, count;
2701 io_buffer_extract_offset_count(buffer_type, size, argc-1, argv+1, &offset, &count);
2703 for (
size_t i = 0; i < count; i++) {
2704 size_t current_offset = offset;
2705 VALUE value = rb_io_buffer_get_value(base, size, buffer_type, &offset);
2729io_buffer_each(
int argc,
VALUE *argv,
VALUE self)
2739 rb_io_buffer_lock(self);
2740 return rb_ensure(io_buffer_each_locked, (
VALUE)&arguments, rb_io_buffer_locked_ensure, self);
2754io_buffer_values(
int argc,
VALUE *argv,
VALUE self)
2759 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2763 buffer_type = TYPE_ID(argv[0]);
2766 buffer_type = RB_IO_BUFFER_DATA_TYPE_U8;
2769 size_t offset, count;
2770 io_buffer_extract_offset_count(buffer_type, size, argc-1, argv+1, &offset, &count);
2774 for (
size_t i = 0; i < count; i++) {
2775 VALUE value = rb_io_buffer_get_value(base, size, buffer_type, &offset);
2783io_buffer_each_byte_locked(
VALUE _arguments)
2786 VALUE self = arguments->self;
2787 int argc = arguments->argc;
2788 VALUE *argv = arguments->argv;
2793 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2795 size_t offset, count;
2796 io_buffer_extract_offset_count(RB_IO_BUFFER_DATA_TYPE_U8, size, argc, argv, &offset, &count);
2798 if (size_sum_is_bigger_than(offset, count, size)) {
2799 rb_raise(rb_eArgError,
"Specified offset+count is bigger than the buffer size!");
2802 for (
size_t i = 0; i < count; i++) {
2803 unsigned char *value = (
unsigned char *)base + i + offset;
2826io_buffer_each_byte(
int argc,
VALUE *argv,
VALUE self)
2836 rb_io_buffer_lock(self);
2837 return rb_ensure(io_buffer_each_byte_locked, (
VALUE)&arguments, rb_io_buffer_locked_ensure, self);
2843 ID type = TYPE_ID(buffer_type);
2844#define IO_BUFFER_SET_VALUE(name) if (type == RB_IO_BUFFER_DATA_TYPE_##name) {io_buffer_write_##name(buffer, offset, value); return;}
2845 IO_BUFFER_SET_VALUE(U8);
2846 IO_BUFFER_SET_VALUE(S8);
2848 IO_BUFFER_SET_VALUE(u16);
2849 IO_BUFFER_SET_VALUE(U16);
2850 IO_BUFFER_SET_VALUE(s16);
2851 IO_BUFFER_SET_VALUE(S16);
2853 IO_BUFFER_SET_VALUE(u32);
2854 IO_BUFFER_SET_VALUE(U32);
2855 IO_BUFFER_SET_VALUE(s32);
2856 IO_BUFFER_SET_VALUE(S32);
2858 IO_BUFFER_SET_VALUE(u64);
2859 IO_BUFFER_SET_VALUE(U64);
2860 IO_BUFFER_SET_VALUE(s64);
2861 IO_BUFFER_SET_VALUE(S64);
2863 IO_BUFFER_SET_VALUE(u128);
2864 IO_BUFFER_SET_VALUE(U128);
2865 IO_BUFFER_SET_VALUE(s128);
2866 IO_BUFFER_SET_VALUE(S128);
2868 IO_BUFFER_SET_VALUE(f32);
2869 IO_BUFFER_SET_VALUE(F32);
2870 IO_BUFFER_SET_VALUE(f64);
2871 IO_BUFFER_SET_VALUE(F64);
2872#undef IO_BUFFER_SET_VALUE
2874 rb_raise(rb_eArgError,
"Invalid type name!");
2917 struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);
2918 size_t offset = io_buffer_extract_offset(_offset);
2919 rb_io_buffer_set_value(buffer,
type, &offset, value);
2942 struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);
2945 rb_raise(rb_eArgError,
"Argument buffer_types should be an array!");
2948 size_t offset = io_buffer_extract_offset(_offset);
2951 rb_raise(rb_eArgError,
"Argument values should be an array!");
2955 rb_raise(rb_eArgError,
"Argument buffer_types and values should have the same length!");
2958 for (
long i = 0; i <
RARRAY_LEN(buffer_types); i++) {
2961 rb_io_buffer_set_value(buffer,
type, &offset, value);
2967static size_t IO_BUFFER_BLOCKING_SIZE = 1024*1024;
2970 unsigned char * destination;
2971 const unsigned char * source;
2976io_buffer_memmove_blocking(
void *data)
2980 memmove(arguments->destination, arguments->source, arguments->length);
2986io_buffer_memmove_unblock(
void *data)
2992io_buffer_memmove(
void *base,
size_t size,
size_t offset,
const void *source_base,
size_t source_offset,
size_t source_size,
size_t length)
2994 if (size_sum_is_bigger_than(offset, length, size)) {
2995 rb_raise(rb_eArgError,
"Specified offset+length is bigger than the buffer size!");
2998 if (size_sum_is_bigger_than(source_offset, length, source_size)) {
2999 rb_raise(rb_eArgError,
"The computed source range exceeds the size of the source buffer!");
3002 if (length == 0)
return;
3007 .destination = (
unsigned char*)base+offset,
3008 .source = (
unsigned char*)source_base+source_offset,
3012 if (arguments.length >= IO_BUFFER_BLOCKING_SIZE) {
3014 }
else if (arguments.length != 0) {
3015 memmove(arguments.destination, arguments.source, arguments.length);
3020io_buffer_extract_copy_arguments(
size_t source_size,
int argc,
VALUE *argv,
size_t *offset,
size_t *length,
size_t *source_offset)
3024 *offset = io_buffer_extract_offset(argv[0]);
3032 *source_offset = io_buffer_extract_offset(argv[2]);
3034 if (*source_offset > source_size) {
3035 rb_raise(rb_eArgError,
"The given source offset is bigger than the source itself!");
3043 if (argc >= 2 && !
RB_NIL_P(argv[1])) {
3044 *length = io_buffer_extract_length(argv[1]);
3048 *length = source_size - *source_offset;
3054io_buffer_copy_from(
struct rb_io_buffer *buffer,
const void *source_base,
size_t source_size,
int argc,
VALUE *argv)
3056 size_t offset, length, source_offset;
3057 io_buffer_extract_copy_arguments(source_size, argc, argv, &offset, &length, &source_offset);
3061 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3063 io_buffer_memmove(base, size, offset, source_base, source_offset, source_size, length);
3070 const void *source_base;
3081io_buffer_copy_to(
void *base,
size_t size,
VALUE _arguments)
3085 size_t offset, length, source_offset;
3086 io_buffer_extract_copy_arguments(arguments->source_size, arguments->argc, arguments->argv, &offset, &length, &source_offset);
3088 io_buffer_memmove(base, size, offset, arguments->source_base, source_offset, arguments->source_size, length);
3097io_buffer_copy_from_readable(
const void *base,
size_t size,
VALUE _arguments)
3101 arguments->source_base = base;
3102 arguments->source_size = size;
3104 return rb_io_buffer_locked_for_writing(arguments->destination, io_buffer_copy_to, _arguments);
3108io_buffer_initialize_copy_from(
const void *base,
size_t size,
VALUE self)
3112 io_buffer_initialize(self, buffer, NULL, size, io_flags_for_size(size),
Qnil);
3115 .destination = self,
3116 .source_base = base,
3117 .source_size = size,
3124 return rb_io_buffer_locked_for_writing(self, io_buffer_copy_to, (
VALUE)&arguments);
3145rb_io_buffer_initialize_copy(
VALUE self,
VALUE source)
3147 return rb_io_buffer_locked_for_reading(source, io_buffer_initialize_copy_from, self);
3219io_buffer_copy(
int argc,
VALUE *argv,
VALUE self)
3223 VALUE source = argv[0];
3225 .destination = self,
3235 return rb_io_buffer_locked_for_reading(source, io_buffer_copy_from_readable, (
VALUE)&arguments);
3253io_buffer_get_string(
int argc,
VALUE *argv,
VALUE self)
3257 size_t offset, length;
3258 struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
3262 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3266 encoding = rb_find_encoding(argv[2]);
3269 encoding = rb_ascii8bit_encoding();
3272 io_buffer_validate_range(buffer, offset, length);
3274 const char *data = base ? (
const char*)base + offset : NULL;
3276 return rb_enc_str_new(data, length, encoding);
3303io_buffer_set_string(
int argc,
VALUE *argv,
VALUE self)
3307 struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);
3311 const void *source_base = RSTRING_PTR(
string);
3312 size_t source_size = RSTRING_LEN(
string);
3314 VALUE result = io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
3320rb_io_buffer_clear(
VALUE self, uint8_t value,
size_t offset,
size_t length)
3322 struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);
3326 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3328 io_buffer_validate_range(buffer, offset, length);
3330 if (length == 0)
return;
3333 memset((
char*)base + offset, value, length);
3368io_buffer_clear(
int argc,
VALUE *argv,
VALUE self)
3377 size_t offset, length;
3378 io_buffer_extract_offset_length(self, argc-1, argv+1, &offset, &length);
3380 rb_io_buffer_clear(self, value, offset, length);
3386io_buffer_default_size(
size_t page_size)
3389 const size_t platform_agnostic_default_size = 64*1024;
3392 const char *default_size = getenv(
"RUBY_IO_BUFFER_DEFAULT_SIZE");
3395 int value = atoi(default_size);
3403 if (platform_agnostic_default_size < page_size) {
3407 return platform_agnostic_default_size;
3413 rb_blocking_function_t *function;
3418io_buffer_blocking_region_begin(
VALUE _argument)
3422 return rb_io_blocking_region(argument->io, argument->function, argument->data);
3426io_buffer_blocking_region_ensure(
VALUE _argument)
3430 io_buffer_unlock(argument->buffer);
3436io_buffer_blocking_region(
VALUE io,
struct rb_io_buffer *buffer, rb_blocking_function_t *function,
void *data)
3438 struct rb_io *ioptr;
3444 .function = function,
3451 io_buffer_lock(buffer);
3453 return rb_ensure(io_buffer_blocking_region_begin, (
VALUE)&argument, io_buffer_blocking_region_ensure, (
VALUE)&argument);
3466io_buffer_read_internal(
void *_argument)
3469 ssize_t result = read(argument->descriptor, argument->base, argument->length);
3475rb_io_buffer_read(
VALUE self,
VALUE io,
size_t offset,
size_t length)
3477 struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);
3481 io_buffer_validate_range(buffer, offset, length);
3486 if (scheduler !=
Qnil) {
3489 if (!UNDEF_P(result)) {
3496 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3502 .base = (
char*)base + offset,
3506 return io_buffer_blocking_region(io, buffer, io_buffer_read_internal, &argument);
3533io_buffer_read(
int argc,
VALUE *argv,
VALUE self)
3539 size_t offset, length;
3540 io_buffer_extract_offset_length(self, argc-1, argv+1, &offset, &length);
3542 return rb_io_buffer_read(self, io, offset, length);
3557io_buffer_pread_internal(
void *_argument)
3560 ssize_t result = pread(argument->descriptor, argument->base, argument->length, argument->from);
3566rb_io_buffer_pread(
VALUE self,
VALUE io, rb_off_t from,
size_t offset,
size_t length)
3568 struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);
3572 io_buffer_validate_range(buffer, offset, length);
3577 if (scheduler !=
Qnil) {
3580 if (!UNDEF_P(result)) {
3587 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3593 .base = (
char*)base + offset,
3598 return io_buffer_blocking_region(io, buffer, io_buffer_pread_internal, &argument);
3629io_buffer_pread(
int argc,
VALUE *argv,
VALUE self)
3636 size_t offset, length;
3637 io_buffer_extract_offset_length(self, argc-2, argv+2, &offset, &length);
3639 return rb_io_buffer_pread(self, io, from, offset, length);
3652io_buffer_write_internal(
void *_argument)
3655 ssize_t result = write(argument->descriptor, argument->base, argument->length);
3661rb_io_buffer_write(
VALUE self,
VALUE io,
size_t offset,
size_t length)
3666 io_buffer_validate_range(buffer, offset, length);
3671 if (scheduler !=
Qnil) {
3674 if (!UNDEF_P(result)) {
3681 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3687 .base = (
const char*)base + offset,
3691 return io_buffer_blocking_region(io, buffer, io_buffer_write_internal, &argument);
3711io_buffer_write(
int argc,
VALUE *argv,
VALUE self)
3717 size_t offset, length;
3718 io_buffer_extract_offset_length(self, argc-1, argv+1, &offset, &length);
3720 return rb_io_buffer_write(self, io, offset, length);
3735io_buffer_pwrite_internal(
void *_argument)
3738 ssize_t result = pwrite(argument->descriptor, argument->base, argument->length, argument->from);
3744rb_io_buffer_pwrite(
VALUE self,
VALUE io, rb_off_t from,
size_t offset,
size_t length)
3749 io_buffer_validate_range(buffer, offset, length);
3754 if (scheduler !=
Qnil) {
3757 if (!UNDEF_P(result)) {
3764 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3770 .base = (
const char*)base + offset,
3775 return io_buffer_blocking_region(io, buffer, io_buffer_pwrite_internal, &argument);
3800io_buffer_pwrite(
int argc,
VALUE *argv,
VALUE self)
3807 size_t offset, length;
3808 io_buffer_extract_offset_length(self, argc-2, argv+2, &offset, &length);
3810 return rb_io_buffer_pwrite(self, io, from, offset, length);
3814io_buffer_check_mask_size(
size_t size)
3817 rb_raise(rb_eIOBufferMaskError,
"Zero-length mask given!");
3821memory_and(
unsigned char * restrict output,
const unsigned char * restrict base,
size_t size,
const unsigned char * restrict mask,
size_t mask_size)
3823 for (
size_t offset = 0; offset < size; offset += 1) {
3824 output[offset] = base[offset] & mask[offset % mask_size];
3845 struct rb_io_buffer *mask_buffer = get_io_buffer(mask);
3849 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3851 const void *mask_base;
3853 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
3855 io_buffer_check_mask_size(mask_size);
3857 VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
3858 struct rb_io_buffer *output_buffer = get_io_buffer(output);
3860 memory_and(output_buffer->base, base, size, mask_base, mask_size);
3866memory_or(
unsigned char * restrict output,
const unsigned char * restrict base,
size_t size,
const unsigned char * restrict mask,
size_t mask_size)
3868 for (
size_t offset = 0; offset < size; offset += 1) {
3869 output[offset] = base[offset] | mask[offset % mask_size];
3890 struct rb_io_buffer *mask_buffer = get_io_buffer(mask);
3894 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3896 const void *mask_base;
3898 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
3900 io_buffer_check_mask_size(mask_size);
3902 VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
3903 struct rb_io_buffer *output_buffer = get_io_buffer(output);
3905 memory_or(output_buffer->base, base, size, mask_base, mask_size);
3911memory_xor(
unsigned char * restrict output,
const unsigned char * restrict base,
size_t size,
const unsigned char * restrict mask,
size_t mask_size)
3913 for (
size_t offset = 0; offset < size; offset += 1) {
3914 output[offset] = base[offset] ^ mask[offset % mask_size];
3935 struct rb_io_buffer *mask_buffer = get_io_buffer(mask);
3939 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3941 const void *mask_base;
3943 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
3945 io_buffer_check_mask_size(mask_size);
3947 VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
3948 struct rb_io_buffer *output_buffer = get_io_buffer(output);
3950 memory_xor(output_buffer->base, base, size, mask_base, mask_size);
3956memory_not(
unsigned char * restrict output,
const unsigned char * restrict base,
size_t size)
3958 for (
size_t offset = 0; offset < size; offset += 1) {
3959 output[offset] = ~base[offset];
3976io_buffer_not(
VALUE self)
3982 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3984 VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
3985 struct rb_io_buffer *output_buffer = get_io_buffer(output);
3987 memory_not(output_buffer->base, base, size);
3995 if (a->base > b->base) {
3996 return io_buffer_overlaps(b, a);
3999 return (b->base >= a->base) && (b->base < (
void*)((
unsigned char *)a->base + a->size));
4005 if (io_buffer_overlaps(a, b))
4006 rb_raise(rb_eIOBufferMaskError,
"Mask overlaps source buffer!");
4010memory_and_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
4012 for (
size_t offset = 0; offset < size; offset += 1) {
4013 base[offset] &= mask[offset % mask_size];
4037 struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);
4039 struct rb_io_buffer *mask_buffer = get_io_buffer(mask);
4041 io_buffer_check_mask_size(mask_buffer->size);
4042 io_buffer_check_overlaps(buffer, mask_buffer);
4046 io_buffer_get_bytes_for_writing(buffer, &base, &size);
4048 const void *mask_base;
4050 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
4052 memory_and_inplace(base, size, mask_buffer->base, mask_buffer->size);
4058memory_or_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
4060 for (
size_t offset = 0; offset < size; offset += 1) {
4061 base[offset] |= mask[offset % mask_size];
4085 struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);
4087 struct rb_io_buffer *mask_buffer = get_io_buffer(mask);
4089 io_buffer_check_mask_size(mask_buffer->size);
4090 io_buffer_check_overlaps(buffer, mask_buffer);
4094 io_buffer_get_bytes_for_writing(buffer, &base, &size);
4096 const void *mask_base;
4098 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
4100 memory_or_inplace(base, size, mask_buffer->base, mask_buffer->size);
4106memory_xor_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
4108 for (
size_t offset = 0; offset < size; offset += 1) {
4109 base[offset] ^= mask[offset % mask_size];
4133 struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);
4135 struct rb_io_buffer *mask_buffer = get_io_buffer(mask);
4137 io_buffer_check_mask_size(mask_buffer->size);
4138 io_buffer_check_overlaps(buffer, mask_buffer);
4142 io_buffer_get_bytes_for_writing(buffer, &base, &size);
4144 const void *mask_base;
4146 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
4148 memory_xor_inplace(base, size, mask_buffer->base, mask_buffer->size);
4154memory_not_inplace(
unsigned char * restrict base,
size_t size)
4156 for (
size_t offset = 0; offset < size; offset += 1) {
4157 base[offset] = ~base[offset];
4179io_buffer_not_inplace(
VALUE self)
4181 struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);
4185 io_buffer_get_bytes_for_writing(buffer, &base, &size);
4187 memory_not_inplace(base, size);
4193memory_bit_count(
const unsigned char *base,
size_t size)
4198 const uint64_t *base64 = (
const uint64_t *)base;
4199 size_t count64 = size / 8;
4200 for (
size_t i = 0; i < count64; i += 1) {
4201 count += rb_popcount64(base64[i]);
4205 size_t remaining = size % 8;
4206 const unsigned char *tail = base + (count64 * 8);
4207 for (
size_t i = 0; i < remaining; i += 1) {
4208 count += rb_popcount32(tail[i]);
4228io_buffer_bit_count(
int argc,
VALUE *argv,
VALUE self)
4232 size_t offset, length;
4233 struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
4235 io_buffer_validate_range(buffer, offset, length);
4239 io_buffer_get_bytes_for_reading(buffer, &base, &size);
4244 size_t count = memory_bit_count((
const unsigned char *)base + offset, length);
4254 if (buffer->base == NULL || !io_buffer_validate(buffer)) {
4258 bool readonly =
true;
4259 if (flags & RUBY_MEMORY_VIEW_WRITABLE) {
4260 if (io_buffer_readonly_p(buffer)) {
4267 if (flags & RUBY_MEMORY_VIEW_FORMAT) {
4270 bool request_multi_dimensional = flags & RUBY_MEMORY_VIEW_MULTI_DIMENSIONAL;
4271 bool request_strides =
4272 (flags & RUBY_MEMORY_VIEW_STRIDES) == RUBY_MEMORY_VIEW_STRIDES;
4273 if (request_multi_dimensional || request_strides) {
4274 size_t n_metadata = 0;
4275 if (request_multi_dimensional)
4277 if (request_strides)
4279 ssize_t *metadata_buffer =
ALLOC_N(ssize_t, n_metadata);
4281 if (request_multi_dimensional) {
4282 ssize_t *shape = &metadata_buffer[i];
4283 shape[0] = buffer->size;
4284 view->
shape = shape;
4287 if (request_strides) {
4288 ssize_t *strides = &metadata_buffer[i];
4295 io_buffer_lock(buffer);
4303 rb_io_buffer_unlock(self);
4311io_buffer_memory_view_available_p(
VALUE self)
4315 return buffer->base != NULL && io_buffer_validate(buffer);
4319 .
get_func = io_buffer_memory_view_get,
4320 .release_func = io_buffer_memory_view_release,
4321 .available_p_func = io_buffer_memory_view_available_p,
4427 rb_eIOBufferLockedError = rb_define_class_under(rb_cIOBuffer,
"LockedError",
rb_eRuntimeError);
4430 rb_eIOBufferAllocationError = rb_define_class_under(rb_cIOBuffer,
"AllocationError",
rb_eRuntimeError);
4433 rb_eIOBufferAccessError = rb_define_class_under(rb_cIOBuffer,
"AccessError",
rb_eRuntimeError);
4436 rb_eIOBufferInvalidatedError = rb_define_class_under(rb_cIOBuffer,
"InvalidatedError",
rb_eRuntimeError);
4439 rb_eIOBufferMaskError = rb_define_class_under(rb_cIOBuffer,
"MaskError", rb_eArgError);
4447 GetSystemInfo(&info);
4448 RUBY_IO_BUFFER_PAGE_SIZE = info.dwPageSize;
4449 RUBY_IO_BUFFER_MAP_ALIGNMENT = info.dwAllocationGranularity;
4451 RUBY_IO_BUFFER_PAGE_SIZE = sysconf(_SC_PAGESIZE);
4452 RUBY_IO_BUFFER_MAP_ALIGNMENT = RUBY_IO_BUFFER_PAGE_SIZE;
4455 RUBY_IO_BUFFER_DEFAULT_SIZE = io_buffer_default_size(RUBY_IO_BUFFER_PAGE_SIZE);
4458 rb_define_const(rb_cIOBuffer,
"VERSION",
INT2NUM(RUBY_IO_BUFFER_VERSION));
4461 rb_define_const(rb_cIOBuffer,
"PAGE_SIZE",
SIZET2NUM(RUBY_IO_BUFFER_PAGE_SIZE));
4464 rb_define_const(rb_cIOBuffer,
"MAP_ALIGNMENT",
SIZET2NUM(RUBY_IO_BUFFER_MAP_ALIGNMENT));
4469 rb_define_const(rb_cIOBuffer,
"DEFAULT_SIZE",
SIZET2NUM(RUBY_IO_BUFFER_DEFAULT_SIZE));
4474 rb_define_method(rb_cIOBuffer,
"initialize_copy", rb_io_buffer_initialize_copy, 1);
4484 rb_define_const(rb_cIOBuffer,
"EXTERNAL",
RB_INT2NUM(RB_IO_BUFFER_EXTERNAL));
4487 rb_define_const(rb_cIOBuffer,
"INTERNAL",
RB_INT2NUM(RB_IO_BUFFER_INTERNAL));
4490 rb_define_const(rb_cIOBuffer,
"MAPPED",
RB_INT2NUM(RB_IO_BUFFER_MAPPED));
4493 rb_define_const(rb_cIOBuffer,
"SHARED",
RB_INT2NUM(RB_IO_BUFFER_SHARED));
4496 rb_define_const(rb_cIOBuffer,
"PRIVATE",
RB_INT2NUM(RB_IO_BUFFER_PRIVATE));
4499 rb_define_const(rb_cIOBuffer,
"READONLY",
RB_INT2NUM(RB_IO_BUFFER_READONLY));
4502 rb_define_const(rb_cIOBuffer,
"LITTLE_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_LITTLE_ENDIAN));
4505 rb_define_const(rb_cIOBuffer,
"BIG_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_BIG_ENDIAN));
4508 rb_define_const(rb_cIOBuffer,
"HOST_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_HOST_ENDIAN));
4511 rb_define_const(rb_cIOBuffer,
"NETWORK_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_NETWORK_ENDIAN));
4537#define IO_BUFFER_DEFINE_DATA_TYPE(name) RB_IO_BUFFER_DATA_TYPE_##name = rb_intern_const(#name)
4538 IO_BUFFER_DEFINE_DATA_TYPE(U8);
4539 IO_BUFFER_DEFINE_DATA_TYPE(S8);
4541 IO_BUFFER_DEFINE_DATA_TYPE(u16);
4542 IO_BUFFER_DEFINE_DATA_TYPE(U16);
4543 IO_BUFFER_DEFINE_DATA_TYPE(s16);
4544 IO_BUFFER_DEFINE_DATA_TYPE(S16);
4546 IO_BUFFER_DEFINE_DATA_TYPE(u32);
4547 IO_BUFFER_DEFINE_DATA_TYPE(U32);
4548 IO_BUFFER_DEFINE_DATA_TYPE(s32);
4549 IO_BUFFER_DEFINE_DATA_TYPE(S32);
4551 IO_BUFFER_DEFINE_DATA_TYPE(u64);
4552 IO_BUFFER_DEFINE_DATA_TYPE(U64);
4553 IO_BUFFER_DEFINE_DATA_TYPE(s64);
4554 IO_BUFFER_DEFINE_DATA_TYPE(S64);
4556 IO_BUFFER_DEFINE_DATA_TYPE(u128);
4557 IO_BUFFER_DEFINE_DATA_TYPE(U128);
4558 IO_BUFFER_DEFINE_DATA_TYPE(s128);
4559 IO_BUFFER_DEFINE_DATA_TYPE(S128);
4561 IO_BUFFER_DEFINE_DATA_TYPE(f32);
4562 IO_BUFFER_DEFINE_DATA_TYPE(F32);
4563 IO_BUFFER_DEFINE_DATA_TYPE(f64);
4564 IO_BUFFER_DEFINE_DATA_TYPE(F64);
4565#undef IO_BUFFER_DEFINE_DATA_TYPE
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
static bool RB_OBJ_FROZEN(VALUE obj)
Checks if an object is frozen.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
int rb_block_given_p(void)
Determines if the current method is given a block.
#define T_STRING
Old name of RUBY_T_STRING.
#define xfree
Old name of ruby_xfree.
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define CLASS_OF
Old name of rb_class_of.
#define SIZET2NUM
Old name of RB_SIZE2NUM.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define STATIC_SYM_P
Old name of RB_STATIC_SYM_P.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define NUM2DBL
Old name of rb_num2dbl.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
#define NIL_P
Old name of RB_NIL_P.
#define T_SYMBOL
Old name of RUBY_T_SYMBOL.
#define DBL2NUM
Old name of rb_float_new.
#define NUM2SIZET
Old name of RB_NUM2SIZE.
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_eTypeError
TypeError exception.
VALUE rb_eRuntimeError
RuntimeError exception.
@ RB_WARN_CATEGORY_EXPERIMENTAL
Warning is for experimental features.
VALUE rb_cObject
Object class.
static VALUE rb_class_of(VALUE obj)
Object to class mapping function.
VALUE rb_obj_class(VALUE obj)
Queries the class of an object.
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
VALUE rb_mComparable
Comparable module.
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length)
Non-blocking read from the passed IO.
VALUE rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t offset, size_t length)
Non-blocking write to the passed IO at the specified offset.
static VALUE rb_fiber_scheduler_io_result(ssize_t result, int error)
Wrap a ssize_t and int errno into a single VALUE.
VALUE rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t offset, size_t length)
Non-blocking read from the passed IO at the specified offset.
VALUE rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length)
Non-blocking write to the passed IO.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
#define RETURN_ENUMERATOR_KW(obj, argc, argv, kw_splat)
Identical to RETURN_SIZED_ENUMERATOR_KW(), except its size is unknown.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
ID rb_sym2id(VALUE obj)
Converts an instance of rb_cSymbol into an ID.
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
void * rb_nogvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2, int flags)
Identical to rb_thread_call_without_gvl(), except it additionally takes "flags" that change the behav...
#define RB_NOGVL_OFFLOAD_SAFE
Passing this flag to rb_nogvl() indicates that the passed function is safe to offload to a background...
#define RB_NUM2INT
Just another name of rb_num2int_inline.
#define RB_UINT2NUM
Just another name of rb_uint2num_inline.
#define RB_INT2NUM
Just another name of rb_int2num_inline.
static unsigned int RB_NUM2UINT(VALUE x)
Converts an instance of rb_cNumeric into C's unsigned int.
#define RB_LL2NUM
Just another name of rb_ll2num_inline.
#define RB_ULL2NUM
Just another name of rb_ull2num_inline.
#define RB_NUM2ULL
Just another name of rb_num2ull_inline.
#define RB_NUM2LL
Just another name of rb_num2ll_inline.
VALUE rb_yield_values(int n,...)
Identical to rb_yield(), except it takes variadic number of parameters and pass them to the block.
VALUE rb_yield(VALUE val)
Yields the block.
static VALUE RB_INT2FIX(long i)
Converts a C's long into an instance of rb_cInteger.
#define RB_NUM2LONG
Just another name of rb_num2long_inline.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
bool rb_memory_view_register(VALUE klass, const rb_memory_view_entry_t *entry)
Associates the passed class with the passed memory view entry.
bool rb_memory_view_init_as_byte_array(rb_memory_view_t *view, VALUE obj, void *data, const ssize_t len, const bool readonly)
Fill the members of view as an 1-dimensional byte array.
VALUE type(ANYARGS)
ANYARGS-ed function type.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_AREF(a, i)
#define StringValue(v)
Ensures that the parameter object is a String.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
VALUE rb_str_to_str(VALUE obj)
Identical to rb_check_string_type(), except it raises exceptions in case of conversion failures.
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
#define errno
Ractor-aware version of errno.
#define RB_NO_KEYWORDS
Do not pass keywords.
static bool RB_NIL_P(VALUE obj)
Checks if the given object is nil.
This is the struct that holds necessary info for a struct.
const char * wrap_struct_name
Name of structs of this kind.
Ruby's IO, metadata and buffers.
Operations applied to a specific kind of a memory view.
rb_memory_view_get_func_t get_func
Exports a memory view from a Ruby object.
A MemoryView structure, rb_memory_view_t, is used for exporting objects' MemoryView.
const ssize_t * strides
ndim size array indicating the number of bytes to skip to go to the next element in each dimension.
const ssize_t * shape
ndim size array indicating the number of elements in each dimension.
void * private_data
The private data for managing this exported memory.
const char * format
A string to describe the format of an element, or NULL for unsigned bytes.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static void Check_Type(VALUE v, enum ruby_value_type t)
Identical to RB_TYPE_P(), except it raises exceptions on predication failure.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.