type_array 0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|