ints.mx raw
1 // Package ints is an optimised encoder for decimal numbers in ASCII format.
2 package ints
3
4 import (
5 _ "embed"
6 "io"
7
8 "smesh.lol/pkg/lol/errorf"
9 )
10
11 //go:embed base10k.txt
12 var base10k []byte
13
14 const base = 10000
15
16 type Integer interface {
17 ~int | ~int8 | ~int16 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint64
18 }
19
20 type T struct {
21 N uint64
22 }
23
24 func New[V Integer](n V) *T {
25 return &T{uint64(n)}
26 }
27
28 func (n *T) Uint64() uint64 { return n.N }
29 func (n *T) Int64() int64 { return int64(n.N) }
30 func (n *T) Uint16() uint16 { return uint16(n.N) }
31
32 var powers = []*T{
33 {1},
34 {1_0000},
35 {1_0000_0000},
36 {1_0000_0000_0000},
37 {1_0000_0000_0000_0000},
38 }
39
40 const zero = '0'
41 const nine = '9'
42
43 func (n *T) Marshal(dst []byte) (b []byte) {
44 nn := n.N
45 b = dst
46 if n.N == 0 {
47 b = append(b, '0')
48 return
49 }
50 var i int
51 var trimmed bool
52 k := len(powers)
53 for k > 0 {
54 k--
55 q := n.N / powers[k].N
56 if !trimmed && q == 0 {
57 continue
58 }
59 offset := q * 4
60 bb := base10k[offset : offset+4]
61 if !trimmed {
62 for i = range bb {
63 if bb[i] != '0' {
64 bb = bb[i:]
65 trimmed = true
66 break
67 }
68 }
69 }
70 b = append(b, bb...)
71 n.N = n.N - q*powers[k].N
72 }
73 n.N = nn
74 return
75 }
76
77 func (n *T) Unmarshal(b []byte) (r []byte, err error) {
78 if len(b) < 1 {
79 err = errorf.E([]byte("zero length number"))
80 return
81 }
82 var sLen int
83 if b[0] == zero {
84 r = b[1:]
85 n.N = 0
86 return
87 }
88 for i, v := range b {
89 if v >= '0' && v <= '9' {
90 b = b[i:]
91 break
92 }
93 }
94 if len(b) == 0 {
95 err = io.EOF
96 return
97 }
98 for ; sLen < len(b) && b[sLen] >= zero && b[sLen] <= nine && b[sLen] != ','; sLen++ {
99 }
100 if sLen == 0 {
101 err = errorf.E([]byte("zero length number"))
102 return
103 }
104 if sLen > 20 {
105 err = errorf.E([]byte("too big number for uint64"))
106 return
107 }
108 r = b[sLen:]
109 b = b[:sLen]
110 n.N = uint64(b[0]) - zero
111 b = b[1:]
112 for _, ch := range b {
113 ch -= zero
114 n.N = n.N*10 + uint64(ch)
115 }
116 return
117 }
118