AS3 | ArrayCollection


/ Published in: ActionScript 3
Save to your folder(s)



Copy this code and paste it in your HTML
  1. package kc.tda {
  2. import kc.api.ICollection;
  3. import kc.api.IIterator;
  4. import kc.events.CollectionEvent;
  5.  
  6. import flash.errors.IllegalOperationError;
  7. import flash.events.EventDispatcher;
  8.  
  9. [Event( name="add", type="kc.events.CollectionEvent" )]
  10. [Event( name="addAll", type="kc.events.CollectionEvent" )]
  11. [Event( name="clear", type="kc.events.CollectionEvent" )]
  12. [Event( name="remove", type="kc.events.CollectionEvent" )]
  13. [Event( name="removeAll", type="kc.events.CollectionEvent" )]
  14. [Event( name="retain", type="kc.events.CollectionEvent" )]
  15.  
  16. public class ArrayCollection extends EventDispatcher implements ICollection {
  17.  
  18. // @const
  19.  
  20. public static const DEFAULT_CAPACITY:int = 1 << 5;
  21. public static const DEFAULT_MIN_CAPACITY:int = 1 << 4;
  22. public static const DEFAULT_MAX_CAPACITY:int = 1 << 30;
  23.  
  24. public static const DEFAULT_LOAD_FACTOR:Number = .75;
  25. public static const DEFAULT_MIN_LOAD_FACTOR:Number = 0;
  26. public static const DEFAULT_MAX_LOAD_FACTOR:Number = 1;
  27.  
  28. public static const NOT_FOUND:int = -1;
  29. public static const MAX_DISPATCH_EVENTS:int = 255;
  30.  
  31. // @protected
  32.  
  33. protected var _records:Array;
  34. protected var _capacity:int;
  35. protected var _events:Array;
  36.  
  37. protected var _expandableCapacity:Boolean;
  38. protected var _loadFactor:Number;
  39. protected var _maxCapacity:int;
  40. protected var _enableEvents:int;
  41.  
  42. // @Cconstructor
  43.  
  44. public function ArrayCollection( capacity:int = undefined, expandableCapacity:Boolean = false, loadFactor:Number = NaN ) {
  45.  
  46. super(this);
  47.  
  48. _events = [
  49. CollectionEvent.ADD,
  50. CollectionEvent.ADD_ALL,
  51. CollectionEvent.CLEAR,
  52. CollectionEvent.REMOVE,
  53. CollectionEvent.REMOVE_ALL,
  54. CollectionEvent.RETAIN
  55. ];
  56.  
  57. _capacity = ResolveLimits (
  58. capacity,
  59. DEFAULT_MIN_CAPACITY,
  60. DEFAULT_MAX_CAPACITY,
  61. DEFAULT_CAPACITY
  62. );
  63.  
  64. this.loadFactor = loadFactor;
  65. this.expandableCapacity = expandableCapacity;
  66. clear();
  67.  
  68. }
  69.  
  70. // @override
  71.  
  72. override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void {
  73. ThrowEventsFilter( type );
  74. super.addEventListener( type, listener, useCapture, priority, useWeakReference );
  75. }
  76.  
  77. // @properties (rw)
  78.  
  79. public function get eventsReleased():int {
  80. return _enableEvents;
  81. }
  82.  
  83. public function get enableEvents():Boolean {
  84. return ( _enableEvents > NOT_FOUND );
  85. }
  86.  
  87. public function set enableEvents( value:Boolean ):void {
  88. _enableEvents = ( ! value )
  89. ? NOT_FOUND
  90. : 0;
  91. }
  92.  
  93. public function get expandableCapacity():Boolean {
  94. return _expandableCapacity;
  95. }
  96.  
  97. public function set expandableCapacity( value:Boolean ):void {
  98. _expandableCapacity = value;
  99. }
  100.  
  101. public function get loadFactor():Number {
  102. return _loadFactor;
  103. }
  104.  
  105. public function set loadFactor( value:Number ):void {
  106. _loadFactor = ResolveLimits (
  107. value,
  108. DEFAULT_MIN_LOAD_FACTOR,
  109. DEFAULT_MAX_LOAD_FACTOR,
  110. DEFAULT_LOAD_FACTOR
  111. );
  112. }
  113.  
  114. // @methods
  115.  
  116. public function add( value:* ):Boolean {
  117.  
  118. if( ! ResolveStatus() ) {
  119. return false;
  120. }
  121.  
  122. var quantity:int = size();
  123. _records.push( value );
  124.  
  125. if( size() != quantity ){
  126. ResolveDispatchEvent( CollectionEvent.ADD );
  127. return true;
  128. } return false;
  129.  
  130. }
  131.  
  132. public function addAll( value:ICollection ):Boolean {
  133.  
  134. var i:IIterator = value.iterator();
  135. var quantity:int = size();
  136.  
  137. enableEvents = false;
  138.  
  139. while( i.hasNext() ){
  140. add( i.next() );
  141. }
  142.  
  143. enableEvents = true;
  144.  
  145. if( size() != quantity ){
  146. ResolveDispatchEvent( CollectionEvent.ADD_ALL );
  147. return true;
  148. } return false;
  149.  
  150. }
  151.  
  152. public function availableCapacity():int {
  153. return ( _maxCapacity - size() );
  154. }
  155.  
  156. public function capacity():int {
  157. return _maxCapacity;
  158. }
  159.  
  160. public function clear():void {
  161.  
  162. if( _records != null ) {
  163. ResolveDispatchEvent( CollectionEvent.CLEAR );
  164. }
  165.  
  166. _records = new Array();
  167. _maxCapacity = _capacity;
  168.  
  169. }
  170.  
  171. public function compare( value1:*, value2:* ):int {
  172. ThrowMethodIsNotAvailable( "compare" );
  173. return NOT_FOUND;
  174. }
  175.  
  176. public function compareTo( value:* ):int {
  177. ThrowIsNotCollection( value );
  178. if( size() > value.size() ) return 1;
  179. else if( size() < value.size() ) return -1;
  180. else return 0;
  181. }
  182.  
  183. public function contains( value:* ):int {
  184. return _records.indexOf( value );
  185. }
  186.  
  187. public function containsAll( value:ICollection ):Boolean {
  188. var i:IIterator = value.iterator();
  189. while( i.hasNext() ){
  190. if( contains( i.next() ) == NOT_FOUND ) {
  191. return false;
  192. }
  193. } return true;
  194. }
  195.  
  196. public function copy():ICollection {
  197. var collection:ArrayCollection = new ArrayCollection( _capacity, _expandableCapacity, _loadFactor );
  198. collection.addAll( this );
  199. return collection;
  200. }
  201.  
  202. public function equals( value:* ):Boolean {
  203. return ( this == value );
  204. }
  205.  
  206. public function isEmpty():Boolean {
  207. return ( size() == 0 );
  208. }
  209.  
  210. public function iteratorWithCopy():IIterator {
  211. return new ArrayIterator( toArray() );
  212. }
  213.  
  214. public function iterator():IIterator {
  215. return new ArrayIterator( _records );
  216. }
  217.  
  218. public function remove( value:* ):Boolean {
  219. ThrowIsEmpty();
  220. var index:int = contains( value );
  221. if( index != NOT_FOUND ) {
  222. if( _records.splice( index, 1 ).length ){
  223. ResolveDispatchEvent( CollectionEvent.REMOVE );
  224. return true;
  225. }
  226. } return false;
  227. }
  228.  
  229. public function removeAll( value:ICollection ):Boolean {
  230.  
  231. var i:IIterator = value.iterator();
  232. var quantity:int = size();
  233.  
  234. enableEvents = false;
  235.  
  236. while( i.hasNext() ){
  237. remove( i.next() );
  238. }
  239.  
  240. enableEvents = true;
  241.  
  242. if( size() != quantity ){
  243. ResolveDispatchEvent( CollectionEvent.REMOVE_ALL );
  244. return true;
  245. } return false;
  246.  
  247. }
  248.  
  249. public function retainAll( value:ICollection ):Boolean {
  250.  
  251. var i:IIterator = iterator();
  252. var quantity:int = size();
  253.  
  254. enableEvents = false;
  255.  
  256. while( i.hasNext() ){
  257. if( value.contains( i.next() ) == NOT_FOUND ) {
  258. i.remove();
  259. }
  260. }
  261.  
  262. enableEvents = true;
  263.  
  264. if( size() != quantity ){
  265. ResolveDispatchEvent( CollectionEvent.RETAIN );
  266. return true;
  267. } return false;
  268.  
  269. }
  270.  
  271. public function size():uint {
  272. return _records.length;
  273. }
  274.  
  275. public function toArray():Array {
  276. return _records.slice();
  277. }
  278.  
  279. public function threshold():int {
  280. return ( _maxCapacity * _loadFactor );
  281. }
  282.  
  283. // @purge
  284.  
  285. public function purge(...rest):void {
  286. _records = null;
  287. _events = null;
  288. _capacity = undefined;
  289. _expandableCapacity = undefined;
  290. _loadFactor = undefined;
  291. _maxCapacity = undefined;
  292. _enableEvents = undefined;
  293. }
  294.  
  295. // @helpres
  296.  
  297. protected function ResolveDispatchEvent( value:String ):void {
  298. if( ! enableEvents || _enableEvents == MAX_DISPATCH_EVENTS ) {
  299. enableEvents = false;
  300. return;
  301. }else if( dispatchEvent( new CollectionEvent( value ) ) ) {
  302. _enableEvents++;
  303. }
  304. }
  305.  
  306. protected function ResolveLimits( value:Number, min:Number, max:Number, def:Number = undefined ):Number {
  307. return Math.min ( max, Math.max ( min, value ) ) || def;
  308. }
  309.  
  310. protected function ResolveLimitsAndCapacity( value:Number, min:Number, max:Number, def:Number = undefined ):Number {
  311. return ResolveCapacity (
  312. ResolveLimits( value, min, max, def )
  313. );
  314. }
  315.  
  316. protected function ResolveCapacity( value:int ):int {
  317. if ( ! ( value > 0 && ( ( value & ( value - 1 ) ) == 0 ) ) ) {
  318. var capacity:int = 1;
  319. while( capacity < value ) {
  320. capacity <<= 1;
  321. } return capacity;
  322. } return value;
  323. }
  324.  
  325. protected function ResolveStatus():Boolean {
  326. if( ! _expandableCapacity && availableCapacity() == 0 ) {
  327. return false;
  328. } ResolveResize();
  329. return true;
  330. }
  331.  
  332. protected function ResolveResize():void {
  333. if( _expandableCapacity && size() == threshold() ) {
  334. _maxCapacity += capacity();
  335. }
  336. }
  337.  
  338. protected function ThrowIsNotExpandibled( type:String = "collection" ):void {
  339. if( ! _expandableCapacity ) {
  340. throw new IllegalOperationError("The \"" + type + "\" is not expandibled.");
  341. }
  342. }
  343.  
  344. protected function ThrowIsNotCollection( value:*, param:String = "value" ):void {
  345. if( ! value is ICollection ) {
  346. throw new IllegalOperationError("The \"" + param + "\" is not an ICollection.");
  347. }
  348. }
  349.  
  350. protected function ThrowIsEmpty( type:String = "collection" ):void {
  351. if ( isEmpty() ) {
  352. throw new IllegalOperationError( "The " + type + " is empty." );
  353. }
  354. }
  355.  
  356. protected function ThrowMethodIsNotAvailable( value:String, replace:String = null ):void {
  357. var error:String = "The \"" + value + "\" method is not available.";
  358. if ( replace != null ) {
  359. error = error.substr( 0, -1 ) + ", use the \"" + replace + "\" method.";
  360. } throw new IllegalOperationError( error );
  361. }
  362.  
  363. protected function ThrowEventsFilter( value:String, list:Array = null ):void {
  364. if( ! enableEvents ){
  365. throw new IllegalOperationError( "The events are not available." );
  366. } if( list == null ) {
  367. list = _events;
  368. } if( list.indexOf( value ) == NOT_FOUND ) {
  369. throw new IllegalOperationError( "The event \"" + value + "\" is not available." );
  370. }
  371. }
  372.  
  373. }
  374.  
  375. }
  376.  
  377. // @INTERFACES
  378.  
  379. package kc.api {
  380. import flash.events.IEventDispatcher;
  381.  
  382. public interface ICollection extends IEventDispatcher, IIterable, IComparable, IComparator, IPurger {
  383.  
  384. // @properties (rw)
  385.  
  386. function get enableEvents():Boolean;
  387. function set enableEvents( value:Boolean ):void;
  388. function get expandableCapacity():Boolean;
  389. function set expandableCapacity( value:Boolean ):void;
  390. function get loadFactor():Number;
  391. function set loadFactor( value:Number ):void;
  392.  
  393. // @properties (r)
  394.  
  395. function get eventsReleased():int;
  396.  
  397. // @methods
  398.  
  399. function add( value:* ):Boolean;
  400. function addAll( value:ICollection ):Boolean;
  401. function availableCapacity():int;
  402. function capacity():int;
  403. function clear():void;
  404. function contains( value:* ):int;
  405. function containsAll( value:ICollection ):Boolean;
  406. function copy():ICollection;
  407. function isEmpty():Boolean;
  408. function remove( value:* ):Boolean;
  409. function removeAll( value:ICollection ):Boolean;
  410. function retainAll( value:ICollection ):Boolean;
  411. function size():uint;
  412. function toArray():Array;
  413. function threshold():int;
  414.  
  415. }
  416.  
  417. }
  418.  
  419. package kc.api {
  420.  
  421. public interface IComparable {
  422.  
  423. // @methods
  424.  
  425. function compareTo( value:* ):int;
  426.  
  427. }
  428.  
  429. }
  430.  
  431. package kc.api {
  432.  
  433. public interface IComparator {
  434.  
  435. // @methods
  436.  
  437. function compare( value1:*, value2:* ):int;
  438. function equals( value:* ):Boolean;
  439.  
  440. }
  441.  
  442. }
  443.  
  444. package kc.api {
  445.  
  446. public interface IIterable {
  447.  
  448. // @methods
  449.  
  450. function iterator():IIterator;
  451.  
  452. }
  453.  
  454. }
  455.  
  456. package kc.api {
  457.  
  458. public interface IIterator {
  459.  
  460. // @methods
  461.  
  462. function hasNext():Boolean;
  463. function next():*;
  464. function remove():void;
  465. function index():int;
  466. function value():*;
  467. function size():int;
  468.  
  469. }
  470.  
  471. }
  472.  
  473. // @EVENTS
  474.  
  475. package kc.events {
  476. import flash.events.Event;
  477.  
  478. public class CollectionEvent extends Event {
  479.  
  480. // @const
  481.  
  482. public static const ADD:String = "add";
  483. public static const ADD_ALL:String = "addAll";
  484. public static const REMOVE:String = "remove";
  485. public static const REMOVE_ALL:String = "removeAll";
  486. public static const RETAIN:String = "retain";
  487. public static const CLEAR:String = "clear";
  488.  
  489. // @queue
  490.  
  491. public static const ENQUEUE:String = "enqueue";
  492. public static const DEQUEUE:String = "dequeue";
  493.  
  494. // @stack
  495.  
  496. public static const PUSH:String = "push";
  497. public static const POP:String = "pop";
  498.  
  499. // @history
  500.  
  501. public static const INDEX_CHANGE:String = "indexChange";
  502.  
  503. // @constructor
  504.  
  505. public function CollectionEvent( type:String, bubbles:Boolean=false, cancelable:Boolean=false ) {
  506. super( type, bubbles, cancelable );
  507. }
  508.  
  509. // @override
  510.  
  511. override public function clone():Event {
  512. return new CollectionEvent( this.type, this.bubbles, this.cancelable );
  513. }
  514.  
  515. override public function toString():String {
  516. return this.formatToString( "CollectionEvent", "type", "bubbles", "cancelable", "eventPhase" );
  517. }
  518.  
  519. }
  520.  
  521. }

URL: http://www.kirikacode.com

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.