-
Notifications
You must be signed in to change notification settings - Fork 0
/
freelist.go
62 lines (53 loc) · 1.45 KB
/
freelist.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
package gofl
type Resetter interface {
// Reset tries to keep the memory allocated and safe to reuse.
Reset()
}
// NewFn should create a new instance of T.
type NewFn[T Resetter] func() T
// FreeList represents a list of T that can be reused. It is safe for concurrent use but it does not protect underlying T from concurrent access.
//
// Zero value is not usable, use gofl.NewFreeList() to create a new instance.
type FreeList[T Resetter] struct {
buffer chan T
newFn NewFn[T]
zero T
}
// NewFreeList creates a new free list with given capacity and newFn.
// If newFn is nil then zero value of T will be returned on Get operation.
func NewFreeList[T Resetter](max uint, f NewFn[T]) FreeList[T] {
return FreeList[T]{
buffer: make(chan T, max),
newFn: f,
}
}
// Get returns a T from the free list. It creates a new instance of T with provided newFn, if not available.
func (fl FreeList[T]) Get() T {
t, _ := fl.get()
return t
}
func (fl FreeList[T]) get() (T, bool) {
select {
case v := <-fl.buffer:
return v, true
default:
if fl.newFn == nil {
return fl.zero, false
}
return fl.newFn(), false
}
}
// Put returns a T to the free list after calling Reset(). T will be dropped if list is full.
func (fl FreeList[T]) Put(v T) {
_ = fl.put(v)
}
func (fl FreeList[T]) put(v T) bool {
v.Reset() // TODO: wasted efforts if buffer is full
select {
case fl.buffer <- v:
return true
default:
// drop item; buffer is full
return false
}
}