summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjmoenig <jens@moenig.org>2014-07-17 08:45:43 +0200
committerjmoenig <jens@moenig.org>2014-07-17 08:45:43 +0200
commitfe8f15b8c7a12b8a5d5d6c15cdc19cde4a2838bc (patch)
tree9168a3595ae3b08a07b3c268b279eafa8a53d1f8
parent4fa53772f5f60cb4e3a0a0c34ecf56836e2f13ca (diff)
downloadsnap-byow-fe8f15b8c7a12b8a5d5d6c15cdc19cde4a2838bc.tar.gz
snap-byow-fe8f15b8c7a12b8a5d5d6c15cdc19cde4a2838bc.zip
change internal list ops to be iterative (bh)
so working with large arrayed lists no longer runs into JS’s maximum recursion limit. Thanks, Brian, for the quick fix!
-rw-r--r--lists.js122
1 files changed, 79 insertions, 43 deletions
diff --git a/lists.js b/lists.js
index ea553b0..d9af5b5 100644
--- a/lists.js
+++ b/lists.js
@@ -132,19 +132,19 @@ List.prototype.cons = function (car, cdr) {
};
List.prototype.cdr = function () {
- function helper(i) {
- if (i > this.contents.length) {
- return new List();
- }
- return this.cons(this.at(i), helper.call(this, i + 1));
- }
+ var result, i;
if (this.isLinked) {
return this.rest || new List();
}
if (this.contents.length < 2) {
return new List();
}
- return helper.call(this, 2);
+
+ result = new List();
+ for (i = this.contents.length; i > 1; i -= 1) {
+ result = this.cons(this.at(i), result);
+ }
+ return result;
};
// List array setters:
@@ -193,32 +193,41 @@ List.prototype.clear = function () {
List.prototype.length = function () {
if (this.isLinked) {
- return (this.first === undefined ? 0 : 1)
- + (this.rest ? this.rest.length() : 0);
+ var pair = this,
+ result = 0;
+ while (pair.isLinked) {
+ result += 1;
+ pair = pair.rest;
+ }
+ return result + pair.contents.length;
}
return this.contents.length;
};
List.prototype.at = function (index) {
- var value, idx = +index;
- if (this.isLinked) {
- return idx === 1 ? this.first : this.rest.at(idx - 1);
+ var value, idx = +index, pair = this;
+ while (pair.isLinked) {
+ if (idx > 1) {
+ pair = pair.rest;
+ idx -= 1;
+ } else {
+ return pair.first;
+ }
}
- value = this.contents[idx - 1];
+ value = pair.contents[idx - 1];
return isNil(value) ? '' : value;
};
List.prototype.contains = function (element) {
- if (this.isLinked) {
+ var pair = this;
+ while (pair.isLinked) {
if (snapEquals(this.first, element)) {
return true;
}
- if (this.rest instanceof List) {
- return this.rest.contains(element);
- }
+ pair = pair.rest;
}
// in case I'm arrayed
- return this.contents.some(function (any) {
+ return pair.contents.some(function (any) {
return snapEquals(any, element);
});
};
@@ -233,11 +242,23 @@ List.prototype.asArray = function () {
List.prototype.asText = function () {
var result = '',
- length = this.length(),
+ length,
element,
+ pair = this,
i;
+ while (pair.isLinked) {
+ element = this.first;
+ if (element instanceof List) {
+ result = result.concat(element.asText());
+ } else {
+ element = isNil(element) ? '' : element.toString();
+ result = result.concat(element);
+ }
+ pair = pair.rest;
+ }
+ length = pair.length();
for (i = 1; i <= length; i += 1) {
- element = this.at(i);
+ element = pair.at(i);
if (element instanceof List) {
result = result.concat(element.asText());
} else {
@@ -250,13 +271,18 @@ List.prototype.asText = function () {
List.prototype.becomeArray = function () {
if (this.isLinked) {
- var next = this;
+ var next = this, i;
this.contents = [];
- while (next instanceof List && (next.length() > 0)) {
- this.contents.push(next.at(1));
- next = next.cdr();
+ while (next.isLinked) {
+ this.contents.push(next.first);
+ next = next.rest;
+ }
+ for (i = 1; i <= next.contents.length; i += 1) {
+ this.contents.push(next.at(i));
}
this.isLinked = false;
+ this.first = null;
+ this.rest = null;
}
};
@@ -278,37 +304,47 @@ List.prototype.becomeLinked = function () {
// List testing
List.prototype.equalTo = function (other) {
- var i;
+ var me = this, it = other, i, j, loopcount;
if (!(other instanceof List)) {
return false;
}
- if ((!this.isLinked) && (!other.isLinked)) {
- if (this.length() === 0 && (other.length() === 0)) {
- return true;
- }
- if (this.length() !== other.length()) {
+
+ while (me.isLinked && it.isLinked) {
+ if (!snapEquals(me.first, it.first)) {
return false;
}
- for (i = 0; i < this.length(); i += 1) {
- if (!snapEquals(this.contents[i], other.contents[i])) {
- return false;
- }
- }
- return true;
+ me = me.rest;
+ it = it.rest;
}
- if ((this.isLinked) && (other.isLinked)) {
- if (snapEquals(this.at(1), other.at(1))) {
- return this.cdr().equalTo(other.cdr());
+
+ if (it.isLinked) {
+ i = it;
+ it = me;
+ me = i;
+ }
+
+ j = 0;
+ while (me.isLinked) {
+ if (!snapEquals(me.first, it.contents[j])) {
+ return false;
}
- return false;
+ me = me.rest;
+ j += 1;
}
- if (this.length() !== other.length()) {
+
+ i = 0;
+ if (me.contents.length !== (it.contents.length - j)) {
return false;
}
- for (i = 1; i <= this.length(); i += 1) {
- if (!snapEquals(this.at(i), other.at(i))) {
+
+ loopcount = me.contents.length;
+ while (loopcount > 0) {
+ loopcount -= 1;
+ if (!snapEquals(me.contents[i], it.contents[j])) {
return false;
}
+ i += 1;
+ j += 1;
}
return true;
};