123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- package httphead
- import (
- "bytes"
- "sort"
- )
- // Option represents a header option.
- type Option struct {
- Name []byte
- Parameters Parameters
- }
- // Size returns number of bytes need to be allocated for use in opt.Copy.
- func (opt Option) Size() int {
- return len(opt.Name) + opt.Parameters.bytes
- }
- // Copy copies all underlying []byte slices into p and returns new Option.
- // Note that p must be at least of opt.Size() length.
- func (opt Option) Copy(p []byte) Option {
- n := copy(p, opt.Name)
- opt.Name = p[:n]
- opt.Parameters, p = opt.Parameters.Copy(p[n:])
- return opt
- }
- // Clone is a shorthand for making slice of opt.Size() sequenced with Copy()
- // call.
- func (opt Option) Clone() Option {
- return opt.Copy(make([]byte, opt.Size()))
- }
- // String represents option as a string.
- func (opt Option) String() string {
- return "{" + string(opt.Name) + " " + opt.Parameters.String() + "}"
- }
- // NewOption creates named option with given parameters.
- func NewOption(name string, params map[string]string) Option {
- p := Parameters{}
- for k, v := range params {
- p.Set([]byte(k), []byte(v))
- }
- return Option{
- Name: []byte(name),
- Parameters: p,
- }
- }
- // Equal reports whether option is equal to b.
- func (opt Option) Equal(b Option) bool {
- if bytes.Equal(opt.Name, b.Name) {
- return opt.Parameters.Equal(b.Parameters)
- }
- return false
- }
- // Parameters represents option's parameters.
- type Parameters struct {
- pos int
- bytes int
- arr [8]pair
- dyn []pair
- }
- // Equal reports whether a equal to b.
- func (p Parameters) Equal(b Parameters) bool {
- switch {
- case p.dyn == nil && b.dyn == nil:
- case p.dyn != nil && b.dyn != nil:
- default:
- return false
- }
- ad, bd := p.data(), b.data()
- if len(ad) != len(bd) {
- return false
- }
- sort.Sort(pairs(ad))
- sort.Sort(pairs(bd))
- for i := 0; i < len(ad); i++ {
- av, bv := ad[i], bd[i]
- if !bytes.Equal(av.key, bv.key) || !bytes.Equal(av.value, bv.value) {
- return false
- }
- }
- return true
- }
- // Size returns number of bytes that needed to copy p.
- func (p *Parameters) Size() int {
- return p.bytes
- }
- // Copy copies all underlying []byte slices into dst and returns new
- // Parameters.
- // Note that dst must be at least of p.Size() length.
- func (p *Parameters) Copy(dst []byte) (Parameters, []byte) {
- ret := Parameters{
- pos: p.pos,
- bytes: p.bytes,
- }
- if p.dyn != nil {
- ret.dyn = make([]pair, len(p.dyn))
- for i, v := range p.dyn {
- ret.dyn[i], dst = v.copy(dst)
- }
- } else {
- for i, p := range p.arr {
- ret.arr[i], dst = p.copy(dst)
- }
- }
- return ret, dst
- }
- // Get returns value by key and flag about existence such value.
- func (p *Parameters) Get(key string) (value []byte, ok bool) {
- for _, v := range p.data() {
- if string(v.key) == key {
- return v.value, true
- }
- }
- return nil, false
- }
- // Set sets value by key.
- func (p *Parameters) Set(key, value []byte) {
- p.bytes += len(key) + len(value)
- if p.pos < len(p.arr) {
- p.arr[p.pos] = pair{key, value}
- p.pos++
- return
- }
- if p.dyn == nil {
- p.dyn = make([]pair, len(p.arr), len(p.arr)+1)
- copy(p.dyn, p.arr[:])
- }
- p.dyn = append(p.dyn, pair{key, value})
- }
- // ForEach iterates over parameters key-value pairs and calls cb for each one.
- func (p *Parameters) ForEach(cb func(k, v []byte) bool) {
- for _, v := range p.data() {
- if !cb(v.key, v.value) {
- break
- }
- }
- }
- // String represents parameters as a string.
- func (p *Parameters) String() (ret string) {
- ret = "["
- for i, v := range p.data() {
- if i > 0 {
- ret += " "
- }
- ret += string(v.key) + ":" + string(v.value)
- }
- return ret + "]"
- }
- func (p *Parameters) data() []pair {
- if p.dyn != nil {
- return p.dyn
- }
- return p.arr[:p.pos]
- }
- type pair struct {
- key, value []byte
- }
- func (p pair) copy(dst []byte) (pair, []byte) {
- n := copy(dst, p.key)
- p.key = dst[:n]
- m := n + copy(dst[n:], p.value)
- p.value = dst[n:m]
- dst = dst[m:]
- return p, dst
- }
- type pairs []pair
- func (p pairs) Len() int { return len(p) }
- func (p pairs) Less(a, b int) bool { return bytes.Compare(p[a].key, p[b].key) == -1 }
- func (p pairs) Swap(a, b int) { p[a], p[b] = p[b], p[a] }
|