@ -0,0 +1,5 @@ | |||
package common | |||
func Arr(items ...interface{}) []interface{} { | |||
return items | |||
} |
@ -0,0 +1,15 @@ | |||
package common | |||
import "sync" | |||
func Parallel(tasks ...func()) { | |||
var wg sync.WaitGroup | |||
wg.Add(len(tasks)) | |||
for _, task := range tasks { | |||
go func(task func()) { | |||
task() | |||
wg.Done() | |||
}(task) | |||
} | |||
wg.Wait() | |||
} |
@ -0,0 +1,275 @@ | |||
package common | |||
import ( | |||
"fmt" | |||
"math/rand" | |||
"strings" | |||
"sync" | |||
) | |||
type BitArray struct { | |||
mtx sync.Mutex | |||
Bits int `json:"bits"` // NOTE: persisted via reflect, must be exported | |||
Elems []uint64 `json:"elems"` // NOTE: persisted via reflect, must be exported | |||
} | |||
// There is no BitArray whose Size is 0. Use nil instead. | |||
func NewBitArray(bits int) *BitArray { | |||
if bits == 0 { | |||
return nil | |||
} | |||
return &BitArray{ | |||
Bits: bits, | |||
Elems: make([]uint64, (bits+63)/64), | |||
} | |||
} | |||
func (bA *BitArray) Size() int { | |||
if bA == nil { | |||
return 0 | |||
} | |||
return bA.Bits | |||
} | |||
// NOTE: behavior is undefined if i >= bA.Bits | |||
func (bA *BitArray) GetIndex(i int) bool { | |||
if bA == nil { | |||
return false | |||
} | |||
bA.mtx.Lock() | |||
defer bA.mtx.Unlock() | |||
return bA.getIndex(i) | |||
} | |||
func (bA *BitArray) getIndex(i int) bool { | |||
if i >= bA.Bits { | |||
return false | |||
} | |||
return bA.Elems[i/64]&(uint64(1)<<uint(i%64)) > 0 | |||
} | |||
// NOTE: behavior is undefined if i >= bA.Bits | |||
func (bA *BitArray) SetIndex(i int, v bool) bool { | |||
if bA == nil { | |||
return false | |||
} | |||
bA.mtx.Lock() | |||
defer bA.mtx.Unlock() | |||
return bA.setIndex(i, v) | |||
} | |||
func (bA *BitArray) setIndex(i int, v bool) bool { | |||
if i >= bA.Bits { | |||
return false | |||
} | |||
if v { | |||
bA.Elems[i/64] |= (uint64(1) << uint(i%64)) | |||
} else { | |||
bA.Elems[i/64] &= ^(uint64(1) << uint(i%64)) | |||
} | |||
return true | |||
} | |||
func (bA *BitArray) Copy() *BitArray { | |||
if bA == nil { | |||
return nil | |||
} | |||
bA.mtx.Lock() | |||
defer bA.mtx.Unlock() | |||
return bA.copy() | |||
} | |||
func (bA *BitArray) copy() *BitArray { | |||
c := make([]uint64, len(bA.Elems)) | |||
copy(c, bA.Elems) | |||
return &BitArray{ | |||
Bits: bA.Bits, | |||
Elems: c, | |||
} | |||
} | |||
func (bA *BitArray) copyBits(bits int) *BitArray { | |||
c := make([]uint64, (bits+63)/64) | |||
copy(c, bA.Elems) | |||
return &BitArray{ | |||
Bits: bits, | |||
Elems: c, | |||
} | |||
} | |||
// Returns a BitArray of larger bits size. | |||
func (bA *BitArray) Or(o *BitArray) *BitArray { | |||
if bA == nil { | |||
o.Copy() | |||
} | |||
bA.mtx.Lock() | |||
defer bA.mtx.Unlock() | |||
c := bA.copyBits(MaxInt(bA.Bits, o.Bits)) | |||
for i := 0; i < len(c.Elems); i++ { | |||
c.Elems[i] |= o.Elems[i] | |||
} | |||
return c | |||
} | |||
// Returns a BitArray of smaller bit size. | |||
func (bA *BitArray) And(o *BitArray) *BitArray { | |||
if bA == nil { | |||
return nil | |||
} | |||
bA.mtx.Lock() | |||
defer bA.mtx.Unlock() | |||
return bA.and(o) | |||
} | |||
func (bA *BitArray) and(o *BitArray) *BitArray { | |||
c := bA.copyBits(MinInt(bA.Bits, o.Bits)) | |||
for i := 0; i < len(c.Elems); i++ { | |||
c.Elems[i] &= o.Elems[i] | |||
} | |||
return c | |||
} | |||
func (bA *BitArray) Not() *BitArray { | |||
if bA == nil { | |||
return nil // Degenerate | |||
} | |||
bA.mtx.Lock() | |||
defer bA.mtx.Unlock() | |||
c := bA.copy() | |||
for i := 0; i < len(c.Elems); i++ { | |||
c.Elems[i] = ^c.Elems[i] | |||
} | |||
return c | |||
} | |||
func (bA *BitArray) Sub(o *BitArray) *BitArray { | |||
if bA == nil { | |||
return nil | |||
} | |||
bA.mtx.Lock() | |||
defer bA.mtx.Unlock() | |||
if bA.Bits > o.Bits { | |||
c := bA.copy() | |||
for i := 0; i < len(o.Elems)-1; i++ { | |||
c.Elems[i] &= ^c.Elems[i] | |||
} | |||
i := len(o.Elems) - 1 | |||
if i >= 0 { | |||
for idx := i * 64; idx < o.Bits; idx++ { | |||
// NOTE: each individual GetIndex() call to o is safe. | |||
c.setIndex(idx, c.getIndex(idx) && !o.GetIndex(idx)) | |||
} | |||
} | |||
return c | |||
} else { | |||
return bA.and(o.Not()) // Note degenerate case where o == nil | |||
} | |||
} | |||
func (bA *BitArray) IsFull() bool { | |||
if bA == nil { | |||
return true | |||
} | |||
bA.mtx.Lock() | |||
defer bA.mtx.Unlock() | |||
// Check all elements except the last | |||
for _, elem := range bA.Elems[:len(bA.Elems)-1] { | |||
if (^elem) != 0 { | |||
return false | |||
} | |||
} | |||
// Check that the last element has (lastElemBits) 1's | |||
lastElemBits := (bA.Bits+63)%64 + 1 | |||
lastElem := bA.Elems[len(bA.Elems)-1] | |||
return (lastElem+1)&((uint64(1)<<uint(lastElemBits))-1) == 0 | |||
} | |||
func (bA *BitArray) PickRandom() (int, bool) { | |||
if bA == nil { | |||
return 0, false | |||
} | |||
bA.mtx.Lock() | |||
defer bA.mtx.Unlock() | |||
length := len(bA.Elems) | |||
if length == 0 { | |||
return 0, false | |||
} | |||
randElemStart := rand.Intn(length) | |||
for i := 0; i < length; i++ { | |||
elemIdx := ((i + randElemStart) % length) | |||
if elemIdx < length-1 { | |||
if bA.Elems[elemIdx] > 0 { | |||
randBitStart := rand.Intn(64) | |||
for j := 0; j < 64; j++ { | |||
bitIdx := ((j + randBitStart) % 64) | |||
if (bA.Elems[elemIdx] & (uint64(1) << uint(bitIdx))) > 0 { | |||
return 64*elemIdx + bitIdx, true | |||
} | |||
} | |||
PanicSanity("should not happen") | |||
} | |||
} else { | |||
// Special case for last elem, to ignore straggler bits | |||
elemBits := bA.Bits % 64 | |||
if elemBits == 0 { | |||
elemBits = 64 | |||
} | |||
randBitStart := rand.Intn(elemBits) | |||
for j := 0; j < elemBits; j++ { | |||
bitIdx := ((j + randBitStart) % elemBits) | |||
if (bA.Elems[elemIdx] & (uint64(1) << uint(bitIdx))) > 0 { | |||
return 64*elemIdx + bitIdx, true | |||
} | |||
} | |||
} | |||
} | |||
return 0, false | |||
} | |||
func (bA *BitArray) String() string { | |||
if bA == nil { | |||
return "nil-BitArray" | |||
} | |||
bA.mtx.Lock() | |||
defer bA.mtx.Unlock() | |||
return bA.stringIndented("") | |||
} | |||
func (bA *BitArray) StringIndented(indent string) string { | |||
if bA == nil { | |||
return "nil-BitArray" | |||
} | |||
bA.mtx.Lock() | |||
defer bA.mtx.Unlock() | |||
return bA.stringIndented(indent) | |||
} | |||
func (bA *BitArray) stringIndented(indent string) string { | |||
lines := []string{} | |||
bits := "" | |||
for i := 0; i < bA.Bits; i++ { | |||
if bA.getIndex(i) { | |||
bits += "X" | |||
} else { | |||
bits += "_" | |||
} | |||
if i%100 == 99 { | |||
lines = append(lines, bits) | |||
bits = "" | |||
} | |||
if i%10 == 9 { | |||
bits += " " | |||
} | |||
if i%50 == 49 { | |||
bits += " " | |||
} | |||
} | |||
if len(bits) > 0 { | |||
lines = append(lines, bits) | |||
} | |||
return fmt.Sprintf("BA{%v:%v}", bA.Bits, strings.Join(lines, indent)) | |||
} |
@ -0,0 +1,120 @@ | |||
package common | |||
import ( | |||
"testing" | |||
) | |||
func randBitArray(bits int) (*BitArray, []byte) { | |||
src := RandBytes((bits + 7) / 8) | |||
bA := NewBitArray(bits) | |||
for i := 0; i < len(src); i++ { | |||
for j := 0; j < 8; j++ { | |||
if i*8+j >= bits { | |||
return bA, src | |||
} | |||
setBit := src[i]&(1<<uint(j)) > 0 | |||
bA.SetIndex(i*8+j, setBit) | |||
} | |||
} | |||
return bA, src | |||
} | |||
func TestAnd(t *testing.T) { | |||
bA1, _ := randBitArray(51) | |||
bA2, _ := randBitArray(31) | |||
bA3 := bA1.And(bA2) | |||
if bA3.Bits != 31 { | |||
t.Error("Expected min bits", bA3.Bits) | |||
} | |||
if len(bA3.Elems) != len(bA2.Elems) { | |||
t.Error("Expected min elems length") | |||
} | |||
for i := 0; i < bA3.Bits; i++ { | |||
expected := bA1.GetIndex(i) && bA2.GetIndex(i) | |||
if bA3.GetIndex(i) != expected { | |||
t.Error("Wrong bit from bA3", i, bA1.GetIndex(i), bA2.GetIndex(i), bA3.GetIndex(i)) | |||
} | |||
} | |||
} | |||
func TestOr(t *testing.T) { | |||
bA1, _ := randBitArray(51) | |||
bA2, _ := randBitArray(31) | |||
bA3 := bA1.Or(bA2) | |||
if bA3.Bits != 51 { | |||
t.Error("Expected max bits") | |||
} | |||
if len(bA3.Elems) != len(bA1.Elems) { | |||
t.Error("Expected max elems length") | |||
} | |||
for i := 0; i < bA3.Bits; i++ { | |||
expected := bA1.GetIndex(i) || bA2.GetIndex(i) | |||
if bA3.GetIndex(i) != expected { | |||
t.Error("Wrong bit from bA3", i, bA1.GetIndex(i), bA2.GetIndex(i), bA3.GetIndex(i)) | |||
} | |||
} | |||
} | |||
func TestSub1(t *testing.T) { | |||
bA1, _ := randBitArray(31) | |||
bA2, _ := randBitArray(51) | |||
bA3 := bA1.Sub(bA2) | |||
if bA3.Bits != bA1.Bits { | |||
t.Error("Expected bA1 bits") | |||
} | |||
if len(bA3.Elems) != len(bA1.Elems) { | |||
t.Error("Expected bA1 elems length") | |||
} | |||
for i := 0; i < bA3.Bits; i++ { | |||
expected := bA1.GetIndex(i) | |||
if bA2.GetIndex(i) { | |||
expected = false | |||
} | |||
if bA3.GetIndex(i) != expected { | |||
t.Error("Wrong bit from bA3", i, bA1.GetIndex(i), bA2.GetIndex(i), bA3.GetIndex(i)) | |||
} | |||
} | |||
} | |||
func TestSub2(t *testing.T) { | |||
bA1, _ := randBitArray(51) | |||
bA2, _ := randBitArray(31) | |||
bA3 := bA1.Sub(bA2) | |||
if bA3.Bits != bA1.Bits { | |||
t.Error("Expected bA1 bits") | |||
} | |||
if len(bA3.Elems) != len(bA1.Elems) { | |||
t.Error("Expected bA1 elems length") | |||
} | |||
for i := 0; i < bA3.Bits; i++ { | |||
expected := bA1.GetIndex(i) | |||
if i < bA2.Bits && bA2.GetIndex(i) { | |||
expected = false | |||
} | |||
if bA3.GetIndex(i) != expected { | |||
t.Error("Wrong bit from bA3") | |||
} | |||
} | |||
} | |||
func TestPickRandom(t *testing.T) { | |||
for idx := 0; idx < 123; idx++ { | |||
bA1 := NewBitArray(123) | |||
bA1.SetIndex(idx, true) | |||
index, ok := bA1.PickRandom() | |||
if !ok { | |||
t.Fatal("Expected to pick element but got none") | |||
} | |||
if index != idx { | |||
t.Fatalf("Expected to pick element at %v but got wrong index", idx) | |||
} | |||
} | |||
} |
@ -0,0 +1,44 @@ | |||
package common | |||
import ( | |||
"bytes" | |||
) | |||
func Fingerprint(slice []byte) []byte { | |||
fingerprint := make([]byte, 6) | |||
copy(fingerprint, slice) | |||
return fingerprint | |||
} | |||
func IsZeros(slice []byte) bool { | |||
for _, byt := range slice { | |||
if byt != byte(0) { | |||
return false | |||
} | |||
} | |||
return true | |||
} | |||
func RightPadBytes(slice []byte, l int) []byte { | |||
if l < len(slice) { | |||
return slice | |||
} | |||
padded := make([]byte, l) | |||
copy(padded[0:len(slice)], slice) | |||
return padded | |||
} | |||
func LeftPadBytes(slice []byte, l int) []byte { | |||
if l < len(slice) { | |||
return slice | |||
} | |||
padded := make([]byte, l) | |||
copy(padded[l-len(slice):], slice) | |||
return padded | |||
} | |||
func TrimmedString(b []byte) string { | |||
trimSet := string([]byte{0}) | |||
return string(bytes.TrimLeft(b, trimSet)) | |||
} |
@ -0,0 +1,62 @@ | |||
package common | |||
import "sync" | |||
// CMap is a goroutine-safe map | |||
type CMap struct { | |||
m map[string]interface{} | |||
l sync.Mutex | |||
} | |||
func NewCMap() *CMap { | |||
return &CMap{ | |||
m: make(map[string]interface{}, 0), | |||
} | |||
} | |||
func (cm *CMap) Set(key string, value interface{}) { | |||
cm.l.Lock() | |||
defer cm.l.Unlock() | |||
cm.m[key] = value | |||
} | |||
func (cm *CMap) Get(key string) interface{} { | |||
cm.l.Lock() | |||
defer cm.l.Unlock() | |||
return cm.m[key] | |||
} | |||
func (cm *CMap) Has(key string) bool { | |||
cm.l.Lock() | |||
defer cm.l.Unlock() | |||
_, ok := cm.m[key] | |||
return ok | |||
} | |||
func (cm *CMap) Delete(key string) { | |||
cm.l.Lock() | |||
defer cm.l.Unlock() | |||
delete(cm.m, key) | |||
} | |||
func (cm *CMap) Size() int { | |||
cm.l.Lock() | |||
defer cm.l.Unlock() | |||
return len(cm.m) | |||
} | |||
func (cm *CMap) Clear() { | |||
cm.l.Lock() | |||
defer cm.l.Unlock() | |||
cm.m = make(map[string]interface{}, 0) | |||
} | |||
func (cm *CMap) Values() []interface{} { | |||
cm.l.Lock() | |||
defer cm.l.Unlock() | |||
items := []interface{}{} | |||
for _, v := range cm.m { | |||
items = append(items, v) | |||
} | |||
return items | |||
} |
@ -0,0 +1,84 @@ | |||
package common | |||
import ( | |||
"fmt" | |||
"strings" | |||
) | |||
const ( | |||
ANSIReset = "\x1b[0m" | |||
ANSIBright = "\x1b[1m" | |||
ANSIDim = "\x1b[2m" | |||
ANSIUnderscore = "\x1b[4m" | |||
ANSIBlink = "\x1b[5m" | |||
ANSIReverse = "\x1b[7m" | |||
ANSIHidden = "\x1b[8m" | |||
ANSIFgBlack = "\x1b[30m" | |||
ANSIFgRed = "\x1b[31m" | |||
ANSIFgGreen = "\x1b[32m" | |||
ANSIFgYellow = "\x1b[33m" | |||
ANSIFgBlue = "\x1b[34m" | |||
ANSIFgMagenta = "\x1b[35m" | |||
ANSIFgCyan = "\x1b[36m" | |||
ANSIFgWhite = "\x1b[37m" | |||
ANSIBgBlack = "\x1b[40m" | |||
ANSIBgRed = "\x1b[41m" | |||
ANSIBgGreen = "\x1b[42m" | |||
ANSIBgYellow = "\x1b[43m" | |||
ANSIBgBlue = "\x1b[44m" | |||
ANSIBgMagenta = "\x1b[45m" | |||
ANSIBgCyan = "\x1b[46m" | |||
ANSIBgWhite = "\x1b[47m" | |||
) | |||
// color the string s with color 'color' | |||
// unless s is already colored | |||
func treat(s string, color string) string { | |||
if len(s) > 2 && s[:2] == "\x1b[" { | |||
return s | |||
} else { | |||
return color + s + ANSIReset | |||
} | |||
} | |||
func treatAll(color string, args ...interface{}) string { | |||
var parts []string | |||
for _, arg := range args { | |||
parts = append(parts, treat(fmt.Sprintf("%v", arg), color)) | |||
} | |||
return strings.Join(parts, "") | |||
} | |||
func Black(args ...interface{}) string { | |||
return treatAll(ANSIFgBlack, args...) | |||
} | |||
func Red(args ...interface{}) string { | |||
return treatAll(ANSIFgRed, args...) | |||
} | |||
func Green(args ...interface{}) string { | |||
return treatAll(ANSIFgGreen, args...) | |||
} | |||
func Yellow(args ...interface{}) string { | |||
return treatAll(ANSIFgYellow, args...) | |||
} | |||
func Blue(args ...interface{}) string { | |||
return treatAll(ANSIFgBlue, args...) | |||
} | |||
func Magenta(args ...interface{}) string { | |||
return treatAll(ANSIFgMagenta, args...) | |||
} | |||
func Cyan(args ...interface{}) string { | |||
return treatAll(ANSIFgCyan, args...) | |||
} | |||
func White(args ...interface{}) string { | |||
return treatAll(ANSIFgWhite, args...) | |||
} |
@ -0,0 +1,45 @@ | |||
package common | |||
import ( | |||
"fmt" | |||
) | |||
type StackError struct { | |||
Err interface{} | |||
Stack []byte | |||
} | |||
func (se StackError) String() string { | |||
return fmt.Sprintf("Error: %v\nStack: %s", se.Err, se.Stack) | |||
} | |||
func (se StackError) Error() string { | |||
return se.String() | |||
} | |||
//-------------------------------------------------------------------------------------------------- | |||
// panic wrappers | |||
// A panic resulting from a sanity check means there is a programmer error | |||
// and some gaurantee is not satisfied. | |||
func PanicSanity(v interface{}) { | |||
panic(Fmt("Paniced on a Sanity Check: %v", v)) | |||
} | |||
// A panic here means something has gone horribly wrong, in the form of data corruption or | |||
// failure of the operating system. In a correct/healthy system, these should never fire. | |||
// If they do, it's indicative of a much more serious problem. | |||
func PanicCrisis(v interface{}) { | |||
panic(Fmt("Paniced on a Crisis: %v", v)) | |||
} | |||
// Indicates a failure of consensus. Someone was malicious or something has | |||
// gone horribly wrong. These should really boot us into an "emergency-recover" mode | |||
func PanicConsensus(v interface{}) { | |||
panic(Fmt("Paniced on a Consensus Failure: %v", v)) | |||
} | |||
// For those times when we're not sure if we should panic | |||
func PanicQ(v interface{}) { | |||
panic(Fmt("Paniced questionably: %v", v)) | |||
} |
@ -0,0 +1,103 @@ | |||
package common | |||
import ( | |||
"container/heap" | |||
) | |||
type Comparable interface { | |||
Less(o interface{}) bool | |||
} | |||
//----------------------------------------------------------------------------- | |||
/* | |||
Example usage: | |||
h := NewHeap() | |||
h.Push(String("msg1"), 1) | |||
h.Push(String("msg3"), 3) | |||
h.Push(String("msg2"), 2) | |||
fmt.Println(h.Pop()) | |||
fmt.Println(h.Pop()) | |||
fmt.Println(h.Pop()) | |||
*/ | |||
type Heap struct { | |||
pq priorityQueue | |||
} | |||
func NewHeap() *Heap { | |||
return &Heap{pq: make([]*pqItem, 0)} | |||
} | |||
func (h *Heap) Len() int64 { | |||
return int64(len(h.pq)) | |||
} | |||
func (h *Heap) Push(value interface{}, priority Comparable) { | |||
heap.Push(&h.pq, &pqItem{value: value, priority: priority}) | |||
} | |||
func (h *Heap) Peek() interface{} { | |||
if len(h.pq) == 0 { | |||
return nil | |||
} | |||
return h.pq[0].value | |||
} | |||
func (h *Heap) Update(value interface{}, priority Comparable) { | |||
h.pq.Update(h.pq[0], value, priority) | |||
} | |||
func (h *Heap) Pop() interface{} { | |||
item := heap.Pop(&h.pq).(*pqItem) | |||
return item.value | |||
} | |||
//----------------------------------------------------------------------------- | |||
/////////////////////// | |||
// From: http://golang.org/pkg/container/heap/#example__priorityQueue | |||
type pqItem struct { | |||
value interface{} | |||
priority Comparable | |||
index int | |||
} | |||
type priorityQueue []*pqItem | |||
func (pq priorityQueue) Len() int { return len(pq) } | |||
func (pq priorityQueue) Less(i, j int) bool { | |||
return pq[i].priority.Less(pq[j].priority) | |||
} | |||
func (pq priorityQueue) Swap(i, j int) { | |||
pq[i], pq[j] = pq[j], pq[i] | |||
pq[i].index = i | |||
pq[j].index = j | |||
} | |||
func (pq *priorityQueue) Push(x interface{}) { | |||
n := len(*pq) | |||
item := x.(*pqItem) | |||
item.index = n | |||
*pq = append(*pq, item) | |||
} | |||
func (pq *priorityQueue) Pop() interface{} { | |||
old := *pq | |||
n := len(old) | |||
item := old[n-1] | |||
item.index = -1 // for safety | |||
*pq = old[0 : n-1] | |||
return item | |||
} | |||
func (pq *priorityQueue) Update(item *pqItem, value interface{}, priority Comparable) { | |||
item.value = value | |||
item.priority = priority | |||
heap.Fix(pq, item.index) | |||
} |
@ -0,0 +1,55 @@ | |||
package common | |||
import ( | |||
"encoding/binary" | |||
"sort" | |||
) | |||
// Sort for []uint64 | |||
type Uint64Slice []uint64 | |||
func (p Uint64Slice) Len() int { return len(p) } | |||
func (p Uint64Slice) Less(i, j int) bool { return p[i] < p[j] } | |||
func (p Uint64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } | |||
func (p Uint64Slice) Sort() { sort.Sort(p) } | |||
func SearchUint64s(a []uint64, x uint64) int { | |||
return sort.Search(len(a), func(i int) bool { return a[i] >= x }) | |||
} | |||
func (p Uint64Slice) Search(x uint64) int { return SearchUint64s(p, x) } | |||
//----------------------------------------------------------------------------- | |||
func PutUint64LE(dest []byte, i uint64) { | |||
binary.LittleEndian.PutUint64(dest, i) | |||
} | |||
func GetUint64LE(src []byte) uint64 { | |||
return binary.LittleEndian.Uint64(src) | |||
} | |||
func PutUint64BE(dest []byte, i uint64) { | |||
binary.BigEndian.PutUint64(dest, i) | |||
} | |||
func GetUint64BE(src []byte) uint64 { | |||
return binary.BigEndian.Uint64(src) | |||
} | |||
func PutInt64LE(dest []byte, i int64) { | |||
binary.LittleEndian.PutUint64(dest, uint64(i)) | |||
} | |||
func GetInt64LE(src []byte) int64 { | |||
return int64(binary.LittleEndian.Uint64(src)) | |||
} | |||
func PutInt64BE(dest []byte, i int64) { | |||
binary.BigEndian.PutUint64(dest, uint64(i)) | |||
} | |||
func GetInt64BE(src []byte) int64 { | |||
return int64(binary.BigEndian.Uint64(src)) | |||
} |
@ -0,0 +1,75 @@ | |||
package common | |||
import ( | |||
"bytes" | |||
"errors" | |||
"io" | |||
) | |||
type PrefixedReader struct { | |||
Prefix []byte | |||
reader io.Reader | |||
} | |||
func NewPrefixedReader(prefix []byte, reader io.Reader) *PrefixedReader { | |||
return &PrefixedReader{prefix, reader} | |||
} | |||
func (pr *PrefixedReader) Read(p []byte) (n int, err error) { | |||
if len(pr.Prefix) > 0 { | |||
read := copy(p, pr.Prefix) | |||
pr.Prefix = pr.Prefix[read:] | |||
return read, nil | |||
} else { | |||
return pr.reader.Read(p) | |||
} | |||
} | |||
// NOTE: Not goroutine safe | |||
type BufferCloser struct { | |||
bytes.Buffer | |||
Closed bool | |||
} | |||
func NewBufferCloser(buf []byte) *BufferCloser { | |||
return &BufferCloser{ | |||
*bytes.NewBuffer(buf), | |||
false, | |||
} | |||
} | |||
func (bc *BufferCloser) Close() error { | |||
if bc.Closed { | |||
return errors.New("BufferCloser already closed") | |||
} | |||
bc.Closed = true | |||
return nil | |||
} | |||
func (bc *BufferCloser) Write(p []byte) (n int, err error) { | |||
if bc.Closed { | |||
return 0, errors.New("Cannot write to closed BufferCloser") | |||
} | |||
return bc.Buffer.Write(p) | |||
} | |||
func (bc *BufferCloser) WriteByte(c byte) error { | |||
if bc.Closed { | |||
return errors.New("Cannot write to closed BufferCloser") | |||
} | |||
return bc.Buffer.WriteByte(c) | |||
} | |||
func (bc *BufferCloser) WriteRune(r rune) (n int, err error) { | |||
if bc.Closed { | |||
return 0, errors.New("Cannot write to closed BufferCloser") | |||
} | |||
return bc.Buffer.WriteRune(r) | |||
} | |||
func (bc *BufferCloser) WriteString(s string) (n int, err error) { | |||
if bc.Closed { | |||
return 0, errors.New("Cannot write to closed BufferCloser") | |||
} | |||
return bc.Buffer.WriteString(s) | |||
} |
@ -0,0 +1,157 @@ | |||
package common | |||
func MaxInt8(a, b int8) int8 { | |||
if a > b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MaxUint8(a, b uint8) uint8 { | |||
if a > b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MaxInt16(a, b int16) int16 { | |||
if a > b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MaxUint16(a, b uint16) uint16 { | |||
if a > b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MaxInt32(a, b int32) int32 { | |||
if a > b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MaxUint32(a, b uint32) uint32 { | |||
if a > b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MaxInt64(a, b int64) int64 { | |||
if a > b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MaxUint64(a, b uint64) uint64 { | |||
if a > b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MaxInt(a, b int) int { | |||
if a > b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MaxUint(a, b uint) uint { | |||
if a > b { | |||
return a | |||
} | |||
return b | |||
} | |||
//----------------------------------------------------------------------------- | |||
func MinInt8(a, b int8) int8 { | |||
if a < b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MinUint8(a, b uint8) uint8 { | |||
if a < b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MinInt16(a, b int16) int16 { | |||
if a < b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MinUint16(a, b uint16) uint16 { | |||
if a < b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MinInt32(a, b int32) int32 { | |||
if a < b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MinUint32(a, b uint32) uint32 { | |||
if a < b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MinInt64(a, b int64) int64 { | |||
if a < b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MinUint64(a, b uint64) uint64 { | |||
if a < b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MinInt(a, b int) int { | |||
if a < b { | |||
return a | |||
} | |||
return b | |||
} | |||
func MinUint(a, b uint) uint { | |||
if a < b { | |||
return a | |||
} | |||
return b | |||
} | |||
//----------------------------------------------------------------------------- | |||
func ExpUint64(a, b uint64) uint64 { | |||
accum := uint64(1) | |||
for b > 0 { | |||
if b&1 == 1 { | |||
accum *= a | |||
} | |||
a *= a | |||
b >>= 1 | |||
} | |||
return accum | |||
} |
@ -0,0 +1,225 @@ | |||
package common | |||
import ( | |||
"bufio" | |||
"fmt" | |||
"io/ioutil" | |||
"os" | |||
"os/signal" | |||
"strings" | |||
"sync" | |||
"time" | |||
) | |||
var ( | |||
GoPath = os.Getenv("GOPATH") | |||
) | |||
func TrapSignal(cb func()) { | |||
c := make(chan os.Signal, 1) | |||
signal.Notify(c, os.Interrupt) | |||
signal.Notify(c, os.Kill) | |||
go func() { | |||
for sig := range c { | |||
fmt.Printf("captured %v, exiting...\n", sig) | |||
if cb != nil { | |||
cb() | |||
} | |||
os.Exit(1) | |||
} | |||
}() | |||
select {} | |||
} | |||
func Exit(s string) { | |||
fmt.Printf(s + "\n") | |||
os.Exit(1) | |||
} | |||
func EnsureDir(dir string) error { | |||
if _, err := os.Stat(dir); os.IsNotExist(err) { | |||
err := os.MkdirAll(dir, 0700) | |||
if err != nil { | |||
return fmt.Errorf("Could not create directory %v. %v", dir, err) | |||
} | |||
} | |||
return nil | |||
} | |||
func FileExists(filePath string) bool { | |||
_, err := os.Stat(filePath) | |||
return !os.IsNotExist(err) | |||
} | |||
func ReadFile(filePath string) ([]byte, error) { | |||
return ioutil.ReadFile(filePath) | |||
} | |||
func MustReadFile(filePath string) []byte { | |||
fileBytes, err := ioutil.ReadFile(filePath) | |||
if err != nil { | |||
Exit(Fmt("MustReadFile failed: %v", err)) | |||
return nil | |||
} | |||
return fileBytes | |||
} | |||
func WriteFile(filePath string, contents []byte) error { | |||
err := ioutil.WriteFile(filePath, contents, 0600) | |||
if err != nil { | |||
return err | |||
} | |||
// fmt.Printf("File written to %v.\n", filePath) | |||
return nil | |||
} | |||
func MustWriteFile(filePath string, contents []byte) { | |||
err := WriteFile(filePath, contents) | |||
if err != nil { | |||
Exit(Fmt("MustWriteFile failed: %v", err)) | |||
} | |||
} | |||
// Writes to newBytes to filePath. | |||
// Guaranteed not to lose *both* oldBytes and newBytes, | |||
// (assuming that the OS is perfect) | |||
func WriteFileAtomic(filePath string, newBytes []byte) error { | |||
// If a file already exists there, copy to filePath+".bak" (overwrite anything) | |||
if _, err := os.Stat(filePath); !os.IsNotExist(err) { | |||
fileBytes, err := ioutil.ReadFile(filePath) | |||
if err != nil { | |||
return fmt.Errorf("Could not read file %v. %v", filePath, err) | |||
} | |||
err = ioutil.WriteFile(filePath+".bak", fileBytes, 0600) | |||
if err != nil { | |||
return fmt.Errorf("Could not write file %v. %v", filePath+".bak", err) | |||
} | |||
} | |||
// Write newBytes to filePath.new | |||
err := ioutil.WriteFile(filePath+".new", newBytes, 0600) | |||
if err != nil { | |||
return fmt.Errorf("Could not write file %v. %v", filePath+".new", err) | |||
} | |||
// Move filePath.new to filePath | |||
err = os.Rename(filePath+".new", filePath) | |||
return err | |||
} | |||
//-------------------------------------------------------------------------------- | |||
/* AutoFile usage | |||
// Create/Append to ./autofile_test | |||
af, err := OpenAutoFile("autofile_test") | |||
if err != nil { | |||
panic(err) | |||
} | |||
// Stream of writes. | |||
// During this time, the file may be moved e.g. by logRotate. | |||
for i := 0; i < 60; i++ { | |||
af.Write([]byte(Fmt("LOOP(%v)", i))) | |||
time.Sleep(time.Second) | |||
} | |||
// Close the AutoFile | |||
err = af.Close() | |||
if err != nil { | |||
panic(err) | |||
} | |||
*/ | |||
const autoFileOpenDuration = 1000 * time.Millisecond | |||
// Automatically closes and re-opens file for writing. | |||
// This is useful for using a log file with the logrotate tool. | |||
type AutoFile struct { | |||
Path string | |||
ticker *time.Ticker | |||
mtx sync.Mutex | |||
file *os.File | |||
} | |||
func OpenAutoFile(path string) (af *AutoFile, err error) { | |||
af = &AutoFile{ | |||
Path: path, | |||
ticker: time.NewTicker(autoFileOpenDuration), | |||
} | |||
if err = af.openFile(); err != nil { | |||
return | |||
} | |||
go af.processTicks() | |||
return | |||
} | |||
func (af *AutoFile) Close() error { | |||
af.ticker.Stop() | |||
af.mtx.Lock() | |||
err := af.closeFile() | |||
af.mtx.Unlock() | |||
return err | |||
} | |||
func (af *AutoFile) processTicks() { | |||
for { | |||
_, ok := <-af.ticker.C | |||
if !ok { | |||
return // Done. | |||
} | |||
af.mtx.Lock() | |||
af.closeFile() | |||
af.mtx.Unlock() | |||
} | |||
} | |||
func (af *AutoFile) closeFile() (err error) { | |||
file := af.file | |||
if file == nil { | |||
return nil | |||
} | |||
af.file = nil | |||
return file.Close() | |||
} | |||
func (af *AutoFile) Write(b []byte) (n int, err error) { | |||
af.mtx.Lock() | |||
defer af.mtx.Unlock() | |||
if af.file == nil { | |||
if err = af.openFile(); err != nil { | |||
return | |||
} | |||
} | |||
return af.file.Write(b) | |||
} | |||
func (af *AutoFile) openFile() error { | |||
file, err := os.OpenFile(af.Path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600) | |||
if err != nil { | |||
return err | |||
} | |||
af.file = file | |||
return nil | |||
} | |||
func Tempfile(prefix string) (*os.File, string) { | |||
file, err := ioutil.TempFile("", prefix) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
return file, file.Name() | |||
} | |||
func Prompt(prompt string, defaultValue string) (string, error) { | |||
fmt.Print(prompt) | |||
reader := bufio.NewReader(os.Stdin) | |||
line, err := reader.ReadString('\n') | |||
if err != nil { | |||
return defaultValue, err | |||
} else { | |||
line = strings.TrimSpace(line) | |||
if line == "" { | |||
return defaultValue, nil | |||
} | |||
return line, nil | |||
} | |||
} |
@ -0,0 +1,145 @@ | |||
package common | |||
import ( | |||
crand "crypto/rand" | |||
"encoding/hex" | |||
"math/rand" | |||
"time" | |||
) | |||
const ( | |||
strChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // 62 characters | |||
) | |||
func init() { | |||
// Seed math/rand with "secure" int64 | |||
b := CRandBytes(8) | |||
var seed uint64 | |||
for i := 0; i < 8; i++ { | |||
seed |= uint64(b[i]) | |||
seed <<= 8 | |||
} | |||
rand.Seed(int64(seed)) | |||
} | |||
// Constructs an alphanumeric string of given length. | |||
func RandStr(length int) string { | |||
chars := []byte{} | |||
MAIN_LOOP: | |||
for { | |||
val := rand.Int63() | |||
for i := 0; i < 10; i++ { | |||
v := int(val & 0x3f) // rightmost 6 bits | |||
if v >= 62 { // only 62 characters in strChars | |||
val >>= 6 | |||
continue | |||
} else { | |||
chars = append(chars, strChars[v]) | |||
if len(chars) == length { | |||
break MAIN_LOOP | |||
} | |||
val >>= 6 | |||
} | |||
} | |||
} | |||
return string(chars) | |||
} | |||
func RandUint16() uint16 { | |||
return uint16(rand.Uint32() & (1<<16 - 1)) | |||
} | |||
func RandUint32() uint32 { | |||
return rand.Uint32() | |||
} | |||
func RandUint64() uint64 { | |||
return uint64(rand.Uint32())<<32 + uint64(rand.Uint32()) | |||
} | |||
func RandUint() uint { | |||
return uint(rand.Int()) | |||
} | |||
func RandInt16() int16 { | |||
return int16(rand.Uint32() & (1<<16 - 1)) | |||
} | |||
func RandInt32() int32 { | |||
return int32(rand.Uint32()) | |||
} | |||
func RandInt64() int64 { | |||
return int64(rand.Uint32())<<32 + int64(rand.Uint32()) | |||
} | |||
func RandInt() int { | |||
return rand.Int() | |||
} | |||
// Distributed pseudo-exponentially to test for various cases | |||
func RandUint16Exp() uint16 { | |||
bits := rand.Uint32() % 16 | |||
if bits == 0 { | |||
return 0 | |||
} | |||
n := uint16(1 << (bits - 1)) | |||
n += uint16(rand.Int31()) & ((1 << (bits - 1)) - 1) | |||
return n | |||
} | |||
// Distributed pseudo-exponentially to test for various cases | |||
func RandUint32Exp() uint32 { | |||
bits := rand.Uint32() % 32 | |||
if bits == 0 { | |||
return 0 | |||
} | |||
n := uint32(1 << (bits - 1)) | |||
n += uint32(rand.Int31()) & ((1 << (bits - 1)) - 1) | |||
return n | |||
} | |||
// Distributed pseudo-exponentially to test for various cases | |||
func RandUint64Exp() uint64 { | |||
bits := rand.Uint32() % 64 | |||
if bits == 0 { | |||
return 0 | |||
} | |||
n := uint64(1 << (bits - 1)) | |||
n += uint64(rand.Int63()) & ((1 << (bits - 1)) - 1) | |||
return n | |||
} | |||
func RandFloat32() float32 { | |||
return rand.Float32() | |||
} | |||
func RandTime() time.Time { | |||
return time.Unix(int64(RandUint64Exp()), 0) | |||
} | |||
func RandBytes(n int) []byte { | |||
bs := make([]byte, n) | |||
for i := 0; i < n; i++ { | |||
bs[i] = byte(rand.Intn(256)) | |||
} | |||
return bs | |||
} | |||
//----------------------------------------------------------------------------- | |||
// CRand* methods are crypto safe. | |||
func CRandBytes(numBytes int) []byte { | |||
b := make([]byte, numBytes) | |||
_, err := crand.Read(b) | |||
if err != nil { | |||
PanicCrisis(err) | |||
} | |||
return b | |||
} | |||
// RandHex(24) gives 96 bits of randomness, strong enough for most purposes. | |||
func CRandHex(numDigits int) string { | |||
return hex.EncodeToString(CRandBytes(numDigits / 2)) | |||
} |
@ -0,0 +1,72 @@ | |||
package common | |||
import "time" | |||
import "sync" | |||
/* | |||
RepeatTimer repeatedly sends a struct{}{} to .Ch after each "dur" period. | |||
It's good for keeping connections alive. | |||
A RepeatTimer must be Stop()'d or it will keep a goroutine alive. | |||
*/ | |||
type RepeatTimer struct { | |||
Ch chan time.Time | |||
mtx sync.Mutex | |||
name string | |||
ticker *time.Ticker | |||
quit chan struct{} | |||
dur time.Duration | |||
} | |||
func NewRepeatTimer(name string, dur time.Duration) *RepeatTimer { | |||
var t = &RepeatTimer{ | |||
Ch: make(chan time.Time), | |||
ticker: time.NewTicker(dur), | |||
quit: make(chan struct{}), | |||
name: name, | |||
dur: dur, | |||
} | |||
go t.fireRoutine(t.ticker) | |||
return t | |||
} | |||
func (t *RepeatTimer) fireRoutine(ticker *time.Ticker) { | |||
for { | |||
select { | |||
case t_ := <-ticker.C: | |||
t.Ch <- t_ | |||
case <-t.quit: | |||
return | |||
} | |||
} | |||
} | |||
// Wait the duration again before firing. | |||
func (t *RepeatTimer) Reset() { | |||
t.Stop() | |||
t.mtx.Lock() // Lock | |||
defer t.mtx.Unlock() | |||
t.ticker = time.NewTicker(t.dur) | |||
t.quit = make(chan struct{}) | |||
go t.fireRoutine(t.ticker) | |||
} | |||
// For ease of .Stop()'ing services before .Start()'ing them, | |||
// we ignore .Stop()'s on nil RepeatTimers. | |||
func (t *RepeatTimer) Stop() bool { | |||
if t == nil { | |||
return false | |||
} | |||
t.mtx.Lock() // Lock | |||
defer t.mtx.Unlock() | |||
exists := t.ticker != nil | |||
if exists { | |||
t.ticker.Stop() | |||
t.ticker = nil | |||
close(t.quit) | |||
} | |||
return exists | |||
} |
@ -0,0 +1,154 @@ | |||
/* | |||
Classical-inheritance-style service declarations. | |||
Services can be started, then stopped. | |||
Users can override the OnStart/OnStop methods. | |||
These methods are guaranteed to be called at most once. | |||
Caller must ensure that Start() and Stop() are not called concurrently. | |||
It is ok to call Stop() without calling Start() first. | |||
Services cannot be re-started unless otherwise documented. | |||
Typical usage: | |||
type FooService struct { | |||
BaseService | |||
// private fields | |||
} | |||
func NewFooService() *FooService { | |||
fs := &FooService{ | |||
// init | |||
} | |||
fs.BaseService = *NewBaseService(log, "FooService", fs) | |||
return fs | |||
} | |||
func (fs *FooService) OnStart() error { | |||
fs.BaseService.OnStart() // Always call the overridden method. | |||
// initialize private fields | |||
// start subroutines, etc. | |||
} | |||
func (fs *FooService) OnStop() error { | |||
fs.BaseService.OnStop() // Always call the overridden method. | |||
// close/destroy private fields | |||
// stop subroutines, etc. | |||
} | |||
*/ | |||
package common | |||
import "sync/atomic" | |||
import "github.com/tendermint/tendermint/Godeps/_workspace/src/github.com/tendermint/log15" | |||
type Service interface { | |||
Start() (bool, error) | |||
OnStart() error | |||
Stop() bool | |||
OnStop() | |||
IsRunning() bool | |||
String() string | |||
} | |||
type BaseService struct { | |||
log log15.Logger | |||
name string | |||
started uint32 // atomic | |||
stopped uint32 // atomic | |||
// The "subclass" of BaseService | |||
impl Service | |||
} | |||
func NewBaseService(log log15.Logger, name string, impl Service) *BaseService { | |||
return &BaseService{ | |||
log: log, | |||
name: name, | |||
impl: impl, | |||
} | |||
} | |||
// Implements Servce | |||
func (bs *BaseService) Start() (bool, error) { | |||
if atomic.CompareAndSwapUint32(&bs.started, 0, 1) { | |||
if atomic.LoadUint32(&bs.stopped) == 1 { | |||
if bs.log != nil { | |||
bs.log.Warn(Fmt("Not starting %v -- already stopped", bs.name), "impl", bs.impl) | |||
} | |||
return false, nil | |||
} else { | |||
if bs.log != nil { | |||
bs.log.Notice(Fmt("Starting %v", bs.name), "impl", bs.impl) | |||
} | |||
} | |||
err := bs.impl.OnStart() | |||
return true, err | |||
} else { | |||
if bs.log != nil { | |||
bs.log.Info(Fmt("Not starting %v -- already started", bs.name), "impl", bs.impl) | |||
} | |||
return false, nil | |||
} | |||
} | |||
// Implements Service | |||
func (bs *BaseService) OnStart() error { return nil } | |||
// Implements Service | |||
func (bs *BaseService) Stop() bool { | |||
if atomic.CompareAndSwapUint32(&bs.stopped, 0, 1) { | |||
if bs.log != nil { | |||
bs.log.Notice(Fmt("Stopping %v", bs.name), "impl", bs.impl) | |||
} | |||
bs.impl.OnStop() | |||
return true | |||
} else { | |||
if bs.log != nil { | |||
bs.log.Notice(Fmt("Not stopping %v", bs.name), "impl", bs.impl) | |||
} | |||
return false | |||
} | |||
} | |||
// Implements Service | |||
func (bs *BaseService) OnStop() {} | |||
// Implements Service | |||
func (bs *BaseService) IsRunning() bool { | |||
return atomic.LoadUint32(&bs.started) == 1 && atomic.LoadUint32(&bs.stopped) == 0 | |||
} | |||
// Implements Servce | |||
func (bs *BaseService) String() string { | |||
return bs.name | |||
} | |||
//---------------------------------------- | |||
type QuitService struct { | |||
BaseService | |||
Quit chan struct{} | |||
} | |||
func NewQuitService(log log15.Logger, name string, impl Service) *QuitService { | |||
return &QuitService{ | |||
BaseService: *NewBaseService(log, name, impl), | |||
Quit: nil, | |||
} | |||
} | |||
// NOTE: when overriding OnStart, must call .QuitService.OnStart(). | |||
func (qs *QuitService) OnStart() error { | |||
qs.Quit = make(chan struct{}) | |||
return nil | |||
} | |||
// NOTE: when overriding OnStop, must call .QuitService.OnStop(). | |||
func (qs *QuitService) OnStop() { | |||
if qs.Quit != nil { | |||
close(qs.Quit) | |||
} | |||
} |
@ -0,0 +1,24 @@ | |||
package common | |||
import ( | |||
"fmt" | |||
"strings" | |||
) | |||
var Fmt = fmt.Sprintf | |||
func RightPadString(s string, totalLength int) string { | |||
remaining := totalLength - len(s) | |||
if remaining > 0 { | |||
s = s + strings.Repeat(" ", remaining) | |||
} | |||
return s | |||
} | |||
func LeftPadString(s string, totalLength int) string { | |||
remaining := totalLength - len(s) | |||
if remaining > 0 { | |||
s = strings.Repeat(" ", remaining) + s | |||
} | |||
return s | |||
} |
@ -0,0 +1,14 @@ | |||
package test | |||
import ( | |||
"testing" | |||
) | |||
func AssertPanics(t *testing.T, msg string, f func()) { | |||
defer func() { | |||
if err := recover(); err == nil { | |||
t.Errorf("Should have panic'd, but didn't: %v", msg) | |||
} | |||
}() | |||
f() | |||
} |
@ -0,0 +1,28 @@ | |||
package test | |||
import ( | |||
. "github.com/tendermint/tendermint/common" | |||
) | |||
// Contract: !bytes.Equal(input, output) && len(input) >= len(output) | |||
func MutateByteSlice(bytez []byte) []byte { | |||
// If bytez is empty, panic | |||
if len(bytez) == 0 { | |||
panic("Cannot mutate an empty bytez") | |||
} | |||
// Copy bytez | |||
mBytez := make([]byte, len(bytez)) | |||
copy(mBytez, bytez) | |||
bytez = mBytez | |||
// Try a random mutation | |||
switch RandInt() % 2 { | |||
case 0: // Mutate a single byte | |||
bytez[RandInt()%len(bytez)] += byte(RandInt()%255 + 1) | |||
case 1: // Remove an arbitrary byte | |||
pos := RandInt() % len(bytez) | |||
bytez = append(bytez[:pos], bytez[pos+1:]...) | |||
} | |||
return bytez | |||
} |
@ -0,0 +1,57 @@ | |||
package common | |||
import ( | |||
"sync/atomic" | |||
"time" | |||
) | |||
/* | |||
ThrottleTimer fires an event at most "dur" after each .Set() call. | |||
If a short burst of .Set() calls happens, ThrottleTimer fires once. | |||
If a long continuous burst of .Set() calls happens, ThrottleTimer fires | |||
at most once every "dur". | |||
*/ | |||
type ThrottleTimer struct { | |||
Name string | |||
Ch chan struct{} | |||
quit chan struct{} | |||
dur time.Duration | |||
timer *time.Timer | |||
isSet uint32 | |||
} | |||
func NewThrottleTimer(name string, dur time.Duration) *ThrottleTimer { | |||
var ch = make(chan struct{}) | |||
var quit = make(chan struct{}) | |||
var t = &ThrottleTimer{Name: name, Ch: ch, dur: dur, quit: quit} | |||
t.timer = time.AfterFunc(dur, t.fireRoutine) | |||
t.timer.Stop() | |||
return t | |||
} | |||
func (t *ThrottleTimer) fireRoutine() { | |||
select { | |||
case t.Ch <- struct{}{}: | |||
atomic.StoreUint32(&t.isSet, 0) | |||
case <-t.quit: | |||
// do nothing | |||
default: | |||
t.timer.Reset(t.dur) | |||
} | |||
} | |||
func (t *ThrottleTimer) Set() { | |||
if atomic.CompareAndSwapUint32(&t.isSet, 0, 1) { | |||
t.timer.Reset(t.dur) | |||
} | |||
} | |||
// For ease of .Stop()'ing services before .Start()'ing them, | |||
// we ignore .Stop()'s on nil ThrottleTimers | |||
func (t *ThrottleTimer) Stop() bool { | |||
if t == nil { | |||
return false | |||
} | |||
close(t.quit) | |||
return t.timer.Stop() | |||
} |
@ -0,0 +1,91 @@ | |||
package common | |||
import ( | |||
"bytes" | |||
"sort" | |||
) | |||
var ( | |||
Zero256 = Word256{0} | |||
One256 = Word256{1} | |||
) | |||
type Word256 [32]byte | |||
func (w Word256) String() string { return string(w[:]) } | |||
func (w Word256) TrimmedString() string { return TrimmedString(w.Bytes()) } | |||
func (w Word256) Copy() Word256 { return w } | |||
func (w Word256) Bytes() []byte { return w[:] } // copied. | |||
func (w Word256) Prefix(n int) []byte { return w[:n] } | |||
func (w Word256) Postfix(n int) []byte { return w[32-n:] } | |||
func (w Word256) IsZero() bool { | |||
accum := byte(0) | |||
for _, byt := range w { | |||
accum |= byt | |||
} | |||
return accum == 0 | |||
} | |||
func (w Word256) Compare(other Word256) int { | |||
return bytes.Compare(w[:], other[:]) | |||
} | |||
func Uint64ToWord256(i uint64) Word256 { | |||
buf := [8]byte{} | |||
PutUint64BE(buf[:], i) | |||
return LeftPadWord256(buf[:]) | |||
} | |||
func Int64ToWord256(i int64) Word256 { | |||
buf := [8]byte{} | |||
PutInt64BE(buf[:], i) | |||
return LeftPadWord256(buf[:]) | |||
} | |||
func RightPadWord256(bz []byte) (word Word256) { | |||
copy(word[:], bz) | |||
return | |||
} | |||
func LeftPadWord256(bz []byte) (word Word256) { | |||
copy(word[32-len(bz):], bz) | |||
return | |||
} | |||
func Uint64FromWord256(word Word256) uint64 { | |||
buf := word.Postfix(8) | |||
return GetUint64BE(buf) | |||
} | |||
func Int64FromWord256(word Word256) int64 { | |||
buf := word.Postfix(8) | |||
return GetInt64BE(buf) | |||
} | |||
//------------------------------------- | |||
type Tuple256 struct { | |||
First Word256 | |||
Second Word256 | |||
} | |||
func (tuple Tuple256) Compare(other Tuple256) int { | |||
firstCompare := tuple.First.Compare(other.First) | |||
if firstCompare == 0 { | |||
return tuple.Second.Compare(other.Second) | |||
} else { | |||
return firstCompare | |||
} | |||
} | |||
func Tuple256Split(t Tuple256) (Word256, Word256) { | |||
return t.First, t.Second | |||
} | |||
type Tuple256Slice []Tuple256 | |||
func (p Tuple256Slice) Len() int { return len(p) } | |||
func (p Tuple256Slice) Less(i, j int) bool { | |||
return p[i].Compare(p[j]) < 0 | |||
} | |||
func (p Tuple256Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } | |||
func (p Tuple256Slice) Sort() { sort.Sort(p) } |