-
Notifications
You must be signed in to change notification settings - Fork 923
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(share/availability): simplify light availability (#3895)
- Loading branch information
Showing
5 changed files
with
68 additions
and
141 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,104 +1,42 @@ | ||
// TODO(@Wondertan): Instead of doing sampling over the coordinates do a random walk over NMT trees. | ||
package light | ||
|
||
import ( | ||
crand "crypto/rand" | ||
"encoding/binary" | ||
"errors" | ||
"math/big" | ||
|
||
"golang.org/x/exp/maps" | ||
) | ||
|
||
// Sample is a point in 2D space over square. | ||
// Sample represents a coordinate in a 2D data square. | ||
type Sample struct { | ||
Row, Col uint16 | ||
Row int `json:"row"` | ||
Col int `json:"col"` | ||
} | ||
|
||
// SampleSquare randomly picks *num* unique points from the given *width* square | ||
// and returns them as samples. | ||
func SampleSquare(squareWidth, num int) ([]Sample, error) { | ||
ss := newSquareSampler(squareWidth, num) | ||
err := ss.generateSample(num) | ||
if err != nil { | ||
return nil, err | ||
// selectRandomSamples randomly picks unique coordinates from a square of given size. | ||
func selectRandomSamples(squareSize, sampleCount int) []Sample { | ||
total := squareSize * squareSize | ||
if sampleCount > total { | ||
sampleCount = total | ||
} | ||
return ss.samples(), nil | ||
} | ||
|
||
type squareSampler struct { | ||
squareWidth int | ||
smpls map[Sample]struct{} | ||
} | ||
|
||
func newSquareSampler(squareWidth, expectedSamples int) *squareSampler { | ||
return &squareSampler{ | ||
squareWidth: squareWidth, | ||
smpls: make(map[Sample]struct{}, expectedSamples), | ||
} | ||
} | ||
|
||
// generateSample randomly picks unique point on a 2D spaces. | ||
func (ss *squareSampler) generateSample(num int) error { | ||
if num > ss.squareWidth*ss.squareWidth { | ||
num = ss.squareWidth | ||
} | ||
|
||
done := 0 | ||
for done < num { | ||
samples := make(map[Sample]struct{}, sampleCount) | ||
for len(samples) < sampleCount { | ||
s := Sample{ | ||
Row: randInt(ss.squareWidth), | ||
Col: randInt(ss.squareWidth), | ||
Row: randInt(squareSize), | ||
Col: randInt(squareSize), | ||
} | ||
|
||
if _, ok := ss.smpls[s]; ok { | ||
continue | ||
} | ||
|
||
done++ | ||
ss.smpls[s] = struct{}{} | ||
samples[s] = struct{}{} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (ss *squareSampler) samples() []Sample { | ||
samples := make([]Sample, 0, len(ss.smpls)) | ||
for s := range ss.smpls { | ||
samples = append(samples, s) | ||
} | ||
return samples | ||
return maps.Keys(samples) | ||
} | ||
|
||
func randInt(max int) uint16 { | ||
func randInt(max int) int { | ||
n, err := crand.Int(crand.Reader, big.NewInt(int64(max))) | ||
if err != nil { | ||
panic(err) // won't panic as rand.Reader is endless | ||
} | ||
|
||
return uint16(n.Uint64()) | ||
} | ||
|
||
// encodeSamples encodes a slice of samples into a byte slice using little endian encoding. | ||
func encodeSamples(samples []Sample) []byte { | ||
bs := make([]byte, 0, len(samples)*4) | ||
for _, s := range samples { | ||
bs = binary.LittleEndian.AppendUint16(bs, s.Row) | ||
bs = binary.LittleEndian.AppendUint16(bs, s.Col) | ||
} | ||
return bs | ||
} | ||
|
||
// decodeSamples decodes a byte slice into a slice of samples. | ||
func decodeSamples(bs []byte) ([]Sample, error) { | ||
if len(bs)%4 != 0 { | ||
return nil, errors.New("invalid byte slice length") | ||
} | ||
|
||
samples := make([]Sample, 0, len(bs)/4) | ||
for i := 0; i < len(bs); i += 4 { | ||
samples = append(samples, Sample{ | ||
Row: binary.LittleEndian.Uint16(bs[i : i+2]), | ||
Col: binary.LittleEndian.Uint16(bs[i+2 : i+4]), | ||
}) | ||
} | ||
return samples, nil | ||
// n.Uint64() is safe as max is int | ||
return int(n.Uint64()) | ||
} |
Oops, something went wrong.