diff options
author | Chouser <chouser@n01se.net> | 2008-09-12 04:08:22 +0000 |
---|---|---|
committer | Chouser <chouser@n01se.net> | 2008-09-12 04:08:22 +0000 |
commit | 5d0db072443c34f3dbd45ae077260e270f53a65a (patch) | |
tree | 12b0bb13e6195aca0939f5add197555217c14ed0 /clojurescript/PersistentVector-proto.js | |
parent | 0b0f94bc8258a31490092928b547614dcf25f722 (diff) |
Initial preliminary checkin of ClojureScript -- very incomplete.
Diffstat (limited to 'clojurescript/PersistentVector-proto.js')
-rw-r--r-- | clojurescript/PersistentVector-proto.js | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/clojurescript/PersistentVector-proto.js b/clojurescript/PersistentVector-proto.js new file mode 100644 index 00000000..cbfdbee4 --- /dev/null +++ b/clojurescript/PersistentVector-proto.js @@ -0,0 +1,189 @@ +RT = { EMPTY_ARRAY: [] }; + +function APersistentVector( _meta ) { + this._meta = _meta; +} + +APersistentVector.prototype.meta = function() { + return this._meta; +}; + +APersistentVector.prototype.peek = function() { + if( this.count() > 0 ) { + return this.nth( this.count() - 1 ); + } + return null; +}; + +function PersistentVector( _meta, cnt, shift, root, tail ) { + APersistentVector.call( this, _meta ); + this._meta = _meta; + this.cnt = cnt; + this.shift = shift; + this.root = root; + this.tail = tail; +} + +PersistentVector.prototype = new APersistentVector( null ); +PersistentVector.contraction = PersistentVector; + +PersistentVector.prototype.tailoff = function() { + return this.cnt - this.tail.length; +}; + +PersistentVector.prototype.nth = function( i ) { + if( i >= 0 && i < this.cnt ) { + if( i >= this.tailoff() ) { + return this.tail[ i & 0x01f ]; + } + var arr = this.root; + for( var level = this.shift; level > 0; level -= 5 ) { + arr = arr[ (i >>> level) & 0x01f ]; + } + return arr[ i & 0x01f ]; + } + throw "IndexOutOfBoundsException"; +}; + +PersistentVector.prototype.assocN = function( i, val ) { + if( i >= 0 && i < this.cnt ) { + if( i >= this.tailoff() ) { + var newTail = this.tail.slice( 0 ); + newTail[ i & 0x01f ] = val; + return new PersistentVector( + this.meta(), this.cnt, this.shift, this.root, newTail ); + } + return new PersistentVector( + this.meta(), this.cnt, this.shift, + this.doAssoc( this.shift, this.root, i, val), this.tail ); + } + if( i == this.cnt ) { + return this.cons( val ); + } + throw "IndexOutOfBoundsException"; +}; + +PersistentVector.prototype.doAssoc = function( level, arr, i, val ) { + var ret = arr.slice( 0 ); + if( level == 0 ) { + ret[ i & 0x01f ] = val; + } + else { + var subidx = (i >>> level) & 0x01f; + ret[ subidx ] = this.doAssoc( level - 5, arr[ subidx ], i, val ); + } + return ret; +}; + +PersistentVector.prototype.count = function() { + return this.cnt; +}; + +PersistentVector.prototype.withMeta = function( _meta ) { + return new PersistentVector( + _meta, this.cnt, this.shift, this.root, this.tail ); +}; + +PersistentVector.prototype.cons = function( val ) { + if( this.tail.length < 32 ) { + var newTail = this.tail.concat( [val] ); + return new PersistentVector( + this.meta(), this.cnt + 1, this.shift, this.root, newTail ); + } + var expansion = [null]; + var newroot = this.pushTail( this.shift - 5, this.root, this.tail, expansion); + var newshift = this.shift; + if( expansion[0] != null ) { + newroot = [newroot, expansion[0]]; + newshift += 5; + } + return new PersistentVector( + this.meta(), this.cnt+1, newshift, newroot, [val] ); +}; + +PersistentVector.prototype.empty = function() { + return PersistentVector.EMPTY.withMeta( this.meta() ); +}; + +PersistentVector.prototype.pushTail = function( level, arr, tailNode, expansion) +{ + var newchild; + if( level == 0 ) { + newchild = tailNode; + } + else { + newchild = this.pushTail( + level - 5, arr[arr.length - 1], tailNode, expansion); + if( expansion[0] == null ) { + var ret = arr.slice( 0 ); + ret[ arr.length - 1 ] = newchild; + return ret; + } + else { + newchild = expansion[0]; + } + } + //expansion + if( arr.length == 32 ) { + expansion[0] = [newchild]; + return arr; + } + expansion[0] = null; + return arr.concat([newchild]); +}; + +PersistentVector.prototype.pop = function() { + if( this.cnt == 0 ) { + throw "IllegalStateException: Can't pop empty vector"; + } + if( this.cnt == 1 ) { + return PersistentVector.EMPTY.withMeta( this.meta() ); + } + if( this.tail.length > 1 ) { + var newTail = this.tail.slice( 0, this.tail.length - 1 ); + return new PersistentVector( + this.meta(), this.cnt - 1, this.shift, this.root, newTail ); + } + var ptail = [null]; + var newroot = this.popTail( this.shift - 5, this.root, ptail ); + var newshift = this.shift; + if( newroot == null ) { + newroot = RT.EMPTY_ARRAY; + } + if( this.shift > 5 && newroot.length == 1 ) { + newroot = newroot[0]; + newshift -= 5; + } + return new PersistentVector( + this.meta(), this.cnt - 1, newshift, newroot, ptail[0] ); +}; + +PersistentVector.prototype.popTail = function( shift, arr, ptail ) { + if( shift > 0 ) { + var newchild = this.popTail( shift - 5, arr[ arr.length - 1 ], ptail ); + if( newchild != null ) { + var ret = arr.slice( 0 ); + ret[ arr.length - 1 ] = newchild; + return ret; + } + } + if( shift == 0 ) { + ptail[0] = arr[ arr.length - 1 ]; + } + //contraction + if( arr.length == 1 ) { + return null; + } + return arr.slice( 0, arr.length - 1 ); +}; + +PersistentVector.EMPTY = new PersistentVector( + {}, 0, 5, RT.EMPTY_ARRAY, RT.EMPTY_ARRAY ); + +PersistentVector.create = function( items ) { + var ret = PersistentVector.EMPTY; + for( var i = 0; i < items.length; ++i ) { + ret = ret.cons( items[ i ] ); + } + return ret; +} |