github.com/quantosnetwork/Quantos@v0.0.0-20220306172517-e20b28c5a29a/encoder/encoder.go (about) 1 package encoder 2 3 import ( 4 "github.com/quantosnetwork/Quantos/crypto" 5 6 "fmt" 7 8 "sort" 9 "sync" 10 "unsafe" 11 ) 12 13 //go:linkname memmov runtime.memmove 14 func memmov(to unsafe.Pointer, from unsafe.Pointer, n uintptr) 15 16 type Encoder struct { 17 buffer []byte 18 length int 19 offset int 20 } 21 22 type sliceHeader struct { 23 data unsafe.Pointer 24 len int 25 cap int 26 } 27 28 //go:nosplit 29 func (e *Encoder) grow(neededLength int) { 30 availableLength := e.length - e.offset 31 if availableLength >= neededLength { 32 return 33 } 34 if e.length == 0 { 35 if neededLength < 16 { 36 neededLength = 16 37 } 38 e.length = neededLength 39 availableLength = neededLength 40 } else { 41 for availableLength < neededLength { 42 e.length += e.length 43 availableLength = e.length - e.offset 44 } 45 } 46 buffer := make([]byte, e.length) 47 memmov( 48 unsafe.Pointer(uintptr((*sliceHeader)(unsafe.Pointer(&buffer)).data)), 49 (*sliceHeader)(unsafe.Pointer(&e.buffer)).data, 50 uintptr(e.offset), 51 ) 52 e.buffer = buffer 53 54 } 55 56 //go:nosplit 57 func (e *Encoder) write(data []byte) { 58 length := len(data) 59 memmov( 60 unsafe.Pointer(uintptr((*sliceHeader)(unsafe.Pointer(&e.buffer)).data)+uintptr(e.offset)), 61 (*sliceHeader)(unsafe.Pointer(&data)).data, 62 uintptr(length), 63 ) 64 e.offset += length 65 } 66 67 //go:nosplit 68 func (e *Encoder) writeByte(data byte) { 69 *(*byte)(unsafe.Pointer(uintptr((*sliceHeader)(unsafe.Pointer(&e.buffer)).data) + uintptr(e.offset))) = data 70 e.offset++ 71 } 72 73 func (e *Encoder) EncodeTo(dst []byte, data interface{}) ([]byte, error) { 74 if cap(dst) > len(dst) { 75 dst = dst[:cap(dst)] 76 } else if len(dst) == 0 { 77 dst = make([]byte, 512) 78 } 79 e.buffer = dst 80 e.length = cap(dst) 81 err := e.encode(data) 82 if err != nil { 83 return nil, err 84 } 85 return e.buffer[:e.offset], nil 86 } 87 88 func (e *Encoder) encode(data interface{}) error { 89 switch value := data.(type) { 90 case int64: 91 e.encodeInt(value) 92 case int32: 93 e.encodeInt(int64(value)) 94 case int16: 95 e.encodeInt(int64(value)) 96 case int8: 97 e.encodeInt(int64(value)) 98 case int: 99 e.encodeInt(int64(value)) 100 case uint64: 101 e.encodeInt(int64(value)) 102 case uint32: 103 e.encodeInt(int64(value)) 104 case uint16: 105 e.encodeInt(int64(value)) 106 case uint8: 107 e.encodeInt(int64(value)) 108 case uint: 109 e.encodeInt(int64(value)) 110 case []byte: 111 e.encodeBytes(value) 112 case string: 113 e.encodeBytes(crypto.StringToBytes(value)) 114 case []interface{}: 115 return e.encodeList(value) 116 case map[string]interface{}: 117 return e.encodeDictionary(value) 118 case map[int]interface{}: 119 return e.encodeHashTable(value) 120 default: 121 return fmt.Errorf("quantos encoding: unsupported type: %T", value) 122 } 123 return nil 124 } 125 126 //go:nosplit 127 func (e *Encoder) encodeBytes(data []byte) { 128 dataLength := len(data) 129 e.grow(dataLength + 23) 130 e.writeInt(int64(len(data))) 131 e.writeByte(':') 132 e.write(data) 133 } 134 135 func (e *Encoder) encodeList(data []interface{}) error { 136 e.grow(1) 137 e.writeByte('l') 138 for _, data := range data { 139 err := e.encode(data) 140 if err != nil { 141 return err 142 } 143 } 144 e.grow(1) 145 e.writeByte('e') 146 return nil 147 } 148 149 const stringsArrayLen = 20 150 151 var stringsArrayPool = sync.Pool{ 152 New: func() interface{} { 153 return &[stringsArrayLen]string{} 154 }, 155 } 156 157 func sortStrings(ss []string) { 158 if len(ss) <= stringsArrayLen { 159 for i := 1; i < len(ss); i++ { 160 for j := i; j > 0; j-- { 161 if ss[j] >= ss[j-1] { 162 break 163 } 164 ss[j], ss[j-1] = ss[j-1], ss[j] 165 } 166 } 167 } else { 168 sort.Strings(ss) 169 } 170 } 171 172 func (e *Encoder) encodeDictionary(data map[string]interface{}) error { 173 e.grow(1) 174 e.writeByte('d') 175 var keys []string 176 if len(data) <= stringsArrayLen { 177 stringsArray := stringsArrayPool.Get().(*[stringsArrayLen]string) 178 defer stringsArrayPool.Put(stringsArray) 179 keys = stringsArray[:0:len(data)] 180 } else { 181 keys = make([]string, 0, len(data)) 182 } 183 for key, _ := range data { 184 keys = append(keys, key) 185 } 186 sortStrings(keys) 187 for _, key := range keys { 188 e.encodeBytes(crypto.StringToBytes(key)) 189 err := e.encode(data[key]) 190 if err != nil { 191 return err 192 } 193 } 194 e.grow(1) 195 e.writeByte('e') 196 return nil 197 } 198 199 func (e *Encoder) encodeHashTable(data map[int]interface{}) error { 200 e.grow(1) 201 e.writeByte('h') 202 var keys []int 203 keys = make([]int, 0, len(data)) 204 for key, _ := range data { 205 keys = append(keys, key) 206 } 207 sort.Ints(keys) 208 209 for _, kk := range keys { 210 e.encodeInt(int64(kk)) 211 } 212 213 e.grow(1) 214 e.writeByte('e') 215 return nil 216 }