Files
2026-07-13 12:49:10 +08:00

135 lines
2.3 KiB
Go

/*
* Copyright 2025 CloudWeGo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package adk
import "sync"
type turnBuffer[T any] struct {
buf []T
mu sync.Mutex
notEmpty *sync.Cond
closed bool
woken bool
}
func newTurnBuffer[T any]() *turnBuffer[T] {
tb := &turnBuffer[T]{}
tb.notEmpty = sync.NewCond(&tb.mu)
return tb
}
func (tb *turnBuffer[T]) Send(value T) {
tb.mu.Lock()
defer tb.mu.Unlock()
if tb.closed {
panic("turnBuffer: send on closed buffer")
}
tb.buf = append(tb.buf, value)
tb.notEmpty.Signal()
}
func (tb *turnBuffer[T]) TrySend(value T) bool {
tb.mu.Lock()
defer tb.mu.Unlock()
if tb.closed {
return false
}
tb.buf = append(tb.buf, value)
tb.notEmpty.Signal()
return true
}
func (tb *turnBuffer[T]) Receive() (T, bool) {
tb.mu.Lock()
defer tb.mu.Unlock()
for len(tb.buf) == 0 && !tb.closed && !tb.woken {
tb.notEmpty.Wait()
}
tb.woken = false
if len(tb.buf) == 0 {
var zero T
return zero, false
}
val := tb.buf[0]
tb.buf = tb.buf[1:]
return val, true
}
func (tb *turnBuffer[T]) Close() {
tb.mu.Lock()
defer tb.mu.Unlock()
if !tb.closed {
tb.closed = true
tb.notEmpty.Broadcast()
}
}
func (tb *turnBuffer[T]) IsClosed() bool {
tb.mu.Lock()
defer tb.mu.Unlock()
return tb.closed
}
func (tb *turnBuffer[T]) TakeAll() []T {
tb.mu.Lock()
defer tb.mu.Unlock()
if len(tb.buf) == 0 {
return nil
}
values := tb.buf
tb.buf = nil
return values
}
func (tb *turnBuffer[T]) PushFront(values []T) {
if len(values) == 0 {
return
}
tb.mu.Lock()
defer tb.mu.Unlock()
tb.buf = append(append([]T{}, values...), tb.buf...)
tb.notEmpty.Signal()
}
func (tb *turnBuffer[T]) Wakeup() {
tb.mu.Lock()
defer tb.mu.Unlock()
tb.woken = true
tb.notEmpty.Broadcast()
}
func (tb *turnBuffer[T]) ClearWakeup() {
tb.mu.Lock()
defer tb.mu.Unlock()
tb.woken = false
}