|
6 | 6 | package chainhash
|
7 | 7 |
|
8 | 8 | import (
|
| 9 | + "encoding/binary" |
9 | 10 | "encoding/hex"
|
10 | 11 | "encoding/json"
|
11 | 12 | "fmt"
|
| 13 | + "math" |
12 | 14 | )
|
13 | 15 |
|
14 | 16 | // HashSize of array used to store hashes. See Hash.
|
@@ -147,3 +149,69 @@ func Decode(dst *Hash, src string) error {
|
147 | 149 |
|
148 | 150 | return nil
|
149 | 151 | }
|
| 152 | + |
| 153 | +// Uint64sToPackedHashes packs the passed in uint64s into the 32 byte hashes. 4 uint64s are packed into |
| 154 | +// each 32 byte hash and if there's leftovers, it's filled with maxuint64. |
| 155 | +func Uint64sToPackedHashes(ints []uint64) []Hash { |
| 156 | + // 4 uint64s fit into a 32 byte slice. For len(ints) < 4, count is 0. |
| 157 | + count := len(ints) / 4 |
| 158 | + |
| 159 | + // If there's leftovers, we need to allocate 1 more. |
| 160 | + if len(ints)%4 != 0 { |
| 161 | + count++ |
| 162 | + } |
| 163 | + |
| 164 | + hashes := make([]Hash, count) |
| 165 | + hashIdx := 0 |
| 166 | + for i := range ints { |
| 167 | + // Move on to the next hash after putting in 4 uint64s into a hash. |
| 168 | + if i != 0 && i%4 == 0 { |
| 169 | + hashIdx++ |
| 170 | + } |
| 171 | + |
| 172 | + // 8 is the size of a uint64. |
| 173 | + start := (i % 4) * 8 |
| 174 | + binary.LittleEndian.PutUint64(hashes[hashIdx][start:start+8], ints[i]) |
| 175 | + } |
| 176 | + |
| 177 | + // Pad the last hash with math.MaxUint64 if needed. We check this by seeing |
| 178 | + // if modulo 4 doesn't equate 0. |
| 179 | + if len(ints)%4 != 0 { |
| 180 | + // Start at the end. |
| 181 | + end := HashSize |
| 182 | + |
| 183 | + // Get the count of how many empty uint64 places we should pad. |
| 184 | + padAmount := 4 - len(ints)%4 |
| 185 | + for i := 0; i < padAmount; i++ { |
| 186 | + // 8 is the size of a uint64. |
| 187 | + binary.LittleEndian.PutUint64(hashes[len(hashes)-1][end-8:end], math.MaxUint64) |
| 188 | + end -= 8 |
| 189 | + } |
| 190 | + } |
| 191 | + |
| 192 | + return hashes |
| 193 | +} |
| 194 | + |
| 195 | +// PackedHashesToUint64 returns the uint64s in the packed hashes as a slice of uint64s. |
| 196 | +func PackedHashesToUint64(hashes []Hash) []uint64 { |
| 197 | + ints := make([]uint64, 0, len(hashes)*4) |
| 198 | + for i := range hashes { |
| 199 | + // We pack 4 ints per hash. |
| 200 | + for j := 0; j < 4; j++ { |
| 201 | + // Offset for each int should be calculated by multiplying by |
| 202 | + // the size of a uint64. |
| 203 | + start := j * 8 |
| 204 | + read := binary.LittleEndian.Uint64(hashes[i][start : start+8]) |
| 205 | + |
| 206 | + // If we reach padded values, break. |
| 207 | + if read == math.MaxUint64 { |
| 208 | + break |
| 209 | + } |
| 210 | + |
| 211 | + // Otherwise we append the read uint64 to the slice. |
| 212 | + ints = append(ints, read) |
| 213 | + } |
| 214 | + } |
| 215 | + |
| 216 | + return ints |
| 217 | +} |
0 commit comments