tree.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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. continue
  86. }
  87. token := route[:i]
  88. return n.forEach(func(k string, v *node) bool {
  89. r := match(k, token)
  90. if !r.found || !t.next(v, route[i+1:], result) {
  91. return false
  92. }
  93. if r.named {
  94. addParam(result, r.key, r.value)
  95. }
  96. return true
  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. continue
  140. }
  141. token := route[:i]
  142. children := nd.getChildren(token)
  143. if child, ok := children[token]; ok {
  144. if child != nil {
  145. return add(child, route[i+1:], item)
  146. }
  147. return errInvalidState
  148. }
  149. child := newNode(nil)
  150. children[token] = child
  151. return add(child, route[i+1:], item)
  152. }
  153. children := nd.getChildren(route)
  154. if child, ok := children[route]; ok {
  155. if child.item != nil {
  156. return errDupItem
  157. }
  158. child.item = item
  159. } else {
  160. children[route] = newNode(item)
  161. }
  162. return nil
  163. }
  164. func addParam(result *Result, k, v string) {
  165. if result.Params == nil {
  166. result.Params = make(map[string]string)
  167. }
  168. result.Params[k] = v
  169. }
  170. func duplicatedItem(item string) error {
  171. return fmt.Errorf("duplicated item for %s", item)
  172. }
  173. func duplicatedSlash(item string) error {
  174. return fmt.Errorf("duplicated slash for %s", item)
  175. }
  176. func match(pat, token string) innerResult {
  177. if pat[0] == colon {
  178. return innerResult{
  179. key: pat[1:],
  180. value: token,
  181. named: true,
  182. found: true,
  183. }
  184. }
  185. return innerResult{
  186. found: pat == token,
  187. }
  188. }
  189. func newNode(item interface{}) *node {
  190. return &node{
  191. item: item,
  192. children: [2]map[string]*node{
  193. make(map[string]*node),
  194. make(map[string]*node),
  195. },
  196. }
  197. }