circbuf.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. package circbuf
  2. import (
  3. "fmt"
  4. )
  5. // Buffer implements a circular buffer. It is a fixed size,
  6. // and new writes overwrite older data, such that for a buffer
  7. // of size N, for any amount of writes, only the last N bytes
  8. // are retained.
  9. type Buffer struct {
  10. data []byte
  11. size int64
  12. writeCursor int64
  13. written int64
  14. }
  15. // NewBuffer creates a new buffer of a given size. The size
  16. // must be greater than 0.
  17. func NewBuffer(size int64) (*Buffer, error) {
  18. if size <= 0 {
  19. return nil, fmt.Errorf("Size must be positive")
  20. }
  21. b := &Buffer{
  22. size: size,
  23. data: make([]byte, size),
  24. }
  25. return b, nil
  26. }
  27. // Write writes up to len(buf) bytes to the internal ring,
  28. // overriding older data if necessary.
  29. func (b *Buffer) Write(buf []byte) (int, error) {
  30. // Account for total bytes written
  31. n := len(buf)
  32. b.written += int64(n)
  33. // If the buffer is larger than ours, then we only care
  34. // about the last size bytes anyways
  35. if int64(n) > b.size {
  36. buf = buf[int64(n)-b.size:]
  37. }
  38. // Copy in place
  39. remain := b.size - b.writeCursor
  40. copy(b.data[b.writeCursor:], buf)
  41. if int64(len(buf)) > remain {
  42. copy(b.data, buf[remain:])
  43. }
  44. // Update location of the cursor
  45. b.writeCursor = ((b.writeCursor + int64(len(buf))) % b.size)
  46. return n, nil
  47. }
  48. // Size returns the size of the buffer
  49. func (b *Buffer) Size() int64 {
  50. return b.size
  51. }
  52. // TotalWritten provides the total number of bytes written
  53. func (b *Buffer) TotalWritten() int64 {
  54. return b.written
  55. }
  56. // Bytes provides a slice of the bytes written. This
  57. // slice should not be written to.
  58. func (b *Buffer) Bytes() []byte {
  59. switch {
  60. case b.written >= b.size && b.writeCursor == 0:
  61. return b.data
  62. case b.written > b.size:
  63. out := make([]byte, b.size)
  64. copy(out, b.data[b.writeCursor:])
  65. copy(out[b.size-b.writeCursor:], b.data[:b.writeCursor])
  66. return out
  67. default:
  68. return b.data[:b.writeCursor]
  69. }
  70. }
  71. // Reset resets the buffer so it has no content.
  72. func (b *Buffer) Reset() {
  73. b.writeCursor = 0
  74. b.written = 0
  75. }
  76. // String returns the contents of the buffer as a string
  77. func (b *Buffer) String() string {
  78. return string(b.Bytes())
  79. }