pax_global_header00006660000000000000000000000064122210375060014510gustar00rootroot0000000000000052 comment=2dfa23e26632767fc06eafc8894b5b1527fc9277 stringmap-2dfa23e26632767fc06eafc8894b5b1527fc9277/000077500000000000000000000000001222103750600204605ustar00rootroot00000000000000stringmap-2dfa23e26632767fc06eafc8894b5b1527fc9277/LICENSE000066400000000000000000000020671222103750600214720ustar00rootroot00000000000000Copyright (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. stringmap-2dfa23e26632767fc06eafc8894b5b1527fc9277/README.md000066400000000000000000000034001222103750600217340ustar00rootroot00000000000000# stringmap.js A fast and robust stringmap implementation that can hold any string keys, 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 Map API as possible. Prefer `sm.remove("key")` for deleting a key. ES6 Map uses `map.delete("key")` instead and for that reason `sm['delete']("key")` is available as a stringmap alias as well. Never do `sm.delete("key")` unless you're certain to be in the land of ES5 or later. ## Examples Available in `examples.js` ```javascript var StringMap = require("stringmap"); var sm1 = new StringMap(); sm1.set("greeting", "yoyoma"); sm1.set("check", true); sm1.set("__proto__", -1); console.log(sm1.has("greeting")); // true console.log(sm1.get("__proto__")); // -1 sm1.remove("greeting"); console.log(sm1.keys()); // [ 'check', '__proto__' ] console.log(sm1.values()); // [ true, -1 ] console.log(sm1.items()); // [ [ 'check', true ], [ '__proto__', -1 ] ] console.log(sm1.toString()); // {"check":true,"__proto__":-1} var sm2 = new StringMap({ one: 1, two: 2, }); console.log(sm2.map(function(value, key) { return value * value; })); // [ 1, 4 ] sm2.forEach(function(value, key) { // ... }); console.log(sm2.isEmpty()); // false console.log(sm2.size()); // 2 var sm3 = sm1.clone(); sm3.merge(sm2); sm3.setMany({ a: {}, b: [], }); console.log(sm3.toString()); // {"check":true,"one":1,"two":2,"a":{},"b":[],"__proto__":-1} ``` ## Installation ### Node Install using npm npm install stringmap ```javascript var StringMap = require("stringmap"); ``` ### Browser Clone the repo and include it in a script tag git clone https://github.com/olov/stringmap.git ```html ``` stringmap-2dfa23e26632767fc06eafc8894b5b1527fc9277/examples.js000066400000000000000000000016241222103750600226370ustar00rootroot00000000000000var StringMap = require("./stringmap"); var sm1 = new StringMap(); sm1.set("greeting", "yoyoma"); sm1.set("check", true); sm1.set("__proto__", -1); console.log(sm1.has("greeting")); // true console.log(sm1.get("__proto__")); // -1 sm1.remove("greeting"); console.log(sm1.keys()); // [ 'check', '__proto__' ] console.log(sm1.values()); // [ true, -1 ] console.log(sm1.items()); // [ [ 'check', true ], [ '__proto__', -1 ] ] console.log(sm1.toString()); // {"check":true,"__proto__":-1} var sm2 = new StringMap({ one: 1, two: 2, }); console.log(sm2.map(function(value, key) { return value * value; })); // [ 1, 4 ] sm2.forEach(function(value, key) { // ... }); console.log(sm2.isEmpty()); // false console.log(sm2.size()); // 2 var sm3 = sm1.clone(); sm3.merge(sm2); sm3.setMany({ a: {}, b: [], }); console.log(sm3.toString()); // {"check":true,"one":1,"two":2,"a":{},"b":[],"__proto__":-1} stringmap-2dfa23e26632767fc06eafc8894b5b1527fc9277/package.json000066400000000000000000000006131222103750600227460ustar00rootroot00000000000000{ "name": "stringmap", "version": "0.2.2", "description": "fast and robust stringmap", "main": "stringmap.js", "repository": { "type": "git", "url": "https://github.com/olov/stringmap.git" }, "keywords": [ "stringmap", "hashmap", "hash", "dict", "dictionary", "__proto__" ], "author": "Olov Lassus ", "license": "MIT" } stringmap-2dfa23e26632767fc06eafc8894b5b1527fc9277/stringmap.js000066400000000000000000000173101222103750600230240ustar00rootroot00000000000000// stringmap.js // MIT licensed, see LICENSE file // Copyright (c) 2013 Olov Lassus var StringMap = (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("StringMap environment error 0, please file a bug at https://github.com/olov/stringmap/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("StringMap environment error 1, please file a bug at https://github.com/olov/stringmap/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; }; })(); // stringmap ctor function stringmap(optional_object) { // use with or without new if (!(this instanceof stringmap)) { return new stringmap(optional_object); } this.obj = create(); this.hasProto = false; // false (no __proto__ key) or true (has __proto__ key) this.proto = undefined; // value for __proto__ key when hasProto is true, undefined otherwise if (optional_object) { this.setMany(optional_object); } }; // primitive methods that deals with data representation stringmap.prototype.has = function(key) { // The type-check of key in has, get, set and delete is important because otherwise an object // {toString: function() { return "__proto__"; }} can avoid the key === "__proto__" test. // The alternative to type-checking would be to force string conversion, i.e. key = String(key); if (typeof key !== "string") { throw new Error("StringMap expected string key"); } return (key === "__proto__" ? this.hasProto : hasOwnProperty.call(this.obj, key)); }; stringmap.prototype.get = function(key) { if (typeof key !== "string") { throw new Error("StringMap expected string key"); } return (key === "__proto__" ? this.proto : (hasOwnProperty.call(this.obj, key) ? this.obj[key] : undefined)); }; stringmap.prototype.set = function(key, value) { if (typeof key !== "string") { throw new Error("StringMap expected string key"); } if (key === "__proto__") { this.hasProto = true; this.proto = value; } else { this.obj[key] = value; } }; stringmap.prototype.remove = function(key) { if (typeof key !== "string") { throw new Error("StringMap expected string key"); } var didExist = this.has(key); if (key === "__proto__") { this.hasProto = false; this.proto = undefined; } else { delete this.obj[key]; } return didExist; }; // alias remove to delete but beware: // sm.delete("key"); // OK in ES5 and later // sm['delete']("key"); // OK in all ES versions // sm.remove("key"); // OK in all ES versions stringmap.prototype['delete'] = stringmap.prototype.remove; stringmap.prototype.isEmpty = function() { for (var key in this.obj) { if (hasOwnProperty.call(this.obj, key)) { return false; } } return !this.hasProto; }; stringmap.prototype.size = function() { var len = 0; for (var key in this.obj) { if (hasOwnProperty.call(this.obj, key)) { ++len; } } return (this.hasProto ? len + 1 : len); }; stringmap.prototype.keys = function() { var keys = []; for (var key in this.obj) { if (hasOwnProperty.call(this.obj, key)) { keys.push(key); } } if (this.hasProto) { keys.push("__proto__"); } return keys; }; stringmap.prototype.values = function() { var values = []; for (var key in this.obj) { if (hasOwnProperty.call(this.obj, key)) { values.push(this.obj[key]); } } if (this.hasProto) { values.push(this.proto); } return values; }; stringmap.prototype.items = function() { var items = []; for (var key in this.obj) { if (hasOwnProperty.call(this.obj, key)) { items.push([key, this.obj[key]]); } } if (this.hasProto) { items.push(["__proto__", this.proto]); } return items; }; // methods that rely on the above primitives stringmap.prototype.setMany = function(object) { if (object === null || (typeof object !== "object" && typeof object !== "function")) { throw new Error("StringMap expected Object"); } for (var key in object) { if (hasOwnProperty.call(object, key)) { this.set(key, object[key]); } } return this; }; stringmap.prototype.merge = function(other) { var keys = other.keys(); for (var i = 0; i < keys.length; i++) { var key = keys[i]; this.set(key, other.get(key)); } return this; }; stringmap.prototype.map = function(fn) { var keys = this.keys(); for (var i = 0; i < keys.length; i++) { var key = keys[i]; keys[i] = fn(this.get(key), key); // re-use keys array for results } return keys; }; stringmap.prototype.forEach = function(fn) { var keys = this.keys(); for (var i = 0; i < keys.length; i++) { var key = keys[i]; fn(this.get(key), key); } }; stringmap.prototype.clone = function() { var other = stringmap(); return other.merge(this); }; stringmap.prototype.toString = function() { var self = this; return "{" + this.keys().map(function(key) { return JSON.stringify(key) + ":" + JSON.stringify(self.get(key)); }).join(",") + "}"; }; return stringmap; })(); if (typeof module !== "undefined" && typeof module.exports !== "undefined") { module.exports = StringMap; }