package go_int32_handle import ( "fmt" "github.com/gammazero/deque" "sync" ) type Payload interface { } var ErrHandleExceedMax = fmt.Errorf("handle exceed max") type HandleManager[T Payload] struct { handles map[int32]T lock sync.RWMutex counter int32 releasedHandles *deque.Deque[int32] max int32 } // New returns a new handle manager, same as NewWithRange(0, 2147483647) func New[T Payload]() *HandleManager[T] { return &HandleManager[T]{ handles: make(map[int32]T), releasedHandles: deque.New[int32](), counter: 0, lock: sync.RWMutex{}, max: 2147483647, } } // NewWithRange returns a new handle manager. // `shouldAbove` is the first handle - 1. this should be greater than 0 or equal to 0. // `max` is the last handle. this should be greater than 0. func NewWithRange[T Payload](shouldAbove int32, max int32) *HandleManager[T] { return &HandleManager[T]{ handles: make(map[int32]T), releasedHandles: deque.New[int32](), counter: shouldAbove, lock: sync.RWMutex{}, max: max, } } func (hm *HandleManager[T]) getNewHandle() int32 { if hm.releasedHandles.Len() > 0 { return hm.releasedHandles.PopFront() } else { hm.counter = hm.counter + 1 return hm.counter } } func (hm *HandleManager[T]) AllocateAndPut(value T) (int32, error) { hm.lock.Lock() defer hm.lock.Unlock() h := hm.getNewHandle() if h >= hm.max { return 0, ErrHandleExceedMax } _, ok := hm.handles[h] if ok { return 0, fmt.Errorf("internal error: failed to allocate handle: next val %d is already in use", h) } hm.handles[h] = value return h, nil } func (hm *HandleManager[T]) Get(h int32) (T, bool) { hm.lock.RLock() defer hm.lock.RUnlock() if h <= 0 { var emptyT T return emptyT, false } value, ok := hm.handles[h] return value, ok } func (hm *HandleManager[T]) Release(h int32) (T, bool) { hm.lock.Lock() defer hm.lock.Unlock() if h <= 0 { var emptyT T return emptyT, false } value, ok := hm.handles[h] if ok { delete(hm.handles, h) hm.releasedHandles.PushBack(h) } return value, ok } func (hm *HandleManager[T]) ReleaseSilently(h int32) { hm.lock.Lock() defer hm.lock.Unlock() if h <= 0 { return } _, ok := hm.handles[h] if ok { delete(hm.handles, h) hm.releasedHandles.PushBack(h) } } func (hm *HandleManager[T]) Count() int { hm.lock.RLock() defer hm.lock.RUnlock() return len(hm.handles) }