type_array 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ .libs/*
2
+ .rbx/*
3
+ *.rbc
4
+ *.lo
5
+ *.la
6
+ *.lai
7
+ *.dylib.dSYM
8
+ *.dylib
9
+ *.o
10
+ *.a
11
+ *.log
12
+ tmp/*
13
+ true/*
14
+ *.bundle
15
+ *.gem
16
+ doc/*
17
+ .DS_Store
18
+ pkg
19
+ ext/type_array/Makefile
data/.travis.yml ADDED
@@ -0,0 +1,18 @@
1
+ language: ruby
2
+ rvm:
3
+ - rbx-18mode
4
+ - rbx-19mode
5
+ - ree
6
+ - 1.8.7
7
+ - 1.9.2
8
+ - 1.9.3
9
+ - ruby-head
10
+ script: "bundle exec rake"
11
+ gemfile:
12
+ - Gemfile
13
+ notifications:
14
+ recipients:
15
+ - lourens@methodmissing.com
16
+ branches:
17
+ only:
18
+ - master
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,4 @@
1
+ = Changelog
2
+
3
+ == 0.1.0 (July 11th, 2012)
4
+ * initial release
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ gem 'rake'
data/Gemfile.lock ADDED
@@ -0,0 +1,18 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ binary_data (0.1)
5
+
6
+ GEM
7
+ specs:
8
+ rake (0.9.2.2)
9
+ rake-compiler (0.8.0)
10
+ rake
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ rake
17
+ rake-compiler (~> 0.8.0)
18
+ binary_data!
data/README.rdoc ADDED
@@ -0,0 +1,140 @@
1
+ = TypeArray - Ruby implementation of the ECMAScript spec ( http://wiki.ecmascript.org/doku.php?id=strawman:typed_arrays ) {<img src="https://secure.travis-ci.org/methodmissing/type_array.png" alt="Build Status" />}[http://travis-ci.org/methodmissing/type_array]
2
+
3
+ (c) 2012 Lourens Naudé (methodmissing)
4
+
5
+ http://github.com/methodmissing/type_array
6
+
7
+ This library provides portable, high performance and memory-safe access to native-typed binary data. It defines a generic fixed length buffer type as well as accessor types (views) for accessing data stored within the buffer.
8
+
9
+ Where binary data has needed to be manipulated, it is often stored as a String or Array. Both of these methods are slow and error-prone. Several protocol implementations would benefit from being able to read and write binary data directly to it's native form.
10
+
11
+ Supported numeric types :
12
+
13
+ * an unsigned-integer: one of uint8, uint16, uint32
14
+ * a signed-integer: one of int8, int16, int32
15
+ * a floating-point: one of float32 or float64
16
+
17
+ There's a few different kinds of typed arrays defined :
18
+
19
+ * Int8Array - 8-bit 2's complement signed integer
20
+ * UInt8Array - 8-bit unsigned integer
21
+ * Int16Array - 16-bit 2's complement signed integer
22
+ * UInt16Array - 16-bit unsigned integer
23
+ * Int32Array - 32-bit 2's complement signed integer
24
+ * Uint32Array - 32-bit unsigned integer
25
+ * Float32Array - 32-bit IEEE floating point
26
+ * Float64Array - 64-bit IEEE floating point
27
+
28
+ == Type Conversion
29
+
30
+ Type Size Description Equivalent C Type Ruby Type
31
+ --------------------------------------------------------------------------------------------------
32
+ Int8Array 1 8-bit 2's complement signed integer signed char Fixnum
33
+ Uint8Array 1 8-bit unsigned integer unsigned char Fixnum
34
+ Int16Array 2 16-bit 2's complement signed integer short Fixnum
35
+ Uint16Array 2 16-bit unsigned integer unsigned short Fixnum
36
+ Int32Array 4 32-bit 2's complement signed integer int Fixnum / Bignum
37
+ Uint32Array 4 32-bit unsigned integer unsigned int Fixnum / Bignum
38
+ Float32Array 4 32-bit IEEE floating point float Float
39
+ Float64Array 8 64-bit IEEE floating point double Float
40
+
41
+ == Array Buffers
42
+
43
+ An opaque buffer with an explicit and fixed length. ArrayBuffer contents cannot be accessed directly - there's no Ruby API exposed to manipulate it.
44
+
45
+ buf = ArrayBuffer.new(8) => ArrayBuffer
46
+ buf.byte_length => 8
47
+
48
+ buf = ArrayBuffer.new("buffer") => ArrayBuffer
49
+ buf.byte_length => 6
50
+ buf.to_s => "buffer"
51
+
52
+ == Type Arrays
53
+
54
+ A group of types are used to create views of the ArrayBuffer. For example, to access the buffer as an array of 32-bit signed integers, an Int32Array would be created that refers to the ArrayBuffer.
55
+
56
+ A number of types are introduced that describe how to interpret the bytes in an ArrayBuffer. For example, an Int32Array views the bytes in an ArrayBuffer (or a subregion of an ArrayBuffer) as 32-bit signed integers. Elements of the array are accessible by getting or setting their index.
57
+
58
+ buf = ArrayBuffer.new("buffer") => ArrayBuffer
59
+ ary = Int32Array.new(buf) => Int32Array
60
+ ary.to_s => "buffer"
61
+
62
+ ary = Int32Array.new("01234567") => Int32Array
63
+ ary[1] = 23 => nil
64
+ ary[1] => 23
65
+
66
+ buf = ArrayBuffer.new(100) => ArrayBuffer
67
+
68
+ ary = Int32Array.new(buf, 20) => Int32Array
69
+ ary.length => 20
70
+ ary.byte_length => 80
71
+ ary.byte_offset => 20
72
+
73
+ ary = Int32Array.new(buf, 0, 20) => Int32Array
74
+ ary.length => 20
75
+ ary.byte_length => 80
76
+ ary.byte_offset => 0
77
+
78
+ ary = Int32Array.new(buf, 20, 20) => Int32Array
79
+ ary.length => 20
80
+ ary.byte_length => 80
81
+ ary.byte_offset => 20
82
+
83
+ ary = Int32Array.new("01234567") => Int32Array
84
+ ary.byte_length => 8
85
+ ary.to_s => "01234567"
86
+
87
+ ary = Int32Array.new(100) => Int32Array
88
+ ary.length => 100
89
+ ary.byte_length => 400
90
+
91
+ == Data Views
92
+
93
+ Multiple views can exist for the same ArrayBuffer, allowing for complex data structures to be built up, albeit with some difficulty. A DataView type is introduced which allows arbitrary indexed reads and writes of basic types from the bytes in the underlying ArrayBuffer. The goal is to allow as close to the native byte access as possible with very few performance penalties, while still retaining safety.
94
+
95
+ buf = ArrayBuffer.new(100) => ArrayBuffer
96
+ view = DataView.new(buf) => DataView
97
+ view.set_float64(2, 77.643) => nil
98
+ view.get_float64(2) => 758
99
+
100
+ buf = ArrayBuffer.new(100) => ArrayBuffer
101
+ view = DataView.new(buf) => DataView
102
+ view.set_uint32(2, 758) => nil
103
+ view.get_uint32(2) => 758
104
+
105
+ buf = ArrayBuffer.new(100) => ArrayBuffer
106
+ view = DataView.new(buf) => DataView
107
+ view.set_int16(2, 20) => nil
108
+ view.get_int16(2) => 20
109
+
110
+ == Requirements
111
+
112
+ * Known to work well on Linux, BSD variants and Mac OS X (not tested on Windows)
113
+ * A C compiler
114
+ * Ruby MRI 1.8 or 1.9, Rubinius or JRuby (versions 1.6 and up, C API is deprecated though)
115
+
116
+ == Installation
117
+
118
+ Rubygems installation
119
+
120
+ gem install type_array
121
+
122
+ Building from source
123
+
124
+ git clone git@github.com:methodmissing/type_array.git
125
+ rake
126
+
127
+ Running tests
128
+
129
+ rake test
130
+
131
+ == Todo
132
+
133
+ * Support Marshal dump / load
134
+ * Low level API for math operations on array elements without creating any Ruby objects
135
+ * Support structs / records
136
+ * Handle edges where coercion to and from Bignum is more appropriate
137
+
138
+ == Contact, feedback and bugs
139
+
140
+ This project is still work in progress. Please log bugs and suggestions at https://github.com/methodmissing/type_array/issues
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems' unless defined?(Gem)
4
+ require 'rake' unless defined?(Rake)
5
+
6
+ # Prefer compiled Rubinius bytecode in .rbx/
7
+ ENV["RBXOPT"] = "-Xrbc.db"
8
+
9
+ require 'rake/extensiontask'
10
+ require 'rake/testtask'
11
+
12
+ begin
13
+ require 'rdoc/task'
14
+ rescue LoadError # fallback to older 1.8.7 rubies
15
+ require 'rake/rdoctask'
16
+ end
17
+
18
+ gemspec = eval(IO.read('type_array.gemspec'))
19
+
20
+ Gem::PackageTask.new(gemspec) do |pkg|
21
+ end
22
+
23
+ Rake::ExtensionTask.new('type_array', gemspec) do |ext|
24
+ ext.name = 'type_array_ext'
25
+ ext.ext_dir = 'ext/type_array'
26
+
27
+ CLEAN.include 'lib/**/type_array_ext.*'
28
+ end
29
+
30
+ desc 'Run TypeArray tests'
31
+ Rake::TestTask.new(:test) do |t|
32
+ t.test_files = Dir.glob("test/**/test_*.rb")
33
+ t.verbose = true
34
+ t.warning = true
35
+ end
36
+
37
+ Rake::RDocTask.new do |rd|
38
+ files = FileList["README.rdoc", "ext/type_array/*.c"]
39
+ rd.title = "TypeArray - Ruby implementation of the ECMAScript spec"
40
+ rd.main = "README.rdoc"
41
+ rd.rdoc_dir = "doc"
42
+ rd.options << "--promiscuous"
43
+ rd.rdoc_files.include(files)
44
+ end
45
+
46
+ task :test => :compile
47
+ task :default => :test
@@ -0,0 +1,183 @@
1
+ #include "type_array_ext.h"
2
+
3
+ /*
4
+ * :nodoc:
5
+ * An Array Buffer implementation with a simple query API for it's chunk of managed memory. The buffer is fixed and
6
+ * cannot be resized. Data View and Type Array instances manipulate the buffer directly (this may change), but none
7
+ * of that's exposed through a Ruby API.
8
+ *
9
+ */
10
+
11
+ VALUE rb_cArrayBuffer;
12
+
13
+ /*
14
+ * :nodoc:
15
+ * GC free callback
16
+ *
17
+ */
18
+ static void rb_free_array_buffer(void *ptr)
19
+ {
20
+ rb_array_buffer_t *buf = (rb_array_buffer_t *)ptr;
21
+ #ifdef TYPE_ARRAY_DEBUG
22
+ printf(">> rb_free_array_buffer %p\n", ptr);
23
+ #endif
24
+ if (buf) {
25
+ if (buf->buf) xfree(buf->buf);
26
+ xfree(buf);
27
+ buf = NULL;
28
+ }
29
+ #ifdef TYPE_ARRAY_DEBUG
30
+ printf("<< rb_free_array_buffer %p\n", ptr);
31
+ #endif
32
+ }
33
+
34
+ /*
35
+ * :nodoc:
36
+ * Utility function to allocate a new ArrayBuffer instance of given length. An optional pointer to an existing chunk
37
+ * of memory may be passed, which becomes the buffer contents. This is useful for reading raw binary data from
38
+ * standard I/O or sockets as binary strings.
39
+ *
40
+ */
41
+ VALUE rb_alloc_array_buffer(unsigned long length, void *data)
42
+ {
43
+ VALUE buffer;
44
+ rb_array_buffer_t *buf = NULL;
45
+ if (length == 0) rb_raise(rb_eRangeError, "ArrayBuffer is not a small enough positive integer");
46
+ buffer = Data_Make_Struct(rb_cArrayBuffer, rb_array_buffer_t, 0, rb_free_array_buffer, buf);
47
+ buf->length = length;
48
+ buf->buf = xcalloc(buf->length, 1);
49
+ if (!buf->buf) rb_raise(rb_eRangeError, "Unable to allocate ArrayBuffer");
50
+ if (data) memmove(buf->buf, data, length);
51
+ rb_obj_call_init(buffer, 0, NULL);
52
+ rb_obj_freeze(buffer);
53
+ return buffer;
54
+ }
55
+
56
+ /*
57
+ * :nodoc:
58
+ * Utility function to create a new ArrayBuffer instance from a begin..end byte range
59
+ *
60
+ */
61
+ static VALUE rb_copy_array_buffer(rb_array_buffer_t *source, long begin, long end)
62
+ {
63
+ long length;
64
+ void *data;
65
+ length = (end - begin);
66
+ if (length < 0) length = 0;
67
+ data = source + begin;
68
+ return rb_alloc_array_buffer(length, data);
69
+ }
70
+
71
+ /*
72
+ * call-seq:
73
+ * ArrayBuffer.new(8) => ArrayBuffer
74
+ * ArrayBuffer.new("buffer") => ArrayBuffer
75
+ *
76
+ * Creates a new ArrayBuffer instance. Both length and data (String) constructors are supported.
77
+ *
78
+ * === Examples
79
+ * buf = ArrayBuffer.new(8) => ArrayBuffer
80
+ * buf.byte_length => 8
81
+ *
82
+ * buf = ArrayBuffer.new("buffer") => ArrayBuffer
83
+ * buf.byte_length => 6
84
+ * buf.to_s => "buffer"
85
+ *
86
+ */
87
+ static VALUE rb_array_buffer_s_new(VALUE klass, VALUE obj)
88
+ {
89
+ VALUE buffer;
90
+ if (FIXNUM_P(obj)) {
91
+ buffer = rb_alloc_array_buffer(FIX2ULONG(obj), NULL);
92
+ } else if (rb_type(obj) == T_STRING) {
93
+ ArrayBufferEncode(obj);
94
+ buffer = rb_alloc_array_buffer((unsigned long)RSTRING_LEN(obj), (void *)RSTRING_PTR(obj));
95
+ } else {
96
+ rb_raise(rb_eTypeError, "ArrayBuffer constructor %s not supported.", RSTRING_PTR(rb_obj_as_string(obj)));
97
+ }
98
+ return buffer;
99
+ }
100
+
101
+ /*
102
+ * call-seq:
103
+ * buf.byte_length => Fixnum
104
+ *
105
+ * Returns the size of the buffer.
106
+ *
107
+ * === Examples
108
+ * buf = ArrayBuffer.new(8) => ArrayBuffer
109
+ * buf.byte_length => 8
110
+ *
111
+ */
112
+ static VALUE rb_array_buffer_byte_length(VALUE obj)
113
+ {
114
+ GetArrayBuffer(obj);
115
+ return ULONG2NUM(buf->length);
116
+ }
117
+
118
+ /*
119
+ * call-seq:
120
+ * buf.slice(1) => ArrayBuffer
121
+ *
122
+ * Returns a new ArrayBuffer instance with a slice (copy) of a range of memory managed by the source buffer.
123
+ *
124
+ * === Examples
125
+ * buf = ArrayBuffer.new(8) => ArrayBuffer
126
+ * buf.slice(2) => ArrayBuffer
127
+ * buf.slice(4,6) => ArrayBuffer
128
+ *
129
+ */
130
+ static VALUE rb_array_buffer_slice(int argc, VALUE *argv, VALUE obj)
131
+ {
132
+ VALUE buffer, begin, end;
133
+ long b = 0;
134
+ long e = 0;
135
+ GetArrayBuffer(obj);
136
+ rb_scan_args(argc, argv, "11", &begin, &end);
137
+ Check_Type(begin, T_FIXNUM);
138
+ b = FIX2LONG(begin);
139
+ if (NIL_P(end)) {
140
+ e = buf->length;
141
+ } else {
142
+ Check_Type(end, T_FIXNUM);
143
+ e = FIX2LONG(end);
144
+ }
145
+ if (b < 0) b = buf->length - abs(b);
146
+ if (e < 0) e = buf->length - abs(e);
147
+
148
+ if (e > buf->length) rb_raise(rb_eRangeError, "Offset out of range.");
149
+ buffer = rb_copy_array_buffer(buf, b, e);
150
+ return buffer;
151
+ }
152
+
153
+ /*
154
+ * call-seq:
155
+ * buf.to_s => String
156
+ *
157
+ * Returns a String (binary) representation of the buffer.
158
+ *
159
+ * === Examples
160
+ * buf = ArrayBuffer.new("buffer") => ArrayBuffer
161
+ * buf.byte_length => 6
162
+ * buf.to_s => "buffer"
163
+ *
164
+ */
165
+ VALUE rb_array_buffer_to_s(VALUE obj)
166
+ {
167
+ VALUE str;
168
+ GetArrayBuffer(obj);
169
+ str = rb_str_new((const char*)buf->buf, buf->length);
170
+ ArrayBufferEncode(str);
171
+ return rb_obj_freeze(str);
172
+ }
173
+
174
+ void _init_array_buffer()
175
+ {
176
+ rb_cArrayBuffer = rb_define_class("ArrayBuffer", rb_cObject);
177
+
178
+ rb_define_singleton_method(rb_cArrayBuffer, "new", rb_array_buffer_s_new, 1);
179
+
180
+ rb_define_method(rb_cArrayBuffer, "byte_length", rb_array_buffer_byte_length, 0);
181
+ rb_define_method(rb_cArrayBuffer, "slice", rb_array_buffer_slice, -1);
182
+ rb_define_method(rb_cArrayBuffer, "to_s", rb_array_buffer_to_s, 0);
183
+ }
@@ -0,0 +1,19 @@
1
+ #ifndef ARRAY_BUFFER_H
2
+ #define ARRAY_BUFFER_H
3
+
4
+ typedef struct {
5
+ unsigned long length;
6
+ void *buf;
7
+ } rb_array_buffer_t;
8
+
9
+ #define GetArrayBuffer(obj) \
10
+ rb_array_buffer_t *buf = NULL; \
11
+ Data_Get_Struct(obj, rb_array_buffer_t, buf); \
12
+ if (!buf) rb_raise(rb_eTypeError, "uninitialized ArrayBuffer!");
13
+
14
+ VALUE rb_alloc_array_buffer(unsigned long length, void *data);
15
+ VALUE rb_array_buffer_to_s(VALUE obj);
16
+
17
+ void _init_array_buffer();
18
+
19
+ #endif