irishjava
irishjava

Reputation: 503

scala collections circular buffer

Just messing about here, with circular buffers. Is this a sensible implementation or is there a faster/more reliable way to skin this cat?

class CircularBuffer[T](size: Int)(implicit mf: Manifest[T]) {

    private val arr = new scala.collection.mutable.ArrayBuffer[T]()

    private var cursor = 0

    val monitor = new ReentrantReadWriteLock()

    def push(value: T) {
      monitor.writeLock().lock()
      try {
        arr(cursor) = value
        cursor += 1
        cursor %= size
      } finally {
        monitor.writeLock().unlock()
      }
    }

    def getAll: Array[T] = {
      monitor.readLock().lock()
      try {
        val copy = new Array[T](size)
        arr.copyToArray(copy)
        copy
      } finally {
        monitor.readLock().unlock()
      }
    }
  }

Upvotes: 7

Views: 5586

Answers (1)

Creation

A type declaration to an existing scala collection class and an appender function is easier to implement than "rolling your own". As noted in the comments this implementation will likely not be as performant as a "true" circular buffer, but it gets the job done with very little coding:

import scala.collection.immutable

type CircularBuffer[T] = immutable.Vector[T]

def emptyCircularBuffer[T] : CircularBuffer[T] = immutable.Vector.empty[T]

def addToCircularBuffer[T](maxSize : Int)(buffer : CircularBuffer[T], item : T) : CircularBuffer[T]  =
  (buffer :+ item) takeRight maxSize

This means that your "CircularBuffer" is actually a Vector and you now get all of the corresponding Vector methods (filter, map, flatMap, etc...) for free:

var intCircularBuffer = emptyCircularBuffer[Int]

//Vector(41)
intCircularBuffer = addToCircularBuffer(2)(intCircularBuffer, 41)

//Vector(41, 42)
intCircularBuffer = addToCircularBuffer(2)(intCircularBuffer, 42)

//Vector(42, 43)
intCircularBuffer = addToCircularBuffer(2)(intCircularBuffer, 43)

//Vector(42)
val evens : CircularBuffer[Int] = intCircularBuffer filter ( _ % 2 == 0)

Indexing

You can similarly add a function for circular indexing:

def circularIndex[T](buffer : CircularBuffer[T])(index : Int) : T = 
  buffer(index % buffer.size)

Upvotes: 6

Related Questions