Skip to content

Commit 2b7b89a

Browse files
committed
feat: add support for performing bounds checking
1 parent 61295ba commit 2b7b89a

File tree

12 files changed

+1200
-917
lines changed

12 files changed

+1200
-917
lines changed

lib/node_modules/@stdlib/slice/base/seq2slice/README.md

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,12 @@ var seq2slice = require( '@stdlib/slice/base/seq2slice' );
4242

4343
<a name="main"></a>
4444

45-
#### seq2slice( str, len )
45+
#### seq2slice( str, len, strict )
4646

4747
Converts a subsequence string to a [`Slice`][@stdlib/slice/ctor] object, where `len` specifies the maximum number of elements allowed in the slice.
4848

4949
```javascript
50-
var s = seq2slice( ':5', 10 );
50+
var s = seq2slice( ':5', 10, false );
5151
// returns <Slice>
5252

5353
var v = s.start;
@@ -77,7 +77,7 @@ where
7777
- The `end` keyword resolves to the provided length `len`. Thus, `:-1` is equivalent to `:end-1`, `:-2` is equivalent to `:end-2`, and so on and so forth. The exception is when performing a division operation when the `increment` is less than zero; in which case, `end` is equal to `len-1` in order to preserve user expectations when `end/d` equals a whole number and slicing from right-to-left. The result from a division operation is **rounded down** to the nearest integer value.
7878

7979
```javascript
80-
var s = seq2slice( 'end:2:-1', 10 );
80+
var s = seq2slice( 'end:2:-1', 10, false );
8181
// returns <Slice>
8282

8383
var v = s.start;
@@ -89,7 +89,7 @@ v = s.stop;
8989
v = s.step;
9090
// returns -1
9191

92-
s = seq2slice( 'end-2:2:-1', 10 );
92+
s = seq2slice( 'end-2:2:-1', 10, false );
9393
// returns <Slice>
9494

9595
v = s.start;
@@ -101,7 +101,7 @@ v = s.stop;
101101
v = s.step;
102102
// returns -1
103103

104-
s = seq2slice( 'end/2:2:-1', 10 );
104+
s = seq2slice( 'end/2:2:-1', 10, false );
105105
// returns <Slice>
106106

107107
v = s.start;
@@ -114,13 +114,26 @@ v = s.step;
114114
// returns -1
115115
```
116116

117-
The function returns `null` if provided in invalid subsequence string.
117+
The function returns an error object if provided in invalid subsequence string.
118118

119119
```javascript
120-
var s = seq2slice( '1:2:3:4', 10 );
121-
// returns null
120+
var s = seq2slice( '1:2:3:4', 10, false );
121+
// returns { 'code': 'ERR_INVALID_SUBSEQUENCE' }
122122
```
123123

124+
When `strict` is `true`, the function returns an error object if a subsequence string resolves to a slice exceeding index bounds.
125+
126+
```javascript
127+
var s = seq2slice( '10:20', 10, true );
128+
// returns { 'code': 'ERR_OUT_OF_BOUNDS' }
129+
```
130+
131+
A returned error object may have one of the following error codes:
132+
133+
- **ERR_INVALID_SUBSEQUENCE**: a subsequence string is invalid.
134+
- **ERR_INVALID_INCREMENT**: a subsequence string must have a non-zero increment.
135+
- **ERR_OUT_OF_BOUNDS**: a subsequence string resolves to a slice exceeding index bounds.
136+
124137
</section>
125138

126139
<!-- /.usage -->
@@ -132,8 +145,8 @@ var s = seq2slice( '1:2:3:4', 10 );
132145
## Notes
133146

134147
- When `len` is zero, the function always returns a Slice object equivalent to `0:0:<increment>`.
135-
- The resolved slice start is clamped to the slice index bounds (i.e., `[0, len)`).
136-
- The resolved slice end is upper bound clamped to `len` (i.e., one greater than the last possible index).
148+
- When `strict` is `false`, the resolved slice start is clamped to the slice index bounds (i.e., `[0, len)`).
149+
- When `strict` is `false`, the resolved slice end is upper bound clamped to `len` (i.e., one greater than the last possible index).
137150
- When the increment is negative, the resolved slice end value may be `null`, thus indicating that a non-empty slice should include the first index.
138151
- The function ensures that results satisfy the convention that `:n` combined with `n:` is equivalent to `:` (i.e., selecting all elements). This convention matches Python slice semantics, but diverges from the MATLAB convention where `:n` and `n:` overlap by one element.
139152
- Unlike MATLAB, but like Python, the subsequence string is upper-bound exclusive. For example, in Python, `0:2` corresponds to the sequence `{0,1}`. In MATLAB, `1:3` corresponds to `{1,2,3}`.
@@ -153,83 +166,83 @@ var s = seq2slice( '1:2:3:4', 10 );
153166
```javascript
154167
var seq2slice = require( '@stdlib/slice/base/seq2slice' );
155168

156-
var s = seq2slice( ':', 5 );
169+
var s = seq2slice( ':', 5, false );
157170
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
158171
// => 'start: 0. stop: 5. step: 1.'
159172

160-
s = seq2slice( '2:', 5 );
173+
s = seq2slice( '2:', 5, false );
161174
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
162175
// => 'start: 2. stop: 5. step: 1.'
163176

164-
s = seq2slice( ':3', 5 );
177+
s = seq2slice( ':3', 5, false );
165178
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
166179
// => 'start: 0. stop: 3. step: 1.'
167180

168-
s = seq2slice( '2:4', 5 );
181+
s = seq2slice( '2:4', 5, false );
169182
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
170183
// => 'start: 2. stop: 4. step: 1.'
171184

172-
s = seq2slice( '1:4:2', 5 );
185+
s = seq2slice( '1:4:2', 5, false );
173186
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
174187
// => 'start: 1. stop: 4. step: 2.'
175188

176-
s = seq2slice( '2::2', 5 );
189+
s = seq2slice( '2::2', 5, false );
177190
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
178191
// => 'start: 2. stop: 5. step: 2.'
179192

180-
s = seq2slice( ':-2', 5 );
193+
s = seq2slice( ':-2', 5, false );
181194
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
182195
// => 'start: 0. stop: 3. step: 1.'
183196

184-
s = seq2slice( ':-1:2', 5 );
197+
s = seq2slice( ':-1:2', 5, false );
185198
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
186199
// => 'start: 0. stop: 4. step: 2.'
187200

188-
s = seq2slice( '-4:-1:2', 5 );
201+
s = seq2slice( '-4:-1:2', 5, false );
189202
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
190203
// => 'start: 1. stop: 4. step: 2.'
191204

192-
s = seq2slice( '-5:-1', 5 );
205+
s = seq2slice( '-5:-1', 5, false );
193206
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
194207
// => 'start: 0. stop: 4. step: 1.'
195208

196-
s = seq2slice( '::-1', 5 );
209+
s = seq2slice( '::-1', 5, false );
197210
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
198211
// => 'start: 4. stop: null. step: -1.'
199212

200-
s = seq2slice( ':0:-1', 5 );
213+
s = seq2slice( ':0:-1', 5, false );
201214
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
202215
// => 'start: 4. stop: 0. step: -1.'
203216

204-
s = seq2slice( '3:0:-1', 5 );
217+
s = seq2slice( '3:0:-1', 5, false );
205218
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
206219
// => 'start: 3. stop: 0. step: -1.'
207220

208-
s = seq2slice( '-1:-4:-2', 5 );
221+
s = seq2slice( '-1:-4:-2', 5, false );
209222
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
210223
// => 'start: 4. stop: 1. step: -2.'
211224

212-
s = seq2slice( ':end', 5 );
225+
s = seq2slice( ':end', 5, false );
213226
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
214227
// => 'start: 0. stop: 5. step: 1.'
215228

216-
s = seq2slice( ':end-1', 5 );
229+
s = seq2slice( ':end-1', 5, false );
217230
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
218231
// => 'start: 0. stop: 4. step: 1.'
219232

220-
s = seq2slice( ':end/2', 5 );
233+
s = seq2slice( ':end/2', 5, false );
221234
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
222235
// => 'start: 0. stop: 2. step: 1.'
223236

224-
s = seq2slice( 'end/2::-1', 5 );
237+
s = seq2slice( 'end/2::-1', 5, false );
225238
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
226239
// => 'start: 2. stop: null. step: -1.'
227240

228-
s = seq2slice( 'end-2::-1', 5 );
241+
s = seq2slice( 'end-2::-1', 5, false );
229242
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
230243
// => 'start: 3. stop: null. step: -1.'
231244

232-
s = seq2slice( 'end/2:', 5 );
245+
s = seq2slice( 'end/2:', 5, false );
233246
console.log( 'start: %s. stop: %s. step: %s.', s.start, s.stop, s.step );
234247
// => 'start: 2. stop: 5. step: 1.'
235248
```

lib/node_modules/@stdlib/slice/base/seq2slice/benchmark/benchmark.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ bench( pkg+'::defaults', function benchmark( b ) {
4040

4141
b.tic();
4242
for ( i = 0; i < b.iterations; i++ ) {
43-
out = seq2slice( values[ i%values.length ], 10 );
43+
out = seq2slice( values[ i%values.length ], 10, false );
4444
if ( typeof out !== 'object' ) {
4545
b.fail( 'should return an object' );
4646
}
@@ -70,7 +70,7 @@ bench( pkg+'::positive_integers', function benchmark( b ) {
7070

7171
b.tic();
7272
for ( i = 0; i < b.iterations; i++ ) {
73-
out = seq2slice( values[ i%values.length ], 10 );
73+
out = seq2slice( values[ i%values.length ], 10, false );
7474
if ( typeof out !== 'object' ) {
7575
b.fail( 'should return an object' );
7676
}
@@ -100,7 +100,7 @@ bench( pkg+'::negative_integers', function benchmark( b ) {
100100

101101
b.tic();
102102
for ( i = 0; i < b.iterations; i++ ) {
103-
out = seq2slice( values[ i%values.length ], 10 );
103+
out = seq2slice( values[ i%values.length ], 10, false );
104104
if ( typeof out !== 'object' ) {
105105
b.fail( 'should return an object' );
106106
}
@@ -126,7 +126,7 @@ bench( pkg+'::end,defaults', function benchmark( b ) {
126126

127127
b.tic();
128128
for ( i = 0; i < b.iterations; i++ ) {
129-
out = seq2slice( values[ i%values.length ], 10 );
129+
out = seq2slice( values[ i%values.length ], 10, false );
130130
if ( typeof out !== 'object' ) {
131131
b.fail( 'should return an object' );
132132
}
@@ -154,7 +154,7 @@ bench( pkg+'::end,subtraction', function benchmark( b ) {
154154

155155
b.tic();
156156
for ( i = 0; i < b.iterations; i++ ) {
157-
out = seq2slice( values[ i%values.length ], 10 );
157+
out = seq2slice( values[ i%values.length ], 10, false );
158158
if ( typeof out !== 'object' ) {
159159
b.fail( 'should return an object' );
160160
}
@@ -182,7 +182,7 @@ bench( pkg+'::end,division', function benchmark( b ) {
182182

183183
b.tic();
184184
for ( i = 0; i < b.iterations; i++ ) {
185-
out = seq2slice( values[ i%values.length ], 10 );
185+
out = seq2slice( values[ i%values.length ], 10, false );
186186
if ( typeof out !== 'object' ) {
187187
b.fail( 'should return an object' );
188188
}

lib/node_modules/@stdlib/slice/base/seq2slice/docs/repl.txt

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
{{alias}}( str, len )
2+
{{alias}}( str, len, strict )
33
Converts a subsequence string to a Slice object.
44

55
A subsequence string has the following format:
@@ -32,10 +32,11 @@
3232
to-left. The result from a division operation is rounded down to the nearest
3333
integer value.
3434

35-
The resolved slice start is clamped to the slice index bounds [0, len).
35+
In non-strict mode, the resolved slice start is clamped to the slice index
36+
bounds [0, len).
3637

37-
The resolved slice end is upper bound clamped to the provided length (i.e.,
38-
one greater than the last possible index).
38+
In non-strict mode, Tte resolved slice end is upper bound clamped to the
39+
provided length (i.e., one greater than the last possible index).
3940

4041
When the increment is negative, the resolved slice end value may be `null`,
4142
thus indicating that a non-empty slice should include the first index.
@@ -46,7 +47,23 @@
4647
When the provided length is zero, the function always returns a slice object
4748
equivalent to '0:0:<increment>'.
4849

49-
The function returns `null` if provided in invalid subsequence string.
50+
The function returns an error object if provided in invalid subsequence
51+
string.
52+
53+
In strict mode, the function returns an error object if provided a
54+
subsequence string which exceeds index bounds.
55+
56+
A returned error object is a plain object having the following properties:
57+
58+
- code: error code.
59+
60+
A returned error object may have one of the following error codes:
61+
62+
- ERR_INVALID_SUBSEQUENCE: a subsequence string is invalid.
63+
- ERR_INVALID_INCREMENT: a subsequence string must have a non-zero
64+
increment.
65+
- ERR_OUT_OF_BOUNDS: a subsequence string resolves to a slice exceeding
66+
index bounds.
5067

5168
Parameters
5269
----------
@@ -56,21 +73,24 @@
5673
len: integer
5774
Maximum number of elements allowed in the slice.
5875

76+
strict: boolean
77+
Boolean indicating whether to enforce strict bounds checking.
78+
5979
Returns
6080
-------
61-
s: Slice|null
62-
Slice instance (or null).
81+
s: Slice|Object
82+
Slice instance or an error object.
6383

6484
Examples
6585
--------
66-
> var s = new {{alias}}( '1:10', 10 );
86+
> var s = new {{alias}}( '1:10', 10, false );
6787
> s.start
6888
1
6989
> s.stop
7090
10
7191
> s.step
7292
1
73-
> s = new {{alias}}( '2:5:2', 10 );
93+
> s = new {{alias}}( '2:5:2', 10, false );
7494
> s.start
7595
2
7696
> s.stop

lib/node_modules/@stdlib/slice/base/seq2slice/docs/types/index.d.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,21 @@
2222

2323
import { Slice } from '@stdlib/types/slice';
2424

25+
/**
26+
* Interface describing an error object.
27+
*/
28+
interface ErrorObject {
29+
/**
30+
* Error code.
31+
*/
32+
code: 'ERR_INVALID_SUBSEQUENCE' | 'ERR_INVALID_INCREMENT' | 'ERR_OUT_OF_BOUNDS';
33+
}
34+
35+
/**
36+
* Conversion result.
37+
*/
38+
type SliceResult = Slice<number, number | null, number> | ErrorObject;
39+
2540
/**
2641
* Converts a subsequence string to a Slice object.
2742
*
@@ -43,24 +58,27 @@ import { Slice } from '@stdlib/types/slice';
4358
* - Both `start` and `stop` can use the `end` keyword (e.g., `end-2::2`, `end-3:`, etc), which supports basic subtraction and division.
4459
* - The `end` keyword resolves to the provided length `len`. Thus, `:-1` is equivalent to `:end-1`, `:-2` is equivalent to `:end-2`, and so on and so forth. The exception is when performing a division operation when the `increment` is less than zero; in which case, `end` is equal to `len-1` in order to preserve user expectations when `end/d` equals a whole number and slicing from right-to-left. The result from a division operation is **rounded down** to the nearest integer value.
4560
*
46-
* - The resolved slice start is clamped to the slice index bounds (i.e., `[0, len)`).
61+
* - When `strict` is `false`, the resolved slice start is clamped to the slice index bounds (i.e., `[0, len)`).
4762
*
48-
* - The resolved slice end is upper bound clamped to `len` (i.e., one greater than the last possible index).
63+
* - When `strict` is `false`, the resolved slice end is upper bound clamped to `len` (i.e., one greater than the last possible index).
4964
*
5065
* - When the increment is negative, the resolved slice end value may be `null`, thus indicating that a non-empty slice should include the first index.
5166
*
5267
* - The function ensures that results satisfy the convention that `:n` combined with `n:` is equivalent to `:` (i.e., selecting all elements).
5368
*
5469
* - When `len` is zero, the function always returns a Slice object equivalent to `0:0:<increment>`.
5570
*
56-
* - The function returns `null` if provided in invalid subsequence string.
71+
* - The function returns an error object if provided in invalid subsequence string.
72+
*
73+
* - If `strict` is `true`, the function returns an error object if provided a subsequence string which exceeds index bounds.
5774
*
5875
* @param str - input string
5976
* @param len - maximum number of elements allowed in the slice
60-
* @returns Slice object (or null)
77+
* @param strict - boolean indicating whether to enforce strict bounds checking
78+
* @returns Slice object or an error object
6179
*
6280
* @example
63-
* var s = seq2slice( '0:10:1', 10 );
81+
* var s = seq2slice( '0:10:1', 10, false );
6482
* // returns <Slice>
6583
*
6684
* var v = s.start;
@@ -73,7 +91,7 @@ import { Slice } from '@stdlib/types/slice';
7391
* // returns 1
7492
*
7593
* @example
76-
* var s = seq2slice( '::-1', 10 );
94+
* var s = seq2slice( '::-1', 10, false );
7795
* // returns <Slice>
7896
*
7997
* var v = s.start;
@@ -86,7 +104,7 @@ import { Slice } from '@stdlib/types/slice';
86104
* // returns -1
87105
*
88106
* @example
89-
* var s = seq2slice( 'end::-1', 10 );
107+
* var s = seq2slice( 'end::-1', 10, false );
90108
* // returns <Slice>
91109
*
92110
* var v = s.start;
@@ -98,7 +116,7 @@ import { Slice } from '@stdlib/types/slice';
98116
* v = s.step;
99117
* // returns -1
100118
*/
101-
declare function seq2slice( str: string, len: number ): Slice<number, number | null, number> | null;
119+
declare function seq2slice( str: string, len: number, strict: boolean ): SliceResult;
102120

103121

104122
// EXPORTS //

0 commit comments

Comments
 (0)