Skip to content

Commit da08e79

Browse files
committed
Add support for creating a strided iterator from an array-like value
1 parent 4c830d8 commit da08e79

File tree

8 files changed

+1614
-0
lines changed

8 files changed

+1614
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
<!--
2+
3+
@license Apache-2.0
4+
5+
Copyright (c) 2018 The Stdlib Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
19+
-->
20+
21+
# Strided Iterator
22+
23+
> Create a strided [iterator][mdn-iterator-protocol] from an array-like value.
24+
25+
<!-- Section to include introductory text. Make sure to keep an empty line after the intro `section` element and another before the `/section` close. -->
26+
27+
<section class="intro">
28+
29+
</section>
30+
31+
<!-- /.intro -->
32+
33+
<!-- Package usage documentation. -->
34+
35+
<section class="usage">
36+
37+
## Usage
38+
39+
```javascript
40+
var array2stridediterator = require( '@stdlib/array/to-strided-iterator' );
41+
```
42+
43+
#### array2stridediterator( N, src, stride, offset\[, mapFcn\[, thisArg]] )
44+
45+
Returns a strided [iterator][mdn-iterator-protocol] which iterates over elements in an array-like value according to specified stride parameters.
46+
47+
```javascript
48+
var values = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
49+
50+
var N = 4;
51+
var stride = -2;
52+
var offset = 6;
53+
54+
var it = array2stridediterator( N, values, stride, offset );
55+
// returns <Object>
56+
57+
var v = it.next().value;
58+
// returns 7
59+
60+
v = it.next().value;
61+
// returns 5
62+
63+
v = it.next().value;
64+
// returns 3
65+
66+
// ...
67+
```
68+
69+
The returned [iterator][mdn-iterator-protocol] protocol-compliant object has the following properties:
70+
71+
- **next**: function which returns an [iterator][mdn-iterator-protocol] protocol-compliant object containing the next iterated value (if one exists) assigned to a `value` property and a `done` property having a `boolean` value indicating whether the [iterator][mdn-iterator-protocol] is finished.
72+
- **return**: function which closes an [iterator][mdn-iterator-protocol] and returns a single (optional) argument in an iterator protocol-compliant object.
73+
74+
To invoke a function for each `src` value, provide a callback function.
75+
76+
```javascript
77+
function fcn( v ) {
78+
return v * 10.0;
79+
}
80+
81+
var it = array2stridediterator( 4, [ 1, 2, 3, 4 ], 1, 0, fcn );
82+
// returns <Object>
83+
84+
var v = it.next().value;
85+
// returns 10.0
86+
87+
v = it.next().value;
88+
// returns 20.0
89+
90+
v = it.next().value;
91+
// returns 30.0
92+
93+
// ...
94+
```
95+
96+
The invoked function is provided four arguments:
97+
98+
- `value`: iterated value
99+
- `index`: iterated value index
100+
- `n`: iteration count
101+
- `src`: source array-like value
102+
103+
```javascript
104+
function fcn( v, i ) {
105+
return v * (i+1);
106+
}
107+
108+
var it = array2stridediterator( 4, [ 1, 2, 3, 4 ], 1, 0, fcn );
109+
// returns <Object>
110+
111+
var v = it.next().value;
112+
// returns 1
113+
114+
v = it.next().value;
115+
// returns 4
116+
117+
v = it.next().value;
118+
// returns 9
119+
120+
// ...
121+
```
122+
123+
To set the callback function execution context, provide a `thisArg`.
124+
125+
```javascript
126+
function fcn( v ) {
127+
this.count += 1;
128+
return v * 10.0;
129+
}
130+
131+
var ctx = {
132+
'count': 0
133+
};
134+
135+
var it = array2stridediterator( 4, [ 1, 2, 3, 4 ], 1, 0, fcn, ctx );
136+
// returns <Object>
137+
138+
var v = it.next().value;
139+
// returns 10.0
140+
141+
v = it.next().value;
142+
// returns 20.0
143+
144+
v = it.next().value;
145+
// returns 30.0
146+
147+
var count = ctx.count;
148+
// returns 3
149+
```
150+
151+
</section>
152+
153+
<!-- /.usage -->
154+
155+
<!-- Package usage notes. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
156+
157+
<section class="notes">
158+
159+
## Notes
160+
161+
- If an environment supports `Symbol.iterator`, the returned [iterator][mdn-iterator-protocol] is iterable.
162+
- If provided a generic `array`, the returned [iterator][mdn-iterator-protocol] does **not** ignore holes. To achieve greater performance for sparse arrays, use a custom [iterator][mdn-iterator-protocol].
163+
- A returned [iterator][mdn-iterator-protocol] does **not** copy a provided array-like `object`. To ensure iterable reproducibility, copy a provided array-like `object` **before** creating an [iterator][mdn-iterator-protocol]. Otherwise, any changes to the contents of an array-like `object` will be reflected in the returned [iterator][mdn-iterator-protocol].
164+
- In environments supporting `Symbol.iterator`, the function **explicitly** does **not** invoke an array's `@@iterator` method, regardless of whether this method is defined. To convert an array to an implementation defined [iterator][mdn-iterator-protocol], invoke this method directly.
165+
166+
</section>
167+
168+
<!-- /.notes -->
169+
170+
<!-- Package usage examples. -->
171+
172+
<section class="examples">
173+
174+
## Examples
175+
176+
<!-- eslint no-undef: "error" -->
177+
178+
```javascript
179+
var Float64Array = require( '@stdlib/array/float64' );
180+
var inmap = require( '@stdlib/utils/inmap' );
181+
var randu = require( '@stdlib/random/base/randu' );
182+
var array2stridediterator = require( '@stdlib/array/to-strided-iterator' );
183+
184+
function scale( v, i ) {
185+
return v * (i+1);
186+
}
187+
188+
// Create an array filled with random numbers:
189+
var arr = inmap( new Float64Array( 100 ), randu );
190+
191+
// Create a strided iterator which scales every fourth value in reverse order:
192+
var it = array2stridediterator( 25, arr, -4, 99, scale );
193+
194+
// Perform manual iteration...
195+
var v;
196+
while ( true ) {
197+
v = it.next();
198+
if ( v.done ) {
199+
break;
200+
}
201+
console.log( v.value );
202+
}
203+
```
204+
205+
</section>
206+
207+
<!-- /.examples -->
208+
209+
<!-- Section to include cited references. If references are included, add a horizontal rule *before* the section. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
210+
211+
<section class="references">
212+
213+
</section>
214+
215+
<!-- /.references -->
216+
217+
<!-- Section for all links. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
218+
219+
<section class="links">
220+
221+
[mdn-iterator-protocol]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterator_protocol
222+
223+
</section>
224+
225+
<!-- /.links -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2018 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
// MODULES //
22+
23+
var bench = require( '@stdlib/bench' );
24+
var isnan = require( '@stdlib/math/base/assert/is-nan' );
25+
var isIteratorLike = require( '@stdlib/assert/is-iterator-like' );
26+
var pkg = require( './../package.json' ).name;
27+
var array2stridediterator = require( './../lib' );
28+
29+
30+
// MAIN //
31+
32+
bench( pkg, function benchmark( b ) {
33+
var values;
34+
var iter;
35+
var N;
36+
var i;
37+
38+
values = [ 1, 2, 3, 4 ];
39+
N = values.length;
40+
41+
b.tic();
42+
for ( i = 0; i < b.iterations; i++ ) {
43+
values[ 0 ] = i;
44+
iter = array2stridediterator( N, values, 1, 0 );
45+
if ( typeof iter !== 'object' ) {
46+
b.fail( 'should return an object' );
47+
}
48+
}
49+
b.toc();
50+
if ( !isIteratorLike( iter ) ) {
51+
b.fail( 'should return an iterator protocol-compliant object' );
52+
}
53+
b.pass( 'benchmark finished' );
54+
b.end();
55+
});
56+
57+
bench( pkg+'::iteration', function benchmark( b ) {
58+
var values;
59+
var iter;
60+
var N;
61+
var z;
62+
var i;
63+
64+
values = [];
65+
values.length = b.iterations;
66+
N = values.length;
67+
68+
iter = array2stridediterator( N, values, 1, 0 );
69+
70+
b.tic();
71+
for ( i = 0; i < b.iterations; i++ ) {
72+
z = iter.next().value;
73+
if ( z !== void 0 ) {
74+
b.fail( 'should be undefined' );
75+
}
76+
}
77+
b.toc();
78+
if ( z !== void 0 ) {
79+
b.fail( 'should be undefined' );
80+
}
81+
b.pass( 'benchmark finished' );
82+
b.end();
83+
});
84+
85+
bench( pkg+'::iteration,map', function benchmark( b ) {
86+
var values;
87+
var iter;
88+
var N;
89+
var z;
90+
var i;
91+
92+
values = [];
93+
values.length = b.iterations;
94+
N = values.length;
95+
96+
iter = array2stridediterator( N, values, 1, 0, transform );
97+
98+
b.tic();
99+
for ( i = 0; i < b.iterations; i++ ) {
100+
z = iter.next().value;
101+
if ( isnan( z ) ) {
102+
b.fail( 'should not be NaN' );
103+
}
104+
}
105+
b.toc();
106+
if ( isnan( z ) ) {
107+
b.fail( 'should not be NaN' );
108+
}
109+
b.pass( 'benchmark finished' );
110+
b.end();
111+
112+
function transform( v, i ) {
113+
return i;
114+
}
115+
});

0 commit comments

Comments
 (0)