Commit f1a22d96 authored by Julien Puydt's avatar Julien Puydt

Imported Upstream version 0.2.1+20130926

parents
Copyright (c) 2013 Olov Lassus <olov.lassus@gmail.com>
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.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
<script src="stringset/stringset.js"></script>
```
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__"}
{
"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 <olov.lassus@gmail.com>",
"license": "MIT"
}
// stringset.js
// MIT licensed, see LICENSE file
// Copyright (c) 2013 Olov Lassus <olov.lassus@gmail.com>
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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment