diff --git a/.gitignore b/.gitignore index 66fd13c..837448b 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ # Dependency directories (remove the comment below to include it) # vendor/ + +*.txt \ No newline at end of file diff --git a/base.go b/base.go new file mode 100644 index 0000000..5532eae --- /dev/null +++ b/base.go @@ -0,0 +1,50 @@ +package unibase2n + +import ( + "errors" +) + +// Base has an encoding buffer thus should not be copied. +// total size: 8 bytes +type Base struct { + off uint16 // starting offset + til uint16 // remianing indicator starting offset + bit uint8 // 2^bit, max is 15 (32768) + pos uint8 // bitwise buffer position + buf [2]byte // en/decoding buffer +} + +var ( + ErrInvalidBitSize = errors.New("bit size >= 16 or == 0") + ErrOffsetOverflow = errors.New("offset overflow") + ErrTailOverflow = errors.New("tail overflow") + ErrTailInCodingArea = errors.New("tail in coding area") +) + +// NewBase generates a new base2n config +func NewBase(off, til uint16, bit uint8) (*Base, error) { + if bit >= 16 || bit == 0 { + return nil, ErrInvalidBitSize + } + offe := uint32(off) + 1< 0x10000 { + return nil, ErrOffsetOverflow + } + tile := uint32(til) // [til, tile) + if bit%2 == 0 { + tile += uint32(bit / 2) + } else { + tile += uint32(bit) + } + if tile > 0x10000 { + return nil, ErrTailOverflow + } + if tile > uint32(off) || uint32(til) < offe { + return nil, ErrTailInCodingArea + } + return &Base{ + off: off, + til: til, + bit: bit, + }, nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..7230110 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/fumiama/unibase2n + +go 1.18 diff --git a/helper.go b/helper.go new file mode 100644 index 0000000..491bd76 --- /dev/null +++ b/helper.go @@ -0,0 +1,20 @@ +package unibase2n + +import ( + "unsafe" +) + +// BytesToString 没有内存开销的转换 +func BytesToString(b []byte) string { + return *(*string)(unsafe.Pointer(&b)) +} + +// StringToBytes 没有内存开销的转换 +func StringToBytes(s string) (b []byte) { + bh := (*slice)(unsafe.Pointer(&b)) + sh := (*slice)(unsafe.Pointer(&s)) + bh.data = sh.data + bh.len = sh.len + bh.cap = sh.len + return b +} diff --git a/pack.go b/pack.go new file mode 100644 index 0000000..8cc127f --- /dev/null +++ b/pack.go @@ -0,0 +1,29 @@ +package unibase2n + +import "unsafe" + +type Pack uint64 + +var ( + Base16384 = newbasepack(0x4e00, 0x3d00, 14) + Base8192 = newbasepack(0xac00, 0xcc00, 13) + Base256 = newbasepack(0x1100, 0x0000, 4) +) + +func newbasepack(off, til uint16, bit uint8) Pack { + b, err := NewBase(off, til, bit) + if err != nil { + panic(err) + } + return b.Pack() +} + +func New(pack Pack) *Base { + b := &Base{} + *(*Pack)(unsafe.Pointer(b)) = pack + return b +} + +func (b *Base) Pack() Pack { + return *(*Pack)(unsafe.Pointer(b)) +} diff --git a/slice.go b/slice.go new file mode 100644 index 0000000..780bd17 --- /dev/null +++ b/slice.go @@ -0,0 +1,15 @@ +package unibase2n + +import "unsafe" + +// slice is the runtime representation of a slice. +// It cannot be used safely or portably and its representation may +// change in a later release. +// +// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the +// data it references will not be garbage collected. +type slice struct { + data unsafe.Pointer + len int + cap int +}