tree.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. 'use strict'
  2. const {
  3. wellknownHeaderNames,
  4. headerNameLowerCasedRecord
  5. } = require('./constants')
  6. class TstNode {
  7. /** @type {any} */
  8. value = null
  9. /** @type {null | TstNode} */
  10. left = null
  11. /** @type {null | TstNode} */
  12. middle = null
  13. /** @type {null | TstNode} */
  14. right = null
  15. /** @type {number} */
  16. code
  17. /**
  18. * @param {string} key
  19. * @param {any} value
  20. * @param {number} index
  21. */
  22. constructor (key, value, index) {
  23. if (index === undefined || index >= key.length) {
  24. throw new TypeError('Unreachable')
  25. }
  26. const code = this.code = key.charCodeAt(index)
  27. // check code is ascii string
  28. if (code > 0x7F) {
  29. throw new TypeError('key must be ascii string')
  30. }
  31. if (key.length !== ++index) {
  32. this.middle = new TstNode(key, value, index)
  33. } else {
  34. this.value = value
  35. }
  36. }
  37. /**
  38. * @param {string} key
  39. * @param {any} value
  40. * @returns {void}
  41. */
  42. add (key, value) {
  43. const length = key.length
  44. if (length === 0) {
  45. throw new TypeError('Unreachable')
  46. }
  47. let index = 0
  48. /**
  49. * @type {TstNode}
  50. */
  51. let node = this
  52. while (true) {
  53. const code = key.charCodeAt(index)
  54. // check code is ascii string
  55. if (code > 0x7F) {
  56. throw new TypeError('key must be ascii string')
  57. }
  58. if (node.code === code) {
  59. if (length === ++index) {
  60. node.value = value
  61. break
  62. } else if (node.middle !== null) {
  63. node = node.middle
  64. } else {
  65. node.middle = new TstNode(key, value, index)
  66. break
  67. }
  68. } else if (node.code < code) {
  69. if (node.left !== null) {
  70. node = node.left
  71. } else {
  72. node.left = new TstNode(key, value, index)
  73. break
  74. }
  75. } else if (node.right !== null) {
  76. node = node.right
  77. } else {
  78. node.right = new TstNode(key, value, index)
  79. break
  80. }
  81. }
  82. }
  83. /**
  84. * @param {Uint8Array} key
  85. * @returns {TstNode | null}
  86. */
  87. search (key) {
  88. const keylength = key.length
  89. let index = 0
  90. /**
  91. * @type {TstNode|null}
  92. */
  93. let node = this
  94. while (node !== null && index < keylength) {
  95. let code = key[index]
  96. // A-Z
  97. // First check if it is bigger than 0x5a.
  98. // Lowercase letters have higher char codes than uppercase ones.
  99. // Also we assume that headers will mostly contain lowercase characters.
  100. if (code <= 0x5a && code >= 0x41) {
  101. // Lowercase for uppercase.
  102. code |= 32
  103. }
  104. while (node !== null) {
  105. if (code === node.code) {
  106. if (keylength === ++index) {
  107. // Returns Node since it is the last key.
  108. return node
  109. }
  110. node = node.middle
  111. break
  112. }
  113. node = node.code < code ? node.left : node.right
  114. }
  115. }
  116. return null
  117. }
  118. }
  119. class TernarySearchTree {
  120. /** @type {TstNode | null} */
  121. node = null
  122. /**
  123. * @param {string} key
  124. * @param {any} value
  125. * @returns {void}
  126. * */
  127. insert (key, value) {
  128. if (this.node === null) {
  129. this.node = new TstNode(key, value, 0)
  130. } else {
  131. this.node.add(key, value)
  132. }
  133. }
  134. /**
  135. * @param {Uint8Array} key
  136. * @returns {any}
  137. */
  138. lookup (key) {
  139. return this.node?.search(key)?.value ?? null
  140. }
  141. }
  142. const tree = new TernarySearchTree()
  143. for (let i = 0; i < wellknownHeaderNames.length; ++i) {
  144. const key = headerNameLowerCasedRecord[wellknownHeaderNames[i]]
  145. tree.insert(key, key)
  146. }
  147. module.exports = {
  148. TernarySearchTree,
  149. tree
  150. }