14#include "internal/array.h"
15#include "internal/bits.h"
16#include "internal/error.h"
17#include "internal/numeric.h"
18#include "internal/string.h"
19#include "internal/thread.h"
22VALUE rb_eIOBufferLockedError;
23VALUE rb_eIOBufferAllocationError;
24VALUE rb_eIOBufferAccessError;
25VALUE rb_eIOBufferInvalidatedError;
26VALUE rb_eIOBufferMaskError;
28size_t RUBY_IO_BUFFER_PAGE_SIZE;
29size_t RUBY_IO_BUFFER_DEFAULT_SIZE;
38 RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH = 16,
40 RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE = 256,
41 RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH = 16,
44 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,
46 RB_IO_BUFFER_DEBUG = 0,
52 enum rb_io_buffer_flags flags;
62io_buffer_map_memory(
size_t size,
int flags)
65 void * base = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
68 rb_sys_fail(
"io_buffer_map_memory:VirtualAlloc");
71 int mmap_flags = MAP_ANONYMOUS;
72 if (flags & RB_IO_BUFFER_SHARED) {
73 mmap_flags |= MAP_SHARED;
76 mmap_flags |= MAP_PRIVATE;
79 void * base = mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
81 if (base == MAP_FAILED) {
82 rb_sys_fail(
"io_buffer_map_memory:mmap");
90io_buffer_map_file(
struct rb_io_buffer *buffer,
int descriptor,
size_t size, rb_off_t offset,
enum rb_io_buffer_flags flags)
93 HANDLE file = (HANDLE)_get_osfhandle(descriptor);
94 if (!file) rb_sys_fail(
"io_buffer_map_descriptor:_get_osfhandle");
96 DWORD protect = PAGE_READONLY, access = FILE_MAP_READ;
98 if (flags & RB_IO_BUFFER_READONLY) {
99 buffer->flags |= RB_IO_BUFFER_READONLY;
102 protect = PAGE_READWRITE;
103 access = FILE_MAP_WRITE;
106 if (flags & RB_IO_BUFFER_PRIVATE) {
107 protect = PAGE_WRITECOPY;
108 access = FILE_MAP_COPY;
109 buffer->flags |= RB_IO_BUFFER_PRIVATE;
113 buffer->flags |= RB_IO_BUFFER_EXTERNAL;
114 buffer->flags |= RB_IO_BUFFER_SHARED;
117 HANDLE mapping = CreateFileMapping(file, NULL, protect, 0, 0, NULL);
118 if (RB_IO_BUFFER_DEBUG) fprintf(stderr,
"io_buffer_map_file:CreateFileMapping -> %p\n", mapping);
119 if (!mapping) rb_sys_fail(
"io_buffer_map_descriptor:CreateFileMapping");
121 void *base = MapViewOfFile(mapping, access, (DWORD)(offset >> 32), (DWORD)(offset & 0xFFFFFFFF), size);
124 CloseHandle(mapping);
125 rb_sys_fail(
"io_buffer_map_file:MapViewOfFile");
128 buffer->mapping = mapping;
130 int protect = PROT_READ, access = 0;
132 if (flags & RB_IO_BUFFER_READONLY) {
133 buffer->flags |= RB_IO_BUFFER_READONLY;
136 protect |= PROT_WRITE;
139 if (flags & RB_IO_BUFFER_PRIVATE) {
140 buffer->flags |= RB_IO_BUFFER_PRIVATE;
141 access |= MAP_PRIVATE;
145 buffer->flags |= RB_IO_BUFFER_EXTERNAL;
146 buffer->flags |= RB_IO_BUFFER_SHARED;
147 access |= MAP_SHARED;
150 void *base = mmap(NULL, size, protect, access, descriptor, offset);
152 if (base == MAP_FAILED) {
153 rb_sys_fail(
"io_buffer_map_file:mmap");
160 buffer->flags |= RB_IO_BUFFER_MAPPED;
161 buffer->flags |= RB_IO_BUFFER_FILE;
165io_buffer_experimental(
void)
167 static int warned = 0;
175 "IO::Buffer is experimental and both the Ruby and C interface may change in the future!"
186 buffer->mapping = NULL;
188 buffer->source =
Qnil;
192io_buffer_initialize(
VALUE self,
struct rb_io_buffer *buffer,
void *base,
size_t size,
enum rb_io_buffer_flags flags,
VALUE source)
199 if (flags & RB_IO_BUFFER_INTERNAL) {
200 base = calloc(size, 1);
202 else if (flags & RB_IO_BUFFER_MAPPED) {
203 base = io_buffer_map_memory(size, flags);
207 rb_raise(rb_eIOBufferAllocationError,
"Could not allocate buffer!");
217 buffer->flags = flags;
221 buffer->mapping = NULL;
229 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
233 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
235 if (buffer->flags & RB_IO_BUFFER_FILE) {
236 UnmapViewOfFile(buffer->base);
239 VirtualFree(buffer->base, 0, MEM_RELEASE);
242 munmap(buffer->base, buffer->size);
256 buffer->source =
Qnil;
260 if (buffer->mapping) {
261 if (RB_IO_BUFFER_DEBUG) fprintf(stderr,
"io_buffer_free:CloseHandle -> %p\n", buffer->mapping);
262 if (!CloseHandle(buffer->mapping)) {
263 fprintf(stderr,
"io_buffer_free:GetLastError -> %d\n", GetLastError());
265 buffer->mapping = NULL;
271rb_io_buffer_type_mark(
void *_buffer)
274 rb_gc_mark(buffer->source);
278rb_io_buffer_type_free(
void *_buffer)
282 io_buffer_free(buffer);
286rb_io_buffer_type_size(
const void *_buffer)
292 total += buffer->size;
299 .wrap_struct_name =
"IO::Buffer",
301 .dmark = rb_io_buffer_type_mark,
302 .dfree = rb_io_buffer_type_free,
303 .dsize = rb_io_buffer_type_size,
306 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
309static inline enum rb_io_buffer_flags
310io_buffer_extract_flags(
VALUE argument)
312 if (rb_int_negative_p(argument)) {
313 rb_raise(rb_eArgError,
"Flags can't be negative!");
316 enum rb_io_buffer_flags flags =
RB_NUM2UINT(argument);
319 return flags & RB_IO_BUFFER_FLAGS_MASK;
324io_buffer_extract_offset(
VALUE argument)
326 if (rb_int_negative_p(argument)) {
327 rb_raise(rb_eArgError,
"Offset can't be negative!");
337io_buffer_extract_length(
VALUE argument)
339 if (rb_int_negative_p(argument)) {
340 rb_raise(rb_eArgError,
"Length can't be negative!");
349io_buffer_extract_size(
VALUE argument)
351 if (rb_int_negative_p(argument)) {
352 rb_raise(rb_eArgError,
"Size can't be negative!");
361io_buffer_extract_width(
VALUE argument,
size_t minimum)
363 if (rb_int_negative_p(argument)) {
364 rb_raise(rb_eArgError,
"Width can't be negative!");
369 if (width < minimum) {
370 rb_raise(rb_eArgError,
"Width must be at least %" PRIuSIZE
"!", minimum);
381io_buffer_default_length(
const struct rb_io_buffer *buffer,
size_t offset)
383 if (offset > buffer->size) {
384 rb_raise(rb_eArgError,
"The given offset is bigger than the buffer size!");
388 return buffer->size - offset;
397io_buffer_extract_length_offset(
VALUE self,
int argc,
VALUE argv[],
size_t *length,
size_t *offset)
402 if (argc >= 2 && !
NIL_P(argv[1])) {
403 *offset = io_buffer_extract_offset(argv[1]);
409 if (argc >= 1 && !
NIL_P(argv[0])) {
410 *length = io_buffer_extract_length(argv[0]);
413 *length = io_buffer_default_length(buffer, *offset);
429io_buffer_extract_offset_length(
VALUE self,
int argc,
VALUE argv[],
size_t *offset,
size_t *length)
434 if (argc >= 1 && !
NIL_P(argv[0])) {
435 *offset = io_buffer_extract_offset(argv[0]);
441 if (argc >= 2 && !
NIL_P(argv[1])) {
442 *length = io_buffer_extract_length(argv[1]);
445 *length = io_buffer_default_length(buffer, *offset);
452rb_io_buffer_type_allocate(
VALUE self)
457 io_buffer_zero(buffer);
462static VALUE io_buffer_for_make_instance(
VALUE klass,
VALUE string,
enum rb_io_buffer_flags flags)
464 VALUE instance = rb_io_buffer_type_allocate(klass);
469 flags |= RB_IO_BUFFER_EXTERNAL;
471 if (RB_OBJ_FROZEN(
string))
472 flags |= RB_IO_BUFFER_READONLY;
474 if (!(flags & RB_IO_BUFFER_READONLY))
475 rb_str_modify(
string);
477 io_buffer_initialize(instance, buffer, RSTRING_PTR(
string), RSTRING_LEN(
string), flags,
string);
486 enum rb_io_buffer_flags flags;
490io_buffer_for_yield_instance(
VALUE _arguments)
494 arguments->instance = io_buffer_for_make_instance(arguments->klass, arguments->string, arguments->flags);
498 return rb_yield(arguments->instance);
502io_buffer_for_yield_instance_ensure(
VALUE _arguments)
506 if (arguments->instance !=
Qnil) {
507 rb_io_buffer_free(arguments->instance);
552rb_io_buffer_type_for(
VALUE klass,
VALUE string)
566 return rb_ensure(io_buffer_for_yield_instance, (
VALUE)&arguments, io_buffer_for_yield_instance_ensure, (
VALUE)&arguments);
570 string = rb_str_tmp_frozen_acquire(
string);
571 return io_buffer_for_make_instance(klass,
string, RB_IO_BUFFER_READONLY);
589rb_io_buffer_type_string(
VALUE klass,
VALUE length)
599 rb_ensure(io_buffer_for_yield_instance, (
VALUE)&arguments, io_buffer_for_yield_instance_ensure, (
VALUE)&arguments);
605rb_io_buffer_new(
void *base,
size_t size,
enum rb_io_buffer_flags flags)
607 VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
612 io_buffer_initialize(instance, buffer, base, size, flags,
Qnil);
618rb_io_buffer_map(
VALUE io,
size_t size, rb_off_t offset,
enum rb_io_buffer_flags flags)
620 io_buffer_experimental();
622 VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
629 io_buffer_map_file(buffer, descriptor, size, offset, flags);
672io_buffer_map(
int argc,
VALUE *argv,
VALUE klass)
680 if (argc >= 2 && !
RB_NIL_P(argv[1])) {
681 size = io_buffer_extract_size(argv[1]);
684 rb_off_t file_size = rb_file_size(io);
688 rb_raise(rb_eArgError,
"Invalid negative file size!");
691 else if ((uintmax_t)file_size > SIZE_MAX) {
692 rb_raise(rb_eArgError,
"File larger than address space!");
696 size = (size_t)file_size;
706 enum rb_io_buffer_flags flags = 0;
708 flags = io_buffer_extract_flags(argv[3]);
711 return rb_io_buffer_map(io, size, offset, flags);
715static inline enum rb_io_buffer_flags
716io_flags_for_size(
size_t size)
718 if (size >= RUBY_IO_BUFFER_PAGE_SIZE) {
719 return RB_IO_BUFFER_MAPPED;
722 return RB_IO_BUFFER_INTERNAL;
750rb_io_buffer_initialize(
int argc,
VALUE *argv,
VALUE self)
752 io_buffer_experimental();
761 size = io_buffer_extract_size(argv[0]);
764 size = RUBY_IO_BUFFER_DEFAULT_SIZE;
767 enum rb_io_buffer_flags flags = 0;
769 flags = io_buffer_extract_flags(argv[1]);
772 flags |= io_flags_for_size(size);
775 io_buffer_initialize(self, buffer, NULL, size, flags,
Qnil);
781io_buffer_validate_slice(
VALUE source,
void *base,
size_t size)
783 void *source_base = NULL;
784 size_t source_size = 0;
790 rb_io_buffer_get_bytes(source, &source_base, &source_size);
794 if (source_base == NULL)
return 0;
797 if (base < source_base)
return 0;
799 const void *source_end = (
char*)source_base + source_size;
800 const void *end = (
char*)base + size;
803 if (end > source_end)
return 0;
812 if (buffer->source !=
Qnil) {
814 return io_buffer_validate_slice(buffer->source, buffer->base, buffer->size);
821enum rb_io_buffer_flags
822rb_io_buffer_get_bytes(
VALUE self,
void **base,
size_t *size)
827 if (io_buffer_validate(buffer)) {
829 *base = buffer->base;
830 *size = buffer->size;
832 return buffer->flags;
844io_buffer_get_bytes_for_writing(
struct rb_io_buffer *buffer,
void **base,
size_t *size)
846 if (buffer->flags & RB_IO_BUFFER_READONLY) {
847 rb_raise(rb_eIOBufferAccessError,
"Buffer is not writable!");
850 if (!io_buffer_validate(buffer)) {
851 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer is invalid!");
855 *base = buffer->base;
856 *size = buffer->size;
864rb_io_buffer_get_bytes_for_writing(
VALUE self,
void **base,
size_t *size)
869 io_buffer_get_bytes_for_writing(buffer, base, size);
873io_buffer_get_bytes_for_reading(
struct rb_io_buffer *buffer,
const void **base,
size_t *size)
875 if (!io_buffer_validate(buffer)) {
876 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer has been invalidated!");
880 *base = buffer->base;
881 *size = buffer->size;
889rb_io_buffer_get_bytes_for_reading(
VALUE self,
const void **base,
size_t *size)
894 io_buffer_get_bytes_for_reading(buffer, base, size);
907rb_io_buffer_to_s(
VALUE self)
915 rb_str_catf(result,
" %p+%"PRIdSIZE, buffer->base, buffer->size);
917 if (buffer->base == NULL) {
921 if (buffer->flags & RB_IO_BUFFER_EXTERNAL) {
925 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
929 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
933 if (buffer->flags & RB_IO_BUFFER_FILE) {
937 if (buffer->flags & RB_IO_BUFFER_SHARED) {
941 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
945 if (buffer->flags & RB_IO_BUFFER_PRIVATE) {
949 if (buffer->flags & RB_IO_BUFFER_READONLY) {
953 if (buffer->source !=
Qnil) {
957 if (!io_buffer_validate(buffer)) {
967io_buffer_hexdump_output_size(
size_t width,
size_t size,
int first)
972 size_t whole_lines = (size / width);
973 size_t partial_line = (size % width) ? 1 : 0;
978 total += (whole_lines + partial_line) * (1 + 10 + width*3 + 1 + 1);
981 if (size && first) total -= 1;
990io_buffer_hexdump(
VALUE string,
size_t width,
const char *base,
size_t length,
size_t offset,
int first)
992 char *text = alloca(width+1);
995 for (; offset < length; offset += width) {
996 memset(text,
'\0', width);
998 rb_str_catf(
string,
"0x%08" PRIxSIZE
" ", offset);
1002 rb_str_catf(
string,
"\n0x%08" PRIxSIZE
" ", offset);
1005 for (
size_t i = 0; i < width; i += 1) {
1006 if (offset+i < length) {
1007 unsigned char value = ((
unsigned char*)base)[offset+i];
1009 if (value < 127 && isprint(value)) {
1010 text[i] = (char)value;
1016 rb_str_catf(
string,
" %02x", value);
1023 rb_str_catf(
string,
" %s", text);
1042rb_io_buffer_inspect(
VALUE self)
1047 VALUE result = rb_io_buffer_to_s(self);
1049 if (io_buffer_validate(buffer)) {
1051 size_t size = buffer->size;
1054 if (size > RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE) {
1055 size = RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE;
1059 io_buffer_hexdump(result, RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH, buffer->base, size, 0, 0);
1062 rb_str_catf(result,
"\n(and %" PRIuSIZE
" more bytes not printed)", buffer->size - size);
1076rb_io_buffer_size(
VALUE self)
1093rb_io_buffer_valid_p(
VALUE self)
1098 return RBOOL(io_buffer_validate(buffer));
1116rb_io_buffer_null_p(
VALUE self)
1121 return RBOOL(buffer->base == NULL);
1132rb_io_buffer_empty_p(
VALUE self)
1137 return RBOOL(buffer->size == 0);
1152rb_io_buffer_external_p(
VALUE self)
1157 return RBOOL(buffer->flags & RB_IO_BUFFER_EXTERNAL);
1177rb_io_buffer_internal_p(
VALUE self)
1182 return RBOOL(buffer->flags & RB_IO_BUFFER_INTERNAL);
1199rb_io_buffer_mapped_p(
VALUE self)
1204 return RBOOL(buffer->flags & RB_IO_BUFFER_MAPPED);
1231rb_io_buffer_shared_p(
VALUE self)
1236 return RBOOL(buffer->flags & RB_IO_BUFFER_SHARED);
1254rb_io_buffer_locked_p(
VALUE self)
1259 return RBOOL(buffer->flags & RB_IO_BUFFER_LOCKED);
1285rb_io_buffer_private_p(
VALUE self)
1290 return RBOOL(buffer->flags & RB_IO_BUFFER_PRIVATE);
1294rb_io_buffer_readonly_p(
VALUE self)
1299 return buffer->flags & RB_IO_BUFFER_READONLY;
1311io_buffer_readonly_p(
VALUE self)
1313 return RBOOL(rb_io_buffer_readonly_p(self));
1319 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1320 rb_raise(rb_eIOBufferLockedError,
"Buffer already locked!");
1323 buffer->flags |= RB_IO_BUFFER_LOCKED;
1327rb_io_buffer_lock(
VALUE self)
1332 io_buffer_lock(buffer);
1340 if (!(buffer->flags & RB_IO_BUFFER_LOCKED)) {
1341 rb_raise(rb_eIOBufferLockedError,
"Buffer not locked!");
1344 buffer->flags &= ~RB_IO_BUFFER_LOCKED;
1348rb_io_buffer_unlock(
VALUE self)
1353 io_buffer_unlock(buffer);
1359rb_io_buffer_try_unlock(
VALUE self)
1364 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1365 buffer->flags &= ~RB_IO_BUFFER_LOCKED;
1403rb_io_buffer_locked(
VALUE self)
1408 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1409 rb_raise(rb_eIOBufferLockedError,
"Buffer already locked!");
1412 buffer->flags |= RB_IO_BUFFER_LOCKED;
1416 buffer->flags &= ~RB_IO_BUFFER_LOCKED;
1447rb_io_buffer_free(
VALUE self)
1452 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1453 rb_raise(rb_eIOBufferLockedError,
"Buffer is locked!");
1456 io_buffer_free(buffer);
1466 io_buffer_unlock(buffer);
1467 io_buffer_free(buffer);
1475io_buffer_validate_range(
struct rb_io_buffer *buffer,
size_t offset,
size_t length)
1478 if (offset + length > buffer->size) {
1479 rb_raise(rb_eArgError,
"Specified offset+length is bigger than the buffer size!");
1500rb_io_buffer_hexdump(
int argc,
VALUE *argv,
VALUE self)
1504 size_t offset, length;
1505 struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
1507 size_t width = RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH;
1509 width = io_buffer_extract_width(argv[2], 1);
1513 io_buffer_validate_range(buffer, offset, length);
1517 if (io_buffer_validate(buffer) && buffer->base) {
1518 result = rb_str_buf_new(io_buffer_hexdump_output_size(width, length, 1));
1520 io_buffer_hexdump(result, width, buffer->base, offset+length, offset, 1);
1527rb_io_buffer_slice(
struct rb_io_buffer *buffer,
VALUE self,
size_t offset,
size_t length)
1529 io_buffer_validate_range(buffer, offset, length);
1535 slice->base = (
char*)buffer->base + offset;
1536 slice->size = length;
1539 if (buffer->source !=
Qnil) {
1540 RB_OBJ_WRITE(instance, &slice->source, buffer->source);
1604io_buffer_slice(
int argc,
VALUE *argv,
VALUE self)
1608 size_t offset, length;
1609 struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
1611 return rb_io_buffer_slice(buffer, self, offset, length);
1633rb_io_buffer_transfer(
VALUE self)
1638 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1639 rb_raise(rb_eIOBufferLockedError,
"Cannot transfer ownership of locked buffer!");
1646 *transferred = *buffer;
1647 io_buffer_zero(buffer);
1653io_buffer_resize_clear(
struct rb_io_buffer *buffer,
void* base,
size_t size)
1655 if (size > buffer->size) {
1656 memset((
unsigned char*)base+buffer->size, 0, size - buffer->size);
1665 io_buffer_initialize(self, &resized, NULL, size, io_flags_for_size(size),
Qnil);
1668 size_t preserve = buffer->size;
1669 if (preserve > size) preserve = size;
1670 memcpy(resized.base, buffer->base, preserve);
1672 io_buffer_resize_clear(buffer, resized.base, size);
1675 io_buffer_free(buffer);
1680rb_io_buffer_resize(
VALUE self,
size_t size)
1685 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1686 rb_raise(rb_eIOBufferLockedError,
"Cannot resize locked buffer!");
1689 if (buffer->base == NULL) {
1690 io_buffer_initialize(self, buffer, NULL, size, io_flags_for_size(size),
Qnil);
1694 if (buffer->flags & RB_IO_BUFFER_EXTERNAL) {
1695 rb_raise(rb_eIOBufferAccessError,
"Cannot resize external buffer!");
1698#if defined(HAVE_MREMAP) && defined(MREMAP_MAYMOVE)
1699 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
1700 void *base = mremap(buffer->base, buffer->size, size, MREMAP_MAYMOVE);
1702 if (base == MAP_FAILED) {
1703 rb_sys_fail(
"rb_io_buffer_resize:mremap");
1706 io_buffer_resize_clear(buffer, base, size);
1708 buffer->base = base;
1709 buffer->size = size;
1715 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
1717 io_buffer_free(buffer);
1721 void *base = realloc(buffer->base, size);
1724 rb_sys_fail(
"rb_io_buffer_resize:realloc");
1727 io_buffer_resize_clear(buffer, base, size);
1729 buffer->base = base;
1730 buffer->size = size;
1735 io_buffer_resize_copy(self, buffer, size);
1759 rb_io_buffer_resize(self, io_buffer_extract_size(size));
1773 const void *ptr1, *ptr2;
1774 size_t size1, size2;
1776 rb_io_buffer_get_bytes_for_reading(self, &ptr1, &size1);
1777 rb_io_buffer_get_bytes_for_reading(other, &ptr2, &size2);
1779 if (size1 < size2) {
1783 if (size1 > size2) {
1787 return RB_INT2NUM(memcmp(ptr1, ptr2, size1));
1791io_buffer_validate_type(
size_t size,
size_t offset)
1793 if (offset > size) {
1794 rb_raise(rb_eArgError,
"Type extends beyond end of buffer! (offset=%"PRIdSIZE
" > size=%"PRIdSIZE
")", offset, size);
1816#define ruby_swap8(value) value
1824ruby_swapf32(
float value)
1826 union swapf32 swap = {.value = value};
1827 swap.integral = ruby_swap32(swap.integral);
1837ruby_swapf64(
double value)
1839 union swapf64 swap = {.value = value};
1840 swap.integral = ruby_swap64(swap.integral);
1844#define IO_BUFFER_DECLARE_TYPE(name, type, endian, wrap, unwrap, swap) \
1845static ID RB_IO_BUFFER_DATA_TYPE_##name; \
1848io_buffer_read_##name(const void* base, size_t size, size_t *offset) \
1850 io_buffer_validate_type(size, *offset + sizeof(type)); \
1852 memcpy(&value, (char*)base + *offset, sizeof(type)); \
1853 if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
1854 *offset += sizeof(type); \
1855 return wrap(value); \
1859io_buffer_write_##name(const void* base, size_t size, size_t *offset, VALUE _value) \
1861 io_buffer_validate_type(size, *offset + sizeof(type)); \
1862 type value = unwrap(_value); \
1863 if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
1864 memcpy((char*)base + *offset, &value, sizeof(type)); \
1865 *offset += sizeof(type); \
1869 RB_IO_BUFFER_DATA_TYPE_##name##_SIZE = sizeof(type) \
1877IO_BUFFER_DECLARE_TYPE(s16, int16_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap16)
1878IO_BUFFER_DECLARE_TYPE(S16, int16_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap16)
1882IO_BUFFER_DECLARE_TYPE(s32, int32_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap32)
1883IO_BUFFER_DECLARE_TYPE(S32, int32_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap32)
1885IO_BUFFER_DECLARE_TYPE(u64, uint64_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_ULL2NUM,
RB_NUM2ULL, ruby_swap64)
1886IO_BUFFER_DECLARE_TYPE(U64, uint64_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_ULL2NUM,
RB_NUM2ULL, ruby_swap64)
1887IO_BUFFER_DECLARE_TYPE(s64, int64_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_LL2NUM,
RB_NUM2LL, ruby_swap64)
1888IO_BUFFER_DECLARE_TYPE(S64, int64_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_LL2NUM,
RB_NUM2LL, ruby_swap64)
1890IO_BUFFER_DECLARE_TYPE(f32,
float, RB_IO_BUFFER_LITTLE_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf32)
1891IO_BUFFER_DECLARE_TYPE(F32,
float, RB_IO_BUFFER_BIG_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf32)
1892IO_BUFFER_DECLARE_TYPE(f64,
double, RB_IO_BUFFER_LITTLE_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf64)
1893IO_BUFFER_DECLARE_TYPE(F64,
double, RB_IO_BUFFER_BIG_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf64)
1894#undef IO_BUFFER_DECLARE_TYPE
1897io_buffer_buffer_type_size(
ID buffer_type)
1899#define IO_BUFFER_DATA_TYPE_SIZE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) return RB_IO_BUFFER_DATA_TYPE_##name##_SIZE;
1900 IO_BUFFER_DATA_TYPE_SIZE(U8)
1901 IO_BUFFER_DATA_TYPE_SIZE(S8)
1902 IO_BUFFER_DATA_TYPE_SIZE(u16)
1903 IO_BUFFER_DATA_TYPE_SIZE(U16)
1904 IO_BUFFER_DATA_TYPE_SIZE(s16)
1905 IO_BUFFER_DATA_TYPE_SIZE(S16)
1906 IO_BUFFER_DATA_TYPE_SIZE(u32)
1907 IO_BUFFER_DATA_TYPE_SIZE(U32)
1908 IO_BUFFER_DATA_TYPE_SIZE(s32)
1909 IO_BUFFER_DATA_TYPE_SIZE(S32)
1910 IO_BUFFER_DATA_TYPE_SIZE(u64)
1911 IO_BUFFER_DATA_TYPE_SIZE(U64)
1912 IO_BUFFER_DATA_TYPE_SIZE(s64)
1913 IO_BUFFER_DATA_TYPE_SIZE(S64)
1914 IO_BUFFER_DATA_TYPE_SIZE(f32)
1915 IO_BUFFER_DATA_TYPE_SIZE(F32)
1916 IO_BUFFER_DATA_TYPE_SIZE(f64)
1917 IO_BUFFER_DATA_TYPE_SIZE(F64)
1918#undef IO_BUFFER_DATA_TYPE_SIZE
1920 rb_raise(rb_eArgError,
"Invalid type name!");
1934io_buffer_size_of(
VALUE klass,
VALUE buffer_type)
1936 if (RB_TYPE_P(buffer_type,
T_ARRAY)) {
1938 for (
long i = 0; i <
RARRAY_LEN(buffer_type); i++) {
1949rb_io_buffer_get_value(
const void* base,
size_t size,
ID buffer_type,
size_t *offset)
1951#define IO_BUFFER_GET_VALUE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) return io_buffer_read_##name(base, size, offset);
1952 IO_BUFFER_GET_VALUE(U8)
1953 IO_BUFFER_GET_VALUE(S8)
1955 IO_BUFFER_GET_VALUE(u16)
1956 IO_BUFFER_GET_VALUE(U16)
1957 IO_BUFFER_GET_VALUE(s16)
1958 IO_BUFFER_GET_VALUE(S16)
1960 IO_BUFFER_GET_VALUE(u32)
1961 IO_BUFFER_GET_VALUE(U32)
1962 IO_BUFFER_GET_VALUE(s32)
1963 IO_BUFFER_GET_VALUE(S32)
1965 IO_BUFFER_GET_VALUE(u64)
1966 IO_BUFFER_GET_VALUE(U64)
1967 IO_BUFFER_GET_VALUE(s64)
1968 IO_BUFFER_GET_VALUE(S64)
1970 IO_BUFFER_GET_VALUE(f32)
1971 IO_BUFFER_GET_VALUE(F32)
1972 IO_BUFFER_GET_VALUE(f64)
1973 IO_BUFFER_GET_VALUE(F64)
1974#undef IO_BUFFER_GET_VALUE
1976 rb_raise(rb_eArgError,
"Invalid type name!");
2018 size_t offset = io_buffer_extract_offset(_offset);
2020 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2022 return rb_io_buffer_get_value(base, size,
RB_SYM2ID(
type), &offset);
2038 size_t offset = io_buffer_extract_offset(_offset);
2042 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2044 if (!RB_TYPE_P(buffer_types,
T_ARRAY)) {
2045 rb_raise(rb_eArgError,
"Argument buffer_types should be an array!");
2050 for (
long i = 0; i <
RARRAY_LEN(buffer_types); i++) {
2051 VALUE type = rb_ary_entry(buffer_types, i);
2053 rb_ary_push(array, value);
2062io_buffer_extract_count(
VALUE argument)
2064 if (rb_int_negative_p(argument)) {
2065 rb_raise(rb_eArgError,
"Count can't be negative!");
2072io_buffer_extract_offset_count(
ID buffer_type,
size_t size,
int argc,
VALUE *argv,
size_t *offset,
size_t *count)
2075 *offset = io_buffer_extract_offset(argv[0]);
2082 *count = io_buffer_extract_count(argv[1]);
2085 if (*offset > size) {
2086 rb_raise(rb_eArgError,
"The given offset is bigger than the buffer size!");
2089 *count = (size - *offset) / io_buffer_buffer_type_size(buffer_type);
2110io_buffer_each(
int argc,
VALUE *argv,
VALUE self)
2117 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2124 buffer_type = RB_IO_BUFFER_DATA_TYPE_U8;
2127 size_t offset, count;
2128 io_buffer_extract_offset_count(buffer_type, size, argc-1, argv+1, &offset, &count);
2130 for (
size_t i = 0; i < count; i++) {
2131 size_t current_offset = offset;
2132 VALUE value = rb_io_buffer_get_value(base, size, buffer_type, &offset);
2150io_buffer_values(
int argc,
VALUE *argv,
VALUE self)
2155 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2162 buffer_type = RB_IO_BUFFER_DATA_TYPE_U8;
2165 size_t offset, count;
2166 io_buffer_extract_offset_count(buffer_type, size, argc-1, argv+1, &offset, &count);
2168 VALUE array = rb_ary_new_capa(count);
2170 for (
size_t i = 0; i < count; i++) {
2171 VALUE value = rb_io_buffer_get_value(base, size, buffer_type, &offset);
2172 rb_ary_push(array, value);
2194io_buffer_each_byte(
int argc,
VALUE *argv,
VALUE self)
2201 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2203 size_t offset, count;
2204 io_buffer_extract_offset_count(RB_IO_BUFFER_DATA_TYPE_U8, size, argc-1, argv+1, &offset, &count);
2206 for (
size_t i = 0; i < count; i++) {
2207 unsigned char *value = (
unsigned char *)base + i + offset;
2215rb_io_buffer_set_value(
const void* base,
size_t size,
ID buffer_type,
size_t *offset,
VALUE value)
2217#define IO_BUFFER_SET_VALUE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) {io_buffer_write_##name(base, size, offset, value); return;}
2218 IO_BUFFER_SET_VALUE(U8);
2219 IO_BUFFER_SET_VALUE(S8);
2221 IO_BUFFER_SET_VALUE(u16);
2222 IO_BUFFER_SET_VALUE(U16);
2223 IO_BUFFER_SET_VALUE(s16);
2224 IO_BUFFER_SET_VALUE(S16);
2226 IO_BUFFER_SET_VALUE(u32);
2227 IO_BUFFER_SET_VALUE(U32);
2228 IO_BUFFER_SET_VALUE(s32);
2229 IO_BUFFER_SET_VALUE(S32);
2231 IO_BUFFER_SET_VALUE(u64);
2232 IO_BUFFER_SET_VALUE(U64);
2233 IO_BUFFER_SET_VALUE(s64);
2234 IO_BUFFER_SET_VALUE(S64);
2236 IO_BUFFER_SET_VALUE(f32);
2237 IO_BUFFER_SET_VALUE(F32);
2238 IO_BUFFER_SET_VALUE(f64);
2239 IO_BUFFER_SET_VALUE(F64);
2240#undef IO_BUFFER_SET_VALUE
2242 rb_raise(rb_eArgError,
"Invalid type name!");
2280 size_t offset = io_buffer_extract_offset(_offset);
2282 rb_io_buffer_get_bytes_for_writing(self, &base, &size);
2284 rb_io_buffer_set_value(base, size,
RB_SYM2ID(
type), &offset, value);
2306 if (!RB_TYPE_P(buffer_types,
T_ARRAY)) {
2307 rb_raise(rb_eArgError,
"Argument buffer_types should be an array!");
2310 if (!RB_TYPE_P(values,
T_ARRAY)) {
2311 rb_raise(rb_eArgError,
"Argument values should be an array!");
2315 rb_raise(rb_eArgError,
"Argument buffer_types and values should have the same length!");
2318 size_t offset = io_buffer_extract_offset(_offset);
2322 rb_io_buffer_get_bytes_for_writing(self, &base, &size);
2324 for (
long i = 0; i <
RARRAY_LEN(buffer_types); i++) {
2325 VALUE type = rb_ary_entry(buffer_types, i);
2326 VALUE value = rb_ary_entry(values, i);
2327 rb_io_buffer_set_value(base, size,
RB_SYM2ID(
type), &offset, value);
2334io_buffer_memcpy(
struct rb_io_buffer *buffer,
size_t offset,
const void *source_base,
size_t source_offset,
size_t source_size,
size_t length)
2338 io_buffer_get_bytes_for_writing(buffer, &base, &size);
2340 io_buffer_validate_range(buffer, offset, length);
2342 if (source_offset + length > source_size) {
2343 rb_raise(rb_eArgError,
"The computed source range exceeds the size of the source buffer!");
2346 memcpy((
unsigned char*)base+offset, (
unsigned char*)source_base+source_offset, length);
2351io_buffer_copy_from(
struct rb_io_buffer *buffer,
const void *source_base,
size_t source_size,
int argc,
VALUE *argv)
2355 size_t source_offset;
2359 offset = io_buffer_extract_offset(argv[0]);
2364 source_offset = io_buffer_extract_offset(argv[2]);
2366 if (source_offset > source_size) {
2367 rb_raise(rb_eArgError,
"The given source offset is bigger than the source itself!");
2375 if (argc >= 2 && !
RB_NIL_P(argv[1])) {
2376 length = io_buffer_extract_length(argv[1]);
2380 length = source_size - source_offset;
2383 io_buffer_memcpy(buffer, offset, source_base, source_offset, source_size, length);
2406rb_io_buffer_initialize_copy(
VALUE self,
VALUE source)
2411 const void *source_base;
2414 rb_io_buffer_get_bytes_for_reading(source, &source_base, &source_size);
2416 io_buffer_initialize(self, buffer, NULL, source_size, io_flags_for_size(source_size),
Qnil);
2418 return io_buffer_copy_from(buffer, source_base, source_size, 0, NULL);
2476io_buffer_copy(
int argc,
VALUE *argv,
VALUE self)
2483 VALUE source = argv[0];
2484 const void *source_base;
2487 rb_io_buffer_get_bytes_for_reading(source, &source_base, &source_size);
2489 return io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
2507io_buffer_get_string(
int argc,
VALUE *argv,
VALUE self)
2511 size_t offset, length;
2512 struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
2516 io_buffer_get_bytes_for_reading(buffer, &base, &size);
2520 encoding = rb_find_encoding(argv[2]);
2523 encoding = rb_ascii8bit_encoding();
2526 io_buffer_validate_range(buffer, offset, length);
2528 return rb_enc_str_new((
const char*)base + offset, length, encoding);
2555io_buffer_set_string(
int argc,
VALUE *argv,
VALUE self)
2564 const void *source_base = RSTRING_PTR(
string);
2565 size_t source_size = RSTRING_LEN(
string);
2567 return io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
2571rb_io_buffer_clear(
VALUE self, uint8_t value,
size_t offset,
size_t length)
2578 io_buffer_get_bytes_for_writing(buffer, &base, &size);
2580 io_buffer_validate_range(buffer, offset, length);
2582 memset((
char*)base + offset, value, length);
2617io_buffer_clear(
int argc,
VALUE *argv,
VALUE self)
2626 size_t offset, length;
2627 io_buffer_extract_offset_length(self, argc-1, argv+1, &offset, &length);
2629 rb_io_buffer_clear(self, value, offset, length);
2635io_buffer_default_size(
size_t page_size)
2638 const size_t platform_agnostic_default_size = 64*1024;
2641 const char *default_size = getenv(
"RUBY_IO_BUFFER_DEFAULT_SIZE");
2644 int value = atoi(default_size);
2652 if (platform_agnostic_default_size < page_size) {
2656 return platform_agnostic_default_size;
2661 rb_blocking_function_t *function;
2667io_buffer_blocking_region_begin(
VALUE _argument)
2671 return rb_thread_io_blocking_region(argument->function, argument->data, argument->descriptor);
2675io_buffer_blocking_region_ensure(
VALUE _argument)
2679 io_buffer_unlock(argument->buffer);
2685io_buffer_blocking_region(
struct rb_io_buffer *buffer, rb_blocking_function_t *function,
void *data,
int descriptor)
2689 .function = function,
2691 .descriptor = descriptor,
2695 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
2696 return io_buffer_blocking_region_begin((
VALUE)&argument);
2700 io_buffer_lock(buffer);
2702 return rb_ensure(io_buffer_blocking_region_begin, (
VALUE)&argument, io_buffer_blocking_region_ensure, (
VALUE)&argument);
2718io_buffer_read_internal(
void *_argument)
2724 ssize_t result = read(argument->descriptor, argument->base, argument->size);
2729 else if (result == 0) {
2735 if (total >= argument->length) {
2739 argument->base = argument->base + result;
2740 argument->size = argument->size - result;
2746rb_io_buffer_read(
VALUE self,
VALUE io,
size_t length,
size_t offset)
2749 if (scheduler !=
Qnil) {
2752 if (!UNDEF_P(result)) {
2760 io_buffer_validate_range(buffer, offset, length);
2766 io_buffer_get_bytes_for_writing(buffer, &base, &size);
2768 base = (
unsigned char*)base + offset;
2769 size = size - offset;
2772 .descriptor = descriptor,
2778 return io_buffer_blocking_region(buffer, io_buffer_read_internal, &argument, descriptor);
2808io_buffer_read(
int argc,
VALUE *argv,
VALUE self)
2814 size_t length, offset;
2815 io_buffer_extract_length_offset(self, argc-1, argv+1, &length, &offset);
2817 return rb_io_buffer_read(self, io, length, offset);
2834io_buffer_pread_internal(
void *_argument)
2840 ssize_t result = pread(argument->descriptor, argument->base, argument->size, argument->offset);
2845 else if (result == 0) {
2851 if (total >= argument->length) {
2855 argument->base = argument->base + result;
2856 argument->size = argument->size - result;
2857 argument->offset = argument->offset + result;
2863rb_io_buffer_pread(
VALUE self,
VALUE io, rb_off_t from,
size_t length,
size_t offset)
2866 if (scheduler !=
Qnil) {
2869 if (!UNDEF_P(result)) {
2877 io_buffer_validate_range(buffer, offset, length);
2883 io_buffer_get_bytes_for_writing(buffer, &base, &size);
2885 base = (
unsigned char*)base + offset;
2886 size = size - offset;
2889 .descriptor = descriptor,
2896 return io_buffer_blocking_region(buffer, io_buffer_pread_internal, &argument, descriptor);
2930io_buffer_pread(
int argc,
VALUE *argv,
VALUE self)
2937 size_t length, offset;
2938 io_buffer_extract_length_offset(self, argc-2, argv+2, &length, &offset);
2940 return rb_io_buffer_pread(self, io, from, length, offset);
2955io_buffer_write_internal(
void *_argument)
2961 ssize_t result = write(argument->descriptor, argument->base, argument->size);
2966 else if (result == 0) {
2972 if (total >= argument->length) {
2976 argument->base = argument->base + result;
2977 argument->size = argument->size - result;
2983rb_io_buffer_write(
VALUE self,
VALUE io,
size_t length,
size_t offset)
2986 if (scheduler !=
Qnil) {
2989 if (!UNDEF_P(result)) {
2997 io_buffer_validate_range(buffer, offset, length);
3003 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3005 base = (
unsigned char*)base + offset;
3006 size = size - offset;
3009 .descriptor = descriptor,
3015 return io_buffer_blocking_region(buffer, io_buffer_write_internal, &argument, descriptor);
3038io_buffer_write(
int argc,
VALUE *argv,
VALUE self)
3044 size_t length, offset;
3045 io_buffer_extract_length_offset(self, argc-1, argv+1, &length, &offset);
3047 return rb_io_buffer_write(self, io, length, offset);
3063io_buffer_pwrite_internal(
void *_argument)
3069 ssize_t result = pwrite(argument->descriptor, argument->base, argument->size, argument->offset);
3074 else if (result == 0) {
3080 if (total >= argument->length) {
3084 argument->base = argument->base + result;
3085 argument->size = argument->size - result;
3086 argument->offset = argument->offset + result;
3092rb_io_buffer_pwrite(
VALUE self,
VALUE io, rb_off_t from,
size_t length,
size_t offset)
3095 if (scheduler !=
Qnil) {
3098 if (!UNDEF_P(result)) {
3106 io_buffer_validate_range(buffer, offset, length);
3112 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3114 base = (
unsigned char*)base + offset;
3115 size = size - offset;
3118 .descriptor = descriptor,
3133 return io_buffer_blocking_region(buffer, io_buffer_pwrite_internal, &argument, descriptor);
3161io_buffer_pwrite(
int argc,
VALUE *argv,
VALUE self)
3168 size_t length, offset;
3169 io_buffer_extract_length_offset(self, argc-2, argv+2, &length, &offset);
3171 return rb_io_buffer_pwrite(self, io, from, length, offset);
3177 if (buffer->size == 0)
3178 rb_raise(rb_eIOBufferMaskError,
"Zero-length mask given!");
3182memory_and(
unsigned char * restrict output,
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3184 for (
size_t offset = 0; offset < size; offset += 1) {
3185 output[offset] = base[offset] & mask[offset % mask_size];
3210 io_buffer_check_mask(mask_buffer);
3212 VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
3216 memory_and(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
3222memory_or(
unsigned char * restrict output,
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3224 for (
size_t offset = 0; offset < size; offset += 1) {
3225 output[offset] = base[offset] | mask[offset % mask_size];
3250 io_buffer_check_mask(mask_buffer);
3252 VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
3256 memory_or(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
3262memory_xor(
unsigned char * restrict output,
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3264 for (
size_t offset = 0; offset < size; offset += 1) {
3265 output[offset] = base[offset] ^ mask[offset % mask_size];
3290 io_buffer_check_mask(mask_buffer);
3292 VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
3296 memory_xor(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
3302memory_not(
unsigned char * restrict output,
unsigned char * restrict base,
size_t size)
3304 for (
size_t offset = 0; offset < size; offset += 1) {
3305 output[offset] = ~base[offset];
3322io_buffer_not(
VALUE self)
3327 VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
3331 memory_not(output_buffer->base, buffer->base, buffer->size);
3339 if (a->base > b->base) {
3340 return io_buffer_overlaps(b, a);
3343 return (b->base >= a->base) && (b->base <= (
void*)((
unsigned char *)a->base + a->size));
3349 if (io_buffer_overlaps(a, b))
3350 rb_raise(rb_eIOBufferMaskError,
"Mask overlaps source buffer!");
3354memory_and_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3356 for (
size_t offset = 0; offset < size; offset += 1) {
3357 base[offset] &= mask[offset % mask_size];
3387 io_buffer_check_mask(mask_buffer);
3388 io_buffer_check_overlaps(buffer, mask_buffer);
3392 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3394 memory_and_inplace(base, size, mask_buffer->base, mask_buffer->size);
3400memory_or_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3402 for (
size_t offset = 0; offset < size; offset += 1) {
3403 base[offset] |= mask[offset % mask_size];
3433 io_buffer_check_mask(mask_buffer);
3434 io_buffer_check_overlaps(buffer, mask_buffer);
3438 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3440 memory_or_inplace(base, size, mask_buffer->base, mask_buffer->size);
3446memory_xor_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3448 for (
size_t offset = 0; offset < size; offset += 1) {
3449 base[offset] ^= mask[offset % mask_size];
3479 io_buffer_check_mask(mask_buffer);
3480 io_buffer_check_overlaps(buffer, mask_buffer);
3484 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3486 memory_xor_inplace(base, size, mask_buffer->base, mask_buffer->size);
3492memory_not_inplace(
unsigned char * restrict base,
size_t size)
3494 for (
size_t offset = 0; offset < size; offset += 1) {
3495 base[offset] = ~base[offset];
3517io_buffer_not_inplace(
VALUE self)
3524 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3526 memory_not_inplace(base, size);
3646 GetSystemInfo(&info);
3647 RUBY_IO_BUFFER_PAGE_SIZE = info.dwPageSize;
3649 RUBY_IO_BUFFER_PAGE_SIZE = sysconf(_SC_PAGESIZE);
3652 RUBY_IO_BUFFER_DEFAULT_SIZE = io_buffer_default_size(RUBY_IO_BUFFER_PAGE_SIZE);
3665 rb_define_method(rb_cIOBuffer,
"initialize_copy", rb_io_buffer_initialize_copy, 1);
3731#define IO_BUFFER_DEFINE_DATA_TYPE(name) RB_IO_BUFFER_DATA_TYPE_##name = rb_intern_const(#name)
3732 IO_BUFFER_DEFINE_DATA_TYPE(U8);
3733 IO_BUFFER_DEFINE_DATA_TYPE(S8);
3735 IO_BUFFER_DEFINE_DATA_TYPE(u16);
3736 IO_BUFFER_DEFINE_DATA_TYPE(U16);
3737 IO_BUFFER_DEFINE_DATA_TYPE(s16);
3738 IO_BUFFER_DEFINE_DATA_TYPE(S16);
3740 IO_BUFFER_DEFINE_DATA_TYPE(u32);
3741 IO_BUFFER_DEFINE_DATA_TYPE(U32);
3742 IO_BUFFER_DEFINE_DATA_TYPE(s32);
3743 IO_BUFFER_DEFINE_DATA_TYPE(S32);
3745 IO_BUFFER_DEFINE_DATA_TYPE(u64);
3746 IO_BUFFER_DEFINE_DATA_TYPE(U64);
3747 IO_BUFFER_DEFINE_DATA_TYPE(s64);
3748 IO_BUFFER_DEFINE_DATA_TYPE(S64);
3750 IO_BUFFER_DEFINE_DATA_TYPE(f32);
3751 IO_BUFFER_DEFINE_DATA_TYPE(F32);
3752 IO_BUFFER_DEFINE_DATA_TYPE(f64);
3753 IO_BUFFER_DEFINE_DATA_TYPE(F64);
3754#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.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
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 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 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 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_eRuntimeError
RuntimeError exception.
@ RB_WARN_CATEGORY_EXPERIMENTAL
Warning is for experimental features.
static VALUE rb_class_of(VALUE obj)
Object to class mapping function.
VALUE rb_mComparable
Comparable module.
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
#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().
#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.
#define RB_SYM2ID
Just another name of rb_sym2id.
void rb_define_const(VALUE klass, const char *name, VALUE val)
Defines a Ruby level constant under a namespace.
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
#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.
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.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.