github.com/niubaoshu/gotiny@v0.0.4-0.20211018120156-10d393f19ad0/utils.go (about)

     1  package gotiny
     2  
     3  import (
     4  	"encoding"
     5  	"encoding/gob"
     6  	"reflect"
     7  	"strings"
     8  	"unsafe"
     9  )
    10  
    11  const (
    12  	ptr1Size = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
    13  )
    14  
    15  func float64ToUint64(v unsafe.Pointer) uint64 {
    16  	return reverse64Byte(*(*uint64)(v))
    17  }
    18  
    19  func uint64ToFloat64(u uint64) float64 {
    20  	u = reverse64Byte(u)
    21  	return *((*float64)(unsafe.Pointer(&u)))
    22  }
    23  
    24  func reverse64Byte(u uint64) uint64 {
    25  	u = (u << 32) | (u >> 32)
    26  	u = ((u << 16) & 0xFFFF0000FFFF0000) | ((u >> 16) & 0xFFFF0000FFFF)
    27  	u = ((u << 8) & 0xFF00FF00FF00FF00) | ((u >> 8) & 0xFF00FF00FF00FF)
    28  	return u
    29  }
    30  
    31  func float32ToUint32(v unsafe.Pointer) uint32 {
    32  	return reverse32Byte(*(*uint32)(v))
    33  }
    34  
    35  func uint32ToFloat32(u uint32) float32 {
    36  	u = reverse32Byte(u)
    37  	return *((*float32)(unsafe.Pointer(&u)))
    38  }
    39  
    40  func reverse32Byte(u uint32) uint32 {
    41  	u = (u << 16) | (u >> 16)
    42  	return ((u << 8) & 0xFF00FF00) | ((u >> 8) & 0xFF00FF)
    43  }
    44  
    45  // int -5 -4 -3 -2 -1 0 1 2 3 4 5  6
    46  // uint 9  7  5  3  1 0 2 4 6 8 10 12
    47  func int64ToUint64(v int64) uint64 {
    48  	return uint64((v << 1) ^ (v >> 63))
    49  }
    50  
    51  // uint 9  7  5  3  1 0 2 4 6 8 10 12
    52  // int -5 -4 -3 -2 -1 0 1 2 3 4 5  6
    53  func uint64ToInt64(u uint64) int64 {
    54  	v := int64(u)
    55  	return (-(v & 1)) ^ (v>>1)&0x7FFFFFFFFFFFFFFF
    56  }
    57  
    58  // int -5 -4 -3 -2 -1 0 1 2 3 4 5  6
    59  // uint 9  7  5  3  1 0 2 4 6 8 10 12
    60  func int32ToUint32(v int32) uint32 {
    61  	return uint32((v << 1) ^ (v >> 31))
    62  }
    63  
    64  // uint 9  7  5  3  1 0 2 4 6 8 10 12
    65  // int -5 -4 -3 -2 -1 0 1 2 3 4 5  6
    66  func uint32ToInt32(u uint32) int32 {
    67  	v := int32(u)
    68  	return (-(v & 1)) ^ (v>>1)&0x7FFFFFFF
    69  }
    70  
    71  // int -5 -4 -3 -2 -1 0 1 2 3 4 5  6
    72  // uint 9  7  5  3  1 0 2 4 6 8 10 12
    73  func int16ToUint16(v int16) uint16 {
    74  	return uint16((v << 1) ^ (v >> 15))
    75  }
    76  
    77  // uint 9  7  5  3  1 0 2 4 6 8 10 12
    78  // int -5 -4 -3 -2 -1 0 1 2 3 4 5  6
    79  func uint16ToInt16(u uint16) int16 {
    80  	v := int16(u)
    81  	return (-(v & 1)) ^ (v>>1)&0x7FFF
    82  }
    83  
    84  func isNil(p unsafe.Pointer) bool {
    85  	return *(*unsafe.Pointer)(p) == nil
    86  }
    87  
    88  type gobInter interface {
    89  	gob.GobEncoder
    90  	gob.GobDecoder
    91  }
    92  
    93  type binInter interface {
    94  	encoding.BinaryMarshaler
    95  	encoding.BinaryUnmarshaler
    96  }
    97  
    98  // 只应该由指针来实现该接口
    99  type GoTinySerializer interface {
   100  	// 编码方法,将对象的序列化结果append到入参数并返回,方法不应该修改入参数值原有的值
   101  	GotinyEncode([]byte) []byte
   102  	// 解码方法,将入参解码到对象里并返回使用的长度。方法从入参的第0个字节开始使用,并且不应该修改入参中的任何数据
   103  	GotinyDecode([]byte) int
   104  }
   105  
   106  func implementOtherSerializer(rt reflect.Type) (encEng encEng, decEng decEng) {
   107  	rtNil := reflect.Zero(reflect.PtrTo(rt)).Interface()
   108  	if _, ok := rtNil.(GoTinySerializer); ok {
   109  		encEng = func(e *Encoder, p unsafe.Pointer) {
   110  			e.buf = reflect.NewAt(rt, p).Interface().(GoTinySerializer).GotinyEncode(e.buf)
   111  		}
   112  		decEng = func(d *Decoder, p unsafe.Pointer) {
   113  			d.index += reflect.NewAt(rt, p).Interface().(GoTinySerializer).GotinyDecode(d.buf[d.index:])
   114  		}
   115  		return
   116  	}
   117  
   118  	if _, ok := rtNil.(binInter); ok {
   119  		encEng = func(e *Encoder, p unsafe.Pointer) {
   120  			buf, err := reflect.NewAt(rt, p).Interface().(encoding.BinaryMarshaler).MarshalBinary()
   121  			if err != nil {
   122  				panic(err)
   123  			}
   124  			e.encLength(len(buf))
   125  			e.buf = append(e.buf, buf...)
   126  		}
   127  
   128  		decEng = func(d *Decoder, p unsafe.Pointer) {
   129  			length := d.decLength()
   130  			start := d.index
   131  			d.index += length
   132  			if err := reflect.NewAt(rt, p).Interface().(encoding.BinaryUnmarshaler).UnmarshalBinary(d.buf[start:d.index]); err != nil {
   133  				panic(err)
   134  			}
   135  		}
   136  		return
   137  	}
   138  
   139  	if _, ok := rtNil.(gobInter); ok {
   140  		encEng = func(e *Encoder, p unsafe.Pointer) {
   141  			buf, err := reflect.NewAt(rt, p).Interface().(gob.GobEncoder).GobEncode()
   142  			if err != nil {
   143  				panic(err)
   144  			}
   145  			e.encLength(len(buf))
   146  			e.buf = append(e.buf, buf...)
   147  		}
   148  		decEng = func(d *Decoder, p unsafe.Pointer) {
   149  			length := d.decLength()
   150  			start := d.index
   151  			d.index += length
   152  			if err := reflect.NewAt(rt, p).Interface().(gob.GobDecoder).GobDecode(d.buf[start:d.index]); err != nil {
   153  				panic(err)
   154  			}
   155  		}
   156  	}
   157  	return
   158  }
   159  
   160  // rt.kind is reflect.struct
   161  func getFieldType(rt reflect.Type, baseOff uintptr) (fields []reflect.Type, offs []uintptr) {
   162  	for i := 0; i < rt.NumField(); i++ {
   163  		field := rt.Field(i)
   164  		if ignoreField(field) {
   165  			continue
   166  		}
   167  		ft := field.Type
   168  		if ft.Kind() == reflect.Struct {
   169  			if _, engine := implementOtherSerializer(ft); engine == nil {
   170  				fFields, fOffs := getFieldType(ft, field.Offset+baseOff)
   171  				fields = append(fields, fFields...)
   172  				offs = append(offs, fOffs...)
   173  				continue
   174  			}
   175  		}
   176  		fields = append(fields, ft)
   177  		offs = append(offs, field.Offset+baseOff)
   178  	}
   179  	return
   180  }
   181  
   182  func ignoreField(field reflect.StructField) bool {
   183  	tinyTag, ok := field.Tag.Lookup("gotiny")
   184  	return ok && strings.TrimSpace(tinyTag) == "-"
   185  }