type_array 0.2 → 0.3

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.
@@ -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