Skip to content

Commit

Permalink
Merge pull request #127 from dcposch/dc/lastindexof
Browse files Browse the repository at this point in the history
Buffer.lastIndexOf
  • Loading branch information
feross authored Aug 8, 2016
2 parents 02b0eb3 + f0d0a7c commit b63b710
Show file tree
Hide file tree
Showing 2 changed files with 209 additions and 166 deletions.
147 changes: 95 additions & 52 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,72 @@ Buffer.prototype.compare = function compare (target, start, end, thisStart, this
return 0
}

function arrayIndexOf (arr, val, byteOffset, encoding) {
// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
// OR the last index of `val` in `buffer` at offset <= `byteOffset`.
//
// Arguments:
// - buffer - a Buffer to search
// - val - a string, Buffer, or number
// - byteOffset - an index into `buffer`; will be clamped to an int32
// - encoding - an optional encoding, relevant is val is a string
// - dir - true for indexOf, false for lastIndexOf
function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
// Empty buffer means no match
if (buffer.length === 0) return -1

// Normalize byteOffset
if (typeof byteOffset === 'string') {
encoding = byteOffset
byteOffset = 0
} else if (byteOffset > 0x7fffffff) {
byteOffset = 0x7fffffff
} else if (byteOffset < -0x80000000) {
byteOffset = -0x80000000
}
byteOffset = +byteOffset // Coerce to Number.
if (isNaN(byteOffset)) {
// byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
byteOffset = dir ? 0 : (buffer.length - 1)
}

// Normalize byteOffset: negative offsets start from the end of the buffer
if (byteOffset < 0) byteOffset = buffer.length + byteOffset
if (byteOffset >= buffer.length) {
if (dir) return -1
else byteOffset = buffer.length - 1
} else if (byteOffset < 0) {
if (dir) byteOffset = 0
else return -1
}

// Normalize val
if (typeof val === 'string') {
val = Buffer.from(val, encoding)
}

// Finally, search either indexOf (if dir is true) or lastIndexOf
if (Buffer.isBuffer(val)) {
// Special case: looking for empty string/buffer always fails
if (val.length === 0) {
return -1
}
return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
} else if (typeof val === 'number') {
val = val & 0xFF // Search for a byte value [0-255]
if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {
if (dir) {
return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
} else {
return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
}
}
return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)
}

throw new TypeError('val must be string, number or Buffer')
}

function arrayIndexOf (arr, val, byteOffset, encoding, dir) {
var indexSize = 1
var arrLength = arr.length
var valLength = val.length
Expand All @@ -673,67 +738,45 @@ function arrayIndexOf (arr, val, byteOffset, encoding) {
}
}

var foundIndex = -1
for (var i = byteOffset; i < arrLength; ++i) {
if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
if (foundIndex === -1) foundIndex = i
if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
} else {
if (foundIndex !== -1) i -= i - foundIndex
foundIndex = -1
var i
if (dir) {
var foundIndex = -1
for (i = byteOffset; i < arrLength; i++) {
if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
if (foundIndex === -1) foundIndex = i
if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
} else {
if (foundIndex !== -1) i -= i - foundIndex
foundIndex = -1
}
}
} else {
if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength
for (i = byteOffset; i >= 0; i--) {
var found = true
for (var j = 0; j < valLength; j++) {
if (read(arr, i + j) !== read(val, j)) {
found = false
break
}
}
if (found) return i
}
}

return -1
}

Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
if (typeof byteOffset === 'string') {
encoding = byteOffset
byteOffset = 0
} else if (byteOffset > 0x7fffffff) {
byteOffset = 0x7fffffff
} else if (byteOffset < -0x80000000) {
byteOffset = -0x80000000
}
byteOffset >>= 0

if (this.length === 0) return -1
if (byteOffset >= this.length) return -1

// Negative offsets start from the end of the buffer
if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)

if (typeof val === 'string') {
val = Buffer.from(val, encoding)
}

if (Buffer.isBuffer(val)) {
// special case: looking for empty string/buffer always fails
if (val.length === 0) {
return -1
}
return arrayIndexOf(this, val, byteOffset, encoding)
}
if (typeof val === 'number') {
// Numbers will be interpreted as unsigned 8-bit integer values between
// `0` and `255`.
val &= 0xFF
if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {
return Uint8Array.prototype.indexOf.call(this, val, byteOffset)
}
return arrayIndexOf(this, [ val ], byteOffset, encoding)
}

throw new TypeError('val must be string, number or Buffer')
Buffer.prototype.includes = function includes (val, byteOffset, encoding) {
return this.indexOf(val, byteOffset, encoding) !== -1
}

Buffer.prototype.lastIndexOf = function () {
throw new Error('Not implemented yet. PR welcome! https://github.com/feross/buffer/issues/114')
Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
}

Buffer.prototype.includes = function includes (val, byteOffset, encoding) {
return this.indexOf(val, byteOffset, encoding) !== -1
Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
}

function hexWrite (buf, string, offset, length) {
Expand Down
Loading

0 comments on commit b63b710

Please sign in to comment.