Skip to content

Instantly share code, notes, and snippets.

@erneestoc
Created April 11, 2015 22:43
Show Gist options
  • Save erneestoc/8f9f8f339829313f338e to your computer and use it in GitHub Desktop.
Save erneestoc/8f9f8f339829313f338e to your computer and use it in GitHub Desktop.
/* Circular Buffer
* original by rayfix @ https://gist.github.com/rayfix/1fb467981e386ad5797e
* added getting and previewing next and previous objects.
*/
import UIKit
public struct RingGenerator<T> : GeneratorType {
public mutating func next() -> T? {
if remainingCount > 0 {
let value = buffer[index%buffer.count]
--remainingCount
++index
return value
} else {
index = 0
let value = buffer[index]
remainingCount = count(buffer)
return next()
}
}
public mutating func nextPreview() -> T? {
if remainingCount > 0 {
let value = buffer[(index+1)%buffer.count]
return value
} else {
let value = buffer[0]
return value
}
}
public mutating func current() -> T? {
return buffer[index%buffer.count]
}
public mutating func prev() -> T? {
if index > 0 {
--index
let value = buffer[index % buffer.count]
++remainingCount
return value
} else {
index = buffer.count
--index
let value = buffer[index]
++remainingCount
return value
}
}
public mutating func prevObject() -> T? {
if index != 0 {
let value = buffer[(index-1)%buffer.count]
return value
} else {
let value = buffer[buffer.count-1]
return value
}
}
private init(_ ring:Ring<T>!) {
buffer = ring.buffer
remainingCount = ring.storedCount
index = (ring.count-remainingCount) % ring.capacity
}
private let buffer:[T]
private var index:Int
private var remainingCount:Int
}
/// A ring keeps track of the last n objects where n is set
/// using capacity. The ring can be iterated on in LIFO
/// order.
public class Ring<T> : SequenceType {
/// Where the buffer is stored.
final private var buffer:[T] = []
/// The total number of times add() has been called since
/// init or the last reset.
public private(set) var count:Int = 0
/// The number of objects this ring can store.
public let capacity:Int
/// The number of objects store in the ring.
public var storedCount:Int {
return min(count, capacity)
}
/// Create an empty ring with the specified capacity
/// @requires capacity must be > 0
public init(capacity cap:Int) {
assert(cap > 0)
capacity = cap
}
/// Add value to the ring.
public func add(value:T) {
if !isFull {
buffer.append(value)
}
else {
buffer[count % buffer.count] = value
}
++count
}
/// The value that will be removed when a new values is
/// added to the ring.
public var willRemoveValue:T? {
if isFull {
let index = (count-storedCount) % capacity
return buffer[index]
}
return nil
}
/// Set the storedCount to zero.
public func reset() {
count = 0
buffer = []
}
/// Return true if the ring is empty
public var isEmpty:Bool {
return count == 0
}
/// Return true if the ring is full and newly added values will bump out old ones.
public var isFull:Bool {
return count >= capacity
}
/// Allow iteration from oldest to newest value.
public func generate() -> RingGenerator<T> {
return RingGenerator(self)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment