Skip to content

Instantly share code, notes, and snippets.

@jonhull
Created January 31, 2017 23:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonhull/b9cd8a50abca16ea49eade2c91edf8a2 to your computer and use it in GitHub Desktop.
Save jonhull/b9cd8a50abca16ea49eade2c91edf8a2 to your computer and use it in GitHub Desktop.
public final class Source<T>:SourceProtocol, ExpressibleByArrayLiteral,Collection {
public typealias Element = T
private let box:_sourceBoxBase<T>
public init<P:SourceProtocol>(_ base:P) where P.Element == T {
self.box = _sourceBox(base)
}
public init(_ constant:T) {
self.box = _sourceBox(ConstantSource(constant))
}
public init(_ ordered:[T]) {
if ordered.count == 1 {
self.box = _sourceBox(ConstantSource(ordered[0]))
}else{
self.box = _sourceBox(OrderedSource(ordered))
}
}
public init(random array: [T], repeatAfter:Int = Int(Int32.max), seed:UInt32 = arc4random_uniform(UInt32.max)){
self.box = _sourceBox(RandomOrderedSource(array, repeatAfter: repeatAfter, seed: seed))
}
public init(_ meta:[Source<T>]) {
self.box = _sourceBox(MetaSource(meta))
}
public init(arrayLiteral elements: T...) {
if elements.count == 1 {
self.box = _sourceBox(ConstantSource(elements[0]))
}else{
self.box = _sourceBox(OrderedSource(elements))
}
}
public var count: Int {return self.box.count}
public subscript(index: Int) -> T {return self.box[index]}
var isConstant:Bool {return self.box.count == 1}
//Collection
public typealias Index = Int
public var startIndex:Index { return 0 }
public var endIndex:Index { return self.count}
public func index(after i: Index) -> Index {return i + 1}
}
extension Source where T:RandomSourceCreatable {
convenience init(_ rnd:RandomSource<T>) {
self.init(RandomBoundedSource(rnd))
}
convenience init(from:T.ConstraintType, to:T.ConstraintType? = nil, repeatAfter:Int? = nil, seed:UInt32 = arc4random_uniform(UInt32.max)) {
let rnd:RandomSource<T> = RandomSource(seed: seed, count: repeatAfter, from: from, to: to)
self.init(RandomBoundedSource(rnd))
}
convenience init(to:T.ConstraintType, repeatAfter:Int? = nil, seed:UInt32 = arc4random_uniform(UInt32.max)) {
let rnd:RandomSource<T> = RandomSource(seed: seed, count: repeatAfter, to: to)
self.init(RandomBoundedSource(rnd))
}
}
//MARK: - Type Erasure
class _sourceBoxBase<T>:SourceProtocol {
typealias Element = T
var count:Int {return 0}
subscript(index:Int) -> Element {fatalError()}
}
class _sourceBox<P:SourceProtocol>:_sourceBoxBase<P.Element> {
let base:P
init(_ base: P) {
self.base = base
}
override var count:Int {return self.base.count}
override subscript(index:Int) -> Element {return self.base[index]}
}
//MARK: - Protocol
public protocol SourceProtocol {
associatedtype Element
var count:Int {get}
subscript(index:Int) -> Element {get}
}
//MARK: - Implimentations
private struct ConstantSource<T>:SourceProtocol {
public typealias Element = T
private let element:Element
init(_ element:Element) {
self.element = element
}
public subscript(index: Int) -> T {
return self.element
}
public var count: Int {
return 1
}
}
private struct OrderedSource<T>:SourceProtocol {
public typealias Element = T
private let components:[T]
init(_ components:[T]) {
self.components = components
}
public subscript(index: Int) -> T {
return self.components[index % components.count]
}
public var count: Int {
return self.components.count
}
}
private struct RandomOrderedSource<T>:SourceProtocol {
public typealias Element = T
private let components:[T]
private let randomSource:RandomSource<UInt32>
init(_ array: [T], repeatAfter:Int = Int(UInt32.max), seed:UInt32 = arc4random_uniform(UInt32.max)) {
self.components = array
self.randomSource = RandomSource<UInt32>(seed: seed, count: repeatAfter, to: UInt32(array.count))
}
public subscript(index:Int) -> T {
return components[Int(randomSource[index % randomSource.count]) % components.count]
}
public var count: Int {
return self.components.count
}
}
private struct RandomBoundedSource<T:RandomSourceCreatable>:SourceProtocol {
public typealias Element = T
private let randomSource:RandomSource<T>
init(_ rnd:RandomSource<T>) {
self.randomSource = rnd
}
public var count: Int {
return self.randomSource.count
}
public subscript(index:Int) -> T {
return self.randomSource[index]
}
}
private struct MetaSource<T>:SourceProtocol {
public typealias Element = T
private let sources:[Source<T>]
init(_ meta:[Source<T>]) {
self.sources = meta
}
public var count: Int {
return self.sources.count
}
//Goes through each source in order, then goes through again with index 1, etc...
public subscript(index:Int) -> T {
let cnt = self.sources.count
let offset = index / cnt
return self.sources[index % cnt][offset]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment