1
0
mirror of https://github.com/fumiama/orbyte.git synced 2026-06-05 10:10:30 +08:00
Files
orbyte/item.go
2025-02-25 14:22:31 +09:00

131 lines
2.7 KiB
Go

package orbyte
import (
"runtime"
"sync/atomic"
)
// Item represents a thread-safe user-defined value.
//
// Only the item that has ownership can be a pointer.
// Do not copy neither Item nor *Item by yourself.
// You must always use the given methods.
type Item[T any] struct {
pool *Pool[T]
cfg any
stat status
val T
}
// Trans ownership to a new item and
// destroy original item immediately.
//
// The value in new item will not be Reset().
//
// Call this function to drop your ownership
// before passing it to another function
// that is not controlled by you.
func (b *Item[T]) Trans() (tb *Item[T]) {
if b.stat.hasdestroyed() {
panic("use after destroy")
}
tb = b.pool.newempty()
*tb = *b
tb.stat = status(atomic.SwapUintptr(
(*uintptr)(&b.stat), uintptr(destroyedstatus),
))
tb.stat.setintrans(true)
b.destroybystat(status(0))
return tb
}
// IsTrans whether this item has been marked as trans.
func (b *Item[T]) IsTrans() bool {
return b.stat.isintrans()
}
// Unwrap use value of the item
func (b *Item[T]) Unwrap() T {
if b.stat.hasdestroyed() {
panic("use after destroy")
}
return b.val
}
// Pointer use pointer value of the item
func (b *Item[T]) Pointer() *T {
if b.stat.hasdestroyed() {
panic("use after destroy")
}
return &b.val
}
// Ref gens new item without ownership.
//
// It's a safe reference, thus calling this
// will not destroy the original item
// comparing with Trans().
func (b *Item[T]) Ref() (rb *Item[T]) {
if b.stat.hasdestroyed() {
panic("use after destroy")
}
rb = b.pool.newempty()
*rb = *b
rb.stat.setbuffered(false)
rb.stat.setintrans(false)
return
}
// Copy data completely with separated ownership.
func (b *Item[T]) Copy() (cb *Item[T]) {
if b.stat.hasdestroyed() {
panic("use after destroy")
}
cb = b.pool.New(b.cfg)
b.pool.pooler.Copy(&cb.val, &b.val)
return
}
func (b *Item[T]) destroybystat(stat status) {
switch {
case stat.hasdestroyed():
panic("use after destroy")
case stat.isintrans():
var v T
b.val = v
case stat.isbuffered():
b.pool.pooler.Reset(&b.val)
default:
var v T
b.val = v
}
b.pool.put(b)
}
// Destroy item and put it back to pool.
func (b *Item[T]) Destroy() {
b.destroybystat(status(atomic.SwapUintptr(
(*uintptr)(&b.stat), uintptr(destroyedstatus),
)))
}
// setautodestroy item on GC.
//
// Only can call once.
func (b *Item[T]) setautodestroy() *Item[T] {
runtime.SetFinalizer(b, func(item *Item[T]) {
// no one is using, no concurrency issue.
if item.stat.hasdestroyed() {
panic("unexpected hasdestroyed")
}
if !item.stat.isintrans() && item.stat.isbuffered() {
item.pool.pooler.Reset(&item.val)
}
item.stat.setdestroyed(true)
item.pool.put(item)
})
return b
}