Back to .md Directory

Comprehensive Test Cases

Test cases for `%TypedArray%.prototype.search`, `%TypedArray%.prototype.searchLast`, and `%TypedArray%.prototype.contains`.

May 2, 2026
0 downloads
1 views
ai
View source

Comprehensive Test Cases

Test cases for %TypedArray%.prototype.search, %TypedArray%.prototype.searchLast, and %TypedArray%.prototype.contains.

Identifier Convention

Each checkbox line has a unique identifier in the form [section.subsection.number], e.g. [2.1.1].

Where a test case is preceded by a "For each ..." qualifier (e.g. "For each method" or "For each TypedArray type"), each variation is referenced by appending a lowercase letter suffix: [1.1.1a] for search, [1.1.1b] for searchLast, [1.1.1c] for contains, etc. The letter ordering follows the order in which the items appear in the qualifier list.


1. Receiver Validation (ValidateTypedArray)

1.1 Invalid this value

For each method (search, searchLast, contains):

  • [1.1.1] this = undefined → TypeError
  • [1.1.2] this = null → TypeError
  • [1.1.3] this = plain object {} → TypeError
  • [1.1.4] this = a number → TypeError
  • [1.1.5] this = a regular Array → TypeError

1.2 Detached buffer

For each method (search, searchLast, contains):

For each TypedArray type (Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float16Array, Float32Array, Float64Array, BigInt64Array, BigUint64Array):

  • [1.2.1] Calling the method on a TypedArray with a detached ArrayBuffer → TypeError

2. Needle Validation (ToCompatibleTypedArrayElementList)

2.1 Same-type TypedArray (iterated via @@iterator)

For each method (search, searchLast, contains):

  • [2.1.1] new Int8Array([1,2,3]).search(new Int8Array([2,3])) → 1
  • [2.1.2] new Uint8Array([1,2,3]).search(new Uint8Array([2,3])) → 1
  • [2.1.3] new Uint8ClampedArray([1,2,3]).search(new Uint8ClampedArray([2,3])) → 1
  • [2.1.4] new Int16Array([1,2,3]).search(new Int16Array([2,3])) → 1
  • [2.1.5] new Uint16Array([1,2,3]).search(new Uint16Array([2,3])) → 1
  • [2.1.6] new Int32Array([1,2,3]).search(new Int32Array([2,3])) → 1
  • [2.1.7] new Uint32Array([1,2,3]).search(new Uint32Array([2,3])) → 1
  • [2.1.8] new Float16Array([1,2,3]).search(new Float16Array([2,3])) → 1
  • [2.1.9] new Float32Array([1,2,3]).search(new Float32Array([2,3])) → 1
  • [2.1.10] new Float64Array([1.5,2.5]).search(new Float64Array([1.5,2.5])) → 0
  • [2.1.11] new BigInt64Array([1n,2n,3n]).search(new BigInt64Array([2n,3n])) → 1
  • [2.1.12] new BigUint64Array([1n,2n]).search(new BigUint64Array([1n,2n])) → 0

2.2 Different-type TypedArray (iterated via @@iterator)

For each method (search, searchLast, contains):

  • [2.2.1] new Uint8Array([1,2,3]).search(new Int16Array([2,3])) → 1
  • [2.2.2] new Float64Array([1,2,3]).search(new Float32Array([2,3])) → 1
  • [2.2.3] new Uint8Array([1,2,3]).search(new Uint32Array([2,3])) → 1
  • [2.2.4] new Int16Array([1,2,3]).search(new Uint8Array([2,3])) → 1

2.3 Different-type TypedArray — precision loss

For each method (search, searchLast, contains):

  • [2.3.1] Searching a Float64Array containing 1.1 (native Float64) with a Float32Array needle [1.1] → -1 (Float32 1.1 is 1.100000023841858 as a Number, which does not SameValueZero-match the Float64 1.1)

2.4 BigInt / Number type mismatch → -1 (not TypeError)

  • [2.4.1] new BigInt64Array([1n,2n]).search(new Uint8Array([1,2])) → -1 (needle yields Numbers, haystack expects BigInts)
  • [2.4.2] new Uint8Array([1,2]).search(new BigInt64Array([1n,2n])) → -1 (needle yields BigInts, haystack expects Numbers)
  • [2.4.3] new BigInt64Array([1n,2n]).searchLast(new Uint8Array([1,2])) → -1
  • [2.4.4] new Uint8Array([1,2]).contains(new BigInt64Array([1n,2n])) → false

2.5 Iterable objects (non-TypedArray)

For each method (search, searchLast, contains):

  • [2.5.1] Plain Array: new Uint8Array([1,2,3]).search([2,3]) → 1
  • [2.5.2] Generator: new Uint8Array([1,2,3]).search(function*() { yield 2; yield 3; }()) → 1
  • [2.5.3] Set: new Uint8Array([1,2,3]).search(new Set([2,3])) → 1
  • [2.5.4] Custom iterable with [Symbol.iterator]():
    const iter = { [Symbol.iterator]() { return { i: 2, next() { return this.i <= 3 ? { value: this.i++, done: false } : { done: true }; } }; } };
    new Uint8Array([1,2,3]).search(iter) // → 1
    
  • [2.5.5] Empty iterable: new Uint8Array([1,2,3]).search([]) → 0 (empty needle)

2.6 Iterable with BigInt target

For each method (search, searchLast, contains):

  • [2.6.1] new BigInt64Array([1n,2n,3n]).search([1n,2n]) → 0
  • [2.6.2] new BigInt64Array([1n,2n,3n]).search([1,2]) → -1 (Numbers are not BigInts, returns not-found)
  • [2.6.3] new BigInt64Array([1n,2n,3n]).search(['1','2']) → -1 (Strings are not BigInts, returns not-found)

2.7 Iterable with wrong-type elements → -1

For each method (search, searchLast, contains):

  • [2.7.1] new Uint8Array([1,2,3]).search([1n, 2n]) → -1 (BigInts are not Numbers)
  • [2.7.2] new Uint8Array([1,2,3]).search(['1', '2']) → -1 (Strings are not Numbers)
  • [2.7.3] new Uint8Array([1,2,3]).search([{}]) → -1 (Objects are not Numbers)
  • [2.7.4] new Uint8Array([1,2,3]).search([Symbol()]) → -1 (Symbols are not Numbers)
  • [2.7.5] new BigInt64Array([1n,2n]).search([1.5]) → -1 (Numbers are not BigInts)
  • [2.7.6] new Uint8Array([1,2,3]).search([1, 2, 3n]) → -1 (first two elements are Numbers but third is a BigInt; not-found returned on encountering the wrong type partway through)
  • [2.7.7] new BigInt64Array([1n,2n,3n]).search([1n, 2n, 3]) → -1 (first two elements are BigInts but third is a Number)
  • [2.7.8] new Uint8Array([1,2,3]).search([1, undefined, 3]) → -1 (undefined is not a Number)
  • [2.7.9] new Uint8Array([1,2,3]).search([1, null, 3]) → -1 (null is not a Number)

2.8 Iterable that throws during iteration

For each method (search, searchLast, contains):

  • [2.8.1] Iterator whose next() throws → the error propagates
  • [2.8.2] Iterable whose @@iterator method throws → the error propagates

2.9 String needle → TypeError

  • [2.9.1] new Uint8Array([1,2,3]).search('hello') → TypeError
  • [2.9.2] new Uint8Array([1,2,3]).searchLast('hello') → TypeError
  • [2.9.3] new Uint8Array([1,2,3]).contains('hello') → TypeError
  • [2.9.4] new Uint8Array([]).search('') → TypeError

2.10 Non-iterable Object → TypeError

For each method (search, searchLast, contains):

  • [2.10.1] new Uint8Array([1,2,3]).search({}) → TypeError
  • [2.10.2] new Uint8Array([1,2,3]).search({ length: 2, 0: 2, 1: 3 }) → TypeError (array-like but not iterable)
  • [2.10.3] new Uint8Array([1,2,3]).search({ [Symbol.iterator]: 42 }) → TypeError (@@iterator is non-callable)
  • [2.10.4] new Uint8Array([1,2,3]).search({ [Symbol.iterator]: null }) → TypeError (GetMethod returns undefined, falls through to throw)

2.11 Non-Object primitives → TypeError

For each method (search, searchLast, contains):

  • [2.11.1] new Uint8Array([1,2,3]).search(42) → TypeError
  • [2.11.2] new Uint8Array([1,2,3]).search(true) → TypeError
  • [2.11.3] new Uint8Array([1,2,3]).search(false) → TypeError
  • [2.11.4] new Uint8Array([1,2,3]).search(undefined) → TypeError
  • [2.11.5] new Uint8Array([1,2,3]).search(null) → TypeError
  • [2.11.6] new Uint8Array([1,2,3]).search(Symbol()) → TypeError
  • [2.11.7] new Uint8Array([1,2,3]).search(42n) → TypeError
  • [2.11.8] new Uint8Array([1,2,3]).search() → TypeError (no argument; needle is undefined)
  • [2.11.9] new Uint8Array([1,2,3]).searchLast() → TypeError (no argument)
  • [2.11.10] new Uint8Array([1,2,3]).contains() → TypeError (no argument)

2.12 TypedArray needle with overridden Symbol.iterator

Since needle elements are collected via @@iterator, a TypedArray whose Symbol.iterator has been overridden will yield whatever the custom iterator produces, not the underlying buffer contents.

For each method (search, searchLast, contains):

  • [2.12.1] Needle TypedArray with Symbol.iterator overridden to yield different values:
    const needle = new Uint8Array([99, 99]);
    needle[Symbol.iterator] = function*() { yield 3; yield 4; };
    new Uint8Array([1, 2, 3, 4, 5]).search(needle) // → 2 (searches for [3,4], not [99,99])
    
  • [2.12.2] Needle TypedArray with Symbol.iterator overridden to yield fewer elements:
    const needle = new Uint8Array([1, 2, 3]);
    needle[Symbol.iterator] = function*() { yield 2; };
    new Uint8Array([1, 2, 3]).search(needle) // → 1 (searches for [2], not [1,2,3])
    
  • [2.12.3] Needle TypedArray with Symbol.iterator overridden to yield nothing:
    const needle = new Uint8Array([1, 2, 3]);
    needle[Symbol.iterator] = function*() {};
    new Uint8Array([1, 2, 3]).search(needle) // → 0 (empty needle returns position)
    
  • [2.12.4] Needle TypedArray with Symbol.iterator overridden to yield more elements:
    const needle = new Uint8Array([1]);
    needle[Symbol.iterator] = function*() { yield 2; yield 3; yield 4; };
    new Uint8Array([1, 2, 3, 4, 5]).search(needle) // → 1 (searches for [2,3,4], not [1])
    

Note: Error cases for overridden Symbol.iterator (wrong types, non-callable, undefined/null, throws) are covered by the corresponding generic cases in sections 2.7, 2.8, and 2.10. The cases above focus on demonstrating that the override is respected for the yielded values.

2.13 Detached TypedArray needle

For each method (search, searchLast, contains):

  • [2.13.1] Same-type, detached: needle is a same-type TypedArray with a detached buffer → iteration via @@iterator; behaviour depends on the TypedArray's @@iterator implementation for detached buffers
  • [2.13.2] Different-type, detached: needle is a different-type TypedArray with a detached buffer → iteration via @@iterator; behaviour depends on the TypedArray's @@iterator implementation for detached buffers

3. Position Validation (ValidateIntegralNumber)

3.1 Default position

  • [3.1.1] search with no position argument → defaults to 0
  • [3.1.2] searchLast with no position argument → defaults to haystackLength - 1
  • [3.1.3] contains with no position argument → defaults to 0

3.2 Explicit undefined → uses default

  • [3.2.1] new Uint8Array([1,2,3]).search([2,3], undefined) → 1 (default 0)
  • [3.2.2] new Uint8Array([1,2,3]).searchLast([2,3], undefined) → 1 (default haystackLength - 1)

3.3 Non-Number position → TypeError

For each method (search, searchLast, contains):

  • [3.3.1] new Uint8Array([1,2,3]).search([2,3], 'hello') → TypeError
  • [3.3.2] new Uint8Array([1,2,3]).search([2,3], {}) → TypeError
  • [3.3.3] new Uint8Array([1,2,3]).search([2,3], true) → TypeError
  • [3.3.4] new Uint8Array([1,2,3]).search([2,3], null) → TypeError
  • [3.3.5] new Uint8Array([1,2,3]).search([2,3], Symbol()) → TypeError
  • [3.3.6] new Uint8Array([1,2,3]).search([2,3], 1n) → TypeError (BigInt is not a Number)

3.4 NaN position → RangeError

For each method (search, searchLast, contains):

  • [3.4.1] new Uint8Array([1,2,3]).search([2,3], NaN) → RangeError

3.5 Non-integral number → RangeError

For each method (search, searchLast, contains):

  • [3.5.1] new Uint8Array([1,2,3]).search([2,3], 1.5) → RangeError
  • [3.5.2] new Uint8Array([1,2,3]).search([2,3], 0.1) → RangeError

3.6 Infinity → RangeError

For each method (search, searchLast, contains):

  • [3.6.1] new Uint8Array([1,2,3]).search([2,3], Infinity) → RangeError
  • [3.6.2] new Uint8Array([1,2,3]).search([2,3], -Infinity) → RangeError

3.7 Negative position (clamped to 0)

  • [3.7.1] new Uint8Array([1,2,3]).search([1,2], -5) → 0 (clamped to 0)
  • [3.7.2] new Uint8Array([1,2,3]).searchLast([1,2], -1) → 0 (clamped to 0)
  • [3.7.3] new Uint8Array([1,2,3]).contains([1,2], -10) → true (clamped to 0)

3.8 Position beyond length (clamped)

  • [3.8.1] new Uint8Array([1,2,3,4,5]).search([3,4], 100) → -1 (clamped to 5, can't match from index 5)
  • [3.8.2] new Uint8Array([1,2,3,4,5]).searchLast([3,4], 100) → 2 (clamped to 4)
  • [3.8.3] new Uint8Array([1,2,3]).contains([2,3], 100) → false (clamped to 3)

3.9 Valid integral positions

  • [3.9.1] new Uint8Array([1,2,3]).search([2,3], 0) → 1
  • [3.9.2] new Uint8Array([1,2,3]).search([2,3], 1) → 1
  • [3.9.3] new Uint8Array([1,2,3]).search([2,3], 2) → -1 (not enough room)
  • [3.9.4] new Uint8Array([1,2,3]).search([1,2], -0) → 0 (ℝ(-0) is 0)

4. search (Forward Search)

4.1 Basic matching

For each TypedArray type (Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float16Array, Float32Array, Float64Array):

  • [4.1.1] new <Type>([1,2,3,4,5]).search(new <Type>([3,4])) → 2
  • [4.1.2] Match at beginning: new <Type>([1,2,3]).search(new <Type>([1,2])) → 0
  • [4.1.3] Match at end: new <Type>([1,2,3]).search(new <Type>([2,3])) → 1
  • [4.1.4] Entire array as needle: new <Type>([1,2,3]).search(new <Type>([1,2,3])) → 0

For BigInt types (BigInt64Array, BigUint64Array):

  • [4.1.5] new <Type>([1n,2n,3n,4n,5n]).search(new <Type>([3n,4n])) → 2
  • [4.1.6] Match at beginning: new <Type>([1n,2n,3n]).search(new <Type>([1n,2n])) → 0
  • [4.1.7] Match at end: new <Type>([1n,2n,3n]).search(new <Type>([2n,3n])) → 1
  • [4.1.8] Entire array as needle: new <Type>([1n,2n,3n]).search(new <Type>([1n,2n,3n])) → 0

4.2 No match

  • [4.2.1] new Uint8Array([1,2,3]).search(new Uint8Array([4,5])) → -1
  • [4.2.2] Partial overlap but not full match: new Uint8Array([1,2,3]).search(new Uint8Array([2,4])) → -1

4.3 Empty needle

  • [4.3.1] new Uint8Array([1,2,3]).search(new Uint8Array([])) → 0 (returns position, which defaults to 0)
  • [4.3.2] new Uint8Array([1,2,3]).search([], 2) → 2 (returns position)
  • [4.3.3] new Uint8Array([]).search([]) → 0

4.4 Empty haystack

  • [4.4.1] new Uint8Array([]).search(new Uint8Array([1])) → -1
  • [4.4.2] new Uint8Array([]).search(new Uint8Array([])) → 0

4.5 Needle longer than haystack

  • [4.5.1] new Uint8Array([1,2]).search(new Uint8Array([1,2,3])) → -1

4.6 Needle longer than remaining elements from position

  • [4.6.1] new Uint8Array([1,2,3,4]).search(new Uint8Array([3,4,5]), 2) → -1 (position + needleLength > haystackLength)
  • [4.6.2] new Uint8Array([1,2,3,4]).search([3,4], 3) → -1

4.7 Position skips earlier matches

  • [4.7.1] new Uint8Array([1,2,1,2]).search([1,2], 1) → 2 (skips match at 0)
  • [4.7.2] new Uint8Array([1,2,1,2,1,2]).search([1,2], 2) → 2
  • [4.7.3] new Uint8Array([1,2,1,2,1,2]).search([1,2], 3) → 4

4.8 Multiple occurrences — returns first from position

  • [4.8.1] new Uint8Array([1,2,3,1,2,3,1,2,3]).search([2,3]) → 1
  • [4.8.2] new Uint8Array([1,2,3,1,2,3,1,2,3]).search([2,3], 2) → 4
  • [4.8.3] new Uint8Array([1,2,3,1,2,3,1,2,3]).search([2,3], 5) → 7

4.9 Single-element needle

  • [4.9.1] new Uint8Array([1,2,3]).search([2]) → 1
  • [4.9.2] new Uint8Array([1,2,3]).search([4]) → -1

5. searchLast (Backward Search)

5.1 Basic matching

For each TypedArray type (Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float16Array, Float32Array, Float64Array):

  • [5.1.1] new <Type>([1,2,3,4,5]).searchLast(new <Type>([3,4])) → 2
  • [5.1.2] new <Type>([1,2,3,1,2,3]).searchLast(new <Type>([1,2,3])) → 3

For BigInt types (BigInt64Array, BigUint64Array):

  • [5.1.3] new <Type>([1n,2n,3n,4n,5n]).searchLast(new <Type>([3n,4n])) → 2
  • [5.1.4] new <Type>([1n,2n,3n,1n,2n,3n]).searchLast(new <Type>([1n,2n,3n])) → 3

5.2 No match

  • [5.2.1] new Uint8Array([1,2,3]).searchLast(new Uint8Array([4,5])) → -1

5.3 Empty needle

  • [5.3.1] new Uint8Array([1,2,3]).searchLast([]) → 2 (returns position, default is haystackLength - 1)
  • [5.3.2] new Uint8Array([1,2,3]).searchLast([], 1) → 1

5.4 Empty haystack

  • [5.4.1] new Uint8Array([]).searchLast(new Uint8Array([1])) → -1

5.5 Needle longer than haystack

  • [5.5.1] new Uint8Array([1,2]).searchLast(new Uint8Array([1,2,3])) → -1

5.6 Position constrains search

  • [5.6.1] new Uint8Array([1,2,3,1,2,3,1,2,3]).searchLast([2,3]) → 7
  • [5.6.2] new Uint8Array([1,2,3,1,2,3,1,2,3]).searchLast([2,3], 5) → 4
  • [5.6.3] new Uint8Array([1,2,3,1,2,3,1,2,3]).searchLast([2,3], 3) → 1
  • [5.6.4] new Uint8Array([1,2,3,1,2,3,1,2,3]).searchLast([2,3], 0) → -1

5.7 Position at exact match start

  • [5.7.1] new Uint8Array([1,2,3,1,2,3]).searchLast([1,2,3], 3) → 3
  • [5.7.2] new Uint8Array([1,2,3,1,2,3]).searchLast([1,2,3], 2) → 0

5.8 Single-element needle

  • [5.8.1] new Uint8Array([1,2,3,2,1]).searchLast([2]) → 3
  • [5.8.2] new Uint8Array([1,2,3,2,1]).searchLast([2], 2) → 1

5.9 Match must start at or before position (not end at or before)

  • [5.9.1] new Uint8Array([1,2,3,4,5]).searchLast([3,4,5], 2) → 2 (match starts at 2, which is ≤ position 2)
  • [5.9.2] new Uint8Array([1,2,3,4,5]).searchLast([3,4,5], 1) → -1 (match would start at 2, which is > position 1)

5.10 Position near end with multi-element needle (k + needleLength ≤ haystackLength constraint)

  • [5.10.1] new Uint8Array([1,2,3,4,5]).searchLast([4,5], 4) → 3 (position is 4, but k + 2 ≤ 5 means k ≤ 3)
  • [5.10.2] new Uint8Array([1,2,3,4,5]).searchLast([3,4,5], 4) → 2 (position is 4, but k + 3 ≤ 5 means k ≤ 2)
  • [5.10.3] new Uint8Array([1,2,3,4,5]).searchLast([1,2,3,4,5], 4) → 0 (only one possible start index)
  • [5.10.4] new Uint8Array([1,2,3,4,5]).searchLast([1,2,3,4,5], 0) → 0

5.11 Empty haystack with empty needle

  • [5.11.1] new Uint8Array([]).searchLast([]) → 0 (position defaults to haystackLength - 1 = -1, clamped to 0; empty needle returns position)

Note: the clamping range for searchLast is [0, haystackLength - 1]. When haystackLength is 0, this is [0, -1], a degenerate range. The spec's clamping definition produces lower (0) when x < lower, so clamp(-1, 0, -1) → 0. This edge case may warrant spec clarification.


6. contains (Boolean Search)

6.1 Basic matching

For each TypedArray type (Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float16Array, Float32Array, Float64Array):

  • [6.1.1] new <Type>([1,2,3,4,5]).contains(new <Type>([3,4])) → true
  • [6.1.2] new <Type>([1,2,3]).contains(new <Type>([4,5])) → false

For BigInt types (BigInt64Array, BigUint64Array):

  • [6.1.3] new <Type>([1n,2n,3n,4n,5n]).contains(new <Type>([3n,4n])) → true
  • [6.1.4] new <Type>([1n,2n,3n]).contains(new <Type>([4n,5n])) → false

6.2 Empty needle

  • [6.2.1] new Uint8Array([1,2,3]).contains([]) → true
  • [6.2.2] new Uint8Array([]).contains([]) → true

6.3 Position parameter

  • [6.3.1] new Uint8Array([1,2,3,4]).contains([3,4], 0) → true
  • [6.3.2] new Uint8Array([1,2,3,4]).contains([3,4], 3) → false (not enough room from position 3)

6.4 Return type

  • [6.4.1] Verify contains return value is strictly true (not 1 or truthy) when match found
  • [6.4.2] Verify contains return value is strictly false (not 0 or falsy) when no match

7. SameValueZero Equality Semantics

7.1 NaN matching

For each floating-point type (Float16Array, Float32Array, Float64Array):

  • [7.1.1] new <Type>([1, NaN, 3]).search(new <Type>([NaN])) → 1
  • [7.1.2] new <Type>([NaN, NaN]).search(new <Type>([NaN, NaN])) → 0
  • [7.1.3] new <Type>([NaN, 1, NaN]).searchLast(new <Type>([NaN])) → 2
  • [7.1.4] new <Type>([1, NaN, 3]).contains(new <Type>([NaN])) → true

7.2 +0 / -0 equivalence

For each floating-point type (Float16Array, Float32Array, Float64Array) and each method (search, searchLast, contains):

  • [7.2.1] new <Type>([1, -0, 3]).search(new <Type>([0])) → 1
  • [7.2.2] new <Type>([1, 0, 3]).search(new <Type>([-0])) → 1
  • [7.2.3] new <Type>([-0]).search(new <Type>([0])) → 0
  • [7.2.4] new <Type>([0]).search(new <Type>([-0])) → 0

7.3 NaN in subsequence

For each floating-point type (Float16Array, Float32Array, Float64Array) and each method (search, searchLast, contains):

  • [7.3.1] new <Type>([1, NaN, 3, 4]).search(new <Type>([NaN, 3])) → 1

7.4 Integer TypedArrays (no NaN / -0 concerns)

For each method (search, searchLast, contains):

  • [7.4.1] new Int32Array([-1, 0, 1]).search(new Int32Array([0, 1])) → 1

8. TypedArray Type Coverage

8.1 Basic search/searchLast/contains per type

For each non-BigInt type (Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float16Array, Float32Array, Float64Array):

  • [8.1.1] new <Type>([1,2,3]).search(new <Type>([2,3])) → 1
  • [8.1.2] new <Type>([1,2,3]).searchLast(new <Type>([2,3])) → 1
  • [8.1.3] new <Type>([1,2,3]).contains(new <Type>([2,3])) → true

For each BigInt type (BigInt64Array, BigUint64Array):

  • [8.1.4] new <Type>([1n,2n,3n]).search(new <Type>([2n,3n])) → 1
  • [8.1.5] new <Type>([1n,2n,3n]).searchLast(new <Type>([2n,3n])) → 1
  • [8.1.6] new <Type>([1n,2n,3n]).contains(new <Type>([2n,3n])) → true

8.2 BigInt array with iterable needle

  • [8.2.1] new BigInt64Array([1n, 2n, 3n]).search([2n, 3n]) → 1
  • [8.2.2] new BigUint64Array([1n, 2n, 3n]).search([2n, 3n]) → 1

8.3 Cross-type with BigInt

  • [8.3.1] new BigInt64Array([1n, 2n]).search(new BigUint64Array([1n, 2n])) → 0 (both yield BigInts)
  • [8.3.2] new BigInt64Array([1n, 2n]).search(new Uint8Array([1, 2])) → -1 (Uint8Array yields Numbers, BigInt64Array expects BigInts)

9. Evaluation Order and Observable Side Effects

9.1 ValidateTypedArray before ToCompatibleTypedArrayElementList

For each method (search, searchLast, contains):

  • [9.1.1] Detached buffer with an iterable needle that has observable side effects → TypeError from validation, iterator never called

9.2 ToCompatibleTypedArrayElementList before ValidateIntegralNumber

For each method (search, searchLast, contains):

  • [9.2.1] Valid TypedArray, invalid needle type, invalid position → TypeError from needle validation (position never validated)
    new Uint8Array([1,2,3]).search(42, 'bad') // → TypeError (from needle, not position)
    

9.3 ValidateIntegralNumber after needle validation

For each method (search, searchLast, contains):

  • [9.3.1] Valid TypedArray, valid iterable needle, invalid position → error from position validation
    new Uint8Array([1,2,3]).search([1,2], NaN) // → RangeError
    new Uint8Array([1,2,3]).search([1,2], 'bad') // → TypeError
    

9.4 Iterator side effects

For each method (search, searchLast, contains):

  • [9.4.1] Iterable whose iterator modifies global state → verify iteration happens exactly once
  • [9.4.2] Iterable whose iterator throws midway → error propagates, partial iteration observable

10. Property and Prototype

10.1 Method existence

  • [10.1.1] typeof Uint8Array.prototype.search'function'
  • [10.1.2] typeof Uint8Array.prototype.searchLast'function'
  • [10.1.3] typeof Uint8Array.prototype.contains'function'

10.2 Method .length property

  • [10.2.1] Uint8Array.prototype.search.length → 1
  • [10.2.2] Uint8Array.prototype.searchLast.length → 1
  • [10.2.3] Uint8Array.prototype.contains.length → 1

10.3 Method .name property

  • [10.3.1] Uint8Array.prototype.search.name'search'
  • [10.3.2] Uint8Array.prototype.searchLast.name'searchLast'
  • [10.3.3] Uint8Array.prototype.contains.name'contains'

10.4 Methods are on %TypedArray%.prototype

  • [10.4.1] Uint8Array.prototype.search === Int32Array.prototype.search → true
  • [10.4.2] Uint8Array.prototype.searchLast === Float64Array.prototype.searchLast → true
  • [10.4.3] Uint8Array.prototype.contains === BigInt64Array.prototype.contains → true

10.5 Not enumerable

  • [10.5.1] Object.getOwnPropertyDescriptor(Uint8Array.prototype, 'search').enumerable → false
  • [10.5.2] Object.getOwnPropertyDescriptor(Uint8Array.prototype, 'searchLast').enumerable → false
  • [10.5.3] Object.getOwnPropertyDescriptor(Uint8Array.prototype, 'contains').enumerable → false

11. Boundary and Stress Cases

11.1 Single-element haystack

  • [11.1.1] new Uint8Array([5]).search([5]) → 0
  • [11.1.2] new Uint8Array([5]).search([6]) → -1
  • [11.1.3] new Uint8Array([5]).searchLast([5]) → 0

11.2 Needle same length as haystack

  • [11.2.1] new Uint8Array([1,2,3]).search([1,2,3]) → 0
  • [11.2.2] new Uint8Array([1,2,3]).search([1,2,4]) → -1
  • [11.2.3] new Uint8Array([1,2,3]).searchLast([1,2,3]) → 0

11.3 Overlapping pattern in haystack

  • [11.3.1] new Uint8Array([1,1,1,2]).search([1,1,2]) → 1
  • [11.3.2] new Uint8Array([1,1,1,1]).search([1,1]) → 0
  • [11.3.3] new Uint8Array([1,1,1,1]).searchLast([1,1]) → 2

11.4 Repeated single value

  • [11.4.1] new Uint8Array([0,0,0,0,0]).search([0,0]) → 0
  • [11.4.2] new Uint8Array([0,0,0,0,0]).searchLast([0,0]) → 3
  • [11.4.3] new Uint8Array([0,0,0,0,0]).search([0,0], 2) → 2
  • [11.4.4] new Uint8Array([0,0,0,0,0]).searchLast([0,0], 2) → 2

11.5 Large TypedArrays

  • [11.5.1] Search in a large TypedArray (e.g., 10,000+ elements) with needle at the end → correct index
  • [11.5.2] Search in a large TypedArray with no match → -1
  • [11.5.3] searchLast in a large TypedArray with needle at the beginning → correct index

11.6 Position equals haystack length

  • [11.6.1] new Uint8Array([1,2,3]).search([], 3) → 3 (empty needle returns position)
  • [11.6.2] new Uint8Array([1,2,3]).search([1], 3) → -1 (position + needleLength > haystackLength)

11.7 Uint8ClampedArray behaviour

Note: ToCompatibleTypedArrayElementList validates that iterable elements are Numbers (for non-BigInt TypedArrays) but does not clamp them. The needle List contains the raw Number values as yielded by the iterator. A value like 300 is a valid Number, but will not SameValueZero-match any stored element (which was clamped to 255 on write).

  • [11.7.1] new Uint8ClampedArray([255, 0]).search([255]) → 0
  • [11.7.2] new Uint8ClampedArray([255, 0]).search([300]) → -1 (300 does not SameValueZero-equal 255)
  • [11.7.3] new Uint8ClampedArray([255, 0]).search(new Uint8ClampedArray([255])) → 0 (iterated value is 255, matches stored 255)

11.8 Typed integer overflow boundaries

  • [11.8.1] new Uint8Array([255, 0, 1]).search([255, 0]) → 0
  • [11.8.2] new Int8Array([-128, 127]).search([-128, 127]) → 0
  • [11.8.3] new Uint16Array([65535, 0]).search([65535, 0]) → 0
  • [11.8.4] new Int32Array([-2147483648, 2147483647]).search([-2147483648]) → 0

11.9 Methods called via .call() on different TypedArray subtypes

  • [11.9.1] Uint8Array.prototype.search.call(new Int32Array([1,2,3]), new Int32Array([2,3])) → 1 (this is Int32Array, needle is same-type relative to this)
  • [11.9.2] Uint8Array.prototype.search.call(new Int32Array([1,2,3]), new Uint8Array([2,3])) → 1 (needle is different-type, iterated via @@iterator)

11.10 Empty haystack with non-empty needle (both directions)

  • [11.10.1] new Uint8Array([]).search([1]) → -1
  • [11.10.2] new Uint8Array([]).searchLast([1]) → -1
  • [11.10.3] new Uint8Array([]).contains([1]) → false

12. SharedArrayBuffer Considerations

The needle is always snapshotted into a List via @@iterator before the search begins, so concurrent modifications to the needle's underlying buffer cannot affect the search. The haystack is not snapshotted — its elements are read directly during the search, consistent with indexOf and lastIndexOf. This means another agent may modify haystack elements during the search.

12.1 Needle backed by SharedArrayBuffer (snapshotted)

  • [12.1.1] Needle elements are read via @@iterator before the search begins, producing a fixed snapshot List. Concurrent writes to the needle's SharedArrayBuffer by another agent after iteration completes do not affect the search result.
  • [12.1.2] Example: needle [2, 3] is iterated and snapshotted; even if another agent changes the needle's buffer to [9, 9] mid-search, the search still looks for [2, 3].

12.2 Haystack backed by SharedArrayBuffer (not snapshotted)

  • [12.2.1] Haystack elements are read individually during the search (via Get). Another agent may modify elements of the haystack concurrently. This is the same behaviour as %TypedArray%.prototype.indexOf and %TypedArray%.prototype.lastIndexOf.
  • [12.2.2] A search may return -1 even if the needle was present at the start of the search, if another agent modifies the haystack during the search.
  • [12.2.3] A search may return an index where the needle no longer exists by the time the result is observed, if another agent modifies the haystack after the match is found.

12.3 Both haystack and needle backed by SharedArrayBuffer

  • [12.3.1] The needle is snapshotted before the search. The haystack is read live. The combination of these two behaviours is well-defined: the search compares a frozen needle List against live haystack reads.

13. Resizable ArrayBuffer Considerations

TypedArrays can be backed by resizable ArrayBuffers (created via new ArrayBuffer(n, { maxByteLength: m })). These buffers can be grown or shrunk via resize(), which can cause a TypedArray to go out of bounds. Auto-length TypedArrays (created without an explicit length) track the buffer size; fixed-length TypedArrays over resizable buffers have a fixed element count but can go out of bounds if the buffer shrinks.

The @@iterator for TypedArrays checks IsTypedArrayOutOfBounds on every .next() call and throws a TypeError if the TypedArray is out of bounds or detached at that point.

13.1 Haystack backed by a resizable ArrayBuffer (basic operation)

For each method (search, searchLast, contains):

  • [13.1.1] Auto-length haystack, no resize during operation → normal search behaviour, length tracks the buffer
    const rab = new ArrayBuffer(5, { maxByteLength: 10 });
    const u8 = new Uint8Array(rab);
    u8.set([1, 2, 3, 4, 5]);
    u8.search([3, 4]) // → 2
    
  • [13.1.2] Fixed-length haystack over resizable buffer, no resize → normal search behaviour
    const rab = new ArrayBuffer(8, { maxByteLength: 16 });
    const u8 = new Uint8Array(rab, 0, 5);
    u8.set([1, 2, 3, 4, 5]);
    u8.search([3, 4]) // → 2
    
  • [13.1.3] Auto-length haystack, buffer grown before calling search → search sees the new length
  • [13.1.4] Fixed-length haystack, buffer shrunk below the fixed length before calling searchValidateTypedArray throws TypeError (TypedArray is out of bounds)

13.2 Needle backed by a resizable ArrayBuffer (basic operation)

For each method (search, searchLast, contains):

  • [13.2.1] Auto-length needle TypedArray over resizable buffer, no resize → normal iteration, produces correct snapshot List
  • [13.2.2] Fixed-length needle TypedArray over resizable buffer, no resize → normal iteration, produces correct snapshot List

13.3 Needle iteration detaches the haystack's buffer

A custom iterable whose iterator detaches the haystack's ArrayBuffer during iteration. ValidateTypedArray was already called (step 2), so _taRecord_ has a pre-detachment buffer witness. After ToCompatibleTypedArrayElementList returns, TypedArrayLength(_taRecord_) uses the stale witness. The search proceeds but element reads from the detached buffer return undefined, which will not SameValueZero-match any numeric needle element.

  • [13.3.1] Custom iterable that detaches the haystack's ArrayBuffer during iteration → search returns -1 (element reads return undefined)
    const ab = new ArrayBuffer(5);
    const u8 = new Uint8Array(ab);
    u8.set([1, 2, 3, 4, 5]);
    const evilNeedle = {
      [Symbol.iterator]() {
        return {
          i: 0,
          next() {
            if (this.i === 0) {
              // Detach the haystack's buffer via transfer
              ab.transfer();
            }
            if (this.i < 2) return { value: this.i++ + 3, done: false };
            return { done: true };
          }
        };
      }
    };
    u8.search(evilNeedle) // → -1 (haystack buffer is now detached)
    
  • [13.3.2] Same scenario with contains → false
  • [13.3.3] Same scenario with searchLast → -1

13.4 Needle's own buffer shrunk or detached during its iteration

When the needle is a TypedArray backed by a resizable ArrayBuffer, the TypedArray @@iterator checks IsTypedArrayOutOfBounds on every .next() call. If the buffer is shrunk or detached such that the needle goes out of bounds, .next() throws a TypeError. This error propagates through IteratorToList and ToCompatibleTypedArrayElementList.

For each method (search, searchLast, contains):

  • [13.4.1] Needle is auto-length over a resizable buffer; a custom next() wrapper shrinks the buffer below the needle's byte offset mid-iteration → TypeError from @@iterator's .next()
  • [13.4.2] Needle is fixed-length over a resizable buffer; buffer is shrunk below byteOffset + length * elementSize mid-iteration → TypeError from @@iterator's .next()
  • [13.4.3] Needle TypedArray's buffer is detached during its own iteration → TypeError from @@iterator's .next()

13.5 Needle's buffer grown during its iteration (auto-length needle)

When the needle is an auto-length TypedArray and its resizable buffer is grown during iteration, the @@iterator sees the new larger TypedArrayLength and continues iterating into the newly available elements. This produces a longer-than-expected needle List.

For each method (search, searchLast, contains):

  • [13.5.1] Auto-length needle over a resizable buffer; buffer is grown during iteration → needle List contains more elements than initially expected; search uses the full (longer) snapshot

13.6 Haystack buffer resized during needle iteration

The _taRecord_ is created by ValidateTypedArray before needle iteration begins. If the haystack's resizable buffer is resized during needle iteration:

For each method (search, searchLast, contains):

  • [13.6.1] Haystack is auto-length; buffer is grown during needle iteration → TypedArrayLength(_taRecord_) returns the pre-growth length (witness is stale); search only scans the original range. Elements beyond the original length are not searched.
  • [13.6.2] Haystack is auto-length; buffer is shrunk during needle iteration (but TypedArray remains in bounds) → TypedArrayLength(_taRecord_) returns the pre-shrink length (witness is stale); search may read undefined for elements beyond the new length. Those reads will not match, effectively returning -1 for needles that would have matched only in the now-truncated region.
  • [13.6.3] Haystack is auto-length; buffer is shrunk below the haystack's byte offset during needle iteration → TypedArrayLength(_taRecord_) uses stale witness; search may read undefined for all elements. Returns -1.
  • [13.6.4] Haystack is fixed-length; buffer is shrunk below the fixed range during needle iteration → same stale-witness behaviour; element reads return undefined.

13.7 Both haystack and needle backed by resizable ArrayBuffers

For each method (search, searchLast, contains):

  • [13.7.1] Both are auto-length over separate resizable buffers, no resize during operation → normal behaviour
  • [13.7.2] Both share the same resizable ArrayBuffer (different views); no resize → needle is snapshotted via iteration, search proceeds normally
  • [13.7.3] Both share the same resizable ArrayBuffer; buffer is grown during needle iteration → needle snapshot may include new elements; haystack length uses stale witness

14. Self-Search and Overlapping Views

14.1 Self-search (searching a TypedArray for itself)

The needle is snapshotted into a List via @@iterator before the search begins, so the search compares the live haystack against an independent copy of its own elements.

  • [14.1.1] const u8 = new Uint8Array([1,2,3]); u8.search(u8) → 0 (entire array matches at index 0)
  • [14.1.2] const u8 = new Uint8Array([1,2,3]); u8.searchLast(u8) → 0 (only one possible match position)
  • [14.1.3] const u8 = new Uint8Array([1,2,3]); u8.contains(u8) → true
  • [14.1.4] const u8 = new Uint8Array([1,2,3]); u8.search(u8, 1) → -1 (needle length 3, only 2 elements from position 1)
  • [14.1.5] Self-search on empty TypedArray: const u8 = new Uint8Array([]); u8.search(u8) → 0 (empty needle returns position)
  • [14.1.6] Self-search on single-element TypedArray: const u8 = new Uint8Array([42]); u8.search(u8) → 0
  • [14.1.7] Self-search with BigInt TypedArray: const b = new BigInt64Array([1n,2n]); b.search(b) → 0

14.2 Needle and haystack sharing the same underlying ArrayBuffer (overlapping views)

Two TypedArrays backed by the same ArrayBuffer but with different byte offsets or lengths. The needle is snapshotted via iteration, so the search is safe regardless of overlap.

For each method (search, searchLast, contains):

  • [14.2.1] Overlapping views, needle is a subview of the haystack:
    const ab = new ArrayBuffer(5);
    const haystack = new Uint8Array(ab); // [1,2,3,4,5]
    haystack.set([1, 2, 3, 4, 5]);
    const needle = new Uint8Array(ab, 2, 2); // [3,4]
    haystack.search(needle) // → 2
    
  • [14.2.2] Overlapping views, haystack is a subview:
    const ab = new ArrayBuffer(5);
    const full = new Uint8Array(ab);
    full.set([1, 2, 3, 4, 5]);
    const haystack = new Uint8Array(ab, 1, 3); // [2,3,4]
    const needle = new Uint8Array(ab, 0, 2); // [1,2]
    haystack.search(needle) // → -1 (haystack is [2,3,4], needle is [1,2])
    
  • [14.2.3] Same buffer, same offset, different element types:
    const ab = new ArrayBuffer(8);
    const u8 = new Uint8Array(ab);
    u8.set([1, 0, 2, 0, 3, 0, 4, 0]);
    const u16 = new Uint16Array(ab); // [1, 2, 3, 4] on little-endian
    u16.search(new Uint16Array([2, 3])) // → 1
    

Related Documents