Created
January 31, 2017 23:44
-
-
Save jonhull/b9cd8a50abca16ea49eade2c91edf8a2 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
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