6 var Symbol = require('es6-symbol');
7 var debug = require('debug')('array-index');
9 var get = Symbol('get');
10 var set = Symbol('set');
11 var length = Symbol('length');
14 * JavaScript Array "length" is bound to an unsigned 32-bit int.
15 * See: http://stackoverflow.com/a/6155063/376773
18 var MAX_LENGTH = Math.pow(2, 32);
24 module.exports = ArrayIndex;
32 function ArrayIndex (_length) {
33 Object.defineProperty(this, 'length', {
42 if (arguments.length > 0) {
43 setLength.call(this, _length);
48 * You overwrite the "get" Symbol in your subclass.
51 ArrayIndex.prototype[ArrayIndex.get] = function () {
52 throw new Error('you must implement the `ArrayIndex.get` Symbol');
56 * You overwrite the "set" Symbol in your subclass.
59 ArrayIndex.prototype[ArrayIndex.set] = function () {
60 throw new Error('you must implement the `ArrayIndex.set` Symbol');
64 * Converts this array class into a real JavaScript Array. Note that this
65 * is a "flattened" array and your defined getters and setters won't be invoked
66 * when you interact with the returned Array. This function will call the
67 * getter on every array index of the object.
69 * @return {Array} The flattened array
73 ArrayIndex.prototype.toArray = function toArray () {
76 var array = new Array(l);
84 * Basic support for `JSON.stringify()`.
87 ArrayIndex.prototype.toJSON = function toJSON () {
88 return this.toArray();
92 * toString() override. Use Array.prototype.toString().
95 ArrayIndex.prototype.toString = function toString () {
96 var a = this.toArray();
97 return a.toString.apply(a, arguments);
101 * inspect() override. For the REPL.
104 ArrayIndex.prototype.inspect = function inspect () {
105 var a = this.toArray();
106 Object.keys(this).forEach(function (k) {
113 * Getter for the "length" property.
114 * Returns the value of the "length" Symbol.
117 function getLength () {
118 debug('getting "length": %o', this[length]);
123 * Setter for the "length" property.
124 * Calls "ensureLength()", then sets the "length" Symbol.
127 function setLength (v) {
128 debug('setting "length": %o', v);
129 return this[length] = ensureLength(this, v);
133 * Ensures that getters/setters from 0 up to "_newLength" have been defined
134 * on `Object.getPrototypeOf(this)`.
139 function ensureLength (self, _newLength) {
141 if (_newLength > MAX_LENGTH) {
142 newLength = MAX_LENGTH;
144 newLength = _newLength | 0;
146 var proto = Object.getPrototypeOf(self);
147 var cur = proto[length] | 0;
148 var num = newLength - cur;
151 debug('creating a descriptor object with %o entries', num);
152 for (var i = cur; i < newLength; i++) {
155 debug('calling `Object.defineProperties()` with %o entries', num);
156 Object.defineProperties(proto, desc);
157 proto[length] = newLength;
163 * Returns a property descriptor for the given "index", with "get" and "set"
164 * functions created within the closure.
169 function setup (index) {
171 return this[ArrayIndex.get](index);
174 return this[ArrayIndex.set](index, v);