code.dwrz.net

Go monorepo.
Log | Files | Refs

ringbuffer.go (2124B)


      1 package io
      2 
      3 import (
      4 	"bytes"
      5 	"io"
      6 )
      7 
      8 // RingBuffer struct satisfies io.ReadWrite interface.
      9 //
     10 // ReadBuffer is a revolving buffer data structure, which can be used to store snapshots of data in a
     11 // revolving window.
     12 type RingBuffer struct {
     13 	slice []byte
     14 	start int
     15 	end   int
     16 	size  int
     17 }
     18 
     19 // NewRingBuffer method takes in a byte slice as an input and returns a RingBuffer.
     20 func NewRingBuffer(slice []byte) *RingBuffer {
     21 	ringBuf := RingBuffer{
     22 		slice: slice,
     23 	}
     24 	return &ringBuf
     25 }
     26 
     27 // Write method inserts the elements in a byte slice, and returns the number of bytes written along with any error.
     28 func (r *RingBuffer) Write(p []byte) (int, error) {
     29 	for _, b := range p {
     30 		// check if end points to invalid index, we need to circle back
     31 		if r.end == len(r.slice) {
     32 			r.end = 0
     33 		}
     34 		// check if start points to invalid index, we need to circle back
     35 		if r.start == len(r.slice) {
     36 			r.start = 0
     37 		}
     38 		// if ring buffer is filled, increment the start index
     39 		if r.size == len(r.slice) {
     40 			r.size--
     41 			r.start++
     42 		}
     43 
     44 		r.slice[r.end] = b
     45 		r.end++
     46 		r.size++
     47 	}
     48 	return len(p), nil
     49 }
     50 
     51 // Read copies the data on the ring buffer into the byte slice provided to the method.
     52 // Returns the read count along with any error encountered while reading.
     53 func (r *RingBuffer) Read(p []byte) (int, error) {
     54 	// readCount keeps track of the number of bytes read
     55 	var readCount int
     56 	for j := 0; j < len(p); j++ {
     57 		// if ring buffer is empty or completely read
     58 		// return EOF error.
     59 		if r.size == 0 {
     60 			return readCount, io.EOF
     61 		}
     62 
     63 		if r.start == len(r.slice) {
     64 			r.start = 0
     65 		}
     66 
     67 		p[j] = r.slice[r.start]
     68 		readCount++
     69 		// increment the start pointer for ring buffer
     70 		r.start++
     71 		// decrement the size of ring buffer
     72 		r.size--
     73 	}
     74 	return readCount, nil
     75 }
     76 
     77 // Len returns the number of unread bytes in the buffer.
     78 func (r *RingBuffer) Len() int {
     79 	return r.size
     80 }
     81 
     82 // Bytes returns a copy of the RingBuffer's bytes.
     83 func (r RingBuffer) Bytes() []byte {
     84 	var b bytes.Buffer
     85 	io.Copy(&b, &r)
     86 	return b.Bytes()
     87 }
     88 
     89 // Reset resets the ring buffer.
     90 func (r *RingBuffer) Reset() {
     91 	*r = RingBuffer{
     92 		slice: r.slice,
     93 	}
     94 }