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  }