123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- /*
- * Public Domain Software
- *
- * I (Matthias Ladkau) am the author of the source code in this file.
- * I have placed the source code in this file in the public domain.
- *
- * For further information see: http://creativecommons.org/publicdomain/zero/1.0/
- */
- /*
- Package datautil contains general data handling objects and helper methods.
- */
- package datautil
- import (
- "fmt"
- "strings"
- "sync"
- )
- /*
- RingBuffer is a classic thread-safe ringbuffer implementation. It stores
- abstract interface{} objects. It has specific methods so it can be used as
- a print logger.
- */
- type RingBuffer struct {
- data []interface{} // Elements of this ring buffer
- size int // Size of the ring buffer
- first int // First item of the ring buffer
- last int // Last item of the ring buffer
- modCount int // Check for modifications during iterations
- lock *sync.RWMutex // Lock for RingBuffer
- }
- /*
- NewRingBuffer creates a new ringbuffer with a given size.
- */
- func NewRingBuffer(size int) *RingBuffer {
- return &RingBuffer{make([]interface{}, size), 0, 0, 0, 0, &sync.RWMutex{}}
- }
- /*
- Reset removes all content from the ringbuffer.
- */
- func (rb *RingBuffer) Reset() {
- rb.lock.Lock()
- defer rb.lock.Unlock()
- rb.data = make([]interface{}, cap(rb.data))
- rb.size = 0
- rb.first = 0
- rb.last = 0
- rb.modCount = 0
- }
- /*
- IsEmpty returns if this ringbuffer is empty.
- */
- func (rb *RingBuffer) IsEmpty() bool {
- rb.lock.RLock()
- defer rb.lock.RUnlock()
- return rb.size == 0
- }
- /*
- Size returns the size of the ringbuffer.
- */
- func (rb *RingBuffer) Size() int {
- rb.lock.RLock()
- defer rb.lock.RUnlock()
- return rb.size
- }
- /*
- Get returns an element of the ringbuffer from a given position.
- */
- func (rb *RingBuffer) Get(p int) interface{} {
- rb.lock.RLock()
- defer rb.lock.RUnlock()
- return rb.data[(rb.first+p)%len(rb.data)]
- }
- /*
- Add adds an item to the ringbuffer.
- */
- func (rb *RingBuffer) Add(e interface{}) {
- rb.lock.Lock()
- defer rb.lock.Unlock()
- ld := len(rb.data)
- rb.data[rb.last] = e
- rb.last = (rb.last + 1) % ld
- if rb.size == ld {
- rb.first = (rb.first + 1) % ld
- } else {
- rb.size++
- }
- rb.modCount++
- }
- /*
- Poll removes and returns the head of the ringbuffer.
- */
- func (rb *RingBuffer) Poll() interface{} {
- rb.lock.Lock()
- defer rb.lock.Unlock()
- if rb.size == 0 {
- return nil
- }
- i := rb.data[rb.first]
- rb.data[rb.first] = nil
- rb.size--
- rb.first = (rb.first + 1) % len(rb.data)
- rb.modCount++
- return i
- }
- /*
- Log writes the given arguments as strings into the ring buffer. Each line is a
- separate item.
- */
- func (rb *RingBuffer) Log(v ...interface{}) {
- lines := strings.Split(fmt.Sprint(v...), "\n")
- for _, line := range lines {
- rb.Add(line)
- }
- }
- /*
- Slice returns the contents of the buffer as a slice.
- */
- func (rb *RingBuffer) Slice() []interface{} {
- rb.lock.RLock()
- defer rb.lock.RUnlock()
- ld := len(rb.data)
- ret := make([]interface{}, rb.size)
- for i := 0; i < rb.size; i++ {
- ret[i] = rb.data[(i+rb.first)%ld]
- }
- return ret
- }
- /*
- StringSlice returns the contents of the buffer as a slice of strings.
- Each item of the buffer is a separate string.
- */
- func (rb *RingBuffer) StringSlice() []string {
- rb.lock.RLock()
- defer rb.lock.RUnlock()
- ld := len(rb.data)
- ret := make([]string, rb.size)
- for i := 0; i < rb.size; i++ {
- ret[i] = fmt.Sprint(rb.data[(i+rb.first)%ld])
- }
- return ret
- }
- /*
- String retusn the contents of the buffer as a string. Each item of the buffer is
- treated as a separate line.
- */
- func (rb *RingBuffer) String() string {
- return strings.Join(rb.StringSlice(), "\n")
- }
|