pax_global_header00006660000000000000000000000064122210404160014502gustar00rootroot0000000000000052 comment=ccb4429c21f23e24d0fd8755373956db3c00798f stringset-ccb4429c21f23e24d0fd8755373956db3c00798f/000077500000000000000000000000001222104041600203765ustar00rootroot00000000000000stringset-ccb4429c21f23e24d0fd8755373956db3c00798f/LICENSE000066400000000000000000000020671222104041600214100ustar00rootroot00000000000000Copyright (c) 2013 Olov Lassus Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. stringset-ccb4429c21f23e24d0fd8755373956db3c00798f/README.md000066400000000000000000000026771222104041600216710ustar00rootroot00000000000000# stringset.js A fast and robust stringset implementation that can hold any string items, including `__proto__`, with minimal overhead compared to a plain object. Works in node and browsers. The API is created to be as close to the ES6 Set API as possible. Prefer `ss.remove("key")` for deleting a key. ES6 Set uses `set.delete("key")` instead and for that reason `ss['delete']("key")` is available as a stringset alias as well. Never do `ss.delete("key")` unless you're certain to be in the land of ES5 or later. ## Examples Available in `examples.js` ```javascript var StringSet = require("stringset"); var ss1 = new StringSet(); ss1.add("greeting"); ss1.add("check"); ss1.add("__proto__"); console.log(ss1.has("greeting")); // true console.log(ss1.has("__proto__")); // true ss1.remove("greeting"); console.log(ss1.items()); // [ 'check', '__proto__' ] console.log(ss1.toString()); // {"check","__proto__"} var ss2 = new StringSet(["one", "two"]); console.log(ss2.isEmpty()); // false console.log(ss2.size()); // 2 var ss3 = ss1.clone(); ss3.merge(ss2); ss3.addMany(["a", "b"]); console.log(ss3.toString()); // {"check","one","two","a","b","__proto__"} ``` ## Installation ### Node Install using npm npm install stringset ```javascript var StringSet = require("stringset"); ``` ### Browser Clone the repo and include it in a script tag git clone https://github.com/olov/stringset.git ```html ``` stringset-ccb4429c21f23e24d0fd8755373956db3c00798f/examples.js000066400000000000000000000011221222104041600225460ustar00rootroot00000000000000var StringSet = require("./stringset"); var ss1 = new StringSet(); ss1.add("greeting"); ss1.add("check"); ss1.add("__proto__"); console.log(ss1.has("greeting")); // true console.log(ss1.has("__proto__")); // true ss1.remove("greeting"); console.log(ss1.items()); // [ 'check', '__proto__' ] console.log(ss1.toString()); // {"check","__proto__"} var ss2 = new StringSet(["one", "two"]); console.log(ss2.isEmpty()); // false console.log(ss2.size()); // 2 var ss3 = ss1.clone(); ss3.merge(ss2); ss3.addMany(["a", "b"]); console.log(ss3.toString()); // {"check","one","two","a","b","__proto__"} stringset-ccb4429c21f23e24d0fd8755373956db3c00798f/package.json000066400000000000000000000005351222104041600226670ustar00rootroot00000000000000{ "name": "stringset", "version": "0.2.1", "description": "fast and robust stringset", "main": "stringset.js", "repository": { "type": "git", "url": "https://github.com/olov/stringset.git" }, "keywords": [ "stringset", "set", "__proto__" ], "author": "Olov Lassus ", "license": "MIT" } stringset-ccb4429c21f23e24d0fd8755373956db3c00798f/stringset.js000066400000000000000000000133751222104041600227670ustar00rootroot00000000000000// stringset.js // MIT licensed, see LICENSE file // Copyright (c) 2013 Olov Lassus var StringSet = (function() { "use strict"; // to save us a few characters var hasOwnProperty = Object.prototype.hasOwnProperty; var create = (function() { function hasOwnEnumerableProps(obj) { for (var prop in obj) { if (hasOwnProperty.call(obj, prop)) { return true; } } return false; } // FF <= 3.6: // o = {}; o.hasOwnProperty("__proto__" or "__count__" or "__parent__") => true // o = {"__proto__": null}; Object.prototype.hasOwnProperty.call(o, "__proto__" or "__count__" or "__parent__") => false function hasOwnPollutedProps(obj) { return hasOwnProperty.call(obj, "__count__") || hasOwnProperty.call(obj, "__parent__"); } var useObjectCreate = false; if (typeof Object.create === "function") { if (!hasOwnEnumerableProps(Object.create(null))) { useObjectCreate = true; } } if (useObjectCreate === false) { if (hasOwnEnumerableProps({})) { throw new Error("StringSet environment error 0, please file a bug at https://github.com/olov/stringset/issues"); } } // no throw yet means we can create objects without own enumerable props (safe-guard against VMs and shims) var o = (useObjectCreate ? Object.create(null) : {}); var useProtoClear = false; if (hasOwnPollutedProps(o)) { o.__proto__ = null; if (hasOwnEnumerableProps(o) || hasOwnPollutedProps(o)) { throw new Error("StringSet environment error 1, please file a bug at https://github.com/olov/stringset/issues"); } useProtoClear = true; } // no throw yet means we can create objects without own polluted props (safe-guard against VMs and shims) return function() { var o = (useObjectCreate ? Object.create(null) : {}); if (useProtoClear) { o.__proto__ = null; } return o; }; })(); // stringset ctor function stringset(optional_array) { // use with or without new if (!(this instanceof stringset)) { return new stringset(optional_array); } this.obj = create(); this.hasProto = false; // false (no __proto__ item) or true (has __proto__ item) if (optional_array) { this.addMany(optional_array); } }; // primitive methods that deals with data representation stringset.prototype.has = function(item) { // The type-check of item in has, get, set and delete is important because otherwise an object // {toString: function() { return "__proto__"; }} can avoid the item === "__proto__" test. // The alternative to type-checking would be to force string conversion, i.e. item = String(item); if (typeof item !== "string") { throw new Error("StringSet expected string item"); } return (item === "__proto__" ? this.hasProto : hasOwnProperty.call(this.obj, item)); }; stringset.prototype.add = function(item) { if (typeof item !== "string") { throw new Error("StringSet expected string item"); } if (item === "__proto__") { this.hasProto = true; } else { this.obj[item] = true; } }; stringset.prototype.remove = function(item) { if (typeof item !== "string") { throw new Error("StringSet expected string item"); } var didExist = this.has(item); if (item === "__proto__") { this.hasProto = false; } else { delete this.obj[item]; } return didExist; }; // alias remove to delete but beware: // ss.delete("key"); // OK in ES5 and later // ss['delete']("key"); // OK in all ES versions // ss.remove("key"); // OK in all ES versions stringset.prototype['delete'] = stringset.prototype.remove; stringset.prototype.isEmpty = function() { for (var item in this.obj) { if (hasOwnProperty.call(this.obj, item)) { return false; } } return !this.hasProto; }; stringset.prototype.size = function() { var len = 0; for (var item in this.obj) { if (hasOwnProperty.call(this.obj, item)) { ++len; } } return (this.hasProto ? len + 1 : len); }; stringset.prototype.items = function() { var items = []; for (var item in this.obj) { if (hasOwnProperty.call(this.obj, item)) { items.push(item); } } if (this.hasProto) { items.push("__proto__"); } return items; }; // methods that rely on the above primitives stringset.prototype.addMany = function(items) { if (!Array.isArray(items)) { throw new Error("StringSet expected array"); } for (var i = 0; i < items.length; i++) { this.add(items[i]); } return this; }; stringset.prototype.merge = function(other) { this.addMany(other.items()); return this; }; stringset.prototype.clone = function() { var other = stringset(); return other.merge(this); }; stringset.prototype.toString = function() { return "{" + this.items().map(JSON.stringify).join(",") + "}"; }; return stringset; })(); if (typeof module !== "undefined" && typeof module.exports !== "undefined") { module.exports = StringSet; }