Created
June 5, 2009 19:08
-
-
Save hdon/124442 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'#!/usr/bin/gsr -zzdd' | |
/* A pure Javascript reference implementation of ServerJS's binary ByteArray | |
* class for reference, implementation, and testing purposes. | |
* | |
* For more info see: https://wiki.mozilla.org/ServerJS/Binary/B | |
*/ | |
/* Do we have modules? */ | |
if (('function' == typeof require) && require("binary")) { | |
print("using require('binary') for ByteString"); | |
var ByteString = require("binary").ByteString; | |
} else { | |
/* TODO invent a pure Javascript ByteString class */ | |
print("defining dummy ByteString"); | |
var ByteString = function(){}; | |
} | |
const ByteArray = function() { | |
/* Private methods */ | |
/** ByteArray.validate(value) | |
* @name ByteArray.validate | |
* @param value | |
* @function | |
* @private | |
* @throws ByteArray.ValueError | |
* | |
* Throws an exception if the argument is not a valid byte value. | |
*/ | |
function validate(v) { | |
if ('number' !== typeof v) | |
throw 'number expected :('; | |
if ((v < 0) || (v > 255)) | |
throw 'value out of range error :('; | |
} | |
/** ByteArray.checkIndex(index) | |
* @name ByteArray.checkIndex | |
* @param index | |
* @function | |
* @private | |
* @throws ByteArray.TypeError | |
* @throws ByteArray.IndexError | |
* | |
* Returns true is the argument is greater than zero but less than the length | |
* of this ByteArray. | |
*/ | |
function checkIndex(i) { | |
if ('number' !== typeof i) | |
throw 'number expected :('; | |
if (0 > i || i >= this.length) | |
throw 'index out of bounds :('; | |
} | |
/** ByteArray.set(index, value) | |
* @name ByteArray.set | |
* @param index | |
* @param value | |
* @function | |
* @private | |
* @throws ByteArray.ValueError | |
* @throws ByteArray.TypeError | |
* @throws ByteArray.IndexError | |
* | |
* Sets member 'index' to 'value'. | |
*/ | |
function set(i, v) { | |
validate(v); | |
checkIndex.call(this, i); | |
this.store[i] = v; | |
} | |
/** ByteArray.grow(length) | |
* @name ByteArray.grow | |
* @param length | |
* @function | |
* | |
* Increases the size of internal byte store. This function *must* be called | |
* to put getters and setters in place, due to a limitation that getters and | |
* setters must be installed individually, and it would be inefficient to | |
* install them all ahead of time for every possible integer :) | |
*/ | |
function grow (length) { | |
while (this.store.length < length) { | |
/* TODO lots of room for improvement... */ | |
var index = this.store.length; | |
this.store.push(0); | |
// ugh! closures! wtf! | |
eval(('this.__defineGetter__(index, function(){return this.store[index]});' + | |
'this.__defineSetter__(index, function(v){set.call(this, index, v)});'). | |
replace(/index/g, index.toString())); | |
} | |
this.length = length; | |
} | |
/* Public methods */ | |
/* Constructor */ | |
function ByteArray(arg) { | |
this.store = new Array(); | |
/** ByteArray(string, charset) | |
* @name ByteArray | |
* @param string Initialization data | |
* @param charset The characterset in which to interpret the | |
* values of the initialization data. | |
* @function | |
* @public | |
* @constructor | |
* @throws ByteArray.InvalidConstructorArguments | |
* | |
* Returns a ByteArray of 'length' bytes each initialized to 0. | |
*/ | |
if (arguments.length == 2) | |
throw 'unimplemented! :('; | |
if (arguments.length != 1) | |
throw 'invalid constructor arguments! :('; | |
/** ByteArray(length) | |
* @name ByteArray | |
* @param length | |
* @function | |
* @public | |
* @constructor | |
* | |
* Returns a ByteArray of 'length' bytes each initialized to 0. | |
*/ | |
if ('number' == typeof arg) { | |
grow.call(this, arg); | |
return; | |
} | |
/** ByteArray(bytes:Array|ByteArray|ByteString) | |
* @name ByteArray | |
* @param bytes Initialization data | |
* @function | |
* @public | |
* @constructor | |
* | |
* Returns a ByteArray of initialized with bytes taken from the 'bytes' | |
* argument. | |
*/ | |
if ((arg instanceof Array) || (arg instanceof ByteString) || (arg instanceof ByteArray)) { | |
grow.call(this, arg.length); | |
for(var i=0, l=arg.length; i<l; i++) | |
set.call(this, i, arg[i]); | |
return; | |
} | |
throw 'invalid constructor arguments! :('; | |
} | |
/** ByteArray.toString() | |
* @name ByteArray.toString | |
* @function | |
* @public | |
* | |
* Returns a friendly-looking string representation of the ByteArray instance. | |
*/ | |
ByteArray.prototype.toString = function() { | |
return "[ByteArray "+this.length+"]"; | |
} | |
/** ByteArray.toArray() | |
* @name ByteArray.toArray | |
* @param charset Character set with which to interpret byte data. | |
* @function | |
* @public | |
* | |
* Returns a new array of values taken from this ByteArray. | |
*/ | |
ByteArray.prototype.toArray = function(charset) { | |
if (charset) throw 'unimplemented! :('; | |
return this.store.map(function(v)v); | |
} | |
/** ByteArray.decodeToString() | |
* @name ByteArray.decodeToString | |
* @param charset Character set with which to interpret byte data. | |
* @function | |
* @public | |
* | |
* Returns a nwe string with each character in the string constituted from one byte | |
* of data from this ByteArray. | |
*/ | |
ByteArray.prototype.decodeToString = function(charset) { | |
if (charset) throw 'unimplemented! :('; | |
return this.store.map(function(c)String.fromCharCode(c)).join(''); | |
} | |
/** ByteArray.toSource() | |
* @name ByteArray.toSource | |
* @function | |
* @public | |
* | |
* Returns a string of executable Javascript source code which can be used to | |
* instantiate an exact copy of this ByteArray instance. | |
*/ | |
ByteArray.prototype.toString = function() { | |
return "(new ByteArray(["+(this.store.join(','))+"]))"; | |
} | |
/** ByteArray.forEach(callback) | |
* @name ByteArray.forEach | |
* @param value | |
* @function | |
* @public | |
* | |
* Calling this function is equivalent to calling "callback(a[n], n, a)" where | |
* 'a' is this instance of ByteArray, 'a[n]' is the nth member of this ByteArray, | |
* and 'callback' is the argument to forEach(). | |
*/ | |
ByteArray.prototype.forEach = function(f) { | |
this.store.forEach(f); | |
} | |
/** ByteArray.push(value) | |
* @name ByteArray.push | |
* @param value | |
* @function | |
* @public | |
* | |
* This extends the contents of this ByteArray instance by appending 'value' to | |
* the end of its contents. | |
*/ | |
ByteArray.prototype.push = function(v) { | |
validate(v); | |
this.store.push(v); | |
this.length++; | |
} | |
/** ByteArray.every(callback) | |
* @name ByteArray.every | |
* @param callback | |
* @function | |
* @public | |
* | |
* Returns true if every element in this ByteArray satisfies the provided testing function. | |
*/ | |
ByteArray.prototype.every = function(f) { | |
return this.store.every(function(v,i)f(v,i,this)); | |
} | |
/** ByteArray.some(callback) | |
* @name ByteArray.some | |
* @param callback | |
* @function | |
* @public | |
* | |
* Returns true if at least one element in this ByteArray satisfies the provided testing function. | |
*/ | |
ByteArray.prototype.some = function(f) { | |
return this.store.some(function(v,i)f(v,i,this)); | |
} | |
/** ByteArray.filter(callback) | |
* @name ByteArray.filter | |
* @param callback | |
* @function | |
* @public | |
* | |
* Returns a new array with the results of calling a provided function on every element in this | |
* ByteArray. | |
* | |
* TODO Option for a binary-descended result | |
*/ | |
ByteArray.prototype.filter = function(f) { | |
return this.store.filter(function(v,i)f(v,i,this)); | |
} | |
/** ByteArray.map(callback) | |
* @name ByteArray.map | |
* @param callback | |
* @function | |
* @public | |
* | |
* Returns a new array with the results of calling a provided function on every element in this | |
* ByteArray. | |
* | |
* TODO Option for a binary-descended result | |
*/ | |
ByteArray.prototype.map = function(f) { | |
return this.store.map(function(v,i)f(v,i,this)); | |
} | |
/** ByteArray.reduce(callback) | |
* @name ByteArray.reduce | |
* @param callback | |
* @function | |
* @public | |
* | |
* Apply a function simultaneously against two values of this ByteArray (from left-to-right) as | |
* to reduce it to a single value. | |
*/ | |
ByteArray.prototype.reduce = function(f) { | |
return this.store.reduce(function(a,b,i)f(a,b,i,this)); | |
} | |
/** ByteArray.reduceRight(callback) | |
* @name ByteArray.reduceRight | |
* @param callback | |
* @function | |
* @public | |
* | |
* Apply a function simultaneously against two values of this ByteArray (from right-to-left) as | |
* to reduce it to a single value. | |
*/ | |
ByteArray.prototype.reduceRight = function(f) { | |
return this.store.reduceRight(function(a,b,i)f(a,b,i,this)); | |
} | |
/* Return new class :) */ | |
return ByteArray; | |
}(); | |
/* Tests! */ | |
var ba = new ByteArray(8); | |
for(var i=0; i<8; i++) { | |
ba[i] = i | 128; | |
} | |
for(var i=0; i<8; i++) { | |
print(ba[i]); | |
} | |
print(ba.every(function(n) n&128) === true); | |
print(ba.some(function(n) n&1) === true); | |
print(ba.some(function(n) n&8) === false); | |
print(new ByteArray(ba).every(function(n) n&128) === true); | |
print(new ByteArray([72,101,108,108,111,32,87,111,114,108,100,33]).decodeToString() === 'Hello World!'); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment