github.com/moreal/bencodex-go@v0.0.0-20231021172012-18277a477d15/internal/encoder/dictionary.go (about) 1 package encoder 2 3 import ( 4 "sync" 5 6 "github.com/moreal/bencodex-go/internal" 7 ) 8 9 const bytesLikeArrayLen = 20 10 11 var stringsArrayPool = sync.Pool{ 12 New: func() interface{} { 13 return &[bytesLikeArrayLen]internal.BencodexBytesLike{} 14 }, 15 } 16 17 // -1 = left go first, 0 = equal, 1 = right go first 18 func compareBytes(x, y []byte) int { 19 var minLen int 20 if len(x) > len(y) { 21 minLen = len(y) 22 } else { 23 minLen = len(x) 24 } 25 26 for i := 0; i < minLen; i++ { 27 if x[i] > y[i] { 28 return 1 29 } else if x[i] < y[i] { 30 return -1 31 } 32 } 33 34 if len(x) == len(y) { 35 return 0 36 } 37 38 if len(x) > len(y) { 39 return 1 40 } 41 42 return -1 43 } 44 45 func sortKeys(keys []internal.BencodexBytesLike) { 46 for i := 1; i < len(keys); i++ { 47 for j := i; j > 0; j-- { 48 if keys[j].IsString() && keys[j-1].IsBytes() { 49 break 50 } else if keys[j].IsBytes() && keys[j-1].IsString() { 51 keys[j], keys[j-1] = keys[j-1], keys[j] 52 } else if keys[j].IsBytes() && keys[j-1].IsBytes() { 53 res := compareBytes(keys[j-1].MustAsBytes(), keys[j].MustAsBytes()) 54 if res >= 0 { 55 break 56 } 57 } else if keys[j].MustAsString() >= keys[j-1].MustAsString() { 58 break 59 } 60 61 keys[j], keys[j-1] = keys[j-1], keys[j] 62 } 63 } 64 } 65 66 func (e *Encoder) encodeDictionary(data map[internal.BencodexBytesLike]interface{}) error { 67 e.grow(1) 68 e.writeByte('d') 69 var keys []internal.BencodexBytesLike 70 if len(data) <= bytesLikeArrayLen { 71 stringsArray := stringsArrayPool.Get().(*[bytesLikeArrayLen]internal.BencodexBytesLike) 72 defer stringsArrayPool.Put(stringsArray) 73 keys = stringsArray[:0:len(data)] 74 } else { 75 keys = make([]internal.BencodexBytesLike, 0, len(data)) 76 } 77 for key, _ := range data { 78 keys = append(keys, key) 79 } 80 sortKeys(keys) 81 for _, key := range keys { 82 e.encodeBytesLike(key) 83 err := e.encode(data[key]) 84 if err != nil { 85 return err 86 } 87 } 88 e.grow(1) 89 e.writeByte('e') 90 return nil 91 }