snow-data 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/COPYING +26 -0
- data/README.md +135 -0
- data/ext/extconf.rb +58 -0
- data/ext/snow-data/snow-data.c +1867 -0
- data/lib/snow-data.rb +8 -0
- data/lib/snow-data/c_struct.rb +724 -0
- data/lib/snow-data/memory.rb +92 -0
- data/lib/snow-data/version.rb +12 -0
- metadata +66 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 425085a25eb678abb07c07ba25d1a52142d86822
|
4
|
+
data.tar.gz: b04d708b4f18e405354bd56f7175e4ddaec4291e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f03aa50d5ad415403388c91d3560b0c3ca188ef8309797c3f3e6f342380c4880b37e224dd025870fa420ec8819b8d7d8a68e0e7aea13d63ab16b150b1228a846
|
7
|
+
data.tar.gz: 17975205c4c120f24ebd00ebe0feb6d47699847a063564a51e42f6a9b66a50d95a4b1ceb6414081bfe79620f6f9dd7ef235a37745db6616a84f738cb0caa1629
|
data/COPYING
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Copyright (c) 2013, Noel Raymond Cower <ncower@gmail.com>.
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
8
|
+
list of conditions and the following disclaimer.
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
|
13
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
14
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
15
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
16
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
17
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
18
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
19
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
20
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
21
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
22
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
23
|
+
|
24
|
+
The views and conclusions contained in the software and documentation are those
|
25
|
+
of the authors and should not be interpreted as representing official policies,
|
26
|
+
either expressed or implied, of the FreeBSD Project.
|
data/README.md
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
snow-data
|
2
|
+
=========
|
3
|
+
|
4
|
+
$ gem install snow-data [ -- [--warn-implicit-size] [--warn-no-bytesize] ]
|
5
|
+
|
6
|
+
|
7
|
+
Intro
|
8
|
+
-----
|
9
|
+
|
10
|
+
Snow-Data is a simple gem for dealing with memory and defining structs in a
|
11
|
+
C-like way. Incidentally, it's also hideously unsafe, so everything is tainted
|
12
|
+
by default. You'll thank me for this later, even if almost every operation does
|
13
|
+
bounds-checking where possible to ensure you're not being a horrible person.
|
14
|
+
|
15
|
+
For more information on usage, see the rdoc documentation for Snow::Memory
|
16
|
+
and Snow::CStruct, as it explains the important things. Like CStructs. And how
|
17
|
+
to talk to people. Ok, it can't help you with that.
|
18
|
+
|
19
|
+
_ALLONS-Y!_
|
20
|
+
|
21
|
+
|
22
|
+
Example
|
23
|
+
-------
|
24
|
+
|
25
|
+
For those wanting a quick-ish example of using snow-data, I'll include one here
|
26
|
+
showing you how you might define a few structs, including a Vec3, Vec2, Color,
|
27
|
+
and Vertex and working with those.
|
28
|
+
|
29
|
+
Bear in mind that, down the road, it will also be possible to assign snow-math
|
30
|
+
types to these as well (provided they use the same underlying types), though I
|
31
|
+
wouldn't use this for defining data types for anything other than transit to
|
32
|
+
another API that expects its data in a format like this.
|
33
|
+
|
34
|
+
How you use it, ultimately, is really up to you.
|
35
|
+
|
36
|
+
#!/usr/bin/env ruby -w
|
37
|
+
|
38
|
+
require 'snow-data'
|
39
|
+
|
40
|
+
# Defines a struct { float x, y, z; } and a struct { float x, y; }, essentially,
|
41
|
+
# all of whose members are 4-byte aligned (this is the default for floats, but
|
42
|
+
# it helps to illustrate that you can specify alignment).
|
43
|
+
Vec3 = Snow::CStruct[:Vec3, 'x: float :4; y: float :4; z: float :4']
|
44
|
+
Vec2 = Snow::CStruct[:Vec2, 'x: float :4; y: float :4']
|
45
|
+
# ui8 is shorthand for uint8_t -- you can write either, and the documentation
|
46
|
+
# for CStruct::new explains the short- and long-form names for each primitive
|
47
|
+
# type provided by Snow-Data. Further, CStructs defined with a name, as with
|
48
|
+
# Vec3, Vec2, and Color, have getters and setters defined in the Memory class
|
49
|
+
# and are usable as member types, as I'll show below.
|
50
|
+
Color = Snow::CStruct[:Color, 'r: ui8; g: ui8; b: ui8; a: ui8']
|
51
|
+
|
52
|
+
# Define a vertex type whose members are all also 4-byte aligned. The vertex
|
53
|
+
# itself has a position, a normal, two texcoords (e.g., diffuse and lightmap),
|
54
|
+
# and a color value. Because we've not given Vertex a name (no :Vertex argument
|
55
|
+
# to CStruct), it isn't usable as a type for struct members.
|
56
|
+
Vertex = Snow::CStruct[<<END_TYPE]
|
57
|
+
position: Vec3 : 4
|
58
|
+
normal: Vec3 : 4
|
59
|
+
texcoord: Vec2[2] : 4
|
60
|
+
color: Color : 4
|
61
|
+
END_TYPE
|
62
|
+
|
63
|
+
# So let's create a vertex.
|
64
|
+
a_vertex = Vertex.new { |v|
|
65
|
+
v.position = Vec3.new { |p| p.x = 1; p.y = 2; p.z = 3 }
|
66
|
+
v.normal = Vec3.new { |n| n.x = 0.707107; n.y = 0; n.z = 0.707107 }
|
67
|
+
# For array types, we must use set_* functions, as the name= shorthand for
|
68
|
+
# struct members only assigns to the first element of an array.
|
69
|
+
v.texcoord = Vec2.new { |t| t.x = 1.0; t.y = 1.0 }
|
70
|
+
# Though if you're masochistic you could also do this:
|
71
|
+
v.__send__(:texcoord=, Vec2.new { |t| t.x = 0.5; t.y = 0.5 }, 1)
|
72
|
+
v.color = Color.new { |c| c.r = 255; c.g = 127; c.b = 63; c.a = 220 }
|
73
|
+
}
|
74
|
+
|
75
|
+
puts <<VERTEX_DESCRIPTION
|
76
|
+
Our vertex has the following properties:
|
77
|
+
Position: #{a_vertex.position.to_h}
|
78
|
+
Normal: #{a_vertex.normal.to_h}
|
79
|
+
Texcoords: [
|
80
|
+
#{a_vertex.texcoord(0).to_h}
|
81
|
+
#{a_vertex.texcoord(1).to_h}
|
82
|
+
]
|
83
|
+
Color: #{a_vertex.color.to_h}
|
84
|
+
|
85
|
+
VERTEX_DESCRIPTION
|
86
|
+
|
87
|
+
# For kicks, let's create an array.
|
88
|
+
some_vertices = Vertex[64]
|
89
|
+
|
90
|
+
# And set all vertices to the above vertex.
|
91
|
+
some_vertices.map! { a_vertex }
|
92
|
+
|
93
|
+
puts <<VERTEX_DESCRIPTION
|
94
|
+
Our vertex in the array at index 36 has the following properties:
|
95
|
+
Position: #{some_vertices[36].position.to_h}
|
96
|
+
Normal: #{some_vertices[36].normal.to_h}
|
97
|
+
Texcoords: [
|
98
|
+
#{some_vertices[36].texcoord(0).to_h}
|
99
|
+
#{some_vertices[36].texcoord(1).to_h}
|
100
|
+
]
|
101
|
+
Color: #{some_vertices[36].color.to_h}
|
102
|
+
VERTEX_DESCRIPTION
|
103
|
+
|
104
|
+
|
105
|
+
License
|
106
|
+
-------
|
107
|
+
|
108
|
+
Snow-Data is licensed under a simplified BSD license, like most of my gems.
|
109
|
+
|
110
|
+
Copyright (c) 2013, Noel Raymond Cower <ncower@gmail.com>.
|
111
|
+
All rights reserved.
|
112
|
+
|
113
|
+
Redistribution and use in source and binary forms, with or without
|
114
|
+
modification, are permitted provided that the following conditions are met:
|
115
|
+
|
116
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
117
|
+
list of conditions and the following disclaimer.
|
118
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
119
|
+
this list of conditions and the following disclaimer in the documentation
|
120
|
+
and/or other materials provided with the distribution.
|
121
|
+
|
122
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
123
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
124
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
125
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
126
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
127
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
128
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
129
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
130
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
131
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
132
|
+
|
133
|
+
The views and conclusions contained in the software and documentation are those
|
134
|
+
of the authors and should not be interpreted as representing official policies,
|
135
|
+
either expressed or implied, of the FreeBSD Project.
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
#! /usr/bin/env ruby -w
|
2
|
+
# This file is part of ruby-snowmath.
|
3
|
+
# Copyright (c) 2013 Noel Raymond Cower. All rights reserved.
|
4
|
+
# See COPYING for license details.
|
5
|
+
|
6
|
+
require 'mkmf'
|
7
|
+
|
8
|
+
# Compile as C99
|
9
|
+
$CFLAGS += " -std=c99 -Wall -pedantic"
|
10
|
+
|
11
|
+
OptKVPair = Struct.new(:key, :value)
|
12
|
+
|
13
|
+
option_mappings = {
|
14
|
+
'-D' => OptKVPair[:build_debug, true],
|
15
|
+
'--debug' => OptKVPair[:build_debug, true],
|
16
|
+
'-ND' => OptKVPair[:build_debug, false],
|
17
|
+
'--release' => OptKVPair[:build_debug, false],
|
18
|
+
'--warn-implicit-size' => OptKVPair[:warn_implicit_size, true],
|
19
|
+
'-Ws' => OptKVPair[:warn_implicit_size, true],
|
20
|
+
'--warn-no-bytesize' => OptKVPair[:warn_no_bytesize, true],
|
21
|
+
'-Wbs' => OptKVPair[:warn_implicit_size, true],
|
22
|
+
'--debug-memory-copy' => OptKVPair[:debug_memory_copy, true],
|
23
|
+
'--debug-allocations' => OptKVPair[:debug_allocations, true]
|
24
|
+
}
|
25
|
+
|
26
|
+
options = {
|
27
|
+
:build_debug => false,
|
28
|
+
:warn_implicit_size => false,
|
29
|
+
:warn_no_bytesize => false,
|
30
|
+
:debug_memory_copy => false,
|
31
|
+
:debug_allocations => false
|
32
|
+
}
|
33
|
+
|
34
|
+
ARGV.each {
|
35
|
+
|arg|
|
36
|
+
pair = option_mappings[arg]
|
37
|
+
if pair
|
38
|
+
options[pair.key] = pair.value
|
39
|
+
else
|
40
|
+
$stderr.puts "Unrecognized install option: #{arg}"
|
41
|
+
end
|
42
|
+
}
|
43
|
+
|
44
|
+
if options[:build_debug]
|
45
|
+
$CFLAGS += " -g"
|
46
|
+
$stdout.puts "Building extension in debug mode"
|
47
|
+
else
|
48
|
+
# mfpmath is ignored on clang, FYI
|
49
|
+
$CFLAGS += " -O3 -fno-strict-aliasing"
|
50
|
+
$stdout.puts "Building extension in release mode"
|
51
|
+
end
|
52
|
+
|
53
|
+
$CFLAGS += ' -DSD_SD_WARN_ON_IMPLICIT_COPY_SIZE' if options[:warn_implicit_size]
|
54
|
+
$CFLAGS += ' -DSD_WARN_ON_NO_BYTESIZE_METHOD' if options[:warn_no_bytesize]
|
55
|
+
$CFLAGS += ' -DSD_VERBOSE_COPY_LOG' if options[:debug_memory_copy]
|
56
|
+
$CFLAGS += ' -DSD_VERBOSE_MALLOC_LOG' if options[:debug_allocations]
|
57
|
+
|
58
|
+
create_makefile('snow-data/snowdata_bindings', 'snow-data/')
|
@@ -0,0 +1,1867 @@
|
|
1
|
+
/*
|
2
|
+
This file is part of ruby-snowdata.
|
3
|
+
Copyright (c) 2013 Noel Raymond Cower. All rights reserved.
|
4
|
+
See COPYING for license details.
|
5
|
+
*/
|
6
|
+
|
7
|
+
#include "ruby.h"
|
8
|
+
#include <stdint.h>
|
9
|
+
#include <stdio.h>
|
10
|
+
|
11
|
+
static ID kSD_IVAR_BYTESIZE;
|
12
|
+
static ID kSD_IVAR_ALIGNMENT;
|
13
|
+
static ID kSD_ID_BYTESIZE;
|
14
|
+
static ID kSD_ID_ADDRESS;
|
15
|
+
|
16
|
+
#define SD_INT8_TO_NUM(X) INT2FIX(X)
|
17
|
+
#define SD_INT16_TO_NUM(X) INT2FIX(X)
|
18
|
+
#define SD_INT32_TO_NUM(X) INT2FIX(X)
|
19
|
+
#define SD_NUM_TO_INT8(X) ((int8_t)INT2FIX(X))
|
20
|
+
#define SD_NUM_TO_INT16(X) ((int16_t)INT2FIX(X))
|
21
|
+
#define SD_NUM_TO_INT32(X) ((int32_t)INT2FIX(X))
|
22
|
+
|
23
|
+
#if INT64_MAX <= INT_MAX
|
24
|
+
#define SD_INT64_TO_NUM(X) INT2FIX(X)
|
25
|
+
#define SD_NUM_TO_INT64(X) ((int64_t)NUM2INT(X))
|
26
|
+
#elif INT64_MAX == LONG_MAX
|
27
|
+
#define SD_INT64_TO_NUM(X) LONG2NUM(X)
|
28
|
+
#define SD_NUM_TO_INT64(X) ((int64_t)NUM2LONG(X))
|
29
|
+
#elif INT64_MAX == LLONG_MAX
|
30
|
+
#define SD_INT64_TO_NUM(X) ULL2NUM(X)
|
31
|
+
#define SD_NUM_TO_INT64(X) ((int64_t)NUM2LL(X))
|
32
|
+
#else
|
33
|
+
#error int64_t is not sizeof int, long, or long long
|
34
|
+
#endif
|
35
|
+
|
36
|
+
#define SD_UINT8_TO_NUM(X) UINT2NUM(X)
|
37
|
+
#define SD_UINT16_TO_NUM(X) UINT2NUM(X)
|
38
|
+
#define SD_UINT32_TO_NUM(X) UINT2NUM(X)
|
39
|
+
|
40
|
+
#define SD_NUM_TO_UINT8(X) ((uint8_t)NUM2UINT(X))
|
41
|
+
#define SD_NUM_TO_UINT16(X) ((uint16_t)NUM2UINT(X))
|
42
|
+
#define SD_NUM_TO_UINT32(X) ((uint32_t)NUM2UINT(X))
|
43
|
+
|
44
|
+
#if UINT64_MAX <= UINT_MAX
|
45
|
+
#define SD_UINT64_TO_NUM(X) UINT2NUM(X)
|
46
|
+
#define SD_NUM_TO_UINT64(X) ((uint64_t)NUM2UINT(X))
|
47
|
+
#elif UINT64_MAX == ULONG_MAX
|
48
|
+
#define SD_UINT64_TO_NUM(X) ULONG2NUM(X)
|
49
|
+
#define SD_NUM_TO_UINT64(X) ((uint64_t)NUM2ULONG(X))
|
50
|
+
#elif UINT64_MAX == ULLONG_MAX
|
51
|
+
#define SD_UINT64_TO_NUM(X) ULL2NUM(X)
|
52
|
+
#define SD_NUM_TO_UINT64(X) ((uint64_t)NUM2ULL(X))
|
53
|
+
#else
|
54
|
+
#error uint64_t is not sizeof unsigned int, unsigned long, or unsigned long long
|
55
|
+
#endif
|
56
|
+
|
57
|
+
#define SD_SIZE_T_TO_NUM(X) SIZET2NUM(X)
|
58
|
+
#define SD_NUM_TO_SIZE_T(X) NUM2SIZET(X)
|
59
|
+
|
60
|
+
#if SIZEOF_PTRDIFF_T <= SIZEOF_INT
|
61
|
+
#define SD_PTRDIFF_T_TO_NUM(X) INT2FIX(X)
|
62
|
+
#define SD_NUM_TO_PTRDIFF_T(X) ((ptrdiff_t)NUM2INT(X))
|
63
|
+
#elif SIZEOF_PTRDIFF_T == SIZEOF_LONG
|
64
|
+
#define SD_PTRDIFF_T_TO_NUM(X) LONG2FIX(X)
|
65
|
+
#define SD_NUM_TO_PTRDIFF_T(X) ((ptrdiff_t)NUM2LONG(X))
|
66
|
+
#elif SIZEOF_PTRDIFF_T == SIZEOF_LONG_LONG
|
67
|
+
#define SD_PTRDIFF_T_TO_NUM(X) LL2NUM(X)
|
68
|
+
#define SD_NUM_TO_PTRDIFF_T(X) ((ptrdiff_t)NUM2LL(X))
|
69
|
+
#else
|
70
|
+
#error ptrdiff_t is not sizeof unsigned int, unsigned long, or unsigned long long
|
71
|
+
#endif
|
72
|
+
|
73
|
+
#if SIZEOF_INTPTR_T <= SIZEOF_INT
|
74
|
+
#define SD_INTPTR_T_TO_NUM(X) INT2FIX(X)
|
75
|
+
#define SD_NUM_TO_INTPTR_T(X) ((intptr_t)NUM2INT(X))
|
76
|
+
#elif SIZEOF_INTPTR_T == SIZEOF_LONG
|
77
|
+
#define SD_INTPTR_T_TO_NUM(X) LONG2FIX(X)
|
78
|
+
#define SD_NUM_TO_INTPTR_T(X) ((intptr_t)NUM2LONG(X))
|
79
|
+
#elif SIZEOF_INTPTR_T == SIZEOF_LONG_LONG
|
80
|
+
#define SD_INTPTR_T_TO_NUM(X) LL2NUM(X)
|
81
|
+
#define SD_NUM_TO_INTPTR_T(X) ((intptr_t)NUM2LL(X))
|
82
|
+
#else
|
83
|
+
#error intptr_t is not sizeof unsigned int, unsigned long, or unsigned long long
|
84
|
+
#endif
|
85
|
+
|
86
|
+
|
87
|
+
#if SIZEOF_UINTPTR_T <= SIZEOF_INT
|
88
|
+
#define SD_UINTPTR_T_TO_NUM(X) INT2FIX(X)
|
89
|
+
#define SD_NUM_TO_UINTPTR_T(X) ((uintptr_t)NUM2INT(X))
|
90
|
+
#elif SIZEOF_UINTPTR_T == SIZEOF_LONG
|
91
|
+
#define SD_UINTPTR_T_TO_NUM(X) LONG2FIX(X)
|
92
|
+
#define SD_NUM_TO_UINTPTR_T(X) ((uintptr_t)NUM2LONG(X))
|
93
|
+
#elif SIZEOF_UINTPTR_T == SIZEOF_LONG_LONG
|
94
|
+
#define SD_UINTPTR_T_TO_NUM(X) LL2NUM(X)
|
95
|
+
#define SD_NUM_TO_UINTPTR_T(X) ((uintptr_t)NUM2LL(X))
|
96
|
+
#else
|
97
|
+
#error uintptr_t is not sizeof unsigned int, unsigned long, or unsigned long long
|
98
|
+
#endif
|
99
|
+
|
100
|
+
#define SD_LONG_TO_NUM(X) LONG2FIX(X)
|
101
|
+
#define SD_LONG_LONG_TO_NUM(X) LL2NUM(X)
|
102
|
+
#define SD_UNSIGNED_LONG_TO_NUM(X) ULONG2NUM(X)
|
103
|
+
#define SD_UNSIGNED_LONG_LONG_TO_NUM(X) ULL2NUM(X)
|
104
|
+
#define SD_FLOAT_TO_NUM(X) rb_float_new((double)(X))
|
105
|
+
#define SD_DOUBLE_TO_NUM(X) rb_float_new(X)
|
106
|
+
#define SD_INT_TO_NUM(X) INT2FIX(X)
|
107
|
+
#define SD_UNSIGNED_INT_TO_NUM(X) UINT2NUM(X)
|
108
|
+
#define SD_SHORT_TO_NUM(X) INT2FIX(X)
|
109
|
+
#define SD_UNSIGNED_SHORT_TO_NUM(X) UINT2NUM(X)
|
110
|
+
#define SD_CHAR_TO_NUM(X) CHR2FIX(X)
|
111
|
+
#define SD_UNSIGNED_CHAR_TO_NUM(X) UINT2NUM(X)
|
112
|
+
#define SD_SIGNED_CHAR_TO_NUM(X) INT2FIX(X)
|
113
|
+
|
114
|
+
#define SD_NUM_TO_LONG(X) ((long)NUM2LONG(X))
|
115
|
+
#define SD_NUM_TO_LONG_LONG(X) ((long long)NUM2LL(X))
|
116
|
+
#define SD_NUM_TO_UNSIGNED_LONG(X) ((unsigned long)NUM2ULONG(X))
|
117
|
+
#define SD_NUM_TO_UNSIGNED_LONG_LONG(X) ((unsigned long long)NUM2ULL(X))
|
118
|
+
#define SD_NUM_TO_FLOAT(X) ((float)rb_num2dbl(X))
|
119
|
+
#define SD_NUM_TO_DOUBLE(X) ((double)rb_num2dbl(X))
|
120
|
+
#define SD_NUM_TO_INT(X) ((int)NUM2INT(X))
|
121
|
+
#define SD_NUM_TO_UNSIGNED_INT(X) ((unsigned int)NUM2UINT(X))
|
122
|
+
#define SD_NUM_TO_SHORT(X) ((short)NUM2INT(X))
|
123
|
+
#define SD_NUM_TO_UNSIGNED_SHORT(X) ((unsigned short)NUM2UINT(X))
|
124
|
+
#define SD_NUM_TO_CHAR(X) ((char)NUM2CHR(X))
|
125
|
+
#define SD_NUM_TO_UNSIGNED_CHAR(X) ((unsigned char)NUM2UINT(X))
|
126
|
+
#define SD_NUM_TO_SIGNED_CHAR(X) ((signed char)NUM2INT(X))
|
127
|
+
|
128
|
+
static void sd_check_null_block(VALUE self)
|
129
|
+
{
|
130
|
+
if (DATA_PTR(self) == NULL) {
|
131
|
+
rb_raise(rb_eRuntimeError, "Pointer is NULL");
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
static void sd_check_block_bounds(VALUE self, size_t offset, size_t size)
|
136
|
+
{
|
137
|
+
const size_t block_size = NUM2SIZET(rb_ivar_get(self, kSD_IVAR_BYTESIZE));
|
138
|
+
if (offset >= block_size) {
|
139
|
+
rb_raise(rb_eRangeError,
|
140
|
+
"Offset %zu is out of bounds for block with size %zu",
|
141
|
+
offset, block_size);
|
142
|
+
} else if (offset + size > block_size || offset + size < offset) {
|
143
|
+
rb_raise(rb_eRangeError,
|
144
|
+
"Offset(%zu) + size(%zu) is out of bounds for block with size %zu",
|
145
|
+
offset, size, block_size);
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
/*
|
150
|
+
Returns 1 if size is a power of two and nonzero, otherwise returns 0.
|
151
|
+
*/
|
152
|
+
static int is_power_of_two(size_t size)
|
153
|
+
{
|
154
|
+
return ((size & (size - 1)) == 0) && (size != 0);
|
155
|
+
}
|
156
|
+
|
157
|
+
/*
|
158
|
+
Returns a size aligned to the given alignment. The alignment must be a power
|
159
|
+
of two.
|
160
|
+
*/
|
161
|
+
static size_t align_size(size_t size, size_t alignment)
|
162
|
+
{
|
163
|
+
return (size + (alignment - 1)) & ~(alignment - 1);
|
164
|
+
}
|
165
|
+
|
166
|
+
/*
|
167
|
+
Given a pointer, returns it aligned to the given alignment. In most cases,
|
168
|
+
this results in no change.
|
169
|
+
*/
|
170
|
+
static void *align_ptr(void *ptr, size_t alignment)
|
171
|
+
{
|
172
|
+
return (void *)(((intptr_t)ptr + (alignment - 1)) & ~(alignment - 1));
|
173
|
+
}
|
174
|
+
|
175
|
+
/*
|
176
|
+
Allocated a block of memory of at least size bytes aligned to the given byte
|
177
|
+
alignment.
|
178
|
+
*/
|
179
|
+
static void *com_malloc(size_t size, size_t alignment)
|
180
|
+
{
|
181
|
+
const size_t aligned_size = align_size(size + sizeof(void *), alignment);
|
182
|
+
void *const ptr = xcalloc(aligned_size, 1);
|
183
|
+
void **const aligned_ptr = align_ptr((uint8_t *)ptr + sizeof(void *), alignment);
|
184
|
+
aligned_ptr[-1] = ptr;
|
185
|
+
#ifdef SD_VERBOSE_MALLOC_LOG
|
186
|
+
fprintf(stderr, "Allocated block %p with aligned size %zu (requested: %zu"
|
187
|
+
" aligned to %zu bytes), returning aligned pointer %p with usable size %td\n",
|
188
|
+
ptr, aligned_size, size, alignment, aligned_ptr,
|
189
|
+
(uint8_t *)(ptr + aligned_size) - (uint8_t *)aligned_ptr);
|
190
|
+
#endif
|
191
|
+
return aligned_ptr;
|
192
|
+
}
|
193
|
+
|
194
|
+
/*
|
195
|
+
Frees memory previously allocated by com_malloc. This _does not work_ if it
|
196
|
+
was allocated by any other means.
|
197
|
+
*/
|
198
|
+
static void com_free(void *aligned_ptr)
|
199
|
+
{
|
200
|
+
#ifdef SD_VERBOSE_MALLOC_LOG
|
201
|
+
fprintf(stderr, "Deallocating aligned pointer %p with underlying pointer %p\n",
|
202
|
+
aligned_ptr,
|
203
|
+
((void **)aligned_ptr)[-1]);
|
204
|
+
#endif
|
205
|
+
xfree(((void **)aligned_ptr)[-1]);
|
206
|
+
}
|
207
|
+
|
208
|
+
/*
|
209
|
+
call-seq:
|
210
|
+
get_int8(offset) => int8_t
|
211
|
+
|
212
|
+
Reads a int8_t from the offset into the memory block and returns it.
|
213
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
214
|
+
which is considered undefined behavior and may crash or do other horrible
|
215
|
+
things.
|
216
|
+
*/
|
217
|
+
static VALUE sd_get_int8(VALUE self, VALUE sd_offset)
|
218
|
+
{
|
219
|
+
typedef int8_t conv_type_t;
|
220
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
221
|
+
conv_type_t value;
|
222
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
223
|
+
sd_check_null_block(self);
|
224
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
225
|
+
return SD_INT8_TO_NUM(value);
|
226
|
+
}
|
227
|
+
|
228
|
+
/*
|
229
|
+
call-seq:
|
230
|
+
set_int8(offset, value) => value
|
231
|
+
|
232
|
+
Sets a int8_t at the offset to the value. Returns the assigned value.
|
233
|
+
*/
|
234
|
+
static VALUE sd_set_int8(VALUE self, VALUE sd_offset, VALUE sd_value)
|
235
|
+
{
|
236
|
+
typedef int8_t conv_type_t;
|
237
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
238
|
+
conv_type_t value;
|
239
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
240
|
+
sd_check_null_block(self);
|
241
|
+
rb_check_frozen(self);
|
242
|
+
value = (conv_type_t)SD_NUM_TO_INT8(sd_value);
|
243
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
244
|
+
return sd_value;
|
245
|
+
}
|
246
|
+
|
247
|
+
/*
|
248
|
+
call-seq:
|
249
|
+
get_int16(offset) => int16_t
|
250
|
+
|
251
|
+
Reads a int16_t from the offset into the memory block and returns it.
|
252
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
253
|
+
which is considered undefined behavior and may crash or do other horrible
|
254
|
+
things.
|
255
|
+
*/
|
256
|
+
static VALUE sd_get_int16(VALUE self, VALUE sd_offset)
|
257
|
+
{
|
258
|
+
typedef int16_t conv_type_t;
|
259
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
260
|
+
conv_type_t value;
|
261
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
262
|
+
sd_check_null_block(self);
|
263
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
264
|
+
return SD_INT16_TO_NUM(value);
|
265
|
+
}
|
266
|
+
|
267
|
+
/*
|
268
|
+
call-seq:
|
269
|
+
set_int16(offset, value) => value
|
270
|
+
|
271
|
+
Sets a int16_t at the offset to the value. Returns the assigned value.
|
272
|
+
*/
|
273
|
+
static VALUE sd_set_int16(VALUE self, VALUE sd_offset, VALUE sd_value)
|
274
|
+
{
|
275
|
+
typedef int16_t conv_type_t;
|
276
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
277
|
+
conv_type_t value;
|
278
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
279
|
+
sd_check_null_block(self);
|
280
|
+
rb_check_frozen(self);
|
281
|
+
value = (conv_type_t)SD_NUM_TO_INT16(sd_value);
|
282
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
283
|
+
return sd_value;
|
284
|
+
}
|
285
|
+
|
286
|
+
/*
|
287
|
+
call-seq:
|
288
|
+
get_int32(offset) => int32_t
|
289
|
+
|
290
|
+
Reads a int32_t from the offset into the memory block and returns it.
|
291
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
292
|
+
which is considered undefined behavior and may crash or do other horrible
|
293
|
+
things.
|
294
|
+
*/
|
295
|
+
static VALUE sd_get_int32(VALUE self, VALUE sd_offset)
|
296
|
+
{
|
297
|
+
typedef int32_t conv_type_t;
|
298
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
299
|
+
conv_type_t value;
|
300
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
301
|
+
sd_check_null_block(self);
|
302
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
303
|
+
return SD_INT32_TO_NUM(value);
|
304
|
+
}
|
305
|
+
|
306
|
+
/*
|
307
|
+
call-seq:
|
308
|
+
set_int32(offset, value) => value
|
309
|
+
|
310
|
+
Sets a int32_t at the offset to the value. Returns the assigned value.
|
311
|
+
*/
|
312
|
+
static VALUE sd_set_int32(VALUE self, VALUE sd_offset, VALUE sd_value)
|
313
|
+
{
|
314
|
+
typedef int32_t conv_type_t;
|
315
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
316
|
+
conv_type_t value;
|
317
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
318
|
+
sd_check_null_block(self);
|
319
|
+
rb_check_frozen(self);
|
320
|
+
value = (conv_type_t)SD_NUM_TO_INT32(sd_value);
|
321
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
322
|
+
return sd_value;
|
323
|
+
}
|
324
|
+
|
325
|
+
/*
|
326
|
+
call-seq:
|
327
|
+
get_int64(offset) => int64_t
|
328
|
+
|
329
|
+
Reads a int64_t from the offset into the memory block and returns it.
|
330
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
331
|
+
which is considered undefined behavior and may crash or do other horrible
|
332
|
+
things.
|
333
|
+
*/
|
334
|
+
static VALUE sd_get_int64(VALUE self, VALUE sd_offset)
|
335
|
+
{
|
336
|
+
typedef int64_t conv_type_t;
|
337
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
338
|
+
conv_type_t value;
|
339
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
340
|
+
sd_check_null_block(self);
|
341
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
342
|
+
return SD_INT64_TO_NUM(value);
|
343
|
+
}
|
344
|
+
|
345
|
+
/*
|
346
|
+
call-seq:
|
347
|
+
set_int64(offset, value) => value
|
348
|
+
|
349
|
+
Sets a int64_t at the offset to the value. Returns the assigned value.
|
350
|
+
*/
|
351
|
+
static VALUE sd_set_int64(VALUE self, VALUE sd_offset, VALUE sd_value)
|
352
|
+
{
|
353
|
+
typedef int64_t conv_type_t;
|
354
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
355
|
+
conv_type_t value;
|
356
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
357
|
+
sd_check_null_block(self);
|
358
|
+
rb_check_frozen(self);
|
359
|
+
value = (conv_type_t)SD_NUM_TO_INT64(sd_value);
|
360
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
361
|
+
return sd_value;
|
362
|
+
}
|
363
|
+
|
364
|
+
/*
|
365
|
+
call-seq:
|
366
|
+
get_uint8(offset) => uint8_t
|
367
|
+
|
368
|
+
Reads a uint8_t from the offset into the memory block and returns it.
|
369
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
370
|
+
which is considered undefined behavior and may crash or do other horrible
|
371
|
+
things.
|
372
|
+
*/
|
373
|
+
static VALUE sd_get_uint8(VALUE self, VALUE sd_offset)
|
374
|
+
{
|
375
|
+
typedef uint8_t conv_type_t;
|
376
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
377
|
+
conv_type_t value;
|
378
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
379
|
+
sd_check_null_block(self);
|
380
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
381
|
+
return SD_UINT8_TO_NUM(value);
|
382
|
+
}
|
383
|
+
|
384
|
+
/*
|
385
|
+
call-seq:
|
386
|
+
set_uint8(offset, value) => value
|
387
|
+
|
388
|
+
Sets a uint8_t at the offset to the value. Returns the assigned value.
|
389
|
+
*/
|
390
|
+
static VALUE sd_set_uint8(VALUE self, VALUE sd_offset, VALUE sd_value)
|
391
|
+
{
|
392
|
+
typedef uint8_t conv_type_t;
|
393
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
394
|
+
conv_type_t value;
|
395
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
396
|
+
sd_check_null_block(self);
|
397
|
+
rb_check_frozen(self);
|
398
|
+
value = (conv_type_t)SD_NUM_TO_UINT8(sd_value);
|
399
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
400
|
+
return sd_value;
|
401
|
+
}
|
402
|
+
|
403
|
+
/*
|
404
|
+
call-seq:
|
405
|
+
get_uint16(offset) => uint16_t
|
406
|
+
|
407
|
+
Reads a uint16_t from the offset into the memory block and returns it.
|
408
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
409
|
+
which is considered undefined behavior and may crash or do other horrible
|
410
|
+
things.
|
411
|
+
*/
|
412
|
+
static VALUE sd_get_uint16(VALUE self, VALUE sd_offset)
|
413
|
+
{
|
414
|
+
typedef uint16_t conv_type_t;
|
415
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
416
|
+
conv_type_t value;
|
417
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
418
|
+
sd_check_null_block(self);
|
419
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
420
|
+
return SD_UINT16_TO_NUM(value);
|
421
|
+
}
|
422
|
+
|
423
|
+
/*
|
424
|
+
call-seq:
|
425
|
+
set_uint16(offset, value) => value
|
426
|
+
|
427
|
+
Sets a uint16_t at the offset to the value. Returns the assigned value.
|
428
|
+
*/
|
429
|
+
static VALUE sd_set_uint16(VALUE self, VALUE sd_offset, VALUE sd_value)
|
430
|
+
{
|
431
|
+
typedef uint16_t conv_type_t;
|
432
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
433
|
+
conv_type_t value;
|
434
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
435
|
+
sd_check_null_block(self);
|
436
|
+
rb_check_frozen(self);
|
437
|
+
value = (conv_type_t)SD_NUM_TO_UINT16(sd_value);
|
438
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
439
|
+
return sd_value;
|
440
|
+
}
|
441
|
+
|
442
|
+
/*
|
443
|
+
call-seq:
|
444
|
+
get_uint32(offset) => uint32_t
|
445
|
+
|
446
|
+
Reads a uint32_t from the offset into the memory block and returns it.
|
447
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
448
|
+
which is considered undefined behavior and may crash or do other horrible
|
449
|
+
things.
|
450
|
+
*/
|
451
|
+
static VALUE sd_get_uint32(VALUE self, VALUE sd_offset)
|
452
|
+
{
|
453
|
+
typedef uint32_t conv_type_t;
|
454
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
455
|
+
conv_type_t value;
|
456
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
457
|
+
sd_check_null_block(self);
|
458
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
459
|
+
return SD_UINT32_TO_NUM(value);
|
460
|
+
}
|
461
|
+
|
462
|
+
/*
|
463
|
+
call-seq:
|
464
|
+
set_uint32(offset, value) => value
|
465
|
+
|
466
|
+
Sets a uint32_t at the offset to the value. Returns the assigned value.
|
467
|
+
*/
|
468
|
+
static VALUE sd_set_uint32(VALUE self, VALUE sd_offset, VALUE sd_value)
|
469
|
+
{
|
470
|
+
typedef uint32_t conv_type_t;
|
471
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
472
|
+
conv_type_t value;
|
473
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
474
|
+
sd_check_null_block(self);
|
475
|
+
rb_check_frozen(self);
|
476
|
+
value = (conv_type_t)SD_NUM_TO_UINT32(sd_value);
|
477
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
478
|
+
return sd_value;
|
479
|
+
}
|
480
|
+
|
481
|
+
/*
|
482
|
+
call-seq:
|
483
|
+
get_uint64(offset) => uint64_t
|
484
|
+
|
485
|
+
Reads a uint64_t from the offset into the memory block and returns it.
|
486
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
487
|
+
which is considered undefined behavior and may crash or do other horrible
|
488
|
+
things.
|
489
|
+
*/
|
490
|
+
static VALUE sd_get_uint64(VALUE self, VALUE sd_offset)
|
491
|
+
{
|
492
|
+
typedef uint64_t conv_type_t;
|
493
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
494
|
+
conv_type_t value;
|
495
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
496
|
+
sd_check_null_block(self);
|
497
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
498
|
+
return SD_UINT64_TO_NUM(value);
|
499
|
+
}
|
500
|
+
|
501
|
+
/*
|
502
|
+
call-seq:
|
503
|
+
set_uint64(offset, value) => value
|
504
|
+
|
505
|
+
Sets a uint64_t at the offset to the value. Returns the assigned value.
|
506
|
+
*/
|
507
|
+
static VALUE sd_set_uint64(VALUE self, VALUE sd_offset, VALUE sd_value)
|
508
|
+
{
|
509
|
+
typedef uint64_t conv_type_t;
|
510
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
511
|
+
conv_type_t value;
|
512
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
513
|
+
sd_check_null_block(self);
|
514
|
+
rb_check_frozen(self);
|
515
|
+
value = (conv_type_t)SD_NUM_TO_UINT64(sd_value);
|
516
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
517
|
+
return sd_value;
|
518
|
+
}
|
519
|
+
|
520
|
+
/*
|
521
|
+
call-seq:
|
522
|
+
get_size_t(offset) => size_t
|
523
|
+
|
524
|
+
Reads a size_t from the offset into the memory block and returns it.
|
525
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
526
|
+
which is considered undefined behavior and may crash or do other horrible
|
527
|
+
things.
|
528
|
+
*/
|
529
|
+
static VALUE sd_get_size_t(VALUE self, VALUE sd_offset)
|
530
|
+
{
|
531
|
+
typedef size_t conv_type_t;
|
532
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
533
|
+
conv_type_t value;
|
534
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
535
|
+
sd_check_null_block(self);
|
536
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
537
|
+
return SD_SIZE_T_TO_NUM(value);
|
538
|
+
}
|
539
|
+
|
540
|
+
/*
|
541
|
+
call-seq:
|
542
|
+
set_size_t(offset, value) => value
|
543
|
+
|
544
|
+
Sets a size_t at the offset to the value. Returns the assigned value.
|
545
|
+
*/
|
546
|
+
static VALUE sd_set_size_t(VALUE self, VALUE sd_offset, VALUE sd_value)
|
547
|
+
{
|
548
|
+
typedef size_t conv_type_t;
|
549
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
550
|
+
conv_type_t value;
|
551
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
552
|
+
sd_check_null_block(self);
|
553
|
+
rb_check_frozen(self);
|
554
|
+
value = (conv_type_t)SD_NUM_TO_SIZE_T(sd_value);
|
555
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
556
|
+
return sd_value;
|
557
|
+
}
|
558
|
+
|
559
|
+
/*
|
560
|
+
call-seq:
|
561
|
+
get_ptrdiff_t(offset) => ptrdiff_t
|
562
|
+
|
563
|
+
Reads a ptrdiff_t from the offset into the memory block and returns it.
|
564
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
565
|
+
which is considered undefined behavior and may crash or do other horrible
|
566
|
+
things.
|
567
|
+
*/
|
568
|
+
static VALUE sd_get_ptrdiff_t(VALUE self, VALUE sd_offset)
|
569
|
+
{
|
570
|
+
typedef ptrdiff_t conv_type_t;
|
571
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
572
|
+
conv_type_t value;
|
573
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
574
|
+
sd_check_null_block(self);
|
575
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
576
|
+
return SD_PTRDIFF_T_TO_NUM(value);
|
577
|
+
}
|
578
|
+
|
579
|
+
/*
|
580
|
+
call-seq:
|
581
|
+
set_ptrdiff_t(offset, value) => value
|
582
|
+
|
583
|
+
Sets a ptrdiff_t at the offset to the value. Returns the assigned value.
|
584
|
+
*/
|
585
|
+
static VALUE sd_set_ptrdiff_t(VALUE self, VALUE sd_offset, VALUE sd_value)
|
586
|
+
{
|
587
|
+
typedef ptrdiff_t conv_type_t;
|
588
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
589
|
+
conv_type_t value;
|
590
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
591
|
+
sd_check_null_block(self);
|
592
|
+
rb_check_frozen(self);
|
593
|
+
value = (conv_type_t)SD_NUM_TO_PTRDIFF_T(sd_value);
|
594
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
595
|
+
return sd_value;
|
596
|
+
}
|
597
|
+
|
598
|
+
/*
|
599
|
+
call-seq:
|
600
|
+
get_intptr_t(offset) => intptr_t
|
601
|
+
|
602
|
+
Reads a intptr_t from the offset into the memory block and returns it.
|
603
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
604
|
+
which is considered undefined behavior and may crash or do other horrible
|
605
|
+
things.
|
606
|
+
*/
|
607
|
+
static VALUE sd_get_intptr_t(VALUE self, VALUE sd_offset)
|
608
|
+
{
|
609
|
+
typedef intptr_t conv_type_t;
|
610
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
611
|
+
conv_type_t value;
|
612
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
613
|
+
sd_check_null_block(self);
|
614
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
615
|
+
return SD_INTPTR_T_TO_NUM(value);
|
616
|
+
}
|
617
|
+
|
618
|
+
/*
|
619
|
+
call-seq:
|
620
|
+
set_intptr_t(offset, value) => value
|
621
|
+
|
622
|
+
Sets a intptr_t at the offset to the value. Returns the assigned value.
|
623
|
+
*/
|
624
|
+
static VALUE sd_set_intptr_t(VALUE self, VALUE sd_offset, VALUE sd_value)
|
625
|
+
{
|
626
|
+
typedef intptr_t conv_type_t;
|
627
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
628
|
+
conv_type_t value;
|
629
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
630
|
+
sd_check_null_block(self);
|
631
|
+
rb_check_frozen(self);
|
632
|
+
value = (conv_type_t)SD_NUM_TO_INTPTR_T(sd_value);
|
633
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
634
|
+
return sd_value;
|
635
|
+
}
|
636
|
+
|
637
|
+
/*
|
638
|
+
call-seq:
|
639
|
+
get_uintptr_t(offset) => uintptr_t
|
640
|
+
|
641
|
+
Reads a uintptr_t from the offset into the memory block and returns it.
|
642
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
643
|
+
which is considered undefined behavior and may crash or do other horrible
|
644
|
+
things.
|
645
|
+
*/
|
646
|
+
static VALUE sd_get_uintptr_t(VALUE self, VALUE sd_offset)
|
647
|
+
{
|
648
|
+
typedef uintptr_t conv_type_t;
|
649
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
650
|
+
conv_type_t value;
|
651
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
652
|
+
sd_check_null_block(self);
|
653
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
654
|
+
return SD_UINTPTR_T_TO_NUM(value);
|
655
|
+
}
|
656
|
+
|
657
|
+
/*
|
658
|
+
call-seq:
|
659
|
+
set_uintptr_t(offset, value) => value
|
660
|
+
|
661
|
+
Sets a uintptr_t at the offset to the value. Returns the assigned value.
|
662
|
+
*/
|
663
|
+
static VALUE sd_set_uintptr_t(VALUE self, VALUE sd_offset, VALUE sd_value)
|
664
|
+
{
|
665
|
+
typedef uintptr_t conv_type_t;
|
666
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
667
|
+
conv_type_t value;
|
668
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
669
|
+
sd_check_null_block(self);
|
670
|
+
rb_check_frozen(self);
|
671
|
+
value = (conv_type_t)SD_NUM_TO_UINTPTR_T(sd_value);
|
672
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
673
|
+
return sd_value;
|
674
|
+
}
|
675
|
+
|
676
|
+
/*
|
677
|
+
call-seq:
|
678
|
+
get_long(offset) => long
|
679
|
+
|
680
|
+
Reads a long from the offset into the memory block and returns it.
|
681
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
682
|
+
which is considered undefined behavior and may crash or do other horrible
|
683
|
+
things.
|
684
|
+
*/
|
685
|
+
static VALUE sd_get_long(VALUE self, VALUE sd_offset)
|
686
|
+
{
|
687
|
+
typedef long conv_type_t;
|
688
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
689
|
+
conv_type_t value;
|
690
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
691
|
+
sd_check_null_block(self);
|
692
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
693
|
+
return SD_LONG_TO_NUM(value);
|
694
|
+
}
|
695
|
+
|
696
|
+
/*
|
697
|
+
call-seq:
|
698
|
+
set_long(offset, value) => value
|
699
|
+
|
700
|
+
Sets a long at the offset to the value. Returns the assigned value.
|
701
|
+
*/
|
702
|
+
static VALUE sd_set_long(VALUE self, VALUE sd_offset, VALUE sd_value)
|
703
|
+
{
|
704
|
+
typedef long conv_type_t;
|
705
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
706
|
+
conv_type_t value;
|
707
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
708
|
+
sd_check_null_block(self);
|
709
|
+
rb_check_frozen(self);
|
710
|
+
value = (conv_type_t)SD_NUM_TO_LONG(sd_value);
|
711
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
712
|
+
return sd_value;
|
713
|
+
}
|
714
|
+
|
715
|
+
/*
|
716
|
+
call-seq:
|
717
|
+
get_long_long(offset) => long long
|
718
|
+
|
719
|
+
Reads a long long from the offset into the memory block and returns it.
|
720
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
721
|
+
which is considered undefined behavior and may crash or do other horrible
|
722
|
+
things.
|
723
|
+
*/
|
724
|
+
static VALUE sd_get_long_long(VALUE self, VALUE sd_offset)
|
725
|
+
{
|
726
|
+
typedef long long conv_type_t;
|
727
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
728
|
+
conv_type_t value;
|
729
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
730
|
+
sd_check_null_block(self);
|
731
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
732
|
+
return SD_LONG_LONG_TO_NUM(value);
|
733
|
+
}
|
734
|
+
|
735
|
+
/*
|
736
|
+
call-seq:
|
737
|
+
set_long_long(offset, value) => value
|
738
|
+
|
739
|
+
Sets a long long at the offset to the value. Returns the assigned value.
|
740
|
+
*/
|
741
|
+
static VALUE sd_set_long_long(VALUE self, VALUE sd_offset, VALUE sd_value)
|
742
|
+
{
|
743
|
+
typedef long long conv_type_t;
|
744
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
745
|
+
conv_type_t value;
|
746
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
747
|
+
sd_check_null_block(self);
|
748
|
+
rb_check_frozen(self);
|
749
|
+
value = (conv_type_t)SD_NUM_TO_LONG_LONG(sd_value);
|
750
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
751
|
+
return sd_value;
|
752
|
+
}
|
753
|
+
|
754
|
+
/*
|
755
|
+
call-seq:
|
756
|
+
get_unsigned_long(offset) => unsigned long
|
757
|
+
|
758
|
+
Reads a unsigned long from the offset into the memory block and returns it.
|
759
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
760
|
+
which is considered undefined behavior and may crash or do other horrible
|
761
|
+
things.
|
762
|
+
*/
|
763
|
+
static VALUE sd_get_unsigned_long(VALUE self, VALUE sd_offset)
|
764
|
+
{
|
765
|
+
typedef unsigned long conv_type_t;
|
766
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
767
|
+
conv_type_t value;
|
768
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
769
|
+
sd_check_null_block(self);
|
770
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
771
|
+
return SD_UNSIGNED_LONG_TO_NUM(value);
|
772
|
+
}
|
773
|
+
|
774
|
+
/*
|
775
|
+
call-seq:
|
776
|
+
set_unsigned_long(offset, value) => value
|
777
|
+
|
778
|
+
Sets a unsigned long at the offset to the value. Returns the assigned value.
|
779
|
+
*/
|
780
|
+
static VALUE sd_set_unsigned_long(VALUE self, VALUE sd_offset, VALUE sd_value)
|
781
|
+
{
|
782
|
+
typedef unsigned long conv_type_t;
|
783
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
784
|
+
conv_type_t value;
|
785
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
786
|
+
sd_check_null_block(self);
|
787
|
+
rb_check_frozen(self);
|
788
|
+
value = (conv_type_t)SD_NUM_TO_UNSIGNED_LONG(sd_value);
|
789
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
790
|
+
return sd_value;
|
791
|
+
}
|
792
|
+
|
793
|
+
/*
|
794
|
+
call-seq:
|
795
|
+
get_unsigned_long_long(offset) => unsigned long long
|
796
|
+
|
797
|
+
Reads a unsigned long long from the offset into the memory block and returns it.
|
798
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
799
|
+
which is considered undefined behavior and may crash or do other horrible
|
800
|
+
things.
|
801
|
+
*/
|
802
|
+
static VALUE sd_get_unsigned_long_long(VALUE self, VALUE sd_offset)
|
803
|
+
{
|
804
|
+
typedef unsigned long long conv_type_t;
|
805
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
806
|
+
conv_type_t value;
|
807
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
808
|
+
sd_check_null_block(self);
|
809
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
810
|
+
return SD_UNSIGNED_LONG_LONG_TO_NUM(value);
|
811
|
+
}
|
812
|
+
|
813
|
+
/*
|
814
|
+
call-seq:
|
815
|
+
set_unsigned_long_long(offset, value) => value
|
816
|
+
|
817
|
+
Sets a unsigned long long at the offset to the value. Returns the assigned value.
|
818
|
+
*/
|
819
|
+
static VALUE sd_set_unsigned_long_long(VALUE self, VALUE sd_offset, VALUE sd_value)
|
820
|
+
{
|
821
|
+
typedef unsigned long long conv_type_t;
|
822
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
823
|
+
conv_type_t value;
|
824
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
825
|
+
sd_check_null_block(self);
|
826
|
+
rb_check_frozen(self);
|
827
|
+
value = (conv_type_t)SD_NUM_TO_UNSIGNED_LONG_LONG(sd_value);
|
828
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
829
|
+
return sd_value;
|
830
|
+
}
|
831
|
+
|
832
|
+
/*
|
833
|
+
call-seq:
|
834
|
+
get_float(offset) => float
|
835
|
+
|
836
|
+
Reads a float from the offset into the memory block and returns it.
|
837
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
838
|
+
which is considered undefined behavior and may crash or do other horrible
|
839
|
+
things.
|
840
|
+
*/
|
841
|
+
static VALUE sd_get_float(VALUE self, VALUE sd_offset)
|
842
|
+
{
|
843
|
+
typedef float conv_type_t;
|
844
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
845
|
+
conv_type_t value;
|
846
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
847
|
+
sd_check_null_block(self);
|
848
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
849
|
+
return SD_FLOAT_TO_NUM(value);
|
850
|
+
}
|
851
|
+
|
852
|
+
/*
|
853
|
+
call-seq:
|
854
|
+
set_float(offset, value) => value
|
855
|
+
|
856
|
+
Sets a float at the offset to the value. Returns the assigned value.
|
857
|
+
*/
|
858
|
+
static VALUE sd_set_float(VALUE self, VALUE sd_offset, VALUE sd_value)
|
859
|
+
{
|
860
|
+
typedef float conv_type_t;
|
861
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
862
|
+
conv_type_t value;
|
863
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
864
|
+
sd_check_null_block(self);
|
865
|
+
rb_check_frozen(self);
|
866
|
+
value = (conv_type_t)SD_NUM_TO_FLOAT(sd_value);
|
867
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
868
|
+
return sd_value;
|
869
|
+
}
|
870
|
+
|
871
|
+
/*
|
872
|
+
call-seq:
|
873
|
+
get_double(offset) => double
|
874
|
+
|
875
|
+
Reads a double from the offset into the memory block and returns it.
|
876
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
877
|
+
which is considered undefined behavior and may crash or do other horrible
|
878
|
+
things.
|
879
|
+
*/
|
880
|
+
static VALUE sd_get_double(VALUE self, VALUE sd_offset)
|
881
|
+
{
|
882
|
+
typedef double conv_type_t;
|
883
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
884
|
+
conv_type_t value;
|
885
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
886
|
+
sd_check_null_block(self);
|
887
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
888
|
+
return SD_DOUBLE_TO_NUM(value);
|
889
|
+
}
|
890
|
+
|
891
|
+
/*
|
892
|
+
call-seq:
|
893
|
+
set_double(offset, value) => value
|
894
|
+
|
895
|
+
Sets a double at the offset to the value. Returns the assigned value.
|
896
|
+
*/
|
897
|
+
static VALUE sd_set_double(VALUE self, VALUE sd_offset, VALUE sd_value)
|
898
|
+
{
|
899
|
+
typedef double conv_type_t;
|
900
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
901
|
+
conv_type_t value;
|
902
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
903
|
+
sd_check_null_block(self);
|
904
|
+
rb_check_frozen(self);
|
905
|
+
value = (conv_type_t)SD_NUM_TO_DOUBLE(sd_value);
|
906
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
907
|
+
return sd_value;
|
908
|
+
}
|
909
|
+
|
910
|
+
/*
|
911
|
+
call-seq:
|
912
|
+
get_int(offset) => int
|
913
|
+
|
914
|
+
Reads a int from the offset into the memory block and returns it.
|
915
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
916
|
+
which is considered undefined behavior and may crash or do other horrible
|
917
|
+
things.
|
918
|
+
*/
|
919
|
+
static VALUE sd_get_int(VALUE self, VALUE sd_offset)
|
920
|
+
{
|
921
|
+
typedef int conv_type_t;
|
922
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
923
|
+
conv_type_t value;
|
924
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
925
|
+
sd_check_null_block(self);
|
926
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
927
|
+
return SD_INT_TO_NUM(value);
|
928
|
+
}
|
929
|
+
|
930
|
+
/*
|
931
|
+
call-seq:
|
932
|
+
set_int(offset, value) => value
|
933
|
+
|
934
|
+
Sets a int at the offset to the value. Returns the assigned value.
|
935
|
+
*/
|
936
|
+
static VALUE sd_set_int(VALUE self, VALUE sd_offset, VALUE sd_value)
|
937
|
+
{
|
938
|
+
typedef int conv_type_t;
|
939
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
940
|
+
conv_type_t value;
|
941
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
942
|
+
sd_check_null_block(self);
|
943
|
+
rb_check_frozen(self);
|
944
|
+
value = (conv_type_t)SD_NUM_TO_INT(sd_value);
|
945
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
946
|
+
return sd_value;
|
947
|
+
}
|
948
|
+
|
949
|
+
/*
|
950
|
+
call-seq:
|
951
|
+
get_unsigned_int(offset) => unsigned int
|
952
|
+
|
953
|
+
Reads a unsigned int from the offset into the memory block and returns it.
|
954
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
955
|
+
which is considered undefined behavior and may crash or do other horrible
|
956
|
+
things.
|
957
|
+
*/
|
958
|
+
static VALUE sd_get_unsigned_int(VALUE self, VALUE sd_offset)
|
959
|
+
{
|
960
|
+
typedef unsigned int conv_type_t;
|
961
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
962
|
+
conv_type_t value;
|
963
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
964
|
+
sd_check_null_block(self);
|
965
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
966
|
+
return SD_UNSIGNED_INT_TO_NUM(value);
|
967
|
+
}
|
968
|
+
|
969
|
+
/*
|
970
|
+
call-seq:
|
971
|
+
set_unsigned_int(offset, value) => value
|
972
|
+
|
973
|
+
Sets a unsigned int at the offset to the value. Returns the assigned value.
|
974
|
+
*/
|
975
|
+
static VALUE sd_set_unsigned_int(VALUE self, VALUE sd_offset, VALUE sd_value)
|
976
|
+
{
|
977
|
+
typedef unsigned int conv_type_t;
|
978
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
979
|
+
conv_type_t value;
|
980
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
981
|
+
sd_check_null_block(self);
|
982
|
+
rb_check_frozen(self);
|
983
|
+
value = (conv_type_t)SD_NUM_TO_UNSIGNED_INT(sd_value);
|
984
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
985
|
+
return sd_value;
|
986
|
+
}
|
987
|
+
|
988
|
+
/*
|
989
|
+
call-seq:
|
990
|
+
get_short(offset) => short
|
991
|
+
|
992
|
+
Reads a short from the offset into the memory block and returns it.
|
993
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
994
|
+
which is considered undefined behavior and may crash or do other horrible
|
995
|
+
things.
|
996
|
+
*/
|
997
|
+
static VALUE sd_get_short(VALUE self, VALUE sd_offset)
|
998
|
+
{
|
999
|
+
typedef short conv_type_t;
|
1000
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
1001
|
+
conv_type_t value;
|
1002
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
1003
|
+
sd_check_null_block(self);
|
1004
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
1005
|
+
return SD_SHORT_TO_NUM(value);
|
1006
|
+
}
|
1007
|
+
|
1008
|
+
/*
|
1009
|
+
call-seq:
|
1010
|
+
set_short(offset, value) => value
|
1011
|
+
|
1012
|
+
Sets a short at the offset to the value. Returns the assigned value.
|
1013
|
+
*/
|
1014
|
+
static VALUE sd_set_short(VALUE self, VALUE sd_offset, VALUE sd_value)
|
1015
|
+
{
|
1016
|
+
typedef short conv_type_t;
|
1017
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
1018
|
+
conv_type_t value;
|
1019
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
1020
|
+
sd_check_null_block(self);
|
1021
|
+
rb_check_frozen(self);
|
1022
|
+
value = (conv_type_t)SD_NUM_TO_SHORT(sd_value);
|
1023
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
1024
|
+
return sd_value;
|
1025
|
+
}
|
1026
|
+
|
1027
|
+
/*
|
1028
|
+
call-seq:
|
1029
|
+
get_unsigned_short(offset) => unsigned short
|
1030
|
+
|
1031
|
+
Reads a unsigned short from the offset into the memory block and returns it.
|
1032
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
1033
|
+
which is considered undefined behavior and may crash or do other horrible
|
1034
|
+
things.
|
1035
|
+
*/
|
1036
|
+
static VALUE sd_get_unsigned_short(VALUE self, VALUE sd_offset)
|
1037
|
+
{
|
1038
|
+
typedef unsigned short conv_type_t;
|
1039
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
1040
|
+
conv_type_t value;
|
1041
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
1042
|
+
sd_check_null_block(self);
|
1043
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
1044
|
+
return SD_UNSIGNED_SHORT_TO_NUM(value);
|
1045
|
+
}
|
1046
|
+
|
1047
|
+
/*
|
1048
|
+
call-seq:
|
1049
|
+
set_unsigned_short(offset, value) => value
|
1050
|
+
|
1051
|
+
Sets a unsigned short at the offset to the value. Returns the assigned value.
|
1052
|
+
*/
|
1053
|
+
static VALUE sd_set_unsigned_short(VALUE self, VALUE sd_offset, VALUE sd_value)
|
1054
|
+
{
|
1055
|
+
typedef unsigned short conv_type_t;
|
1056
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
1057
|
+
conv_type_t value;
|
1058
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
1059
|
+
sd_check_null_block(self);
|
1060
|
+
rb_check_frozen(self);
|
1061
|
+
value = (conv_type_t)SD_NUM_TO_UNSIGNED_SHORT(sd_value);
|
1062
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
1063
|
+
return sd_value;
|
1064
|
+
}
|
1065
|
+
|
1066
|
+
/*
|
1067
|
+
call-seq:
|
1068
|
+
get_char(offset) => char
|
1069
|
+
|
1070
|
+
Reads a char from the offset into the memory block and returns it.
|
1071
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
1072
|
+
which is considered undefined behavior and may crash or do other horrible
|
1073
|
+
things.
|
1074
|
+
*/
|
1075
|
+
static VALUE sd_get_char(VALUE self, VALUE sd_offset)
|
1076
|
+
{
|
1077
|
+
typedef char conv_type_t;
|
1078
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
1079
|
+
conv_type_t value;
|
1080
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
1081
|
+
sd_check_null_block(self);
|
1082
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
1083
|
+
return SD_CHAR_TO_NUM(value);
|
1084
|
+
}
|
1085
|
+
|
1086
|
+
/*
|
1087
|
+
call-seq:
|
1088
|
+
set_char(offset, value) => value
|
1089
|
+
|
1090
|
+
Sets a char at the offset to the value. Returns the assigned value.
|
1091
|
+
*/
|
1092
|
+
static VALUE sd_set_char(VALUE self, VALUE sd_offset, VALUE sd_value)
|
1093
|
+
{
|
1094
|
+
typedef char conv_type_t;
|
1095
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
1096
|
+
conv_type_t value;
|
1097
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
1098
|
+
sd_check_null_block(self);
|
1099
|
+
rb_check_frozen(self);
|
1100
|
+
value = (conv_type_t)SD_NUM_TO_CHAR(sd_value);
|
1101
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
1102
|
+
return sd_value;
|
1103
|
+
}
|
1104
|
+
|
1105
|
+
/*
|
1106
|
+
call-seq:
|
1107
|
+
get_unsigned_char(offset) => unsigned char
|
1108
|
+
|
1109
|
+
Reads a unsigned char from the offset into the memory block and returns it.
|
1110
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
1111
|
+
which is considered undefined behavior and may crash or do other horrible
|
1112
|
+
things.
|
1113
|
+
*/
|
1114
|
+
static VALUE sd_get_unsigned_char(VALUE self, VALUE sd_offset)
|
1115
|
+
{
|
1116
|
+
typedef unsigned char conv_type_t;
|
1117
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
1118
|
+
conv_type_t value;
|
1119
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
1120
|
+
sd_check_null_block(self);
|
1121
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
1122
|
+
return SD_UNSIGNED_CHAR_TO_NUM(value);
|
1123
|
+
}
|
1124
|
+
|
1125
|
+
/*
|
1126
|
+
call-seq:
|
1127
|
+
set_unsigned_char(offset, value) => value
|
1128
|
+
|
1129
|
+
Sets a unsigned char at the offset to the value. Returns the assigned value.
|
1130
|
+
*/
|
1131
|
+
static VALUE sd_set_unsigned_char(VALUE self, VALUE sd_offset, VALUE sd_value)
|
1132
|
+
{
|
1133
|
+
typedef unsigned char conv_type_t;
|
1134
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
1135
|
+
conv_type_t value;
|
1136
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
1137
|
+
sd_check_null_block(self);
|
1138
|
+
rb_check_frozen(self);
|
1139
|
+
value = (conv_type_t)SD_NUM_TO_UNSIGNED_CHAR(sd_value);
|
1140
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
1141
|
+
return sd_value;
|
1142
|
+
}
|
1143
|
+
|
1144
|
+
/*
|
1145
|
+
call-seq:
|
1146
|
+
get_signed_char(offset) => signed char
|
1147
|
+
|
1148
|
+
Reads a signed char from the offset into the memory block and returns it.
|
1149
|
+
The offset is not bounds-checked and it is possible to read outside of bounds,
|
1150
|
+
which is considered undefined behavior and may crash or do other horrible
|
1151
|
+
things.
|
1152
|
+
*/
|
1153
|
+
static VALUE sd_get_signed_char(VALUE self, VALUE sd_offset)
|
1154
|
+
{
|
1155
|
+
typedef signed char conv_type_t;
|
1156
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
1157
|
+
conv_type_t value;
|
1158
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
1159
|
+
sd_check_null_block(self);
|
1160
|
+
value = *(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset);
|
1161
|
+
return SD_SIGNED_CHAR_TO_NUM(value);
|
1162
|
+
}
|
1163
|
+
|
1164
|
+
/*
|
1165
|
+
call-seq:
|
1166
|
+
set_signed_char(offset, value) => value
|
1167
|
+
|
1168
|
+
Sets a signed char at the offset to the value. Returns the assigned value.
|
1169
|
+
*/
|
1170
|
+
static VALUE sd_set_signed_char(VALUE self, VALUE sd_offset, VALUE sd_value)
|
1171
|
+
{
|
1172
|
+
typedef signed char conv_type_t;
|
1173
|
+
const size_t offset = NUM2SIZET(sd_offset);
|
1174
|
+
conv_type_t value;
|
1175
|
+
sd_check_block_bounds(self, offset, sizeof(conv_type_t));
|
1176
|
+
sd_check_null_block(self);
|
1177
|
+
rb_check_frozen(self);
|
1178
|
+
value = (conv_type_t)SD_NUM_TO_SIGNED_CHAR(sd_value);
|
1179
|
+
*(conv_type_t *)(((uint8_t *)RDATA(self)->data) + offset) = value;
|
1180
|
+
return sd_value;
|
1181
|
+
}
|
1182
|
+
|
1183
|
+
/*
|
1184
|
+
call-seq:
|
1185
|
+
get_string(offset, length = nil) -> String
|
1186
|
+
|
1187
|
+
Copies a string out of the block and returns it. The length argument is used
|
1188
|
+
to specify how the string is copied.
|
1189
|
+
|
1190
|
+
If length is nil, the string is extracted from offset up to the first null
|
1191
|
+
character. If length is -1, it extracts all characters from offset onward in
|
1192
|
+
the string and returns it. Otherwise, for any other length, it tries to copy
|
1193
|
+
length characters from the block before the end of the block.
|
1194
|
+
|
1195
|
+
This method does not work on zero-length blocks.
|
1196
|
+
*/
|
1197
|
+
static VALUE sd_get_string(int argc, VALUE *argv, VALUE self)
|
1198
|
+
{
|
1199
|
+
VALUE sd_offset;
|
1200
|
+
VALUE sd_length;
|
1201
|
+
size_t offset;
|
1202
|
+
size_t length = ~(size_t)0;
|
1203
|
+
size_t self_length = NUM2SIZET(rb_ivar_get(self, kSD_IVAR_BYTESIZE));
|
1204
|
+
const uint8_t *data = DATA_PTR(self);
|
1205
|
+
|
1206
|
+
sd_check_null_block(self);
|
1207
|
+
|
1208
|
+
rb_scan_args(argc, argv, "11", &sd_offset, &sd_length);
|
1209
|
+
|
1210
|
+
offset = NUM2SIZET(sd_offset);
|
1211
|
+
|
1212
|
+
if (offset >= self_length) {
|
1213
|
+
return rb_str_new("", 0);
|
1214
|
+
}
|
1215
|
+
|
1216
|
+
if (RTEST(sd_length)) {
|
1217
|
+
length = NUM2SIZET(sd_length);
|
1218
|
+
|
1219
|
+
if (length == ~(size_t)0
|
1220
|
+
|| (offset + length) > self_length
|
1221
|
+
|| (offset + length) < offset) {
|
1222
|
+
length = self_length - offset;
|
1223
|
+
}
|
1224
|
+
} else {
|
1225
|
+
for (length = offset; length < self_length && data[length]; ++length)
|
1226
|
+
;
|
1227
|
+
length -= offset;
|
1228
|
+
}
|
1229
|
+
|
1230
|
+
return rb_str_new((const char *)(data + offset), length);
|
1231
|
+
}
|
1232
|
+
|
1233
|
+
static VALUE sd_set_string_nullterm(VALUE self, VALUE sd_offset, VALUE sd_value, int null_terminated)
|
1234
|
+
{
|
1235
|
+
uint8_t *data = DATA_PTR(self);
|
1236
|
+
const uint8_t *string_data = (const uint8_t *)StringValueCStr(sd_value);
|
1237
|
+
size_t offset = NUM2SIZET(sd_offset);
|
1238
|
+
/* Subtract 1 from the block length to account for a null character) */
|
1239
|
+
size_t length = NUM2SIZET(rb_ivar_get(self, kSD_IVAR_BYTESIZE)) - null_terminated;
|
1240
|
+
size_t str_length = RSTRING_LEN(sd_value);
|
1241
|
+
|
1242
|
+
if (offset >= length) {
|
1243
|
+
return sd_value;
|
1244
|
+
}
|
1245
|
+
|
1246
|
+
length -= offset;
|
1247
|
+
if (str_length < length) {
|
1248
|
+
length = str_length;
|
1249
|
+
}
|
1250
|
+
|
1251
|
+
if (length > 0) {
|
1252
|
+
memcpy(data + offset, string_data, length);
|
1253
|
+
}
|
1254
|
+
|
1255
|
+
if (null_terminated) {
|
1256
|
+
data[offset + length] = '\0';
|
1257
|
+
}
|
1258
|
+
|
1259
|
+
return sd_value;
|
1260
|
+
}
|
1261
|
+
|
1262
|
+
/*
|
1263
|
+
call-seq:
|
1264
|
+
set_string(offset, value, null_terminated = false) -> value
|
1265
|
+
|
1266
|
+
Copies the string value into the block at the offset supplied.
|
1267
|
+
|
1268
|
+
If null_terminated is true, it will always write a null-terminating character
|
1269
|
+
if it fits. This means that you need at least string.bytesize + 1 bytes
|
1270
|
+
available from the offset onwards to fully story a string, otherwise the
|
1271
|
+
string's contents will be truncated to fit the null-terminating character.
|
1272
|
+
|
1273
|
+
If null_terminated is false, no null character is written and only the string
|
1274
|
+
bytes are copied to the block. If the full string does not fit, it will be
|
1275
|
+
truncated.
|
1276
|
+
*/
|
1277
|
+
static VALUE sd_set_string(int argc, VALUE *argv, VALUE self)
|
1278
|
+
{
|
1279
|
+
VALUE sd_offset, sd_value, sd_null_terminated;
|
1280
|
+
|
1281
|
+
sd_check_null_block(self);
|
1282
|
+
rb_check_frozen(self);
|
1283
|
+
|
1284
|
+
rb_scan_args(argc, argv, "21", &sd_offset, &sd_value, &sd_null_terminated);
|
1285
|
+
|
1286
|
+
return sd_set_string_nullterm(self, sd_offset, sd_value, !!RTEST(sd_null_terminated));
|
1287
|
+
}
|
1288
|
+
|
1289
|
+
/*
|
1290
|
+
call-seq:
|
1291
|
+
new(address, size, alignment = SIZEOF_VOID_POINTER) => Memory
|
1292
|
+
|
1293
|
+
Creates a new Memory object that wraps an existing pointer. Alignment is
|
1294
|
+
optional and defaults to the size of a pointer (Memory::SIZEOF_VOID_POINTER).
|
1295
|
+
|
1296
|
+
Size must be greater than zero. Zero-sized blocks are not permitted as they
|
1297
|
+
render most memory functionality useless and make it very difficult to ensure
|
1298
|
+
nothing bad is happening when you do bad things with snow-data. Because, let's
|
1299
|
+
be honest with ourselves for a moment, everyone using this gem? They're bad
|
1300
|
+
people. They're very bad people.
|
1301
|
+
|
1302
|
+
Note that Memory objects created with this method will not attempt to free
|
1303
|
+
the memory they wrap, as they did not allocate it and so do not own it. If
|
1304
|
+
an address held by a Memory object is invalid, the Memory object is also
|
1305
|
+
implicitly invalid as well, though there is no way for it to check this. You
|
1306
|
+
are responsible for freeing any memory not allocated through ::malloc and
|
1307
|
+
Memory subclasses.
|
1308
|
+
|
1309
|
+
It is an ArgumentError to provide a size of zero, nil, or false. It is also
|
1310
|
+
an ArgumentError to provide a NULL (zero) address.
|
1311
|
+
|
1312
|
+
If a subclass overrides ::new, it is also aliased as ::wrap and ::__wrap__.
|
1313
|
+
Subclasses may override ::wrap but must not override ::__wrap__.
|
1314
|
+
*/
|
1315
|
+
static VALUE sd_memory_new(int argc, VALUE *argv, VALUE self)
|
1316
|
+
{
|
1317
|
+
VALUE sd_size;
|
1318
|
+
VALUE sd_address;
|
1319
|
+
VALUE sd_alignment;
|
1320
|
+
VALUE memory = Qnil;
|
1321
|
+
void *address;
|
1322
|
+
size_t size;
|
1323
|
+
size_t alignment;
|
1324
|
+
|
1325
|
+
rb_scan_args(argc, argv, "21", &sd_address, &sd_size, &sd_alignment);
|
1326
|
+
|
1327
|
+
address = (void *)SD_NUM_TO_INTPTR_T(sd_address);
|
1328
|
+
size = 0;
|
1329
|
+
alignment = SIZEOF_VOIDP;
|
1330
|
+
|
1331
|
+
if (address == NULL) {
|
1332
|
+
rb_raise(rb_eArgError, "Address is NULL (%p).", address);
|
1333
|
+
}
|
1334
|
+
|
1335
|
+
if (RTEST(sd_size)) {
|
1336
|
+
size = NUM2SIZET(sd_size);
|
1337
|
+
} else {
|
1338
|
+
rb_raise(rb_eArgError, "Block size is false or nil");
|
1339
|
+
}
|
1340
|
+
|
1341
|
+
if (!size) {
|
1342
|
+
rb_raise(rb_eArgError, "Block size must be 1 or greater");
|
1343
|
+
}
|
1344
|
+
|
1345
|
+
if (RTEST(sd_alignment)) {
|
1346
|
+
alignment = NUM2SIZET(sd_alignment);
|
1347
|
+
}
|
1348
|
+
|
1349
|
+
memory = Data_Wrap_Struct(self, 0, 0, address);
|
1350
|
+
rb_ivar_set(memory, kSD_IVAR_BYTESIZE, SIZET2NUM(size));
|
1351
|
+
rb_ivar_set(memory, kSD_IVAR_ALIGNMENT, SIZET2NUM(alignment));
|
1352
|
+
rb_obj_call_init(memory, 0, 0);
|
1353
|
+
rb_obj_taint(memory);
|
1354
|
+
|
1355
|
+
return memory;
|
1356
|
+
}
|
1357
|
+
|
1358
|
+
/*
|
1359
|
+
call-seq:
|
1360
|
+
malloc(size, alignment = nil) => Memory
|
1361
|
+
|
1362
|
+
Allocates a new block with the given size and alignment and returns it. If
|
1363
|
+
no alignment is specified, it defaults to Snow::Memory::SIZEOF_VOID_POINTER.
|
1364
|
+
|
1365
|
+
Raises a RangeError if either size is zero or alignment is not a power of two.
|
1366
|
+
*/
|
1367
|
+
static VALUE sd_memory_malloc(int argc, VALUE *argv, VALUE self)
|
1368
|
+
{
|
1369
|
+
VALUE sd_size;
|
1370
|
+
VALUE sd_alignment;
|
1371
|
+
size_t alignment;
|
1372
|
+
size_t size;
|
1373
|
+
void *data;
|
1374
|
+
VALUE memory;
|
1375
|
+
|
1376
|
+
rb_scan_args(argc, argv, "11", &sd_size, &sd_alignment);
|
1377
|
+
|
1378
|
+
/* Get size and alignment */
|
1379
|
+
size = NUM2SIZET(sd_size);
|
1380
|
+
alignment = RTEST(sd_alignment) ? NUM2SIZET(sd_alignment) : sizeof(void *);
|
1381
|
+
if (!is_power_of_two(alignment)) {
|
1382
|
+
rb_raise(rb_eRangeError, "Alignment must be a power of two -- %zu is not a"
|
1383
|
+
" power of two", alignment);
|
1384
|
+
} else if (size < 1) {
|
1385
|
+
rb_raise(rb_eRangeError, "Size of block must be 1 or more -- zero-byte"
|
1386
|
+
" blocks are not permitted");
|
1387
|
+
}
|
1388
|
+
|
1389
|
+
/* Allocate block */
|
1390
|
+
data = com_malloc(size, alignment);
|
1391
|
+
memory = Data_Wrap_Struct(self, 0, com_free, data);
|
1392
|
+
|
1393
|
+
rb_ivar_set(memory, kSD_IVAR_BYTESIZE, SIZET2NUM(size));
|
1394
|
+
rb_ivar_set(memory, kSD_IVAR_ALIGNMENT, SIZET2NUM(alignment));
|
1395
|
+
rb_obj_call_init(memory, 0, 0);
|
1396
|
+
rb_obj_taint(memory);
|
1397
|
+
return memory;
|
1398
|
+
}
|
1399
|
+
|
1400
|
+
/*
|
1401
|
+
call-seq:
|
1402
|
+
realloc!(size, alignment = nil) => self
|
1403
|
+
|
1404
|
+
Reallocates the memory backing this pointer with a new size and optionally a
|
1405
|
+
new alignment. If the new size is the same as the old size, the method returns
|
1406
|
+
early and nothing is reallocated.
|
1407
|
+
|
1408
|
+
If a new alignment is specified, the memory will be reallocated regardless of
|
1409
|
+
whether the new and old sizes are the same. If no alignment is specified, the
|
1410
|
+
memory's previous alignment is used.
|
1411
|
+
|
1412
|
+
If the block for this memory was previously freed or the block is not owner by
|
1413
|
+
this object, a new block is allocated and the memory takes ownership of it.
|
1414
|
+
It is fine to realloc! on a previously freed block.
|
1415
|
+
|
1416
|
+
Raises a RangeError if either size is zero or alignment is not a power of two.
|
1417
|
+
*/
|
1418
|
+
static VALUE sd_memory_realloc(int argc, VALUE *argv, VALUE self)
|
1419
|
+
{
|
1420
|
+
struct RData *data;
|
1421
|
+
void *new_data;
|
1422
|
+
size_t size;
|
1423
|
+
size_t prev_size;
|
1424
|
+
size_t prev_align;
|
1425
|
+
size_t alignment;
|
1426
|
+
VALUE sd_size;
|
1427
|
+
VALUE sd_alignment;
|
1428
|
+
|
1429
|
+
/*
|
1430
|
+
Don't check for null/zero length here, as it is safe to reuse a memory via
|
1431
|
+
realloc!. It's less safe for structs and arrays, but you just have to do the
|
1432
|
+
sane thing in most cases. Granted, I'm a hypocrite for saying you need to
|
1433
|
+
do the sane thing after writing this gem.
|
1434
|
+
*/
|
1435
|
+
rb_check_frozen(self);
|
1436
|
+
|
1437
|
+
rb_scan_args(argc, argv, "11", &sd_size, &sd_alignment);
|
1438
|
+
|
1439
|
+
size = NUM2SIZET(sd_size);
|
1440
|
+
prev_align =
|
1441
|
+
alignment = NUM2SIZET(rb_ivar_get(self, kSD_IVAR_ALIGNMENT));
|
1442
|
+
prev_size = NUM2SIZET(rb_ivar_get(self, kSD_IVAR_BYTESIZE));
|
1443
|
+
|
1444
|
+
if (RTEST(sd_alignment)) {
|
1445
|
+
alignment = NUM2SIZET(sd_alignment);
|
1446
|
+
}
|
1447
|
+
|
1448
|
+
if (prev_size == size && alignment == prev_align) {
|
1449
|
+
return self;
|
1450
|
+
} else if (!is_power_of_two(alignment)) {
|
1451
|
+
rb_raise(rb_eRangeError, "Alignment must be a power of two -- %zu is not a"
|
1452
|
+
" power of two", alignment);
|
1453
|
+
} else if (size < 1) {
|
1454
|
+
rb_raise(rb_eRangeError, "Size of block must be 1 or more -- zero-byte"
|
1455
|
+
" blocks are not permitted");
|
1456
|
+
}
|
1457
|
+
|
1458
|
+
data = RDATA(self);
|
1459
|
+
new_data = com_malloc(size, alignment);
|
1460
|
+
|
1461
|
+
if (data->data && prev_size > 0) {
|
1462
|
+
const size_t copy_sizes[2] = { prev_size, size };
|
1463
|
+
memcpy(new_data, data->data, copy_sizes[prev_size > size]);
|
1464
|
+
}
|
1465
|
+
|
1466
|
+
if (data->dfree) {
|
1467
|
+
data->dfree(data->data);
|
1468
|
+
} else if (data->data) {
|
1469
|
+
rb_warning("realloc called on unowned pointer %p -- allocating new block"
|
1470
|
+
" and memcpying contents (size: %zd bytes), but original block will"
|
1471
|
+
" not be freed.", data->data, prev_size);
|
1472
|
+
}
|
1473
|
+
|
1474
|
+
data->data = new_data;
|
1475
|
+
data->dfree = com_free;
|
1476
|
+
|
1477
|
+
rb_ivar_set(self, kSD_IVAR_BYTESIZE, SIZET2NUM(size));
|
1478
|
+
rb_ivar_set(self, kSD_IVAR_ALIGNMENT, SIZET2NUM(alignment));
|
1479
|
+
return self;
|
1480
|
+
}
|
1481
|
+
|
1482
|
+
/*
|
1483
|
+
call-seq:
|
1484
|
+
free!() => self
|
1485
|
+
|
1486
|
+
Frees any memory owned by the object. This is a convenience function for when
|
1487
|
+
you want to free the memory ahead of the object being collected by the GC.
|
1488
|
+
*/
|
1489
|
+
static VALUE sd_memory_free(VALUE self)
|
1490
|
+
{
|
1491
|
+
struct RData *data = RDATA(self);
|
1492
|
+
|
1493
|
+
rb_check_frozen(self);
|
1494
|
+
|
1495
|
+
if (data->data && data->dfree) {
|
1496
|
+
data->dfree(data->data);
|
1497
|
+
data->dfree = 0;
|
1498
|
+
} else if (!data->data) {
|
1499
|
+
rb_raise(rb_eRuntimeError,
|
1500
|
+
"Double-free on %s",
|
1501
|
+
rb_obj_classname(self));
|
1502
|
+
}
|
1503
|
+
|
1504
|
+
data->data = 0;
|
1505
|
+
rb_ivar_set(self, kSD_IVAR_BYTESIZE, INT2FIX(0));
|
1506
|
+
|
1507
|
+
return self;
|
1508
|
+
}
|
1509
|
+
|
1510
|
+
/*
|
1511
|
+
call-seq:
|
1512
|
+
copy!(source, destination_offset = nil, source_offset = nil, byte_size = nil) => self
|
1513
|
+
|
1514
|
+
Copies byte_size bytes from an offset in the source data to an offset into
|
1515
|
+
the receiver (the destination).
|
1516
|
+
|
1517
|
+
If either offset is nil, they default to zero.
|
1518
|
+
|
1519
|
+
If the byte_size is nil, it defaults to the receiver's #bytesize.
|
1520
|
+
|
1521
|
+
If the source responds to #bytesize and the source's bytesize is smaller than
|
1522
|
+
the size given, the source's size is used instead of the specified or default
|
1523
|
+
size.
|
1524
|
+
|
1525
|
+
The source pointer does not have its bounds checked, as this isn't possible
|
1526
|
+
for all cases. Instead, you must ensure that your source offset and byte size
|
1527
|
+
are both within range of the source data.
|
1528
|
+
|
1529
|
+
For those curious, under the hood, this uses memmove, not memcpy. So, it is
|
1530
|
+
possible to copy overlapping regions of memory, but it isn't guaranteed to be
|
1531
|
+
as fast as a simple memcpy. Either way, if this is a concern for you, you
|
1532
|
+
probably shouldn't be using Ruby.
|
1533
|
+
|
1534
|
+
=== Exceptions
|
1535
|
+
|
1536
|
+
- If attempting to copy into a region that is outside the bounds of the
|
1537
|
+
receiver will raise a RangeError.
|
1538
|
+
- If either the receiver or the source address is NULL, it will raise an
|
1539
|
+
ArgumentError.
|
1540
|
+
- If the source object is neither a Data object (or a subclass thereof) or a
|
1541
|
+
Numerical address, it raises a TypeError.
|
1542
|
+
*/
|
1543
|
+
static VALUE sd_memory_copy(int argc, VALUE *argv, VALUE self)
|
1544
|
+
{
|
1545
|
+
VALUE sd_source;
|
1546
|
+
VALUE sd_destination_offset;
|
1547
|
+
VALUE sd_source_offset;
|
1548
|
+
VALUE sd_byte_size;
|
1549
|
+
struct RData *self_data;
|
1550
|
+
const uint8_t *source_pointer;
|
1551
|
+
uint8_t *destination_pointer;
|
1552
|
+
size_t source_offset;
|
1553
|
+
size_t destination_offset;
|
1554
|
+
size_t byte_size;
|
1555
|
+
size_t self_byte_size;
|
1556
|
+
int source_is_data = 0;
|
1557
|
+
|
1558
|
+
sd_check_null_block(self);
|
1559
|
+
rb_check_frozen(self);
|
1560
|
+
|
1561
|
+
rb_scan_args(argc, argv, "13",
|
1562
|
+
&sd_source,
|
1563
|
+
&sd_destination_offset,
|
1564
|
+
&sd_source_offset,
|
1565
|
+
&sd_byte_size);
|
1566
|
+
|
1567
|
+
/*
|
1568
|
+
By default, try to get an address from the object, if possible. Then use
|
1569
|
+
that address and don't extract it from the Data object or what have you.
|
1570
|
+
*/
|
1571
|
+
if (rb_obj_respond_to(sd_source, kSD_ID_ADDRESS, 0)) {
|
1572
|
+
VALUE source_address = rb_funcall2(sd_source, kSD_ID_ADDRESS, 0, 0);
|
1573
|
+
if (RTEST(rb_obj_is_kind_of(source_address, rb_cNumeric))) {
|
1574
|
+
source_pointer = (uint8_t *)SD_NUM_TO_INTPTR_T(source_address);
|
1575
|
+
goto sd_memory_copy_skip_data_check;
|
1576
|
+
}
|
1577
|
+
}
|
1578
|
+
|
1579
|
+
if (RTEST(rb_obj_is_kind_of(sd_source, rb_cData))) {
|
1580
|
+
/* Otherwise extract a pointer from the object if it's a Data object */
|
1581
|
+
const struct RData *source_data = RDATA(sd_source);
|
1582
|
+
source_pointer = ((const uint8_t *)source_data->data);
|
1583
|
+
source_is_data = 1;
|
1584
|
+
} else if (RTEST(rb_obj_is_kind_of(sd_source, rb_cNumeric))) {
|
1585
|
+
/* Otherwise, if it's a Numeric, try to convert what is assumed to be an
|
1586
|
+
address to a pointer */
|
1587
|
+
source_pointer = (uint8_t *)SD_NUM_TO_INTPTR_T(sd_source);
|
1588
|
+
} else {
|
1589
|
+
rb_raise(rb_eTypeError,
|
1590
|
+
"Source object must be type of numeric (address) or Data- got %s",
|
1591
|
+
rb_obj_classname(sd_source));
|
1592
|
+
}
|
1593
|
+
|
1594
|
+
sd_memory_copy_skip_data_check: /* skip from address check */
|
1595
|
+
self_data = RDATA(self);
|
1596
|
+
|
1597
|
+
/*
|
1598
|
+
Check if the source pointer is NULL -- error if it is (the destination
|
1599
|
+
pointer is checked by sd_check_null_block above).
|
1600
|
+
*/
|
1601
|
+
if (source_pointer == NULL) {
|
1602
|
+
rb_raise(rb_eArgError, "Source pointer is NULL");
|
1603
|
+
}
|
1604
|
+
|
1605
|
+
/* Grab data from ruby values and offset the source pointer. */
|
1606
|
+
source_offset = RTEST(sd_source_offset) ? NUM2SIZET(sd_source_offset) : 0;
|
1607
|
+
destination_offset = RTEST(sd_destination_offset) ? NUM2SIZET(sd_destination_offset) : 0;
|
1608
|
+
destination_pointer = (uint8_t *)self_data->data + destination_offset;
|
1609
|
+
self_byte_size = NUM2SIZET(rb_ivar_get(self, kSD_IVAR_BYTESIZE));
|
1610
|
+
source_pointer += source_offset;
|
1611
|
+
|
1612
|
+
if (self_byte_size == 0) {
|
1613
|
+
/*
|
1614
|
+
If self is a zero-length block, do not try to copy. It's just not sane to
|
1615
|
+
attempt it here since we can't do any bounds checking, even if the bounds
|
1616
|
+
might be arbitrarily specified (in which case I'd just be shooting myself
|
1617
|
+
in the foot if I did that and trying to circumvent the anti-foot-shot
|
1618
|
+
protections).
|
1619
|
+
*/
|
1620
|
+
rb_raise(rb_eRuntimeError, "self.bytesize == 0 -- cannot safely copy to this block");
|
1621
|
+
} else if (!RTEST(sd_byte_size)) {
|
1622
|
+
/*
|
1623
|
+
If not copy size is specified, use self_byte_size and just try to cram as
|
1624
|
+
much in there as is feasible. Truncate self_byte_size as needed for the
|
1625
|
+
offset.
|
1626
|
+
*/
|
1627
|
+
byte_size = self_byte_size - destination_offset;
|
1628
|
+
#ifdef SD_WARN_ON_IMPLICIT_COPY_SIZE
|
1629
|
+
if (!source_is_data) {
|
1630
|
+
rb_warning(
|
1631
|
+
"Copying %zu bytes from non-Data memory address %p without explicit size",
|
1632
|
+
byte_size,
|
1633
|
+
source_pointer);
|
1634
|
+
}
|
1635
|
+
#endif
|
1636
|
+
} else {
|
1637
|
+
/* User-specified size */
|
1638
|
+
byte_size = NUM2SIZET(sd_byte_size);
|
1639
|
+
}
|
1640
|
+
|
1641
|
+
/*
|
1642
|
+
If the source responds to bytesize, check if the copy is within bounds for
|
1643
|
+
the source. If it's out of bounds, raise a RangeError, otherwise optionally
|
1644
|
+
emit a warning that bounds checking doesn't work for this source.
|
1645
|
+
*/
|
1646
|
+
if (rb_obj_respond_to(sd_source, kSD_ID_BYTESIZE, 0)) {
|
1647
|
+
size_t source_size = NUM2SIZET(rb_funcall2(sd_source, kSD_ID_BYTESIZE, 0, 0));
|
1648
|
+
if (source_offset > source_size
|
1649
|
+
|| (source_offset + byte_size) > source_size
|
1650
|
+
|| (source_offset + byte_size) < source_offset) {
|
1651
|
+
rb_raise(rb_eRangeError, "Attempt to copy out of source bounds");
|
1652
|
+
}
|
1653
|
+
}
|
1654
|
+
#ifdef SD_WARN_ON_NO_BYTESIZE_METHOD
|
1655
|
+
else if (source_is_data) {
|
1656
|
+
rb_warning(
|
1657
|
+
"Copying from Data object pointer %p that does not respond to #bytesize"
|
1658
|
+
" -- this operation is not bounds-checked.",
|
1659
|
+
source_pointer);
|
1660
|
+
}
|
1661
|
+
#endif
|
1662
|
+
|
1663
|
+
if ((destination_offset + byte_size) > self_byte_size
|
1664
|
+
|| (destination_offset + byte_size) < destination_offset) {
|
1665
|
+
rb_raise(rb_eRangeError,
|
1666
|
+
"Offset %zu with byte size %zu is out of bounds of self",
|
1667
|
+
destination_offset,
|
1668
|
+
byte_size);
|
1669
|
+
}
|
1670
|
+
|
1671
|
+
#ifdef SD_VERBOSE_COPY_LOG
|
1672
|
+
/*
|
1673
|
+
Emit some debugging info just in case things go completely haywire and you
|
1674
|
+
really need to know what's going on.
|
1675
|
+
*/
|
1676
|
+
fprintf(stderr,
|
1677
|
+
"# copy! ----------------------------------------\n"
|
1678
|
+
"# destination_pointer = %p" "\n"
|
1679
|
+
"# source_pointer = %p" "\n"
|
1680
|
+
"# destination_offset = %zu" "\n"
|
1681
|
+
"# source_offset = %zu" "\n"
|
1682
|
+
"# byte_size = %zu" "\n"
|
1683
|
+
"# self_byte_size = %zu" "\n"
|
1684
|
+
"# source.class = %s" "\n"
|
1685
|
+
"# self.class = %s" "\n"
|
1686
|
+
"# --------------------------------------- /copy!\n",
|
1687
|
+
destination_pointer - destination_offset,
|
1688
|
+
source_pointer - source_offset,
|
1689
|
+
destination_offset,
|
1690
|
+
source_offset,
|
1691
|
+
byte_size,
|
1692
|
+
self_byte_size,
|
1693
|
+
rb_obj_classname(sd_source),
|
1694
|
+
rb_obj_classname(self));
|
1695
|
+
#endif
|
1696
|
+
|
1697
|
+
/* And skip a copy if we can */
|
1698
|
+
if (byte_size == 0 || source_pointer == destination_pointer) {
|
1699
|
+
return self;
|
1700
|
+
}
|
1701
|
+
|
1702
|
+
memmove(destination_pointer, source_pointer, byte_size);
|
1703
|
+
|
1704
|
+
return self;
|
1705
|
+
}
|
1706
|
+
|
1707
|
+
/*
|
1708
|
+
call-seq:
|
1709
|
+
to_s(null_terminated = true) => String
|
1710
|
+
|
1711
|
+
Gets a string representation of the contents of this block. If null_terminated
|
1712
|
+
is true (or nil), the returned string will end before the first null
|
1713
|
+
character.
|
1714
|
+
*/
|
1715
|
+
static VALUE sd_memory_to_s(int argc, VALUE *argv, VALUE self)
|
1716
|
+
{
|
1717
|
+
VALUE null_terminated;
|
1718
|
+
size_t byte_size = NUM2SIZET(rb_ivar_get(self, kSD_IVAR_BYTESIZE));
|
1719
|
+
const char *data = DATA_PTR(self);
|
1720
|
+
|
1721
|
+
sd_check_null_block(self);
|
1722
|
+
|
1723
|
+
rb_scan_args(argc, argv, "01", &null_terminated);
|
1724
|
+
|
1725
|
+
if (null_terminated == Qnil || RTEST(null_terminated)) {
|
1726
|
+
size_t string_length = 0;
|
1727
|
+
for (; string_length < byte_size && data[string_length]; ++string_length)
|
1728
|
+
;
|
1729
|
+
byte_size = string_length;
|
1730
|
+
}
|
1731
|
+
|
1732
|
+
return rb_str_new(data, byte_size);
|
1733
|
+
}
|
1734
|
+
|
1735
|
+
/*
|
1736
|
+
call-seq:
|
1737
|
+
address => Integer
|
1738
|
+
|
1739
|
+
Gets the address of this memory block as an Integer.
|
1740
|
+
*/
|
1741
|
+
static VALUE sd_memory_address(VALUE self)
|
1742
|
+
{
|
1743
|
+
return SD_UINTPTR_T_TO_NUM((uintptr_t)RDATA(self)->data);
|
1744
|
+
}
|
1745
|
+
|
1746
|
+
/*
|
1747
|
+
call-seq:
|
1748
|
+
align_size(size_or_offset, alignment = nil) => Integer
|
1749
|
+
|
1750
|
+
Aligns a given size or offset to a specific alignment. If no alignment is
|
1751
|
+
provided, it defaults to the size of a pointer on the architecture the
|
1752
|
+
extension was compiled for.
|
1753
|
+
|
1754
|
+
See Snow::Memory::SIZEOF_VOID_POINTER for the size of a pointer.
|
1755
|
+
|
1756
|
+
Raises a RangeError if the alignment is not a power of two. In this case, 1
|
1757
|
+
is considered a valid power of two.
|
1758
|
+
*/
|
1759
|
+
static VALUE sd_align_size(int argc, VALUE *argv, VALUE self)
|
1760
|
+
{
|
1761
|
+
VALUE sd_alignment;
|
1762
|
+
VALUE sd_size;
|
1763
|
+
size_t alignment = sizeof(void *);
|
1764
|
+
rb_scan_args(argc, argv, "11", &sd_size, &sd_alignment);
|
1765
|
+
if (RTEST(sd_alignment)) {
|
1766
|
+
alignment = NUM2SIZET(sd_alignment);
|
1767
|
+
if (!is_power_of_two(alignment)) {
|
1768
|
+
rb_raise(rb_eRangeError, "Alignment must be a power of two -- %zu is not"
|
1769
|
+
" a power of two", alignment);
|
1770
|
+
}
|
1771
|
+
}
|
1772
|
+
return SIZET2NUM(align_size(NUM2SIZET(sd_size), alignment));
|
1773
|
+
}
|
1774
|
+
|
1775
|
+
void Init_snowdata_bindings(void)
|
1776
|
+
{
|
1777
|
+
VALUE sd_snow_module = rb_define_module("Snow");
|
1778
|
+
VALUE sd_memory_klass = rb_define_class_under(sd_snow_module, "Memory", rb_cData);
|
1779
|
+
|
1780
|
+
kSD_IVAR_BYTESIZE = rb_intern("@__bytesize__");
|
1781
|
+
kSD_IVAR_ALIGNMENT = rb_intern("@__alignment__");
|
1782
|
+
kSD_ID_BYTESIZE = rb_intern("bytesize");
|
1783
|
+
kSD_ID_ADDRESS = rb_intern("address");
|
1784
|
+
|
1785
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_INT"), SIZET2NUM(SIZEOF_INT));
|
1786
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_SHORT"), SIZET2NUM(SIZEOF_SHORT));
|
1787
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_LONG"), SIZET2NUM(SIZEOF_LONG));
|
1788
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_LONG_LONG"), SIZET2NUM(SIZEOF_LONG_LONG));
|
1789
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_OFF_T"), SIZET2NUM(SIZEOF_OFF_T));
|
1790
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_VOIDP"), SIZET2NUM(SIZEOF_VOIDP));
|
1791
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_FLOAT"), SIZET2NUM(SIZEOF_FLOAT));
|
1792
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_DOUBLE"), SIZET2NUM(SIZEOF_DOUBLE));
|
1793
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_SIZE_T"), SIZET2NUM(SIZEOF_SIZE_T));
|
1794
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_PTRDIFF_T"), SIZET2NUM(SIZEOF_PTRDIFF_T));
|
1795
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_INT8_T"), SIZET2NUM(SIZEOF_INT8_T));
|
1796
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_UINT8_T"), SIZET2NUM(SIZEOF_UINT8_T));
|
1797
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_INT16_T"), SIZET2NUM(SIZEOF_INT16_T));
|
1798
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_UINT16_T"), SIZET2NUM(SIZEOF_UINT16_T));
|
1799
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_INT32_T"), SIZET2NUM(SIZEOF_INT32_T));
|
1800
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_UINT32_T"), SIZET2NUM(SIZEOF_UINT32_T));
|
1801
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_INT64_T"), SIZET2NUM(SIZEOF_INT64_T));
|
1802
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_UINT64_T"), SIZET2NUM(SIZEOF_UINT64_T));
|
1803
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_INTPTR_T"), SIZET2NUM(SIZEOF_INTPTR_T));
|
1804
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_UINTPTR_T"), SIZET2NUM(SIZEOF_UINTPTR_T));
|
1805
|
+
rb_const_set(sd_memory_klass, rb_intern("SIZEOF_VOID_POINTER"), SIZET2NUM(sizeof(void *)));
|
1806
|
+
|
1807
|
+
rb_define_singleton_method(sd_memory_klass, "new", sd_memory_new, -1);
|
1808
|
+
rb_define_singleton_method(sd_memory_klass, "malloc", sd_memory_malloc, -1);
|
1809
|
+
rb_define_singleton_method(sd_memory_klass, "align_size", sd_align_size, -1);
|
1810
|
+
rb_define_method(sd_memory_klass, "realloc!", sd_memory_realloc, -1);
|
1811
|
+
rb_define_method(sd_memory_klass, "copy!", sd_memory_copy, -1);
|
1812
|
+
rb_define_method(sd_memory_klass, "to_s", sd_memory_to_s, -1);
|
1813
|
+
rb_define_method(sd_memory_klass, "free!", sd_memory_free, 0);
|
1814
|
+
rb_define_method(sd_memory_klass, "address", sd_memory_address, 0);
|
1815
|
+
rb_define_method(sd_memory_klass, "get_int8_t", sd_get_int8, 1);
|
1816
|
+
rb_define_method(sd_memory_klass, "set_int8_t", sd_set_int8, 2);
|
1817
|
+
rb_define_method(sd_memory_klass, "get_int16_t", sd_get_int16, 1);
|
1818
|
+
rb_define_method(sd_memory_klass, "set_int16_t", sd_set_int16, 2);
|
1819
|
+
rb_define_method(sd_memory_klass, "get_int32_t", sd_get_int32, 1);
|
1820
|
+
rb_define_method(sd_memory_klass, "set_int32_t", sd_set_int32, 2);
|
1821
|
+
rb_define_method(sd_memory_klass, "get_int64_t", sd_get_int64, 1);
|
1822
|
+
rb_define_method(sd_memory_klass, "set_int64_t", sd_set_int64, 2);
|
1823
|
+
rb_define_method(sd_memory_klass, "get_uint8_t", sd_get_uint8, 1);
|
1824
|
+
rb_define_method(sd_memory_klass, "set_uint8_t", sd_set_uint8, 2);
|
1825
|
+
rb_define_method(sd_memory_klass, "get_uint16_t", sd_get_uint16, 1);
|
1826
|
+
rb_define_method(sd_memory_klass, "set_uint16_t", sd_set_uint16, 2);
|
1827
|
+
rb_define_method(sd_memory_klass, "get_uint32_t", sd_get_uint32, 1);
|
1828
|
+
rb_define_method(sd_memory_klass, "set_uint32_t", sd_set_uint32, 2);
|
1829
|
+
rb_define_method(sd_memory_klass, "get_uint64_t", sd_get_uint64, 1);
|
1830
|
+
rb_define_method(sd_memory_klass, "set_uint64_t", sd_set_uint64, 2);
|
1831
|
+
rb_define_method(sd_memory_klass, "get_size_t", sd_get_size_t, 1);
|
1832
|
+
rb_define_method(sd_memory_klass, "set_size_t", sd_set_size_t, 2);
|
1833
|
+
rb_define_method(sd_memory_klass, "get_ptrdiff_t", sd_get_ptrdiff_t, 1);
|
1834
|
+
rb_define_method(sd_memory_klass, "set_ptrdiff_t", sd_set_ptrdiff_t, 2);
|
1835
|
+
rb_define_method(sd_memory_klass, "get_intptr_t", sd_get_intptr_t, 1);
|
1836
|
+
rb_define_method(sd_memory_klass, "set_intptr_t", sd_set_intptr_t, 2);
|
1837
|
+
rb_define_method(sd_memory_klass, "get_uintptr_t", sd_get_uintptr_t, 1);
|
1838
|
+
rb_define_method(sd_memory_klass, "set_uintptr_t", sd_set_uintptr_t, 2);
|
1839
|
+
rb_define_method(sd_memory_klass, "get_long", sd_get_long, 1);
|
1840
|
+
rb_define_method(sd_memory_klass, "set_long", sd_set_long, 2);
|
1841
|
+
rb_define_method(sd_memory_klass, "get_long_long", sd_get_long_long, 1);
|
1842
|
+
rb_define_method(sd_memory_klass, "set_long_long", sd_set_long_long, 2);
|
1843
|
+
rb_define_method(sd_memory_klass, "get_unsigned_long", sd_get_unsigned_long, 1);
|
1844
|
+
rb_define_method(sd_memory_klass, "set_unsigned_long", sd_set_unsigned_long, 2);
|
1845
|
+
rb_define_method(sd_memory_klass, "get_unsigned_long_long", sd_get_unsigned_long_long, 1);
|
1846
|
+
rb_define_method(sd_memory_klass, "set_unsigned_long_long", sd_set_unsigned_long_long, 2);
|
1847
|
+
rb_define_method(sd_memory_klass, "get_float", sd_get_float, 1);
|
1848
|
+
rb_define_method(sd_memory_klass, "set_float", sd_set_float, 2);
|
1849
|
+
rb_define_method(sd_memory_klass, "get_double", sd_get_double, 1);
|
1850
|
+
rb_define_method(sd_memory_klass, "set_double", sd_set_double, 2);
|
1851
|
+
rb_define_method(sd_memory_klass, "get_int", sd_get_int, 1);
|
1852
|
+
rb_define_method(sd_memory_klass, "set_int", sd_set_int, 2);
|
1853
|
+
rb_define_method(sd_memory_klass, "get_unsigned_int", sd_get_unsigned_int, 1);
|
1854
|
+
rb_define_method(sd_memory_klass, "set_unsigned_int", sd_set_unsigned_int, 2);
|
1855
|
+
rb_define_method(sd_memory_klass, "get_short", sd_get_short, 1);
|
1856
|
+
rb_define_method(sd_memory_klass, "set_short", sd_set_short, 2);
|
1857
|
+
rb_define_method(sd_memory_klass, "get_unsigned_short", sd_get_unsigned_short, 1);
|
1858
|
+
rb_define_method(sd_memory_klass, "set_unsigned_short", sd_set_unsigned_short, 2);
|
1859
|
+
rb_define_method(sd_memory_klass, "get_char", sd_get_char, 1);
|
1860
|
+
rb_define_method(sd_memory_klass, "set_char", sd_set_char, 2);
|
1861
|
+
rb_define_method(sd_memory_klass, "get_unsigned_char", sd_get_unsigned_char, 1);
|
1862
|
+
rb_define_method(sd_memory_klass, "set_unsigned_char", sd_set_unsigned_char, 2);
|
1863
|
+
rb_define_method(sd_memory_klass, "get_signed_char", sd_get_signed_char, 1);
|
1864
|
+
rb_define_method(sd_memory_klass, "set_signed_char", sd_set_signed_char, 2);
|
1865
|
+
rb_define_method(sd_memory_klass, "get_string", sd_get_string, -1);
|
1866
|
+
rb_define_method(sd_memory_klass, "set_string", sd_set_string, -1);
|
1867
|
+
}
|