PDA

View Full Version : TypedArray



TheCanadian
July 28th, 2008, 11:30 PM
This may be useful for someone, maybe. I don't know. But I was bored so I made it. It's an Array that only accepts one type of data. The first argument of the constructor is the data type that the array contains, the second is a filter boolean and the rest are values to be added to the array. The filter property determines whether to throw an error if another data type is added or to remove the value.

I'll look into any errors/suggestions.


package {
dynamic public class TypedArray extends Array {
protected var pType:Class;
protected var pFilter:Boolean;
public function TypedArray(t:Class, f:Boolean = false, ... values) {
pType = t;
pFilter = f;
push.apply(this, values);
}

override AS3 function push(... values):uint {
return super.push.apply(this, values.filter(test));
}
override AS3 function splice(... values):* {
return super.splice.apply(this, values.slice(0, 2).concat(values.slice(2).filter(test)));
}
override AS3 function unshift(... values):uint {
return super.unshift.apply(this, values.filter(test));
}

public function get type():Class {
return pType;
}
public function get filter():Boolean {
return pFilter;
}

protected function test(item:*, ... values):Boolean {
if(item is pType) return true;
else if(filter) return false
else throw new TypeError("All values must be of type " + pType);
}
}
}

:hoser:

duncanhall
July 29th, 2008, 07:05 AM
Nice work, I might start using this to try and get into the habit before AS4 is upon us.

wvxvw
August 3rd, 2008, 06:47 PM
import TypedArray;
var ta = new TypedArray(String);
ta[0] = "abcd";
ta[1] = "efg";
ta.forEach(fooFunc);
function fooFunc(i:int, s:String, a:Array):void
{
a[i] = new Sprite();
}
trace(ta);
Output:

[object Sprite],efg
You have to either override all the array methods to make it work... or, I'd extend Proxy, and not Array, to make something like this...

TheCanadian
August 4th, 2008, 01:40 AM
The only problem with extending proxy is that you couldn't use TypedArray instances in functions that require an Array. On the other hand, I completely missed the fact that you can add objects with array access :lol:

I miss __resolve :(

wvxvw
August 4th, 2008, 07:16 AM
Hm... can you remind me of any built-in functions that require array as an argument? I just can't recall any at the moment...
And... don't know, I like Proxy more than __resolve =) May be than extend an array + use it as wrapper for internal class that extends Proxy? Anyway... typed arrays are meant to be faster than untyped, that's their basic purpose... but, calling dynamic properties is slower... and, another advantage should be that if you try to do something like:

typedArray[0].charAt(); if the type of Array isn't String should throw an error even before it's compiled / autocomplete it if it's String... And, I can't see a way to do it with the tools we have at hand in AS3...

dail
August 4th, 2008, 05:25 PM
Theres a nice write up and example for using Typed Arrays in the Flash Help, under "Working With Arrays" in the "Programming ActionScript 3" section. Although, I'm sure you've seen it.

TheCanadian
August 5th, 2008, 12:30 AM
Hm... can you remind me of any built-in functions that require array as an argument? I just can't recall any at the moment...
And... don't know, I like Proxy more than __resolve =) May be than extend an array + use it as wrapper for internal class that extends Proxy? Anyway... typed arrays are meant to be faster than untyped, that's their basic purpose... but, calling dynamic properties is slower... and, another advantage should be that if you try to do something like:

typedArray[0].charAt(); if the type of Array isn't String should throw an error even before it's compiled / autocomplete it if it's String... And, I can't see a way to do it with the tools we have at hand in AS3...
How about concat or ColorMatrixFilter, to name a few. And they don't have to built-in.

The only problem with Proxy is there is no way to use it and extend another class. And a TypedArray should be faster but there is no way to do that with higher level code like AS3. So TypedArray in AS3 is really just another level of type checking. We'll have to wait until Vector in FP10 for the real deal.

wvxvw
August 5th, 2008, 05:43 AM
BTW... concat doesn't require the arguments to be an array, it can accept any argumens Array.concat(...args). But, yes, ColorMatrixFilter does require. Huh... if there was something like IArray it'd make things less complicated =)

TheCanadian
August 5th, 2008, 09:44 PM
Yes but if you passed concat a TypedArray which extends Proxy, it would just add the instance rather than the contents to the new array (like it would with a regular old Array instance).

IArray would be nice. Or a better way to implement proxy.

sekasi
August 5th, 2008, 10:38 PM
Wait for FP10 for proper typed arrays ;)

Nice work nontheless Canada. Two thumbs.

Krilnon
August 6th, 2008, 12:14 AM
Wait for FP10 for proper typed arrays

They're mentioned in post #7.(-:

TheCanadian
August 6th, 2008, 12:15 AM
They're mentioned in post #7.(-:
Thanks for saying that so I didn't have to :P

Although I suppose I just did :look:

wvxvw
August 6th, 2008, 07:21 PM
Yes, I know it doesn't look totaly sane... anyhow, just another way of doing the same thing =)

PS. left sort() and sortOn() undone... actually, I'm not sure what to do with them... it seems quite useless to make a special options like Array.NUMERIC etc... but, don't know... any ideas?

package com.aditall.utils
{
import flash.utils.Proxy;
import flash.utils.flash_proxy;

/**
* ProxyArray class.
* @author wvxvw
*/
public final dynamic class ProxyArray extends Proxy
{
private var _array:Array;
private var _class:Class;

public function ProxyArray(type:Class, ...args)
{
_class = type;
if (args.length)
{
_array = [];
while (args.length) _array.push(test(args.shift()));
} else {
_array = [];
}
}

public function push(...args):void
{
while (args.length) _array.push(test(args.shift()));
}

public function unshift(...args):void
{
while (args.length) _array.push(test(args.pop()));
}

public function pop():*
{
return _array.pop();
}

public function shift():*
{
return _array.shift();
}

public function get length():int
{
return _array.length;
}

public function concat(...args):ProxyArray
{
var pArray:ProxyArray = slice();
var i:int;
var l:int = args.length;
for (i = 0; i < l; i++) pArray = proxyConcat(pArray, args[i]);
return pArray;
}

public function join(sep:*):String
{
return _array.join(sep);
}

public function lastIndexOf(searchElement:*, fromIndex:int = 0x7fffffff):int
{
return _array.lastIndexOf(searchElement, fromIndex);
}

public function indexOf(searchElement:*, fromIndex:int = 0):int
{
return _array.indexOf(searchElement, fromIndex);
}

public function forEach(callback:Function, thisObject:* = null):void
{
var i:int;
var l:int = length;
for (i = 0; i < l; i++) callback.apply(thisObject, [this[i], i, this]);
}

public function every(callback:Function, thisObject:* = null):Boolean
{
var i:int;
var l:int = length;
for (i = 0; i < l; i++)
{
if (!callback.apply(thisObject, [this[i]])) return false;
}
return true;
}

public function filter(callback:Function, thisObject:* = null):ProxyArray
{
var i:int;
var l:int = length;
var pArray:ProxyArray = new ProxyArray(_class);
for (i = 0; i < l; i++)
{
if (callback.apply(thisObject, [this[i], i, this])) pArray.push(this[i]);
}
return pArray;
}

public function map(callback:Function, thisObject:* = null):ProxyArray
{
var i:int;
var l:int = length;
var pArray:ProxyArray = new ProxyArray(_class);
for (i = 0; i < l; i++)
{
callback.apply(thisObject, [this[i], i, this]);
pArray.push(this[i]);
}
return pArray;
}

public function some(callback:Function, thisObject:* = null):Boolean
{
var i:int;
var l:int = length;
for (i = 0; i < l; i++)
{
if (callback.apply(thisObject, [this[i]])) return true;
}
return false;
}

public function sort(...args):ProxyArray
{
throw new Error("Not implemented");
return null;
}

public function sortOn(fieldName:Object, options:Object = null):ProxyArray
{
throw new Error("Not implemented");
return null;
}

public function reverse():ProxyArray
{
_array.reverse();
return this;
}

public function slice(startIndex:int = 0, endIndex:int = 16777215):ProxyArray
{
var arr:Array = _array.slice(startIndex, endIndex);
var pArray:ProxyArray = new ProxyArray(_class);
while (arr.length) pArray.push(arr.shift());
return pArray;
}

public function toString():String
{
return _array.toString();
}

public function get proxyClass():Class
{
return _class;
}

public function get proxyArray():Array
{
return _array;
}

private function test(value:*):*
{
if (value is _class) return value;
throw new Error("Type mismatch, " + typeof(value) + " should be " + _class);
}

private function proxyConcat(proxyArray:ProxyArray, value:*):*
{
if (value is ProxyArray)
{
if (ProxyArray(value).proxyClass == _class)
{
while (ProxyArray(value).length) proxyArray.push(ProxyArray(value).shift());
} else {
throw new Error("Type mismatch, " + ProxyArray(value).proxyClass + " should be " + _class);
}
return proxyArray;
}
proxyArray.push(test(value));
return proxyArray;
}

flash_proxy override function callProperty(name:*, ...args):*
{
return undefined;
}

flash_proxy override function setProperty(name:*, value:*):void
{
if (int(name) != name) throw new Error("Acces of undefined property: " + name);
_array[name] = test(value);
}

flash_proxy override function getProperty(name:*):*
{
if (int(name) != name) throw new Error("Acces of undefined property: " + name);
return _array[name];
}

flash_proxy override function nextName(index:int):String
{
return _array[index - 1];
}

flash_proxy override function nextNameIndex(index:int):int
{
if (index < _array.length) return index + 1;
return 0;
}

flash_proxy override function nextValue(index:int):*
{
return _array[index - 1];
}
}

}

TheCanadian
August 6th, 2008, 09:08 PM
Nice, now it just depends on which functionality you need of the two :thumb: Technically I should make my class non-dynamic and use a getIndex function to access properties to deal with aformentioned issues. Maybe later :run: