16#include "internal/array.h"
17#include "internal/bits.h"
18#include "internal/error.h"
19#include "internal/gc.h"
20#include "internal/numeric.h"
21#include "internal/string.h"
22#include "internal/io.h"
25VALUE rb_eIOBufferLockedError;
26VALUE rb_eIOBufferAllocationError;
27VALUE rb_eIOBufferAccessError;
28VALUE rb_eIOBufferInvalidatedError;
29VALUE rb_eIOBufferMaskError;
31size_t RUBY_IO_BUFFER_PAGE_SIZE;
32size_t RUBY_IO_BUFFER_DEFAULT_SIZE;
41 RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH = 16,
43 RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE = 256,
44 RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH = 16,
47 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,
49 RB_IO_BUFFER_DEBUG = 0,
55 enum rb_io_buffer_flags flags;
65io_buffer_map_memory(
size_t size,
int flags)
68 void * base = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
71 rb_sys_fail(
"io_buffer_map_memory:VirtualAlloc");
74 int mmap_flags = MAP_ANONYMOUS;
75 if (flags & RB_IO_BUFFER_SHARED) {
76 mmap_flags |= MAP_SHARED;
79 mmap_flags |= MAP_PRIVATE;
82 void * base = mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
84 if (base == MAP_FAILED) {
85 rb_sys_fail(
"io_buffer_map_memory:mmap");
88 ruby_annotate_mmap(base, size,
"Ruby:io_buffer_map_memory");
95io_buffer_map_file(
struct rb_io_buffer *buffer,
int descriptor,
size_t size, rb_off_t offset,
enum rb_io_buffer_flags flags)
98 HANDLE file = (HANDLE)_get_osfhandle(descriptor);
99 if (!file) rb_sys_fail(
"io_buffer_map_descriptor:_get_osfhandle");
101 DWORD protect = PAGE_READONLY, access = FILE_MAP_READ;
103 if (flags & RB_IO_BUFFER_READONLY) {
104 buffer->flags |= RB_IO_BUFFER_READONLY;
107 protect = PAGE_READWRITE;
108 access = FILE_MAP_WRITE;
111 if (flags & RB_IO_BUFFER_PRIVATE) {
112 protect = PAGE_WRITECOPY;
113 access = FILE_MAP_COPY;
114 buffer->flags |= RB_IO_BUFFER_PRIVATE;
118 buffer->flags |= RB_IO_BUFFER_EXTERNAL;
119 buffer->flags |= RB_IO_BUFFER_SHARED;
122 HANDLE mapping = CreateFileMapping(file, NULL, protect, 0, 0, NULL);
123 if (RB_IO_BUFFER_DEBUG) fprintf(stderr,
"io_buffer_map_file:CreateFileMapping -> %p\n", mapping);
124 if (!mapping) rb_sys_fail(
"io_buffer_map_descriptor:CreateFileMapping");
126 void *base = MapViewOfFile(mapping, access, (DWORD)(offset >> 32), (DWORD)(offset & 0xFFFFFFFF), size);
129 CloseHandle(mapping);
130 rb_sys_fail(
"io_buffer_map_file:MapViewOfFile");
133 buffer->mapping = mapping;
135 int protect = PROT_READ, access = 0;
137 if (flags & RB_IO_BUFFER_READONLY) {
138 buffer->flags |= RB_IO_BUFFER_READONLY;
141 protect |= PROT_WRITE;
144 if (flags & RB_IO_BUFFER_PRIVATE) {
145 buffer->flags |= RB_IO_BUFFER_PRIVATE;
146 access |= MAP_PRIVATE;
150 buffer->flags |= RB_IO_BUFFER_EXTERNAL;
151 buffer->flags |= RB_IO_BUFFER_SHARED;
152 access |= MAP_SHARED;
155 void *base = mmap(NULL, size, protect, access, descriptor, offset);
157 if (base == MAP_FAILED) {
158 rb_sys_fail(
"io_buffer_map_file:mmap");
165 buffer->flags |= RB_IO_BUFFER_MAPPED;
166 buffer->flags |= RB_IO_BUFFER_FILE;
170io_buffer_experimental(
void)
172 static int warned = 0;
180 "IO::Buffer is experimental and both the Ruby and C interface may change in the future!"
191 buffer->mapping = NULL;
193 buffer->source =
Qnil;
197io_buffer_initialize(
VALUE self,
struct rb_io_buffer *buffer,
void *base,
size_t size,
enum rb_io_buffer_flags flags,
VALUE source)
204 if (flags & RB_IO_BUFFER_INTERNAL) {
205 base = calloc(size, 1);
207 else if (flags & RB_IO_BUFFER_MAPPED) {
208 base = io_buffer_map_memory(size, flags);
212 rb_raise(rb_eIOBufferAllocationError,
"Could not allocate buffer!");
222 buffer->flags = flags;
226 buffer->mapping = NULL;
234 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
238 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
240 if (buffer->flags & RB_IO_BUFFER_FILE) {
241 UnmapViewOfFile(buffer->base);
244 VirtualFree(buffer->base, 0, MEM_RELEASE);
247 munmap(buffer->base, buffer->size);
261 buffer->source =
Qnil;
265 if (buffer->mapping) {
266 if (RB_IO_BUFFER_DEBUG) fprintf(stderr,
"io_buffer_free:CloseHandle -> %p\n", buffer->mapping);
267 if (!CloseHandle(buffer->mapping)) {
268 fprintf(stderr,
"io_buffer_free:GetLastError -> %lu\n", GetLastError());
270 buffer->mapping = NULL;
276rb_io_buffer_type_mark(
void *_buffer)
279 if (buffer->source !=
Qnil) {
283 rb_gc_mark(buffer->source);
285 rb_gc_mark_movable(buffer->source);
291rb_io_buffer_type_compact(
void *_buffer)
294 if (buffer->source !=
Qnil) {
299 buffer->source = rb_gc_location(buffer->source);
305rb_io_buffer_type_free(
void *_buffer)
309 io_buffer_free(buffer);
313rb_io_buffer_type_size(
const void *_buffer)
319 total += buffer->size;
328 .dmark = rb_io_buffer_type_mark,
329 .dfree = rb_io_buffer_type_free,
330 .dsize = rb_io_buffer_type_size,
331 .dcompact = rb_io_buffer_type_compact,
334 .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
337static inline enum rb_io_buffer_flags
338io_buffer_extract_flags(
VALUE argument)
340 if (rb_int_negative_p(argument)) {
341 rb_raise(rb_eArgError,
"Flags can't be negative!");
344 enum rb_io_buffer_flags flags =
RB_NUM2UINT(argument);
347 return flags & RB_IO_BUFFER_FLAGS_MASK;
352io_buffer_extract_offset(
VALUE argument)
354 if (rb_int_negative_p(argument)) {
355 rb_raise(rb_eArgError,
"Offset can't be negative!");
365io_buffer_extract_length(
VALUE argument)
367 if (rb_int_negative_p(argument)) {
368 rb_raise(rb_eArgError,
"Length can't be negative!");
377io_buffer_extract_size(
VALUE argument)
379 if (rb_int_negative_p(argument)) {
380 rb_raise(rb_eArgError,
"Size can't be negative!");
389io_buffer_extract_width(
VALUE argument,
size_t minimum)
391 if (rb_int_negative_p(argument)) {
392 rb_raise(rb_eArgError,
"Width can't be negative!");
397 if (width < minimum) {
398 rb_raise(rb_eArgError,
"Width must be at least %" PRIuSIZE
"!", minimum);
409io_buffer_default_length(
const struct rb_io_buffer *buffer,
size_t offset)
411 if (offset > buffer->size) {
412 rb_raise(rb_eArgError,
"The given offset is bigger than the buffer size!");
416 return buffer->size - offset;
425io_buffer_extract_length_offset(
VALUE self,
int argc,
VALUE argv[],
size_t *length,
size_t *offset)
430 if (argc >= 2 && !
NIL_P(argv[1])) {
431 *offset = io_buffer_extract_offset(argv[1]);
437 if (argc >= 1 && !
NIL_P(argv[0])) {
438 *length = io_buffer_extract_length(argv[0]);
441 *length = io_buffer_default_length(buffer, *offset);
457io_buffer_extract_offset_length(
VALUE self,
int argc,
VALUE argv[],
size_t *offset,
size_t *length)
462 if (argc >= 1 && !
NIL_P(argv[0])) {
463 *offset = io_buffer_extract_offset(argv[0]);
469 if (argc >= 2 && !
NIL_P(argv[1])) {
470 *length = io_buffer_extract_length(argv[1]);
473 *length = io_buffer_default_length(buffer, *offset);
480rb_io_buffer_type_allocate(
VALUE self)
485 io_buffer_zero(buffer);
490static VALUE io_buffer_for_make_instance(
VALUE klass,
VALUE string,
enum rb_io_buffer_flags flags)
492 VALUE instance = rb_io_buffer_type_allocate(klass);
497 flags |= RB_IO_BUFFER_EXTERNAL;
500 flags |= RB_IO_BUFFER_READONLY;
502 if (!(flags & RB_IO_BUFFER_READONLY))
503 rb_str_modify(
string);
505 io_buffer_initialize(instance, buffer, RSTRING_PTR(
string), RSTRING_LEN(
string), flags,
string);
514 enum rb_io_buffer_flags flags;
518io_buffer_for_yield_instance(
VALUE _arguments)
522 arguments->instance = io_buffer_for_make_instance(arguments->klass, arguments->string, arguments->flags);
528 return rb_yield(arguments->instance);
532io_buffer_for_yield_instance_ensure(
VALUE _arguments)
536 if (arguments->instance !=
Qnil) {
537 rb_io_buffer_free(arguments->instance);
584rb_io_buffer_type_for(
VALUE klass,
VALUE string)
598 return rb_ensure(io_buffer_for_yield_instance, (
VALUE)&arguments, io_buffer_for_yield_instance_ensure, (
VALUE)&arguments);
602 string = rb_str_tmp_frozen_acquire(
string);
603 return io_buffer_for_make_instance(klass,
string, RB_IO_BUFFER_READONLY);
621rb_io_buffer_type_string(
VALUE klass,
VALUE length)
631 rb_ensure(io_buffer_for_yield_instance, (
VALUE)&arguments, io_buffer_for_yield_instance_ensure, (
VALUE)&arguments);
637rb_io_buffer_new(
void *base,
size_t size,
enum rb_io_buffer_flags flags)
639 VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
644 io_buffer_initialize(instance, buffer, base, size, flags,
Qnil);
650rb_io_buffer_map(
VALUE io,
size_t size, rb_off_t offset,
enum rb_io_buffer_flags flags)
652 io_buffer_experimental();
654 VALUE instance = rb_io_buffer_type_allocate(rb_cIOBuffer);
661 io_buffer_map_file(buffer, descriptor, size, offset, flags);
711io_buffer_map(
int argc,
VALUE *argv,
VALUE klass)
718 rb_off_t file_size = rb_file_size(io);
720 if (UNLIKELY(file_size <= 0)) {
721 rb_raise(rb_eArgError,
"Invalid negative or zero file size!");
724 else if (UNLIKELY((uintmax_t)file_size > SIZE_MAX)) {
725 rb_raise(rb_eArgError,
"File larger than address space!");
729 if (argc >= 2 && !
RB_NIL_P(argv[1])) {
730 size = io_buffer_extract_size(argv[1]);
731 if (UNLIKELY(size == 0)) {
732 rb_raise(rb_eArgError,
"Size can't be zero!");
734 if (UNLIKELY(size > (
size_t)file_size)) {
735 rb_raise(rb_eArgError,
"Size can't be larger than file size!");
740 size = (size_t)file_size;
747 if (UNLIKELY(offset < 0)) {
748 rb_raise(rb_eArgError,
"Offset can't be negative!");
750 if (UNLIKELY(offset >= file_size)) {
751 rb_raise(rb_eArgError,
"Offset too large!");
755 size = (size_t)(file_size - offset);
757 else if (UNLIKELY((
size_t)(file_size - offset) < size)) {
758 rb_raise(rb_eArgError,
"Offset too large!");
762 enum rb_io_buffer_flags flags = 0;
764 flags = io_buffer_extract_flags(argv[3]);
767 return rb_io_buffer_map(io, size, offset, flags);
771static inline enum rb_io_buffer_flags
772io_flags_for_size(
size_t size)
774 if (size >= RUBY_IO_BUFFER_PAGE_SIZE) {
775 return RB_IO_BUFFER_MAPPED;
778 return RB_IO_BUFFER_INTERNAL;
806rb_io_buffer_initialize(
int argc,
VALUE *argv,
VALUE self)
808 io_buffer_experimental();
817 size = io_buffer_extract_size(argv[0]);
820 size = RUBY_IO_BUFFER_DEFAULT_SIZE;
823 enum rb_io_buffer_flags flags = 0;
825 flags = io_buffer_extract_flags(argv[1]);
828 flags |= io_flags_for_size(size);
831 io_buffer_initialize(self, buffer, NULL, size, flags,
Qnil);
837io_buffer_validate_slice(
VALUE source,
void *base,
size_t size)
839 void *source_base = NULL;
840 size_t source_size = 0;
846 rb_io_buffer_get_bytes(source, &source_base, &source_size);
850 if (source_base == NULL)
return 0;
853 if (base < source_base)
return 0;
855 const void *source_end = (
char*)source_base + source_size;
856 const void *end = (
char*)base + size;
859 if (end > source_end)
return 0;
868 if (buffer->source !=
Qnil) {
870 return io_buffer_validate_slice(buffer->source, buffer->base, buffer->size);
877enum rb_io_buffer_flags
878rb_io_buffer_get_bytes(
VALUE self,
void **base,
size_t *size)
883 if (io_buffer_validate(buffer)) {
885 *base = buffer->base;
886 *size = buffer->size;
888 return buffer->flags;
900io_buffer_get_bytes_for_writing(
struct rb_io_buffer *buffer,
void **base,
size_t *size)
902 if (buffer->flags & RB_IO_BUFFER_READONLY ||
904 rb_raise(rb_eIOBufferAccessError,
"Buffer is not writable!");
907 if (!io_buffer_validate(buffer)) {
908 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer is invalid!");
912 *base = buffer->base;
913 *size = buffer->size;
921rb_io_buffer_get_bytes_for_writing(
VALUE self,
void **base,
size_t *size)
926 io_buffer_get_bytes_for_writing(buffer, base, size);
930io_buffer_get_bytes_for_reading(
struct rb_io_buffer *buffer,
const void **base,
size_t *size)
932 if (!io_buffer_validate(buffer)) {
933 rb_raise(rb_eIOBufferInvalidatedError,
"Buffer has been invalidated!");
937 *base = buffer->base;
938 *size = buffer->size;
946rb_io_buffer_get_bytes_for_reading(
VALUE self,
const void **base,
size_t *size)
951 io_buffer_get_bytes_for_reading(buffer, base, size);
964rb_io_buffer_to_s(
VALUE self)
972 rb_str_catf(result,
" %p+%"PRIdSIZE, buffer->base, buffer->size);
974 if (buffer->base == NULL) {
978 if (buffer->flags & RB_IO_BUFFER_EXTERNAL) {
982 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
986 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
990 if (buffer->flags & RB_IO_BUFFER_FILE) {
994 if (buffer->flags & RB_IO_BUFFER_SHARED) {
998 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1002 if (buffer->flags & RB_IO_BUFFER_PRIVATE) {
1006 if (buffer->flags & RB_IO_BUFFER_READONLY) {
1010 if (buffer->source !=
Qnil) {
1014 if (!io_buffer_validate(buffer)) {
1024io_buffer_hexdump_output_size(
size_t width,
size_t size,
int first)
1027 size_t total = size;
1029 size_t whole_lines = (size / width);
1030 size_t partial_line = (size % width) ? 1 : 0;
1035 total += (whole_lines + partial_line) * (1 + 10 + width*3 + 1 + 1);
1038 if (size && first) total -= 1;
1047io_buffer_hexdump(
VALUE string,
size_t width,
const char *base,
size_t length,
size_t offset,
int first)
1049 char *text = alloca(width+1);
1052 for (; offset < length; offset += width) {
1053 memset(text,
'\0', width);
1055 rb_str_catf(
string,
"0x%08" PRIxSIZE
" ", offset);
1059 rb_str_catf(
string,
"\n0x%08" PRIxSIZE
" ", offset);
1062 for (
size_t i = 0; i < width; i += 1) {
1063 if (offset+i < length) {
1064 unsigned char value = ((
unsigned char*)base)[offset+i];
1066 if (value < 127 && isprint(value)) {
1067 text[i] = (char)value;
1073 rb_str_catf(
string,
" %02x", value);
1080 rb_str_catf(
string,
" %s", text);
1099rb_io_buffer_inspect(
VALUE self)
1104 VALUE result = rb_io_buffer_to_s(self);
1106 if (io_buffer_validate(buffer)) {
1108 size_t size = buffer->size;
1111 if (size > RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE) {
1112 size = RB_IO_BUFFER_INSPECT_HEXDUMP_MAXIMUM_SIZE;
1116 io_buffer_hexdump(result, RB_IO_BUFFER_INSPECT_HEXDUMP_WIDTH, buffer->base, size, 0, 0);
1119 rb_str_catf(result,
"\n(and %" PRIuSIZE
" more bytes not printed)", buffer->size - size);
1133rb_io_buffer_size(
VALUE self)
1150rb_io_buffer_valid_p(
VALUE self)
1155 return RBOOL(io_buffer_validate(buffer));
1173rb_io_buffer_null_p(
VALUE self)
1178 return RBOOL(buffer->base == NULL);
1189rb_io_buffer_empty_p(
VALUE self)
1194 return RBOOL(buffer->size == 0);
1209rb_io_buffer_external_p(
VALUE self)
1214 return RBOOL(buffer->flags & RB_IO_BUFFER_EXTERNAL);
1234rb_io_buffer_internal_p(
VALUE self)
1239 return RBOOL(buffer->flags & RB_IO_BUFFER_INTERNAL);
1256rb_io_buffer_mapped_p(
VALUE self)
1261 return RBOOL(buffer->flags & RB_IO_BUFFER_MAPPED);
1288rb_io_buffer_shared_p(
VALUE self)
1293 return RBOOL(buffer->flags & RB_IO_BUFFER_SHARED);
1311rb_io_buffer_locked_p(
VALUE self)
1316 return RBOOL(buffer->flags & RB_IO_BUFFER_LOCKED);
1342rb_io_buffer_private_p(
VALUE self)
1347 return RBOOL(buffer->flags & RB_IO_BUFFER_PRIVATE);
1351rb_io_buffer_readonly_p(
VALUE self)
1356 return buffer->flags & RB_IO_BUFFER_READONLY;
1368io_buffer_readonly_p(
VALUE self)
1370 return RBOOL(rb_io_buffer_readonly_p(self));
1376 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1377 rb_raise(rb_eIOBufferLockedError,
"Buffer already locked!");
1380 buffer->flags |= RB_IO_BUFFER_LOCKED;
1384rb_io_buffer_lock(
VALUE self)
1389 io_buffer_lock(buffer);
1397 if (!(buffer->flags & RB_IO_BUFFER_LOCKED)) {
1398 rb_raise(rb_eIOBufferLockedError,
"Buffer not locked!");
1401 buffer->flags &= ~RB_IO_BUFFER_LOCKED;
1405rb_io_buffer_unlock(
VALUE self)
1410 io_buffer_unlock(buffer);
1416rb_io_buffer_try_unlock(
VALUE self)
1421 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1422 buffer->flags &= ~RB_IO_BUFFER_LOCKED;
1460rb_io_buffer_locked(
VALUE self)
1465 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1466 rb_raise(rb_eIOBufferLockedError,
"Buffer already locked!");
1469 buffer->flags |= RB_IO_BUFFER_LOCKED;
1473 buffer->flags &= ~RB_IO_BUFFER_LOCKED;
1504rb_io_buffer_free(
VALUE self)
1509 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1510 rb_raise(rb_eIOBufferLockedError,
"Buffer is locked!");
1513 io_buffer_free(buffer);
1523 io_buffer_unlock(buffer);
1524 io_buffer_free(buffer);
1532io_buffer_validate_range(
struct rb_io_buffer *buffer,
size_t offset,
size_t length)
1535 if (offset + length > buffer->size) {
1536 rb_raise(rb_eArgError,
"Specified offset+length is bigger than the buffer size!");
1557rb_io_buffer_hexdump(
int argc,
VALUE *argv,
VALUE self)
1561 size_t offset, length;
1562 struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
1564 size_t width = RB_IO_BUFFER_HEXDUMP_DEFAULT_WIDTH;
1566 width = io_buffer_extract_width(argv[2], 1);
1570 io_buffer_validate_range(buffer, offset, length);
1574 if (io_buffer_validate(buffer) && buffer->base) {
1575 result =
rb_str_buf_new(io_buffer_hexdump_output_size(width, length, 1));
1577 io_buffer_hexdump(result, width, buffer->base, offset+length, offset, 1);
1584rb_io_buffer_slice(
struct rb_io_buffer *buffer,
VALUE self,
size_t offset,
size_t length)
1586 io_buffer_validate_range(buffer, offset, length);
1592 slice->flags |= (buffer->flags & RB_IO_BUFFER_READONLY);
1593 slice->base = (
char*)buffer->base + offset;
1594 slice->size = length;
1597 if (buffer->source !=
Qnil) {
1598 RB_OBJ_WRITE(instance, &slice->source, buffer->source);
1658io_buffer_slice(
int argc,
VALUE *argv,
VALUE self)
1662 size_t offset, length;
1663 struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
1665 return rb_io_buffer_slice(buffer, self, offset, length);
1687rb_io_buffer_transfer(
VALUE self)
1692 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1693 rb_raise(rb_eIOBufferLockedError,
"Cannot transfer ownership of locked buffer!");
1700 *transferred = *buffer;
1701 io_buffer_zero(buffer);
1707io_buffer_resize_clear(
struct rb_io_buffer *buffer,
void* base,
size_t size)
1709 if (size > buffer->size) {
1710 memset((
unsigned char*)base+buffer->size, 0, size - buffer->size);
1719 io_buffer_initialize(self, &resized, NULL, size, io_flags_for_size(size),
Qnil);
1722 size_t preserve = buffer->size;
1723 if (preserve > size) preserve = size;
1724 memcpy(resized.base, buffer->base, preserve);
1726 io_buffer_resize_clear(buffer, resized.base, size);
1729 io_buffer_free(buffer);
1734rb_io_buffer_resize(
VALUE self,
size_t size)
1739 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
1740 rb_raise(rb_eIOBufferLockedError,
"Cannot resize locked buffer!");
1743 if (buffer->base == NULL) {
1744 io_buffer_initialize(self, buffer, NULL, size, io_flags_for_size(size),
Qnil);
1748 if (buffer->flags & RB_IO_BUFFER_EXTERNAL) {
1749 rb_raise(rb_eIOBufferAccessError,
"Cannot resize external buffer!");
1752#if defined(HAVE_MREMAP) && defined(MREMAP_MAYMOVE)
1753 if (buffer->flags & RB_IO_BUFFER_MAPPED) {
1754 void *base = mremap(buffer->base, buffer->size, size, MREMAP_MAYMOVE);
1756 if (base == MAP_FAILED) {
1757 rb_sys_fail(
"rb_io_buffer_resize:mremap");
1760 io_buffer_resize_clear(buffer, base, size);
1762 buffer->base = base;
1763 buffer->size = size;
1769 if (buffer->flags & RB_IO_BUFFER_INTERNAL) {
1771 io_buffer_free(buffer);
1775 void *base = realloc(buffer->base, size);
1778 rb_sys_fail(
"rb_io_buffer_resize:realloc");
1781 io_buffer_resize_clear(buffer, base, size);
1783 buffer->base = base;
1784 buffer->size = size;
1789 io_buffer_resize_copy(self, buffer, size);
1813 rb_io_buffer_resize(self, io_buffer_extract_size(size));
1827 const void *ptr1, *ptr2;
1828 size_t size1, size2;
1830 rb_io_buffer_get_bytes_for_reading(self, &ptr1, &size1);
1831 rb_io_buffer_get_bytes_for_reading(other, &ptr2, &size2);
1833 if (size1 < size2) {
1837 if (size1 > size2) {
1841 return RB_INT2NUM(memcmp(ptr1, ptr2, size1));
1845io_buffer_validate_type(
size_t size,
size_t offset)
1847 if (offset > size) {
1848 rb_raise(rb_eArgError,
"Type extends beyond end of buffer! (offset=%"PRIdSIZE
" > size=%"PRIdSIZE
")", offset, size);
1873#define ruby_swap8(value) value
1881ruby_swapf32(
float value)
1883 union swapf32 swap = {.value = value};
1884 swap.integral = ruby_swap32(swap.integral);
1894ruby_swapf64(
double value)
1896 union swapf64 swap = {.value = value};
1897 swap.integral = ruby_swap64(swap.integral);
1909#ifdef HAVE_UINT128_T
1910#if __has_builtin(__builtin_bswap128)
1911 result.value = __builtin_bswap128(x.value);
1914 uint64_t low = (uint64_t)x.value;
1915 uint64_t high = (uint64_t)(x.value >> 64);
1916 low = ruby_swap64(low);
1917 high = ruby_swap64(high);
1918 result.value = ((uint128_t)low << 64) | high;
1925 result.parts.low = ruby_swap64(x.parts.high);
1926 result.parts.high = ruby_swap64(x.parts.low);
1937 conversion.uint128 = ruby_swap128_uint(conversion.uint128);
1938 return conversion.int128;
1941#define IO_BUFFER_DECLARE_TYPE(name, type, endian, wrap, unwrap, swap) \
1942static ID RB_IO_BUFFER_DATA_TYPE_##name; \
1945io_buffer_read_##name(const void* base, size_t size, size_t *offset) \
1947 io_buffer_validate_type(size, *offset + sizeof(type)); \
1949 memcpy(&value, (char*)base + *offset, sizeof(type)); \
1950 if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
1951 *offset += sizeof(type); \
1952 return wrap(value); \
1956io_buffer_write_##name(const void* base, size_t size, size_t *offset, VALUE _value) \
1958 io_buffer_validate_type(size, *offset + sizeof(type)); \
1959 type value = unwrap(_value); \
1960 if (endian != RB_IO_BUFFER_HOST_ENDIAN) value = swap(value); \
1961 memcpy((char*)base + *offset, &value, sizeof(type)); \
1962 *offset += sizeof(type); \
1966 RB_IO_BUFFER_DATA_TYPE_##name##_SIZE = sizeof(type) \
1974IO_BUFFER_DECLARE_TYPE(s16, int16_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap16)
1975IO_BUFFER_DECLARE_TYPE(S16, int16_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap16)
1979IO_BUFFER_DECLARE_TYPE(s32, int32_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap32)
1980IO_BUFFER_DECLARE_TYPE(S32, int32_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_INT2NUM,
RB_NUM2INT, ruby_swap32)
1982IO_BUFFER_DECLARE_TYPE(u64, uint64_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_ULL2NUM,
RB_NUM2ULL, ruby_swap64)
1983IO_BUFFER_DECLARE_TYPE(U64, uint64_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_ULL2NUM,
RB_NUM2ULL, ruby_swap64)
1984IO_BUFFER_DECLARE_TYPE(s64, int64_t, RB_IO_BUFFER_LITTLE_ENDIAN,
RB_LL2NUM,
RB_NUM2LL, ruby_swap64)
1985IO_BUFFER_DECLARE_TYPE(S64, int64_t, RB_IO_BUFFER_BIG_ENDIAN,
RB_LL2NUM,
RB_NUM2LL, ruby_swap64)
1987IO_BUFFER_DECLARE_TYPE(u128,
rb_uint128_t, RB_IO_BUFFER_LITTLE_ENDIAN, rb_uint128_to_numeric, rb_numeric_to_uint128, ruby_swap128_uint)
1988IO_BUFFER_DECLARE_TYPE(U128,
rb_uint128_t, RB_IO_BUFFER_BIG_ENDIAN, rb_uint128_to_numeric, rb_numeric_to_uint128, ruby_swap128_uint)
1989IO_BUFFER_DECLARE_TYPE(s128,
rb_int128_t, RB_IO_BUFFER_LITTLE_ENDIAN, rb_int128_to_numeric, rb_numeric_to_int128, ruby_swap128_int)
1990IO_BUFFER_DECLARE_TYPE(S128,
rb_int128_t, RB_IO_BUFFER_BIG_ENDIAN, rb_int128_to_numeric, rb_numeric_to_int128, ruby_swap128_int)
1992IO_BUFFER_DECLARE_TYPE(f32,
float, RB_IO_BUFFER_LITTLE_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf32)
1993IO_BUFFER_DECLARE_TYPE(F32,
float, RB_IO_BUFFER_BIG_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf32)
1994IO_BUFFER_DECLARE_TYPE(f64,
double, RB_IO_BUFFER_LITTLE_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf64)
1995IO_BUFFER_DECLARE_TYPE(F64,
double, RB_IO_BUFFER_BIG_ENDIAN,
DBL2NUM,
NUM2DBL, ruby_swapf64)
1996#undef IO_BUFFER_DECLARE_TYPE
1999io_buffer_buffer_type_size(
ID buffer_type)
2001#define IO_BUFFER_DATA_TYPE_SIZE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) return RB_IO_BUFFER_DATA_TYPE_##name##_SIZE;
2002 IO_BUFFER_DATA_TYPE_SIZE(U8)
2003 IO_BUFFER_DATA_TYPE_SIZE(S8)
2004 IO_BUFFER_DATA_TYPE_SIZE(u16)
2005 IO_BUFFER_DATA_TYPE_SIZE(U16)
2006 IO_BUFFER_DATA_TYPE_SIZE(s16)
2007 IO_BUFFER_DATA_TYPE_SIZE(S16)
2008 IO_BUFFER_DATA_TYPE_SIZE(u32)
2009 IO_BUFFER_DATA_TYPE_SIZE(U32)
2010 IO_BUFFER_DATA_TYPE_SIZE(s32)
2011 IO_BUFFER_DATA_TYPE_SIZE(S32)
2012 IO_BUFFER_DATA_TYPE_SIZE(u64)
2013 IO_BUFFER_DATA_TYPE_SIZE(U64)
2014 IO_BUFFER_DATA_TYPE_SIZE(s64)
2015 IO_BUFFER_DATA_TYPE_SIZE(S64)
2016 IO_BUFFER_DATA_TYPE_SIZE(u128)
2017 IO_BUFFER_DATA_TYPE_SIZE(U128)
2018 IO_BUFFER_DATA_TYPE_SIZE(s128)
2019 IO_BUFFER_DATA_TYPE_SIZE(S128)
2020 IO_BUFFER_DATA_TYPE_SIZE(f32)
2021 IO_BUFFER_DATA_TYPE_SIZE(F32)
2022 IO_BUFFER_DATA_TYPE_SIZE(f64)
2023 IO_BUFFER_DATA_TYPE_SIZE(F64)
2024#undef IO_BUFFER_DATA_TYPE_SIZE
2026 rb_raise(rb_eArgError,
"Invalid type name!");
2040io_buffer_size_of(
VALUE klass,
VALUE buffer_type)
2044 for (
long i = 0; i <
RARRAY_LEN(buffer_type); i++) {
2055rb_io_buffer_get_value(
const void* base,
size_t size,
ID buffer_type,
size_t *offset)
2057#define IO_BUFFER_GET_VALUE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) return io_buffer_read_##name(base, size, offset);
2058 IO_BUFFER_GET_VALUE(U8)
2059 IO_BUFFER_GET_VALUE(S8)
2061 IO_BUFFER_GET_VALUE(u16)
2062 IO_BUFFER_GET_VALUE(U16)
2063 IO_BUFFER_GET_VALUE(s16)
2064 IO_BUFFER_GET_VALUE(S16)
2066 IO_BUFFER_GET_VALUE(u32)
2067 IO_BUFFER_GET_VALUE(U32)
2068 IO_BUFFER_GET_VALUE(s32)
2069 IO_BUFFER_GET_VALUE(S32)
2071 IO_BUFFER_GET_VALUE(u64)
2072 IO_BUFFER_GET_VALUE(U64)
2073 IO_BUFFER_GET_VALUE(s64)
2074 IO_BUFFER_GET_VALUE(S64)
2076 IO_BUFFER_GET_VALUE(u128)
2077 IO_BUFFER_GET_VALUE(U128)
2078 IO_BUFFER_GET_VALUE(s128)
2079 IO_BUFFER_GET_VALUE(S128)
2081 IO_BUFFER_GET_VALUE(f32)
2082 IO_BUFFER_GET_VALUE(F32)
2083 IO_BUFFER_GET_VALUE(f64)
2084 IO_BUFFER_GET_VALUE(F64)
2085#undef IO_BUFFER_GET_VALUE
2087 rb_raise(rb_eArgError,
"Invalid type name!");
2133 size_t offset = io_buffer_extract_offset(_offset);
2135 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2137 return rb_io_buffer_get_value(base, size,
RB_SYM2ID(
type), &offset);
2153 size_t offset = io_buffer_extract_offset(_offset);
2157 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2160 rb_raise(rb_eArgError,
"Argument buffer_types should be an array!");
2165 for (
long i = 0; i <
RARRAY_LEN(buffer_types); i++) {
2177io_buffer_extract_count(
VALUE argument)
2179 if (rb_int_negative_p(argument)) {
2180 rb_raise(rb_eArgError,
"Count can't be negative!");
2187io_buffer_extract_offset_count(
ID buffer_type,
size_t size,
int argc,
VALUE *argv,
size_t *offset,
size_t *count)
2190 *offset = io_buffer_extract_offset(argv[0]);
2197 *count = io_buffer_extract_count(argv[1]);
2200 if (*offset > size) {
2201 rb_raise(rb_eArgError,
"The given offset is bigger than the buffer size!");
2204 *count = (size - *offset) / io_buffer_buffer_type_size(buffer_type);
2225io_buffer_each(
int argc,
VALUE *argv,
VALUE self)
2232 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2239 buffer_type = RB_IO_BUFFER_DATA_TYPE_U8;
2242 size_t offset, count;
2243 io_buffer_extract_offset_count(buffer_type, size, argc-1, argv+1, &offset, &count);
2245 for (
size_t i = 0; i < count; i++) {
2246 size_t current_offset = offset;
2247 VALUE value = rb_io_buffer_get_value(base, size, buffer_type, &offset);
2265io_buffer_values(
int argc,
VALUE *argv,
VALUE self)
2270 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2277 buffer_type = RB_IO_BUFFER_DATA_TYPE_U8;
2280 size_t offset, count;
2281 io_buffer_extract_offset_count(buffer_type, size, argc-1, argv+1, &offset, &count);
2285 for (
size_t i = 0; i < count; i++) {
2286 VALUE value = rb_io_buffer_get_value(base, size, buffer_type, &offset);
2309io_buffer_each_byte(
int argc,
VALUE *argv,
VALUE self)
2316 rb_io_buffer_get_bytes_for_reading(self, &base, &size);
2318 size_t offset, count;
2319 io_buffer_extract_offset_count(RB_IO_BUFFER_DATA_TYPE_U8, size, argc, argv, &offset, &count);
2321 for (
size_t i = 0; i < count; i++) {
2322 unsigned char *value = (
unsigned char *)base + i + offset;
2330rb_io_buffer_set_value(
const void* base,
size_t size,
ID buffer_type,
size_t *offset,
VALUE value)
2332#define IO_BUFFER_SET_VALUE(name) if (buffer_type == RB_IO_BUFFER_DATA_TYPE_##name) {io_buffer_write_##name(base, size, offset, value); return;}
2333 IO_BUFFER_SET_VALUE(U8);
2334 IO_BUFFER_SET_VALUE(S8);
2336 IO_BUFFER_SET_VALUE(u16);
2337 IO_BUFFER_SET_VALUE(U16);
2338 IO_BUFFER_SET_VALUE(s16);
2339 IO_BUFFER_SET_VALUE(S16);
2341 IO_BUFFER_SET_VALUE(u32);
2342 IO_BUFFER_SET_VALUE(U32);
2343 IO_BUFFER_SET_VALUE(s32);
2344 IO_BUFFER_SET_VALUE(S32);
2346 IO_BUFFER_SET_VALUE(u64);
2347 IO_BUFFER_SET_VALUE(U64);
2348 IO_BUFFER_SET_VALUE(s64);
2349 IO_BUFFER_SET_VALUE(S64);
2351 IO_BUFFER_SET_VALUE(u128);
2352 IO_BUFFER_SET_VALUE(U128);
2353 IO_BUFFER_SET_VALUE(s128);
2354 IO_BUFFER_SET_VALUE(S128);
2356 IO_BUFFER_SET_VALUE(f32);
2357 IO_BUFFER_SET_VALUE(F32);
2358 IO_BUFFER_SET_VALUE(f64);
2359 IO_BUFFER_SET_VALUE(F64);
2360#undef IO_BUFFER_SET_VALUE
2362 rb_raise(rb_eArgError,
"Invalid type name!");
2400 size_t offset = io_buffer_extract_offset(_offset);
2402 rb_io_buffer_get_bytes_for_writing(self, &base, &size);
2404 rb_io_buffer_set_value(base, size,
RB_SYM2ID(
type), &offset, value);
2427 rb_raise(rb_eArgError,
"Argument buffer_types should be an array!");
2431 rb_raise(rb_eArgError,
"Argument values should be an array!");
2435 rb_raise(rb_eArgError,
"Argument buffer_types and values should have the same length!");
2438 size_t offset = io_buffer_extract_offset(_offset);
2442 rb_io_buffer_get_bytes_for_writing(self, &base, &size);
2444 for (
long i = 0; i <
RARRAY_LEN(buffer_types); i++) {
2447 rb_io_buffer_set_value(base, size,
RB_SYM2ID(
type), &offset, value);
2453static size_t IO_BUFFER_BLOCKING_SIZE = 1024*1024;
2456 unsigned char * destination;
2457 const unsigned char * source;
2462io_buffer_memmove_blocking(
void *data)
2466 memmove(arguments->destination, arguments->source, arguments->length);
2472io_buffer_memmove_unblock(
void *data)
2478io_buffer_memmove(
struct rb_io_buffer *buffer,
size_t offset,
const void *source_base,
size_t source_offset,
size_t source_size,
size_t length)
2482 io_buffer_get_bytes_for_writing(buffer, &base, &size);
2484 io_buffer_validate_range(buffer, offset, length);
2486 if (source_offset + length > source_size) {
2487 rb_raise(rb_eArgError,
"The computed source range exceeds the size of the source buffer!");
2491 .destination = (
unsigned char*)base+offset,
2492 .source = (
unsigned char*)source_base+source_offset,
2496 if (arguments.length >= IO_BUFFER_BLOCKING_SIZE) {
2498 }
else if (arguments.length != 0) {
2499 memmove(arguments.destination, arguments.source, arguments.length);
2505io_buffer_copy_from(
struct rb_io_buffer *buffer,
const void *source_base,
size_t source_size,
int argc,
VALUE *argv)
2509 size_t source_offset;
2513 offset = io_buffer_extract_offset(argv[0]);
2518 source_offset = io_buffer_extract_offset(argv[2]);
2520 if (source_offset > source_size) {
2521 rb_raise(rb_eArgError,
"The given source offset is bigger than the source itself!");
2529 if (argc >= 2 && !
RB_NIL_P(argv[1])) {
2530 length = io_buffer_extract_length(argv[1]);
2534 length = source_size - source_offset;
2537 io_buffer_memmove(buffer, offset, source_base, source_offset, source_size, length);
2560rb_io_buffer_initialize_copy(
VALUE self,
VALUE source)
2565 const void *source_base;
2568 rb_io_buffer_get_bytes_for_reading(source, &source_base, &source_size);
2570 io_buffer_initialize(self, buffer, NULL, source_size, io_flags_for_size(source_size),
Qnil);
2572 return io_buffer_copy_from(buffer, source_base, source_size, 0, NULL);
2644io_buffer_copy(
int argc,
VALUE *argv,
VALUE self)
2651 VALUE source = argv[0];
2652 const void *source_base;
2655 rb_io_buffer_get_bytes_for_reading(source, &source_base, &source_size);
2657 return io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
2675io_buffer_get_string(
int argc,
VALUE *argv,
VALUE self)
2679 size_t offset, length;
2680 struct rb_io_buffer *buffer = io_buffer_extract_offset_length(self, argc, argv, &offset, &length);
2684 io_buffer_get_bytes_for_reading(buffer, &base, &size);
2688 encoding = rb_find_encoding(argv[2]);
2691 encoding = rb_ascii8bit_encoding();
2694 io_buffer_validate_range(buffer, offset, length);
2696 return rb_enc_str_new((
const char*)base + offset, length, encoding);
2723io_buffer_set_string(
int argc,
VALUE *argv,
VALUE self)
2732 const void *source_base = RSTRING_PTR(
string);
2733 size_t source_size = RSTRING_LEN(
string);
2735 return io_buffer_copy_from(buffer, source_base, source_size, argc-1, argv+1);
2739rb_io_buffer_clear(
VALUE self, uint8_t value,
size_t offset,
size_t length)
2746 io_buffer_get_bytes_for_writing(buffer, &base, &size);
2748 io_buffer_validate_range(buffer, offset, length);
2750 memset((
char*)base + offset, value, length);
2785io_buffer_clear(
int argc,
VALUE *argv,
VALUE self)
2794 size_t offset, length;
2795 io_buffer_extract_offset_length(self, argc-1, argv+1, &offset, &length);
2797 rb_io_buffer_clear(self, value, offset, length);
2803io_buffer_default_size(
size_t page_size)
2806 const size_t platform_agnostic_default_size = 64*1024;
2809 const char *default_size = getenv(
"RUBY_IO_BUFFER_DEFAULT_SIZE");
2812 int value = atoi(default_size);
2820 if (platform_agnostic_default_size < page_size) {
2824 return platform_agnostic_default_size;
2830 rb_blocking_function_t *function;
2835io_buffer_blocking_region_begin(
VALUE _argument)
2839 return rb_io_blocking_region(argument->io, argument->function, argument->data);
2843io_buffer_blocking_region_ensure(
VALUE _argument)
2847 io_buffer_unlock(argument->buffer);
2853io_buffer_blocking_region(
VALUE io,
struct rb_io_buffer *buffer, rb_blocking_function_t *function,
void *data)
2855 struct rb_io *ioptr;
2861 .function = function,
2866 if (buffer->flags & RB_IO_BUFFER_LOCKED) {
2867 return io_buffer_blocking_region_begin((
VALUE)&argument);
2871 io_buffer_lock(buffer);
2873 return rb_ensure(io_buffer_blocking_region_begin, (
VALUE)&argument, io_buffer_blocking_region_ensure, (
VALUE)&argument);
2889io_buffer_read_internal(
void *_argument)
2895 ssize_t result = read(argument->descriptor, argument->base, argument->size);
2900 else if (result == 0) {
2906 if (total >= argument->length) {
2910 argument->base = argument->base + result;
2911 argument->size = argument->size - result;
2917rb_io_buffer_read(
VALUE self,
VALUE io,
size_t length,
size_t offset)
2922 if (scheduler !=
Qnil) {
2925 if (!UNDEF_P(result)) {
2933 io_buffer_validate_range(buffer, offset, length);
2939 io_buffer_get_bytes_for_writing(buffer, &base, &size);
2941 base = (
unsigned char*)base + offset;
2942 size = size - offset;
2945 .descriptor = descriptor,
2951 return io_buffer_blocking_region(io, buffer, io_buffer_read_internal, &argument);
2981io_buffer_read(
int argc,
VALUE *argv,
VALUE self)
2987 size_t length, offset;
2988 io_buffer_extract_length_offset(self, argc-1, argv+1, &length, &offset);
2990 return rb_io_buffer_read(self, io, length, offset);
3007io_buffer_pread_internal(
void *_argument)
3013 ssize_t result = pread(argument->descriptor, argument->base, argument->size, argument->offset);
3018 else if (result == 0) {
3024 if (total >= argument->length) {
3028 argument->base = argument->base + result;
3029 argument->size = argument->size - result;
3030 argument->offset = argument->offset + result;
3036rb_io_buffer_pread(
VALUE self,
VALUE io, rb_off_t from,
size_t length,
size_t offset)
3041 if (scheduler !=
Qnil) {
3044 if (!UNDEF_P(result)) {
3052 io_buffer_validate_range(buffer, offset, length);
3058 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3060 base = (
unsigned char*)base + offset;
3061 size = size - offset;
3064 .descriptor = descriptor,
3071 return io_buffer_blocking_region(io, buffer, io_buffer_pread_internal, &argument);
3105io_buffer_pread(
int argc,
VALUE *argv,
VALUE self)
3112 size_t length, offset;
3113 io_buffer_extract_length_offset(self, argc-2, argv+2, &length, &offset);
3115 return rb_io_buffer_pread(self, io, from, length, offset);
3130io_buffer_write_internal(
void *_argument)
3136 ssize_t result = write(argument->descriptor, argument->base, argument->size);
3141 else if (result == 0) {
3147 if (total >= argument->length) {
3151 argument->base = argument->base + result;
3152 argument->size = argument->size - result;
3158rb_io_buffer_write(
VALUE self,
VALUE io,
size_t length,
size_t offset)
3163 if (scheduler !=
Qnil) {
3166 if (!UNDEF_P(result)) {
3174 io_buffer_validate_range(buffer, offset, length);
3180 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3182 base = (
unsigned char*)base + offset;
3183 size = size - offset;
3186 .descriptor = descriptor,
3192 return io_buffer_blocking_region(io, buffer, io_buffer_write_internal, &argument);
3215io_buffer_write(
int argc,
VALUE *argv,
VALUE self)
3221 size_t length, offset;
3222 io_buffer_extract_length_offset(self, argc-1, argv+1, &length, &offset);
3224 return rb_io_buffer_write(self, io, length, offset);
3241io_buffer_pwrite_internal(
void *_argument)
3247 ssize_t result = pwrite(argument->descriptor, argument->base, argument->size, argument->offset);
3252 else if (result == 0) {
3258 if (total >= argument->length) {
3262 argument->base = argument->base + result;
3263 argument->size = argument->size - result;
3264 argument->offset = argument->offset + result;
3270rb_io_buffer_pwrite(
VALUE self,
VALUE io, rb_off_t from,
size_t length,
size_t offset)
3275 if (scheduler !=
Qnil) {
3278 if (!UNDEF_P(result)) {
3286 io_buffer_validate_range(buffer, offset, length);
3292 io_buffer_get_bytes_for_reading(buffer, &base, &size);
3294 base = (
unsigned char*)base + offset;
3295 size = size - offset;
3298 .descriptor = descriptor,
3313 return io_buffer_blocking_region(io, buffer, io_buffer_pwrite_internal, &argument);
3341io_buffer_pwrite(
int argc,
VALUE *argv,
VALUE self)
3348 size_t length, offset;
3349 io_buffer_extract_length_offset(self, argc-2, argv+2, &length, &offset);
3351 return rb_io_buffer_pwrite(self, io, from, length, offset);
3357 if (buffer->size == 0)
3358 rb_raise(rb_eIOBufferMaskError,
"Zero-length mask given!");
3362memory_and(
unsigned char * restrict output,
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3364 for (
size_t offset = 0; offset < size; offset += 1) {
3365 output[offset] = base[offset] & mask[offset % mask_size];
3390 io_buffer_check_mask(mask_buffer);
3392 VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
3396 memory_and(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
3402memory_or(
unsigned char * restrict output,
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3404 for (
size_t offset = 0; offset < size; offset += 1) {
3405 output[offset] = base[offset] | mask[offset % mask_size];
3430 io_buffer_check_mask(mask_buffer);
3432 VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
3436 memory_or(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
3442memory_xor(
unsigned char * restrict output,
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3444 for (
size_t offset = 0; offset < size; offset += 1) {
3445 output[offset] = base[offset] ^ mask[offset % mask_size];
3470 io_buffer_check_mask(mask_buffer);
3472 VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
3476 memory_xor(output_buffer->base, buffer->base, buffer->size, mask_buffer->base, mask_buffer->size);
3482memory_not(
unsigned char * restrict output,
unsigned char * restrict base,
size_t size)
3484 for (
size_t offset = 0; offset < size; offset += 1) {
3485 output[offset] = ~base[offset];
3502io_buffer_not(
VALUE self)
3507 VALUE output = rb_io_buffer_new(NULL, buffer->size, io_flags_for_size(buffer->size));
3511 memory_not(output_buffer->base, buffer->base, buffer->size);
3519 if (a->base > b->base) {
3520 return io_buffer_overlaps(b, a);
3523 return (b->base >= a->base) && (b->base < (
void*)((
unsigned char *)a->base + a->size));
3529 if (io_buffer_overlaps(a, b))
3530 rb_raise(rb_eIOBufferMaskError,
"Mask overlaps source buffer!");
3534memory_and_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3536 for (
size_t offset = 0; offset < size; offset += 1) {
3537 base[offset] &= mask[offset % mask_size];
3567 io_buffer_check_mask(mask_buffer);
3568 io_buffer_check_overlaps(buffer, mask_buffer);
3572 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3574 memory_and_inplace(base, size, mask_buffer->base, mask_buffer->size);
3580memory_or_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3582 for (
size_t offset = 0; offset < size; offset += 1) {
3583 base[offset] |= mask[offset % mask_size];
3613 io_buffer_check_mask(mask_buffer);
3614 io_buffer_check_overlaps(buffer, mask_buffer);
3618 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3620 memory_or_inplace(base, size, mask_buffer->base, mask_buffer->size);
3626memory_xor_inplace(
unsigned char * restrict base,
size_t size,
unsigned char * restrict mask,
size_t mask_size)
3628 for (
size_t offset = 0; offset < size; offset += 1) {
3629 base[offset] ^= mask[offset % mask_size];
3659 io_buffer_check_mask(mask_buffer);
3660 io_buffer_check_overlaps(buffer, mask_buffer);
3664 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3666 memory_xor_inplace(base, size, mask_buffer->base, mask_buffer->size);
3672memory_not_inplace(
unsigned char * restrict base,
size_t size)
3674 for (
size_t offset = 0; offset < size; offset += 1) {
3675 base[offset] = ~base[offset];
3697io_buffer_not_inplace(
VALUE self)
3704 io_buffer_get_bytes_for_writing(buffer, &base, &size);
3706 memory_not_inplace(base, size);
3824 GetSystemInfo(&info);
3825 RUBY_IO_BUFFER_PAGE_SIZE = info.dwPageSize;
3827 RUBY_IO_BUFFER_PAGE_SIZE = sysconf(_SC_PAGESIZE);
3830 RUBY_IO_BUFFER_DEFAULT_SIZE = io_buffer_default_size(RUBY_IO_BUFFER_PAGE_SIZE);
3833 rb_define_const(rb_cIOBuffer,
"PAGE_SIZE",
SIZET2NUM(RUBY_IO_BUFFER_PAGE_SIZE));
3838 rb_define_const(rb_cIOBuffer,
"DEFAULT_SIZE",
SIZET2NUM(RUBY_IO_BUFFER_DEFAULT_SIZE));
3843 rb_define_method(rb_cIOBuffer,
"initialize_copy", rb_io_buffer_initialize_copy, 1);
3853 rb_define_const(rb_cIOBuffer,
"EXTERNAL",
RB_INT2NUM(RB_IO_BUFFER_EXTERNAL));
3856 rb_define_const(rb_cIOBuffer,
"INTERNAL",
RB_INT2NUM(RB_IO_BUFFER_INTERNAL));
3859 rb_define_const(rb_cIOBuffer,
"MAPPED",
RB_INT2NUM(RB_IO_BUFFER_MAPPED));
3862 rb_define_const(rb_cIOBuffer,
"SHARED",
RB_INT2NUM(RB_IO_BUFFER_SHARED));
3865 rb_define_const(rb_cIOBuffer,
"LOCKED",
RB_INT2NUM(RB_IO_BUFFER_LOCKED));
3868 rb_define_const(rb_cIOBuffer,
"PRIVATE",
RB_INT2NUM(RB_IO_BUFFER_PRIVATE));
3871 rb_define_const(rb_cIOBuffer,
"READONLY",
RB_INT2NUM(RB_IO_BUFFER_READONLY));
3874 rb_define_const(rb_cIOBuffer,
"LITTLE_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_LITTLE_ENDIAN));
3877 rb_define_const(rb_cIOBuffer,
"BIG_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_BIG_ENDIAN));
3880 rb_define_const(rb_cIOBuffer,
"HOST_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_HOST_ENDIAN));
3883 rb_define_const(rb_cIOBuffer,
"NETWORK_ENDIAN",
RB_INT2NUM(RB_IO_BUFFER_NETWORK_ENDIAN));
3909#define IO_BUFFER_DEFINE_DATA_TYPE(name) RB_IO_BUFFER_DATA_TYPE_##name = rb_intern_const(#name)
3910 IO_BUFFER_DEFINE_DATA_TYPE(U8);
3911 IO_BUFFER_DEFINE_DATA_TYPE(S8);
3913 IO_BUFFER_DEFINE_DATA_TYPE(u16);
3914 IO_BUFFER_DEFINE_DATA_TYPE(U16);
3915 IO_BUFFER_DEFINE_DATA_TYPE(s16);
3916 IO_BUFFER_DEFINE_DATA_TYPE(S16);
3918 IO_BUFFER_DEFINE_DATA_TYPE(u32);
3919 IO_BUFFER_DEFINE_DATA_TYPE(U32);
3920 IO_BUFFER_DEFINE_DATA_TYPE(s32);
3921 IO_BUFFER_DEFINE_DATA_TYPE(S32);
3923 IO_BUFFER_DEFINE_DATA_TYPE(u64);
3924 IO_BUFFER_DEFINE_DATA_TYPE(U64);
3925 IO_BUFFER_DEFINE_DATA_TYPE(s64);
3926 IO_BUFFER_DEFINE_DATA_TYPE(S64);
3928 IO_BUFFER_DEFINE_DATA_TYPE(u128);
3929 IO_BUFFER_DEFINE_DATA_TYPE(U128);
3930 IO_BUFFER_DEFINE_DATA_TYPE(s128);
3931 IO_BUFFER_DEFINE_DATA_TYPE(S128);
3933 IO_BUFFER_DEFINE_DATA_TYPE(f32);
3934 IO_BUFFER_DEFINE_DATA_TYPE(F32);
3935 IO_BUFFER_DEFINE_DATA_TYPE(f64);
3936 IO_BUFFER_DEFINE_DATA_TYPE(F64);
3937#undef IO_BUFFER_DEFINE_DATA_TYPE
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
static bool RB_OBJ_FROZEN(VALUE obj)
Checks if an object is frozen.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
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 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 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.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_entry(VALUE ary, long off)
Queries an element of an array.
#define RETURN_ENUMERATOR_KW(obj, argc, argv, kw_splat)
Identical to RETURN_SIZED_ENUMERATOR_KW(), except its size is unknown.
static int rb_check_arity(int argc, int min, int max)
Ensures that the passed integer is in the passed range.
VALUE rb_str_append(VALUE dst, VALUE src)
Identical to rb_str_buf_append(), except it converts the right hand side before concatenating.
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
VALUE rb_str_locktmp(VALUE str)
Obtains a "temporary lock" of the string.
VALUE rb_str_unlocktmp(VALUE str)
Releases a lock formerly obtained by rb_str_locktmp().
VALUE rb_str_buf_new(long capa)
Allocates a "string buffer".
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
#define RB_SYM2ID
Just another name of rb_sym2id.
VALUE rb_io_get_io(VALUE io)
Identical to rb_io_check_io(), except it raises exceptions on conversion failures.
int rb_io_descriptor(VALUE io)
Returns an integer representing the numeric file descriptor for io.
#define RB_IO_POINTER(obj, fp)
Queries the underlying IO pointer.
VALUE rb_io_get_write_io(VALUE io)
Queries the tied IO for writing.
void * rb_nogvl(void *(*func)(void *), void *data1, rb_unblock_function_t *ubf, void *data2, int flags)
Identical to rb_thread_call_without_gvl(), except it additionally takes "flags" that change the behav...
#define RB_NOGVL_OFFLOAD_SAFE
Passing this flag to rb_nogvl() indicates that the passed function is safe to offload to a background...
#define RB_NUM2INT
Just another name of rb_num2int_inline.
#define RB_UINT2NUM
Just another name of rb_uint2num_inline.
#define RB_INT2NUM
Just another name of rb_int2num_inline.
static unsigned int RB_NUM2UINT(VALUE x)
Converts an instance of rb_cNumeric into C's unsigned int.
#define RB_LL2NUM
Just another name of rb_ll2num_inline.
#define RB_ULL2NUM
Just another name of rb_ull2num_inline.
#define RB_NUM2ULL
Just another name of rb_num2ull_inline.
#define RB_NUM2LL
Just another name of rb_num2ll_inline.
VALUE rb_yield_values(int n,...)
Identical to rb_yield(), except it takes variadic number of parameters and pass them to the block.
VALUE rb_yield(VALUE val)
Yields the block.
static VALUE RB_INT2FIX(long i)
Converts a C's long into an instance of rb_cInteger.
#define RB_NUM2LONG
Just another name of rb_num2long_inline.
VALUE type(ANYARGS)
ANYARGS-ed function type.
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
#define NUM2OFFT
Converts an instance of rb_cNumeric into C's off_t.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_AREF(a, i)
#define StringValue(v)
Ensures that the parameter object is a String.
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
VALUE rb_str_to_str(VALUE obj)
Identical to rb_check_string_type(), except it raises exceptions in case of conversion failures.
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
#define errno
Ractor-aware version of errno.
#define RB_NO_KEYWORDS
Do not pass keywords.
VALUE rb_fiber_scheduler_current(void)
Identical to rb_fiber_scheduler_get(), except it also returns RUBY_Qnil in case of a blocking fiber.
VALUE rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset)
Non-blocking write to the passed IO at the specified offset.
VALUE rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset)
Non-blocking read from the passed IO.
static VALUE rb_fiber_scheduler_io_result(ssize_t result, int error)
Wrap a ssize_t and int errno into a single VALUE.
VALUE rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset)
Non-blocking read from the passed IO at the specified offset.
VALUE rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset)
Non-blocking write to the passed IO.
static bool RB_NIL_P(VALUE obj)
Checks if the given object is nil.
This is the struct that holds necessary info for a struct.
const char * wrap_struct_name
Name of structs of this kind.
Ruby's IO, metadata and buffers.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.