Class: Snow::Memory
- Inherits:
-
Data
- Object
- Data
- Snow::Memory
- Defined in:
- lib/snow-data/memory.rb,
ext/snow-data/snow-data.c
Overview
A class for representing blocks of memory. You can either allocate memory using ::malloc or wrap existing blocks of memory using ::new or ::wrap (or ::__wrap__ if a subclass has extended ::wrap and ::new).
If wrapping an existing block of memory, note that the Memory object does not take ownership of the block. As such, freeing it is the responsibility of its allocator. Only a block allocated by ::malloc will be freed by a Memory object, either by calling #free! or when the GC collects the object.
When subclassing Memory, which is fine to do, you’ll likely want to override Memory::new and possibly Memory::wrap. It is also possible to override Memory::malloc, but it’s recommended you never do this. If you do, keep in mind that __malloc__ exists as an alias of malloc and you must never try to override it, as this could result in very strange behavior. Similarly, new is aliased as both wrap and __wrap__, the latter of which you should must never override either. Again, it may result in undesirable behavior, crashes, and angry responses to any issues you create on GitHub as a result.
Constant Summary collapse
- HAS_ALLOCA =
Whether or not __alloca__ is available (and ergo any other variant of it). You may check this instead of calling respond_to? if you wish.
self.respond_to?(:__alloca__)
Class Method Summary collapse
-
.__alloca__(sd_size) ⇒ Object
Allocates size bytes on the stack and yields it to a block before for use, then returns the result of the block.
-
.__malloc__(*args) ⇒ Object
(also: malloc, [])
Allocates a new block with the given size and alignment and returns it.
-
.__wrap__(*args) ⇒ Object
(also: new, wrap)
Creates a new Memory object that wraps an existing pointer.
-
.align_size(size_or_offset, alignment = nil) ⇒ Integer
Aligns a given size or offset to a specific alignment.
Instance Method Summary collapse
-
#==(other) ⇒ Object
Returns whether this and another block are equal in terms of their properties – that is, whether they have the address and bytesize.
-
#address ⇒ Integer
Gets the address of this memory block as an Integer.
-
#alignment ⇒ Object
The alignment in bytes of a memory block.
-
#bytesize ⇒ Object
The size in bytes of a memory block.
-
#copy!(source, destination_offset = nil, source_offset = nil, byte_size = nil) ⇒ self
Copies byte_size bytes from an offset in the source data to an offset into the receiver (the destination).
-
#dup ⇒ Object
Creates a new block of memory with the same class, size, and alignment; copies the receiver’s data to the new block; and returns the new block.
-
#free! ⇒ self
Frees any memory owned by the object.
-
#get_char(offset) ⇒ String
Reads a char from the offset into the memory block and returns it.
-
#get_double(offset) ⇒ Object
Reads a double from the offset into the memory block and returns it.
-
#get_float(offset) ⇒ Float
Reads a float from the offset into the memory block and returns it.
-
#get_int(offset) ⇒ Integer
Reads a int from the offset into the memory block and returns it.
-
#get_int16(offset) ⇒ Object
Reads a int16_t from the offset into the memory block and returns it.
-
#get_int32(offset) ⇒ Object
Reads a int32_t from the offset into the memory block and returns it.
-
#get_int64(offset) ⇒ Object
Reads a int64_t from the offset into the memory block and returns it.
-
#get_int8(offset) ⇒ Object
Reads a int8_t from the offset into the memory block and returns it.
-
#get_intptr_t(offset) ⇒ Object
Reads a intptr_t from the offset into the memory block and returns it.
-
#get_long(offset) ⇒ Integer
Reads a long from the offset into the memory block and returns it.
-
#get_long_long(offset) ⇒ Integer
Reads a long long from the offset into the memory block and returns it.
-
#get_ptrdiff_t(offset) ⇒ Object
Reads a ptrdiff_t from the offset into the memory block and returns it.
-
#get_short(offset) ⇒ Integer
Reads a short from the offset into the memory block and returns it.
-
#get_signed_char(offset) ⇒ Object
Reads a signed char from the offset into the memory block and returns it.
-
#get_size_t(offset) ⇒ Object
Reads a size_t from the offset into the memory block and returns it.
-
#get_string(offset, length = nil) ⇒ String
Copies a string out of the block and returns it.
-
#get_uint16(offset) ⇒ Object
Reads a uint16_t from the offset into the memory block and returns it.
-
#get_uint32(offset) ⇒ Object
Reads a uint32_t from the offset into the memory block and returns it.
-
#get_uint64(offset) ⇒ Object
Reads a uint64_t from the offset into the memory block and returns it.
-
#get_uint8(offset) ⇒ Object
Reads a uint8_t from the offset into the memory block and returns it.
-
#get_uintptr_t(offset) ⇒ Object
Reads a uintptr_t from the offset into the memory block and returns it.
-
#get_unsigned_char(offset) ⇒ Object
Reads a unsigned char from the offset into the memory block and returns it.
-
#get_unsigned_int(offset) ⇒ Integer
Reads a unsigned int from the offset into the memory block and returns it.
-
#get_unsigned_long(offset) ⇒ Integer
Reads a unsigned long from the offset into the memory block and returns it.
-
#get_unsigned_long_long(offset) ⇒ Integer
Reads a unsigned long long from the offset into the memory block and returns it.
-
#get_unsigned_short(offset) ⇒ Integer
Reads a unsigned short from the offset into the memory block and returns it.
-
#inspect ⇒ Object
Returns a string showing the memory block’s classname, object ID, address, size, and alignment.
-
#null? ⇒ Boolean
Returns whether the memory block is pointing to a null address.
-
#realloc!(size, alignment = nil) ⇒ self
Reallocates the memory backing this pointer with a new size and optionally a new alignment.
-
#set_char(offset, value) ⇒ Object
Sets a char at the offset to the value.
-
#set_double(offset, value) ⇒ Object
Sets a double at the offset to the value.
-
#set_float(offset, value) ⇒ Object
Sets a float at the offset to the value.
-
#set_int(offset, value) ⇒ Object
Sets a int at the offset to the value.
-
#set_int16(offset, value) ⇒ Object
Sets a int16_t at the offset to the value.
-
#set_int32(offset, value) ⇒ Object
Sets a int32_t at the offset to the value.
-
#set_int64(offset, value) ⇒ Object
Sets a int64_t at the offset to the value.
-
#set_int8(offset, value) ⇒ Object
Sets a int8_t at the offset to the value.
-
#set_intptr_t(offset, value) ⇒ Object
Sets a intptr_t at the offset to the value.
-
#set_long(offset, value) ⇒ Object
Sets a long at the offset to the value.
-
#set_long_long(offset, value) ⇒ Object
Sets a long long at the offset to the value.
-
#set_ptrdiff_t(offset, value) ⇒ Object
Sets a ptrdiff_t at the offset to the value.
-
#set_short(offset, value) ⇒ Object
Sets a short at the offset to the value.
-
#set_signed_char(offset, value) ⇒ Object
Sets a signed char at the offset to the value.
-
#set_size_t(offset, value) ⇒ Object
Sets a size_t at the offset to the value.
-
#set_string(offset, value, null_terminated = false) ⇒ Object
Copies the string value into the block at the offset supplied.
-
#set_uint16(offset, value) ⇒ Object
Sets a uint16_t at the offset to the value.
-
#set_uint32(offset, value) ⇒ Object
Sets a uint32_t at the offset to the value.
-
#set_uint64(offset, value) ⇒ Object
Sets a uint64_t at the offset to the value.
-
#set_uint8(offset, value) ⇒ Object
Sets a uint8_t at the offset to the value.
-
#set_uintptr_t(offset, value) ⇒ Object
Sets a uintptr_t at the offset to the value.
-
#set_unsigned_char(offset, value) ⇒ Object
Sets a unsigned char at the offset to the value.
-
#set_unsigned_int(offset, value) ⇒ Object
Sets a unsigned int at the offset to the value.
-
#set_unsigned_long(offset, value) ⇒ Object
Sets a unsigned long at the offset to the value.
-
#set_unsigned_long_long(offset, value) ⇒ Object
Sets a unsigned long long at the offset to the value.
-
#set_unsigned_short(offset, value) ⇒ Object
Sets a unsigned short at the offset to the value.
-
#to_s(null_terminated = true) ⇒ String
Gets a string representation of the contents of this block.
Class Method Details
.alloca(size) {|memory| ... } ⇒ Object .__alloca__(size) {|memory| ... } ⇒ Object
Allocates size bytes on the stack and yields it to a block before for use, then returns the result of the block. Outside of the block, any use of the yielded memory’s address is considered undefined behavior and may lead to crashes or worse. The yielded memory is only valid for the duration of the block. If you want to preserve the memory after use, either duplicate the memory block or realloc! the memory, both of which will copy it from the stack to the heap.
The alignment of the yielded memory is always the size of a pointer.
Because of how downright evil alloca is in some situations, it is disabled by default. You must explicitly install snow-data with the –allow-alloca flag to use this function. If you’re not certain whether alloca is available for a particular installation, then you should check if the Memory class responds to it first.
if Snow::Memory.respond_to?(:__alloca__)
Snow::Memory.__alloca__(64) { |mem|
# ...
}
end
Subclasses may override alloca to provide a predefined size argument, but subclasses must never override __alloca__. It is considered bad form to implement __alloca__ using heap allocation for installations that don’t provide it.
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 |
# File 'ext/snow-data/snow-data.c', line 1491
static VALUE sd_memory_alloca(VALUE self, VALUE sd_size)
{
VALUE result = Qnil;
void *stack_memory = NULL;
struct RData *block_data;
size_t size = NUM2SIZET(sd_size);
VALUE block;
rb_need_block();
if (size == 0) {
rb_raise(rb_eRangeError, "Size of block must be 1 or more -- zero-byte"
" blocks are not permitted.");
}
stack_memory = alloca(size);
if (stack_memory == NULL) {
rb_raise(rb_eNoMemError,
"Failed to allocated %zu bytes via alloca",
size);
}
block = sd_wrap_memory(self, stack_memory, size, SIZEOF_VOIDP, SD_DO_NOT_FREE_MEMORY);
block_data = RDATA(block);
result = rb_yield(block);
/*
If the block hasn't been realloc!'d or freed, free it now if it hasn't been
frozen for some reason.
*/
if (block_data->data == stack_memory && !block_data->dfree && !OBJ_FROZEN(block)) {
sd_memory_force_free(block);
}
return result;
}
|
.malloc(size, alignment = nil) ⇒ Memory .__malloc__(size, alignment = nil) ⇒ Memory Also known as: malloc, []
Allocates a new block with the given size and alignment and returns it. If no alignment is specified, it defaults to Snow::Memory::SIZEOF_VOID_POINTER.
Raises a RangeError if either size is zero or alignment is not a power of two.
If a subclass overrides ::malloc, which is a bad idea and should not be done, then it is aliased as ::__malloc__ as well. Subclasses must never override ::__malloc__.
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 |
# File 'ext/snow-data/snow-data.c', line 1429
static VALUE sd_memory_malloc(int argc, VALUE *argv, VALUE self)
{
VALUE sd_size;
VALUE sd_alignment;
size_t alignment;
size_t size;
void *data;
VALUE memory;
rb_scan_args(argc, argv, "11", &sd_size, &sd_alignment);
/* Get size and alignment */
size = NUM2SIZET(sd_size);
alignment = RTEST(sd_alignment) ? NUM2SIZET(sd_alignment) : sizeof(void *);
if (!is_power_of_two(alignment)) {
rb_raise(rb_eRangeError, "Alignment must be a power of two -- %zu is not a"
" power of two", alignment);
} else if (size < 1) {
rb_raise(rb_eRangeError, "Size of block must be 1 or more -- zero-byte"
" blocks are not permitted");
}
/* Allocate block */
data = com_malloc(size, alignment);
memory = sd_wrap_memory(self, data, size, alignment, SD_FREE_MEMORY);
return memory;
}
|
.new(address, size, alignment = SIZEOF_VOID_POINTER) ⇒ Memory .wrap(address, size, alignment = SIZEOF_VOID_POINTER) ⇒ Memory .__wrap__(address, size, alignment = SIZEOF_VOID_POINTER) ⇒ Memory Also known as: new, wrap
Creates a new Memory object that wraps an existing pointer. Alignment is optional and defaults to the size of a pointer (Memory::SIZEOF_VOID_POINTER).
Size must be greater than zero. Zero-sized blocks are not permitted as they render most memory functionality useless and make it very difficult to ensure nothing bad is happening when you do bad things with snow-data. Because, let’s be honest with ourselves for a moment, everyone using this gem? They’re bad people. They’re very bad people.
Note that Memory objects created with this method will not attempt to free the memory they wrap, as they did not allocate it and so do not own it. If an address held by a Memory object is invalid, the Memory object is also implicitly invalid as well, though there is no way for it to check this. You are responsible for freeing any memory not allocated through ::malloc and Memory subclasses.
It is an ArgumentError to provide a size of zero, nil, or false. It is also an ArgumentError to provide a NULL (zero) address.
If a subclass overrides ::new, it is also aliased as ::wrap and ::__wrap__. Subclasses may override ::wrap or ::new but must never override ::__wrap__.
1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 |
# File 'ext/snow-data/snow-data.c', line 1376
static VALUE sd_memory_new(int argc, VALUE *argv, VALUE self)
{
VALUE sd_size;
VALUE sd_address;
VALUE sd_alignment;
VALUE memory = Qnil;
void *address;
size_t size;
size_t alignment;
rb_scan_args(argc, argv, "21", &sd_address, &sd_size, &sd_alignment);
address = (void *)SD_NUM_TO_INTPTR_T(sd_address);
size = 0;
alignment = SIZEOF_VOIDP;
if (address == NULL) {
rb_raise(rb_eArgError, "Address is NULL (%p).", address);
}
if (RTEST(sd_size)) {
size = NUM2SIZET(sd_size);
} else {
rb_raise(rb_eArgError, "Block size is false or nil");
}
if (!size) {
rb_raise(rb_eArgError, "Block size must be 1 or greater");
}
if (RTEST(sd_alignment)) {
alignment = NUM2SIZET(sd_alignment);
}
memory = sd_wrap_memory(self, address, size, alignment, SD_DO_NOT_FREE_MEMORY);
return memory;
}
|
.align_size(size_or_offset, alignment = nil) ⇒ Integer
Aligns a given size or offset to a specific alignment. If no alignment is provided, it defaults to the size of a pointer on the architecture the extension was compiled for.
See Snow::Memory::SIZEOF_VOID_POINTER for the size of a pointer.
Raises a RangeError if the alignment is not a power of two. In this case, 1 is considered a valid power of two.
1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 |
# File 'ext/snow-data/snow-data.c', line 1874
static VALUE sd_align_size(int argc, VALUE *argv, VALUE self)
{
VALUE sd_alignment;
VALUE sd_size;
size_t alignment = sizeof(void *);
rb_scan_args(argc, argv, "11", &sd_size, &sd_alignment);
if (RTEST(sd_alignment)) {
alignment = NUM2SIZET(sd_alignment);
if (!is_power_of_two(alignment)) {
rb_raise(rb_eRangeError, "Alignment must be a power of two -- %zu is not"
" a power of two", alignment);
}
}
return SIZET2NUM(align_size(NUM2SIZET(sd_size), alignment));
}
|
Instance Method Details
#==(other) ⇒ Object
Returns whether this and another block are equal in terms of their properties – that is, whether they have the address and bytesize. If true, the objects refer to teh same block of memory. If false, they might still overlap, refer to different chunks of memory, one might be null, etc.
79 80 81 82 83 84 85 86 87 |
# File 'lib/snow-data/memory.rb', line 79 def ==(other) return false unless other if other.kind_of?(::Snow::Memory) || (other.respond_to?(:address) && other.respond_to?(:bytesize)) self.address == other.address && self.bytesize == other.bytesize else false end end |
#address ⇒ Integer
Gets the address of this memory block as an Integer.
1856 1857 1858 1859 |
# File 'ext/snow-data/snow-data.c', line 1856
static VALUE sd_memory_address(VALUE self)
{
return SD_UINTPTR_T_TO_NUM((uintptr_t)RDATA(self)->data);
}
|
#alignment ⇒ Object
The alignment in bytes of a memory block.
60 61 62 |
# File 'lib/snow-data/memory.rb', line 60 def alignment @__alignment__ end |
#bytesize ⇒ Object
The size in bytes of a memory block.
52 53 54 |
# File 'lib/snow-data/memory.rb', line 52 def bytesize @__bytesize__ end |
#copy!(source, destination_offset = nil, source_offset = nil, byte_size = nil) ⇒ self
Copies byte_size bytes from an offset in the source data to an offset into the receiver (the destination).
If either offset is nil, they default to zero.
If the byte_size is nil, it defaults to the receiver’s #bytesize.
If the source responds to #bytesize and the source’s bytesize is smaller than the size given, the source’s size is used instead of the specified or default size.
The source pointer does not have its bounds checked, as this isn’t possible for all cases. Instead, you must ensure that your source offset and byte size are both within range of the source data.
For those curious, under the hood, this uses memmove, not memcpy. So, it is possible to copy overlapping regions of memory, but it isn’t guaranteed to be as fast as a simple memcpy. Either way, if this is a concern for you, you probably shouldn’t be using Ruby.
Exceptions
-
If attempting to copy into a region that is outside the bounds of the receiver will raise a RangeError.
-
If either the receiver or the source address is NULL, it will raise an ArgumentError.
-
If the source object is neither a Data object (or a subclass thereof) or a Numerical address, it raises a TypeError.
1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 |
# File 'ext/snow-data/snow-data.c', line 1658
static VALUE sd_memory_copy(int argc, VALUE *argv, VALUE self)
{
VALUE sd_source;
VALUE sd_destination_offset;
VALUE sd_source_offset;
VALUE sd_byte_size;
struct RData *self_data;
const uint8_t *source_pointer;
uint8_t *destination_pointer;
size_t source_offset;
size_t destination_offset;
size_t byte_size;
size_t self_byte_size;
int source_is_data = 0;
sd_check_null_block(self);
rb_check_frozen(self);
rb_scan_args(argc, argv, "13",
&sd_source,
&sd_destination_offset,
&sd_source_offset,
&sd_byte_size);
/*
By default, try to get an address from the object, if possible. Then use
that address and don't extract it from the Data object or what have you.
*/
if (rb_obj_respond_to(sd_source, kSD_ID_ADDRESS, 0)) {
VALUE source_address = rb_funcall2(sd_source, kSD_ID_ADDRESS, 0, 0);
if (RTEST(rb_obj_is_kind_of(source_address, rb_cNumeric))) {
source_pointer = (uint8_t *)SD_NUM_TO_INTPTR_T(source_address);
goto sd_memory_copy_skip_data_check;
}
}
if (RTEST(rb_obj_is_kind_of(sd_source, rb_cData))) {
/* Otherwise extract a pointer from the object if it's a Data object */
const struct RData *source_data = RDATA(sd_source);
source_pointer = ((const uint8_t *)source_data->data);
source_is_data = 1;
} else if (RTEST(rb_obj_is_kind_of(sd_source, rb_cNumeric))) {
/* Otherwise, if it's a Numeric, try to convert what is assumed to be an
address to a pointer */
source_pointer = (uint8_t *)SD_NUM_TO_INTPTR_T(sd_source);
} else {
rb_raise(rb_eTypeError,
"Source object must be type of numeric (address) or Data- got %s",
rb_obj_classname(sd_source));
}
sd_memory_copy_skip_data_check: /* skip from address check */
self_data = RDATA(self);
/*
Check if the source pointer is NULL -- error if it is (the destination
pointer is checked by sd_check_null_block above).
*/
if (source_pointer == NULL) {
rb_raise(rb_eArgError, "Source pointer is NULL");
}
/* Grab data from ruby values and offset the source pointer. */
source_offset = RTEST(sd_source_offset) ? NUM2SIZET(sd_source_offset) : 0;
destination_offset = RTEST(sd_destination_offset) ? NUM2SIZET(sd_destination_offset) : 0;
destination_pointer = (uint8_t *)self_data->data + destination_offset;
self_byte_size = NUM2SIZET(rb_ivar_get(self, kSD_IVAR_BYTESIZE));
source_pointer += source_offset;
if (self_byte_size == 0) {
/*
If self is a zero-length block, do not try to copy. It's just not sane to
attempt it here since we can't do any bounds checking, even if the bounds
might be arbitrarily specified (in which case I'd just be shooting myself
in the foot if I did that and trying to circumvent the anti-foot-shot
protections).
*/
rb_raise(rb_eRuntimeError, "self.bytesize == 0 -- cannot safely copy to this block");
} else if (!RTEST(sd_byte_size)) {
/*
If not copy size is specified, use self_byte_size and just try to cram as
much in there as is feasible. Truncate self_byte_size as needed for the
offset.
*/
byte_size = self_byte_size - destination_offset;
#ifdef SD_WARN_ON_IMPLICIT_COPY_SIZE
if (!source_is_data) {
rb_warning(
"Copying %zu bytes from non-Data memory address %p without explicit size",
byte_size,
source_pointer);
}
#endif
} else {
/* User-specified size */
byte_size = NUM2SIZET(sd_byte_size);
}
/*
If the source responds to bytesize, check if the copy is within bounds for
the source. If it's out of bounds, raise a RangeError, otherwise optionally
emit a warning that bounds checking doesn't work for this source.
*/
if (rb_obj_respond_to(sd_source, kSD_ID_BYTESIZE, 0)) {
size_t source_size = NUM2SIZET(rb_funcall2(sd_source, kSD_ID_BYTESIZE, 0, 0));
if (source_offset > source_size
|| (source_offset + byte_size) > source_size
|| (source_offset + byte_size) < source_offset) {
rb_raise(rb_eRangeError, "Attempt to copy out of source bounds");
}
}
#ifdef SD_WARN_ON_NO_BYTESIZE_METHOD
else if (source_is_data) {
rb_warning(
"Copying from Data object pointer %p that does not respond to #bytesize"
" -- this operation is not bounds-checked.",
source_pointer);
}
#endif
if ((destination_offset + byte_size) > self_byte_size
|| (destination_offset + byte_size) < destination_offset) {
rb_raise(rb_eRangeError,
"Offset %zu with byte size %zu is out of bounds of self",
destination_offset,
byte_size);
}
#ifdef SD_VERBOSE_COPY_LOG
/*
Emit some debugging info just in case things go completely haywire and you
really need to know what's going on.
*/
fprintf(stderr,
"# copy! ----------------------------------------\n"
"# destination_pointer = %p" "\n"
"# source_pointer = %p" "\n"
"# destination_offset = %zu" "\n"
"# source_offset = %zu" "\n"
"# byte_size = %zu" "\n"
"# self_byte_size = %zu" "\n"
"# source.class = %s" "\n"
"# self.class = %s" "\n"
"# --------------------------------------- /copy!\n",
destination_pointer - destination_offset,
source_pointer - source_offset,
destination_offset,
source_offset,
byte_size,
self_byte_size,
rb_obj_classname(sd_source),
rb_obj_classname(self));
#endif
/* And skip a copy if we can */
if (byte_size == 0 || source_pointer == destination_pointer) {
return self;
}
memmove(destination_pointer, source_pointer, byte_size);
return self;
}
|
#dup ⇒ Object
Creates a new block of memory with the same class, size, and alignment; copies the receiver’s data to the new block; and returns the new block.
103 104 105 106 |
# File 'lib/snow-data/memory.rb', line 103 def dup new_self = self.class.__malloc__(self.bytesize, self.alignment) new_self.copy!(self, 0, 0, self.bytesize) end |
#free! ⇒ self
Frees any memory owned by the object. This is a convenience function for when you want to free the memory ahead of the object being collected by the GC.
1618 1619 1620 1621 1622 1623 |
# File 'ext/snow-data/snow-data.c', line 1618
static VALUE sd_memory_free(VALUE self)
{
rb_check_frozen(self);
sd_memory_force_free(self);
return self;
}
|
#get_char(offset) ⇒ String
Reads a char from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 |
# File 'ext/snow-data/snow-data.c', line 1101
static VALUE sd_get_char(VALUE self, VALUE sd_offset)
{
typedef char conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_CHAR_TO_NUM(value);
}
|
#get_double(offset) ⇒ Object
Reads a double from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
906 907 908 909 910 911 912 913 914 915 |
# File 'ext/snow-data/snow-data.c', line 906
static VALUE sd_get_double(VALUE self, VALUE sd_offset)
{
typedef double conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_DOUBLE_TO_NUM(value);
}
|
#get_float(offset) ⇒ Float
Reads a float from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
867 868 869 870 871 872 873 874 875 876 |
# File 'ext/snow-data/snow-data.c', line 867
static VALUE sd_get_float(VALUE self, VALUE sd_offset)
{
typedef float conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_FLOAT_TO_NUM(value);
}
|
#get_int(offset) ⇒ Integer
Reads a int from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
945 946 947 948 949 950 951 952 953 954 |
# File 'ext/snow-data/snow-data.c', line 945
static VALUE sd_get_int(VALUE self, VALUE sd_offset)
{
typedef int conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_INT_TO_NUM(value);
}
|
#get_int16(offset) ⇒ Object
Reads a int16_t from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
282 283 284 285 286 287 288 289 290 291 |
# File 'ext/snow-data/snow-data.c', line 282
static VALUE sd_get_int16(VALUE self, VALUE sd_offset)
{
typedef int16_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_INT16_TO_NUM(value);
}
|
#get_int32(offset) ⇒ Object
Reads a int32_t from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
321 322 323 324 325 326 327 328 329 330 |
# File 'ext/snow-data/snow-data.c', line 321
static VALUE sd_get_int32(VALUE self, VALUE sd_offset)
{
typedef int32_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_INT32_TO_NUM(value);
}
|
#get_int64(offset) ⇒ Object
Reads a int64_t from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
360 361 362 363 364 365 366 367 368 369 |
# File 'ext/snow-data/snow-data.c', line 360
static VALUE sd_get_int64(VALUE self, VALUE sd_offset)
{
typedef int64_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_INT64_TO_NUM(value);
}
|
#get_int8(offset) ⇒ Object
Reads a int8_t from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
243 244 245 246 247 248 249 250 251 252 |
# File 'ext/snow-data/snow-data.c', line 243
static VALUE sd_get_int8(VALUE self, VALUE sd_offset)
{
typedef int8_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_INT8_TO_NUM(value);
}
|
#get_intptr_t(offset) ⇒ Object
Reads a intptr_t from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
633 634 635 636 637 638 639 640 641 642 |
# File 'ext/snow-data/snow-data.c', line 633
static VALUE sd_get_intptr_t(VALUE self, VALUE sd_offset)
{
typedef intptr_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_INTPTR_T_TO_NUM(value);
}
|
#get_long(offset) ⇒ Integer
Reads a long from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
711 712 713 714 715 716 717 718 719 720 |
# File 'ext/snow-data/snow-data.c', line 711
static VALUE sd_get_long(VALUE self, VALUE sd_offset)
{
typedef long conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_LONG_TO_NUM(value);
}
|
#get_long_long(offset) ⇒ Integer
Reads a long long from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
750 751 752 753 754 755 756 757 758 759 |
# File 'ext/snow-data/snow-data.c', line 750
static VALUE sd_get_long_long(VALUE self, VALUE sd_offset)
{
typedef long long conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_LONG_LONG_TO_NUM(value);
}
|
#get_ptrdiff_t(offset) ⇒ Object
Reads a ptrdiff_t from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
594 595 596 597 598 599 600 601 602 603 |
# File 'ext/snow-data/snow-data.c', line 594
static VALUE sd_get_ptrdiff_t(VALUE self, VALUE sd_offset)
{
typedef ptrdiff_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_PTRDIFF_T_TO_NUM(value);
}
|
#get_short(offset) ⇒ Integer
Reads a short from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 |
# File 'ext/snow-data/snow-data.c', line 1023
static VALUE sd_get_short(VALUE self, VALUE sd_offset)
{
typedef short conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_SHORT_TO_NUM(value);
}
|
#get_signed_char(offset) ⇒ Object
Reads a signed char from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 |
# File 'ext/snow-data/snow-data.c', line 1179
static VALUE sd_get_signed_char(VALUE self, VALUE sd_offset)
{
typedef signed char conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_SIGNED_CHAR_TO_NUM(value);
}
|
#get_size_t(offset) ⇒ Object
Reads a size_t from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
555 556 557 558 559 560 561 562 563 564 |
# File 'ext/snow-data/snow-data.c', line 555
static VALUE sd_get_size_t(VALUE self, VALUE sd_offset)
{
typedef size_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_SIZE_T_TO_NUM(value);
}
|
#get_string(offset, length = nil) ⇒ String
Copies a string out of the block and returns it. The length argument is used to specify how the string is copied.
If length is nil, the string is extracted from offset up to the first null character. If length is -1, it extracts all characters from offset onward in the string and returns it. Otherwise, for any other length, it tries to copy length characters from the block before the end of the block.
This method does not work on zero-length blocks.
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 |
# File 'ext/snow-data/snow-data.c', line 1223
static VALUE sd_get_string(int argc, VALUE *argv, VALUE self)
{
VALUE sd_offset;
VALUE sd_length;
size_t offset;
size_t length = ~(size_t)0;
size_t self_length = NUM2SIZET(rb_ivar_get(self, kSD_IVAR_BYTESIZE));
const uint8_t *data = DATA_PTR(self);
sd_check_null_block(self);
rb_scan_args(argc, argv, "11", &sd_offset, &sd_length);
offset = NUM2SIZET(sd_offset);
if (offset >= self_length) {
return rb_str_new("", 0);
}
if (RTEST(sd_length)) {
length = NUM2SIZET(sd_length);
if (length == ~(size_t)0
|| (offset + length) > self_length
|| (offset + length) < offset) {
length = self_length - offset;
}
} else {
for (length = offset; length < self_length && data[length]; ++length)
;
length -= offset;
}
return rb_str_new((const char *)(data + offset), length);
}
|
#get_uint16(offset) ⇒ Object
Reads a uint16_t from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
438 439 440 441 442 443 444 445 446 447 |
# File 'ext/snow-data/snow-data.c', line 438
static VALUE sd_get_uint16(VALUE self, VALUE sd_offset)
{
typedef uint16_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_UINT16_TO_NUM(value);
}
|
#get_uint32(offset) ⇒ Object
Reads a uint32_t from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
477 478 479 480 481 482 483 484 485 486 |
# File 'ext/snow-data/snow-data.c', line 477
static VALUE sd_get_uint32(VALUE self, VALUE sd_offset)
{
typedef uint32_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_UINT32_TO_NUM(value);
}
|
#get_uint64(offset) ⇒ Object
Reads a uint64_t from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
516 517 518 519 520 521 522 523 524 525 |
# File 'ext/snow-data/snow-data.c', line 516
static VALUE sd_get_uint64(VALUE self, VALUE sd_offset)
{
typedef uint64_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_UINT64_TO_NUM(value);
}
|
#get_uint8(offset) ⇒ Object
Reads a uint8_t from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
399 400 401 402 403 404 405 406 407 408 |
# File 'ext/snow-data/snow-data.c', line 399
static VALUE sd_get_uint8(VALUE self, VALUE sd_offset)
{
typedef uint8_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_UINT8_TO_NUM(value);
}
|
#get_uintptr_t(offset) ⇒ Object
Reads a uintptr_t from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
672 673 674 675 676 677 678 679 680 681 |
# File 'ext/snow-data/snow-data.c', line 672
static VALUE sd_get_uintptr_t(VALUE self, VALUE sd_offset)
{
typedef uintptr_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_UINTPTR_T_TO_NUM(value);
}
|
#get_unsigned_char(offset) ⇒ Object
Reads a unsigned char from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 |
# File 'ext/snow-data/snow-data.c', line 1140
static VALUE sd_get_unsigned_char(VALUE self, VALUE sd_offset)
{
typedef unsigned char conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_UNSIGNED_CHAR_TO_NUM(value);
}
|
#get_unsigned_int(offset) ⇒ Integer
Reads a unsigned int from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
984 985 986 987 988 989 990 991 992 993 |
# File 'ext/snow-data/snow-data.c', line 984
static VALUE sd_get_unsigned_int(VALUE self, VALUE sd_offset)
{
typedef unsigned int conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_UNSIGNED_INT_TO_NUM(value);
}
|
#get_unsigned_long(offset) ⇒ Integer
Reads a unsigned long from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
789 790 791 792 793 794 795 796 797 798 |
# File 'ext/snow-data/snow-data.c', line 789
static VALUE sd_get_unsigned_long(VALUE self, VALUE sd_offset)
{
typedef unsigned long conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_UNSIGNED_LONG_TO_NUM(value);
}
|
#get_unsigned_long_long(offset) ⇒ Integer
Reads a unsigned long long from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
828 829 830 831 832 833 834 835 836 837 |
# File 'ext/snow-data/snow-data.c', line 828
static VALUE sd_get_unsigned_long_long(VALUE self, VALUE sd_offset)
{
typedef unsigned long long conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_UNSIGNED_LONG_LONG_TO_NUM(value);
}
|
#get_unsigned_short(offset) ⇒ Integer
Reads a unsigned short from the offset into the memory block and returns it. The offset is not bounds-checked and it is possible to read outside of bounds, which is considered undefined behavior and may crash or do other horrible things.
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 |
# File 'ext/snow-data/snow-data.c', line 1062
static VALUE sd_get_unsigned_short(VALUE self, VALUE sd_offset)
{
typedef unsigned short conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
return SD_UNSIGNED_SHORT_TO_NUM(value);
}
|
#inspect ⇒ Object
Returns a string showing the memory block’s classname, object ID, address, size, and alignment.
94 95 96 |
# File 'lib/snow-data/memory.rb', line 94 def inspect "<#{self.class}:0x#{__id__.to_s(16).rjust(14, ?0)} *0x#{self.address.to_s(16).rjust(14, ?0)}:#{self.bytesize}:#{self.alignment}>" end |
#null? ⇒ Boolean
Returns whether the memory block is pointing to a null address.
68 69 70 |
# File 'lib/snow-data/memory.rb', line 68 def null? self.address == 0 end |
#realloc!(size, alignment = nil) ⇒ self
Reallocates the memory backing this pointer with a new size and optionally a new alignment. If the new size is the same as the old size, the method returns early and nothing is reallocated.
If a new alignment is specified, the memory will be reallocated regardless of whether the new and old sizes are the same. If no alignment is specified, the memory’s previous alignment is used.
If the block for this memory was previously freed or the block is not owner by this object, a new block is allocated and the memory takes ownership of it. It is fine to realloc! on a previously freed block.
Raises a RangeError if either size is zero or alignment is not a power of two.
1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 |
# File 'ext/snow-data/snow-data.c', line 1547
static VALUE sd_memory_realloc(int argc, VALUE *argv, VALUE self)
{
struct RData *data;
void *new_data;
size_t size;
size_t prev_size;
size_t prev_align;
size_t alignment;
VALUE sd_size;
VALUE sd_alignment;
/*
Don't check for null/zero length here, as it is safe to reuse a memory via
realloc!. It's less safe for structs and arrays, but you just have to do the
sane thing in most cases. Granted, I'm a hypocrite for saying you need to
do the sane thing after writing this gem.
*/
rb_check_frozen(self);
rb_scan_args(argc, argv, "11", &sd_size, &sd_alignment);
size = NUM2SIZET(sd_size);
prev_align =
alignment = NUM2SIZET(rb_ivar_get(self, kSD_IVAR_ALIGNMENT));
prev_size = NUM2SIZET(rb_ivar_get(self, kSD_IVAR_BYTESIZE));
if (RTEST(sd_alignment)) {
alignment = NUM2SIZET(sd_alignment);
}
if (prev_size == size && alignment == prev_align) {
return self;
} else if (!is_power_of_two(alignment)) {
rb_raise(rb_eRangeError, "Alignment must be a power of two -- %zu is not a"
" power of two", alignment);
} else if (size < 1) {
rb_raise(rb_eRangeError, "Size of block must be 1 or more -- zero-byte"
" blocks are not permitted");
}
data = RDATA(self);
new_data = com_malloc(size, alignment);
if (data->data && prev_size > 0) {
const size_t copy_sizes[2] = { prev_size, size };
memcpy(new_data, data->data, copy_sizes[prev_size > size]);
}
if (data->dfree) {
data->dfree(data->data);
} else if (data->data) {
rb_warning("realloc called on unowned pointer %p -- allocating new block"
" and memcpying contents (size: %zd bytes), but original block will"
" not be freed.", data->data, prev_size);
}
data->data = new_data;
data->dfree = com_free;
rb_ivar_set(self, kSD_IVAR_BYTESIZE, SIZET2NUM(size));
rb_ivar_set(self, kSD_IVAR_ALIGNMENT, SIZET2NUM(alignment));
return self;
}
|
#set_char(offset, value) ⇒ Object
Sets a char at the offset to the value. Returns the assigned value.
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 |
# File 'ext/snow-data/snow-data.c', line 1118
static VALUE sd_set_char(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef char conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_CHAR(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_double(offset, value) ⇒ Object
Sets a double at the offset to the value. Returns the assigned value.
923 924 925 926 927 928 929 930 931 932 933 934 |
# File 'ext/snow-data/snow-data.c', line 923
static VALUE sd_set_double(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef double conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_DOUBLE(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_float(offset, value) ⇒ Object
Sets a float at the offset to the value. Returns the assigned value.
884 885 886 887 888 889 890 891 892 893 894 895 |
# File 'ext/snow-data/snow-data.c', line 884
static VALUE sd_set_float(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef float conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_FLOAT(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_int(offset, value) ⇒ Object
Sets a int at the offset to the value. Returns the assigned value.
962 963 964 965 966 967 968 969 970 971 972 973 |
# File 'ext/snow-data/snow-data.c', line 962
static VALUE sd_set_int(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef int conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_INT(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_int16(offset, value) ⇒ Object
Sets a int16_t at the offset to the value. Returns the assigned value.
299 300 301 302 303 304 305 306 307 308 309 310 |
# File 'ext/snow-data/snow-data.c', line 299
static VALUE sd_set_int16(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef int16_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_INT16(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_int32(offset, value) ⇒ Object
Sets a int32_t at the offset to the value. Returns the assigned value.
338 339 340 341 342 343 344 345 346 347 348 349 |
# File 'ext/snow-data/snow-data.c', line 338
static VALUE sd_set_int32(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef int32_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_INT32(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_int64(offset, value) ⇒ Object
Sets a int64_t at the offset to the value. Returns the assigned value.
377 378 379 380 381 382 383 384 385 386 387 388 |
# File 'ext/snow-data/snow-data.c', line 377
static VALUE sd_set_int64(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef int64_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_INT64(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_int8(offset, value) ⇒ Object
Sets a int8_t at the offset to the value. Returns the assigned value.
260 261 262 263 264 265 266 267 268 269 270 271 |
# File 'ext/snow-data/snow-data.c', line 260
static VALUE sd_set_int8(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef int8_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_INT8(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_intptr_t(offset, value) ⇒ Object
Sets a intptr_t at the offset to the value. Returns the assigned value.
650 651 652 653 654 655 656 657 658 659 660 661 |
# File 'ext/snow-data/snow-data.c', line 650
static VALUE sd_set_intptr_t(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef intptr_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_INTPTR_T(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_long(offset, value) ⇒ Object
Sets a long at the offset to the value. Returns the assigned value.
728 729 730 731 732 733 734 735 736 737 738 739 |
# File 'ext/snow-data/snow-data.c', line 728
static VALUE sd_set_long(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef long conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_LONG(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_long_long(offset, value) ⇒ Object
Sets a long long at the offset to the value. Returns the assigned value.
767 768 769 770 771 772 773 774 775 776 777 778 |
# File 'ext/snow-data/snow-data.c', line 767
static VALUE sd_set_long_long(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef long long conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_LONG_LONG(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_ptrdiff_t(offset, value) ⇒ Object
Sets a ptrdiff_t at the offset to the value. Returns the assigned value.
611 612 613 614 615 616 617 618 619 620 621 622 |
# File 'ext/snow-data/snow-data.c', line 611
static VALUE sd_set_ptrdiff_t(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef ptrdiff_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_PTRDIFF_T(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_short(offset, value) ⇒ Object
Sets a short at the offset to the value. Returns the assigned value.
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 |
# File 'ext/snow-data/snow-data.c', line 1040
static VALUE sd_set_short(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef short conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_SHORT(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_signed_char(offset, value) ⇒ Object
Sets a signed char at the offset to the value. Returns the assigned value.
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 |
# File 'ext/snow-data/snow-data.c', line 1196
static VALUE sd_set_signed_char(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef signed char conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_SIGNED_CHAR(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_size_t(offset, value) ⇒ Object
Sets a size_t at the offset to the value. Returns the assigned value.
572 573 574 575 576 577 578 579 580 581 582 583 |
# File 'ext/snow-data/snow-data.c', line 572
static VALUE sd_set_size_t(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef size_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_SIZE_T(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_string(offset, value, null_terminated = false) ⇒ Object
Copies the string value into the block at the offset supplied.
If null_terminated is true, it will always write a null-terminating character if it fits. This means that you need at least string.bytesize + 1 bytes available from the offset onwards to fully story a string, otherwise the string’s contents will be truncated to fit the null-terminating character.
If null_terminated is false, no null character is written and only the string bytes are copied to the block. If the full string does not fit, it will be truncated.
1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 |
# File 'ext/snow-data/snow-data.c', line 1303
static VALUE sd_set_string(int argc, VALUE *argv, VALUE self)
{
VALUE sd_offset, sd_value, sd_null_terminated;
sd_check_null_block(self);
rb_check_frozen(self);
rb_scan_args(argc, argv, "21", &sd_offset, &sd_value, &sd_null_terminated);
return sd_set_string_nullterm(self, sd_offset, sd_value, !!RTEST(sd_null_terminated));
}
|
#set_uint16(offset, value) ⇒ Object
Sets a uint16_t at the offset to the value. Returns the assigned value.
455 456 457 458 459 460 461 462 463 464 465 466 |
# File 'ext/snow-data/snow-data.c', line 455
static VALUE sd_set_uint16(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef uint16_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_UINT16(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_uint32(offset, value) ⇒ Object
Sets a uint32_t at the offset to the value. Returns the assigned value.
494 495 496 497 498 499 500 501 502 503 504 505 |
# File 'ext/snow-data/snow-data.c', line 494
static VALUE sd_set_uint32(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef uint32_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_UINT32(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_uint64(offset, value) ⇒ Object
Sets a uint64_t at the offset to the value. Returns the assigned value.
533 534 535 536 537 538 539 540 541 542 543 544 |
# File 'ext/snow-data/snow-data.c', line 533
static VALUE sd_set_uint64(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef uint64_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_UINT64(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_uint8(offset, value) ⇒ Object
Sets a uint8_t at the offset to the value. Returns the assigned value.
416 417 418 419 420 421 422 423 424 425 426 427 |
# File 'ext/snow-data/snow-data.c', line 416
static VALUE sd_set_uint8(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef uint8_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_UINT8(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_uintptr_t(offset, value) ⇒ Object
Sets a uintptr_t at the offset to the value. Returns the assigned value.
689 690 691 692 693 694 695 696 697 698 699 700 |
# File 'ext/snow-data/snow-data.c', line 689
static VALUE sd_set_uintptr_t(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef uintptr_t conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_UINTPTR_T(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_unsigned_char(offset, value) ⇒ Object
Sets a unsigned char at the offset to the value. Returns the assigned value.
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 |
# File 'ext/snow-data/snow-data.c', line 1157
static VALUE sd_set_unsigned_char(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef unsigned char conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_UNSIGNED_CHAR(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_unsigned_int(offset, value) ⇒ Object
Sets a unsigned int at the offset to the value. Returns the assigned value.
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 |
# File 'ext/snow-data/snow-data.c', line 1001
static VALUE sd_set_unsigned_int(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef unsigned int conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_UNSIGNED_INT(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_unsigned_long(offset, value) ⇒ Object
Sets a unsigned long at the offset to the value. Returns the assigned value.
806 807 808 809 810 811 812 813 814 815 816 817 |
# File 'ext/snow-data/snow-data.c', line 806
static VALUE sd_set_unsigned_long(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef unsigned long conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_UNSIGNED_LONG(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_unsigned_long_long(offset, value) ⇒ Object
Sets a unsigned long long at the offset to the value. Returns the assigned value.
845 846 847 848 849 850 851 852 853 854 855 856 |
# File 'ext/snow-data/snow-data.c', line 845
static VALUE sd_set_unsigned_long_long(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef unsigned long long conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_UNSIGNED_LONG_LONG(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#set_unsigned_short(offset, value) ⇒ Object
Sets a unsigned short at the offset to the value. Returns the assigned value.
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 |
# File 'ext/snow-data/snow-data.c', line 1079
static VALUE sd_set_unsigned_short(VALUE self, VALUE sd_offset, VALUE sd_value)
{
typedef unsigned short conv_type_t;
const size_t offset = NUM2SIZET(sd_offset);
conv_type_t value;
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
sd_check_null_block(self);
rb_check_frozen(self);
value = (conv_type_t)SD_NUM_TO_UNSIGNED_SHORT(sd_value);
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
return sd_value;
}
|
#to_s(null_terminated = true) ⇒ String
Gets a string representation of the contents of this block. If null_terminated is true (or nil), the returned string will end before the first null character.
1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 |
# File 'ext/snow-data/snow-data.c', line 1830
static VALUE sd_memory_to_s(int argc, VALUE *argv, VALUE self)
{
VALUE null_terminated;
size_t byte_size = NUM2SIZET(rb_ivar_get(self, kSD_IVAR_BYTESIZE));
const char *data = DATA_PTR(self);
sd_check_null_block(self);
rb_scan_args(argc, argv, "01", &null_terminated);
if (null_terminated == Qnil || RTEST(null_terminated)) {
size_t string_length = 0;
for (; string_length < byte_size && data[string_length]; ++string_length)
;
byte_size = string_length;
}
return rb_str_new(data, byte_size);
}
|