tree.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package search
  2. import "errors"
  3. const (
  4. colon = ':'
  5. slash = '/'
  6. )
  7. var (
  8. // ErrDupItem means adding duplicated item.
  9. ErrDupItem = errors.New("duplicated item")
  10. // ErrDupSlash means item is started with more than one slash.
  11. ErrDupSlash = errors.New("duplicated slash")
  12. // ErrEmptyItem means adding empty item.
  13. ErrEmptyItem = errors.New("empty item")
  14. // ErrInvalidState means search tree is in an invalid state.
  15. ErrInvalidState = errors.New("search tree is in an invalid state")
  16. // ErrNotFromRoot means path is not starting with slash.
  17. ErrNotFromRoot = errors.New("path should start with /")
  18. // NotFound is used to hold the not found result.
  19. NotFound Result
  20. )
  21. type (
  22. innerResult struct {
  23. key string
  24. value string
  25. named bool
  26. found bool
  27. }
  28. node struct {
  29. item interface{}
  30. children [2]map[string]*node
  31. }
  32. // A Tree is a search tree.
  33. Tree struct {
  34. root *node
  35. }
  36. // A Result is a search result from tree.
  37. Result struct {
  38. Item interface{}
  39. Params map[string]string
  40. }
  41. )
  42. // NewTree returns a Tree.
  43. func NewTree() *Tree {
  44. return &Tree{
  45. root: newNode(nil),
  46. }
  47. }
  48. // Add adds item to associate with route.
  49. func (t *Tree) Add(route string, item interface{}) error {
  50. if len(route) == 0 || route[0] != slash {
  51. return ErrNotFromRoot
  52. }
  53. if item == nil {
  54. return ErrEmptyItem
  55. }
  56. return add(t.root, route[1:], item)
  57. }
  58. // Search searches item that associates with given route.
  59. func (t *Tree) Search(route string) (Result, bool) {
  60. if len(route) == 0 || route[0] != slash {
  61. return NotFound, false
  62. }
  63. var result Result
  64. ok := t.next(t.root, route[1:], &result)
  65. return result, ok
  66. }
  67. func (t *Tree) next(n *node, route string, result *Result) bool {
  68. if len(route) == 0 && n.item != nil {
  69. result.Item = n.item
  70. return true
  71. }
  72. for i := range route {
  73. if route[i] == slash {
  74. token := route[:i]
  75. return n.forEach(func(k string, v *node) bool {
  76. if r := match(k, token); r.found {
  77. if t.next(v, route[i+1:], result) {
  78. if r.named {
  79. addParam(result, r.key, r.value)
  80. }
  81. return true
  82. }
  83. }
  84. return false
  85. })
  86. }
  87. }
  88. return n.forEach(func(k string, v *node) bool {
  89. if r := match(k, route); r.found && v.item != nil {
  90. result.Item = v.item
  91. if r.named {
  92. addParam(result, r.key, r.value)
  93. }
  94. return true
  95. }
  96. return false
  97. })
  98. }
  99. func (nd *node) forEach(fn func(string, *node) bool) bool {
  100. for _, children := range nd.children {
  101. for k, v := range children {
  102. if fn(k, v) {
  103. return true
  104. }
  105. }
  106. }
  107. return false
  108. }
  109. func (nd *node) getChildren(route string) map[string]*node {
  110. if len(route) > 0 && route[0] == colon {
  111. return nd.children[1]
  112. }
  113. return nd.children[0]
  114. }
  115. func add(nd *node, route string, item interface{}) error {
  116. if len(route) == 0 {
  117. if nd.item != nil {
  118. return ErrDupItem
  119. }
  120. nd.item = item
  121. return nil
  122. }
  123. if route[0] == slash {
  124. return ErrDupSlash
  125. }
  126. for i := range route {
  127. if route[i] == slash {
  128. token := route[:i]
  129. children := nd.getChildren(token)
  130. if child, ok := children[token]; ok {
  131. if child != nil {
  132. return add(child, route[i+1:], item)
  133. }
  134. return ErrInvalidState
  135. }
  136. child := newNode(nil)
  137. children[token] = child
  138. return add(child, route[i+1:], item)
  139. }
  140. }
  141. children := nd.getChildren(route)
  142. if child, ok := children[route]; ok {
  143. if child.item != nil {
  144. return ErrDupItem
  145. }
  146. child.item = item
  147. } else {
  148. children[route] = newNode(item)
  149. }
  150. return nil
  151. }
  152. func addParam(result *Result, k, v string) {
  153. if result.Params == nil {
  154. result.Params = make(map[string]string)
  155. }
  156. result.Params[k] = v
  157. }
  158. func match(pat, token string) innerResult {
  159. if pat[0] == colon {
  160. return innerResult{
  161. key: pat[1:],
  162. value: token,
  163. named: true,
  164. found: true,
  165. }
  166. }
  167. return innerResult{
  168. found: pat == token,
  169. }
  170. }
  171. func newNode(item interface{}) *node {
  172. return &node{
  173. item: item,
  174. children: [2]map[string]*node{
  175. make(map[string]*node),
  176. make(map[string]*node),
  177. },
  178. }
  179. }