/src/sys/js/fan/List.js
JavaScript | 1035 lines | 849 code | 109 blank | 77 comment | 297 complexity | 21e6b710e9ce57996a6c52e859a99c50 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
- //
- // Copyright (c) 2009, Brian Frank and Andy Frank
- // Licensed under the Academic Free License version 3.0
- //
- // History:
- // 12 Jan 09 Andy Frank Creation
- // 20 May 09 Andy Frank Refactor to new OO model
- // 3 Dec 09 Andy Frank Wrap Array object
- //
- /**
- * List
- */
- fan.sys.List = fan.sys.Obj.$extend(fan.sys.Obj);
- //////////////////////////////////////////////////////////////////////////
- // Constructors
- //////////////////////////////////////////////////////////////////////////
- fan.sys.List.make = function(of, values)
- {
- if (of == null) throw fan.sys.NullErr();
- if (values === undefined || typeof(values) == "number") values = [];
- var self = new fan.sys.List();
- self.m_of = of;
- self.m_size = values.length;
- self.m_values = values;
- self.m_readonly = false;
- self.m_immutable = false;
- return self;
- }
- fan.sys.List.makeObj = function(capacity)
- {
- return fan.sys.List.make(fan.sys.Obj.$type);
- }
- fan.sys.List.prototype.$ctor = function()
- {
- }
- //////////////////////////////////////////////////////////////////////////
- // Identity
- //////////////////////////////////////////////////////////////////////////
- fan.sys.List.prototype.$typeof = function() { return this.m_of.toListOf(); }
- fan.sys.List.prototype.of = function() { return this.m_of; }
- fan.sys.List.prototype.isEmpty = function() { return this.m_size == 0; }
- fan.sys.List.prototype.size = function() { return this.m_size; }
- fan.sys.List.prototype.size$ = function(val)
- {
- this.modify();
- var oldSize = this.m_size;
- var newSize = val;
- for (var i=0; this.m_size+i<newSize; i++)
- this.m_values.push(null);
- this.m_size = newSize;
- }
- fan.sys.List.prototype.capacity = function() { return this.m_values.length; }
- fan.sys.List.prototype.capacity$ = function(val)
- {
- this.modify();
- if (val < this.m_size) throw fan.sys.ArgErr.make("capacity < size");
- // noop
- }
- fan.sys.List.prototype.get = function(index)
- {
- if (index < 0) index = this.m_size + index;
- if (index >= this.m_size || index < 0) throw fan.sys.IndexErr.make(index);
- return this.m_values[index];
- }
- fan.sys.List.prototype.getSafe = function(index, def)
- {
- if (def === undefined) def = null;
- if (index < 0) index = this.m_size + index;
- if (index >= this.m_size || index < 0) return def;
- return this.m_values[index];
- }
- fan.sys.List.prototype.getRange = function(range)
- {
- var s = range.$start(this.m_size);
- var e = range.$end(this.m_size);
- if (e+1 < s || s < 0) throw fan.sys.IndexErr.make(range);
- return fan.sys.List.make(this.m_of, this.m_values.slice(s, e+1));
- }
- fan.sys.List.prototype.contains = function(value)
- {
- return this.index(value) != null;
- }
- fan.sys.List.prototype.containsAll = function(list)
- {
- for (var i=0; i<list.size(); ++i)
- if (this.index(list.get(i)) == null)
- return false;
- return true;
- }
- fan.sys.List.prototype.containsAny = function(list)
- {
- for (var i=0; i<list.size(); ++i)
- if (this.index(list.get(i)) != null)
- return true;
- return false;
- }
- fan.sys.List.prototype.index = function(value, off)
- {
- if (off === undefined) off = 0;
- var size = this.m_size;
- var values = this.m_values;
- if (size == 0) return null;
- var start = off;
- if (start < 0) start = size + start;
- if (start >= size || start < 0) throw fan.sys.IndexErr.make(off);
- if (value == null)
- {
- for (var i=start; i<size; ++i)
- if (values[i] == null)
- return i;
- }
- else
- {
- for (var i=start; i<size; ++i)
- {
- var obj = values[i];
- if (obj != null && fan.sys.ObjUtil.equals(obj, value))
- return i;
- }
- }
- return null;
- }
- fan.sys.List.prototype.indexr = function(value, off)
- {
- if (off === undefined) off = -1;
- var size = this.m_size;
- var values = this.m_values;
- if (size == 0) return null;
- var start = off;
- if (start < 0) start = size + start;
- if (start >= size || start < 0) throw fan.sys.IndexErr.make(off);
- if (value == null)
- {
- for (var i=start; i>=0; --i)
- if (values[i] == null)
- return i;
- }
- else
- {
- for (var i=start; i>=0; --i)
- {
- var obj = values[i];
- if (obj != null && fan.sys.ObjUtil.equals(obj, value))
- return i;
- }
- }
- return null;
- }
- fan.sys.List.prototype.indexSame = function(value, off)
- {
- if (off === undefined) off = 0;
- var size = this.m_size;
- var values = this.m_values;
- if (size == 0) return null;
- var start = off;
- if (start < 0) start = size + start;
- if (start >= size || start < 0) throw fan.sys.IndexErr.make(off);
- for (var i=start; i<size; i++)
- if (value === values[i])
- return i;
- return null;
- }
- fan.sys.List.prototype.first = function()
- {
- if (this.m_size == 0) return null;
- return this.m_values[0];
- }
- fan.sys.List.prototype.last = function()
- {
- if (this.m_size == 0) return null;
- return this.m_values[this.m_size-1];
- }
- fan.sys.List.prototype.dup = function()
- {
- return fan.sys.List.make(this.m_of, this.m_values.slice(0));
- }
- fan.sys.List.prototype.hash = function()
- {
- var hash = 33;
- var size = this.m_size;
- var vals = this.m_values;
- for (var i=0; i<size; ++i)
- {
- var obj = vals[i];
- hash = (31*hash) + (obj == null ? 0 : fan.sys.ObjUtil.hash(obj));
- }
- return hash;
- }
- fan.sys.List.prototype.equals = function(that)
- {
- if (that instanceof fan.sys.List)
- {
- if (!this.m_of.equals(that.m_of)) return false;
- if (this.m_size != that.m_size) return false;
- for (var i=0; i<this.m_size; ++i)
- if (!fan.sys.ObjUtil.equals(this.m_values[i], that.m_values[i]))
- return false;
- return true;
- }
- return false;
- }
- //////////////////////////////////////////////////////////////////////////
- // Modification
- //////////////////////////////////////////////////////////////////////////
- fan.sys.List.prototype.set = function(index, value)
- {
- this.modify();
- //try
- //{
- if (index < 0) index = this.m_size + index;
- if (index >= this.m_size || index < 0) throw fan.sys.IndexErr.make(index);
- this.m_values[index] = value;
- return this;
- //}
- //catch (ArrayIndexOutOfBoundsException e)
- //{
- // throw IndexErr.make(index).val;
- //}
- //catch (ArrayStoreException e)
- //{
- // throw CastErr.make("Setting '" + FanObj.type(value) + "' into '" + of + "[]'").val;
- //}
- }
- fan.sys.List.prototype.add = function(value)
- {
- // modify in insert$
- return this.insert$(this.m_size, value);
- }
- fan.sys.List.prototype.addAll = function(list)
- {
- // modify in insertAll$
- return this.insertAll$(this.m_size, list);
- }
- fan.sys.List.prototype.insert = function(index, value)
- {
- // modify in insert$
- if (index < 0) index = this.m_size + index;
- if (index > this.m_size || index < 0) throw fan.sys.IndexErr.make(index);
- return this.insert$(index, value);
- }
- fan.sys.List.prototype.insert$ = function(i, value)
- {
- //try
- //{
- this.modify();
- this.m_values.splice(i, 0, value);
- this.m_size++;
- return this;
- //}
- //catch (ArrayStoreException e)
- //{
- // throw CastErr.make("Adding '" + FanObj.type(value) + "' into '" + of + "[]'").val;
- //}
- }
- fan.sys.List.prototype.insertAll = function(index, list)
- {
- // modify in insertAll$
- if (index < 0) index = this.m_size + index;
- if (index > this.m_size || index < 0) throw fan.sys.IndexErr.make(index);
- return this.insertAll$(index, list);
- }
- fan.sys.List.prototype.insertAll$ = function(i, list)
- {
- // TODO: worth it to optimze small lists?
- // splice(i, 0, list[0], list[1], list[2])
- this.modify();
- if (list.m_size == 0) return this;
- var vals = list.m_values;
- if (this.m_values === vals) vals = vals.slice(0);
- for (var j=0; j<list.m_size; j++)
- this.m_values.splice(i+j, 0, vals[j]);
- this.m_size += list.m_size;
- return this;
- }
- fan.sys.List.prototype.remove = function(value)
- {
- // modify in removeAt
- var index = this.index(value);
- if (index == null) return null;
- return this.removeAt(index);
- }
- fan.sys.List.prototype.removeSame = function(value)
- {
- // modify in removeAt
- var index = this.indexSame(value);
- if (index == null) return null;
- return this.removeAt(index);
- }
- fan.sys.List.prototype.removeAt = function(index)
- {
- this.modify();
- if (index < 0) index = this.m_size + index;
- if (index >= this.m_size || index < 0) throw fan.sys.IndexErr.make(index);
- var old = this.m_values.splice(index, 1);
- this.m_size--;
- return old[0];
- }
- fan.sys.List.prototype.removeRange = function(r)
- {
- this.modify();
- var s = r.$start(this.m_size);
- var e = r.$end(this.m_size);
- var n = e - s + 1;
- if (n < 0) throw fan.sys.IndexErr.make(r);
- this.m_values.splice(s, n);
- this.m_size -= n;
- return this;
- }
- fan.sys.List.prototype.removeAll = function(toRemove)
- {
- this.modify();
- for (var i=0; i<toRemove.m_size; i++)
- this.remove(toRemove.get(i));
- return this;
- }
- fan.sys.List.prototype.trim = function()
- {
- this.modify();
- return this;
- }
- fan.sys.List.prototype.clear = function()
- {
- this.modify();
- this.m_values.splice(0, this.m_size);
- this.m_size = 0;
- return this;
- }
- fan.sys.List.prototype.fill = function(value, times)
- {
- this.modify();
- for (var i=0; i<times; i++) this.add(value);
- return this;
- }
- //////////////////////////////////////////////////////////////////////////
- // Stack
- //////////////////////////////////////////////////////////////////////////
- fan.sys.List.prototype.peek = function()
- {
- if (this.m_size == 0) return null;
- return this.m_values[this.m_size-1];
- }
- fan.sys.List.prototype.pop = function()
- {
- // modify in removeAt()
- if (this.m_size == 0) return null;
- return this.removeAt(-1);
- }
- fan.sys.List.prototype.push = function(obj)
- {
- // modify in add()
- return this.add(obj);
- }
- //////////////////////////////////////////////////////////////////////////
- // Iterators
- //////////////////////////////////////////////////////////////////////////
- fan.sys.List.prototype.each = function(f)
- {
- if (f.m_params.size() == 1)
- {
- for (var i=0; i<this.m_size; i++)
- f.call(this.m_values[i])
- }
- else
- {
- for (var i=0; i<this.m_size; i++)
- f.call(this.m_values[i], i)
- }
- }
- fan.sys.List.prototype.eachr = function(f)
- {
- if (f.m_params.size() == 1)
- {
- for (var i=this.m_size-1; i>=0; i--)
- f.call(this.m_values[i])
- }
- else
- {
- for (var i=this.m_size-1; i>=0; i--)
- f.call(this.m_values[i], i)
- }
- }
- fan.sys.List.prototype.eachRange = function(r, f)
- {
- var s = r.$start(this.m_size);
- var e = r.$end(this.m_size);
- var n = e - s + 1;
- if (n < 0) throw fan.sys.IndexErr.make(r);
- if (f.m_params.size() == 1)
- {
- for (var i=s; i<=e; ++i)
- f.call(this.m_values[i]);
- }
- else
- {
- for (var i=s; i<=e; ++i)
- f.call(this.m_values[i], i);
- }
- }
- fan.sys.List.prototype.eachWhile = function(f)
- {
- if (f.m_params.size() == 1)
- {
- for (var i=0; i<this.m_size; ++i)
- {
- var r = f.call(this.m_values[i]);
- if (r != null) return r;
- }
- }
- else
- {
- for (var i=0; i<this.m_size; ++i)
- {
- var r = f.call(this.m_values[i], i);
- if (r != null) return r;
- }
- }
- return null;
- }
- fan.sys.List.prototype.eachrWhile = function(f)
- {
- if (f.m_params.size() == 1)
- {
- for (var i=this.m_size-1; i>=0; i--)
- {
- var r = f.call(this.m_values[i]);
- if (r != null) return r;
- }
- }
- else
- {
- for (var i=this.m_size-1; i>=0; i--)
- {
- var r = f.call(this.m_values[i], i);
- if (r != null) return r;
- }
- }
- return null;
- }
- fan.sys.List.prototype.find = function(f)
- {
- if (f.m_params.size() == 1)
- {
- for (var i=0; i<this.m_size; i++)
- if (f.call(this.m_values[i]) == true)
- return this.m_values[i];
- }
- else
- {
- for (var i=0; i<this.m_size; i++)
- if (f.call(this.m_values[i], i) == true)
- return this.m_values[i];
- }
- return null;
- }
- fan.sys.List.prototype.findIndex = function(f)
- {
- if (f.m_params.size() == 1)
- {
- for (var i=0; i<this.m_size; i++)
- if (f.call(this.m_values[i]) == true)
- return i;
- }
- else
- {
- for (var i=0; i<this.m_size; i++)
- if (f.call(this.m_values[i], i) == true)
- return i;
- }
- return null;
- }
- fan.sys.List.prototype.findAll = function(f)
- {
- var acc = fan.sys.List.make(this.m_of);
- if (f.m_params.size() == 1)
- {
- for (var i=0; i<this.m_size; i++)
- if (f.call(this.m_values[i]) == true)
- acc.add(this.m_values[i]);
- }
- else
- {
- for (var i=0; i<this.m_size; i++)
- if (f.call(this.m_values[i], i) == true)
- acc.add(this.m_values[i]);
- }
- return acc;
- }
- fan.sys.List.prototype.findType = function(t)
- {
- var acc = fan.sys.List.make(t);
- for (var i=0; i<this.m_size; ++i)
- {
- var item = this.m_values[i];
- if (item != null && fan.sys.ObjUtil.$typeof(item).is(t))
- acc.add(item);
- }
- return acc;
- }
- fan.sys.List.prototype.exclude = function(f)
- {
- var acc = fan.sys.List.make(this.m_of);
- if (f.m_params.size() == 1)
- {
- for (var i=0; i<this.m_size; ++i)
- if (f.call(this.m_values[i]) != true)
- acc.add(this.m_values[i]);
- }
- else
- {
- for (var i=0; i<this.m_size; ++i)
- if (f.call(this.m_values[i], i) != true)
- acc.add(this.m_values[i]);
- }
- return acc;
- }
- fan.sys.List.prototype.any = function(f)
- {
- if (f.m_params.size() == 1)
- {
- for (var i=0; i<this.m_size; ++i)
- if (f.call(this.m_values[i]) == true)
- return true;
- }
- else
- {
- for (var i=0; i<this.m_size; ++i)
- if (f.call(this.m_values[i], i) == true)
- return true;
- }
- return false;
- }
- fan.sys.List.prototype.all = function(f)
- {
- if (f.m_params.size() == 1)
- {
- for (var i=0; i<this.m_size; ++i)
- if (f.call(this.m_values[i]) != true)
- return false;
- }
- else
- {
- for (var i=0; i<this.m_size; ++i)
- if (f.call(this.m_values[i], i) != true)
- return false;
- }
- return true;
- }
- fan.sys.List.prototype.reduce = function(reduction, f)
- {
- if (f.m_params.size() == 1)
- {
- for (var i=0; i<this.m_size; ++i)
- reduction = f.call(reduction, this.m_values[i]);
- }
- else
- {
- for (var i=0; i<this.m_size; ++i)
- reduction = f.call(reduction, this.m_values[i], i);
- }
- return reduction;
- }
- fan.sys.List.prototype.map = function(f)
- {
- var r = f.returns();
- if (r == fan.sys.Void.$type) r = fan.sys.Obj.$type.toNullable();
- var acc = fan.sys.List.make(r);
- if (f.m_params.size() == 1)
- {
- for (var i=0; i<this.m_size; ++i)
- acc.add(f.call(this.m_values[i]));
- }
- else
- {
- for (var i=0; i<this.m_size; ++i)
- acc.add(f.call(this.m_values[i], i));
- }
- return acc;
- }
- fan.sys.List.prototype.max = function(f)
- {
- if (f === undefined) f = null;
- if (this.m_size == 0) return null;
- var max = this.m_values[0];
- for (var i=1; i<this.m_size; ++i)
- {
- var s = this.m_values[i];
- if (f == null)
- max = (s != null && s > max) ? s : max;
- else
- max = (s != null && f.call(s, max) > 0) ? s : max;
- }
- return max;
- }
- fan.sys.List.prototype.min = function(f)
- {
- if (f === undefined) f = null;
- if (this.m_size == 0) return null;
- var min = this.m_values[0];
- for (var i=1; i<this.m_size; ++i)
- {
- var s = this.m_values[i];
- if (f == null)
- min = (s == null || s < min) ? s : min;
- else
- min = (s == null || f.call(s, min) < 0) ? s : min;
- }
- return min;
- }
- fan.sys.List.prototype.unique = function()
- {
- var dups = fan.sys.Map.make(fan.sys.Obj.$type, fan.sys.Obj.$type);
- var acc = fan.sys.List.make(this.m_of);
- for (var i=0; i<this.m_size; ++i)
- {
- var v = this.m_values[i];
- var key = v;
- if (key == null) key = "__null_key__";
- if (dups.get(key) == null)
- {
- dups.set(key, this);
- acc.add(v);
- }
- }
- return acc;
- }
- fan.sys.List.prototype.union = function(that)
- {
- var dups = fan.sys.Map.make(fan.sys.Obj.$type, fan.sys.Obj.$type);
- var acc = fan.sys.List.make(this.m_of);
- // first me
- for (var i=0; i<this.m_size; ++i)
- {
- var v = this.m_values[i];
- var key = v;
- if (key == null) key = "__null_key__";
- if (dups.get(key) == null)
- {
- dups.set(key, this);
- acc.add(v);
- }
- }
- // then him
- for (var i=0; i<that.m_size; ++i)
- {
- var v = that.m_values[i];
- var key = v;
- if (key == null) key = "__null_key__";
- if (dups.get(key) == null)
- {
- dups.set(key, this);
- acc.add(v);
- }
- }
- return acc;
- }
- fan.sys.List.prototype.intersection = function(that)
- {
- // put other list into map
- var dups = fan.sys.Map.make(fan.sys.Obj.$type, fan.sys.Obj.$type);
- for (var i=0; i<that.m_size; ++i)
- {
- var v = that.m_values[i];
- var key = v;
- if (key == null) key = "__null_key__";
- dups.set(key, this);
- }
- // now walk this list and accumulate
- // everything found in the dups map
- var acc = fan.sys.List.make(this.m_of);
- for (var i=0; i<this.m_size; ++i)
- {
- var v = this.m_values[i];
- var key = v;
- if (key == null) key = "__null_key__";
- if (dups.get(key) != null)
- {
- acc.add(v);
- dups.remove(key);
- }
- }
- return acc;
- }
- //////////////////////////////////////////////////////////////////////////
- // Utils
- //////////////////////////////////////////////////////////////////////////
- fan.sys.List.prototype.sort = function(f)
- {
- this.modify();
- if (f === undefined) f = null;
- if (f != null)
- this.m_values.sort(function(a,b) { return f.call(a,b) });
- else
- this.m_values.sort(function(a,b) { return fan.sys.ObjUtil.compare(a,b,false) });
- return this;
- }
- fan.sys.List.prototype.sortr = function(f)
- {
- this.modify();
- if (f === undefined) f = null;
- if (f != null)
- this.m_values.sort(function(a,b) { return f.call(b,a) });
- else
- this.m_values.sort(function(a,b) { return fan.sys.ObjUtil.compare(b,a,false) });
- return this;
- }
- fan.sys.List.prototype.binarySearch = function(key, f)
- {
- var c = f != null
- ? function(item,index) { return f.call(key,item) }
- : function(item,index) { return fan.sys.ObjUtil.compare(key,item,false) };
- return this.doBinaryFind(c);
- }
- fan.sys.List.prototype.binaryFind = function(f)
- {
- return this.doBinaryFind(f.m_func);
- }
- fan.sys.List.prototype.doBinaryFind = function(f)
- {
- var low = 0;
- var high = this.m_size - 1;
- while (low <= high)
- {
- var mid = Math.floor((low + high) / 2);
- var cmp = f(this.m_values[mid], mid);
- if (cmp > 0) low = mid + 1;
- else if (cmp < 0) high = mid - 1;
- else return mid;
- }
- return -(low + 1);
- }
- fan.sys.List.prototype.reverse = function()
- {
- this.modify();
- var mid = this.m_size/2;
- for (var i=0; i<mid; ++i)
- {
- var a = this.m_values[i];
- var b = this.m_values[this.m_size-i-1];
- this.m_values[i] = b;
- this.m_values[this.m_size-i-1] = a;
- }
- return this;
- }
- fan.sys.List.prototype.swap = function(a, b)
- {
- // modify in set()
- var temp = this.get(a);
- this.set(a, this.get(b));
- this.set(b, temp);
- return this;
- }
- fan.sys.List.prototype.moveTo = function(item, toIndex)
- {
- this.modify();
- var curIndex = this.index(item);
- if (curIndex == null) return this;
- if (curIndex == toIndex) return this;
- this.removeAt(curIndex);
- if (toIndex == -1) return this.add(item);
- if (toIndex < 0) ++toIndex;
- return this.insert(toIndex, item);
- }
- fan.sys.List.prototype.flatten = function()
- {
- var acc = fan.sys.List.make(fan.sys.Obj.$type.toNullable());
- this.doFlatten(acc);
- return acc;
- }
- fan.sys.List.prototype.doFlatten = function(acc)
- {
- for (var i=0; i<this.m_size; ++i)
- {
- var item = this.m_values[i];
- if (item instanceof fan.sys.List)
- item.doFlatten(acc);
- else
- acc.add(item);
- }
- }
- fan.sys.List.prototype.random = function()
- {
- if (this.m_size == 0) return null;
- var i = Math.floor(Math.random() * 4294967296);
- if (i < 0) i = -i;
- return this.m_values[i % this.m_size];
- }
- fan.sys.List.prototype.shuffle = function()
- {
- this.modify();
- for (var i=0; i<this.m_size; ++i)
- {
- var randi = Math.floor(Math.random() * (i+1));
- var temp = this.m_values[i];
- this.m_values[i] = this.m_values[randi];
- this.m_values[randi] = temp;
- }
- return this;
- }
- //////////////////////////////////////////////////////////////////////////
- // Conversion
- //////////////////////////////////////////////////////////////////////////
- fan.sys.List.prototype.join = function(sep, f)
- {
- if (sep === undefined) sep = "";
- if (f === undefined) f = null;
- if (this.m_size === 0) return "";
- if (this.m_size === 1)
- {
- var v = this.m_values[0];
- if (f != null) return f.call(v, 0);
- if (v == null) return "null";
- return fan.sys.ObjUtil.toStr(v);
- }
- var s = ""
- for (var i=0; i<this.m_size; ++i)
- {
- if (i > 0) s += sep;
- if (f == null)
- s += this.m_values[i];
- else
- s += f.call(this.m_values[i], i);
- }
- return s;
- }
- fan.sys.List.prototype.toStr = function()
- {
- if (this.m_size == 0) return "[,]";
- var s = "[";
- for (var i=0; i<this.m_size; i++)
- {
- if (i > 0) s += ", ";
- s += this.m_values[i];
- }
- s += "]";
- return s;
- }
- fan.sys.List.prototype.toCode = function()
- {
- var s = '';
- s += this.m_of.signature();
- s += '[';
- if (this.m_size == 0) s += ',';
- for (var i=0; i<this.m_size; ++i)
- {
- if (i > 0) s += ', ';
- s += fan.sys.ObjUtil.trap(this.m_values[i], "toCode", null);
- }
- s += ']';
- return s;
- }
- fan.sys.List.prototype.$literalEncode = function(out)
- {
- // route back to obj encoder
- out.writeList(this);
- }
- //////////////////////////////////////////////////////////////////////////
- // Readonly
- //////////////////////////////////////////////////////////////////////////
- fan.sys.List.prototype.isRW = function()
- {
- return !this.m_readonly;
- }
- fan.sys.List.prototype.isRO = function()
- {
- return this.m_readonly;
- }
- fan.sys.List.prototype.rw = function()
- {
- if (!this.m_readonly) return this;
- var rw = fan.sys.List.make(this.m_of, this.m_values.slice(0));
- rw.m_readonly = false;
- rw.m_readonlyList = this;
- return rw;
- }
- fan.sys.List.prototype.ro = function()
- {
- if (this.m_readonly) return this;
- if (this.m_readonlyList == null)
- {
- var ro = fan.sys.List.make(this.m_of, this.m_values.slice(0));
- ro.m_readonly = true;
- this.m_readonlyList = ro;
- }
- return this.m_readonlyList;
- }
- fan.sys.List.prototype.isImmutable = function()
- {
- return this.m_immutable;
- }
- fan.sys.List.prototype.toImmutable = function()
- {
- if (this.m_immutable) return this;
- // make safe copy
- var temp = [];
- for (var i=0; i<this.m_size; ++i)
- {
- var item = this.m_values[i];
- if (item != null)
- {
- if (item instanceof fan.sys.List) item = item.toImmutable();
- else if (item instanceof fan.sys.Map) item = item.toImmutable();
- else if (!fan.sys.ObjUtil.isImmutable(item))
- throw fan.sys.NotImmutableErr.make("Item [" + i + "] not immutable " +
- fan.sys.Type.of(item));
- }
- temp[i] = item;
- }
- // return new immutable list
- var ro = fan.sys.List.make(this.m_of, temp);
- ro.m_readonly = true;
- ro.m_immutable = true;
- return ro;
- }
- fan.sys.List.prototype.modify = function()
- {
- // if readonly then throw readonly exception
- if (this.m_readonly)
- throw fan.sys.ReadonlyErr.make("List is readonly");
- // if we have a cached readonlyList, then detach
- // it so it remains immutable
- if (this.m_readonlyList != null)
- {
- this.m_readonlyList.m_values = this.m_values.slice(0);
- this.m_readonlyList = null;
- }
- }