/** * Copyright 2010 Tim Down. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ (function () { "use strict"; Kotlin.equals = function (obj1, obj2) { if (typeof obj1 == "object") { if (obj1.equals !== undefined) { return obj1.equals(obj2); } } return (obj1 === obj2); }; Kotlin.defs = {}; Kotlin.Exceptions = {}; Kotlin.Exception = Kotlin.$createClass(); Kotlin.RuntimeException = Kotlin.$createClass(Kotlin.Exception); Kotlin.Exceptions.IndexOutOfBounds = Kotlin.$createClass(Kotlin.Exception); Kotlin.Exceptions.NullPointerException = Kotlin.$createClass(Kotlin.Exception); Kotlin.Exceptions.NoSuchElementException = Kotlin.$createClass(Kotlin.Exception); Kotlin.Exceptions.IllegalArgumentException = Kotlin.$createClass(Kotlin.Exception); Kotlin.Exceptions.IllegalStateException = Kotlin.$createClass(Kotlin.Exception); Kotlin.Exceptions.IndexOutOfBoundsException = Kotlin.$createClass(Kotlin.Exception); Kotlin.Exceptions.UnsupportedOperationException = Kotlin.$createClass(Kotlin.Exception); Kotlin.Exceptions.IOException = Kotlin.$createClass(Kotlin.Exception); Kotlin.throwNPE = function() { throw Kotlin.$new(Kotlin.Exceptions.NullPointerException)(); }; Kotlin.AbstractList = Kotlin.$createClass({ set:function (index, value) { throw Kotlin.$new(Kotlin.Exceptions.UnsupportedOperationException)(); }, iterator:function () { return Kotlin.$new(Kotlin.ArrayIterator)(this); }, isEmpty:function () { return (this.size() === 0); }, add:function (element) { throw Kotlin.$new(Kotlin.Exceptions.UnsupportedOperationException)(); }, addAll:function (collection) { var it = collection.iterator(); while (it.get_hasNext()) { this.add(it.next()); } }, remove:function(value) { for (var i = 0; i < this.$size; ++i) { if (this.array[i] == value) { this.removeByIndex(i); return; } } }, removeByIndex:function (index) { throw Kotlin.$new(Kotlin.Exceptions.UnsupportedOperationException)(); }, clear:function () { throw Kotlin.$new(Kotlin.Exceptions.UnsupportedOperationException)(); }, contains:function (obj) { for (var i = 0; i < this.$size; ++i) { if (Kotlin.equals(this.array[i], obj)) { return true; } } return false; } }); Kotlin.ArrayList = Kotlin.$createClass({ initialize:function () { this.array = []; this.$size = 0; }, get:function (index) { if ((index < 0) || (index >= this.$size)) { throw Kotlin.Exceptions.IndexOutOfBounds; } return (this.array)[index]; }, set:function (index, value) { if ((index < 0) || (index >= this.$size)) { throw Kotlin.Exceptions.IndexOutOfBounds; } (this.array)[index] = value; }, size:function () { return this.$size; }, iterator:function () { return Kotlin.$new(Kotlin.ArrayIterator)(this); }, isEmpty:function () { return (this.$size === 0); }, add:function (element) { this.array[this.$size++] = element; }, addAll:function (collection) { var it = collection.iterator(); while (it.get_hasNext()) { this.add(it.next()); } }, remove:function(value) { for (var i = 0; i < this.$size; ++i) { if (this.array[i] == value) { this.removeByIndex(i); return; } } }, removeByIndex:function (index) { for (var i = index; i < this.$size - 1; ++i) { this.array[i] = this.array[i + 1]; } this.$size--; }, clear:function () { this.array = []; this.$size = 0; }, contains:function (obj) { for (var i = 0; i < this.$size; ++i) { if (Kotlin.equals(this.array[i], obj)) { return true; } } return false; } }); Kotlin.parseInt = function (str) { return parseInt(str, 10); } ; Kotlin.safeParseInt = function(str) { var r = parseInt(str, 10); return isNaN(r) ? null : r; }; Kotlin.safeParseDouble = function(str) { var r = parseFloat(str, 10); return isNaN(r) ? null : r; }; Kotlin.System = function () { var output = ""; var print = function (obj) { if (obj !== undefined) { if (obj === null || typeof obj !== "object") { output += obj; } else { output += obj.toString(); } } }; var println = function (obj) { this.print(obj); output += "\n"; }; return { out:function () { return { print:print, println:println }; }, output:function () { return output; }, flush:function () { output = ""; } }; }(); Kotlin.println = function (s) { Kotlin.System.out().println(s); }; Kotlin.print = function (s) { Kotlin.System.out().print(s); }; Kotlin.AbstractFunctionInvocationError = Kotlin.$createClass(); Kotlin.Iterator = Kotlin.$createClass({ initialize:function () { }, next:function () { throw Kotlin.$new(Kotlin.AbstractFunctionInvocationError)(); }, get_hasNext:function () { throw Kotlin.$new(Kotlin.AbstractFunctionInvocationError)(); } }); Kotlin.Runnable = Kotlin.$createClass({ run:function () { throw Kotlin.$new(Kotlin.AbstractFunctionInvocationError)(); } }); Kotlin.ArrayIterator = Kotlin.$createClass(Kotlin.Iterator, { initialize: function (array) { this.array = array; this.index = 0; }, next: function () { return this.array.get(this.index++); }, get_hasNext: function () { return this.array.size() > this.index; } }); Kotlin.RangeIterator = Kotlin.$createClass(Kotlin.Iterator, { initialize:function (start, count, reversed) { this.$start = start; this.$count = count; this.$reversed = reversed; this.$i = this.get_start(); }, get_start:function () { return this.$start; }, get_count:function () { return this.$count; }, set_count:function (tmp$0) { this.$count = tmp$0; }, get_reversed:function () { return this.$reversed; }, get_i:function () { return this.$i; }, set_i:function (tmp$0) { this.$i = tmp$0; }, next:function () { this.set_count(this.get_count() - 1); if (this.get_reversed()) { this.set_i(this.get_i() - 1); return this.get_i() + 1; } else { this.set_i(this.get_i() + 1); return this.get_i() - 1; } }, get_hasNext: function () { return this.get_count() > 0; } }); Kotlin.NumberRange = Kotlin.$createClass({initialize:function (start, size, reversed) { this.$start = start; this.$size = size; this.$reversed = reversed; }, get_start:function () { return this.$start; }, get_size:function () { return this.$size; }, get_reversed:function () { return this.$reversed; }, get_end:function () { return this.get_reversed() ? this.get_start() - this.get_size() + 1 : this.get_start() + this.get_size() - 1; }, contains:function (number) { if (this.get_reversed()) { return number <= this.get_start() && number > this.get_start() - this.get_size(); } else { return number >= this.get_start() && number < this.get_start() + this.get_size(); } }, iterator:function () { return Kotlin.$new(Kotlin.RangeIterator)(this.get_start(), this.get_size(), this.get_reversed()); } }); Kotlin.Comparator = Kotlin.$createClass( { initialize: function () { }, compare: function (el1, el2) { throw Kotlin.$new(Kotlin.AbstractFunctionInvocationError)(); } } ); Kotlin.comparator = function (f) { var result = Kotlin.$new(Kotlin.Comparator)(); result.compare = f; return result; }; Kotlin.collectionsMax = function (col, comp) { var it = col.iterator(); if (col.isEmpty()) { //TODO: which exception? throw Kotlin.Exception(); } var max = it.next(); while (it.get_hasNext()) { var el = it.next(); if (comp.compare(max, el) < 0) { max = el; } } return max; }; Kotlin.StringBuilder = Kotlin.$createClass( { initialize:function () { this.string = ""; }, append:function (obj) { this.string = this.string + obj.toString(); }, toString:function () { return this.string; } } ); Kotlin.splitString = function (str, regex) { return str.split(regex); }; Kotlin.nullArray = function (size) { var res = []; var i = size; while (i > 0) { res[--i] = null; } return res; }; Kotlin.arrayFromFun = function (size, initFun) { var res = []; var i = size; while (i > 0) { res[--i] = initFun(i); } return res; }; Kotlin.arrayIndices = function (arr) { return Kotlin.$new(Kotlin.NumberRange)(0, arr.length); }; var intrinsicArrayIterator = Kotlin.$createClass( Kotlin.Iterator, { initialize: function (arr) { this.arr = arr; this.len = arr.length; this.i = 0; }, next: function () { return this.arr[this.i++]; }, get_hasNext: function () { return this.i < this.len; } } ); Kotlin.arrayIterator = function (arr) { return Kotlin.$new(intrinsicArrayIterator)(arr); }; Kotlin.toString = function (obj) { return obj.toString(); }; Kotlin.jsonFromTuples = function (pairArr) { var i = pairArr.length; var res = {}; while (i > 0) { --i; res[pairArr[i][0]] = pairArr[i][1]; } return res; }; //TODO: use intrinsic Kotlin.jsonSet = function (obj, attrName, value) { obj[attrName] = value; }; Kotlin.jsonGet = function (obj, attrName) { return obj[attrName]; }; Kotlin.jsonAddProperties = function (obj1, obj2) { for (var p in obj2) { if (obj2.hasOwnProperty(p)) { obj1[p] = obj2[p]; } } return obj1; }; //TODO: use intrinsic Kotlin.sure = function (obj) { return obj; }; (function () { var FUNCTION = "function"; var arrayRemoveAt = (typeof Array.prototype.splice == FUNCTION) ? function (arr, idx) { arr.splice(idx, 1); } : function (arr, idx) { var itemsAfterDeleted, i, len; if (idx === arr.length - 1) { arr.length = idx; } else { itemsAfterDeleted = arr.slice(idx + 1); arr.length = idx; for (i = 0, len = itemsAfterDeleted.length; i < len; ++i) { arr[idx + i] = itemsAfterDeleted[i]; } } }; function hashObject(obj) { var hashCode; if (typeof obj == "string") { return obj; } else if (typeof obj.hashCode == FUNCTION) { // Check the hashCode method really has returned a string hashCode = obj.hashCode(); return (typeof hashCode == "string") ? hashCode : hashObject(hashCode); } else if (typeof obj.toString == FUNCTION) { return obj.toString(); } else { try { return String(obj); } catch (ex) { // For host objects (such as ActiveObjects in IE) that have no toString() method and throw an error when // passed to String() return Object.prototype.toString.call(obj); } } } function equals_fixedValueHasEquals(fixedValue, variableValue) { return fixedValue.equals(variableValue); } function equals_fixedValueNoEquals(fixedValue, variableValue) { return (typeof variableValue.equals == FUNCTION) ? variableValue.equals(fixedValue) : (fixedValue === variableValue); } function createKeyValCheck(kvStr) { return function (kv) { if (kv === null) { throw new Error("null is not a valid " + kvStr); } else if (typeof kv == "undefined") { throw new Error(kvStr + " must not be undefined"); } }; } var checkKey = createKeyValCheck("key"), checkValue = createKeyValCheck("value"); /*----------------------------------------------------------------------------------------------------------------*/ function Bucket(hash, firstKey, firstValue, equalityFunction) { this[0] = hash; this.entries = []; this.addEntry(firstKey, firstValue); if (equalityFunction !== null) { this.getEqualityFunction = function () { return equalityFunction; }; } } var EXISTENCE = 0, ENTRY = 1, ENTRY_INDEX_AND_VALUE = 2; function createBucketSearcher(mode) { return function (key) { var i = this.entries.length, entry, equals = this.getEqualityFunction(key); while (i--) { entry = this.entries[i]; if (equals(key, entry[0])) { switch (mode) { case EXISTENCE: return true; case ENTRY: return entry; case ENTRY_INDEX_AND_VALUE: return [ i, entry[1] ]; } } } return false; }; } function createBucketLister(entryProperty) { return function (aggregatedArr) { var startIndex = aggregatedArr.length; for (var i = 0, len = this.entries.length; i < len; ++i) { aggregatedArr[startIndex + i] = this.entries[i][entryProperty]; } }; } Bucket.prototype = { getEqualityFunction:function (searchValue) { return (typeof searchValue.equals == FUNCTION) ? equals_fixedValueHasEquals : equals_fixedValueNoEquals; }, getEntryForKey:createBucketSearcher(ENTRY), getEntryAndIndexForKey:createBucketSearcher(ENTRY_INDEX_AND_VALUE), removeEntryForKey:function (key) { var result = this.getEntryAndIndexForKey(key); if (result) { arrayRemoveAt(this.entries, result[0]); return result[1]; } return null; }, addEntry:function (key, value) { this.entries[this.entries.length] = [key, value]; }, keys:createBucketLister(0), values:createBucketLister(1), getEntries:function (entries) { var startIndex = entries.length; for (var i = 0, len = this.entries.length; i < len; ++i) { // Clone the entry stored in the bucket before adding to array entries[startIndex + i] = this.entries[i].slice(0); } }, containsKey:createBucketSearcher(EXISTENCE), containsValue:function (value) { var i = this.entries.length; while (i--) { if (value === this.entries[i][1]) { return true; } } return false; } }; /*----------------------------------------------------------------------------------------------------------------*/ // Supporting functions for searching hashtable buckets function searchBuckets(buckets, hash) { var i = buckets.length, bucket; while (i--) { bucket = buckets[i]; if (hash === bucket[0]) { return i; } } return null; } function getBucketForHash(bucketsByHash, hash) { var bucket = bucketsByHash[hash]; // Check that this is a genuine bucket and not something inherited from the bucketsByHash's prototype return ( bucket && (bucket instanceof Bucket) ) ? bucket : null; } /*----------------------------------------------------------------------------------------------------------------*/ var Hashtable = function (hashingFunctionParam, equalityFunctionParam) { var that = this; var buckets = []; var bucketsByHash = {}; var hashingFunction = (typeof hashingFunctionParam == FUNCTION) ? hashingFunctionParam : hashObject; var equalityFunction = (typeof equalityFunctionParam == FUNCTION) ? equalityFunctionParam : null; this.put = function (key, value) { checkKey(key); checkValue(value); var hash = hashingFunction(key), bucket, bucketEntry, oldValue = null; // Check if a bucket exists for the bucket key bucket = getBucketForHash(bucketsByHash, hash); if (bucket) { // Check this bucket to see if it already contains this key bucketEntry = bucket.getEntryForKey(key); if (bucketEntry) { // This bucket entry is the current mapping of key to value, so replace old value and we're done. oldValue = bucketEntry[1]; bucketEntry[1] = value; } else { // The bucket does not contain an entry for this key, so add one bucket.addEntry(key, value); } } else { // No bucket exists for the key, so create one and put our key/value mapping in bucket = new Bucket(hash, key, value, equalityFunction); buckets[buckets.length] = bucket; bucketsByHash[hash] = bucket; } return oldValue; }; this.get = function (key) { checkKey(key); var hash = hashingFunction(key); // Check if a bucket exists for the bucket key var bucket = getBucketForHash(bucketsByHash, hash); if (bucket) { // Check this bucket to see if it contains this key var bucketEntry = bucket.getEntryForKey(key); if (bucketEntry) { // This bucket entry is the current mapping of key to value, so return the value. return bucketEntry[1]; } } return null; }; this.containsKey = function (key) { checkKey(key); var bucketKey = hashingFunction(key); // Check if a bucket exists for the bucket key var bucket = getBucketForHash(bucketsByHash, bucketKey); return bucket ? bucket.containsKey(key) : false; }; this.containsValue = function (value) { checkValue(value); var i = buckets.length; while (i--) { if (buckets[i].containsValue(value)) { return true; } } return false; }; this.clear = function () { buckets.length = 0; bucketsByHash = {}; }; this.isEmpty = function () { return !buckets.length; }; var createBucketAggregator = function (bucketFuncName) { return function () { var aggregated = [], i = buckets.length; while (i--) { buckets[i][bucketFuncName](aggregated); } return aggregated; }; }; this._keys = createBucketAggregator("keys"); this._values = createBucketAggregator("values"); this._entries = createBucketAggregator("getEntries"); this.values = function() { var values = this._values(); var i = values.length var result = Kotlin.$new(Kotlin.ArrayList)(); while (--i) { result.add(values[i]); } return result; }; this.remove = function (key) { checkKey(key); var hash = hashingFunction(key), bucketIndex, oldValue = null; // Check if a bucket exists for the bucket key var bucket = getBucketForHash(bucketsByHash, hash); if (bucket) { // Remove entry from this bucket for this key oldValue = bucket.removeEntryForKey(key); if (oldValue !== null) { // Entry was removed, so check if bucket is empty if (!bucket.entries.length) { // Bucket is empty, so remove it from the bucket collections bucketIndex = searchBuckets(buckets, hash); arrayRemoveAt(buckets, bucketIndex); delete bucketsByHash[hash]; } } } return oldValue; }; this.size = function () { var total = 0, i = buckets.length; while (i--) { total += buckets[i].entries.length; } return total; }; this.each = function (callback) { var entries = that.entries(), i = entries.length, entry; while (i--) { entry = entries[i]; callback(entry[0], entry[1]); } }; this.putAll = function (hashtable, conflictCallback) { var entries = hashtable.entries(); var entry, key, value, thisValue, i = entries.length; var hasConflictCallback = (typeof conflictCallback == FUNCTION); while (i--) { entry = entries[i]; key = entry[0]; value = entry[1]; // Check for a conflict. The default behaviour is to overwrite the value for an existing key if (hasConflictCallback && (thisValue = that.get(key))) { value = conflictCallback(key, thisValue, value); } that.put(key, value); } }; this.clone = function () { var clone = new Hashtable(hashingFunctionParam, equalityFunctionParam); clone.putAll(that); return clone; }; this.keySet = function () { var res = Kotlin.$new(Kotlin.HashSet)(); var keys = this._keys(); var i = keys.length; while (i--) { res.add(keys[i]); } return res; }; }; Kotlin.HashTable = Hashtable; })(); Kotlin.HashMap = Kotlin.$createClass( { initialize:function () { Kotlin.HashTable.call(this); } } ); (function () { function HashSet(hashingFunction, equalityFunction) { var hashTable = new Kotlin.HashTable(hashingFunction, equalityFunction); this.add = function (o) { hashTable.put(o, true); }; this.addAll = function (arr) { var i = arr.length; while (i--) { hashTable.put(arr[i], true); } }; this.values = function () { return hashTable._keys(); }; this.iterator = function () { return Kotlin.arrayIterator(this.values()); }; this.remove = function (o) { return hashTable.remove(o) ? o : null; }; this.contains = function (o) { return hashTable.containsKey(o); }; this.clear = function () { hashTable.clear(); }; this.size = function () { return hashTable.size(); }; this.isEmpty = function () { return hashTable.isEmpty(); }; this.clone = function () { var h = new HashSet(hashingFunction, equalityFunction); h.addAll(hashTable.keys()); return h; }; this.intersection = function (hashSet) { var intersection = new HashSet(hashingFunction, equalityFunction); var values = hashSet.values(), i = values.length, val; while (i--) { val = values[i]; if (hashTable.containsKey(val)) { intersection.add(val); } } return intersection; }; this.union = function (hashSet) { var union = this.clone(); var values = hashSet.values(), i = values.length, val; while (i--) { val = values[i]; if (!hashTable.containsKey(val)) { union.add(val); } } return union; }; this.isSubsetOf = function (hashSet) { var values = hashTable.keys(), i = values.length; while (i--) { if (!hashSet.contains(values[i])) { return false; } } return true; }; } Kotlin.HashSet = Kotlin.$createClass({initialize: function () { HashSet.call(this); }}); }()); })();