1 /* 2 * ISet.js - ilib Set class definition for platforms older than ES6 3 * 4 * Copyright © 2015, JEDLSoft 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 20 /** 21 * Create a new set with elements in the given array. The type of 22 * the set is gleaned from the type of the first element in the 23 * elements array, or the first element added to the set. The type 24 * may be "string" or "number", and all elements will be returned 25 * as elements of that type. 26 * 27 * @class 28 * @param {Array.<string|number>=} elements initial elements to add to the set 29 * @constructor 30 */ 31 var ISet = function(elements) { 32 this.elements = {}; 33 34 if (elements && elements.length) { 35 for (var i = 0; i < elements.length; i++) { 36 this.elements[elements[i]] = true; 37 } 38 39 this.type = typeof(elements[0]); 40 } 41 }; 42 43 /** 44 * @private 45 */ 46 ISet.prototype._addOne = function(element) { 47 if (this.isEmpty()) { 48 this.type = typeof(element); 49 } 50 51 if (!this.elements[element]) { 52 this.elements[element] = true; 53 return true; 54 } 55 56 return false; 57 }; 58 59 /** 60 * Adds the specified element or array of elements to this set if it is or they are not 61 * already present. 62 * 63 * @param {*|Array.<*>} element element or array of elements to add 64 * @return {boolean} true if this set did not already contain the specified element[s] 65 */ 66 ISet.prototype.add = function(element) { 67 var ret = false; 68 69 if (typeof(element) === "object") { 70 for (var i = 0; i < element.length; i++) { 71 ret = this._addOne(element[i]) || ret; 72 } 73 } else { 74 ret = this._addOne(element); 75 } 76 77 return ret; 78 }; 79 80 /** 81 * Removes all of the elements from this set. 82 */ 83 ISet.prototype.clear = function() { 84 this.elements = {}; 85 }; 86 87 /** 88 * Returns true if this set contains the specified element. 89 * @param {*} element the element to test 90 * @return {boolean} 91 */ 92 ISet.prototype.contains = function(element) { 93 return this.elements[element] || false; 94 }; 95 96 ISet.prototype.has = ISet.prototype.contains; // for compatibility with ES6 97 98 /** 99 * Returns true if this set contains no elements. 100 * @return {boolean} 101 */ 102 ISet.prototype.isEmpty = function() { 103 return (Object.keys(this.elements).length === 0); 104 }; 105 106 /** 107 * Removes the specified element from this set if it is present. 108 * @param {*} element the element to remove 109 * @return {boolean} true if the set contained the specified element 110 */ 111 ISet.prototype.remove = function(element) { 112 if (this.elements[element]) { 113 delete this.elements[element]; 114 return true; 115 } 116 117 return false; 118 }; 119 120 /** 121 * Return the set as a javascript array. 122 * @return {Array.<*>} the set represented as a javascript array 123 */ 124 ISet.prototype.asArray = function() { 125 var keys = Object.keys(this.elements); 126 127 // keys is an array of strings. Convert to numbers if necessary 128 if (this.type === "number") { 129 var tmp = []; 130 for (var i = 0; i < keys.length; i++) { 131 tmp.push(Number(keys[i]).valueOf()); 132 } 133 keys = tmp; 134 } 135 136 return keys; 137 }; 138 139 /** 140 * Represents the current set as json. 141 * @return {string} the current set represented as json 142 */ 143 ISet.prototype.toJson = function() { 144 return JSON.stringify(this.asArray()); 145 }; 146 147 /** 148 * Convert to a javascript representation of this object. 149 * In this case, it is a normal JS array. 150 * @return {*} the JS representation of this object 151 */ 152 ISet.prototype.toJS = function() { 153 return this.asArray(); 154 }; 155 156 /** 157 * Convert from a js representation to an internal one. 158 * @return {ISet|undefined} the current object, or undefined if the conversion did not work 159 */ 160 ISet.prototype.fromJS = function(obj) { 161 return this.add(obj) ? this : undefined; 162 }; 163 164 module.exports = ISet; 165