1 package types
2 3 import (
4 "errors"
5 "io"
6 7 "next.orly.dev/pkg/lol/chk"
8 )
9 10 // MaxUint40 is the maximum value of a 40-bit unsigned integer: 2^40 - 1.
11 const MaxUint40 uint64 = 1<<40 - 1
12 13 // Uint40 is a codec for encoding and decoding 40-bit unsigned integers.
14 type Uint40 struct{ value uint64 }
15 16 // Set sets the value as a 40-bit unsigned integer.
17 // If the value exceeds the maximum allowable value for 40 bits, it returns an error.
18 func (c *Uint40) Set(value uint64) error {
19 if value > MaxUint40 {
20 return errors.New("value exceeds 40-bit range")
21 }
22 c.value = value
23 return nil
24 }
25 26 // Get gets the value as a 40-bit unsigned integer.
27 func (c *Uint40) Get() uint64 { return c.value }
28 29 // SetInt sets the value as an int, converting it to a 40-bit unsigned integer.
30 // If the value is out of the 40-bit range, it returns an error.
31 func (c *Uint40) SetInt(value int) error {
32 if value < 0 || uint64(value) > MaxUint40 {
33 return errors.New("value exceeds 40-bit range")
34 }
35 c.value = uint64(value)
36 return nil
37 }
38 39 // GetInt gets the value as an int, converted from the 40-bit unsigned integer.
40 // Note: If the value exceeds the int range, it will be truncated.
41 func (c *Uint40) GetInt() int { return int(c.value) }
42 43 // MarshalWrite encodes the 40-bit unsigned integer and writes it to the provided writer.
44 // The encoding uses 5 bytes in BigEndian order.
45 func (c *Uint40) MarshalWrite(w io.Writer) (err error) {
46 if c.value > MaxUint40 {
47 return errors.New("value exceeds 40-bit range")
48 }
49 // Fixed array avoids heap escape
50 var buf [5]byte
51 // Write the upper 5 bytes (ignoring the most significant 3 bytes of uint64)
52 buf[0] = byte((c.value >> 32) & 0xFF) // Most significant byte
53 buf[1] = byte((c.value >> 24) & 0xFF)
54 buf[2] = byte((c.value >> 16) & 0xFF)
55 buf[3] = byte((c.value >> 8) & 0xFF)
56 buf[4] = byte(c.value & 0xFF) // Least significant byte
57 _, err = w.Write(buf[:])
58 return err
59 }
60 61 // UnmarshalRead reads 5 bytes from the provided reader and decodes it into a 40-bit unsigned integer.
62 func (c *Uint40) UnmarshalRead(r io.Reader) (err error) {
63 // Fixed array avoids heap escape
64 var buf [5]byte
65 _, err = r.Read(buf[:])
66 if chk.E(err) {
67 return err
68 }
69 // Decode the 5 bytes into a 40-bit unsigned integer
70 c.value = (uint64(buf[0]) << 32) |
71 (uint64(buf[1]) << 24) |
72 (uint64(buf[2]) << 16) |
73 (uint64(buf[3]) << 8) |
74 uint64(buf[4])
75 76 return nil
77 }
78 79 type Uint40s []*Uint40
80 81 // Union computes the union of the current Uint40s slice with another Uint40s slice. The result
82 // contains all unique elements from both slices.
83 func (s Uint40s) Union(other Uint40s) Uint40s {
84 totalCap := len(s) + len(other)
85 valueMap := make(map[uint64]bool, totalCap)
86 result := make(Uint40s, 0, totalCap) // Pre-allocate for worst case
87 88 // Add elements from the current Uint40s slice to the result
89 for _, item := range s {
90 val := item.Get()
91 if !valueMap[val] {
92 valueMap[val] = true
93 result = append(result, item)
94 }
95 }
96 97 // Add elements from the other Uint40s slice to the result
98 for _, item := range other {
99 val := item.Get()
100 if !valueMap[val] {
101 valueMap[val] = true
102 result = append(result, item)
103 }
104 }
105 106 return result
107 }
108 109 // Intersection computes the intersection of the current Uint40s slice with another Uint40s
110 // slice. The result contains only the elements that exist in both slices.
111 func (s Uint40s) Intersection(other Uint40s) Uint40s {
112 // Result can be at most the size of the smaller slice
113 smallerLen := len(s)
114 if len(other) < smallerLen {
115 smallerLen = len(other)
116 }
117 valueMap := make(map[uint64]bool, len(other))
118 result := make(Uint40s, 0, smallerLen) // Pre-allocate for worst case
119 120 // Add all elements from the other Uint40s slice to the map
121 for _, item := range other {
122 valueMap[item.Get()] = true
123 }
124 125 // Check for common elements in the current Uint40s slice
126 for _, item := range s {
127 val := item.Get()
128 if valueMap[val] {
129 result = append(result, item)
130 }
131 }
132 133 return result
134 }
135 136 // Difference computes the difference of the current Uint40s slice with another Uint40s slice.
137 // The result contains only the elements that are in the current slice but not in the other
138 // slice.
139 func (s Uint40s) Difference(other Uint40s) Uint40s {
140 valueMap := make(map[uint64]bool, len(other))
141 result := make(Uint40s, 0, len(s)) // Pre-allocate for worst case (no overlap)
142 143 // Mark all elements in the other Uint40s slice
144 for _, item := range other {
145 valueMap[item.Get()] = true
146 }
147 148 // Add elements from the current Uint40s slice that are not in the other Uint40s slice
149 for _, item := range s {
150 val := item.Get()
151 if !valueMap[val] {
152 result = append(result, item)
153 }
154 }
155 156 return result
157 }
158