|
- package amqp
-
- import (
- "bytes"
- "fmt"
- "math/big"
- )
-
- const (
- free = 0
- allocated = 1
- )
-
- // allocator maintains a bitset of allocated numbers.
- type allocator struct {
- pool *big.Int
- last int
- low int
- high int
- }
-
- // NewAllocator reserves and frees integers out of a range between low and
- // high.
- //
- // O(N) worst case space used, where N is maximum allocated, divided by
- // sizeof(big.Word)
- func newAllocator(low, high int) *allocator {
- return &allocator{
- pool: big.NewInt(0),
- last: low,
- low: low,
- high: high,
- }
- }
-
- // String returns a string describing the contents of the allocator like
- // "allocator[low..high] reserved..until"
- //
- // O(N) where N is high-low
- func (a allocator) String() string {
- b := &bytes.Buffer{}
- fmt.Fprintf(b, "allocator[%d..%d]", a.low, a.high)
-
- for low := a.low; low <= a.high; low++ {
- high := low
- for a.reserved(high) && high <= a.high {
- high++
- }
-
- if high > low+1 {
- fmt.Fprintf(b, " %d..%d", low, high-1)
- } else if high > low {
- fmt.Fprintf(b, " %d", high-1)
- }
-
- low = high
- }
- return b.String()
- }
-
- // Next reserves and returns the next available number out of the range between
- // low and high. If no number is available, false is returned.
- //
- // O(N) worst case runtime where N is allocated, but usually O(1) due to a
- // rolling index into the oldest allocation.
- func (a *allocator) next() (int, bool) {
- wrapped := a.last
-
- // Find trailing bit
- for ; a.last <= a.high; a.last++ {
- if a.reserve(a.last) {
- return a.last, true
- }
- }
-
- // Find preceding free'd pool
- a.last = a.low
-
- for ; a.last < wrapped; a.last++ {
- if a.reserve(a.last) {
- return a.last, true
- }
- }
-
- return 0, false
- }
-
- // reserve claims the bit if it is not already claimed, returning true if
- // successfully claimed.
- func (a *allocator) reserve(n int) bool {
- if a.reserved(n) {
- return false
- }
- a.pool.SetBit(a.pool, n-a.low, allocated)
- return true
- }
-
- // reserved returns true if the integer has been allocated
- func (a *allocator) reserved(n int) bool {
- return a.pool.Bit(n-a.low) == allocated
- }
-
- // release frees the use of the number for another allocation
- func (a *allocator) release(n int) {
- a.pool.SetBit(a.pool, n-a.low, free)
- }
|