UNPKG

3.45 kBPlain TextView Raw
1// Copyright (c) Jupyter Development Team.
2// Distributed under the terms of the Modified BSD License.
3/*-----------------------------------------------------------------------------
4| Copyright (c) 2014-2017, PhosphorJS Contributors
5|
6| Distributed under the terms of the BSD 3-Clause License.
7|
8| The full license is in the file LICENSE, distributed with this software.
9|----------------------------------------------------------------------------*/
10import { IIterator } from './iter';
11
12/**
13 * Create an iterator of evenly spaced values.
14 *
15 * @param start - The starting value for the range, inclusive.
16 *
17 * @param stop - The stopping value for the range, exclusive.
18 *
19 * @param step - The distance between each value.
20 *
21 * @returns An iterator which produces evenly spaced values.
22 *
23 * #### Notes
24 * In the single argument form of `range(stop)`, `start` defaults to
25 * `0` and `step` defaults to `1`.
26 *
27 * In the two argument form of `range(start, stop)`, `step` defaults
28 * to `1`.
29 */
30export function range(
31 start: number,
32 stop?: number,
33 step?: number
34): IIterator<number> {
35 if (stop === undefined) {
36 return new RangeIterator(0, start, 1);
37 }
38 if (step === undefined) {
39 return new RangeIterator(start, stop, 1);
40 }
41 return new RangeIterator(start, stop, step);
42}
43
44/**
45 * An iterator which produces a range of evenly spaced values.
46 */
47export class RangeIterator implements IIterator<number> {
48 /**
49 * Construct a new range iterator.
50 *
51 * @param start - The starting value for the range, inclusive.
52 *
53 * @param stop - The stopping value for the range, exclusive.
54 *
55 * @param step - The distance between each value.
56 */
57 constructor(start: number, stop: number, step: number) {
58 this._start = start;
59 this._stop = stop;
60 this._step = step;
61 this._length = Private.rangeLength(start, stop, step);
62 }
63
64 /**
65 * Get an iterator over the object's values.
66 *
67 * @returns An iterator which yields the object's values.
68 */
69 iter(): IIterator<number> {
70 return this;
71 }
72
73 /**
74 * Create an independent clone of the iterator.
75 *
76 * @returns A new independent clone of the iterator.
77 */
78 clone(): IIterator<number> {
79 let result = new RangeIterator(this._start, this._stop, this._step);
80 result._index = this._index;
81 return result;
82 }
83
84 /**
85 * Get the next value from the iterator.
86 *
87 * @returns The next value from the iterator, or `undefined`.
88 */
89 next(): number | undefined {
90 if (this._index >= this._length) {
91 return undefined;
92 }
93 return this._start + this._step * this._index++;
94 }
95
96 private _index = 0;
97 private _length: number;
98 private _start: number;
99 private _stop: number;
100 private _step: number;
101}
102
103/**
104 * The namespace for the module implementation details.
105 */
106namespace Private {
107 /**
108 * Compute the effective length of a range.
109 *
110 * @param start - The starting value for the range, inclusive.
111 *
112 * @param stop - The stopping value for the range, exclusive.
113 *
114 * @param step - The distance between each value.
115 *
116 * @returns The number of steps need to traverse the range.
117 */
118 export function rangeLength(
119 start: number,
120 stop: number,
121 step: number
122 ): number {
123 if (step === 0) {
124 return Infinity;
125 }
126 if (start > stop && step > 0) {
127 return 0;
128 }
129 if (start < stop && step < 0) {
130 return 0;
131 }
132 return Math.ceil((stop - start) / step);
133 }
134}