ringbuffer.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * Public Domain Software
  3. *
  4. * I (Matthias Ladkau) am the author of the source code in this file.
  5. * I have placed the source code in this file in the public domain.
  6. *
  7. * For further information see: http://creativecommons.org/publicdomain/zero/1.0/
  8. */
  9. /*
  10. Package datautil contains general data handling objects and helper methods.
  11. */
  12. package datautil
  13. import (
  14. "fmt"
  15. "strings"
  16. "sync"
  17. )
  18. /*
  19. RingBuffer is a classic thread-safe ringbuffer implementation. It stores
  20. abstract interface{} objects. It has specific methods so it can be used as
  21. a print logger.
  22. */
  23. type RingBuffer struct {
  24. data []interface{} // Elements of this ring buffer
  25. size int // Size of the ring buffer
  26. first int // First item of the ring buffer
  27. last int // Last item of the ring buffer
  28. modCount int // Check for modifications during iterations
  29. lock *sync.RWMutex // Lock for RingBuffer
  30. }
  31. /*
  32. NewRingBuffer creates a new ringbuffer with a given size.
  33. */
  34. func NewRingBuffer(size int) *RingBuffer {
  35. return &RingBuffer{make([]interface{}, size), 0, 0, 0, 0, &sync.RWMutex{}}
  36. }
  37. /*
  38. Reset removes all content from the ringbuffer.
  39. */
  40. func (rb *RingBuffer) Reset() {
  41. rb.lock.Lock()
  42. defer rb.lock.Unlock()
  43. rb.data = make([]interface{}, cap(rb.data))
  44. rb.size = 0
  45. rb.first = 0
  46. rb.last = 0
  47. rb.modCount = 0
  48. }
  49. /*
  50. IsEmpty returns if this ringbuffer is empty.
  51. */
  52. func (rb *RingBuffer) IsEmpty() bool {
  53. rb.lock.RLock()
  54. defer rb.lock.RUnlock()
  55. return rb.size == 0
  56. }
  57. /*
  58. Size returns the size of the ringbuffer.
  59. */
  60. func (rb *RingBuffer) Size() int {
  61. rb.lock.RLock()
  62. defer rb.lock.RUnlock()
  63. return rb.size
  64. }
  65. /*
  66. Get returns an element of the ringbuffer from a given position.
  67. */
  68. func (rb *RingBuffer) Get(p int) interface{} {
  69. rb.lock.RLock()
  70. defer rb.lock.RUnlock()
  71. return rb.data[(rb.first+p)%len(rb.data)]
  72. }
  73. /*
  74. Add adds an item to the ringbuffer.
  75. */
  76. func (rb *RingBuffer) Add(e interface{}) {
  77. rb.lock.Lock()
  78. defer rb.lock.Unlock()
  79. ld := len(rb.data)
  80. rb.data[rb.last] = e
  81. rb.last = (rb.last + 1) % ld
  82. if rb.size == ld {
  83. rb.first = (rb.first + 1) % ld
  84. } else {
  85. rb.size++
  86. }
  87. rb.modCount++
  88. }
  89. /*
  90. Poll removes and returns the head of the ringbuffer.
  91. */
  92. func (rb *RingBuffer) Poll() interface{} {
  93. rb.lock.Lock()
  94. defer rb.lock.Unlock()
  95. if rb.size == 0 {
  96. return nil
  97. }
  98. i := rb.data[rb.first]
  99. rb.data[rb.first] = nil
  100. rb.size--
  101. rb.first = (rb.first + 1) % len(rb.data)
  102. rb.modCount++
  103. return i
  104. }
  105. /*
  106. Log writes the given arguments as strings into the ring buffer. Each line is a
  107. separate item.
  108. */
  109. func (rb *RingBuffer) Log(v ...interface{}) {
  110. lines := strings.Split(fmt.Sprint(v...), "\n")
  111. for _, line := range lines {
  112. rb.Add(line)
  113. }
  114. }
  115. /*
  116. Slice returns the contents of the buffer as a slice.
  117. */
  118. func (rb *RingBuffer) Slice() []interface{} {
  119. rb.lock.RLock()
  120. defer rb.lock.RUnlock()
  121. ld := len(rb.data)
  122. ret := make([]interface{}, rb.size)
  123. for i := 0; i < rb.size; i++ {
  124. ret[i] = rb.data[(i+rb.first)%ld]
  125. }
  126. return ret
  127. }
  128. /*
  129. StringSlice returns the contents of the buffer as a slice of strings.
  130. Each item of the buffer is a separate string.
  131. */
  132. func (rb *RingBuffer) StringSlice() []string {
  133. rb.lock.RLock()
  134. defer rb.lock.RUnlock()
  135. ld := len(rb.data)
  136. ret := make([]string, rb.size)
  137. for i := 0; i < rb.size; i++ {
  138. ret[i] = fmt.Sprint(rb.data[(i+rb.first)%ld])
  139. }
  140. return ret
  141. }
  142. /*
  143. String retusn the contents of the buffer as a string. Each item of the buffer is
  144. treated as a separate line.
  145. */
  146. func (rb *RingBuffer) String() string {
  147. return strings.Join(rb.StringSlice(), "\n")
  148. }