Skip to content

Commit ce1bb46

Browse files
author
Yehor Khilchenko
committed
support iterable objects: String Map Set
I added support for iterable objects using [Symbol.iterator], also tests are written
1 parent 8ad8ab6 commit ce1bb46

11 files changed

+882
-106
lines changed

lib/array.js

Lines changed: 119 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@
22

33
const common = require('@metarhia/common');
44

5+
const copy = name => {
6+
switch (name) {
7+
case 'Set':
8+
return new Set();
9+
case 'Map':
10+
return new Map();
11+
case 'Array':
12+
return [];
13+
case 'String':
14+
return '';
15+
}
16+
return null;
17+
};
18+
519
// Asynchronous map (iterate parallel)
620
// items - <Array>, incoming
721
// fn - <Function>, to be executed for each value in the array
@@ -12,31 +26,47 @@ const common = require('@metarhia/common');
1226
// done - <Function>, on done, optional
1327
// err - <Error> | <null>
1428
// result - <Array>
15-
const map = (items, fn, done) => {
29+
const map = (
30+
// Asynchronous map (iterate parallel)
31+
items, // array, incoming
32+
fn, // function, (current, callback) => callback(err, value)
33+
// to be executed for each value in the array
34+
// current - current element being processed in the array
35+
// callback - function(err, value)
36+
done // function (optional), on done callback function(err, result)
37+
) => {
1638
done = done || common.emptyness;
17-
const len = items.length;
18-
if (!len) {
19-
done(null, []);
39+
const len = items.length || items.size;
40+
const name = items.constructor.name;
41+
let result = copy(name);
42+
if (!len || !result) {
43+
done(null, result);
2044
return;
2145
}
2246
let errored = false;
2347
let count = 0;
24-
const result = new Array(len);
48+
const data = items[Symbol.iterator]();
2549

26-
const next = (index, err, value) => {
50+
const next = (err, value) => {
2751
if (errored) return;
2852
if (err) {
2953
errored = true;
3054
done(err);
3155
return;
3256
}
33-
result[index] = value;
57+
if (name === 'Array') result.push(value);
58+
else if (name === 'Set') result.add(value);
59+
else if (name === 'Map') result.set(value[0], value[1]);
60+
else result += value;
3461
count++;
3562
if (count === len) done(null, result);
3663
};
3764

38-
for (let i = 0; i < len; i++) {
39-
fn(items[i], next.bind(null, i));
65+
let i = 0;
66+
while (i < len) {
67+
const item = data.next();
68+
fn(item.value, next);
69+
i++;
4070
}
4171
};
4272

@@ -59,8 +89,13 @@ const asyncMap = (items, fn, options = {}, done) => {
5989
options = DEFAULT_OPTIONS;
6090
}
6191

62-
if (!items.length) {
63-
if (done) done(null, []);
92+
const len = items.length || items.size;
93+
const name = items.constructor.name;
94+
let result = done ? copy(name) : null;
95+
const data = items[Symbol.iterator]();
96+
97+
if (!len || !result) {
98+
if (done) done(null, result);
6499
return;
65100
}
66101

@@ -71,7 +106,6 @@ const asyncMap = (items, fn, options = {}, done) => {
71106
let sum = 0;
72107
let count = 0;
73108

74-
const result = done ? new Array(items.length) : null;
75109
const ratio = percent / (1 - percent);
76110

77111
const countNumber = () => {
@@ -83,16 +117,21 @@ const asyncMap = (items, fn, options = {}, done) => {
83117

84118
const next = () => {
85119
const itemsNumber = count ? countNumber() : min;
86-
const iterMax = Math.min(items.length, itemsNumber + count);
120+
const iterMax = Math.min(len, itemsNumber + count);
87121

88122
begin = Date.now();
89123
for (; count < iterMax; count++) {
90-
const itemResult = fn(items[count], count);
91-
if (done) result[count] = itemResult;
124+
const itemResult = fn(data.next().value, count);
125+
if (done) {
126+
if (name === 'Array') result.push(itemResult);
127+
else if (name === 'Set') result.add(itemResult);
128+
else if (name === 'Map') result.set(itemResult[0], itemResult[1]);
129+
else result += itemResult;
130+
}
92131
}
93132
sum += Date.now() - begin;
94133

95-
if (count < items.length) {
134+
if (count < len) {
96135
begin = Date.now();
97136
setTimeout(next, 0);
98137
} else if (done) {
@@ -115,39 +154,36 @@ const asyncMap = (items, fn, options = {}, done) => {
115154
// result - <Array>
116155
const filter = (items, fn, done) => {
117156
done = done || common.emptyness;
118-
const len = items.length;
157+
const len = items.length || items.size;
158+
const data = items[Symbol.iterator]();
159+
const name = items.constructor.name;
160+
let result = copy(name);
119161

120-
if (!len) {
121-
done(null, []);
162+
if (!len || !result) {
163+
done(null, result);
122164
return;
123165
}
124166

125167
let count = 0;
126-
let suitable = 0;
127-
const data = new Array(len);
128-
const rejected = Symbol('rejected');
129-
130-
const next = (index, err, accepted) => {
131-
if (!accepted || err) {
132-
data[index] = rejected;
133-
} else {
134-
data[index] = items[index];
135-
suitable++;
168+
169+
const next = (value, err, accepted) => {
170+
if (accepted && !err) {
171+
if (name === 'Array') result.push(value);
172+
else if (name === 'Set') result.add(value);
173+
else if (name === 'Map') result.set(value[0], value[1]);
174+
else result += value;
136175
}
137176
count++;
138177
if (count === len) {
139-
const result = new Array(suitable);
140-
let pos = 0;
141-
for (let i = 0; i < len; i++) {
142-
const val = data[i];
143-
if (val !== rejected) result[pos++] = val;
144-
}
145178
done(null, result);
146179
}
147180
};
148181

149-
for (let i = 0; i < len; i++) {
150-
fn(items[i], next.bind(null, i));
182+
let i = 0;
183+
while (i < len) {
184+
const item = data.next();
185+
fn(item.value, next.bind(null, item.value));
186+
i++;
151187
}
152188
};
153189

@@ -173,7 +209,8 @@ const REDUCE_EMPTY_ARR =
173209
// argument in first iteration
174210
const reduce = (items, fn, done, initial) => {
175211
done = done || common.emptyness;
176-
const len = items.length;
212+
const len = items.length || items.size || 0;
213+
items = [...items];
177214
const hasInitial = typeof initial !== 'undefined';
178215

179216
if (len === 0 && !hasInitial) {
@@ -231,7 +268,8 @@ const REDUCE_RIGHT_EMPTY_ARR =
231268
// argument in first iteration
232269
const reduceRight = (items, fn, done, initial) => {
233270
done = done || common.emptyness;
234-
const len = items.length;
271+
const len = items.length || items.size || 0;
272+
items = [...items];
235273
const hasInitial = typeof initial !== 'undefined';
236274

237275
if (len === 0 && !hasInitial) {
@@ -276,10 +314,17 @@ const reduceRight = (items, fn, done, initial) => {
276314
// done - <Function>, on done, optional
277315
// err - <Error> | <null>
278316
// items - <Array>
279-
const each = (items, fn, done) => {
317+
const each = (
318+
// Asynchronous each (iterate in parallel)
319+
items, // array, incoming
320+
fn, // function, (value, callback) => callback(err)
321+
// value - item from items array
322+
// callback - callback function(err)
323+
done // function (optional), on done callback function(err, items)
324+
) => {
280325
done = done || common.emptyness;
281-
const len = items.length;
282-
if (len === 0) {
326+
const len = items.length || items.size;
327+
if (!len) {
283328
done(null, items);
284329
return;
285330
}
@@ -297,9 +342,7 @@ const each = (items, fn, done) => {
297342
if (count === len) done(null);
298343
};
299344

300-
for (let i = 0; i < len; i++) {
301-
fn(items[i], next);
302-
}
345+
for (const item of items) fn(item, next);
303346
};
304347

305348
// Asynchronous series
@@ -311,9 +354,17 @@ const each = (items, fn, done) => {
311354
// done - <Function>, on done, optional
312355
// err - <Error> | <null>
313356
// items - <Array>
314-
const series = (items, fn, done) => {
357+
const series = (
358+
// Asynchronous series
359+
items, // array, incoming
360+
fn, // function, (value, callback) => callback(err)
361+
// value - item from items array
362+
// callback - callback (err)
363+
done // function (optional), on done callback (err, items)
364+
) => {
315365
done = done || common.emptyness;
316-
const len = items.length;
366+
const len = items.length || items.size;
367+
const data = items[Symbol.iterator]();
317368
let i = -1;
318369

319370
const next = () => {
@@ -322,7 +373,7 @@ const series = (items, fn, done) => {
322373
done(null, items);
323374
return;
324375
}
325-
fn(items[i], err => {
376+
fn(data.next().value, err => {
326377
if (err) {
327378
done(err);
328379
return;
@@ -345,15 +396,16 @@ const series = (items, fn, done) => {
345396
// result - <any>
346397
const find = (items, fn, done) => {
347398
done = done || common.emptyness;
348-
const len = items.length;
349-
if (len === 0) {
399+
const len = items.length || items.size;
400+
const data = items[Symbol.iterator]();
401+
if (!len) {
350402
done();
351403
return;
352404
}
353405
let finished = false;
354406
const last = len - 1;
355407

356-
const next = (index, err, accepted) => {
408+
const next = (index, item, err, accepted) => {
357409
if (finished) return;
358410
if (err) {
359411
finished = true;
@@ -362,14 +414,15 @@ const find = (items, fn, done) => {
362414
}
363415
if (accepted) {
364416
finished = true;
365-
done(null, items[index]);
417+
done(null, item);
366418
return;
367419
}
368420
if (index === last) done(null);
369421
};
370422

371423
for (let i = 0; i < len; i++) {
372-
fn(items[i], next.bind(null, i));
424+
const item = data.next().value;
425+
fn(item, next.bind(null, i, item));
373426
}
374427
};
375428

@@ -383,14 +436,21 @@ const find = (items, fn, done) => {
383436
// done - <Function>, on done, optional
384437
// err - <Error> | <null>
385438
// result - <boolean>
386-
const every = (items, fn, done) => {
439+
const every = (
440+
// Asynchronous every
441+
items, // array, incoming
442+
fn, // function, (value, callback) => callback(err, fits)
443+
// value - item from items array
444+
// callback - callback function(err, fits)
445+
done // function, optional on done callback function(err, result)
446+
) => {
387447
done = done || common.emptyness;
388-
if (items.length === 0) {
448+
const len = items.length || items.size;
449+
if (!len) {
389450
done(null, true);
390451
return;
391452
}
392453
let proceedItemsCount = 0;
393-
const len = items.length;
394454

395455
const finish = (err, accepted) => {
396456
if (!done) return;
@@ -402,7 +462,6 @@ const every = (items, fn, done) => {
402462
proceedItemsCount++;
403463
if (proceedItemsCount === len) done(null, true);
404464
};
405-
406465
for (const item of items) fn(item, finish);
407466
};
408467

@@ -418,15 +477,16 @@ const every = (items, fn, done) => {
418477
// result - <boolean>
419478
const some = (items, fn, done) => {
420479
done = done || common.emptyness;
421-
const len = items.length;
480+
const len = items.length || items.size;
481+
const data = items[Symbol.iterator]();
422482
let i = 0;
423483

424484
const next = () => {
425485
if (i === len) {
426486
done(null, false);
427487
return;
428488
}
429-
fn(items[i], (err, accepted) => {
489+
fn(data.next().value, (err, accepted) => {
430490
if (err) {
431491
done(err);
432492
return;

0 commit comments

Comments
 (0)