tree.go 4.2 KB

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