type_array 0.1
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.
- data/.gitignore +19 -0
- data/.travis.yml +18 -0
- data/CHANGELOG.rdoc +4 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +18 -0
- data/README.rdoc +140 -0
- data/Rakefile +47 -0
- data/ext/type_array/array_buffer.c +183 -0
- data/ext/type_array/array_buffer.h +19 -0
- data/ext/type_array/data_view.c +574 -0
- data/ext/type_array/data_view.h +35 -0
- data/ext/type_array/extconf.rb +14 -0
- data/ext/type_array/jruby.h +9 -0
- data/ext/type_array/prelude.h +25 -0
- data/ext/type_array/rubinius.h +19 -0
- data/ext/type_array/ruby18.h +15 -0
- data/ext/type_array/ruby19.h +12 -0
- data/ext/type_array/type_array.c +540 -0
- data/ext/type_array/type_array.h +38 -0
- data/ext/type_array/type_array_ext.c +25 -0
- data/ext/type_array/type_array_ext.h +71 -0
- data/lib/type_array/io.rb +28 -0
- data/lib/type_array/version.rb +3 -0
- data/lib/type_array.rb +14 -0
- data/test/helper.rb +23 -0
- data/test/test_array_buffer.rb +132 -0
- data/test/test_data_view.rb +218 -0
- data/test/test_float_32_array.rb +36 -0
- data/test/test_float_64_array.rb +38 -0
- data/test/test_int_16_array.rb +37 -0
- data/test/test_int_32_array.rb +43 -0
- data/test/test_int_8_array.rb +29 -0
- data/test/test_type_array.rb +155 -0
- data/test/test_uint_16_array.rb +35 -0
- data/test/test_uint_32_array.rb +35 -0
- data/test/test_uint_8_array.rb +33 -0
- data/type_array.gemspec +22 -0
- metadata +112 -0
@@ -0,0 +1,540 @@
|
|
1
|
+
#include "type_array_ext.h"
|
2
|
+
|
3
|
+
/*
|
4
|
+
* :nodoc:
|
5
|
+
* Provides a typed interface to a given ArrayBuffer instance. Values will only be coerced according to the type of
|
6
|
+
* array. Currently coercing to and from Ruby objects are handled through callbacks via function pointers. This may
|
7
|
+
* change in the short term.
|
8
|
+
*
|
9
|
+
*/
|
10
|
+
|
11
|
+
VALUE rb_cTypeArray;
|
12
|
+
|
13
|
+
VALUE rb_cInt8Array;
|
14
|
+
VALUE rb_cUInt8Array;
|
15
|
+
VALUE rb_cInt16Array;
|
16
|
+
VALUE rb_cUInt16Array;
|
17
|
+
VALUE rb_cInt32Array;
|
18
|
+
VALUE rb_cUInt32Array;
|
19
|
+
VALUE rb_cFloat32Array;
|
20
|
+
VALUE rb_cFloat64Array;
|
21
|
+
|
22
|
+
static ID rb_type_array_intern_aget;
|
23
|
+
static ID rb_type_array_intern_aset;
|
24
|
+
|
25
|
+
/*
|
26
|
+
* :nodoc:
|
27
|
+
* Coerces a Ruby object to an int8 at a given offset, according to host endianness.
|
28
|
+
*
|
29
|
+
*/
|
30
|
+
DefineTypeArraySetter(int8, (signed char)NUM2CHR(item));
|
31
|
+
|
32
|
+
/*
|
33
|
+
* :nodoc:
|
34
|
+
* Coerces an int8 at a given offset to a Ruby object, according to host endianness.
|
35
|
+
*
|
36
|
+
*/
|
37
|
+
DefineTypeArrayGetter(int8, signed char, TACHR2FIX(val));
|
38
|
+
|
39
|
+
/*
|
40
|
+
* :nodoc:
|
41
|
+
* Coerces a Ruby object to an unsigned int8 at a given offset, according to host endianness.
|
42
|
+
*
|
43
|
+
*/
|
44
|
+
DefineTypeArraySetter(uint8, (unsigned char)NUM2CHR(item));
|
45
|
+
|
46
|
+
/*
|
47
|
+
* :nodoc:
|
48
|
+
* Coerces an unsigned int8 at a given offset to a Ruby object, according to host endianness.
|
49
|
+
*
|
50
|
+
*/
|
51
|
+
DefineTypeArrayGetter(uint8, unsigned char, TACHR2FIX(val));
|
52
|
+
|
53
|
+
/*
|
54
|
+
* :nodoc:
|
55
|
+
* Coerces a Ruby object to an int16 at a given offset, according to host endianness.
|
56
|
+
*
|
57
|
+
*/
|
58
|
+
DefineTypeArraySetter(int16, (short)NUM2INT(item));
|
59
|
+
|
60
|
+
/*
|
61
|
+
* :nodoc:
|
62
|
+
* Coerces an int16 at a given offset to a Ruby object, according to host endianness.
|
63
|
+
*
|
64
|
+
*/
|
65
|
+
DefineTypeArrayGetter(int16, short, INT2FIX(val));
|
66
|
+
|
67
|
+
/*
|
68
|
+
* :nodoc:
|
69
|
+
* Coerces a Ruby object to an unsigned int16 at a given offset, according to host endianness.
|
70
|
+
*
|
71
|
+
*/
|
72
|
+
DefineTypeArraySetter(uint16, (unsigned short)NUM2INT(item));
|
73
|
+
|
74
|
+
/*
|
75
|
+
* :nodoc:
|
76
|
+
* Coerces an unsigned int16 at a given offset to a Ruby object, according to host endianness.
|
77
|
+
*
|
78
|
+
*/
|
79
|
+
DefineTypeArrayGetter(uint16, unsigned short, INT2FIX(val));
|
80
|
+
|
81
|
+
/*
|
82
|
+
* :nodoc:
|
83
|
+
* Coerces a Ruby object to an int32 at a given offset, according to host endianness.
|
84
|
+
*
|
85
|
+
*/
|
86
|
+
DefineTypeArraySetter(int32, NUM2INT(item));
|
87
|
+
|
88
|
+
/*
|
89
|
+
* :nodoc:
|
90
|
+
* Coerces an int32 at a given offset to a Ruby object, according to host endianness.
|
91
|
+
*
|
92
|
+
*/
|
93
|
+
DefineTypeArrayGetter(int32, int, INT2FIX(val));
|
94
|
+
|
95
|
+
/*
|
96
|
+
* :nodoc:
|
97
|
+
* Coerces a Ruby object to an unsigned int32 at a given offset, according to host endianness.
|
98
|
+
*
|
99
|
+
*/
|
100
|
+
DefineTypeArraySetter(uint32, NUM2UINT(item));
|
101
|
+
|
102
|
+
/*
|
103
|
+
* :nodoc:
|
104
|
+
* Coerces an unsigned int32 at a given offset to a Ruby object, according to host endianness.
|
105
|
+
*
|
106
|
+
*/
|
107
|
+
DefineTypeArrayGetter(uint32, unsigned int, UINT2NUM(val));
|
108
|
+
|
109
|
+
/*
|
110
|
+
* :nodoc:
|
111
|
+
* Coerces a Ruby object to a float32 (float) at a given offset, according to host endianness.
|
112
|
+
*
|
113
|
+
*/
|
114
|
+
static void rb_type_array_aset_float32(rb_array_buffer_t *buf, long index, VALUE item)
|
115
|
+
{
|
116
|
+
float val;
|
117
|
+
switch (TYPE(item)) {
|
118
|
+
case T_FIXNUM:
|
119
|
+
val = (float)FIX2LONG(item);
|
120
|
+
break;
|
121
|
+
case T_BIGNUM:
|
122
|
+
val = (float)rb_big2dbl(item);
|
123
|
+
break;
|
124
|
+
case T_FLOAT:
|
125
|
+
val = (float)RFLOAT_VALUE(item);
|
126
|
+
break;
|
127
|
+
default:
|
128
|
+
rb_raise(rb_eTypeError, "Type arrays only support Fixnum, Bignum and Float instances");
|
129
|
+
}
|
130
|
+
rb_type_array_set_float32(buf, index, val, TYPE_ARRAY_IS_LITTLE_ENDIAN);
|
131
|
+
}
|
132
|
+
|
133
|
+
/*
|
134
|
+
* :nodoc:
|
135
|
+
* Coerces a float32 (float) at a given offset to a Ruby object, according to host endianness.
|
136
|
+
*
|
137
|
+
*/
|
138
|
+
DefineTypeArrayGetter(float32, float, rb_float_new((double)val));
|
139
|
+
|
140
|
+
/*
|
141
|
+
* :nodoc:
|
142
|
+
* Coerces a Ruby object to a float64 (double) at a given offset, according to host endianness.
|
143
|
+
*
|
144
|
+
*/
|
145
|
+
static void rb_type_array_aset_float64(rb_array_buffer_t *buf, long index, VALUE item)
|
146
|
+
{
|
147
|
+
double val;
|
148
|
+
switch (TYPE(item)) {
|
149
|
+
case T_FIXNUM:
|
150
|
+
val = FIX2LONG(item);
|
151
|
+
break;
|
152
|
+
case T_BIGNUM:
|
153
|
+
val = rb_big2dbl(item);
|
154
|
+
break;
|
155
|
+
case T_FLOAT:
|
156
|
+
val = RFLOAT_VALUE(item);
|
157
|
+
break;
|
158
|
+
default:
|
159
|
+
rb_raise(rb_eTypeError, "Type arrays only support Fixnum, Bignum and Float instances");
|
160
|
+
}
|
161
|
+
rb_type_array_set_float64(buf, index, val, TYPE_ARRAY_IS_LITTLE_ENDIAN);
|
162
|
+
}
|
163
|
+
|
164
|
+
/*
|
165
|
+
* :nodoc:
|
166
|
+
* Coerces a float64 (double) at a given offset to a Ruby object, according to host endianness.
|
167
|
+
*
|
168
|
+
*/
|
169
|
+
DefineTypeArrayGetter(float64, double, rb_float_new(val));
|
170
|
+
|
171
|
+
/*
|
172
|
+
* :nodoc:
|
173
|
+
* Asserts type alignment.
|
174
|
+
*
|
175
|
+
*/
|
176
|
+
inline int rb_type_array_assert_alignment(unsigned long val, unsigned long bytes) {
|
177
|
+
return (val & (bytes - 1)) == 0 ? 1 : 0;
|
178
|
+
}
|
179
|
+
|
180
|
+
/*
|
181
|
+
* :nodoc:
|
182
|
+
* Swizzles byte order.
|
183
|
+
*
|
184
|
+
*/
|
185
|
+
inline void rb_type_array_swizzle(char* buf, unsigned long len) {
|
186
|
+
unsigned long i;
|
187
|
+
for (i = 0; i < len / 2; ++i) {
|
188
|
+
char t = buf[i];
|
189
|
+
buf[i] = buf[len - i - 1];
|
190
|
+
buf[len - i - 1] = t;
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
/*
|
195
|
+
* :nodoc:
|
196
|
+
* Validates offset boundaries.
|
197
|
+
*
|
198
|
+
*/
|
199
|
+
static inline long rb_type_array_assert_offset(rb_type_array_t *ary, VALUE idx)
|
200
|
+
{
|
201
|
+
long index;
|
202
|
+
Check_Type(idx, T_FIXNUM);
|
203
|
+
index = FIX2LONG(idx) * ary->size;
|
204
|
+
if (index < 0) rb_raise(rb_eRangeError, "Offset may not be negative.");
|
205
|
+
if (!rb_type_array_assert_alignment(index, ary->size)) rb_raise(rb_eRangeError, "Byte offset is not aligned.");
|
206
|
+
if ((unsigned long)index > ary->byte_length) rb_raise(rb_eRangeError, "Offset out of range.");
|
207
|
+
if (ary->size > (ary->byte_length - (unsigned long)index)) rb_raise(rb_eRangeError, "Offset/length out of range.");
|
208
|
+
return index;
|
209
|
+
}
|
210
|
+
|
211
|
+
/*
|
212
|
+
* :nodoc:
|
213
|
+
* GC mark callback
|
214
|
+
*
|
215
|
+
*/
|
216
|
+
static void rb_mark_type_array(void *ptr)
|
217
|
+
{
|
218
|
+
rb_type_array_t *ary = (rb_type_array_t *)ptr;
|
219
|
+
if (ary) rb_gc_mark(ary->buf);
|
220
|
+
}
|
221
|
+
|
222
|
+
/*
|
223
|
+
* :nodoc:
|
224
|
+
* GC free callback
|
225
|
+
*
|
226
|
+
*/
|
227
|
+
static void rb_free_type_array(void *ptr)
|
228
|
+
{
|
229
|
+
rb_type_array_t *ary = (rb_type_array_t *)ptr;
|
230
|
+
#ifdef TYPE_ARRAY_DEBUG
|
231
|
+
printf(">> rb_free_type_array %p\n", ptr);
|
232
|
+
#endif
|
233
|
+
if (ary) {
|
234
|
+
xfree(ary);
|
235
|
+
ary = NULL;
|
236
|
+
}
|
237
|
+
#ifdef TYPE_ARRAY_DEBUG
|
238
|
+
printf("<< rb_free_type_array %p\n", ptr);
|
239
|
+
#endif
|
240
|
+
}
|
241
|
+
|
242
|
+
/*
|
243
|
+
* call-seq:
|
244
|
+
* Int32Array.new(100) => Int32Array
|
245
|
+
* Int32Array.new("01234567") => Int32Array
|
246
|
+
* Int32Array.new(buf, 20) => Int32Array
|
247
|
+
* Int32Array.new(buf, 0, 20) => Int32Array
|
248
|
+
* Int32Array.new(buf, 20, 20) => Int32Array
|
249
|
+
*
|
250
|
+
* Creates a new TypeArray instance. ArrayBuffer, data (String) and length constructors are supported.
|
251
|
+
*
|
252
|
+
* === Examples
|
253
|
+
* buf = ArrayBuffer.new(100) => ArrayBuffer
|
254
|
+
*
|
255
|
+
* ary = Int32Array.new(buf, 20) => Int32Array
|
256
|
+
* ary.length => 20
|
257
|
+
* ary.byte_length => 80
|
258
|
+
* ary.byte_offset => 20
|
259
|
+
*
|
260
|
+
* ary = Int32Array.new(buf, 0, 20) => Int32Array
|
261
|
+
* ary.length => 20
|
262
|
+
* ary.byte_length => 80
|
263
|
+
* ary.byte_offset => 0
|
264
|
+
*
|
265
|
+
* ary = Int32Array.new(buf, 20, 20) => Int32Array
|
266
|
+
* ary.length => 20
|
267
|
+
* ary.byte_length => 80
|
268
|
+
* ary.byte_offset => 20
|
269
|
+
*
|
270
|
+
* ary = Int32Array.new("01234567") => Int32Array
|
271
|
+
* ary.byte_length => 8
|
272
|
+
* ary.to_s => "01234567"
|
273
|
+
*
|
274
|
+
* ary = Int32Array.new(100) => Int32Array
|
275
|
+
* ary.length => 100
|
276
|
+
* ary.byte_length => 400
|
277
|
+
*/
|
278
|
+
static VALUE rb_type_array_s_new(int argc, VALUE *argv, VALUE klass)
|
279
|
+
{
|
280
|
+
VALUE type_array;
|
281
|
+
VALUE obj, byte_offset, length;
|
282
|
+
rb_type_array_t *array = NULL;
|
283
|
+
unsigned long buffer_length, offset;
|
284
|
+
if (klass == rb_cTypeArray) rb_raise(rb_eTypeError, "TypeArray cannot be instantiated directly.");
|
285
|
+
rb_scan_args(argc, argv, "12", &obj, &byte_offset, &length);
|
286
|
+
type_array = Data_Make_Struct(klass, rb_type_array_t, rb_mark_type_array, rb_free_type_array, array);
|
287
|
+
array->size = FIX2ULONG(rb_const_get(klass, rb_intern("BYTES_PER_ELEMENT")));
|
288
|
+
array->byte_offset = 0;
|
289
|
+
array->length = 0;
|
290
|
+
|
291
|
+
if (klass == rb_cInt8Array) {
|
292
|
+
array->aref_fn = rb_type_array_aref_int8;
|
293
|
+
array->aset_fn = rb_type_array_aset_int8;
|
294
|
+
} else if (klass == rb_cUInt8Array) {
|
295
|
+
array->aref_fn = rb_type_array_aref_uint8;
|
296
|
+
array->aset_fn = rb_type_array_aset_uint8;
|
297
|
+
} else if (klass == rb_cInt16Array) {
|
298
|
+
array->aref_fn = rb_type_array_aref_int16;
|
299
|
+
array->aset_fn = rb_type_array_aset_int16;
|
300
|
+
} else if (klass == rb_cUInt16Array) {
|
301
|
+
array->aref_fn = rb_type_array_aref_uint16;
|
302
|
+
array->aset_fn = rb_type_array_aset_uint16;
|
303
|
+
} else if (klass == rb_cInt32Array) {
|
304
|
+
array->aref_fn = rb_type_array_aref_int32;
|
305
|
+
array->aset_fn = rb_type_array_aset_int32;
|
306
|
+
} else if (klass == rb_cUInt32Array) {
|
307
|
+
array->aref_fn = rb_type_array_aref_uint32;
|
308
|
+
array->aset_fn = rb_type_array_aset_uint32;
|
309
|
+
} else if (klass == rb_cFloat32Array) {
|
310
|
+
array->aref_fn = rb_type_array_aref_float32;
|
311
|
+
array->aset_fn = rb_type_array_aset_float32;
|
312
|
+
} else if (klass == rb_cFloat64Array) {
|
313
|
+
array->aref_fn = rb_type_array_aref_float64;
|
314
|
+
array->aset_fn = rb_type_array_aset_float64;
|
315
|
+
}
|
316
|
+
|
317
|
+
if (FIXNUM_P(obj)) {
|
318
|
+
array->length = FIX2ULONG(obj);
|
319
|
+
array->byte_length = (array->length * array->size);
|
320
|
+
array->buf = rb_alloc_array_buffer(array->byte_length, NULL);
|
321
|
+
} else if (rb_type(obj) == T_STRING) {
|
322
|
+
array->byte_length = (unsigned long)RSTRING_LEN(obj);
|
323
|
+
array->length = (array->byte_length / array->size);
|
324
|
+
ArrayBufferEncode(obj);
|
325
|
+
array->buf = rb_alloc_array_buffer(array->byte_length, (void *)RSTRING_PTR(obj));
|
326
|
+
} else if (rb_class_of(obj) == rb_cArrayBuffer) {
|
327
|
+
GetArrayBuffer(obj);
|
328
|
+
if (!NIL_P(byte_offset)) {
|
329
|
+
Check_Type(byte_offset, T_FIXNUM);
|
330
|
+
array->byte_offset = FIX2ULONG(byte_offset);
|
331
|
+
if (!rb_type_array_assert_alignment(array->byte_offset, array->size))
|
332
|
+
rb_raise(rb_eRangeError, "Byte offset is not aligned.");
|
333
|
+
}
|
334
|
+
buffer_length = buf->length;
|
335
|
+
if (!NIL_P(length)) {
|
336
|
+
Check_Type(length, T_FIXNUM);
|
337
|
+
array->length = FIX2ULONG(length);
|
338
|
+
array->byte_length = array->length * array->size;
|
339
|
+
} else {
|
340
|
+
array->byte_length = buffer_length - array->byte_offset;
|
341
|
+
}
|
342
|
+
if ((array->byte_offset + array->byte_length) > buffer_length)
|
343
|
+
rb_raise(rb_eRangeError, "Byte offset / length is not aligned.");
|
344
|
+
if (array->length == 0) array->length = array->byte_length / array->size;
|
345
|
+
if (array->byte_offset > buffer_length || array->byte_offset + array->length > buffer_length ||
|
346
|
+
array->byte_offset + array->length * array->size > buffer_length) {
|
347
|
+
rb_raise(rb_eRangeError, "Length is out of range.");
|
348
|
+
}
|
349
|
+
array->buf = obj;
|
350
|
+
} else if (rb_obj_is_kind_of(obj, rb_cTypeArray) == Qtrue) {
|
351
|
+
GetTypeArray(obj);
|
352
|
+
array->length = ary->length;
|
353
|
+
array->byte_length = (array->size * array->length);
|
354
|
+
array->buf = rb_alloc_array_buffer(array->byte_length, NULL);
|
355
|
+
array->byte_offset = 0;
|
356
|
+
for (offset = 0; offset < array->length; ++offset) {
|
357
|
+
VALUE offs = INT2FIX(offset);
|
358
|
+
VALUE val = rb_funcall(obj, rb_type_array_intern_aget, 1, offs);
|
359
|
+
rb_funcall(type_array, rb_type_array_intern_aset, 2, offs, val);
|
360
|
+
}
|
361
|
+
} else {
|
362
|
+
rb_raise(rb_eTypeError, "TypeArray constructor %s not supported.", RSTRING_PTR(rb_obj_as_string(obj)));
|
363
|
+
}
|
364
|
+
rb_obj_call_init(type_array, 0, NULL);
|
365
|
+
return type_array;
|
366
|
+
}
|
367
|
+
|
368
|
+
/*
|
369
|
+
* call-seq:
|
370
|
+
* ary.byte_length => Fixnum
|
371
|
+
*
|
372
|
+
* Returns the size of the underlying buffer managed by this TypeArray instance.
|
373
|
+
*
|
374
|
+
* === Examples
|
375
|
+
* ary = Int32Array.new("01234567") => Int32Array
|
376
|
+
* ary.byte_length => 8
|
377
|
+
*
|
378
|
+
*/
|
379
|
+
static VALUE rb_type_array_byte_length(VALUE obj)
|
380
|
+
{
|
381
|
+
GetTypeArray(obj);
|
382
|
+
return ULONG2NUM(ary->byte_length);
|
383
|
+
}
|
384
|
+
|
385
|
+
/*
|
386
|
+
* call-seq:
|
387
|
+
* ary.length => Fixnum
|
388
|
+
*
|
389
|
+
* Returns the max number of elements this typed array instance can accommodate.
|
390
|
+
*
|
391
|
+
* === Examples
|
392
|
+
* ary = Int32Array.new("01234567") => Int32Array
|
393
|
+
* ary.byte_length => 8
|
394
|
+
* ary.length => 2
|
395
|
+
*
|
396
|
+
*/
|
397
|
+
static VALUE rb_type_array_length(VALUE obj)
|
398
|
+
{
|
399
|
+
GetTypeArray(obj);
|
400
|
+
return ULONG2NUM(ary->length);
|
401
|
+
}
|
402
|
+
|
403
|
+
/*
|
404
|
+
* call-seq:
|
405
|
+
* ary.buffer => String
|
406
|
+
*
|
407
|
+
* Returns the underlying buffer managed by this ArrayBuffer instance.
|
408
|
+
*
|
409
|
+
* === Examples
|
410
|
+
* ary = Int32Array.new("buffer") => DataView
|
411
|
+
* ary.buffer => ArrayBuffer
|
412
|
+
*
|
413
|
+
*/
|
414
|
+
static VALUE rb_type_array_buffer(VALUE obj)
|
415
|
+
{
|
416
|
+
GetTypeArray(obj);
|
417
|
+
return ary->buf;
|
418
|
+
}
|
419
|
+
|
420
|
+
/*
|
421
|
+
* call-seq:
|
422
|
+
* art.to_s => String
|
423
|
+
*
|
424
|
+
* Returns a String (binary) representation of the underlying buffer managed by this TypeArray instance.
|
425
|
+
*
|
426
|
+
* === Examples
|
427
|
+
* buf = ArrayBuffer.new("buffer") => ArrayBuffer
|
428
|
+
* ary = Int32Array.new(buf) => Int32Array
|
429
|
+
* ary.to_s => "buffer"
|
430
|
+
*
|
431
|
+
*/
|
432
|
+
static VALUE rb_type_array_to_s(VALUE obj)
|
433
|
+
{
|
434
|
+
GetTypeArray(obj);
|
435
|
+
return rb_array_buffer_to_s(ary->buf);
|
436
|
+
}
|
437
|
+
|
438
|
+
/*
|
439
|
+
* call-seq:
|
440
|
+
* ary.byte_offset => Fixnum
|
441
|
+
*
|
442
|
+
* Returns the offset into the underlying buffer managed by this TypeArray instance.
|
443
|
+
*
|
444
|
+
* === Examples
|
445
|
+
* ary = Int32Array.new("01234567") => Int32Array
|
446
|
+
* ary.byte_offset => 0
|
447
|
+
*
|
448
|
+
* ary = Int32Array.new("01234567", 2) => Int32Array
|
449
|
+
* ary.byte_offset => 2
|
450
|
+
*
|
451
|
+
*/
|
452
|
+
static VALUE rb_type_array_byte_offset(VALUE obj)
|
453
|
+
{
|
454
|
+
GetTypeArray(obj);
|
455
|
+
return ULONG2NUM(ary->byte_offset);
|
456
|
+
}
|
457
|
+
|
458
|
+
/*
|
459
|
+
* call-seq:
|
460
|
+
* ary[1] = 20 => nil
|
461
|
+
*
|
462
|
+
* Sets a value at a given offset, with coercion dependent on the array type of this instance.
|
463
|
+
*
|
464
|
+
* === Examples
|
465
|
+
* ary = Int32Array.new("01234567") => Int32Array
|
466
|
+
* ary[1] = 23 => nil
|
467
|
+
*
|
468
|
+
*/
|
469
|
+
static VALUE rb_type_array_aset(VALUE obj, VALUE idx, VALUE item)
|
470
|
+
{
|
471
|
+
GetTypeArray(obj);
|
472
|
+
GetArrayBuffer(ary->buf);
|
473
|
+
long index = rb_type_array_assert_offset(ary, idx);
|
474
|
+
switch (TYPE(item)) {
|
475
|
+
case T_FIXNUM:
|
476
|
+
case T_BIGNUM:
|
477
|
+
case T_FLOAT:
|
478
|
+
break;
|
479
|
+
default:
|
480
|
+
rb_raise(rb_eTypeError, "Type arrays only support Fixnum, Bignum and Float instances");
|
481
|
+
}
|
482
|
+
ary->aset_fn(buf->buf, index, item);
|
483
|
+
return Qnil;
|
484
|
+
}
|
485
|
+
|
486
|
+
/*
|
487
|
+
* call-seq:
|
488
|
+
* ary[1] => Fixnum, Bignum or Float
|
489
|
+
*
|
490
|
+
* Gets a value at a given offset, with coercion dependent on the array type of this instance.
|
491
|
+
*
|
492
|
+
* === Examples
|
493
|
+
* ary = Int32Array.new("01234567") => Int32Array
|
494
|
+
* ary[1] = 23 => nil
|
495
|
+
* ary[1] => 23
|
496
|
+
*
|
497
|
+
*/
|
498
|
+
static VALUE rb_type_array_aget(VALUE obj, VALUE idx)
|
499
|
+
{
|
500
|
+
GetTypeArray(obj);
|
501
|
+
GetArrayBuffer(ary->buf);
|
502
|
+
long index = rb_type_array_assert_offset(ary, idx);
|
503
|
+
return ary->aref_fn(buf->buf, index);
|
504
|
+
}
|
505
|
+
|
506
|
+
void _init_type_array()
|
507
|
+
{
|
508
|
+
rb_cTypeArray = rb_define_class("TypeArray", rb_cObject);
|
509
|
+
|
510
|
+
rb_type_array_intern_aget = rb_intern("[]");
|
511
|
+
rb_type_array_intern_aset = rb_intern("[]=");
|
512
|
+
|
513
|
+
rb_cInt8Array = rb_define_class("Int8Array", rb_cTypeArray);
|
514
|
+
rb_cUInt8Array = rb_define_class("UInt8Array", rb_cTypeArray);
|
515
|
+
rb_cInt16Array = rb_define_class("Int16Array", rb_cTypeArray);
|
516
|
+
rb_cUInt16Array = rb_define_class("UInt16Array", rb_cTypeArray);
|
517
|
+
rb_cInt32Array = rb_define_class("Int32Array", rb_cTypeArray);
|
518
|
+
rb_cUInt32Array = rb_define_class("UInt32Array", rb_cTypeArray);
|
519
|
+
rb_cFloat32Array = rb_define_class("Float32Array", rb_cTypeArray);
|
520
|
+
rb_cFloat64Array = rb_define_class("Float64Array", rb_cTypeArray);
|
521
|
+
|
522
|
+
rb_define_const(rb_cInt8Array, "BYTES_PER_ELEMENT", ULONG2NUM(sizeof(signed char)));
|
523
|
+
rb_define_const(rb_cUInt8Array, "BYTES_PER_ELEMENT", ULONG2NUM(sizeof(unsigned char)));
|
524
|
+
rb_define_const(rb_cInt16Array, "BYTES_PER_ELEMENT", ULONG2NUM(sizeof(short)));
|
525
|
+
rb_define_const(rb_cUInt16Array, "BYTES_PER_ELEMENT", ULONG2NUM(sizeof(unsigned short)));
|
526
|
+
rb_define_const(rb_cInt32Array, "BYTES_PER_ELEMENT", ULONG2NUM(sizeof(int)));
|
527
|
+
rb_define_const(rb_cUInt32Array, "BYTES_PER_ELEMENT", ULONG2NUM(sizeof(unsigned int)));
|
528
|
+
rb_define_const(rb_cFloat32Array, "BYTES_PER_ELEMENT", ULONG2NUM(sizeof(float)));
|
529
|
+
rb_define_const(rb_cFloat64Array, "BYTES_PER_ELEMENT", ULONG2NUM(sizeof(double)));
|
530
|
+
|
531
|
+
rb_define_singleton_method(rb_cTypeArray, "new", rb_type_array_s_new, -1);
|
532
|
+
|
533
|
+
rb_define_method(rb_cTypeArray, "byte_length", rb_type_array_byte_length, 0);
|
534
|
+
rb_define_method(rb_cTypeArray, "length", rb_type_array_length, 0);
|
535
|
+
rb_define_method(rb_cTypeArray, "buffer", rb_type_array_buffer, 0);
|
536
|
+
rb_define_method(rb_cTypeArray, "byte_offset", rb_type_array_byte_offset, 0);
|
537
|
+
rb_define_method(rb_cTypeArray, "to_s", rb_type_array_to_s, 0);
|
538
|
+
rb_define_method(rb_cTypeArray, "[]=", rb_type_array_aset, 2);
|
539
|
+
rb_define_method(rb_cTypeArray, "[]", rb_type_array_aget, 1);
|
540
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#ifndef TYPE_ARRAY_H
|
2
|
+
#define TYPE_ARRAY_H
|
3
|
+
|
4
|
+
typedef void (type_array_aset_fn) (rb_array_buffer_t *buf, long index, VALUE item);
|
5
|
+
typedef VALUE (type_array_aref_fn) (rb_array_buffer_t *buf, long index);
|
6
|
+
|
7
|
+
typedef struct {
|
8
|
+
unsigned long size;
|
9
|
+
unsigned long length;
|
10
|
+
unsigned long byte_length;
|
11
|
+
unsigned long byte_offset;
|
12
|
+
type_array_aset_fn *aset_fn;
|
13
|
+
type_array_aref_fn *aref_fn;
|
14
|
+
VALUE buf;
|
15
|
+
} rb_type_array_t;
|
16
|
+
|
17
|
+
#define GetTypeArray(obj) \
|
18
|
+
rb_type_array_t *ary = NULL; \
|
19
|
+
Data_Get_Struct(obj, rb_type_array_t, ary); \
|
20
|
+
if (!ary) rb_raise(rb_eTypeError, "uninitialized TypeArray!");
|
21
|
+
|
22
|
+
void rb_type_array_swizzle(char* buf, unsigned long len);
|
23
|
+
void _init_type_array();
|
24
|
+
|
25
|
+
#define DefineTypeArraySetter(name, coercion) \
|
26
|
+
void rb_type_array_aset_##name(rb_array_buffer_t *buf, long index, VALUE item) \
|
27
|
+
{ \
|
28
|
+
rb_type_array_set_##name(buf, index, coercion, TYPE_ARRAY_IS_LITTLE_ENDIAN); \
|
29
|
+
}
|
30
|
+
|
31
|
+
#define DefineTypeArrayGetter(name, type, coercion) \
|
32
|
+
VALUE rb_type_array_aref_##name(rb_array_buffer_t *buf, long index) \
|
33
|
+
{ \
|
34
|
+
type val = rb_type_array_get_##name(buf, index, TYPE_ARRAY_IS_LITTLE_ENDIAN); \
|
35
|
+
return coercion; \
|
36
|
+
}
|
37
|
+
|
38
|
+
#endif
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#include "type_array_ext.h"
|
2
|
+
|
3
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
4
|
+
rb_encoding *binary_encoding;
|
5
|
+
#endif
|
6
|
+
|
7
|
+
DefineTypeAccessor(int8, signed char);
|
8
|
+
DefineTypeAccessor(uint8, unsigned char);
|
9
|
+
DefineTypeAccessor(int16, short);
|
10
|
+
DefineTypeAccessor(uint16, unsigned short);
|
11
|
+
DefineTypeAccessor(int32, int);
|
12
|
+
DefineTypeAccessor(uint32, unsigned int);
|
13
|
+
DefineTypeAccessor(float32, float);
|
14
|
+
DefineTypeAccessor(float64, double);
|
15
|
+
|
16
|
+
void Init_type_array_ext()
|
17
|
+
{
|
18
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
19
|
+
binary_encoding = rb_enc_find("binary");
|
20
|
+
#endif
|
21
|
+
|
22
|
+
_init_array_buffer();
|
23
|
+
_init_type_array();
|
24
|
+
_init_data_view();
|
25
|
+
}
|
@@ -0,0 +1,71 @@
|
|
1
|
+
#ifndef TYPE_ARRAY_EXT_H
|
2
|
+
#define TYPE_ARRAY_EXT_H
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
#include "prelude.h"
|
6
|
+
|
7
|
+
extern VALUE rb_cArrayBuffer;
|
8
|
+
|
9
|
+
extern VALUE rb_cTypeArray;
|
10
|
+
extern VALUE rb_cInt8Array;
|
11
|
+
extern VALUE rb_cUInt8Array;
|
12
|
+
extern VALUE rb_cInt16Array;
|
13
|
+
extern VALUE rb_cUInt16Array;
|
14
|
+
extern VALUE rb_cInt32Array;
|
15
|
+
extern VALUE rb_cUInt32Array;
|
16
|
+
extern VALUE rb_cInt64Array;
|
17
|
+
extern VALUE rb_cUInt64Array;
|
18
|
+
|
19
|
+
extern VALUE rb_cDataView;
|
20
|
+
|
21
|
+
/* Special case overrides as the Ruby specific implementations casts to long (thx James Tucker) */
|
22
|
+
#define TAINT2FIX(i) ((VALUE)(((char)(i))<<1 | FIXNUM_FLAG))
|
23
|
+
#define TACHR2FIX(x) TAINT2FIX((char)((x)&0xff))
|
24
|
+
|
25
|
+
void rb_type_array_set_int8(void *abuf, unsigned long index, signed char val, VALUE swiz);
|
26
|
+
void rb_type_array_set_uint8(void *abuf, unsigned long index, unsigned char val, VALUE swiz);
|
27
|
+
void rb_type_array_set_int16(void *abuf, unsigned long index, short val, VALUE swiz);
|
28
|
+
void rb_type_array_set_uint16(void *abuf, unsigned long index, unsigned short val, VALUE swiz);
|
29
|
+
void rb_type_array_set_int32(void *abuf, unsigned long index, int val, VALUE swiz);
|
30
|
+
void rb_type_array_set_uint32(void *abuf, unsigned long index, unsigned int val, VALUE swiz);
|
31
|
+
void rb_type_array_set_float32(void *abuf, unsigned long index, float val, VALUE swiz);
|
32
|
+
void rb_type_array_set_float64(void *abuf, unsigned long index, double val, VALUE swiz);
|
33
|
+
|
34
|
+
signed char rb_type_array_get_int8(void *abuf, unsigned long index, VALUE swiz);
|
35
|
+
unsigned char rb_type_array_get_uint8(void *abuf, unsigned long index, VALUE swiz);
|
36
|
+
short rb_type_array_get_int16(void *abuf, unsigned long index, VALUE swiz);
|
37
|
+
unsigned short rb_type_array_get_uint16(void *abuf, unsigned long index, VALUE swiz);
|
38
|
+
int rb_type_array_get_int32(void *abuf, unsigned long index, VALUE swiz);
|
39
|
+
unsigned int rb_type_array_get_uint32(void *abuf, unsigned long index, VALUE swiz);
|
40
|
+
float rb_type_array_get_float32(void *abuf, unsigned long index, VALUE swiz);
|
41
|
+
double rb_type_array_get_float64(void *abuf, unsigned long index, VALUE swiz);
|
42
|
+
|
43
|
+
#define DefineTypeGetter(name, type) \
|
44
|
+
inline type rb_type_array_get_##name(void *abuf, unsigned long index, VALUE swiz) \
|
45
|
+
{ \
|
46
|
+
char buf[sizeof(type)]; \
|
47
|
+
type val; \
|
48
|
+
memmove(buf, (char *)abuf + index, sizeof(type)); \
|
49
|
+
if (swiz) rb_type_array_swizzle(buf, sizeof(type)); \
|
50
|
+
memmove(&val, buf, sizeof(type)); \
|
51
|
+
return val; \
|
52
|
+
}
|
53
|
+
|
54
|
+
#define DefineTypeSetter(name, type) \
|
55
|
+
inline void rb_type_array_set_##name(void *abuf, unsigned long index, type val, VALUE swiz) \
|
56
|
+
{ \
|
57
|
+
char buf[sizeof(type)]; \
|
58
|
+
memmove(buf, &val, sizeof(type)); \
|
59
|
+
if (swiz) rb_type_array_swizzle(buf, sizeof(type)); \
|
60
|
+
memmove((char *)abuf + index, buf, sizeof(type)); \
|
61
|
+
}
|
62
|
+
|
63
|
+
#define DefineTypeAccessor(name, type) \
|
64
|
+
DefineTypeSetter(name, type); \
|
65
|
+
DefineTypeGetter(name, type);
|
66
|
+
|
67
|
+
#include "array_buffer.h"
|
68
|
+
#include "type_array.h"
|
69
|
+
#include "data_view.h"
|
70
|
+
|
71
|
+
#endif
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
module TypeArray::IOReader
|
6
|
+
def read(io, length)
|
7
|
+
buf = nil
|
8
|
+
case io
|
9
|
+
when BasicSocket
|
10
|
+
buf = io.recv(length)
|
11
|
+
when IO
|
12
|
+
buf = ""
|
13
|
+
io.read(length, buf)
|
14
|
+
end
|
15
|
+
new(buf)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module TypeArray::IOWriter
|
20
|
+
def write(io)
|
21
|
+
case io
|
22
|
+
when BasicSocket
|
23
|
+
io.send(to_s, 0)
|
24
|
+
when IO
|
25
|
+
io.write(to_s)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|