mirror of
https://github.com/fumiama/orbyte.git
synced 2026-06-05 02:00:30 +08:00
168 lines
3.6 KiB
Go
168 lines
3.6 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]
|
|
stat status
|
|
// align 64
|
|
|
|
cfg any
|
|
// align 64
|
|
|
|
// id only take effect on issync = True
|
|
id int64
|
|
// align 64
|
|
|
|
val T
|
|
}
|
|
|
|
// Ignore marks Item to be independent and will not be
|
|
// put back.
|
|
func (b *Item[T]) Ignore() *Item[T] {
|
|
b.stat.setignored(true)
|
|
return b
|
|
}
|
|
|
|
// Trans disable inner val being reset by
|
|
// destroy and return a safe copy of val.
|
|
//
|
|
// This method is not thread-safe.
|
|
// Only call once on one item.
|
|
// The item will be destroyed after calling Trans().
|
|
//
|
|
// Use it to drop your ownership
|
|
// before passing val (not its pointer)
|
|
// to another function that is not controlled by you.
|
|
func (b *Item[T]) Trans() T {
|
|
if b.stat.hasdestroyed() {
|
|
panic("use after destroy")
|
|
}
|
|
if b.pool.issync {
|
|
if !b.stat.setinsyncop(true) {
|
|
panic("non-unique op")
|
|
}
|
|
}
|
|
val := b.val
|
|
atomic.StoreUintptr(
|
|
(*uintptr)(&b.stat), uintptr(destroyedstatus),
|
|
)
|
|
runtime.KeepAlive(b)
|
|
b.destroybystat(0)
|
|
return val
|
|
}
|
|
|
|
// HasInvolved whether this item is buffered
|
|
// and will be Reset on putting back.
|
|
func (b *Item[T]) HasInvolved() bool {
|
|
if b.pool.issync {
|
|
if !b.stat.setinsyncop(true) && getGoroutineID() != b.id {
|
|
panic("non-unique op")
|
|
}
|
|
atomic.StoreInt64(&b.id, getGoroutineID())
|
|
defer b.stat.setinsyncop(false)
|
|
}
|
|
return b.stat.isbuffered()
|
|
}
|
|
|
|
// V use value of the item.
|
|
//
|
|
// This operation is safe in function f.
|
|
func (b *Item[T]) V(f func(T)) *Item[T] {
|
|
if b.stat.hasdestroyed() {
|
|
panic("use after destroy")
|
|
}
|
|
if b.pool.issync {
|
|
if !b.stat.setinsyncop(true) && getGoroutineID() != b.id {
|
|
panic("non-unique op")
|
|
}
|
|
atomic.StoreInt64(&b.id, getGoroutineID())
|
|
defer b.stat.setinsyncop(false)
|
|
}
|
|
f(b.val)
|
|
runtime.KeepAlive(b)
|
|
return b
|
|
}
|
|
|
|
// P use pointer value of the item.
|
|
//
|
|
// This operation is safe in function f.
|
|
func (b *Item[T]) P(f func(*T)) *Item[T] {
|
|
if b.stat.hasdestroyed() {
|
|
panic("use after destroy")
|
|
}
|
|
if b.pool.issync {
|
|
if !b.stat.setinsyncop(true) && getGoroutineID() != b.id {
|
|
panic("non-unique op")
|
|
}
|
|
atomic.StoreInt64(&b.id, getGoroutineID())
|
|
defer b.stat.setinsyncop(false)
|
|
}
|
|
f(&b.val)
|
|
runtime.KeepAlive(b)
|
|
return b
|
|
}
|
|
|
|
// Copy data completely with separated ownership.
|
|
func (b *Item[T]) Copy() (cb *Item[T]) {
|
|
if b.stat.hasdestroyed() {
|
|
panic("use after destroy")
|
|
}
|
|
if b.pool.issync {
|
|
if !b.stat.setinsyncop(true) && getGoroutineID() != b.id {
|
|
panic("non-unique op")
|
|
}
|
|
atomic.StoreInt64(&b.id, getGoroutineID())
|
|
defer b.stat.setinsyncop(false)
|
|
}
|
|
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("destroy after destroy")
|
|
case stat.isbuffered():
|
|
b.pool.pooler.Reset(&b.val)
|
|
default:
|
|
var v T
|
|
b.val = v
|
|
}
|
|
b.pool.put(b, stat.hasignored())
|
|
}
|
|
|
|
// ManualDestroy item and put it back to pool.
|
|
//
|
|
// Calling this method only when you're sure that
|
|
// no one will use it, or it will cause a panic.
|
|
func (b *Item[T]) ManualDestroy() {
|
|
if b.pool.issync {
|
|
b.stat.setinsyncop(true)
|
|
}
|
|
runtime.SetFinalizer(b, nil)
|
|
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.
|
|
item.destroybystat(item.stat)
|
|
})
|
|
return b
|
|
}
|