Created
April 11, 2015 22:43
-
-
Save erneestoc/8f9f8f339829313f338e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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