ordered_group.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. package middleware
  2. import "fmt"
  3. // RelativePosition provides specifying the relative position of a middleware
  4. // in an ordered group.
  5. type RelativePosition int
  6. // Relative position for middleware in steps.
  7. const (
  8. After RelativePosition = iota
  9. Before
  10. )
  11. type ider interface {
  12. ID() string
  13. }
  14. // orderedIDs provides an ordered collection of items with relative ordering
  15. // by name.
  16. type orderedIDs struct {
  17. order *relativeOrder
  18. items map[string]ider
  19. }
  20. // selected based on the general upper bound of # of middlewares in each step
  21. // in the downstream aws-sdk-go-v2
  22. const baseOrderedItems = 8
  23. func newOrderedIDs(cap int) *orderedIDs {
  24. return &orderedIDs{
  25. order: newRelativeOrder(cap),
  26. items: make(map[string]ider, cap),
  27. }
  28. }
  29. // Add injects the item to the relative position of the item group. Returns an
  30. // error if the item already exists.
  31. func (g *orderedIDs) Add(m ider, pos RelativePosition) error {
  32. id := m.ID()
  33. if len(id) == 0 {
  34. return fmt.Errorf("empty ID, ID must not be empty")
  35. }
  36. if err := g.order.Add(pos, id); err != nil {
  37. return err
  38. }
  39. g.items[id] = m
  40. return nil
  41. }
  42. // Insert injects the item relative to an existing item id. Returns an error if
  43. // the original item does not exist, or the item being added already exists.
  44. func (g *orderedIDs) Insert(m ider, relativeTo string, pos RelativePosition) error {
  45. if len(m.ID()) == 0 {
  46. return fmt.Errorf("insert ID must not be empty")
  47. }
  48. if len(relativeTo) == 0 {
  49. return fmt.Errorf("relative to ID must not be empty")
  50. }
  51. if err := g.order.Insert(relativeTo, pos, m.ID()); err != nil {
  52. return err
  53. }
  54. g.items[m.ID()] = m
  55. return nil
  56. }
  57. // Get returns the ider identified by id. If ider is not present, returns false.
  58. func (g *orderedIDs) Get(id string) (ider, bool) {
  59. v, ok := g.items[id]
  60. return v, ok
  61. }
  62. // Swap removes the item by id, replacing it with the new item. Returns an error
  63. // if the original item doesn't exist.
  64. func (g *orderedIDs) Swap(id string, m ider) (ider, error) {
  65. if len(id) == 0 {
  66. return nil, fmt.Errorf("swap from ID must not be empty")
  67. }
  68. iderID := m.ID()
  69. if len(iderID) == 0 {
  70. return nil, fmt.Errorf("swap to ID must not be empty")
  71. }
  72. if err := g.order.Swap(id, iderID); err != nil {
  73. return nil, err
  74. }
  75. removed := g.items[id]
  76. delete(g.items, id)
  77. g.items[iderID] = m
  78. return removed, nil
  79. }
  80. // Remove removes the item by id. Returns an error if the item
  81. // doesn't exist.
  82. func (g *orderedIDs) Remove(id string) (ider, error) {
  83. if len(id) == 0 {
  84. return nil, fmt.Errorf("remove ID must not be empty")
  85. }
  86. if err := g.order.Remove(id); err != nil {
  87. return nil, err
  88. }
  89. removed := g.items[id]
  90. delete(g.items, id)
  91. return removed, nil
  92. }
  93. func (g *orderedIDs) List() []string {
  94. items := g.order.List()
  95. order := make([]string, len(items))
  96. copy(order, items)
  97. return order
  98. }
  99. // Clear removes all entries and slots.
  100. func (g *orderedIDs) Clear() {
  101. g.order.Clear()
  102. g.items = map[string]ider{}
  103. }
  104. // GetOrder returns the item in the order it should be invoked in.
  105. func (g *orderedIDs) GetOrder() []interface{} {
  106. order := g.order.List()
  107. ordered := make([]interface{}, len(order))
  108. for i := 0; i < len(order); i++ {
  109. ordered[i] = g.items[order[i]]
  110. }
  111. return ordered
  112. }
  113. // relativeOrder provides ordering of item
  114. type relativeOrder struct {
  115. order []string
  116. }
  117. func newRelativeOrder(cap int) *relativeOrder {
  118. return &relativeOrder{
  119. order: make([]string, 0, cap),
  120. }
  121. }
  122. // Add inserts an item into the order relative to the position provided.
  123. func (s *relativeOrder) Add(pos RelativePosition, ids ...string) error {
  124. if len(ids) == 0 {
  125. return nil
  126. }
  127. for _, id := range ids {
  128. if _, ok := s.has(id); ok {
  129. return fmt.Errorf("already exists, %v", id)
  130. }
  131. }
  132. switch pos {
  133. case Before:
  134. return s.insert(0, Before, ids...)
  135. case After:
  136. s.order = append(s.order, ids...)
  137. default:
  138. return fmt.Errorf("invalid position, %v", int(pos))
  139. }
  140. return nil
  141. }
  142. // Insert injects an item before or after the relative item. Returns
  143. // an error if the relative item does not exist.
  144. func (s *relativeOrder) Insert(relativeTo string, pos RelativePosition, ids ...string) error {
  145. if len(ids) == 0 {
  146. return nil
  147. }
  148. for _, id := range ids {
  149. if _, ok := s.has(id); ok {
  150. return fmt.Errorf("already exists, %v", id)
  151. }
  152. }
  153. i, ok := s.has(relativeTo)
  154. if !ok {
  155. return fmt.Errorf("not found, %v", relativeTo)
  156. }
  157. return s.insert(i, pos, ids...)
  158. }
  159. // Swap will replace the item id with the to item. Returns an
  160. // error if the original item id does not exist. Allows swapping out an
  161. // item for another item with the same id.
  162. func (s *relativeOrder) Swap(id, to string) error {
  163. i, ok := s.has(id)
  164. if !ok {
  165. return fmt.Errorf("not found, %v", id)
  166. }
  167. if _, ok = s.has(to); ok && id != to {
  168. return fmt.Errorf("already exists, %v", to)
  169. }
  170. s.order[i] = to
  171. return nil
  172. }
  173. func (s *relativeOrder) Remove(id string) error {
  174. i, ok := s.has(id)
  175. if !ok {
  176. return fmt.Errorf("not found, %v", id)
  177. }
  178. s.order = append(s.order[:i], s.order[i+1:]...)
  179. return nil
  180. }
  181. func (s *relativeOrder) List() []string {
  182. return s.order
  183. }
  184. func (s *relativeOrder) Clear() {
  185. s.order = s.order[0:0]
  186. }
  187. func (s *relativeOrder) insert(i int, pos RelativePosition, ids ...string) error {
  188. switch pos {
  189. case Before:
  190. n := len(ids)
  191. var src []string
  192. if n <= cap(s.order)-len(s.order) {
  193. s.order = s.order[:len(s.order)+n]
  194. src = s.order
  195. } else {
  196. src = s.order
  197. s.order = make([]string, len(s.order)+n)
  198. copy(s.order[:i], src[:i]) // only when allocating a new slice do we need to copy the front half
  199. }
  200. copy(s.order[i+n:], src[i:])
  201. copy(s.order[i:], ids)
  202. case After:
  203. if i == len(s.order)-1 || len(s.order) == 0 {
  204. s.order = append(s.order, ids...)
  205. } else {
  206. s.order = append(s.order[:i+1], append(ids, s.order[i+1:]...)...)
  207. }
  208. default:
  209. return fmt.Errorf("invalid position, %v", int(pos))
  210. }
  211. return nil
  212. }
  213. func (s *relativeOrder) has(id string) (i int, found bool) {
  214. for i := 0; i < len(s.order); i++ {
  215. if s.order[i] == id {
  216. return i, true
  217. }
  218. }
  219. return 0, false
  220. }