Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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()
      }
    }
  }
like image 623
irishjava Avatar asked Apr 30 '13 16:04

irishjava


1 Answers

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)
like image 137
Ramón J Romero y Vigil Avatar answered Sep 23 '22 12:09

Ramón J Romero y Vigil