Skip to content

Commit

Permalink
optimize find method
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-tymoshenko committed Dec 26, 2021
1 parent c01e005 commit 471a55f
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 121 deletions.
16 changes: 12 additions & 4 deletions custom_node.js
Expand Up @@ -135,15 +135,23 @@ Node.prototype.findByLabel = function (path) {
return this.children[path[0]]
}

Node.prototype.findMatchingChild = function (derivedConstraints, path) {
var child = this.children[path[0]]
Node.prototype.findMatchingChild = function (derivedConstraints, path, pathIndex) {
var child = this.children[path[pathIndex]]
if (child !== undefined && (child.numberOfChildren > 0 || child.getMatchingHandler(derivedConstraints) !== null)) {
if (path.slice(0, child.prefix.length) === child.prefix) {
let isPathStartsWithPrefix = true
for (let i = 0; i < child.prefix.length; i++) {
if (path.charCodeAt(pathIndex + i) !== child.prefix.charCodeAt(i)) {
isPathStartsWithPrefix = false
break
}
}

if (isPathStartsWithPrefix) {
return child
}
}

child = this.children[':']
child = path[pathIndex] !== ':' ? this.children[':'] : undefined
if (child !== undefined && (child.numberOfChildren > 0 || child.getMatchingHandler(derivedConstraints) !== null)) {
return child
}
Expand Down
190 changes: 73 additions & 117 deletions index.js
Expand Up @@ -398,7 +398,7 @@ Router.prototype.lookup = function lookup (req, res, ctx) {
}

Router.prototype.find = function find (method, path, derivedConstraints) {
var currentNode = this.trees[method]
let currentNode = this.trees[method]
if (currentNode === undefined) return null

if (path.charCodeAt(0) !== 47) { // 47 is '/'
Expand All @@ -413,37 +413,35 @@ Router.prototype.find = function find (method, path, derivedConstraints) {
return this._onBadUrl(path)
}

var originalPath = path
var originalPathLength = path.length

if (this.caseSensitive === false) {
path = path.toLowerCase()
}

var maxParamLength = this.maxParamLength
var wildcardNode = null
var pathLenWildcard = 0
var decoded = null
const maxParamLength = this.maxParamLength

let pathIndex = currentNode.prefix.length
const params = []
var i = 0
var idxInOriginalPath = 0
const pathLen = path.length

let wildcardNode = null
let wildcardNodePathIndex = 0

let lastParametricBrother = null
const parametricBrothersStack = []

while (true) {
var pathLen = path.length
var prefix = currentNode.prefix

// found the route
if (pathLen === 0 || path === prefix) {
var handle = derivedConstraints !== undefined ? currentNode.getMatchingHandler(derivedConstraints) : currentNode.unconstrainedHandler
if (pathIndex === pathLen) {
const handle = derivedConstraints !== undefined
? currentNode.getMatchingHandler(derivedConstraints)
: currentNode.unconstrainedHandler

if (handle !== null && handle !== undefined) {
var paramsObj = {}
const paramsObj = {}
if (handle.paramsLength > 0) {
var paramNames = handle.params
const paramNames = handle.params

for (i = 0; i < handle.paramsLength; i++) {
for (let i = 0; i < handle.paramsLength; i++) {
paramsObj[paramNames[i]] = params[i]
}
}
Expand All @@ -456,150 +454,108 @@ Router.prototype.find = function find (method, path, derivedConstraints) {
}
}

const parameterBrother = currentNode.parametricBrother
if (
path !== '' &&
parameterBrother !== null &&
parameterBrother !== lastParametricBrother
) {
parametricBrothersStack.push({
pathPointer: originalPathLength - pathLen,
paramsCount: params.length
})
lastParametricBrother = parameterBrother
}

var prefixLen = prefix.length
var len = 0

// search for the longest common prefix
i = pathLen < prefixLen ? pathLen : prefixLen
while (len < i && path.charCodeAt(len) === prefix.charCodeAt(len)) len++

if (len === prefixLen) {
path = path.slice(len)
pathLen = path.length
idxInOriginalPath += len
}

var node = currentNode.findMatchingChild(derivedConstraints, path)
let node = currentNode.findMatchingChild(derivedConstraints, path, pathIndex)

if (node === null) {
node = currentNode.parametricBrother
if (node === null) {
return this._getWildcardNode(wildcardNode, originalPath, pathLenWildcard, derivedConstraints, params)
return this._getWildcardNode(wildcardNode, path, wildcardNodePathIndex, derivedConstraints, params)
}

const { pathPointer, paramsCount } = parametricBrothersStack.pop()
const parametricBrotherPath = originalPath.slice(pathPointer)
const { brotherPathIndex, paramsCount } = parametricBrothersStack.pop()
pathIndex = brotherPathIndex
params.splice(paramsCount)
} else if (
pathIndex < pathLen &&
node.parametricBrother !== null &&
node.parametricBrother !== lastParametricBrother
) {
parametricBrothersStack.push({
brotherPathIndex: pathIndex,
paramsCount: params.length
})
lastParametricBrother = node.parametricBrother
}

idxInOriginalPath = idxInOriginalPath -
(parametricBrotherPath.length - path.length)
path = parametricBrotherPath
pathLen = parametricBrotherPath.length
len = prefixLen
// if exist, save the wildcard child
if (currentNode.wildcardChild !== null) {
wildcardNode = currentNode.wildcardChild
wildcardNodePathIndex = pathIndex
}

var kind = node.kind
currentNode = node
const kind = node.kind

// static route
if (kind === NODE_TYPES.STATIC) {
// if exist, save the wildcard child
if (currentNode.wildcardChild !== null) {
wildcardNode = currentNode.wildcardChild
pathLenWildcard = pathLen
}
currentNode = node
pathIndex += node.prefix.length
continue
}

if (len !== prefixLen) {
return this._getWildcardNode(wildcardNode, originalPath, pathLenWildcard, derivedConstraints, params)
}

// if exist, save the wildcard child
if (currentNode.wildcardChild !== null) {
wildcardNode = currentNode.wildcardChild
pathLenWildcard = pathLen
}
let paramEndIndex = pathIndex

// parametric route
if (kind === NODE_TYPES.PARAM) {
currentNode = node
i = path.indexOf('/')
if (i === -1) i = pathLen
if (i > maxParamLength) return null
decoded = sanitizedUrl.sliceParameter(idxInOriginalPath, idxInOriginalPath + i)
if (decoded === null) {
return this._onBadUrl(originalPath.slice(idxInOriginalPath, idxInOriginalPath + i))
for (; paramEndIndex < pathLen; paramEndIndex++) {
if (path.charCodeAt(paramEndIndex) === 47) {
break
}
}
params.push(decoded)
path = path.slice(i)
idxInOriginalPath += i
continue
}

// wildcard route
if (kind === NODE_TYPES.MATCH_ALL) {
decoded = sanitizedUrl.sliceParameter(idxInOriginalPath)
if (decoded === null) {
return this._onBadUrl(originalPath.slice(idxInOriginalPath))
}
params.push(decoded)
currentNode = node
path = ''
continue
paramEndIndex = pathLen
}

// parametric(regex) route
if (kind === NODE_TYPES.REGEX) {
currentNode = node
i = path.indexOf('/')
if (i === -1) i = pathLen
if (i > maxParamLength) return null
decoded = sanitizedUrl.sliceParameter(idxInOriginalPath, idxInOriginalPath + i)
if (decoded === null) {
return this._onBadUrl(originalPath.slice(idxInOriginalPath, idxInOriginalPath + i))
for (; paramEndIndex < pathLen; paramEndIndex++) {
if (path.charCodeAt(paramEndIndex) === 47) {
break
}
}
if (!node.regex.test(path.slice(pathIndex, paramEndIndex))) {
return null
}
if (!node.regex.test(decoded)) return null
params.push(decoded)
path = path.slice(i)
idxInOriginalPath += i
continue
}

// multiparametric route
if (kind === NODE_TYPES.MULTI_PARAM) {
currentNode = node
i = 0
if (node.regex !== null) {
var matchedParameter = path.match(node.regex)
const matchedParameter = node.regex.exec(path.slice(pathIndex))
if (matchedParameter === null) return null
i = matchedParameter[1].length
paramEndIndex = pathIndex + matchedParameter[1].length
} else {
while (i < pathLen && path.charCodeAt(i) !== 47 && path.charCodeAt(i) !== 45 && path.charCodeAt(i) !== 46) i++
if (i > maxParamLength) return null
}
decoded = sanitizedUrl.sliceParameter(idxInOriginalPath, idxInOriginalPath + i)
if (decoded === null) {
return this._onBadUrl(originalPath.slice(idxInOriginalPath, idxInOriginalPath + i))
for (; paramEndIndex < pathLen; paramEndIndex++) {
const charCode = path.charCodeAt(paramEndIndex)
if (charCode === 47 || charCode === 45 || charCode === 46) {
break
}
}
}
params.push(decoded)
path = path.slice(i)
idxInOriginalPath += i
continue
}

wildcardNode = null
if (paramEndIndex > pathIndex + maxParamLength) {
return null
}

const decoded = sanitizedUrl.sliceParameter(pathIndex, paramEndIndex)
if (decoded === null) {
return this._onBadUrl(path.slice(pathIndex, paramEndIndex))
}

params.push(decoded)
pathIndex = paramEndIndex
// wildcardNode = null
}
}

Router.prototype._getWildcardNode = function (node, sanitizedUrl, len, derivedConstraints, params) {
if (node === null) return null
var decoded = sanitizedUrl.slice(-len)
var decoded = sanitizedUrl.slice(len)
if (decoded === null) {
return this._onBadUrl(sanitizedUrl.slice(-len))
return this._onBadUrl(sanitizedUrl.slice(len))
}

var handle = derivedConstraints !== undefined ? node.getMatchingHandler(derivedConstraints) : node.unconstrainedHandler
Expand Down

0 comments on commit 471a55f

Please sign in to comment.