TypeArray - Ruby implementation of the ECMAScript spec ( wiki.ecmascript.org/doku.php?id=strawman:typed_arrays ) <img src=“https://secure.travis-ci.org/methodmissing/type_array.png” alt=“Build Status” />

© 2012 Lourens Naudé (methodmissing)

http://github.com/methodmissing/type_array

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.

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.

Supported numeric types :

  • an unsigned-integer: one of uint8, uint16, uint32

  • a signed-integer: one of int8, int16, int32

  • a floating-point: one of float32 or float64

There’s a few different kinds of typed arrays defined :

  • Int8Array - 8-bit 2’s complement signed integer

  • UInt8Array - 8-bit unsigned integer

  • Int16Array - 16-bit 2’s complement signed integer

  • UInt16Array - 16-bit unsigned integer

  • Int32Array - 32-bit 2’s complement signed integer

  • Uint32Array - 32-bit unsigned integer

  • Float32Array - 32-bit IEEE floating point

  • Float64Array - 64-bit IEEE floating point

Type Conversion

Type         Size    Description                             Equivalent C Type    Ruby Type
--------------------------------------------------------------------------------------------------
Int8Array     1       8-bit 2's complement signed integer     signed char          Fixnum
Uint8Array    1       8-bit unsigned integer                  unsigned char        Fixnum
Int16Array    2       16-bit 2's complement signed integer    short                Fixnum
Uint16Array   2       16-bit unsigned integer                 unsigned short       Fixnum
Int32Array    4       32-bit 2's complement signed integer    int                  Fixnum / Bignum
Uint32Array   4       32-bit unsigned integer                 unsigned int         Fixnum / Bignum
Float32Array  4       32-bit IEEE floating point              float                Float
Float64Array  8       64-bit IEEE floating point              double               Float

Array Buffers

An opaque buffer with an explicit and fixed length. ArrayBuffer contents cannot be accessed directly - there’s no Ruby API exposed to manipulate it.

buf = ArrayBuffer.new(8)         =>  ArrayBuffer
buf.byte_length                  =>  8

buf = ArrayBuffer.new("buffer")  =>  ArrayBuffer
buf.byte_length                  =>  6
buf.to_s                         =>  "buffer"

Type Arrays

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.

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.

buf = ArrayBuffer.new("buffer")    =>  ArrayBuffer
ary = Int32Array.new(buf)          =>  Int32Array
ary.to_s                           =>  "buffer"

ary = Int32Array.new("01234567")   =>  Int32Array
ary[1] = 23                        =>  nil
ary[1]                             =>  23

buf = ArrayBuffer.new(100)         =>  ArrayBuffer

ary = Int32Array.new(buf, 20)      =>  Int32Array
ary.length                         =>  20
ary.byte_length                    =>  80
ary.byte_offset                    =>  20

ary = Int32Array.new(buf, 0, 20)   =>  Int32Array
ary.length                         =>  20
ary.byte_length                    =>  80
ary.byte_offset                    =>  0

ary = Int32Array.new(buf, 20, 20)  =>  Int32Array
ary.length                         =>  20
ary.byte_length                    =>  80
ary.byte_offset                    =>  20

ary = Int32Array.new("01234567")   =>  Int32Array
ary.byte_length                    =>  8
ary.to_s                           =>  "01234567"

ary = Int32Array.new(100)          =>  Int32Array
ary.length                         =>  100
ary.byte_length                    =>  400

Data Views

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.

buf = ArrayBuffer.new(100)   =>  ArrayBuffer
view = DataView.new(buf)     =>  DataView
view.set_float64(2, 77.643)  =>  nil
view.get_float64(2)          =>  758

buf = ArrayBuffer.new(100)  => ArrayBuffer
view = DataView.new(buf)    =>  DataView
view.set_uint32(2, 758)     =>  nil
view.get_uint32(2)          =>  758

buf = ArrayBuffer.new(100)  => ArrayBuffer
view = DataView.new(buf)    =>  DataView
view.set_int16(2, 20)       =>  nil
view.get_int16(2)           =>  20

Requirements

  • Known to work well on Linux, BSD variants and Mac OS X (not tested on Windows)

  • A C compiler

  • Ruby MRI 1.8 or 1.9, Rubinius or JRuby (versions 1.6 and up, C API is deprecated though)

Installation

Rubygems installation

gem install type_array

Building from source

git clone git@github.com:methodmissing/type_array.git
rake

Running tests

rake test

Todo

  • Support structs / records

  • Handle edges where coercion to and from Bignum is more appropriate

Contact, feedback and bugs

This project is still work in progress. Please log bugs and suggestions at github.com/methodmissing/type_array/issues