17#include "internal/array.h"
18#include "internal/bits.h"
19#include "internal/error.h"
20#include "internal/gc.h"
21#include "internal/numeric.h"
22#include "internal/string.h"
23#include "internal/io.h"
24#include "internal/io_buffer.h"
27VALUE rb_cIOBufferStorage;
28VALUE rb_cIOBufferSlice;
29VALUE rb_eIOBufferLockedError;
30VALUE rb_eIOBufferAllocationError;
31VALUE rb_eIOBufferAccessError;
32VALUE rb_eIOBufferInvalidatedError;
33VALUE rb_eIOBufferMaskError;
35size_t RUBY_IO_BUFFER_PAGE_SIZE;
36size_t RUBY_IO_BUFFER_MAP_ALIGNMENT;
37size_t RUBY_IO_BUFFER_DEFAULT_SIZE;
46 RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH = 16,
47 RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH = 1024,
49 RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE = 256,
50 RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH = 16,
53 RB_IO_BUFFER_FLAGS_MASK = RB_IO_BUFFER_EXTERNAL | RB_IO_BUFFER_INTERNAL | RB_IO_BUFFER_MAPPED | RB_IO_BUFFER_SHARED | RB_IO_BUFFER_PRIVATE | RB_IO_BUFFER_READONLY,
55 RB_IO_BUFFER_ALLOCATION_FLAGS = RB_IO_BUFFER_INTERNAL | RB_IO_BUFFER_MAPPED,
56 RB_IO_BUFFER_MAPPING_FLAGS = RB_IO_BUFFER_SHARED | RB_IO_BUFFER_PRIVATE,
59 IO_BUFFER_SLICE = 1 << 9,
61 RB_IO_BUFFER_DEBUG = 0,
76 enum rb_io_buffer_flags flags;
93 return (buffer->flags & IO_BUFFER_SLICE) != 0;
101 if (io_buffer_slice_p(view)) {
102 rb_raise(rb_eIOBufferAccessError,
"Slice does not manage an allocation!");
108io_buffer_map_memory(
size_t size,
int flags)
111 void * base = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
114 rb_sys_fail(
"io_buffer_map_memory:VirtualAlloc");
117 int mmap_flags = MAP_ANONYMOUS;
118 if (flags & RB_IO_BUFFER_SHARED) {
119 mmap_flags |= MAP_SHARED;
122 mmap_flags |= MAP_PRIVATE;
125 void * base = mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
127 if (base == MAP_FAILED) {
128 rb_sys_fail(
"io_buffer_map_memory:mmap");
131 ruby_annotate_mmap(base, size,
"Ruby:io_buffer_map_memory");
138io_buffer_storage_map_file(
struct rb_io_buffer_storage *storage,
int descriptor,
size_t size, rb_off_t offset,
enum rb_io_buffer_flags flags)
142 HANDLE file = (HANDLE)_get_osfhandle(descriptor);
143 if (!file) rb_sys_fail(
"io_buffer_map_descriptor:_get_osfhandle");
145 DWORD protect = PAGE_READONLY, access = FILE_MAP_READ;
147 if (flags & RB_IO_BUFFER_READONLY) {
148 buffer->flags |= RB_IO_BUFFER_READONLY;
151 protect = PAGE_READWRITE;
152 access = FILE_MAP_WRITE;
155 if (flags & RB_IO_BUFFER_PRIVATE) {
156 protect = PAGE_WRITECOPY;
157 access = FILE_MAP_COPY;
158 buffer->flags |= RB_IO_BUFFER_PRIVATE;
162 buffer->flags |= RB_IO_BUFFER_EXTERNAL;
163 buffer->flags |= RB_IO_BUFFER_SHARED;
166 HANDLE mapping = CreateFileMapping(file, NULL, protect, 0, 0, NULL);
167 if (RB_IO_BUFFER_DEBUG) fprintf(stderr,
"io_buffer_storage_map_file:CreateFileMapping -> %p\n", mapping);
168 if (!mapping) rb_sys_fail(
"io_buffer_map_descriptor:CreateFileMapping");
170 void *base = MapViewOfFile(mapping, access, (DWORD)(offset >> 32), (DWORD)(offset & 0xFFFFFFFF), size);
173 CloseHandle(mapping);
174 rb_sys_fail(
"io_buffer_storage_map_file:MapViewOfFile");
177 storage->mapping = mapping;
179 int protect = PROT_READ, access = 0;
181 if (flags & RB_IO_BUFFER_READONLY) {
182 buffer->flags |= RB_IO_BUFFER_READONLY;
185 protect |= PROT_WRITE;
188 if (flags & RB_IO_BUFFER_PRIVATE) {
189 buffer->flags |= RB_IO_BUFFER_PRIVATE;
190 access |= MAP_PRIVATE;
194 buffer->flags |= RB_IO_BUFFER_EXTERNAL;
195 buffer->flags |= RB_IO_BUFFER_SHARED;
196 access |= MAP_SHARED;
199 void *base = mmap(NULL, size, protect, access, descriptor, offset);
201 if (base == MAP_FAILED) {
202 rb_sys_fail(
"io_buffer_storage_map_file:mmap");
209 buffer->flags |= RB_IO_BUFFER_MAPPED;
210 buffer->flags |= RB_IO_BUFFER_FILE;
214io_buffer_experimental(
void)
216 static int warned = 0;
224 "IO::Buffer is experimental and both the Ruby and C interface may change in the future!"
232 storage->view.base = NULL;
233 storage->view.size = 0;
234 storage->view.flags = 0;
235 storage->view.source =
Qnil;
236 storage->lock_count = 0;
238 storage->mapping = NULL;
243io_buffer_storage_initialize(
VALUE self,
struct rb_io_buffer_storage *storage,
void *base,
size_t size,
enum rb_io_buffer_flags flags,
VALUE source)
246 if (source !=
Qnil) {
258 if (flags & RB_IO_BUFFER_INTERNAL) {
259 base = calloc(size, 1);
261 else if (flags & RB_IO_BUFFER_MAPPED) {
262 base = io_buffer_map_memory(size, flags);
266 rb_raise(rb_eIOBufferAllocationError,
"Could not allocate buffer!");
277 buffer->flags = flags & ~IO_BUFFER_SLICE;
278 storage->lock_count = 0;
282 storage->mapping = NULL;
291 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
295 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
297 if (buffer->flags & RB_IO_BUFFER_FILE) {
298 UnmapViewOfFile(buffer->base);
301 VirtualFree(buffer->base, 0, MEM_RELEASE);
304 munmap(buffer->base, buffer->size);
316 if (storage->mapping) {
317 if (RB_IO_BUFFER_DEBUG) fprintf(stderr,
"io_buffer_storage_release:CloseHandle -> %p\n", storage->mapping);
318 if (!CloseHandle(storage->mapping)) {
319 fprintf(stderr,
"io_buffer_storage_release:GetLastError -> %lu\n", GetLastError());
321 storage->mapping = NULL;
325 io_buffer_storage_zero(storage);
329rb_io_buffer_type_mark(
void *_buffer)
332 if (buffer->source !=
Qnil) {
336 rb_gc_mark(buffer->source);
338 rb_gc_mark_movable(buffer->source);
344rb_io_buffer_type_compact(
void *_buffer)
347 if (buffer->source !=
Qnil) {
352 rb_gc_update_moved(&buffer->source);
358rb_io_buffer_type_free(
void *_buffer)
362 if (!io_buffer_slice_p(buffer)) io_buffer_storage_release(io_buffer_storage_from_view(buffer));
366rb_io_buffer_type_size(
const void *_buffer)
369 size_t total = io_buffer_slice_p(buffer) ?
sizeof(
struct rb_io_buffer_view) : sizeof(struct rb_io_buffer_storage);
371 if (buffer->flags & RB_IO_BUFFER_ALLOCATION_FLAGS) {
372 total += buffer->size;
381 .dmark = rb_io_buffer_type_mark,
382 .dfree = rb_io_buffer_type_free,
383 .dsize = rb_io_buffer_type_size,
384 .dcompact = rb_io_buffer_type_compact,
387 .flags = RUBY_TYPED_THREAD_SAFE_FREE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
391rb_io_buffer_p(
VALUE self)
393 return rb_typeddata_is_kind_of(self, &rb_io_buffer_type);
398get_io_buffer_view(
VALUE self)
407get_io_buffer_storage(
VALUE self)
409 return io_buffer_storage_from_view(get_io_buffer_view(self));
418 return !io_buffer_slice_p(buffer) && (buffer->flags & RB_IO_BUFFER_ALLOCATION_FLAGS) != 0;
427 return (uintptr_t)buffer->base;
435 while (io_buffer_slice_p(buffer)) {
436 if (
NIL_P(buffer->source)) rb_raise(rb_eIOBufferInvalidatedError,
"Uninitialized slice!");
437 buffer = get_io_buffer_view(buffer->source);
440 return io_buffer_storage_from_view(buffer);
446 if (io_buffer_slice_p(buffer) &&
NIL_P(buffer->source))
return false;
447 return io_buffer_lock_owner(buffer)->lock_count > 0;
450static inline enum rb_io_buffer_flags
451io_buffer_extract_flags(
VALUE argument)
453 if (rb_int_negative_p(argument)) {
454 rb_raise(rb_eArgError,
"Flags can't be negative!");
457 enum rb_io_buffer_flags flags =
RB_NUM2UINT(argument);
460 return flags & RB_IO_BUFFER_FLAGS_MASK;
463static inline enum rb_io_buffer_flags
464io_buffer_flags_for_map(
enum rb_io_buffer_flags flags)
466 if (flags & RB_IO_BUFFER_INTERNAL) {
467 rb_raise(rb_eArgError,
"IO::Buffer::INTERNAL can't be used with IO::Buffer.map!");
470 if (flags & RB_IO_BUFFER_EXTERNAL) {
471 rb_raise(rb_eArgError,
"IO::Buffer::EXTERNAL can't be used with IO::Buffer.map!");
474 if ((flags & RB_IO_BUFFER_MAPPING_FLAGS) == RB_IO_BUFFER_MAPPING_FLAGS) {
475 rb_raise(rb_eArgError,
"Flags can't include both IO::Buffer::SHARED and IO::Buffer::PRIVATE!");
483io_buffer_extract_offset(
VALUE argument)
485 if (rb_int_negative_p(argument)) {
486 rb_raise(rb_eArgError,
"Offset can't be negative!");
496io_buffer_extract_length(
VALUE argument)
498 if (rb_int_negative_p(argument)) {
499 rb_raise(rb_eArgError,
"Length can't be negative!");
508io_buffer_extract_size(
VALUE argument)
510 if (rb_int_negative_p(argument)) {
511 rb_raise(rb_eArgError,
"Size can't be negative!");
519io_buffer_extract_amount(
VALUE argument)
521 if (rb_int_negative_p(argument)) {
522 rb_raise(rb_eArgError,
"Amount can't be negative!");
531io_buffer_extract_width(
VALUE argument,
size_t minimum)
533 if (rb_int_negative_p(argument)) {
534 rb_raise(rb_eArgError,
"Width can't be negative!");
539 if (width < minimum) {
540 rb_raise(rb_eArgError,
"Width must be at least %" PRIuSIZE
"!", minimum);
543 if (width > RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH) {
544 rb_raise(rb_eArgError,
"Width must be at most %" PRIuSIZE
"!", (
size_t)RB_IO_BUFFER_HEXDUMP_MAXIMUM_WIDTH);
557 if (offset > buffer->size) {
558 rb_raise(rb_eArgError,
"The given offset is bigger than the buffer size!");
562 return buffer->size - offset;
570io_buffer_extract_offset_length(
VALUE self,
int argc,
VALUE argv[],
size_t *offset,
size_t *length)
574 if (argc >= 1 && !
NIL_P(argv[0])) {
575 *offset = io_buffer_extract_offset(argv[0]);
581 if (argc >= 2 && !
NIL_P(argv[1])) {
582 *length = io_buffer_extract_length(argv[1]);
585 *length = io_buffer_default_length(buffer, *offset);
592rb_io_buffer_type_allocate(
VALUE self)
594 io_buffer_experimental();
599 io_buffer_storage_zero(buffer);
605io_buffer_slice_allocate(
VALUE klass)
609 buffer->flags = (
enum rb_io_buffer_flags)IO_BUFFER_SLICE;
610 buffer->source =
Qnil;
623io_buffer_s_new(
int argc,
VALUE *argv,
VALUE klass)
625 if (klass == rb_cIOBuffer) klass = rb_cIOBufferStorage;
630io_buffer_storage_class(
VALUE klass)
632 if (klass == rb_cIOBuffer)
return rb_cIOBufferStorage;
634 rb_raise(
rb_eTypeError,
"Storage factory requires IO::Buffer::Storage!");
637static VALUE io_buffer_for_make_instance(
VALUE klass,
VALUE string,
enum rb_io_buffer_flags flags)
639 VALUE instance = rb_io_buffer_type_allocate(klass);
641 flags |= RB_IO_BUFFER_EXTERNAL;
644 flags |= RB_IO_BUFFER_READONLY;
646 if (!(flags & RB_IO_BUFFER_READONLY))
647 rb_str_modify(
string);
651 io_buffer_storage_initialize(instance, buffer, NULL, RSTRING_LEN(
string), flags,
string);
660 enum rb_io_buffer_flags flags;
664io_buffer_for_yield_instance(
VALUE _arguments)
668 arguments->instance = io_buffer_for_make_instance(arguments->klass, arguments->string, arguments->flags);
674 return rb_yield(arguments->instance);
678io_buffer_for_yield_instance_ensure(
VALUE _arguments)
682 if (arguments->instance !=
Qnil) {
683 rb_io_buffer_free(arguments->instance);
697 enum rb_io_buffer_flags flags;
703static VALUE rb_io_buffer_locked_ensure(
VALUE self);
712io_buffer_for_locked_callback_call(
VALUE _arguments)
716 return arguments->callback(arguments->buffer, arguments->argument);
724 .callback = callback,
725 .argument = argument,
728 rb_io_buffer_lock(buffer);
729 return rb_ensure(io_buffer_for_locked_callback_call, (
VALUE)&arguments, rb_io_buffer_locked_ensure, buffer);
733io_buffer_for_callback_call(
VALUE _arguments)
737 arguments->instance = io_buffer_for_make_instance(arguments->klass, arguments->string, arguments->flags);
741 arguments->locked = 1;
744 return io_buffer_for_locked_callback(arguments->instance, arguments->callback, arguments->argument);
748io_buffer_for_callback_ensure(
VALUE _arguments)
752 if (arguments->instance !=
Qnil) {
753 rb_io_buffer_free(arguments->instance);
756 if (arguments->locked) {
766 if (rb_io_buffer_p(string_or_buffer)) {
767 return io_buffer_for_locked_callback(string_or_buffer, callback, argument);
772 .klass = rb_cIOBufferStorage,
773 .string = string_or_buffer,
775 .flags = RB_IO_BUFFER_READONLY,
777 .callback = callback,
778 .argument = argument,
781 io_buffer_for_callback_ensure, (
VALUE)&arguments);
784 rb_raise(
rb_eTypeError,
"expected String or IO::Buffer, not %"PRIsVALUE,
795 if (rb_io_buffer_p(string_or_buffer)) {
797 if (io_buffer_readonly_p(buffer)) {
798 rb_raise(rb_eArgError,
"buffer is read-only");
800 return io_buffer_for_locked_callback(string_or_buffer, callback, argument);
805 .klass = rb_cIOBufferStorage,
806 .string = string_or_buffer,
810 .callback = callback,
811 .argument = argument,
814 io_buffer_for_callback_ensure, (
VALUE)&arguments);
817 rb_raise(
rb_eTypeError,
"expected String or IO::Buffer, not %"PRIsVALUE,
859rb_io_buffer_type_for(
VALUE klass,
VALUE string)
861 klass = io_buffer_storage_class(klass);
874 return rb_ensure(io_buffer_for_yield_instance, (
VALUE)&arguments, io_buffer_for_yield_instance_ensure, (
VALUE)&arguments);
880 return io_buffer_for_make_instance(klass,
string, RB_IO_BUFFER_READONLY);
898rb_io_buffer_type_string(
VALUE klass,
VALUE length)
900 klass = io_buffer_storage_class(klass);
909 rb_ensure(io_buffer_for_yield_instance, (
VALUE)&arguments, io_buffer_for_yield_instance_ensure, (
VALUE)&arguments);
915rb_io_buffer_new(
void *base,
size_t size,
enum rb_io_buffer_flags flags)
917 VALUE instance = rb_io_buffer_type_allocate(rb_cIOBufferStorage);
921 io_buffer_storage_initialize(instance, buffer, base, size, flags,
Qnil);
927rb_io_buffer_new_locked(
void *base,
size_t size,
enum rb_io_buffer_flags flags)
929 VALUE instance = rb_io_buffer_new(base, size, flags);
931 rb_io_buffer_lock(instance);
937io_buffer_storage_map(
VALUE klass,
VALUE io,
size_t size, rb_off_t offset,
enum rb_io_buffer_flags flags)
939 if (UNLIKELY(offset < 0)) {
940 rb_raise(rb_eArgError,
941 "Offset (%" PRIsVALUE
") can't be negative!",
945 if (UNLIKELY((uintmax_t)offset % RUBY_IO_BUFFER_MAP_ALIGNMENT != 0)) {
946 rb_raise(rb_eArgError,
947 "Offset (%" PRIsVALUE
") must be a multiple of IO::Buffer::MAP_ALIGNMENT (%" PRIuSIZE
")!",
949 RUBY_IO_BUFFER_MAP_ALIGNMENT);
952 VALUE instance = rb_io_buffer_type_allocate(klass);
956 io_buffer_storage_map_file(storage, descriptor, size, offset, flags);
962rb_io_buffer_map(
VALUE io,
size_t size, rb_off_t offset,
enum rb_io_buffer_flags flags)
964 return io_buffer_storage_map(rb_cIOBufferStorage, io, size, offset, flags);
1019io_buffer_map(
int argc,
VALUE *argv,
VALUE klass)
1021 klass = io_buffer_storage_class(klass);
1027 rb_off_t file_size = rb_file_size(io);
1029 if (UNLIKELY(file_size <= 0)) {
1030 rb_raise(rb_eArgError,
"Invalid negative or zero file size!");
1033 else if (UNLIKELY((uintmax_t)file_size > SIZE_MAX)) {
1034 rb_raise(rb_eArgError,
"File larger than address space!");
1038 if (argc >= 2 && !
RB_NIL_P(argv[1])) {
1039 size = io_buffer_extract_size(argv[1]);
1040 if (UNLIKELY(size == 0)) {
1041 rb_raise(rb_eArgError,
"Size can't be zero!");
1043 if (UNLIKELY(size > (
size_t)file_size)) {
1044 rb_raise(rb_eArgError,
1045 "Size (%" PRIuSIZE
") can't be larger than "
1046 "file size (%" PRIuSIZE
")",
1053 size = (size_t)file_size;
1057 rb_off_t offset = 0;
1060 if (UNLIKELY(offset < 0)) {
1061 rb_raise(rb_eArgError,
1062 "Offset (%" PRIsVALUE
") can't be negative!",
1065 if (UNLIKELY(offset >= file_size)) {
1066 rb_raise(rb_eArgError,
1067 "Offset (%" PRIsVALUE
") can't be larger than "
1068 "file size (%" PRIuSIZE
")",
1074 size = (size_t)(file_size - offset);
1076 else if (UNLIKELY((
size_t)(file_size - offset) < size)) {
1077 size_t maximum_offset =
1078 ((size_t)file_size - size) / RUBY_IO_BUFFER_MAP_ALIGNMENT *
1079 RUBY_IO_BUFFER_MAP_ALIGNMENT;
1080 rb_raise(rb_eArgError,
1081 "Offset (%" PRIsVALUE
") can't be larger than "
1082 "%" PRIuSIZE
" for requested size (%" PRIuSIZE
")",
1089 enum rb_io_buffer_flags flags = 0;
1091 flags = io_buffer_extract_flags(argv[3]);
1093 flags = io_buffer_flags_for_map(flags);
1095 return io_buffer_storage_map(klass, io, size, offset, flags);
1099static inline enum rb_io_buffer_flags
1100io_flags_for_size(
size_t size)
1102 if (size >= RUBY_IO_BUFFER_PAGE_SIZE) {
1103 return RB_IO_BUFFER_MAPPED;
1106 return RB_IO_BUFFER_INTERNAL;
1109static inline enum rb_io_buffer_flags
1110io_buffer_flags_for_new(
enum rb_io_buffer_flags flags,
size_t size)
1117 if (!(flags & RB_IO_BUFFER_ALLOCATION_FLAGS)) {
1118 if (flags & RB_IO_BUFFER_MAPPING_FLAGS) {
1120 flags |= RB_IO_BUFFER_MAPPED;
1124 flags |= io_flags_for_size(size);
1128 enum rb_io_buffer_flags allocation = flags & RB_IO_BUFFER_ALLOCATION_FLAGS;
1131 if ((
unsigned int)allocation == RB_IO_BUFFER_ALLOCATION_FLAGS) {
1132 rb_raise(rb_eArgError,
"Flags can't include both IO::Buffer::INTERNAL and IO::Buffer::MAPPED!");
1135 if (flags & RB_IO_BUFFER_EXTERNAL) {
1136 rb_raise(rb_eArgError,
"IO::Buffer::EXTERNAL can't be used with IO::Buffer.new!");
1139 if ((flags & RB_IO_BUFFER_MAPPING_FLAGS) && allocation != RB_IO_BUFFER_MAPPED) {
1140 rb_raise(rb_eArgError,
"IO::Buffer::SHARED and IO::Buffer::PRIVATE require IO::Buffer::MAPPED!");
1143 if ((flags & RB_IO_BUFFER_MAPPING_FLAGS) == RB_IO_BUFFER_MAPPING_FLAGS) {
1144 rb_raise(rb_eArgError,
"Flags can't include both IO::Buffer::SHARED and IO::Buffer::PRIVATE!");
1180rb_io_buffer_initialize(
int argc,
VALUE *argv,
VALUE self)
1182 rb_check_frozen(self);
1187 size = io_buffer_extract_size(argv[0]);
1190 size = RUBY_IO_BUFFER_DEFAULT_SIZE;
1193 enum rb_io_buffer_flags flags = 0;
1195 flags = io_buffer_extract_flags(argv[1]);
1197 flags = io_buffer_flags_for_new(flags, size);
1200 if (buffer->lock_count) rb_raise(rb_eIOBufferLockedError,
"Cannot initialize locked buffer!");
1201 io_buffer_storage_release(buffer);
1202 io_buffer_storage_initialize(self, buffer, NULL, size, flags,
Qnil);
1217io_buffer_try_get_bytes(
const struct rb_io_buffer_view *buffer,
void **base,
size_t *size)
1219 size_t length = buffer->size;
1221 void *source_base = NULL;
1223 while (buffer->source !=
Qnil) {
1227 if (io_buffer_slice_p(buffer)) {
1228 source_buffer = get_io_buffer_view(buffer->source);
1229 source_size = source_buffer->size;
1236 size_t relative_offset = io_buffer_slice_offset(buffer);
1237 if (relative_offset > source_size || buffer->size > source_size - relative_offset ||
1238 relative_offset > SIZE_MAX - offset) {
1244 offset += relative_offset;
1245 if (!source_buffer) {
1246 *base = source_base ? (
char *)source_base + offset : NULL;
1251 buffer = source_buffer;
1256 if (io_buffer_slice_p(buffer)) {
1263 *base = buffer->base ? (
char *)buffer->base + offset : NULL;
1273 return io_buffer_try_get_bytes(buffer, &base, &size);
1276enum rb_io_buffer_flags
1277rb_io_buffer_get_bytes(
VALUE self,
void **base,
size_t *size)
1281 if (io_buffer_try_get_bytes(buffer, base, size)) {
1282 enum rb_io_buffer_flags flags = buffer->flags & ~IO_BUFFER_SLICE;
1283 if (io_buffer_readonly_p(buffer)) flags |= RB_IO_BUFFER_READONLY;
1291io_buffer_get_bytes_for_writing(
const struct rb_io_buffer_view *buffer,
void **base,
size_t *size)
1293 if (io_buffer_readonly_p(buffer)) {
1294 rb_raise(rb_eIOBufferAccessError,
"Buffer is not writable!");
1297 if (!io_buffer_validate(buffer)) {
1298 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer is invalid!");
1301 io_buffer_try_get_bytes(buffer, base, size);
1309 io_buffer_get_bytes_for_writing(buffer, &base, &size);
1313get_io_buffer_view_for_writing(
VALUE self)
1315 rb_check_frozen(self);
1318 io_buffer_validate_for_writing(buffer);
1323rb_io_buffer_get_bytes_for_writing(
VALUE self,
void **base,
size_t *size)
1327 io_buffer_get_bytes_for_writing(buffer, base, size);
1331io_buffer_get_bytes_for_reading(
const struct rb_io_buffer_view *buffer,
const void **base,
size_t *size)
1333 void *writable_base = NULL;
1334 if (!io_buffer_try_get_bytes(buffer, &writable_base, size)) {
1335 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer has been invalidated!");
1337 *base = writable_base;
1345 io_buffer_get_bytes_for_reading(buffer, &base, &size);
1349rb_io_buffer_get_bytes_for_reading(
VALUE self,
const void **base,
size_t *size)
1353 io_buffer_get_bytes_for_reading(buffer, base, size);
1366rb_io_buffer_to_s(
VALUE self)
1377 io_buffer_try_get_bytes(buffer, &base, &size);
1378 rb_str_catf(result,
" %p+%"PRIdSIZE, base, buffer->size);
1384 if (buffer->flags & RB_IO_BUFFER_EXTERNAL) {
1388 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
1392 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
1396 if (buffer->flags & RB_IO_BUFFER_FILE) {
1400 if (buffer->flags & RB_IO_BUFFER_SHARED) {
1404 if (io_buffer_locked(buffer)) {
1408 if (buffer->flags & RB_IO_BUFFER_PRIVATE) {
1412 if (io_buffer_readonly_p(buffer)) {
1416 if (buffer->source !=
Qnil) {
1420 if (!io_buffer_validate(buffer)) {
1430io_buffer_hexdump_output_size(
size_t width,
size_t size,
int first)
1433 size_t total = size;
1435 size_t whole_lines = (size / width);
1436 size_t partial_line = (size % width) ? 1 : 0;
1441 total += (whole_lines + partial_line) * (1 + 10 + width*3 + 1 + 1);
1444 if (size && first) total -= 1;
1453io_buffer_hexdump(
VALUE string,
size_t width,
const char *base,
size_t length,
size_t offset,
int first)
1455 char *text = alloca(width+1);
1458 for (; offset < length; offset += width) {
1459 memset(text,
'\0', width);
1461 rb_str_catf(
string,
"0x%08" PRIxSIZE
" ", offset);
1465 rb_str_catf(
string,
"\n0x%08" PRIxSIZE
" ", offset);
1468 for (
size_t i = 0; i < width; i += 1) {
1469 if (offset+i < length) {
1470 unsigned char value = ((
unsigned char*)base)[offset+i];
1472 if (value < 127 && isprint(value)) {
1473 text[i] = (char)value;
1479 rb_str_catf(
string,
" %02x", value);
1486 rb_str_catf(
string,
" %s", text);
1505rb_io_buffer_inspect(
VALUE self)
1509 VALUE result = rb_io_buffer_to_s(self);
1513 if (io_buffer_try_get_bytes(buffer, &base, &total) && base) {
1515 size_t size = buffer->size;
1518 if (size > RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE) {
1519 size = RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE;
1523 io_buffer_hexdump(result, RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH, base, size, 0, 0);
1526 rb_str_catf(result,
"\n(and %" PRIuSIZE
" more bytes not printed)", buffer->size - size);
1540rb_io_buffer_size(
VALUE self)
1564rb_io_buffer_valid_p(
VALUE self)
1568 return RBOOL(io_buffer_validate(buffer));
1589rb_io_buffer_null_p(
VALUE self)
1595 io_buffer_try_get_bytes(buffer, &base, &size);
1597 return RBOOL(base == NULL);
1610rb_io_buffer_empty_p(
VALUE self)
1614 return RBOOL(buffer->size == 0);
1629rb_io_buffer_external_p(
VALUE self)
1633 return RBOOL(buffer->flags & RB_IO_BUFFER_EXTERNAL);
1653rb_io_buffer_internal_p(
VALUE self)
1657 return RBOOL(buffer->flags & RB_IO_BUFFER_INTERNAL);
1674rb_io_buffer_mapped_p(
VALUE self)
1678 return RBOOL(buffer->flags & RB_IO_BUFFER_MAPPED);
1705rb_io_buffer_shared_p(
VALUE self)
1709 return RBOOL(buffer->flags & RB_IO_BUFFER_SHARED);
1726rb_io_buffer_locked_p(
VALUE self)
1730 return RBOOL(io_buffer_locked(buffer));
1756rb_io_buffer_private_p(
VALUE self)
1760 return RBOOL(buffer->flags & RB_IO_BUFFER_PRIVATE);
1767 if (buffer->flags & RB_IO_BUFFER_READONLY)
1770 VALUE source = buffer->source;
1780 buffer = get_io_buffer_view(source);
1785rb_io_buffer_readonly_p(
VALUE self)
1788 return io_buffer_readonly_p(buffer);
1804io_buffer_readonly(
VALUE self)
1808 return RBOOL(io_buffer_readonly_p(buffer));
1816 if (owner->lock_count == SIZE_MAX) {
1817 rb_raise(rb_eIOBufferLockedError,
"It's locks all the way down!");
1820 owner->lock_count += 1;
1824rb_io_buffer_lock(
VALUE self)
1828 io_buffer_lock(buffer);
1838 if (owner->lock_count == 0) {
1839 rb_raise(rb_eIOBufferLockedError,
"Buffer not locked!");
1842 owner->lock_count -= 1;
1846rb_io_buffer_unlock(
VALUE self)
1850 io_buffer_unlock(buffer);
1856rb_io_buffer_try_unlock(
VALUE self)
1861 if (owner->lock_count > 0) {
1862 owner->lock_count -= 1;
1871rb_io_buffer_locked_ensure(
VALUE self)
1875 io_buffer_unlock(buffer);
1882 VALUE (*callback)(
const void *base,
size_t size,
VALUE argument);
1887io_buffer_readable_bytes_call(
VALUE _arguments)
1893 rb_io_buffer_get_bytes_for_reading(arguments->self, &base, &size);
1895 return arguments->callback(base, size, arguments->argument);
1899rb_io_buffer_locked_for_reading(
VALUE self,
VALUE (*callback)(
const void *base,
size_t size,
VALUE argument),
VALUE argument)
1902 io_buffer_validate_for_reading(buffer);
1906 .callback = callback,
1907 .argument = argument,
1910 rb_io_buffer_lock(self);
1911 return rb_ensure(io_buffer_readable_bytes_call, (
VALUE)&arguments, rb_io_buffer_locked_ensure, self);
1916 VALUE (*callback)(
void *base,
size_t size,
VALUE argument);
1921io_buffer_writable_bytes_call(
VALUE _arguments)
1927 rb_io_buffer_get_bytes_for_writing(arguments->self, &base, &size);
1929 return arguments->callback(base, size, arguments->argument);
1933rb_io_buffer_locked_for_writing(
VALUE self,
VALUE (*callback)(
void *base,
size_t size,
VALUE argument),
VALUE argument)
1935 get_io_buffer_view_for_writing(self);
1939 .callback = callback,
1940 .argument = argument,
1943 rb_io_buffer_lock(self);
1944 return rb_ensure(io_buffer_writable_bytes_call, (
VALUE)&arguments, rb_io_buffer_locked_ensure, self);
1975rb_io_buffer_locked(
VALUE self)
1981 io_buffer_validate_for_reading(buffer);
1983 io_buffer_lock(buffer);
1989rb_io_buffer_free(
VALUE self)
1993 if (buffer->lock_count) {
1994 rb_raise(rb_eIOBufferLockedError,
"Buffer is locked!");
1997 io_buffer_storage_release(buffer);
2038io_buffer_free(
VALUE self)
2040 rb_check_frozen(self);
2042 return rb_io_buffer_free(self);
2052 if (buffer->lock_count != 1) {
2053 rb_bug(
"rb_io_buffer_free_locked: expected lock count 1, got %" PRIuSIZE, buffer->lock_count);
2056 io_buffer_unlock(&buffer->view);
2057 io_buffer_storage_release(buffer);
2063size_sum_is_bigger_than(
size_t a,
size_t b,
size_t x)
2065 struct rbimpl_size_overflow_tag size = rbimpl_size_add_overflow(a, b);
2066 return size.overflowed || size.result > x;
2072io_buffer_validate_range(
const struct rb_io_buffer_view *buffer,
size_t offset,
size_t length)
2074 io_buffer_validate_for_reading(buffer);
2076 if (size_sum_is_bigger_than(offset, length, buffer->size)) {
2077 rb_raise(rb_eArgError,
"Specified offset+length is bigger than the buffer size!");
2101rb_io_buffer_hexdump(
int argc,
VALUE *argv,
VALUE self)
2105 size_t offset, length;
2106 struct rb_io_buffer_view *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
2108 size_t width = RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH;
2110 width = io_buffer_extract_width(argv[2], 1);
2114 io_buffer_validate_range(buffer, offset, length);
2120 if (io_buffer_try_get_bytes(buffer, &base, &size) && base) {
2121 result =
rb_str_buf_new(io_buffer_hexdump_output_size(width, length, 1));
2123 io_buffer_hexdump(result, width, base, offset+length, offset, 1);
2132 io_buffer_validate_range(buffer, offset, length);
2134 VALUE instance = io_buffer_slice_allocate(rb_cIOBufferSlice);
2137 slice->size = length;
2141 slice->base = (
void *)(uintptr_t)offset;
2154io_buffer_slice_initialize(
int argc,
VALUE *argv,
VALUE self)
2156 rb_check_frozen(self);
2161 VALUE source = argv[0];
2162 size_t offset, length;
2163 struct rb_io_buffer_view *parent = io_buffer_extract_offset_length(source, argc-1, argv+1, &offset, &length);
2164 io_buffer_validate_range(parent, offset, length);
2166 slice = get_io_buffer_view(self);
2168 slice->base = (
void *)(uintptr_t)offset;
2169 slice->size = length;
2198io_buffer_slice_initialize_copy(
VALUE self,
VALUE other)
2200 if (self == other)
return self;
2201 rb_check_frozen(self);
2204 if (!io_buffer_slice_p(original)) rb_raise(
rb_eTypeError,
"Expected IO::Buffer::Slice!");
2207 slice->base = original->base;
2208 slice->size = original->size;
2209 slice->flags = original->flags;
2238io_buffer_source(
VALUE self)
2240 return get_io_buffer_view(self)->source;
2300io_buffer_slice(
int argc,
VALUE *argv,
VALUE self)
2304 size_t offset, length;
2305 struct rb_io_buffer_view *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
2307 return rb_io_buffer_slice(buffer, self, offset, length);
2311rb_io_buffer_transfer(
VALUE self)
2315 if (buffer->lock_count) {
2316 rb_raise(rb_eIOBufferLockedError,
"Cannot transfer ownership of locked buffer!");
2322 *transferred = *buffer;
2323 io_buffer_storage_zero(buffer);
2354io_buffer_transfer(
VALUE self)
2356 rb_check_frozen(self);
2358 return rb_io_buffer_transfer(self);
2362io_buffer_storage_resize_clear(
const struct rb_io_buffer_storage *storage,
void* base,
size_t size)
2364 if (size > storage->view.size) {
2365 memset((
unsigned char*)base+storage->view.size, 0, size - storage->view.size);
2374 enum rb_io_buffer_flags flags = io_flags_for_size(size) | (storage->view.flags & RB_IO_BUFFER_READONLY);
2375 io_buffer_storage_initialize(self, &resized, NULL, size, flags,
Qnil);
2377 if (storage->view.base) {
2378 size_t preserve = storage->view.size;
2379 if (preserve > size) preserve = size;
2380 memcpy(resized.view.base, storage->view.base, preserve);
2382 io_buffer_storage_resize_clear(storage, resized.view.base, size);
2385 io_buffer_storage_release(storage);
2390rb_io_buffer_advance(
VALUE self,
size_t amount)
2394 if (io_buffer_owning_p(buffer)) {
2395 rb_raise(rb_eIOBufferAccessError,
"Cannot advance an owning buffer!");
2398 if (!io_buffer_validate(buffer)) {
2399 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer has been invalidated!");
2402 if (amount > buffer->size) {
2403 rb_raise(rb_eArgError,
"Advance amount exceeds buffer size!");
2406 if (buffer->source !=
Qnil) {
2409 buffer->base = (
void *)(uintptr_t)(io_buffer_slice_offset(buffer) + amount);
2411 else if (buffer->base) {
2413 buffer->base = (
char *)buffer->base + amount;
2416 buffer->size -= amount;
2422 if (
NIL_P(
slice->source)) rb_raise(rb_eIOBufferInvalidatedError,
"Uninitialized slice!");
2425 void *source_base = NULL;
2426 size_t source_size = 0;
2428 if (!io_buffer_try_get_bytes(source, &source_base, &source_size)) {
2429 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer is invalid!");
2432 size_t offset = io_buffer_slice_offset(slice);
2434 if (offset > source_size) {
2435 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer is invalid!");
2438 if (size > source_size - offset) {
2439 rb_raise(rb_eArgError,
"Resized slice exceeds its source buffer!");
2451 io_buffer_validate_for_reading(buffer);
2453 if (storage->lock_count) {
2454 rb_raise(rb_eIOBufferLockedError,
"Cannot resize locked buffer!");
2461 if (buffer->flags & RB_IO_BUFFER_EXTERNAL) {
2462 rb_raise(rb_eIOBufferAccessError,
"Cannot resize external buffer!");
2465 if (buffer->base == NULL) {
2466 io_buffer_storage_initialize(self, storage, NULL, size, io_flags_for_size(size),
Qnil);
2471 io_buffer_storage_release(storage);
2475#if defined(HAVE_MREMAP) && defined(MREMAP_MAYMOVE)
2476 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
2477 void *base = mremap(buffer->base, buffer->size, size, MREMAP_MAYMOVE);
2479 if (base == MAP_FAILED) {
2480 rb_sys_fail(
"rb_io_buffer_resize:mremap");
2483 io_buffer_storage_resize_clear(storage, base, size);
2485 buffer->base = base;
2486 buffer->size = size;
2492 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
2493 void *base = realloc(buffer->base, size);
2496 rb_sys_fail(
"rb_io_buffer_resize:realloc");
2499 io_buffer_storage_resize_clear(storage, base, size);
2501 buffer->base = base;
2502 buffer->size = size;
2507 io_buffer_storage_resize_copy(self, storage, size);
2511rb_io_buffer_resize(
VALUE self,
size_t size)
2514 if (io_buffer_slice_p(view)) {
2515 io_buffer_resize_slice(view, size);
2518 io_buffer_storage_resize(self, io_buffer_storage_from_view(view), size);
2549 rb_check_frozen(self);
2551 rb_io_buffer_resize(self, io_buffer_extract_size(size));
2581 rb_check_frozen(self);
2583 size_t size = io_buffer_extract_amount(amount);
2586 rb_check_frozen(self);
2588 rb_io_buffer_advance(self, size);
2610 const void *ptr1, *ptr2;
2611 size_t size1, size2;
2613 rb_io_buffer_get_bytes_for_reading(self, &ptr1, &size1);
2614 rb_io_buffer_get_bytes_for_reading(other, &ptr2, &size2);
2616 if (size1 < size2) {
2620 if (size1 > size2) {
2630 return RB_INT2NUM(memcmp(ptr1, ptr2, size1));
2646 if (!rb_io_buffer_p(other))
return Qfalse;
2648 return RBOOL(rb_io_buffer_compare(self, other) ==
INT2FIX(0));
2652io_buffer_validate_type(
size_t size,
size_t offset,
size_t extend)
2654 if (size_sum_is_bigger_than(offset, extend, size)) {
2655 rb_raise(rb_eArgError,
"Type extends beyond end of buffer! (offset=%"PRIdSIZE
" > size=%"PRIdSIZE
")", offset, size);
2680#define ruby_swap8(value) value
2688ruby_swapf32(
float value)
2690 union swapf32 swap = {.value = value};
2691 swap.integral = ruby_swap32(swap.integral);
2701ruby_swapf64(
double value)
2703 union swapf64 swap = {.value = value};
2704 swap.integral = ruby_swap64(swap.integral);
2716#ifdef HAVE_UINT128_T
2717#if __has_builtin(__builtin_bswap128)
2718 result.value = __builtin_bswap128(x.value);
2721 uint64_t low = (uint64_t)x.value;
2722 uint64_t high = (uint64_t)(x.value >> 64);
2723 low = ruby_swap64(low);
2724 high = ruby_swap64(high);
2725 result.value = ((uint128_t)low << 64) | high;
2732 result.parts.low = ruby_swap64(x.parts.high);
2733 result.parts.high = ruby_swap64(x.parts.low);
2744 conversion.uint128 = ruby_swap128_uint(conversion.uint128);
2745 return conversion.int128;
2748#define IO_BUFFER_VALIDATE_TYPE_FOR_WRITING(buffer, base, size, offset, type) \
2749 (io_buffer_get_bytes_for_writing(buffer, &(base), &(size)), \
2750 io_buffer_validate_type(size, offset, sizeof(type)))
2752#define IO_BUFFER_DECLARE_TYPE(name, type, endian, wrap, unwrap, swap) \
2753static ID RB_IO_BUFFER_DATA_TYPE_##name; \
2756io_buffer_read_##name(const void* base, size_t size, size_t *offset) \
2758 io_buffer_validate_type(size, *offset, sizeof(type)); \
2760 memcpy(&value, (char*)base + *offset, sizeof(type)); \
2761 if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
2762 *offset += sizeof(type); \
2763 return wrap(value); \
2767io_buffer_write_##name(struct rb_io_buffer_view* buffer, size_t *offset, VALUE _value) \
2769 void* base; size_t size; \
2770 IO_BUFFER_VALIDATE_TYPE_FOR_WRITING(buffer, base, size, *offset, type); \
2771 type value = unwrap(_value); \
2772 IO_BUFFER_VALIDATE_TYPE_FOR_WRITING(buffer, base, size, *offset, type); \
2773 if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
2774 memcpy((char*)base + *offset, &value, sizeof(type)); \
2775 *offset += sizeof(type); \
2779 RB_IO_BUFFER_DATA_TYPE_##name##_SIZE = sizeof(type) \
2787IO_BUFFER_DECLARE_TYPE(s16, int16_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap16)
2788IO_BUFFER_DECLARE_TYPE(S16, int16_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap16)
2792IO_BUFFER_DECLARE_TYPE(s32, int32_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap32)
2793IO_BUFFER_DECLARE_TYPE(S32, int32_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap32)
2795IO_BUFFER_DECLARE_TYPE(u64, uint64_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_ULL2NUM,
RB_NUM2ULL, ruby_swap64)
2796IO_BUFFER_DECLARE_TYPE(U64, uint64_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_ULL2NUM,
RB_NUM2ULL, ruby_swap64)
2797IO_BUFFER_DECLARE_TYPE(s64, int64_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_LL2NUM,
RB_NUM2LL, ruby_swap64)
2798IO_BUFFER_DECLARE_TYPE(S64, int64_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_LL2NUM,
RB_NUM2LL, ruby_swap64)
2800IO_BUFFER_DECLARE_TYPE(u128,
rb_uint128_t, RB_IO_BUFFER_LITTLE_ENDIAN, rb_uint128_to_numeric, rb_numeric_to_uint128, ruby_swap128_uint)
2801IO_BUFFER_DECLARE_TYPE(U128,
rb_uint128_t, RB_IO_BUFFER_BIG_ENDIAN, rb_uint128_to_numeric, rb_numeric_to_uint128, ruby_swap128_uint)
2802IO_BUFFER_DECLARE_TYPE(s128,
rb_int128_t, RB_IO_BUFFER_LITTLE_ENDIAN, rb_int128_to_numeric, rb_numeric_to_int128, ruby_swap128_int)
2803IO_BUFFER_DECLARE_TYPE(S128,
rb_int128_t, RB_IO_BUFFER_BIG_ENDIAN, rb_int128_to_numeric, rb_numeric_to_int128, ruby_swap128_int)
2805IO_BUFFER_DECLARE_TYPE(f32,
float, RB_IO_BUFFER_LITTLE_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf32)
2806IO_BUFFER_DECLARE_TYPE(F32,
float, RB_IO_BUFFER_BIG_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf32)
2807IO_BUFFER_DECLARE_TYPE(f64,
double, RB_IO_BUFFER_LITTLE_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf64)
2808IO_BUFFER_DECLARE_TYPE(F64,
double, RB_IO_BUFFER_BIG_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf64)
2809#undef IO_BUFFER_DECLARE_TYPE
2812io_buffer_buffer_type_size(
ID buffer_type)
2814#define IO_BUFFER_DATA_TYPE_SIZE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) return RB_IO_BUFFER_DATA_TYPE_##name##_SIZE;
2815 IO_BUFFER_DATA_TYPE_SIZE(U8)
2816 IO_BUFFER_DATA_TYPE_SIZE(S8)
2817 IO_BUFFER_DATA_TYPE_SIZE(u16)
2818 IO_BUFFER_DATA_TYPE_SIZE(U16)
2819 IO_BUFFER_DATA_TYPE_SIZE(s16)
2820 IO_BUFFER_DATA_TYPE_SIZE(S16)
2821 IO_BUFFER_DATA_TYPE_SIZE(u32)
2822 IO_BUFFER_DATA_TYPE_SIZE(U32)
2823 IO_BUFFER_DATA_TYPE_SIZE(s32)
2824 IO_BUFFER_DATA_TYPE_SIZE(S32)
2825 IO_BUFFER_DATA_TYPE_SIZE(u64)
2826 IO_BUFFER_DATA_TYPE_SIZE(U64)
2827 IO_BUFFER_DATA_TYPE_SIZE(s64)
2828 IO_BUFFER_DATA_TYPE_SIZE(S64)
2829 IO_BUFFER_DATA_TYPE_SIZE(u128)
2830 IO_BUFFER_DATA_TYPE_SIZE(U128)
2831 IO_BUFFER_DATA_TYPE_SIZE(s128)
2832 IO_BUFFER_DATA_TYPE_SIZE(S128)
2833 IO_BUFFER_DATA_TYPE_SIZE(f32)
2834 IO_BUFFER_DATA_TYPE_SIZE(F32)
2835 IO_BUFFER_DATA_TYPE_SIZE(f64)
2836 IO_BUFFER_DATA_TYPE_SIZE(F64)
2837#undef IO_BUFFER_DATA_TYPE_SIZE
2839 rb_raise(rb_eArgError,
"Invalid type name!");
2843io_buffer_type_id(
VALUE name)
2849#define TYPE_ID(name) io_buffer_type_id(name)
2862io_buffer_size_of(
VALUE klass,
VALUE buffer_type)
2867 total += io_buffer_buffer_type_size(TYPE_ID(
RARRAY_AREF(buffer_type, i)));
2872 return SIZET2NUM(io_buffer_buffer_type_size(TYPE_ID(buffer_type)));
2880rb_jit_io_buffer_readable_ptr(
VALUE self,
size_t offset,
size_t length)
2885 if (!io_buffer_try_get_bytes(get_io_buffer_view(self), &base, &size))
return NULL;
2886 if (!base)
return NULL;
2887 if (size_sum_is_bigger_than(offset, length, size))
return NULL;
2889 return (
const char *)base + offset;
2894rb_io_buffer_get_value(
const void* base,
size_t size,
ID buffer_type,
size_t *offset)
2896#define IO_BUFFER_GET_VALUE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) return io_buffer_read_##name(base, size, offset);
2897 IO_BUFFER_GET_VALUE(U8)
2898 IO_BUFFER_GET_VALUE(S8)
2900 IO_BUFFER_GET_VALUE(u16)
2901 IO_BUFFER_GET_VALUE(U16)
2902 IO_BUFFER_GET_VALUE(s16)
2903 IO_BUFFER_GET_VALUE(S16)
2905 IO_BUFFER_GET_VALUE(u32)
2906 IO_BUFFER_GET_VALUE(U32)
2907 IO_BUFFER_GET_VALUE(s32)
2908 IO_BUFFER_GET_VALUE(S32)
2910 IO_BUFFER_GET_VALUE(u64)
2911 IO_BUFFER_GET_VALUE(U64)
2912 IO_BUFFER_GET_VALUE(s64)
2913 IO_BUFFER_GET_VALUE(S64)
2915 IO_BUFFER_GET_VALUE(u128)
2916 IO_BUFFER_GET_VALUE(U128)
2917 IO_BUFFER_GET_VALUE(s128)
2918 IO_BUFFER_GET_VALUE(S128)
2920 IO_BUFFER_GET_VALUE(f32)
2921 IO_BUFFER_GET_VALUE(F32)
2922 IO_BUFFER_GET_VALUE(f64)
2923 IO_BUFFER_GET_VALUE(F64)
2924#undef IO_BUFFER_GET_VALUE
2926 rb_raise(rb_eArgError,
"Invalid type name!");
2972 size_t offset = io_buffer_extract_offset(_offset);
2974 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2976 return rb_io_buffer_get_value(base, size, TYPE_ID(
type), &offset);
2992 size_t offset = io_buffer_extract_offset(_offset);
2996 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2999 rb_raise(rb_eArgError,
"Argument buffer_types should be an array!");
3006 VALUE value = rb_io_buffer_get_value(base, size, TYPE_ID(
type), &offset);
3016io_buffer_extract_count(
VALUE argument)
3018 if (rb_int_negative_p(argument)) {
3019 rb_raise(rb_eArgError,
"Count can't be negative!");
3026io_buffer_extract_offset_count(
ID buffer_type,
size_t size,
int argc,
VALUE *argv,
size_t *offset,
size_t *count)
3029 *offset = io_buffer_extract_offset(argv[0]);
3036 *count = io_buffer_extract_count(argv[1]);
3039 if (*offset > size) {
3040 rb_raise(rb_eArgError,
"The given offset is bigger than the buffer size!");
3043 *count = (size - *offset) / io_buffer_buffer_type_size(buffer_type);
3054io_buffer_each_locked(
VALUE _arguments)
3057 VALUE self = arguments->self;
3058 int argc = arguments->argc;
3059 VALUE *argv = arguments->argv;
3064 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
3068 buffer_type = TYPE_ID(argv[0]);
3071 buffer_type = RB_IO_BUFFER_DATA_TYPE_U8;
3074 size_t offset, count;
3075 io_buffer_extract_offset_count(buffer_type, size, argc-1, argv+1, &offset, &count);
3077 for (
size_t i = 0; i < count; i++) {
3078 size_t current_offset = offset;
3079 VALUE value = rb_io_buffer_get_value(base, size, buffer_type, &offset);
3103io_buffer_each(
int argc,
VALUE *argv,
VALUE self)
3113 rb_io_buffer_lock(self);
3114 return rb_ensure(io_buffer_each_locked, (
VALUE)&arguments, rb_io_buffer_locked_ensure, self);
3128io_buffer_values(
int argc,
VALUE *argv,
VALUE self)
3133 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
3137 buffer_type = TYPE_ID(argv[0]);
3140 buffer_type = RB_IO_BUFFER_DATA_TYPE_U8;
3143 size_t offset, count;
3144 io_buffer_extract_offset_count(buffer_type, size, argc-1, argv+1, &offset, &count);
3148 for (
size_t i = 0; i < count; i++) {
3149 VALUE value = rb_io_buffer_get_value(base, size, buffer_type, &offset);
3157io_buffer_each_byte_locked(
VALUE _arguments)
3160 VALUE self = arguments->self;
3161 int argc = arguments->argc;
3162 VALUE *argv = arguments->argv;
3167 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
3169 size_t offset, count;
3170 io_buffer_extract_offset_count(RB_IO_BUFFER_DATA_TYPE_U8, size, argc, argv, &offset, &count);
3172 if (size_sum_is_bigger_than(offset, count, size)) {
3173 rb_raise(rb_eArgError,
"Specified offset+count is bigger than the buffer size!");
3176 for (
size_t i = 0; i < count; i++) {
3177 unsigned char *value = (
unsigned char *)base + i + offset;
3200io_buffer_each_byte(
int argc,
VALUE *argv,
VALUE self)
3210 rb_io_buffer_lock(self);
3211 return rb_ensure(io_buffer_each_byte_locked, (
VALUE)&arguments, rb_io_buffer_locked_ensure, self);
3217 ID type = TYPE_ID(buffer_type);
3218#define IO_BUFFER_SET_VALUE(name) if (type == RB_IO_BUFFER_DATA_TYPE_##name) {io_buffer_write_##name(buffer, offset, value); return;}
3219 IO_BUFFER_SET_VALUE(U8);
3220 IO_BUFFER_SET_VALUE(S8);
3222 IO_BUFFER_SET_VALUE(u16);
3223 IO_BUFFER_SET_VALUE(U16);
3224 IO_BUFFER_SET_VALUE(s16);
3225 IO_BUFFER_SET_VALUE(S16);
3227 IO_BUFFER_SET_VALUE(u32);
3228 IO_BUFFER_SET_VALUE(U32);
3229 IO_BUFFER_SET_VALUE(s32);
3230 IO_BUFFER_SET_VALUE(S32);
3232 IO_BUFFER_SET_VALUE(u64);
3233 IO_BUFFER_SET_VALUE(U64);
3234 IO_BUFFER_SET_VALUE(s64);
3235 IO_BUFFER_SET_VALUE(S64);
3237 IO_BUFFER_SET_VALUE(u128);
3238 IO_BUFFER_SET_VALUE(U128);
3239 IO_BUFFER_SET_VALUE(s128);
3240 IO_BUFFER_SET_VALUE(S128);
3242 IO_BUFFER_SET_VALUE(f32);
3243 IO_BUFFER_SET_VALUE(F32);
3244 IO_BUFFER_SET_VALUE(f64);
3245 IO_BUFFER_SET_VALUE(F64);
3246#undef IO_BUFFER_SET_VALUE
3248 rb_raise(rb_eArgError,
"Invalid type name!");
3292 size_t offset = io_buffer_extract_offset(_offset);
3293 rb_io_buffer_set_value(buffer,
type, &offset, value);
3319 rb_raise(rb_eArgError,
"Argument buffer_types should be an array!");
3322 size_t offset = io_buffer_extract_offset(_offset);
3325 rb_raise(rb_eArgError,
"Argument values should be an array!");
3329 rb_raise(rb_eArgError,
"Argument buffer_types and values should have the same length!");
3335 rb_io_buffer_set_value(buffer,
type, &offset, value);
3341static size_t IO_BUFFER_BLOCKING_SIZE = 1024*1024;
3344 unsigned char * destination;
3345 const unsigned char * source;
3350io_buffer_memmove_blocking(
void *data)
3354 memmove(arguments->destination, arguments->source, arguments->length);
3360io_buffer_memmove_unblock(
void *data)
3366io_buffer_memmove(
void *base,
size_t size,
size_t offset,
const void *source_base,
size_t source_offset,
size_t source_size,
size_t length)
3368 if (size_sum_is_bigger_than(offset, length, size)) {
3369 rb_raise(rb_eArgError,
"Specified offset+length is bigger than the buffer size!");
3372 if (size_sum_is_bigger_than(source_offset, length, source_size)) {
3373 rb_raise(rb_eArgError,
"The computed source range exceeds the size of the source buffer!");
3376 if (length == 0)
return;
3381 .destination = (
unsigned char*)base+offset,
3382 .source = (
unsigned char*)source_base+source_offset,
3386 if (arguments.length >= IO_BUFFER_BLOCKING_SIZE) {
3388 }
else if (arguments.length != 0) {
3389 memmove(arguments.destination, arguments.source, arguments.length);
3394io_buffer_extract_copy_arguments(
size_t source_size,
int argc,
VALUE *argv,
size_t *offset,
size_t *length,
size_t *source_offset)
3398 *offset = io_buffer_extract_offset(argv[0]);
3406 *source_offset = io_buffer_extract_offset(argv[2]);
3408 if (*source_offset > source_size) {
3409 rb_raise(rb_eArgError,
"The given source offset is bigger than the source itself!");
3417 if (argc >= 2 && !
RB_NIL_P(argv[1])) {
3418 *length = io_buffer_extract_length(argv[1]);
3422 *length = source_size - *source_offset;
3428io_buffer_copy_from(
struct rb_io_buffer_view *buffer,
const void *source_base,
size_t source_size,
int argc,
VALUE *argv)
3430 size_t offset, length, source_offset;
3431 io_buffer_extract_copy_arguments(source_size, argc, argv, &offset, &length, &source_offset);
3435 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3437 if (length >= IO_BUFFER_BLOCKING_SIZE) {
3438 io_buffer_lock(buffer);
3441 io_buffer_memmove(base, size, offset, source_base, source_offset, source_size, length);
3443 if (length >= IO_BUFFER_BLOCKING_SIZE) {
3444 io_buffer_unlock(buffer);
3452 const void *source_base;
3463io_buffer_copy_to(
void *base,
size_t size,
VALUE _arguments)
3467 size_t offset, length, source_offset;
3468 io_buffer_extract_copy_arguments(arguments->source_size, arguments->argc, arguments->argv, &offset, &length, &source_offset);
3470 io_buffer_memmove(base, size, offset, arguments->source_base, source_offset, arguments->source_size, length);
3479io_buffer_copy_from_readable(
const void *base,
size_t size,
VALUE _arguments)
3483 arguments->source_base = base;
3484 arguments->source_size = size;
3486 return rb_io_buffer_locked_for_writing(arguments->destination, io_buffer_copy_to, _arguments);
3490io_buffer_initialize_copy_from(
const void *base,
size_t size,
VALUE self)
3493 if (buffer->lock_count) rb_raise(rb_eIOBufferLockedError,
"Cannot initialize locked buffer!");
3494 io_buffer_storage_release(buffer);
3495 io_buffer_storage_initialize(self, buffer, NULL, size, io_flags_for_size(size),
Qnil);
3498 .destination = self,
3499 .source_base = base,
3500 .source_size = size,
3507 return rb_io_buffer_locked_for_writing(self, io_buffer_copy_to, (
VALUE)&arguments);
3528rb_io_buffer_initialize_copy(
VALUE self,
VALUE source)
3530 if (self == source)
return self;
3531 rb_check_frozen(self);
3532 return rb_io_buffer_locked_for_reading(source, io_buffer_initialize_copy_from, self);
3604io_buffer_copy(
int argc,
VALUE *argv,
VALUE self)
3608 VALUE source = argv[0];
3610 .destination = self,
3620 return rb_io_buffer_locked_for_reading(source, io_buffer_copy_from_readable, (
VALUE)&arguments);
3630io_buffer_get_string_locked(
const void *base,
size_t size,
VALUE _arguments)
3633 if (size_sum_is_bigger_than(arguments->offset, arguments->length, size)) {
3634 rb_raise(rb_eArgError,
"Specified offset+length is bigger than the buffer size!");
3636 const char *data = base ? (
const char *)base + arguments->offset : NULL;
3637 return rb_enc_str_new(data, arguments->length, arguments->encoding);
3655io_buffer_get_string(
int argc,
VALUE *argv,
VALUE self)
3660 io_buffer_extract_offset_length(self, argc, argv, &arguments.offset, &arguments.length);
3664 arguments.encoding = argc >= 3 ? rb_find_encoding(argv[2]) : rb_ascii8bit_encoding();
3665 return rb_io_buffer_locked_for_reading(self, io_buffer_get_string_locked, (
VALUE)&arguments);
3692io_buffer_set_string(
int argc,
VALUE *argv,
VALUE self)
3700 const void *source_base = RSTRING_PTR(
string);
3701 size_t source_size = RSTRING_LEN(
string);
3703 VALUE result = io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
3709rb_io_buffer_clear(
VALUE self, uint8_t value,
size_t offset,
size_t length)
3715 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3717 io_buffer_validate_range(buffer, offset, length);
3719 if (length == 0)
return;
3722 memset((
char*)base + offset, value, length);
3757io_buffer_clear(
int argc,
VALUE *argv,
VALUE self)
3766 size_t offset, length;
3767 io_buffer_extract_offset_length(self, argc-1, argv+1, &offset, &length);
3769 rb_io_buffer_clear(self, value, offset, length);
3775io_buffer_default_size(
size_t page_size)
3778 const size_t platform_agnostic_default_size = 64*1024;
3781 const char *default_size = getenv(
"RUBY_IO_BUFFER_DEFAULT_SIZE");
3784 int value = atoi(default_size);
3792 if (platform_agnostic_default_size < page_size) {
3796 return platform_agnostic_default_size;
3802 rb_blocking_function_t *function;
3807io_buffer_blocking_region_begin(
VALUE _argument)
3811 return rb_io_blocking_region(argument->io, argument->function, argument->data);
3815io_buffer_blocking_region_ensure(
VALUE _argument)
3819 io_buffer_unlock(argument->buffer);
3825io_buffer_blocking_region(
VALUE io,
struct rb_io_buffer_view *buffer, rb_blocking_function_t *function,
void *data)
3827 struct rb_io *ioptr;
3833 .function = function,
3840 io_buffer_lock(buffer);
3842 return rb_ensure(io_buffer_blocking_region_begin, (
VALUE)&argument, io_buffer_blocking_region_ensure, (
VALUE)&argument);
3855io_buffer_read_internal(
void *_argument)
3858 ssize_t result = read(argument->descriptor, argument->base, argument->length);
3864rb_io_buffer_read(
VALUE self,
VALUE io,
size_t offset,
size_t length)
3869 io_buffer_validate_range(buffer, offset, length);
3874 if (scheduler !=
Qnil) {
3877 if (!UNDEF_P(result)) {
3882 buffer = get_io_buffer_view_for_writing(self);
3883 io_buffer_validate_range(buffer, offset, length);
3888 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3894 .base = (
char*)base + offset,
3898 return io_buffer_blocking_region(io, buffer, io_buffer_read_internal, &argument);
3925io_buffer_read(
int argc,
VALUE *argv,
VALUE self)
3931 size_t offset, length;
3932 io_buffer_extract_offset_length(self, argc-1, argv+1, &offset, &length);
3934 return rb_io_buffer_read(self, io, offset, length);
3949io_buffer_pread_internal(
void *_argument)
3952 ssize_t result = pread(argument->descriptor, argument->base, argument->length, argument->from);
3958rb_io_buffer_pread(
VALUE self,
VALUE io, rb_off_t from,
size_t offset,
size_t length)
3963 io_buffer_validate_range(buffer, offset, length);
3968 if (scheduler !=
Qnil) {
3971 if (!UNDEF_P(result)) {
3975 buffer = get_io_buffer_view_for_writing(self);
3976 io_buffer_validate_range(buffer, offset, length);
3981 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3987 .base = (
char*)base + offset,
3992 return io_buffer_blocking_region(io, buffer, io_buffer_pread_internal, &argument);
4023io_buffer_pread(
int argc,
VALUE *argv,
VALUE self)
4030 size_t offset, length;
4031 io_buffer_extract_offset_length(self, argc-2, argv+2, &offset, &length);
4033 return rb_io_buffer_pread(self, io, from, offset, length);
4046io_buffer_write_internal(
void *_argument)
4049 ssize_t result = write(argument->descriptor, argument->base, argument->length);
4055rb_io_buffer_write(
VALUE self,
VALUE io,
size_t offset,
size_t length)
4060 io_buffer_validate_range(buffer, offset, length);
4065 if (scheduler !=
Qnil) {
4068 if (!UNDEF_P(result)) {
4072 buffer = get_io_buffer_view(self);
4073 io_buffer_validate_range(buffer, offset, length);
4078 io_buffer_get_bytes_for_reading(buffer, &base, &size);
4084 .base = (
const char*)base + offset,
4088 return io_buffer_blocking_region(io, buffer, io_buffer_write_internal, &argument);
4108io_buffer_write(
int argc,
VALUE *argv,
VALUE self)
4114 size_t offset, length;
4115 io_buffer_extract_offset_length(self, argc-1, argv+1, &offset, &length);
4117 return rb_io_buffer_write(self, io, offset, length);
4132io_buffer_pwrite_internal(
void *_argument)
4135 ssize_t result = pwrite(argument->descriptor, argument->base, argument->length, argument->from);
4141rb_io_buffer_pwrite(
VALUE self,
VALUE io, rb_off_t from,
size_t offset,
size_t length)
4146 io_buffer_validate_range(buffer, offset, length);
4151 if (scheduler !=
Qnil) {
4154 if (!UNDEF_P(result)) {
4158 buffer = get_io_buffer_view(self);
4159 io_buffer_validate_range(buffer, offset, length);
4164 io_buffer_get_bytes_for_reading(buffer, &base, &size);
4170 .base = (
const char*)base + offset,
4175 return io_buffer_blocking_region(io, buffer, io_buffer_pwrite_internal, &argument);
4200io_buffer_pwrite(
int argc,
VALUE *argv,
VALUE self)
4207 size_t offset, length;
4208 io_buffer_extract_offset_length(self, argc-2, argv+2, &offset, &length);
4210 return rb_io_buffer_pwrite(self, io, from, offset, length);
4214io_buffer_check_mask_size(
size_t size)
4217 rb_raise(rb_eIOBufferMaskError,
"Zero-length mask given!");
4221memory_and(
unsigned char * restrict output,
const unsigned char * restrict base,
size_t size,
const unsigned char * restrict mask,
size_t mask_size)
4223 for (
size_t offset = 0; offset < size; offset += 1) {
4224 output[offset] = base[offset] & mask[offset % mask_size];
4249 io_buffer_get_bytes_for_reading(buffer, &base, &size);
4251 const void *mask_base;
4253 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
4255 io_buffer_check_mask_size(mask_size);
4257 VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
4260 memory_and(output_buffer->base, base, size, mask_base, mask_size);
4266memory_or(
unsigned char * restrict output,
const unsigned char * restrict base,
size_t size,
const unsigned char * restrict mask,
size_t mask_size)
4268 for (
size_t offset = 0; offset < size; offset += 1) {
4269 output[offset] = base[offset] | mask[offset % mask_size];
4294 io_buffer_get_bytes_for_reading(buffer, &base, &size);
4296 const void *mask_base;
4298 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
4300 io_buffer_check_mask_size(mask_size);
4302 VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
4305 memory_or(output_buffer->base, base, size, mask_base, mask_size);
4311memory_xor(
unsigned char * restrict output,
const unsigned char * restrict base,
size_t size,
const unsigned char * restrict mask,
size_t mask_size)
4313 for (
size_t offset = 0; offset < size; offset += 1) {
4314 output[offset] = base[offset] ^ mask[offset % mask_size];
4339 io_buffer_get_bytes_for_reading(buffer, &base, &size);
4341 const void *mask_base;
4343 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
4345 io_buffer_check_mask_size(mask_size);
4347 VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
4350 memory_xor(output_buffer->base, base, size, mask_base, mask_size);
4356memory_not(
unsigned char * restrict output,
const unsigned char * restrict base,
size_t size)
4358 for (
size_t offset = 0; offset < size; offset += 1) {
4359 output[offset] = ~base[offset];
4376io_buffer_not(
VALUE self)
4382 io_buffer_get_bytes_for_reading(buffer, &base, &size);
4384 VALUE output = rb_io_buffer_new(NULL, size, io_flags_for_size(size));
4387 memory_not(output_buffer->base, base, size);
4396 void *a_base = NULL, *b_base = NULL;
4397 size_t a_size = 0, b_size = 0;
4398 if (!io_buffer_try_get_bytes(a, &a_base, &a_size))
return 0;
4399 if (!io_buffer_try_get_bytes(b, &b_base, &b_size))
return 0;
4401 if (a_size == 0 || b_size == 0 || a_base == NULL || b_base == NULL)
return 0;
4405 uintptr_t a_start = (uintptr_t)a_base;
4406 uintptr_t b_start = (uintptr_t)b_base;
4407 if (a_start <= b_start)
return b_start - a_start < a_size;
4408 return a_start - b_start < b_size;
4414 if (io_buffer_overlaps(a, b))
4415 rb_raise(rb_eIOBufferMaskError,
"Mask overlaps source buffer!");
4419memory_and_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
4421 for (
size_t offset = 0; offset < size; offset += 1) {
4422 base[offset] &= mask[offset % mask_size];
4450 io_buffer_check_mask_size(mask_buffer->size);
4451 io_buffer_check_overlaps(buffer, mask_buffer);
4455 io_buffer_get_bytes_for_writing(buffer, &base, &size);
4457 const void *mask_base;
4459 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
4461 memory_and_inplace(base, size, (
unsigned char *)mask_base, mask_size);
4467memory_or_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
4469 for (
size_t offset = 0; offset < size; offset += 1) {
4470 base[offset] |= mask[offset % mask_size];
4498 io_buffer_check_mask_size(mask_buffer->size);
4499 io_buffer_check_overlaps(buffer, mask_buffer);
4503 io_buffer_get_bytes_for_writing(buffer, &base, &size);
4505 const void *mask_base;
4507 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
4509 memory_or_inplace(base, size, (
unsigned char *)mask_base, mask_size);
4515memory_xor_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
4517 for (
size_t offset = 0; offset < size; offset += 1) {
4518 base[offset] ^= mask[offset % mask_size];
4546 io_buffer_check_mask_size(mask_buffer->size);
4547 io_buffer_check_overlaps(buffer, mask_buffer);
4551 io_buffer_get_bytes_for_writing(buffer, &base, &size);
4553 const void *mask_base;
4555 io_buffer_get_bytes_for_reading(mask_buffer, &mask_base, &mask_size);
4557 memory_xor_inplace(base, size, (
unsigned char *)mask_base, mask_size);
4563memory_not_inplace(
unsigned char * restrict base,
size_t size)
4565 for (
size_t offset = 0; offset < size; offset += 1) {
4566 base[offset] = ~base[offset];
4588io_buffer_not_inplace(
VALUE self)
4594 io_buffer_get_bytes_for_writing(buffer, &base, &size);
4596 memory_not_inplace(base, size);
4602memory_bit_count(
const unsigned char *base,
size_t size)
4607 const uint64_t *base64 = (
const uint64_t *)base;
4608 size_t count64 = size / 8;
4609 for (
size_t i = 0; i < count64; i += 1) {
4610 count += rb_popcount64(base64[i]);
4614 size_t remaining = size % 8;
4615 const unsigned char *tail = base + (count64 * 8);
4616 for (
size_t i = 0; i < remaining; i += 1) {
4617 count += rb_popcount32(tail[i]);
4637io_buffer_bit_count(
int argc,
VALUE *argv,
VALUE self)
4641 size_t offset, length;
4642 struct rb_io_buffer_view *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
4644 io_buffer_validate_range(buffer, offset, length);
4648 io_buffer_get_bytes_for_reading(buffer, &base, &size);
4653 size_t count = memory_bit_count((
const unsigned char *)base + offset, length);
4665 if (!io_buffer_try_get_bytes(buffer, &base, &size) || base == NULL) {
4669 bool readonly =
true;
4670 if (flags & RUBY_MEMORY_VIEW_WRITABLE) {
4671 if (io_buffer_readonly_p(buffer)) {
4678 if (flags & RUBY_MEMORY_VIEW_FORMAT) {
4681 bool request_multi_dimensional = flags & RUBY_MEMORY_VIEW_MULTI_DIMENSIONAL;
4682 bool request_strides =
4683 (flags & RUBY_MEMORY_VIEW_STRIDES) == RUBY_MEMORY_VIEW_STRIDES;
4684 if (request_multi_dimensional || request_strides) {
4685 size_t n_metadata = 0;
4686 if (request_multi_dimensional)
4688 if (request_strides)
4690 ssize_t *metadata_buffer =
ALLOC_N(ssize_t, n_metadata);
4692 if (request_multi_dimensional) {
4693 ssize_t *shape = &metadata_buffer[i];
4694 shape[0] = buffer->size;
4695 view->shape = shape;
4698 if (request_strides) {
4699 ssize_t *strides = &metadata_buffer[i];
4701 view->strides = strides;
4704 view->private_data = metadata_buffer;
4706 io_buffer_lock(buffer);
4714 rb_io_buffer_unlock(self);
4715 if (
view->private_data) {
4722io_buffer_memory_view_available_p(
VALUE self)
4728 return io_buffer_try_get_bytes(buffer, &base, &size) && base != NULL;
4732 .
get_func = io_buffer_memory_view_get,
4733 .release_func = io_buffer_memory_view_release,
4734 .available_p_func = io_buffer_memory_view_available_p,
4866 rb_cIOBufferStorage = rb_define_class_under(rb_cIOBuffer,
"Storage", rb_cIOBuffer);
4903 rb_cIOBufferSlice = rb_define_class_under(rb_cIOBuffer,
"Slice", rb_cIOBuffer);
4905 rb_define_method(rb_cIOBufferSlice,
"initialize", io_buffer_slice_initialize, -1);
4906 rb_define_method(rb_cIOBufferSlice,
"initialize_copy", io_buffer_slice_initialize_copy, 1);
4909 rb_eIOBufferLockedError = rb_define_class_under(rb_cIOBuffer,
"LockedError",
rb_eRuntimeError);
4912 rb_eIOBufferAllocationError = rb_define_class_under(rb_cIOBuffer,
"AllocationError",
rb_eRuntimeError);
4915 rb_eIOBufferAccessError = rb_define_class_under(rb_cIOBuffer,
"AccessError",
rb_eRuntimeError);
4918 rb_eIOBufferInvalidatedError = rb_define_class_under(rb_cIOBuffer,
"InvalidatedError",
rb_eRuntimeError);
4921 rb_eIOBufferMaskError = rb_define_class_under(rb_cIOBuffer,
"MaskError", rb_eArgError);
4930 GetSystemInfo(&info);
4931 RUBY_IO_BUFFER_PAGE_SIZE = info.dwPageSize;
4932 RUBY_IO_BUFFER_MAP_ALIGNMENT = info.dwAllocationGranularity;
4934 RUBY_IO_BUFFER_PAGE_SIZE = sysconf(_SC_PAGESIZE);
4935 RUBY_IO_BUFFER_MAP_ALIGNMENT = RUBY_IO_BUFFER_PAGE_SIZE;
4938 RUBY_IO_BUFFER_DEFAULT_SIZE = io_buffer_default_size(RUBY_IO_BUFFER_PAGE_SIZE);
4941 rb_define_const(rb_cIOBuffer,
"VERSION",
INT2NUM(RUBY_IO_BUFFER_VERSION));
4944 rb_define_const(rb_cIOBuffer,
"PAGE_SIZE",
SIZET2NUM(RUBY_IO_BUFFER_PAGE_SIZE));
4947 rb_define_const(rb_cIOBuffer,
"MAP_ALIGNMENT",
SIZET2NUM(RUBY_IO_BUFFER_MAP_ALIGNMENT));
4952 rb_define_const(rb_cIOBuffer,
"DEFAULT_SIZE",
SIZET2NUM(RUBY_IO_BUFFER_DEFAULT_SIZE));
4961 rb_define_method(rb_cIOBufferStorage,
"initialize", rb_io_buffer_initialize, -1);
4962 rb_define_method(rb_cIOBufferStorage,
"initialize_copy", rb_io_buffer_initialize_copy, 1);
4972 rb_define_const(rb_cIOBuffer,
"EXTERNAL",
RB_INT2NUM(RB_IO_BUFFER_EXTERNAL));
4975 rb_define_const(rb_cIOBuffer,
"INTERNAL",
RB_INT2NUM(RB_IO_BUFFER_INTERNAL));
4978 rb_define_const(rb_cIOBuffer,
"MAPPED",
RB_INT2NUM(RB_IO_BUFFER_MAPPED));
4981 rb_define_const(rb_cIOBuffer,
"SHARED",
RB_INT2NUM(RB_IO_BUFFER_SHARED));
4984 rb_define_const(rb_cIOBuffer,
"PRIVATE",
RB_INT2NUM(RB_IO_BUFFER_PRIVATE));
4987 rb_define_const(rb_cIOBuffer,
"READONLY",
RB_INT2NUM(RB_IO_BUFFER_READONLY));
4990 rb_define_const(rb_cIOBuffer,
"LITTLE_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_LITTLE_ENDIAN));
4993 rb_define_const(rb_cIOBuffer,
"BIG_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_BIG_ENDIAN));
4996 rb_define_const(rb_cIOBuffer,
"HOST_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_HOST_ENDIAN));
4999 rb_define_const(rb_cIOBuffer,
"NETWORK_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_NETWORK_ENDIAN));
5003 rb_define_method(rb_cIOBufferStorage,
"external?", rb_io_buffer_external_p, 0);
5004 rb_define_method(rb_cIOBufferStorage,
"internal?", rb_io_buffer_internal_p, 0);
5005 rb_define_method(rb_cIOBufferStorage,
"mapped?", rb_io_buffer_mapped_p, 0);
5006 rb_define_method(rb_cIOBufferStorage,
"shared?", rb_io_buffer_shared_p, 0);
5008 rb_define_method(rb_cIOBufferStorage,
"private?", rb_io_buffer_private_p, 0);
5029#define IO_BUFFER_DEFINE_DATA_TYPE(name) RB_IO_BUFFER_DATA_TYPE_##name = rb_intern_const(#name)
5030 IO_BUFFER_DEFINE_DATA_TYPE(U8);
5031 IO_BUFFER_DEFINE_DATA_TYPE(S8);
5033 IO_BUFFER_DEFINE_DATA_TYPE(u16);
5034 IO_BUFFER_DEFINE_DATA_TYPE(U16);
5035 IO_BUFFER_DEFINE_DATA_TYPE(s16);
5036 IO_BUFFER_DEFINE_DATA_TYPE(S16);
5038 IO_BUFFER_DEFINE_DATA_TYPE(u32);
5039 IO_BUFFER_DEFINE_DATA_TYPE(U32);
5040 IO_BUFFER_DEFINE_DATA_TYPE(s32);
5041 IO_BUFFER_DEFINE_DATA_TYPE(S32);
5043 IO_BUFFER_DEFINE_DATA_TYPE(u64);
5044 IO_BUFFER_DEFINE_DATA_TYPE(U64);
5045 IO_BUFFER_DEFINE_DATA_TYPE(s64);
5046 IO_BUFFER_DEFINE_DATA_TYPE(S64);
5048 IO_BUFFER_DEFINE_DATA_TYPE(u128);
5049 IO_BUFFER_DEFINE_DATA_TYPE(U128);
5050 IO_BUFFER_DEFINE_DATA_TYPE(s128);
5051 IO_BUFFER_DEFINE_DATA_TYPE(S128);
5053 IO_BUFFER_DEFINE_DATA_TYPE(f32);
5054 IO_BUFFER_DEFINE_DATA_TYPE(F32);
5055 IO_BUFFER_DEFINE_DATA_TYPE(f64);
5056 IO_BUFFER_DEFINE_DATA_TYPE(F64);
5057#undef IO_BUFFER_DEFINE_DATA_TYPE
std::string_view view(const pm_buffer_t *buffer PRISM_LIFETIMEBOUND) noexcept
The bytes written to the given buffer so far.
#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.
VALUE rb_singleton_class(VALUE obj)
Finds or creates the singleton class of the passed object.
void rb_undef_method(VALUE klass, const char *name)
Defines an undef of a method.
int rb_block_given_p(void)
Determines if the current method is given a block.
#define T_STRING
Old name of RUBY_T_STRING.
#define xfree
Old name of ruby_xfree.
#define INT2FIX
Old name of RB_INT2FIX.
#define OBJ_FROZEN
Old name of RB_OBJ_FROZEN.
#define rb_str_cat2
Old name of rb_str_cat_cstr.
#define CLASS_OF
Old name of rb_class_of.
#define SIZET2NUM
Old name of RB_SIZE2NUM.
#define NUM2UINT
Old name of RB_NUM2UINT.
#define STATIC_SYM_P
Old name of RB_STATIC_SYM_P.
#define ALLOC_N
Old name of RB_ALLOC_N.
#define NUM2DBL
Old name of rb_num2dbl.
#define INT2NUM
Old name of RB_INT2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#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.
VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_splat)
Identical to rb_class_new_instance(), except you can specify how to handle the last element of the gi...
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_class_inherited_p(VALUE scion, VALUE ascendant)
Determines if the given two modules are relatives.
VALUE rb_mComparable
Comparable module.
#define RB_OBJ_WRITE(old, slot, young)
Declaration of a "back" pointer.
#define RUBY_ASSERT(...)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length)
Non-blocking read from the passed IO.
VALUE rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t offset, size_t length)
Non-blocking write to the passed IO at the specified offset.
static VALUE rb_fiber_scheduler_io_result(ssize_t result, int error)
Wrap a ssize_t and int errno into a single VALUE.
VALUE rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t offset, size_t length)
Non-blocking read from the passed IO at the specified offset.
VALUE rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length)
Non-blocking write to the passed IO.
VALUE rb_ary_entry(VALUE ary, rb_len_t off)
Queries an element of an array.
VALUE rb_ary_new_capa(rb_len_t 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.
#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_new_frozen(VALUE str)
Creates a frozen copy of the string, if necessary.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_buf_new(rb_len_t capa)
Allocates a "string buffer".
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_undef_alloc_func(VALUE klass)
Deletes the allocator function of a 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_NUM2LEN
Converts an instance of rb_cNumeric into rb_len_t.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
bool rb_memory_view_register(VALUE klass, const rb_memory_view_entry_t *entry)
Associates the passed class with the passed memory view entry.
bool rb_memory_view_init_as_byte_array(rb_memory_view_t *view, VALUE obj, void *data, const ssize_t len, const bool readonly)
Fill the members of view as an 1-dimensional byte array.
VALUE type(ANYARGS)
ANYARGS-ed function type.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define OFFT2NUM
Converts a C's off_t into an instance of rb_cInteger.
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
std::string_view slice(const pm_parser_t *parser PRISM_LIFETIMEBOUND, pm_location_t location) noexcept
The bytes of source that the given location covers.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_AREF(a, i)
References an object in an array.
#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_PASS_CALLED_KEYWORDS
Pass keywords if current method is called with keywords, useful for argument delegation.
#define RB_NO_KEYWORDS
Do not pass keywords.
static bool RB_NIL_P(VALUE obj)
Checks if the given object is nil.
#define RTEST
This is an old name of RB_TEST.
This is the struct that holds necessary info for a struct.
const char * wrap_struct_name
Name of structs of this kind.
Ruby's IO, metadata and buffers.
Operations applied to a specific kind of a memory view.
rb_memory_view_get_func_t get_func
Exports a memory view from a Ruby object.
A MemoryView structure, rb_memory_view_t, is used for exporting objects' MemoryView.
long rb_len_t
A signed integer type for lengths and indices of objects such as String and Array.
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.