Skip to content

Commit 88bcf94

Browse files
author
Kjerand Pedersen
committed
optimisations
1 parent cb2597d commit 88bcf94

File tree

6 files changed

+256
-14
lines changed

6 files changed

+256
-14
lines changed

src/functions.js

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import { Vector } from './vector';
22
import { Matrix } from './matrix';
33
import { flatten } from './array';
44
import op from './math';
5-
5+
import {
6+
constantIterator,
7+
combinedIterator,
8+
arrayIterator,
9+
} from './utils';
610
import {
711
DEG2RAD,
812
RAD2DEG,
@@ -73,14 +77,25 @@ export function mix(a, b, t) {
7377
if (a.constructor !== b.constructor)
7478
throw Error('Unable to mix different types!');
7579

76-
const va = standardizeArgument(a);
77-
const vb = standardizeArgument(b);
78-
79-
if (va.length !== vb.length)
80-
throw Error('Values must have the same number of components!');
81-
82-
const ts = standardizeArgument(t);
83-
const mixed = va.map((v, i) => op.mix(v, vb[i], i < ts.length ? ts[i] : ts[0]));
80+
const mixed = [];
81+
const iterators = [
82+
arrayIterator(a._values),
83+
arrayIterator(b._values),
84+
t._values ? arrayIterator(t._values) : constantIterator(t),
85+
];
86+
const itr = () => {
87+
const va = iterators[0].next();
88+
if (!va.done) {
89+
const vb = iterators[1].next();
90+
if (!vb.done) {
91+
const vt = iterators[2].next();
92+
mixed.push(op.mix(va.value, vb.value, vt.value));
93+
return true;
94+
}
95+
}
96+
return false;
97+
};
98+
while (itr());
8499

85100
if (Array.isArray(a)) {
86101
return mixed;
@@ -94,8 +109,13 @@ export function clamp(val, min = 0, max = 1) {
94109
if (op.isDefined(val)) {
95110
return op.clamp(val, min, max);
96111
}
97-
const arr = standardizeArgument(val);
98-
const clamped = arr.map(v => op.clamp(v, min, max));
112+
const itr = arrayIterator(val._values || val);
113+
let v = itr.next();
114+
const clamped = [];
115+
while (!v.done) {
116+
clamped.push(op.clamp(v.value, min, max));
117+
v = itr.next();
118+
}
99119
if (Array.isArray(val)) return clamped;
100120

101121
return val.clone().copyFrom(clamped);

src/matrix.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,32 @@ export class Matrix {
254254
get size() {
255255
return [this.rows, this.cols];
256256
}
257+
258+
get count() {
259+
return this.rows * this.cols;
260+
}
261+
262+
iterator() {
263+
const _t = this;
264+
let r = 0;
265+
let c = 0;
266+
return {
267+
next: () => {
268+
if (c >= this.cols) {
269+
r++;
270+
c = 0;
271+
}
272+
let v;
273+
if (r < this.rows) {
274+
v = _t[r][c++];
275+
}
276+
return {
277+
value: v,
278+
done: v === undefined,
279+
};
280+
},
281+
};
282+
}
257283
}
258284

259285
// add extra accessors

src/utils.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,75 @@ export function range(size, start = 0, step = 1) {
1818
}
1919
return arr;
2020
}
21+
22+
export function constantIterator(value, times = Infinity) {
23+
let i = 0;
24+
return {
25+
next: () => (i++ < times ? ({
26+
value,
27+
done: false,
28+
}) : ({ value: undefined, done: true })),
29+
};
30+
}
31+
32+
function array2dIterator(arr) {
33+
let r = 0;
34+
let c = 0;
35+
const last = arr.length - 1;
36+
return {
37+
next: () => {
38+
let value;
39+
const done = r > last;
40+
if (!done) {
41+
value = arr[r][c];
42+
c++;
43+
if (c >= arr[r].length) {
44+
r++;
45+
c = 0;
46+
}
47+
}
48+
return {
49+
value,
50+
done,
51+
};
52+
},
53+
};
54+
}
55+
56+
export function arrayIterator(arr) {
57+
if (arr[0] && Array.isArray(arr[0])) return array2dIterator(arr);
58+
let i = 0;
59+
return {
60+
next: () => {
61+
const value = arr[i];
62+
const done = i >= arr.length;
63+
i++;
64+
return {
65+
value,
66+
done,
67+
};
68+
},
69+
};
70+
}
71+
72+
export function combinedIterator(...iterators) {
73+
const value = new Array(iterators.length);
74+
let done = false;
75+
const iterate = () => {
76+
for (let i = 0; i < iterators.length; i++) {
77+
const _c = iterators[i].next();
78+
if (_c.done) {
79+
done = true;
80+
break;
81+
}
82+
value[i] = _c.value;
83+
}
84+
return {
85+
value,
86+
done,
87+
};
88+
};
89+
return {
90+
next: iterate,
91+
};
92+
}

src/vector.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,24 @@ export class Vector {
205205
const squared = this._values.reduce((acc, c) => acc + c ** 2, 0);
206206
return Math.sqrt(squared);
207207
}
208+
209+
get count() {
210+
return this.cols;
211+
}
212+
213+
iterator() {
214+
const _t = this;
215+
let i = 0;
216+
return {
217+
next: () => {
218+
const v = i >= this.cols ? undefined : _t[i++];
219+
return {
220+
value: v,
221+
done: v === undefined,
222+
};
223+
},
224+
};
225+
}
208226
}
209227

210228
// add getters and setters from accessors

test/benchmark.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { vec2 } from '../src/vector';
33
import { mix, dot } from '../src/functions';
44
import { range } from '../src/utils';
55

6+
const steps = 1000;
7+
68
const T = mat3(
79
0, -2, 3,
810
2, 0, 2,
@@ -11,8 +13,6 @@ const T = mat3(
1113

1214
const v = vec2(-1, -2);
1315
const columns = 20;
14-
const steps = 1;
15-
1616
const w = 1000;
1717
const h = w * 0.75;
1818
const u = Math.ceil(w / columns);

test/utils.spec.js

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import expect from 'expect';
2-
import { argumentsToList } from '../src/utils';
2+
import {
3+
argumentsToList,
4+
constantIterator,
5+
combinedIterator,
6+
arrayIterator,
7+
} from '../src/utils';
38
import { vec2, vec4 } from '../src/vector';
49

510
describe('Utils functions', () => {
@@ -10,4 +15,105 @@ describe('Utils functions', () => {
1015
expect(argumentsToList([1, vec2(2, 3)])).toEqual([1, 2, 3]);
1116
expect(argumentsToList(vec4(1, 2, 3, 4))).toEqual([1, 2, 3, 4]);
1217
});
18+
19+
it('Can create iterator out of constants', () => {
20+
const a = 5;
21+
const itr = constantIterator(a, 5);
22+
23+
let current = itr.next();
24+
expect(current.value).toBe(a);
25+
expect(current.done).toBeFalsy();
26+
current = itr.next();
27+
expect(current.value).toBe(a);
28+
expect(current.done).toBeFalsy();
29+
current = itr.next();
30+
expect(current.value).toBe(a);
31+
expect(current.done).toBeFalsy();
32+
current = itr.next();
33+
expect(current.value).toBe(a);
34+
expect(current.done).toBeFalsy();
35+
current = itr.next();
36+
expect(current.value).toBe(a);
37+
expect(current.done).toBeFalsy();
38+
current = itr.next();
39+
expect(current.done).toBeTruthy();
40+
expect(current.value).toBeUndefined;
41+
current = itr.next();
42+
expect(current.done).toBeTruthy();
43+
expect(current.value).toBeUndefined;
44+
});
45+
46+
it('Can create iterator out of arrays', () => {
47+
const arr = [1, 2, 3, 4, 5];
48+
const itr = arrayIterator(arr);
49+
50+
let current = itr.next();
51+
expect(current.value).toBe(1);
52+
expect(current.done).toBeFalsy();
53+
current = itr.next();
54+
expect(current.value).toBe(2);
55+
expect(current.done).toBeFalsy();
56+
current = itr.next();
57+
expect(current.value).toBe(3);
58+
expect(current.done).toBeFalsy();
59+
current = itr.next();
60+
expect(current.value).toBe(4);
61+
expect(current.done).toBeFalsy();
62+
current = itr.next();
63+
expect(current.value).toBe(5);
64+
expect(current.done).toBeFalsy();
65+
current = itr.next();
66+
expect(current.done).toBeTruthy();
67+
expect(current.value).toBeUndefined;
68+
current = itr.next();
69+
expect(current.done).toBeTruthy();
70+
expect(current.value).toBeUndefined;
71+
});
72+
73+
it('Can create iterator out of 2d arrays', () => {
74+
const arr = [[1, 2], [3, 4], [5]];
75+
const itr = arrayIterator(arr);
76+
77+
let current = itr.next();
78+
expect(current.value).toBe(1);
79+
expect(current.done).toBeFalsy();
80+
current = itr.next();
81+
expect(current.value).toBe(2);
82+
expect(current.done).toBeFalsy();
83+
current = itr.next();
84+
expect(current.value).toBe(3);
85+
expect(current.done).toBeFalsy();
86+
current = itr.next();
87+
expect(current.value).toBe(4);
88+
expect(current.done).toBeFalsy();
89+
current = itr.next();
90+
expect(current.value).toBe(5);
91+
expect(current.done).toBeFalsy();
92+
current = itr.next();
93+
expect(current.done).toBeTruthy();
94+
expect(current.value).toBeUndefined;
95+
current = itr.next();
96+
expect(current.done).toBeTruthy();
97+
expect(current.value).toBeUndefined;
98+
});
99+
100+
it('Can combine and traverse multiple iterators', () => {
101+
const a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
102+
const b = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
103+
const t = 3;
104+
105+
const itr = combinedIterator(
106+
arrayIterator(a),
107+
arrayIterator(b),
108+
constantIterator(t),
109+
);
110+
let i = 1;
111+
let current = itr.next();
112+
while (!current.done) {
113+
expect(current.value).toEqual([i, i, 3]);
114+
current = itr.next();
115+
i++;
116+
}
117+
expect(i).toBe(10);
118+
});
13119
});

0 commit comments

Comments
 (0)