option.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. package httphead
  2. import (
  3. "bytes"
  4. "sort"
  5. )
  6. // Option represents a header option.
  7. type Option struct {
  8. Name []byte
  9. Parameters Parameters
  10. }
  11. // Size returns number of bytes need to be allocated for use in opt.Copy.
  12. func (opt Option) Size() int {
  13. return len(opt.Name) + opt.Parameters.bytes
  14. }
  15. // Copy copies all underlying []byte slices into p and returns new Option.
  16. // Note that p must be at least of opt.Size() length.
  17. func (opt Option) Copy(p []byte) Option {
  18. n := copy(p, opt.Name)
  19. opt.Name = p[:n]
  20. opt.Parameters, p = opt.Parameters.Copy(p[n:])
  21. return opt
  22. }
  23. // Clone is a shorthand for making slice of opt.Size() sequenced with Copy()
  24. // call.
  25. func (opt Option) Clone() Option {
  26. return opt.Copy(make([]byte, opt.Size()))
  27. }
  28. // String represents option as a string.
  29. func (opt Option) String() string {
  30. return "{" + string(opt.Name) + " " + opt.Parameters.String() + "}"
  31. }
  32. // NewOption creates named option with given parameters.
  33. func NewOption(name string, params map[string]string) Option {
  34. p := Parameters{}
  35. for k, v := range params {
  36. p.Set([]byte(k), []byte(v))
  37. }
  38. return Option{
  39. Name: []byte(name),
  40. Parameters: p,
  41. }
  42. }
  43. // Equal reports whether option is equal to b.
  44. func (opt Option) Equal(b Option) bool {
  45. if bytes.Equal(opt.Name, b.Name) {
  46. return opt.Parameters.Equal(b.Parameters)
  47. }
  48. return false
  49. }
  50. // Parameters represents option's parameters.
  51. type Parameters struct {
  52. pos int
  53. bytes int
  54. arr [8]pair
  55. dyn []pair
  56. }
  57. // Equal reports whether a equal to b.
  58. func (p Parameters) Equal(b Parameters) bool {
  59. switch {
  60. case p.dyn == nil && b.dyn == nil:
  61. case p.dyn != nil && b.dyn != nil:
  62. default:
  63. return false
  64. }
  65. ad, bd := p.data(), b.data()
  66. if len(ad) != len(bd) {
  67. return false
  68. }
  69. sort.Sort(pairs(ad))
  70. sort.Sort(pairs(bd))
  71. for i := 0; i < len(ad); i++ {
  72. av, bv := ad[i], bd[i]
  73. if !bytes.Equal(av.key, bv.key) || !bytes.Equal(av.value, bv.value) {
  74. return false
  75. }
  76. }
  77. return true
  78. }
  79. // Size returns number of bytes that needed to copy p.
  80. func (p *Parameters) Size() int {
  81. return p.bytes
  82. }
  83. // Copy copies all underlying []byte slices into dst and returns new
  84. // Parameters.
  85. // Note that dst must be at least of p.Size() length.
  86. func (p *Parameters) Copy(dst []byte) (Parameters, []byte) {
  87. ret := Parameters{
  88. pos: p.pos,
  89. bytes: p.bytes,
  90. }
  91. if p.dyn != nil {
  92. ret.dyn = make([]pair, len(p.dyn))
  93. for i, v := range p.dyn {
  94. ret.dyn[i], dst = v.copy(dst)
  95. }
  96. } else {
  97. for i, p := range p.arr {
  98. ret.arr[i], dst = p.copy(dst)
  99. }
  100. }
  101. return ret, dst
  102. }
  103. // Get returns value by key and flag about existence such value.
  104. func (p *Parameters) Get(key string) (value []byte, ok bool) {
  105. for _, v := range p.data() {
  106. if string(v.key) == key {
  107. return v.value, true
  108. }
  109. }
  110. return nil, false
  111. }
  112. // Set sets value by key.
  113. func (p *Parameters) Set(key, value []byte) {
  114. p.bytes += len(key) + len(value)
  115. if p.pos < len(p.arr) {
  116. p.arr[p.pos] = pair{key, value}
  117. p.pos++
  118. return
  119. }
  120. if p.dyn == nil {
  121. p.dyn = make([]pair, len(p.arr), len(p.arr)+1)
  122. copy(p.dyn, p.arr[:])
  123. }
  124. p.dyn = append(p.dyn, pair{key, value})
  125. }
  126. // ForEach iterates over parameters key-value pairs and calls cb for each one.
  127. func (p *Parameters) ForEach(cb func(k, v []byte) bool) {
  128. for _, v := range p.data() {
  129. if !cb(v.key, v.value) {
  130. break
  131. }
  132. }
  133. }
  134. // String represents parameters as a string.
  135. func (p *Parameters) String() (ret string) {
  136. ret = "["
  137. for i, v := range p.data() {
  138. if i > 0 {
  139. ret += " "
  140. }
  141. ret += string(v.key) + ":" + string(v.value)
  142. }
  143. return ret + "]"
  144. }
  145. func (p *Parameters) data() []pair {
  146. if p.dyn != nil {
  147. return p.dyn
  148. }
  149. return p.arr[:p.pos]
  150. }
  151. type pair struct {
  152. key, value []byte
  153. }
  154. func (p pair) copy(dst []byte) (pair, []byte) {
  155. n := copy(dst, p.key)
  156. p.key = dst[:n]
  157. m := n + copy(dst[n:], p.value)
  158. p.value = dst[n:m]
  159. dst = dst[m:]
  160. return p, dst
  161. }
  162. type pairs []pair
  163. func (p pairs) Len() int { return len(p) }
  164. func (p pairs) Less(a, b int) bool { return bytes.Compare(p[a].key, p[b].key) == -1 }
  165. func (p pairs) Swap(a, b int) { p[a], p[b] = p[b], p[a] }