forked from loxilb-io/loxilib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcounter.go
100 lines (87 loc) · 1.96 KB
/
counter.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// SPDX-License-Identifier: Apache 2.0
// Copyright (c) 2022 NetLOX Inc
package loxilib
import (
"errors"
)
// Counter - context container
type Counter struct {
begin uint64
end uint64
start uint64
len uint64
cap uint64
counters []uint64
}
// NewCounter - Allocate a set of counters
func NewCounter(begin uint64, length uint64) *Counter {
counter := new(Counter)
counter.counters = make([]uint64, length)
counter.begin = begin
counter.start = 0
counter.end = length - 1
counter.len = length
counter.cap = length
for i := uint64(0); i < length; i++ {
counter.counters[i] = i + 1
}
counter.counters[length-1] = ^uint64(0)
return counter
}
// GetCounter - Get next available counter
func (C *Counter) GetCounter() (uint64, error) {
if C.cap <= 0 || C.start == ^uint64(0) {
return ^uint64(0), errors.New("Overflow")
}
C.cap--
var rid = C.start
if C.start == C.end {
C.start = ^uint64(0)
} else {
C.start = C.counters[rid]
C.counters[rid] = ^uint64(0)
}
return rid + C.begin, nil
}
// PutCounter - Return a counter to the available list
func (C *Counter) PutCounter(id uint64) error {
if id < C.begin || id >= C.begin+C.len {
return errors.New("Range")
}
rid := id - C.begin
var tmp = C.end
C.end = rid
C.counters[tmp] = rid
C.cap++
if C.start == ^uint64(0) {
C.start = C.end
}
return nil
}
// ReserveCounter - Don't allocate this counter
func (C *Counter) ReserveCounter(id uint64) error {
if id < C.begin || id >= C.begin+C.len {
return errors.New("Range")
}
if C.cap <= 0 || C.start == ^uint64(0) || C.counters[id] == ^uint64(0) {
return errors.New("Overflow")
}
rid := id - C.begin
if C.counters[rid] == ^uint64(0) {
return errors.New("Already exists")
}
for i := uint64(0); i < C.len; i++ {
if C.counters[i] == rid {
C.counters[i] = C.counters[rid]
}
}
if C.start == rid {
C.start = C.counters[rid]
}
if C.end == rid {
C.end = C.counters[rid]
}
C.counters[rid] = ^uint64(0)
C.cap--
return nil
}