16#include "internal/array.h"
17#include "internal/bits.h"
18#include "internal/error.h"
19#include "internal/gc.h"
20#include "internal/numeric.h"
21#include "internal/string.h"
22#include "internal/io.h"
23#include "internal/io_buffer.h"
26VALUE rb_eIOBufferLockedError;
27VALUE rb_eIOBufferAllocationError;
28VALUE rb_eIOBufferAccessError;
29VALUE rb_eIOBufferInvalidatedError;
30VALUE rb_eIOBufferMaskError;
32size_t RUBY_IO_BUFFER_PAGE_SIZE;
33size_t RUBY_IO_BUFFER_DEFAULT_SIZE;
42 RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH = 16,
43 RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH = 1024,
45 RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE = 256,
46 RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH = 16,
49 RB_IO_BUFFER_FLAGS_MASK = RB_IO_BUFFER_EXTERNAL | RB_IO_BUFFER_INTERNAL | RB_IO_BUFFER_MAPPED | RB_IO_BUFFER_SHARED | RB_IO_BUFFER_LOCKED | RB_IO_BUFFER_PRIVATE | RB_IO_BUFFER_READONLY,
51 RB_IO_BUFFER_DEBUG = 0,
57 enum rb_io_buffer_flags flags;
67io_buffer_map_memory(
size_t size,
int flags)
70 void * base = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
73 rb_sys_fail(
"io_buffer_map_memory:VirtualAlloc");
76 int mmap_flags = MAP_ANONYMOUS;
77 if (flags & RB_IO_BUFFER_SHARED) {
78 mmap_flags |= MAP_SHARED;
81 mmap_flags |= MAP_PRIVATE;
84 void * base = mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
86 if (base == MAP_FAILED) {
87 rb_sys_fail(
"io_buffer_map_memory:mmap");
90 ruby_annotate_mmap(base, size,
"Ruby:io_buffer_map_memory");
97io_buffer_map_file(
struct rb_io_buffer *buffer,
int descriptor,
size_t size, rb_off_t offset,
enum rb_io_buffer_flags flags)
100 HANDLE file = (HANDLE)_get_osfhandle(descriptor);
101 if (!file) rb_sys_fail(
"io_buffer_map_descriptor:_get_osfhandle");
103 DWORD protect = PAGE_READONLY, access = FILE_MAP_READ;
105 if (flags & RB_IO_BUFFER_READONLY) {
106 buffer->flags |= RB_IO_BUFFER_READONLY;
109 protect = PAGE_READWRITE;
110 access = FILE_MAP_WRITE;
113 if (flags & RB_IO_BUFFER_PRIVATE) {
114 protect = PAGE_WRITECOPY;
115 access = FILE_MAP_COPY;
116 buffer->flags |= RB_IO_BUFFER_PRIVATE;
120 buffer->flags |= RB_IO_BUFFER_EXTERNAL;
121 buffer->flags |= RB_IO_BUFFER_SHARED;
124 HANDLE mapping = CreateFileMapping(file, NULL, protect, 0, 0, NULL);
125 if (RB_IO_BUFFER_DEBUG) fprintf(stderr,
"io_buffer_map_file:CreateFileMapping -> %p\n", mapping);
126 if (!mapping) rb_sys_fail(
"io_buffer_map_descriptor:CreateFileMapping");
128 void *base = MapViewOfFile(mapping, access, (DWORD)(offset >> 32), (DWORD)(offset & 0xFFFFFFFF), size);
131 CloseHandle(mapping);
132 rb_sys_fail(
"io_buffer_map_file:MapViewOfFile");
135 buffer->mapping = mapping;
137 int protect = PROT_READ, access = 0;
139 if (flags & RB_IO_BUFFER_READONLY) {
140 buffer->flags |= RB_IO_BUFFER_READONLY;
143 protect |= PROT_WRITE;
146 if (flags & RB_IO_BUFFER_PRIVATE) {
147 buffer->flags |= RB_IO_BUFFER_PRIVATE;
148 access |= MAP_PRIVATE;
152 buffer->flags |= RB_IO_BUFFER_EXTERNAL;
153 buffer->flags |= RB_IO_BUFFER_SHARED;
154 access |= MAP_SHARED;
157 void *base = mmap(NULL, size, protect, access, descriptor, offset);
159 if (base == MAP_FAILED) {
160 rb_sys_fail(
"io_buffer_map_file:mmap");
167 buffer->flags |= RB_IO_BUFFER_MAPPED;
168 buffer->flags |= RB_IO_BUFFER_FILE;
172io_buffer_experimental(
void)
174 static int warned = 0;
182 "IO::Buffer is experimental and both the Ruby and C interface may change in the future!"
193 buffer->mapping = NULL;
195 buffer->source =
Qnil;
199io_buffer_initialize(
VALUE self,
struct rb_io_buffer *buffer,
void *base,
size_t size,
enum rb_io_buffer_flags flags,
VALUE source)
206 if (flags & RB_IO_BUFFER_INTERNAL) {
207 base = calloc(size, 1);
209 else if (flags & RB_IO_BUFFER_MAPPED) {
210 base = io_buffer_map_memory(size, flags);
214 rb_raise(rb_eIOBufferAllocationError,
"Could not allocate buffer!");
224 buffer->flags = flags;
228 buffer->mapping = NULL;
236 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
240 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
242 if (buffer->flags & RB_IO_BUFFER_FILE) {
243 UnmapViewOfFile(buffer->base);
246 VirtualFree(buffer->base, 0, MEM_RELEASE);
249 munmap(buffer->base, buffer->size);
263 buffer->source =
Qnil;
267 if (buffer->mapping) {
268 if (RB_IO_BUFFER_DEBUG) fprintf(stderr,
"io_buffer_free:CloseHandle -> %p\n", buffer->mapping);
269 if (!CloseHandle(buffer->mapping)) {
270 fprintf(stderr,
"io_buffer_free:GetLastError -> %lu\n", GetLastError());
272 buffer->mapping = NULL;
278rb_io_buffer_type_mark(
void *_buffer)
281 if (buffer->source !=
Qnil) {
285 rb_gc_mark(buffer->source);
287 rb_gc_mark_movable(buffer->source);
293rb_io_buffer_type_compact(
void *_buffer)
296 if (buffer->source !=
Qnil) {
301 buffer->source = rb_gc_location(buffer->source);
307rb_io_buffer_type_free(
void *_buffer)
311 io_buffer_free(buffer);
315rb_io_buffer_type_size(
const void *_buffer)
321 total += buffer->size;
330 .dmark = rb_io_buffer_type_mark,
331 .dfree = rb_io_buffer_type_free,
332 .dsize = rb_io_buffer_type_size,
333 .dcompact = rb_io_buffer_type_compact,
336 .flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
340get_io_buffer(
VALUE self)
347static inline enum rb_io_buffer_flags
348io_buffer_extract_flags(
VALUE argument)
350 if (rb_int_negative_p(argument)) {
351 rb_raise(rb_eArgError,
"Flags can't be negative!");
354 enum rb_io_buffer_flags flags =
RB_NUM2UINT(argument);
357 return flags & RB_IO_BUFFER_FLAGS_MASK;
362io_buffer_extract_offset(
VALUE argument)
364 if (rb_int_negative_p(argument)) {
365 rb_raise(rb_eArgError,
"Offset can't be negative!");
375io_buffer_extract_length(
VALUE argument)
377 if (rb_int_negative_p(argument)) {
378 rb_raise(rb_eArgError,
"Length can't be negative!");
387io_buffer_extract_size(
VALUE argument)
389 if (rb_int_negative_p(argument)) {
390 rb_raise(rb_eArgError,
"Size can't be negative!");
399io_buffer_extract_width(
VALUE argument,
size_t minimum)
401 if (rb_int_negative_p(argument)) {
402 rb_raise(rb_eArgError,
"Width can't be negative!");
407 if (width < minimum) {
408 rb_raise(rb_eArgError,
"Width must be at least %" PRIuSIZE
"!", minimum);
411 if (width > RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH) {
412 rb_raise(rb_eArgError,
"Width must be at most %" PRIuSIZE
"!", (
size_t)RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH);
423io_buffer_default_length(
const struct rb_io_buffer *buffer,
size_t offset)
425 if (offset > buffer->size) {
426 rb_raise(rb_eArgError,
"The given offset is bigger than the buffer size!");
430 return buffer->size - offset;
439io_buffer_extract_length_offset(
VALUE self,
int argc,
VALUE argv[],
size_t *length,
size_t *offset)
443 if (argc >= 2 && !
NIL_P(argv[1])) {
444 *offset = io_buffer_extract_offset(argv[1]);
450 if (argc >= 1 && !
NIL_P(argv[0])) {
451 *length = io_buffer_extract_length(argv[0]);
454 *length = io_buffer_default_length(buffer, *offset);
470io_buffer_extract_offset_length(
VALUE self,
int argc,
VALUE argv[],
size_t *offset,
size_t *length)
474 if (argc >= 1 && !
NIL_P(argv[0])) {
475 *offset = io_buffer_extract_offset(argv[0]);
481 if (argc >= 2 && !
NIL_P(argv[1])) {
482 *length = io_buffer_extract_length(argv[1]);
485 *length = io_buffer_default_length(buffer, *offset);
492rb_io_buffer_type_allocate(
VALUE self)
494 io_buffer_experimental();
499 io_buffer_zero(buffer);
504static VALUE io_buffer_for_make_instance(
VALUE klass,
VALUE string,
enum rb_io_buffer_flags flags)
506 VALUE instance = rb_io_buffer_type_allocate(klass);
510 flags |= RB_IO_BUFFER_EXTERNAL;
513 flags |= RB_IO_BUFFER_READONLY;
515 if (!(flags & RB_IO_BUFFER_READONLY))
516 rb_str_modify(
string);
518 io_buffer_initialize(instance, buffer, RSTRING_PTR(
string), RSTRING_LEN(
string), flags,
string);
527 enum rb_io_buffer_flags flags;
531io_buffer_for_yield_instance(
VALUE _arguments)
535 arguments->instance = io_buffer_for_make_instance(arguments->klass, arguments->string, arguments->flags);
541 return rb_yield(arguments->instance);
545io_buffer_for_yield_instance_ensure(
VALUE _arguments)
549 if (arguments->instance !=
Qnil) {
550 rb_io_buffer_free(arguments->instance);
564 enum rb_io_buffer_flags flags;
571io_buffer_for_callback_call(
VALUE _arguments)
575 arguments->instance = io_buffer_for_make_instance(arguments->klass, arguments->string, arguments->flags);
579 arguments->locked = 1;
582 return arguments->callback(arguments->instance, arguments->argument);
586io_buffer_for_callback_ensure(
VALUE _arguments)
590 if (arguments->instance !=
Qnil) {
591 rb_io_buffer_free(arguments->instance);
594 if (arguments->locked) {
605 return callback(string_or_buffer, argument);
610 .klass = rb_cIOBuffer,
611 .string = string_or_buffer,
613 .flags = RB_IO_BUFFER_READONLY,
615 .callback = callback,
616 .argument = argument,
619 io_buffer_for_callback_ensure, (
VALUE)&arguments);
622 rb_raise(
rb_eTypeError,
"expected String or IO::Buffer, not %"PRIsVALUE,
628int rb_io_buffer_readonly_p(
VALUE self);
634 if (rb_io_buffer_readonly_p(string_or_buffer)) {
635 rb_raise(rb_eArgError,
"buffer is read-only");
637 return callback(string_or_buffer, argument);
642 .klass = rb_cIOBuffer,
643 .string = string_or_buffer,
647 .callback = callback,
648 .argument = argument,
651 io_buffer_for_callback_ensure, (
VALUE)&arguments);
654 rb_raise(
rb_eTypeError,
"expected String or IO::Buffer, not %"PRIsVALUE,
696rb_io_buffer_type_for(
VALUE klass,
VALUE string)
710 return rb_ensure(io_buffer_for_yield_instance, (
VALUE)&arguments, io_buffer_for_yield_instance_ensure, (
VALUE)&arguments);
714 string = rb_str_tmp_frozen_acquire(
string);
715 return io_buffer_for_make_instance(klass,
string, RB_IO_BUFFER_READONLY);
733rb_io_buffer_type_string(
VALUE klass,
VALUE length)
743 rb_ensure(io_buffer_for_yield_instance, (
VALUE)&arguments, io_buffer_for_yield_instance_ensure, (
VALUE)&arguments);
749rb_io_buffer_new(
void *base,
size_t size,
enum rb_io_buffer_flags flags)
751 VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
755 io_buffer_initialize(instance, buffer, base, size, flags,
Qnil);
761rb_io_buffer_map(
VALUE io,
size_t size, rb_off_t offset,
enum rb_io_buffer_flags flags)
763 VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
769 io_buffer_map_file(buffer, descriptor, size, offset, flags);
819io_buffer_map(
int argc,
VALUE *argv,
VALUE klass)
826 rb_off_t file_size = rb_file_size(io);
828 if (UNLIKELY(file_size <= 0)) {
829 rb_raise(rb_eArgError,
"Invalid negative or zero file size!");
832 else if (UNLIKELY((uintmax_t)file_size > SIZE_MAX)) {
833 rb_raise(rb_eArgError,
"File larger than address space!");
837 if (argc >= 2 && !
RB_NIL_P(argv[1])) {
838 size = io_buffer_extract_size(argv[1]);
839 if (UNLIKELY(size == 0)) {
840 rb_raise(rb_eArgError,
"Size can't be zero!");
842 if (UNLIKELY(size > (
size_t)file_size)) {
843 rb_raise(rb_eArgError,
844 "Size (%" PRIuSIZE
") can't be larger than "
845 "file size (%" PRIuSIZE
")",
852 size = (size_t)file_size;
859 if (UNLIKELY(offset < 0)) {
860 rb_raise(rb_eArgError,
861 "Offset (%" PRIsVALUE
") can't be negative!",
864 if (UNLIKELY(offset >= file_size)) {
865 rb_raise(rb_eArgError,
866 "Offset (%" PRIsVALUE
") can't be larger than "
867 "file size (%" PRIuSIZE
")",
873 size = (size_t)(file_size - offset);
875 else if (UNLIKELY((
size_t)(file_size - offset) < size)) {
876 size_t maximum_page_count =
877 (file_size - size) / RUBY_IO_BUFFER_PAGE_SIZE;
878 size_t maximum_offset =
879 RUBY_IO_BUFFER_PAGE_SIZE * maximum_page_count;
880 rb_raise(rb_eArgError,
881 "Offset (%" PRIsVALUE
") can't be larger than "
882 "%" PRIuSIZE
" for requested size (%" PRIuSIZE
")",
889 enum rb_io_buffer_flags flags = 0;
891 flags = io_buffer_extract_flags(argv[3]);
894 return rb_io_buffer_map(io, size, offset, flags);
898static inline enum rb_io_buffer_flags
899io_flags_for_size(
size_t size)
901 if (size >= RUBY_IO_BUFFER_PAGE_SIZE) {
902 return RB_IO_BUFFER_MAPPED;
905 return RB_IO_BUFFER_INTERNAL;
933rb_io_buffer_initialize(
int argc,
VALUE *argv,
VALUE self)
941 size = io_buffer_extract_size(argv[0]);
944 size = RUBY_IO_BUFFER_DEFAULT_SIZE;
947 enum rb_io_buffer_flags flags = 0;
949 flags = io_buffer_extract_flags(argv[1]);
952 flags |= io_flags_for_size(size);
955 io_buffer_initialize(self, buffer, NULL, size, flags,
Qnil);
961io_buffer_validate_slice(
VALUE source,
void *base,
size_t size)
963 void *source_base = NULL;
964 size_t source_size = 0;
970 rb_io_buffer_get_bytes(source, &source_base, &source_size);
974 if (source_base == NULL)
return 0;
977 if (base < source_base)
return 0;
979 const void *source_end = (
char*)source_base + source_size;
980 const void *end = (
char*)base + size;
983 if (end > source_end)
return 0;
992 if (buffer->source !=
Qnil) {
994 return io_buffer_validate_slice(buffer->source, buffer->base, buffer->size);
1001enum rb_io_buffer_flags
1002rb_io_buffer_get_bytes(
VALUE self,
void **base,
size_t *size)
1006 if (io_buffer_validate(buffer)) {
1008 *base = buffer->base;
1009 *size = buffer->size;
1011 return buffer->flags;
1023io_buffer_validate_for_writing(
struct rb_io_buffer *buffer)
1025 if (buffer->flags & RB_IO_BUFFER_READONLY ||
1027 rb_raise(rb_eIOBufferAccessError,
"Buffer is not writable!");
1030 if (!io_buffer_validate(buffer)) {
1031 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer is invalid!");
1036get_io_buffer_for_writing(
VALUE self)
1039 io_buffer_validate_for_writing(buffer);
1044io_buffer_get_bytes_for_writing(
struct rb_io_buffer *buffer,
void **base,
size_t *size)
1046 io_buffer_validate_for_writing(buffer);
1049 *base = buffer->base;
1050 *size = buffer->size;
1058rb_io_buffer_get_bytes_for_writing(
VALUE self,
void **base,
size_t *size)
1062 io_buffer_get_bytes_for_writing(buffer, base, size);
1066io_buffer_validate_for_reading(
struct rb_io_buffer *buffer)
1068 if (!io_buffer_validate(buffer)) {
1069 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer has been invalidated!");
1074io_buffer_get_bytes_for_reading(
struct rb_io_buffer *buffer,
const void **base,
size_t *size)
1076 io_buffer_validate_for_reading(buffer);
1079 *base = buffer->base;
1080 *size = buffer->size;
1088rb_io_buffer_get_bytes_for_reading(
VALUE self,
const void **base,
size_t *size)
1092 io_buffer_get_bytes_for_reading(buffer, base, size);
1105rb_io_buffer_to_s(
VALUE self)
1112 rb_str_catf(result,
" %p+%"PRIdSIZE, buffer->base, buffer->size);
1114 if (buffer->base == NULL) {
1118 if (buffer->flags & RB_IO_BUFFER_EXTERNAL) {
1122 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
1126 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
1130 if (buffer->flags & RB_IO_BUFFER_FILE) {
1134 if (buffer->flags & RB_IO_BUFFER_SHARED) {
1138 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1142 if (buffer->flags & RB_IO_BUFFER_PRIVATE) {
1146 if (buffer->flags & RB_IO_BUFFER_READONLY) {
1150 if (buffer->source !=
Qnil) {
1154 if (!io_buffer_validate(buffer)) {
1164io_buffer_hexdump_output_size(
size_t width,
size_t size,
int first)
1167 size_t total = size;
1169 size_t whole_lines = (size / width);
1170 size_t partial_line = (size % width) ? 1 : 0;
1175 total += (whole_lines + partial_line) * (1 + 10 + width*3 + 1 + 1);
1178 if (size && first) total -= 1;
1187io_buffer_hexdump(
VALUE string,
size_t width,
const char *base,
size_t length,
size_t offset,
int first)
1189 char *text = alloca(width+1);
1192 for (; offset < length; offset += width) {
1193 memset(text,
'\0', width);
1195 rb_str_catf(
string,
"0x%08" PRIxSIZE
" ", offset);
1199 rb_str_catf(
string,
"\n0x%08" PRIxSIZE
" ", offset);
1202 for (
size_t i = 0; i < width; i += 1) {
1203 if (offset+i < length) {
1204 unsigned char value = ((
unsigned char*)base)[offset+i];
1206 if (value < 127 && isprint(value)) {
1207 text[i] = (char)value;
1213 rb_str_catf(
string,
" %02x", value);
1220 rb_str_catf(
string,
" %s", text);
1239rb_io_buffer_inspect(
VALUE self)
1243 VALUE result = rb_io_buffer_to_s(self);
1245 if (io_buffer_validate(buffer)) {
1247 size_t size = buffer->size;
1250 if (size > RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE) {
1251 size = RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE;
1255 io_buffer_hexdump(result, RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH, buffer->base, size, 0, 0);
1258 rb_str_catf(result,
"\n(and %" PRIuSIZE
" more bytes not printed)", buffer->size - size);
1272rb_io_buffer_size(
VALUE self)
1288rb_io_buffer_valid_p(
VALUE self)
1292 return RBOOL(io_buffer_validate(buffer));
1310rb_io_buffer_null_p(
VALUE self)
1314 return RBOOL(buffer->base == NULL);
1325rb_io_buffer_empty_p(
VALUE self)
1329 return RBOOL(buffer->size == 0);
1344rb_io_buffer_external_p(
VALUE self)
1348 return RBOOL(buffer->flags & RB_IO_BUFFER_EXTERNAL);
1368rb_io_buffer_internal_p(
VALUE self)
1372 return RBOOL(buffer->flags & RB_IO_BUFFER_INTERNAL);
1389rb_io_buffer_mapped_p(
VALUE self)
1393 return RBOOL(buffer->flags & RB_IO_BUFFER_MAPPED);
1420rb_io_buffer_shared_p(
VALUE self)
1424 return RBOOL(buffer->flags & RB_IO_BUFFER_SHARED);
1442rb_io_buffer_locked_p(
VALUE self)
1446 return RBOOL(buffer->flags & RB_IO_BUFFER_LOCKED);
1472rb_io_buffer_private_p(
VALUE self)
1476 return RBOOL(buffer->flags & RB_IO_BUFFER_PRIVATE);
1480rb_io_buffer_readonly_p(
VALUE self)
1484 return buffer->flags & RB_IO_BUFFER_READONLY;
1497io_buffer_readonly_p(
VALUE self)
1499 return RBOOL(rb_io_buffer_readonly_p(self));
1505 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1509 buffer->flags |= RB_IO_BUFFER_LOCKED;
1516 if (!io_buffer_try_lock(buffer)) {
1517 rb_raise(rb_eIOBufferLockedError,
"Buffer already locked!");
1522rb_io_buffer_lock(
VALUE self)
1526 io_buffer_lock(buffer);
1534 if (!(buffer->flags & RB_IO_BUFFER_LOCKED)) {
1535 rb_raise(rb_eIOBufferLockedError,
"Buffer not locked!");
1538 buffer->flags &= ~RB_IO_BUFFER_LOCKED;
1542rb_io_buffer_unlock(
VALUE self)
1546 io_buffer_unlock(buffer);
1552rb_io_buffer_try_unlock(
VALUE self)
1556 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1557 buffer->flags &= ~RB_IO_BUFFER_LOCKED;
1565rb_io_buffer_locked_ensure(
VALUE self)
1569 buffer->flags &= ~RB_IO_BUFFER_LOCKED;
1605rb_io_buffer_locked(
VALUE self)
1609 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1610 rb_raise(rb_eIOBufferLockedError,
"Buffer already locked!");
1613 buffer->flags |= RB_IO_BUFFER_LOCKED;
1644rb_io_buffer_free(
VALUE self)
1648 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1649 rb_raise(rb_eIOBufferLockedError,
"Buffer is locked!");
1652 io_buffer_free(buffer);
1661 io_buffer_unlock(buffer);
1662 io_buffer_free(buffer);
1668size_sum_is_bigger_than(
size_t a,
size_t b,
size_t x)
1670 struct rbimpl_size_overflow_tag size = rbimpl_size_add_overflow(a, b);
1671 return size.overflowed || size.result > x;
1677io_buffer_validate_range(
struct rb_io_buffer *buffer,
size_t offset,
size_t length)
1679 io_buffer_validate_for_reading(buffer);
1681 if (size_sum_is_bigger_than(offset, length, buffer->size)) {
1682 rb_raise(rb_eArgError,
"Specified offset+length is bigger than the buffer size!");
1706rb_io_buffer_hexdump(
int argc,
VALUE *argv,
VALUE self)
1710 size_t offset, length;
1711 struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
1713 size_t width = RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH;
1715 width = io_buffer_extract_width(argv[2], 1);
1719 io_buffer_validate_range(buffer, offset, length);
1723 if (io_buffer_validate(buffer) && buffer->base) {
1724 result =
rb_str_buf_new(io_buffer_hexdump_output_size(width, length, 1));
1726 io_buffer_hexdump(result, width, buffer->base, offset+length, offset, 1);
1733rb_io_buffer_slice(
struct rb_io_buffer *buffer,
VALUE self,
size_t offset,
size_t length)
1735 io_buffer_validate_range(buffer, offset, length);
1740 slice->flags |= (buffer->flags & RB_IO_BUFFER_READONLY);
1741 slice->base = (
char*)buffer->base + offset;
1742 slice->size = length;
1745 if (buffer->source !=
Qnil) {
1746 RB_OBJ_WRITE(instance, &slice->source, buffer->source);
1806io_buffer_slice(
int argc,
VALUE *argv,
VALUE self)
1810 size_t offset, length;
1811 struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
1813 return rb_io_buffer_slice(buffer, self, offset, length);
1835rb_io_buffer_transfer(
VALUE self)
1839 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1840 rb_raise(rb_eIOBufferLockedError,
"Cannot transfer ownership of locked buffer!");
1847 *transferred = *buffer;
1848 io_buffer_zero(buffer);
1854io_buffer_resize_clear(
struct rb_io_buffer *buffer,
void* base,
size_t size)
1856 if (size > buffer->size) {
1857 memset((
unsigned char*)base+buffer->size, 0, size - buffer->size);
1866 io_buffer_initialize(self, &resized, NULL, size, io_flags_for_size(size),
Qnil);
1869 size_t preserve = buffer->size;
1870 if (preserve > size) preserve = size;
1871 memcpy(resized.base, buffer->base, preserve);
1873 io_buffer_resize_clear(buffer, resized.base, size);
1876 io_buffer_free(buffer);
1881rb_io_buffer_resize(
VALUE self,
size_t size)
1885 io_buffer_validate_for_reading(buffer);
1887 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1888 rb_raise(rb_eIOBufferLockedError,
"Cannot resize locked buffer!");
1891 if (buffer->base == NULL) {
1892 io_buffer_initialize(self, buffer, NULL, size, io_flags_for_size(size),
Qnil);
1896 if (buffer->flags & RB_IO_BUFFER_EXTERNAL) {
1897 rb_raise(rb_eIOBufferAccessError,
"Cannot resize external buffer!");
1900#if defined(HAVE_MREMAP) && defined(MREMAP_MAYMOVE)
1901 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
1902 void *base = mremap(buffer->base, buffer->size, size, MREMAP_MAYMOVE);
1904 if (base == MAP_FAILED) {
1905 rb_sys_fail(
"rb_io_buffer_resize:mremap");
1908 io_buffer_resize_clear(buffer, base, size);
1910 buffer->base = base;
1911 buffer->size = size;
1917 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
1919 io_buffer_free(buffer);
1923 void *base = realloc(buffer->base, size);
1926 rb_sys_fail(
"rb_io_buffer_resize:realloc");
1929 io_buffer_resize_clear(buffer, base, size);
1931 buffer->base = base;
1932 buffer->size = size;
1937 io_buffer_resize_copy(self, buffer, size);
1961 rb_io_buffer_resize(self, io_buffer_extract_size(size));
1983 const void *ptr1, *ptr2;
1984 size_t size1, size2;
1986 rb_io_buffer_get_bytes_for_reading(self, &ptr1, &size1);
1987 rb_io_buffer_get_bytes_for_reading(other, &ptr2, &size2);
1989 if (size1 < size2) {
1993 if (size1 > size2) {
1997 return RB_INT2NUM(memcmp(ptr1, ptr2, size1));
2001io_buffer_validate_type(
size_t size,
size_t offset,
size_t extend)
2003 if (size_sum_is_bigger_than(offset, extend, size)) {
2004 rb_raise(rb_eArgError,
"Type extends beyond end of buffer! (offset=%"PRIdSIZE
" > size=%"PRIdSIZE
")", offset, size);
2029#define ruby_swap8(value) value
2037ruby_swapf32(
float value)
2039 union swapf32 swap = {.value = value};
2040 swap.integral = ruby_swap32(swap.integral);
2050ruby_swapf64(
double value)
2052 union swapf64 swap = {.value = value};
2053 swap.integral = ruby_swap64(swap.integral);
2065#ifdef HAVE_UINT128_T
2066#if __has_builtin(__builtin_bswap128)
2067 result.value = __builtin_bswap128(x.value);
2070 uint64_t low = (uint64_t)x.value;
2071 uint64_t high = (uint64_t)(x.value >> 64);
2072 low = ruby_swap64(low);
2073 high = ruby_swap64(high);
2074 result.value = ((uint128_t)low << 64) | high;
2081 result.parts.low = ruby_swap64(x.parts.high);
2082 result.parts.high = ruby_swap64(x.parts.low);
2093 conversion.uint128 = ruby_swap128_uint(conversion.uint128);
2094 return conversion.int128;
2097#define IO_BUFFER_VALIDATE_TYPE_FOR_WRITING(buffer, base, size, offset, type) \
2098 (io_buffer_get_bytes_for_writing(buffer, &(base), &(size)), \
2099 io_buffer_validate_type(size, offset, sizeof(type)))
2101#define IO_BUFFER_DECLARE_TYPE(name, type, endian, wrap, unwrap, swap) \
2102static ID RB_IO_BUFFER_DATA_TYPE_##name; \
2105io_buffer_read_##name(const void* base, size_t size, size_t *offset) \
2107 io_buffer_validate_type(size, *offset, sizeof(type)); \
2109 memcpy(&value, (char*)base + *offset, sizeof(type)); \
2110 if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
2111 *offset += sizeof(type); \
2112 return wrap(value); \
2116io_buffer_write_##name(struct rb_io_buffer* buffer, size_t *offset, VALUE _value) \
2118 void* base; size_t size; \
2119 IO_BUFFER_VALIDATE_TYPE_FOR_WRITING(buffer, base, size, *offset, type); \
2120 type value = unwrap(_value); \
2121 IO_BUFFER_VALIDATE_TYPE_FOR_WRITING(buffer, base, size, *offset, type); \
2122 if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
2123 memcpy((char*)base + *offset, &value, sizeof(type)); \
2124 *offset += sizeof(type); \
2128 RB_IO_BUFFER_DATA_TYPE_##name##_SIZE = sizeof(type) \
2136IO_BUFFER_DECLARE_TYPE(s16, int16_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap16)
2137IO_BUFFER_DECLARE_TYPE(S16, int16_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap16)
2141IO_BUFFER_DECLARE_TYPE(s32, int32_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap32)
2142IO_BUFFER_DECLARE_TYPE(S32, int32_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap32)
2144IO_BUFFER_DECLARE_TYPE(u64, uint64_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_ULL2NUM,
RB_NUM2ULL, ruby_swap64)
2145IO_BUFFER_DECLARE_TYPE(U64, uint64_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_ULL2NUM,
RB_NUM2ULL, ruby_swap64)
2146IO_BUFFER_DECLARE_TYPE(s64, int64_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_LL2NUM,
RB_NUM2LL, ruby_swap64)
2147IO_BUFFER_DECLARE_TYPE(S64, int64_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_LL2NUM,
RB_NUM2LL, ruby_swap64)
2149IO_BUFFER_DECLARE_TYPE(u128,
rb_uint128_t, RB_IO_BUFFER_LITTLE_ENDIAN, rb_uint128_to_numeric, rb_numeric_to_uint128, ruby_swap128_uint)
2150IO_BUFFER_DECLARE_TYPE(U128,
rb_uint128_t, RB_IO_BUFFER_BIG_ENDIAN, rb_uint128_to_numeric, rb_numeric_to_uint128, ruby_swap128_uint)
2151IO_BUFFER_DECLARE_TYPE(s128,
rb_int128_t, RB_IO_BUFFER_LITTLE_ENDIAN, rb_int128_to_numeric, rb_numeric_to_int128, ruby_swap128_int)
2152IO_BUFFER_DECLARE_TYPE(S128,
rb_int128_t, RB_IO_BUFFER_BIG_ENDIAN, rb_int128_to_numeric, rb_numeric_to_int128, ruby_swap128_int)
2154IO_BUFFER_DECLARE_TYPE(f32,
float, RB_IO_BUFFER_LITTLE_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf32)
2155IO_BUFFER_DECLARE_TYPE(F32,
float, RB_IO_BUFFER_BIG_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf32)
2156IO_BUFFER_DECLARE_TYPE(f64,
double, RB_IO_BUFFER_LITTLE_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf64)
2157IO_BUFFER_DECLARE_TYPE(F64,
double, RB_IO_BUFFER_BIG_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf64)
2158#undef IO_BUFFER_DECLARE_TYPE
2161io_buffer_buffer_type_size(
ID buffer_type)
2163#define IO_BUFFER_DATA_TYPE_SIZE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) return RB_IO_BUFFER_DATA_TYPE_##name##_SIZE;
2164 IO_BUFFER_DATA_TYPE_SIZE(U8)
2165 IO_BUFFER_DATA_TYPE_SIZE(S8)
2166 IO_BUFFER_DATA_TYPE_SIZE(u16)
2167 IO_BUFFER_DATA_TYPE_SIZE(U16)
2168 IO_BUFFER_DATA_TYPE_SIZE(s16)
2169 IO_BUFFER_DATA_TYPE_SIZE(S16)
2170 IO_BUFFER_DATA_TYPE_SIZE(u32)
2171 IO_BUFFER_DATA_TYPE_SIZE(U32)
2172 IO_BUFFER_DATA_TYPE_SIZE(s32)
2173 IO_BUFFER_DATA_TYPE_SIZE(S32)
2174 IO_BUFFER_DATA_TYPE_SIZE(u64)
2175 IO_BUFFER_DATA_TYPE_SIZE(U64)
2176 IO_BUFFER_DATA_TYPE_SIZE(s64)
2177 IO_BUFFER_DATA_TYPE_SIZE(S64)
2178 IO_BUFFER_DATA_TYPE_SIZE(u128)
2179 IO_BUFFER_DATA_TYPE_SIZE(U128)
2180 IO_BUFFER_DATA_TYPE_SIZE(s128)
2181 IO_BUFFER_DATA_TYPE_SIZE(S128)
2182 IO_BUFFER_DATA_TYPE_SIZE(f32)
2183 IO_BUFFER_DATA_TYPE_SIZE(F32)
2184 IO_BUFFER_DATA_TYPE_SIZE(f64)
2185 IO_BUFFER_DATA_TYPE_SIZE(F64)
2186#undef IO_BUFFER_DATA_TYPE_SIZE
2188 rb_raise(rb_eArgError,
"Invalid type name!");
2192io_buffer_type_id(
VALUE name)
2198#define TYPE_ID(name) io_buffer_type_id(name)
2211io_buffer_size_of(
VALUE klass,
VALUE buffer_type)
2215 for (
long i = 0; i <
RARRAY_LEN(buffer_type); i++) {
2216 total += io_buffer_buffer_type_size(TYPE_ID(
RARRAY_AREF(buffer_type, i)));
2221 return SIZET2NUM(io_buffer_buffer_type_size(TYPE_ID(buffer_type)));
2226rb_io_buffer_get_value(
const void* base,
size_t size,
ID buffer_type,
size_t *offset)
2228#define IO_BUFFER_GET_VALUE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) return io_buffer_read_##name(base, size, offset);
2229 IO_BUFFER_GET_VALUE(U8)
2230 IO_BUFFER_GET_VALUE(S8)
2232 IO_BUFFER_GET_VALUE(u16)
2233 IO_BUFFER_GET_VALUE(U16)
2234 IO_BUFFER_GET_VALUE(s16)
2235 IO_BUFFER_GET_VALUE(S16)
2237 IO_BUFFER_GET_VALUE(u32)
2238 IO_BUFFER_GET_VALUE(U32)
2239 IO_BUFFER_GET_VALUE(s32)
2240 IO_BUFFER_GET_VALUE(S32)
2242 IO_BUFFER_GET_VALUE(u64)
2243 IO_BUFFER_GET_VALUE(U64)
2244 IO_BUFFER_GET_VALUE(s64)
2245 IO_BUFFER_GET_VALUE(S64)
2247 IO_BUFFER_GET_VALUE(u128)
2248 IO_BUFFER_GET_VALUE(U128)
2249 IO_BUFFER_GET_VALUE(s128)
2250 IO_BUFFER_GET_VALUE(S128)
2252 IO_BUFFER_GET_VALUE(f32)
2253 IO_BUFFER_GET_VALUE(F32)
2254 IO_BUFFER_GET_VALUE(f64)
2255 IO_BUFFER_GET_VALUE(F64)
2256#undef IO_BUFFER_GET_VALUE
2258 rb_raise(rb_eArgError,
"Invalid type name!");
2304 size_t offset = io_buffer_extract_offset(_offset);
2306 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2308 return rb_io_buffer_get_value(base, size, TYPE_ID(
type), &offset);
2324 size_t offset = io_buffer_extract_offset(_offset);
2328 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2331 rb_raise(rb_eArgError,
"Argument buffer_types should be an array!");
2336 for (
long i = 0; i <
RARRAY_LEN(buffer_types); i++) {
2338 VALUE value = rb_io_buffer_get_value(base, size, TYPE_ID(
type), &offset);
2348io_buffer_extract_count(
VALUE argument)
2350 if (rb_int_negative_p(argument)) {
2351 rb_raise(rb_eArgError,
"Count can't be negative!");
2358io_buffer_extract_offset_count(
ID buffer_type,
size_t size,
int argc,
VALUE *argv,
size_t *offset,
size_t *count)
2361 *offset = io_buffer_extract_offset(argv[0]);
2368 *count = io_buffer_extract_count(argv[1]);
2371 if (*offset > size) {
2372 rb_raise(rb_eArgError,
"The given offset is bigger than the buffer size!");
2375 *count = (size - *offset) / io_buffer_buffer_type_size(buffer_type);
2396io_buffer_each(
int argc,
VALUE *argv,
VALUE self)
2403 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2407 buffer_type = TYPE_ID(argv[0]);
2410 buffer_type = RB_IO_BUFFER_DATA_TYPE_U8;
2413 size_t offset, count;
2414 io_buffer_extract_offset_count(buffer_type, size, argc-1, argv+1, &offset, &count);
2416 for (
size_t i = 0; i < count; i++) {
2417 size_t current_offset = offset;
2418 VALUE value = rb_io_buffer_get_value(base, size, buffer_type, &offset);
2436io_buffer_values(
int argc,
VALUE *argv,
VALUE self)
2441 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2445 buffer_type = TYPE_ID(argv[0]);
2448 buffer_type = RB_IO_BUFFER_DATA_TYPE_U8;
2451 size_t offset, count;
2452 io_buffer_extract_offset_count(buffer_type, size, argc-1, argv+1, &offset, &count);
2456 for (
size_t i = 0; i < count; i++) {
2457 VALUE value = rb_io_buffer_get_value(base, size, buffer_type, &offset);
2480io_buffer_each_byte(
int argc,
VALUE *argv,
VALUE self)
2487 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2489 size_t offset, count;
2490 io_buffer_extract_offset_count(RB_IO_BUFFER_DATA_TYPE_U8, size, argc, argv, &offset, &count);
2492 if (size_sum_is_bigger_than(offset, count, size)) {
2493 rb_raise(rb_eArgError,
"Specified offset+count is bigger than the buffer size!");
2496 for (
size_t i = 0; i < count; i++) {
2497 unsigned char *value = (
unsigned char *)base + i + offset;
2507 ID type = TYPE_ID(buffer_type);
2508#define IO_BUFFER_SET_VALUE(name) if (type == RB_IO_BUFFER_DATA_TYPE_##name) {io_buffer_write_##name(buffer, offset, value); return;}
2509 IO_BUFFER_SET_VALUE(U8);
2510 IO_BUFFER_SET_VALUE(S8);
2512 IO_BUFFER_SET_VALUE(u16);
2513 IO_BUFFER_SET_VALUE(U16);
2514 IO_BUFFER_SET_VALUE(s16);
2515 IO_BUFFER_SET_VALUE(S16);
2517 IO_BUFFER_SET_VALUE(u32);
2518 IO_BUFFER_SET_VALUE(U32);
2519 IO_BUFFER_SET_VALUE(s32);
2520 IO_BUFFER_SET_VALUE(S32);
2522 IO_BUFFER_SET_VALUE(u64);
2523 IO_BUFFER_SET_VALUE(U64);
2524 IO_BUFFER_SET_VALUE(s64);
2525 IO_BUFFER_SET_VALUE(S64);
2527 IO_BUFFER_SET_VALUE(u128);
2528 IO_BUFFER_SET_VALUE(U128);
2529 IO_BUFFER_SET_VALUE(s128);
2530 IO_BUFFER_SET_VALUE(S128);
2532 IO_BUFFER_SET_VALUE(f32);
2533 IO_BUFFER_SET_VALUE(F32);
2534 IO_BUFFER_SET_VALUE(f64);
2535 IO_BUFFER_SET_VALUE(F64);
2536#undef IO_BUFFER_SET_VALUE
2538 rb_raise(rb_eArgError,
"Invalid type name!");
2581 struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);
2582 size_t offset = io_buffer_extract_offset(_offset);
2583 rb_io_buffer_set_value(buffer,
type, &offset, value);
2606 struct rb_io_buffer *buffer = get_io_buffer_for_writing(self);
2609 rb_raise(rb_eArgError,
"Argument buffer_types should be an array!");
2612 size_t offset = io_buffer_extract_offset(_offset);
2615 rb_raise(rb_eArgError,
"Argument values should be an array!");
2619 rb_raise(rb_eArgError,
"Argument buffer_types and values should have the same length!");
2622 for (
long i = 0; i <
RARRAY_LEN(buffer_types); i++) {
2625 rb_io_buffer_set_value(buffer,
type, &offset, value);
2631static size_t IO_BUFFER_BLOCKING_SIZE = 1024*1024;
2634 unsigned char * destination;
2635 const unsigned char * source;
2640io_buffer_memmove_blocking(
void *data)
2644 memmove(arguments->destination, arguments->source, arguments->length);
2650io_buffer_memmove_unblock(
void *data)
2656io_buffer_memmove(
struct rb_io_buffer *buffer,
size_t offset,
const void *source_base,
size_t source_offset,
size_t source_size,
size_t length)
2660 io_buffer_get_bytes_for_writing(buffer, &base, &size);
2662 io_buffer_validate_range(buffer, offset, length);
2664 if (size_sum_is_bigger_than(source_offset, length, source_size)) {
2665 rb_raise(rb_eArgError,
"The computed source range exceeds the size of the source buffer!");
2669 .destination = (
unsigned char*)base+offset,
2670 .source = (
unsigned char*)source_base+source_offset,
2674 if (arguments.length >= IO_BUFFER_BLOCKING_SIZE) {
2676 }
else if (arguments.length != 0) {
2677 memmove(arguments.destination, arguments.source, arguments.length);
2683io_buffer_copy_from(
struct rb_io_buffer *buffer,
const void *source_base,
size_t source_size,
int argc,
VALUE *argv)
2687 size_t source_offset;
2691 offset = io_buffer_extract_offset(argv[0]);
2696 source_offset = io_buffer_extract_offset(argv[2]);
2698 if (source_offset > source_size) {
2699 rb_raise(rb_eArgError,
"The given source offset is bigger than the source itself!");
2707 if (argc >= 2 && !
RB_NIL_P(argv[1])) {
2708 length = io_buffer_extract_length(argv[1]);
2712 length = source_size - source_offset;
2715 io_buffer_memmove(buffer, offset, source_base, source_offset, source_size, length);
2738rb_io_buffer_initialize_copy(
VALUE self,
VALUE source)
2742 const void *source_base;
2745 rb_io_buffer_get_bytes_for_reading(source, &source_base, &source_size);
2747 io_buffer_initialize(self, buffer, NULL, source_size, io_flags_for_size(source_size),
Qnil);
2749 VALUE result = io_buffer_copy_from(buffer, source_base, source_size, 0, NULL);
2823io_buffer_copy(
int argc,
VALUE *argv,
VALUE self)
2829 VALUE source = argv[0];
2830 const void *source_base;
2833 rb_io_buffer_get_bytes_for_reading(source, &source_base, &source_size);
2835 VALUE result = io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
2855io_buffer_get_string(
int argc,
VALUE *argv,
VALUE self)
2859 size_t offset, length;
2860 struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
2864 io_buffer_get_bytes_for_reading(buffer, &base, &size);
2868 encoding = rb_find_encoding(argv[2]);
2871 encoding = rb_ascii8bit_encoding();
2874 io_buffer_validate_range(buffer, offset, length);
2876 return rb_enc_str_new((
const char*)base + offset, length, encoding);
2903io_buffer_set_string(
int argc,
VALUE *argv,
VALUE self)
2911 const void *source_base = RSTRING_PTR(
string);
2912 size_t source_size = RSTRING_LEN(
string);
2914 VALUE result = io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
2920rb_io_buffer_clear(
VALUE self, uint8_t value,
size_t offset,
size_t length)
2926 io_buffer_get_bytes_for_writing(buffer, &base, &size);
2928 io_buffer_validate_range(buffer, offset, length);
2930 memset((
char*)base + offset, value, length);
2965io_buffer_clear(
int argc,
VALUE *argv,
VALUE self)
2974 size_t offset, length;
2975 io_buffer_extract_offset_length(self, argc-1, argv+1, &offset, &length);
2977 rb_io_buffer_clear(self, value, offset, length);
2983io_buffer_default_size(
size_t page_size)
2986 const size_t platform_agnostic_default_size = 64*1024;
2989 const char *default_size = getenv(
"RUBY_IO_BUFFER_DEFAULT_SIZE");
2992 int value = atoi(default_size);
3000 if (platform_agnostic_default_size < page_size) {
3004 return platform_agnostic_default_size;
3010 rb_blocking_function_t *function;
3015io_buffer_blocking_region_begin(
VALUE _argument)
3019 return rb_io_blocking_region(argument->io, argument->function, argument->data);
3023io_buffer_blocking_region_ensure(
VALUE _argument)
3027 io_buffer_unlock(argument->buffer);
3033io_buffer_blocking_region(
VALUE io,
struct rb_io_buffer *buffer, rb_blocking_function_t *function,
void *data)
3035 struct rb_io *ioptr;
3041 .function = function,
3046 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
3047 return io_buffer_blocking_region_begin((
VALUE)&argument);
3051 io_buffer_lock(buffer);
3053 return rb_ensure(io_buffer_blocking_region_begin, (
VALUE)&argument, io_buffer_blocking_region_ensure, (
VALUE)&argument);
3069io_buffer_read_internal(
void *_argument)
3075 ssize_t result = read(argument->descriptor, argument->base, argument->size);
3080 else if (result == 0) {
3086 if (total >= argument->length) {
3090 argument->base = argument->base + result;
3091 argument->size = argument->size - result;
3097rb_io_buffer_read(
VALUE self,
VALUE io,
size_t length,
size_t offset)
3102 if (scheduler !=
Qnil) {
3105 if (!UNDEF_P(result)) {
3112 io_buffer_validate_range(buffer, offset, length);
3118 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3120 base = (
unsigned char*)base + offset;
3121 size = size - offset;
3124 .descriptor = descriptor,
3130 return io_buffer_blocking_region(io, buffer, io_buffer_read_internal, &argument);
3160io_buffer_read(
int argc,
VALUE *argv,
VALUE self)
3166 size_t length, offset;
3167 io_buffer_extract_length_offset(self, argc-1, argv+1, &length, &offset);
3169 return rb_io_buffer_read(self, io, length, offset);
3186io_buffer_pread_internal(
void *_argument)
3192 ssize_t result = pread(argument->descriptor, argument->base, argument->size, argument->offset);
3197 else if (result == 0) {
3203 if (total >= argument->length) {
3207 argument->base = argument->base + result;
3208 argument->size = argument->size - result;
3209 argument->offset = argument->offset + result;
3215rb_io_buffer_pread(
VALUE self,
VALUE io, rb_off_t from,
size_t length,
size_t offset)
3220 if (scheduler !=
Qnil) {
3223 if (!UNDEF_P(result)) {
3230 io_buffer_validate_range(buffer, offset, length);
3236 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3238 base = (
unsigned char*)base + offset;
3239 size = size - offset;
3242 .descriptor = descriptor,
3249 return io_buffer_blocking_region(io, buffer, io_buffer_pread_internal, &argument);
3283io_buffer_pread(
int argc,
VALUE *argv,
VALUE self)
3290 size_t length, offset;
3291 io_buffer_extract_length_offset(self, argc-2, argv+2, &length, &offset);
3293 return rb_io_buffer_pread(self, io, from, length, offset);
3308io_buffer_write_internal(
void *_argument)
3314 ssize_t result = write(argument->descriptor, argument->base, argument->size);
3319 else if (result == 0) {
3325 if (total >= argument->length) {
3329 argument->base = argument->base + result;
3330 argument->size = argument->size - result;
3336rb_io_buffer_write(
VALUE self,
VALUE io,
size_t length,
size_t offset)
3341 if (scheduler !=
Qnil) {
3344 if (!UNDEF_P(result)) {
3351 io_buffer_validate_range(buffer, offset, length);
3357 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3359 base = (
unsigned char*)base + offset;
3360 size = size - offset;
3363 .descriptor = descriptor,
3369 return io_buffer_blocking_region(io, buffer, io_buffer_write_internal, &argument);
3392io_buffer_write(
int argc,
VALUE *argv,
VALUE self)
3398 size_t length, offset;
3399 io_buffer_extract_length_offset(self, argc-1, argv+1, &length, &offset);
3401 return rb_io_buffer_write(self, io, length, offset);
3418io_buffer_pwrite_internal(
void *_argument)
3424 ssize_t result = pwrite(argument->descriptor, argument->base, argument->size, argument->offset);
3429 else if (result == 0) {
3435 if (total >= argument->length) {
3439 argument->base = argument->base + result;
3440 argument->size = argument->size - result;
3441 argument->offset = argument->offset + result;
3447rb_io_buffer_pwrite(
VALUE self,
VALUE io, rb_off_t from,
size_t length,
size_t offset)
3452 if (scheduler !=
Qnil) {
3455 if (!UNDEF_P(result)) {
3462 io_buffer_validate_range(buffer, offset, length);
3468 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3470 base = (
unsigned char*)base + offset;
3471 size = size - offset;
3474 .descriptor = descriptor,
3489 return io_buffer_blocking_region(io, buffer, io_buffer_pwrite_internal, &argument);
3517io_buffer_pwrite(
int argc,
VALUE *argv,
VALUE self)
3524 size_t length, offset;
3525 io_buffer_extract_length_offset(self, argc-2, argv+2, &length, &offset);
3527 return rb_io_buffer_pwrite(self, io, from, length, offset);
3531io_buffer_check_mask_size(
size_t size)
3534 rb_raise(rb_eIOBufferMaskError,
"Zero-length mask given!");
3538memory_and(
unsigned char * restrict output,
const unsigned char * restrict base,
size_t size,
const unsigned char * restrict mask,
size_t mask_size)
3540 for (
size_t offset = 0; offset < size; offset += 1) {
3541 output[offset] = base[offset] & mask[offset % mask_size];
3562 struct rb_io_buffer *mask_buffer = get_io_buffer(mask);
3566 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3568 const void *mask_base;
3570 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
3572 io_buffer_check_mask_size(mask_size);
3574 VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
3575 struct rb_io_buffer *output_buffer = get_io_buffer(output);
3577 memory_and(output_buffer->base, base, size, mask_base, mask_size);
3583memory_or(
unsigned char * restrict output,
const unsigned char * restrict base,
size_t size,
const unsigned char * restrict mask,
size_t mask_size)
3585 for (
size_t offset = 0; offset < size; offset += 1) {
3586 output[offset] = base[offset] | mask[offset % mask_size];
3607 struct rb_io_buffer *mask_buffer = get_io_buffer(mask);
3611 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3613 const void *mask_base;
3615 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
3617 io_buffer_check_mask_size(mask_size);
3619 VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
3620 struct rb_io_buffer *output_buffer = get_io_buffer(output);
3622 memory_or(output_buffer->base, base, size, mask_base, mask_size);
3628memory_xor(
unsigned char * restrict output,
const unsigned char * restrict base,
size_t size,
const unsigned char * restrict mask,
size_t mask_size)
3630 for (
size_t offset = 0; offset < size; offset += 1) {
3631 output[offset] = base[offset] ^ mask[offset % mask_size];
3652 struct rb_io_buffer *mask_buffer = get_io_buffer(mask);
3656 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3658 const void *mask_base;
3660 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
3662 io_buffer_check_mask_size(mask_size);
3664 VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
3665 struct rb_io_buffer *output_buffer = get_io_buffer(output);
3667 memory_xor(output_buffer->base, base, size, mask_base, mask_size);
3673memory_not(
unsigned char * restrict output,
const unsigned char * restrict base,
size_t size)
3675 for (
size_t offset = 0; offset < size; offset += 1) {
3676 output[offset] = ~base[offset];
3693io_buffer_not(
VALUE self)
3699 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3701 VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
3702 struct rb_io_buffer *output_buffer = get_io_buffer(output);
3704 memory_not(output_buffer->base, base, size);
3712 if (a->base > b->base) {
3713 return io_buffer_overlaps(b, a);
3716 return (b->base >= a->base) && (b->base < (
void*)((
unsigned char *)a->base + a->size));
3722 if (io_buffer_overlaps(a, b))
3723 rb_raise(rb_eIOBufferMaskError,
"Mask overlaps source buffer!");
3727memory_and_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3729 for (
size_t offset = 0; offset < size; offset += 1) {
3730 base[offset] &= mask[offset % mask_size];
3756 struct rb_io_buffer *mask_buffer = get_io_buffer(mask);
3758 io_buffer_check_mask_size(mask_buffer->size);
3759 io_buffer_check_overlaps(buffer, mask_buffer);
3763 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3765 const void *mask_base;
3767 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
3769 memory_and_inplace(base, size, mask_buffer->base, mask_buffer->size);
3775memory_or_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3777 for (
size_t offset = 0; offset < size; offset += 1) {
3778 base[offset] |= mask[offset % mask_size];
3804 struct rb_io_buffer *mask_buffer = get_io_buffer(mask);
3806 io_buffer_check_mask_size(mask_buffer->size);
3807 io_buffer_check_overlaps(buffer, mask_buffer);
3811 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3813 const void *mask_base;
3815 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
3817 memory_or_inplace(base, size, mask_buffer->base, mask_buffer->size);
3823memory_xor_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3825 for (
size_t offset = 0; offset < size; offset += 1) {
3826 base[offset] ^= mask[offset % mask_size];
3852 struct rb_io_buffer *mask_buffer = get_io_buffer(mask);
3854 io_buffer_check_mask_size(mask_buffer->size);
3855 io_buffer_check_overlaps(buffer, mask_buffer);
3859 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3861 const void *mask_base;
3863 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
3865 memory_xor_inplace(base, size, mask_buffer->base, mask_buffer->size);
3871memory_not_inplace(
unsigned char * restrict base,
size_t size)
3873 for (
size_t offset = 0; offset < size; offset += 1) {
3874 base[offset] = ~base[offset];
3896io_buffer_not_inplace(
VALUE self)
3902 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3904 memory_not_inplace(base, size);
3910memory_bit_count(
const unsigned char *base,
size_t size)
3915 const uint64_t *base64 = (
const uint64_t *)base;
3916 size_t count64 = size / 8;
3917 for (
size_t i = 0; i < count64; i += 1) {
3918 count += rb_popcount64(base64[i]);
3922 size_t remaining = size % 8;
3923 const unsigned char *tail = base + (count64 * 8);
3924 for (
size_t i = 0; i < remaining; i += 1) {
3925 count += rb_popcount32(tail[i]);
3945io_buffer_bit_count(
int argc,
VALUE *argv,
VALUE self)
3949 size_t offset, length;
3950 struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
3952 io_buffer_validate_range(buffer, offset, length);
3956 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3958 size_t count = memory_bit_count((
const unsigned char *)base + offset, length);
4056 rb_eIOBufferLockedError = rb_define_class_under(rb_cIOBuffer,
"LockedError",
rb_eRuntimeError);
4059 rb_eIOBufferAllocationError = rb_define_class_under(rb_cIOBuffer,
"AllocationError",
rb_eRuntimeError);
4062 rb_eIOBufferAccessError = rb_define_class_under(rb_cIOBuffer,
"AccessError",
rb_eRuntimeError);
4065 rb_eIOBufferInvalidatedError = rb_define_class_under(rb_cIOBuffer,
"InvalidatedError",
rb_eRuntimeError);
4068 rb_eIOBufferMaskError = rb_define_class_under(rb_cIOBuffer,
"MaskError", rb_eArgError);
4076 GetSystemInfo(&info);
4077 RUBY_IO_BUFFER_PAGE_SIZE = info.dwPageSize;
4079 RUBY_IO_BUFFER_PAGE_SIZE = sysconf(_SC_PAGESIZE);
4082 RUBY_IO_BUFFER_DEFAULT_SIZE = io_buffer_default_size(RUBY_IO_BUFFER_PAGE_SIZE);
4085 rb_define_const(rb_cIOBuffer,
"PAGE_SIZE",
SIZET2NUM(RUBY_IO_BUFFER_PAGE_SIZE));
4090 rb_define_const(rb_cIOBuffer,
"DEFAULT_SIZE",
SIZET2NUM(RUBY_IO_BUFFER_DEFAULT_SIZE));
4095 rb_define_method(rb_cIOBuffer,
"initialize_copy", rb_io_buffer_initialize_copy, 1);
4105 rb_define_const(rb_cIOBuffer,
"EXTERNAL",
RB_INT2NUM(RB_IO_BUFFER_EXTERNAL));
4108 rb_define_const(rb_cIOBuffer,
"INTERNAL",
RB_INT2NUM(RB_IO_BUFFER_INTERNAL));
4111 rb_define_const(rb_cIOBuffer,
"MAPPED",
RB_INT2NUM(RB_IO_BUFFER_MAPPED));
4114 rb_define_const(rb_cIOBuffer,
"SHARED",
RB_INT2NUM(RB_IO_BUFFER_SHARED));
4117 rb_define_const(rb_cIOBuffer,
"LOCKED",
RB_INT2NUM(RB_IO_BUFFER_LOCKED));
4120 rb_define_const(rb_cIOBuffer,
"PRIVATE",
RB_INT2NUM(RB_IO_BUFFER_PRIVATE));
4123 rb_define_const(rb_cIOBuffer,
"READONLY",
RB_INT2NUM(RB_IO_BUFFER_READONLY));
4126 rb_define_const(rb_cIOBuffer,
"LITTLE_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_LITTLE_ENDIAN));
4129 rb_define_const(rb_cIOBuffer,
"BIG_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_BIG_ENDIAN));
4132 rb_define_const(rb_cIOBuffer,
"HOST_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_HOST_ENDIAN));
4135 rb_define_const(rb_cIOBuffer,
"NETWORK_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_NETWORK_ENDIAN));
4161#define IO_BUFFER_DEFINE_DATA_TYPE(name) RB_IO_BUFFER_DATA_TYPE_##name = rb_intern_const(#name)
4162 IO_BUFFER_DEFINE_DATA_TYPE(U8);
4163 IO_BUFFER_DEFINE_DATA_TYPE(S8);
4165 IO_BUFFER_DEFINE_DATA_TYPE(u16);
4166 IO_BUFFER_DEFINE_DATA_TYPE(U16);
4167 IO_BUFFER_DEFINE_DATA_TYPE(s16);
4168 IO_BUFFER_DEFINE_DATA_TYPE(S16);
4170 IO_BUFFER_DEFINE_DATA_TYPE(u32);
4171 IO_BUFFER_DEFINE_DATA_TYPE(U32);
4172 IO_BUFFER_DEFINE_DATA_TYPE(s32);
4173 IO_BUFFER_DEFINE_DATA_TYPE(S32);
4175 IO_BUFFER_DEFINE_DATA_TYPE(u64);
4176 IO_BUFFER_DEFINE_DATA_TYPE(U64);
4177 IO_BUFFER_DEFINE_DATA_TYPE(s64);
4178 IO_BUFFER_DEFINE_DATA_TYPE(S64);
4180 IO_BUFFER_DEFINE_DATA_TYPE(u128);
4181 IO_BUFFER_DEFINE_DATA_TYPE(U128);
4182 IO_BUFFER_DEFINE_DATA_TYPE(s128);
4183 IO_BUFFER_DEFINE_DATA_TYPE(S128);
4185 IO_BUFFER_DEFINE_DATA_TYPE(f32);
4186 IO_BUFFER_DEFINE_DATA_TYPE(F32);
4187 IO_BUFFER_DEFINE_DATA_TYPE(f64);
4188 IO_BUFFER_DEFINE_DATA_TYPE(F64);
4189#undef IO_BUFFER_DEFINE_DATA_TYPE
#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 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 NUM2DBL
Old name of rb_num2dbl.
#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_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.
VALUE type(ANYARGS)
ANYARGS-ed function type.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#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.
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_pwrite(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset)
Non-blocking write to the passed IO at the specified offset.
VALUE rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset)
Non-blocking read from the passed IO.
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 length, size_t offset)
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 length, size_t offset)
Non-blocking write to the passed IO.
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.
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.