type_array 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,13 @@
1
1
  = Changelog
2
2
 
3
+ == 0.3.0 (July 18th, 2012)
4
+ * Introduce support for setting operator results at a given offset without coercion to a Ruby object
5
+ * Let TypeArray be enumerable as well
6
+ * Support Marshal dump / load
7
+
8
+ == 0.2.0 (July 12th, 2012)
9
+ * Introduce support for lower level comparison at given offsets (avoids excess Ruby object allocations)
10
+ * Introduce support for lower level math operations at given offsets (avoids excess Ruby object allocations)
11
+
3
12
  == 0.1.0 (July 11th, 2012)
4
13
  * initial release
@@ -130,7 +130,6 @@ Running tests
130
130
 
131
131
  == Todo
132
132
 
133
- * Support Marshal dump / load
134
133
  * Support structs / records
135
134
  * Handle edges where coercion to and from Bignum is more appropriate
136
135
 
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ $:.unshift File.expand_path('lib')
4
+ require 'type_array'
5
+ require 'benchmark'
6
+
7
+ typed = Float32Array.new(1_000_000)
8
+ native = Array.new(1_000_000)
9
+
10
+
11
+ Benchmark.bmbm do |x|
12
+ x.report("typed array []=") do
13
+ 1_000_000.times {|i| typed[i] = 0.1234567890123456; typed[i] }
14
+ end
15
+
16
+ x.report("array []=") do
17
+ 1_000_000.times {|i| native[i] = 0.1234567890123456; typed[i] }
18
+ end
19
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ $:.unshift File.expand_path('lib')
4
+ require 'type_array'
5
+ require 'benchmark'
6
+
7
+ buf = ArrayBuffer.new(24)
8
+
9
+ typed = Float64Array.new(buf)
10
+
11
+ typed[0] = 2.33
12
+ typed[1] = 2.33
13
+ typed[2] = 7.45
14
+ native = [2.33, 2.33, 7.45]
15
+
16
+
17
+ Benchmark.bmbm do |x|
18
+ x.report("type array eql") do
19
+ 1_000_000.times {|i| typed.eql(0,1) }
20
+ end
21
+
22
+ x.report("type array mul") do
23
+ 1_000_000.times {|i| typed.mul(0,1) }
24
+ end
25
+
26
+ x.report("array eql") do
27
+ 1_000_000.times {|i| native[0] == native[1] }
28
+ end
29
+
30
+ x.report("array mul") do
31
+ 1_000_000.times {|i| native[0] * native[1] }
32
+ end
33
+ end
@@ -237,7 +237,8 @@ DefineTypeArrayOperator(eql, ==, float64, double, (val == 0 ? Qfalse : Qtrue));
237
237
  * Asserts type alignment.
238
238
  *
239
239
  */
240
- inline int rb_type_array_assert_alignment(unsigned long val, unsigned long bytes) {
240
+ inline int rb_type_array_assert_alignment(unsigned long val, unsigned long bytes)
241
+ {
241
242
  return (val & (bytes - 1)) == 0 ? 1 : 0;
242
243
  }
243
244
 
@@ -246,7 +247,8 @@ inline int rb_type_array_assert_alignment(unsigned long val, unsigned long bytes
246
247
  * Swizzles byte order.
247
248
  *
248
249
  */
249
- inline void rb_type_array_swizzle(char* buf, unsigned long len) {
250
+ inline void rb_type_array_swizzle(char* buf, unsigned long len)
251
+ {
250
252
  unsigned long i;
251
253
  for (i = 0; i < len / 2; ++i) {
252
254
  char t = buf[i];
@@ -257,14 +259,12 @@ inline void rb_type_array_swizzle(char* buf, unsigned long len) {
257
259
 
258
260
  /*
259
261
  * :nodoc:
260
- * Validates offset boundaries.
262
+ * Validates offset boundaries (no index coercion)
261
263
  *
262
264
  */
263
- static inline long rb_type_array_assert_offset(rb_type_array_t *ary, VALUE idx)
265
+ static inline long rb_type_array_assert_offset0(rb_type_array_t *ary, long idx)
264
266
  {
265
- long index;
266
- Check_Type(idx, T_FIXNUM);
267
- index = FIX2LONG(idx) * ary->size;
267
+ long index = idx * ary->size;
268
268
  if (index < 0) rb_raise(rb_eRangeError, "Offset may not be negative.");
269
269
  if (!rb_type_array_assert_alignment(index, ary->size)) rb_raise(rb_eRangeError, "Byte offset is not aligned.");
270
270
  if ((unsigned long)index > ary->byte_length) rb_raise(rb_eRangeError, "Offset out of range.");
@@ -272,6 +272,17 @@ static inline long rb_type_array_assert_offset(rb_type_array_t *ary, VALUE idx)
272
272
  return index;
273
273
  }
274
274
 
275
+ /*
276
+ * :nodoc:
277
+ * Validates offset boundaries.
278
+ *
279
+ */
280
+ static inline long rb_type_array_assert_offset(rb_type_array_t *ary, VALUE idx)
281
+ {
282
+ Check_Type(idx, T_FIXNUM);
283
+ return rb_type_array_assert_offset0(ary, FIX2LONG(idx));
284
+ }
285
+
275
286
  /*
276
287
  * :nodoc:
277
288
  * GC mark callback
@@ -502,13 +513,16 @@ static VALUE rb_type_array_byte_length(VALUE obj)
502
513
  * ary.mul(0,1) => 8
503
514
  * ary.mul(1,2) => 32
504
515
  */
505
- static VALUE rb_type_array_mul(VALUE obj, VALUE off1, VALUE off2)
516
+ static VALUE rb_type_array_mul(int argc, VALUE *argv, VALUE obj)
506
517
  {
518
+ VALUE off1, off2, off3;
507
519
  GetTypeArray(obj);
508
520
  GetArrayBuffer(ary->buf);
521
+ rb_scan_args(argc, argv, "21", &off1, &off2, &off3);
509
522
  long offset1 = rb_type_array_assert_offset(ary, off1);
510
523
  long offset2 = rb_type_array_assert_offset(ary, off2);
511
- return ary->mul_fn(buf->buf, offset1, offset2);
524
+ long offset3 = NIL_P(off3) ? 0 : rb_type_array_assert_offset(ary, off3);
525
+ return ary->mul_fn(buf->buf, offset1, offset2, offset3);
512
526
  }
513
527
 
514
528
  /*
@@ -527,13 +541,16 @@ static VALUE rb_type_array_mul(VALUE obj, VALUE off1, VALUE off2)
527
541
  * ary.plus(0,1) => 6
528
542
  * ary.plus(1,2) => 12
529
543
  */
530
- static VALUE rb_type_array_plus(VALUE obj, VALUE off1, VALUE off2)
544
+ static VALUE rb_type_array_plus(int argc, VALUE *argv, VALUE obj)
531
545
  {
546
+ VALUE off1, off2, off3;
532
547
  GetTypeArray(obj);
533
548
  GetArrayBuffer(ary->buf);
549
+ rb_scan_args(argc, argv, "21", &off1, &off2, &off3);
534
550
  long offset1 = rb_type_array_assert_offset(ary, off1);
535
551
  long offset2 = rb_type_array_assert_offset(ary, off2);
536
- return ary->plus_fn(buf->buf, offset1, offset2);
552
+ long offset3 = NIL_P(off3) ? 0 : rb_type_array_assert_offset(ary, off3);
553
+ return ary->plus_fn(buf->buf, offset1, offset2, offset3);
537
554
  }
538
555
 
539
556
  /*
@@ -552,13 +569,16 @@ static VALUE rb_type_array_plus(VALUE obj, VALUE off1, VALUE off2)
552
569
  * ary.minus(1, 0) => 2
553
570
  * ary.minus(2, 1) => 4
554
571
  */
555
- static VALUE rb_type_array_minus(VALUE obj, VALUE off1, VALUE off2)
572
+ static VALUE rb_type_array_minus(int argc, VALUE *argv, VALUE obj)
556
573
  {
574
+ VALUE off1, off2, off3;
557
575
  GetTypeArray(obj);
558
576
  GetArrayBuffer(ary->buf);
577
+ rb_scan_args(argc, argv, "21", &off1, &off2, &off3);
559
578
  long offset1 = rb_type_array_assert_offset(ary, off1);
560
579
  long offset2 = rb_type_array_assert_offset(ary, off2);
561
- return ary->minus_fn(buf->buf, offset1, offset2);
580
+ long offset3 = NIL_P(off3) ? 0 : rb_type_array_assert_offset(ary, off3);
581
+ return ary->minus_fn(buf->buf, offset1, offset2, offset3);
562
582
  }
563
583
 
564
584
  /*
@@ -577,20 +597,23 @@ static VALUE rb_type_array_minus(VALUE obj, VALUE off1, VALUE off2)
577
597
  * ary.div(1, 0) => 2
578
598
  * ary.div(2, 1) => 2
579
599
  */
580
- static VALUE rb_type_array_div(VALUE obj, VALUE off1, VALUE off2)
600
+ static VALUE rb_type_array_div(int argc, VALUE *argv, VALUE obj)
581
601
  {
602
+ VALUE off1, off2, off3;
582
603
  GetTypeArray(obj);
583
604
  GetArrayBuffer(ary->buf);
605
+ rb_scan_args(argc, argv, "21", &off1, &off2, &off3);
584
606
  long offset1 = rb_type_array_assert_offset(ary, off1);
585
607
  long offset2 = rb_type_array_assert_offset(ary, off2);
586
- return ary->div_fn(buf->buf, offset1, offset2);
608
+ long offset3 = NIL_P(off3) ? 0 : rb_type_array_assert_offset(ary, off3);
609
+ return ary->div_fn(buf->buf, offset1, offset2, offset3);
587
610
  }
588
611
 
589
612
  /*
590
613
  * call-seq:
591
- * ary.div(0,1) => Fixnum, Bignum or Float
614
+ * ary.eql(0,1) => true or fales
592
615
  *
593
- * Gets two values at given offsets and divides them - only the result's coerced to a Ruby object.
616
+ * Gets two values at given offsets and compares them - a boolean's returned
594
617
  *
595
618
  * === Examples
596
619
  * buf = ArrayBuffer.new(16) => ArrayBuffer
@@ -599,8 +622,8 @@ static VALUE rb_type_array_div(VALUE obj, VALUE off1, VALUE off2)
599
622
  * ary[1] = 4 => nil
600
623
  * ary[2] = 8 => nil
601
624
  *
602
- * ary.div(1, 0) => 2
603
- * ary.div(2, 1) => 2
625
+ * ary.eql(1, 0) => false
626
+ * ary.eql(2, 2) => true
604
627
  */
605
628
  static VALUE rb_type_array_eql(VALUE obj, VALUE off1, VALUE off2)
606
629
  {
@@ -608,7 +631,7 @@ static VALUE rb_type_array_eql(VALUE obj, VALUE off1, VALUE off2)
608
631
  GetArrayBuffer(ary->buf);
609
632
  long offset1 = rb_type_array_assert_offset(ary, off1);
610
633
  long offset2 = rb_type_array_assert_offset(ary, off2);
611
- return ary->eql_fn(buf->buf, offset1, offset2);
634
+ return ary->eql_fn(buf->buf, offset1, offset2, 0);
612
635
  }
613
636
 
614
637
  /*
@@ -732,9 +755,41 @@ static VALUE rb_type_array_aget(VALUE obj, VALUE idx)
732
755
  return ary->aref_fn(buf->buf, index);
733
756
  }
734
757
 
758
+ /*
759
+ * call-seq:
760
+ * type_array.each {|item| block } => TypeArray
761
+ *
762
+ * Calls <i>block</i> once for each element in <i>self</i>, passing that element as a parameter.
763
+ *
764
+ * === Examples
765
+ * buf = ArrayBuffer.new(16) => ArrayBuffer
766
+ *
767
+ * ary = Int32Array.new(buf) => Int32Array
768
+ * ary[0] = 2 => nil
769
+ * ary[1] = 4 => nil
770
+ * ary[2] = 8 => nil
771
+ * ary[3] = 16 => nil
772
+ *
773
+ * ary.map(&:to_s) => %w(2 4 8 16)
774
+ *
775
+ */
776
+ static VALUE rb_type_array_each(VALUE obj)
777
+ {
778
+ long index;
779
+ GetTypeArray(obj);
780
+ GetArrayBuffer(ary->buf);
781
+
782
+ RETURN_ENUMERATOR(obj, 0, 0);
783
+ for (index = 0; index < ary->length; index++) {
784
+ rb_yield(ary->aref_fn(buf->buf, (index * ary->size)));
785
+ }
786
+ return obj;
787
+ }
788
+
735
789
  void _init_type_array()
736
790
  {
737
791
  rb_cTypeArray = rb_define_class("TypeArray", rb_cObject);
792
+ rb_include_module(rb_cTypeArray, rb_mEnumerable);
738
793
 
739
794
  rb_type_array_intern_aget = rb_intern("[]");
740
795
  rb_type_array_intern_aset = rb_intern("[]=");
@@ -766,9 +821,10 @@ void _init_type_array()
766
821
  rb_define_method(rb_cTypeArray, "to_s", rb_type_array_to_s, 0);
767
822
  rb_define_method(rb_cTypeArray, "[]=", rb_type_array_aset, 2);
768
823
  rb_define_method(rb_cTypeArray, "[]", rb_type_array_aget, 1);
769
- rb_define_method(rb_cTypeArray, "mul", rb_type_array_mul, 2);
770
- rb_define_method(rb_cTypeArray, "plus", rb_type_array_plus, 2);
771
- rb_define_method(rb_cTypeArray, "minus", rb_type_array_minus, 2);
772
- rb_define_method(rb_cTypeArray, "div", rb_type_array_div, 2);
824
+ rb_define_method(rb_cTypeArray, "mul", rb_type_array_mul, -1);
825
+ rb_define_method(rb_cTypeArray, "plus", rb_type_array_plus, -1);
826
+ rb_define_method(rb_cTypeArray, "minus", rb_type_array_minus, -1);
827
+ rb_define_method(rb_cTypeArray, "div", rb_type_array_div, -1);
773
828
  rb_define_method(rb_cTypeArray, "eql", rb_type_array_eql, 2);
829
+ rb_define_method(rb_cTypeArray, "each", rb_type_array_each, 0);
774
830
  }
@@ -3,7 +3,7 @@
3
3
 
4
4
  typedef void (type_array_aset_fn) (rb_array_buffer_t *buf, long index, VALUE item);
5
5
  typedef VALUE (type_array_aref_fn) (rb_array_buffer_t *buf, long index);
6
- typedef VALUE (type_array_operator_fn) (rb_array_buffer_t *buf, long off1, long off2);
6
+ typedef VALUE (type_array_operator_fn) (rb_array_buffer_t *buf, long off1, long off2, long off3);
7
7
 
8
8
  typedef struct {
9
9
  unsigned long size;
@@ -48,13 +48,18 @@ void _init_type_array();
48
48
  DefineTypeArrayOperator(div, /, name, type, coercion); \
49
49
 
50
50
  #define DefineTypeArrayOperator(op_name, op, name, type, coercion) \
51
- VALUE rb_type_array_##op_name##_##name(rb_array_buffer_t *buf, long off1, long off2) \
51
+ VALUE rb_type_array_##op_name##_##name(rb_array_buffer_t *buf, long off1, long off2, long off3) \
52
52
  { \
53
53
  type val; \
54
54
  type val1 = rb_type_array_get_##name(buf, off1, TYPE_ARRAY_IS_LITTLE_ENDIAN); \
55
55
  type val2 = rb_type_array_get_##name(buf, off2, TYPE_ARRAY_IS_LITTLE_ENDIAN); \
56
56
  val = val1 op val2; \
57
- return coercion; \
57
+ if (off3 != 0) { \
58
+ rb_type_array_set_##name(buf, off3, val, TYPE_ARRAY_IS_LITTLE_ENDIAN); \
59
+ return Qnil; \
60
+ } else { \
61
+ return coercion; \
62
+ } \
58
63
  }
59
64
 
60
65
  #endif
@@ -7,8 +7,9 @@ require "type_array_ext"
7
7
 
8
8
  require 'type_array/version' unless defined? TypeArray::VERSION
9
9
  require 'type_array/io'
10
+ require 'type_array/marshal'
10
11
 
11
12
  [ArrayBuffer, TypeArray, DataView].each do |c|
12
13
  c.extend TypeArray::IOReader
13
- c.send(:include, TypeArray::IOWriter)
14
+ c.send(:include, TypeArray::IOWriter, TypeArray::Marshal)
14
15
  end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ module TypeArray::Marshal
4
+ def self.included(klass)
5
+ class << klass
6
+ def _load(str); new(str) end
7
+ end
8
+ end
9
+
10
+ def _dump(obj)
11
+ to_s
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  class TypeArray
2
- VERSION = '0.2'
2
+ VERSION = '0.3'
3
3
  end
@@ -66,6 +66,17 @@ class TestArrayBuffer < TypeArrayTestCase
66
66
  assert str.frozen?
67
67
  end
68
68
 
69
+ def test_marshal
70
+ buf = ArrayBuffer.new(4)
71
+ assert_equal "\x00\x00\x00\x00", buf.to_s
72
+
73
+ serialized = "\x04\bu:\x10ArrayBuffer\t\x00\x00\x00\x00"
74
+ assert_equal serialized, Marshal.dump(buf)
75
+
76
+ buf = Marshal.load(serialized)
77
+ assert_equal "\x00\x00\x00\x00", buf.to_s
78
+ end
79
+
69
80
  def test_io
70
81
  buf = ArrayBuffer.new(16)
71
82
 
@@ -69,6 +69,22 @@ class TestDataView < TypeArrayTestCase
69
69
  assert str.frozen?
70
70
  end
71
71
 
72
+ def test_marshal
73
+ buf = ArrayBuffer.new(4)
74
+
75
+ view = DataView.new(buf)
76
+ view.set_int8(1, 5)
77
+ view.set_int16(3, 7)
78
+
79
+ serialized = "\x04\bu:\rDataView\t\x00\x05\x00\a"
80
+ assert_equal serialized, Marshal.dump(view)
81
+
82
+ view = Marshal.load(serialized)
83
+ assert_instance_of DataView, view
84
+ assert_equal 5, view.get_int8(1)
85
+ assert_equal 7, view.get_int8(3)
86
+ end
87
+
72
88
  def test_int8
73
89
  buf = ArrayBuffer.new(100)
74
90
 
@@ -89,7 +89,7 @@ class TestTypeArray < TypeArrayTestCase
89
89
 
90
90
  ary2 = Int8Array.new(ary)
91
91
  assert_equal 100, ary2[0]
92
- assert_equal -56, ary2[1]
92
+ assert_equal(-56, ary2[1])
93
93
  assert_equal 44, ary2[2]
94
94
  end
95
95
 
@@ -163,6 +163,9 @@ class TestTypeArray < TypeArrayTestCase
163
163
 
164
164
  assert_equal 8, ary.mul(0,1)
165
165
  assert_equal 32, ary.mul(1, 2)
166
+
167
+ ary.mul(0, 1, 3)
168
+ assert_equal 8, ary[3]
166
169
  end
167
170
 
168
171
  def test_plus
@@ -175,6 +178,9 @@ class TestTypeArray < TypeArrayTestCase
175
178
 
176
179
  assert_equal 6, ary.plus(0,1)
177
180
  assert_equal 12, ary.plus(1, 2)
181
+
182
+ ary.plus(1, 2, 3)
183
+ assert_equal 12, ary[3]
178
184
  end
179
185
 
180
186
  def test_minus
@@ -187,6 +193,9 @@ class TestTypeArray < TypeArrayTestCase
187
193
 
188
194
  assert_equal 2, ary.minus(1,0)
189
195
  assert_equal 4, ary.minus(2, 1)
196
+
197
+ ary.minus(2, 1, 3)
198
+ assert_equal 4, ary[3]
190
199
  end
191
200
 
192
201
  def test_div
@@ -199,6 +208,9 @@ class TestTypeArray < TypeArrayTestCase
199
208
 
200
209
  assert_equal 2, ary.div(1,0)
201
210
  assert_equal 2, ary.div(2, 1)
211
+
212
+ ary.div(2, 1, 3)
213
+ assert_equal 2, ary[3]
202
214
  end
203
215
 
204
216
  def test_eql
@@ -225,4 +237,38 @@ class TestTypeArray < TypeArrayTestCase
225
237
  assert ary.eql(0,1)
226
238
  assert !ary.eql(1,2)
227
239
  end
240
+
241
+ def test_each
242
+ buf = ArrayBuffer.new(16)
243
+
244
+ ary = Int32Array.new(buf)
245
+ ary[0] = 2
246
+ ary[1] = 4
247
+ ary[2] = 8
248
+ ary[3] = 16
249
+
250
+ vals = []
251
+ assert_equal ary, ary.each{|v| vals << v }
252
+
253
+ assert_equal [2, 4, 8, 16], vals
254
+ assert_equal %w(2 4 8 16), ary.map(&:to_s)
255
+ end
256
+
257
+ def test_marshal
258
+ buf = ArrayBuffer.new(16)
259
+
260
+ ary = Int32Array.new(buf)
261
+ ary[0] = 2
262
+ ary[1] = 4
263
+ ary[2] = 8
264
+ ary[3] = 16
265
+
266
+ serialized = "\x04\bu:\x0FInt32Array\x15\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\b\x00\x00\x00\x10"
267
+ assert_equal serialized, Marshal.dump(ary)
268
+
269
+ ary = Marshal.load(serialized)
270
+ assert_instance_of Int32Array, ary
271
+ assert_equal 2, ary[0]
272
+ assert_equal 16, ary[3]
273
+ end
228
274
  end
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: type_array
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 13
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 2
9
- version: "0.2"
8
+ - 3
9
+ version: "0.3"
10
10
  platform: ruby
11
11
  authors:
12
12
  - "Lourens Naud\xC3\xA9"
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2012-07-12 00:00:00 Z
17
+ date: 2012-07-18 00:00:00 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: rake-compiler
@@ -49,6 +49,8 @@ files:
49
49
  - Gemfile.lock
50
50
  - README.rdoc
51
51
  - Rakefile
52
+ - bench/get_set.rb
53
+ - bench/operators.rb
52
54
  - ext/type_array/array_buffer.c
53
55
  - ext/type_array/array_buffer.h
54
56
  - ext/type_array/data_view.c
@@ -65,6 +67,7 @@ files:
65
67
  - ext/type_array/type_array_ext.h
66
68
  - lib/type_array.rb
67
69
  - lib/type_array/io.rb
70
+ - lib/type_array/marshal.rb
68
71
  - lib/type_array/version.rb
69
72
  - test/helper.rb
70
73
  - test/test_array_buffer.rb
@@ -108,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
111
  requirements: []
109
112
 
110
113
  rubyforge_project:
111
- rubygems_version: 1.8.15
114
+ rubygems_version: 1.8.23
112
115
  signing_key:
113
116
  specification_version: 3
114
117
  summary: Typed Arrays for Ruby