Proper implementation of Sequence Protocol in a Class - swift

I have been working on learning something about the Accelerate framework and am writing a Vector class to go along with my learning experience. I decided I needed to implement the Sequence protocol and after several false starts and much searching for relevant information to my problem finally came up with a solution that seems to work. Not sure if my solution is proper or not and would like comment if there are better ways to do this. Current code is a bit long but not super long so I will post it here.
import Foundation
import Accelerate
public class Vdsp{
public class VectorD: Sequence, IteratorProtocol {
var vindex = 0
public func makeIterator() -> Double? {
return next()
}
public func next() -> Double? {
let nextIndex = self.vindex * self.s + self.o
guard self.vindex < self.l && nextIndex < self.count
else {
self.vindex = 0
return nil
}
self.vindex += 1
return self.data[nextIndex]
}
public let count : Int
fileprivate var l: Int
fileprivate var o: Int
fileprivate var s: Int
public var length : Int {
get {
return self.l
}
set (value){
let l = (value - 1) * self.s + self.o
if l < 0 || l >= self.count {
preconditionFailure("length exceeds vector boundary")
}
self.l = value
}
}
public var stride : Int {
get {
return self.s
}
set (value){
let l = (self.l - 1) * value + self.o
if l < 0 || l >= self.count {
preconditionFailure("stride will cause vector to exceed vector boundary")
}
self.s = value
}
}
public var offset : Int {
get {
return self.o
}
set (value){
let l = (self.l - 1) * self.s + value
if l < 0 || l >= self.count {
preconditionFailure("stride will cause vector to exceed vector boundary")
}
self.o = value
}
}
// length * stride + offset >= 0 and <= count
public var data : Array<Double>
public init(length: Int){
self.count = length
self.l = length
self.s = 1
self.o = 0
data = Array(repeating: 0.0, count: count)
}
// MARK: - Utility functions
public var empty : VectorD { // Create a new vector unit stride, zero offset
get{
return VectorD(length: length)
}
}
public func display(decimals: Int) -> String {
let fmt = String("%0." + String(decimals) + "f\n")
var aString = ""
for i in 0..<length {
aString += String(format: fmt!, self.data[offset + i * stride])
}
return aString
}
// MARK: - Subscripts and Operators
public subscript(index: Int) -> Double {
get {
if index > length {
preconditionFailure("index \(index) out of bounds")
} else {
return data[self.offset + index * self.stride]
}
}
set(newValue) {
if index > self.length {
preconditionFailure("index \(index) out of bounds")
} else {
self.data[self.offset + index * self.stride] = newValue
}
}
}
public static func + (left: VectorD, right: VectorD) -> VectorD {
return Vdsp.add(left, right)
}
public static func + (left: Double, right: VectorD) -> VectorD {
return Vdsp.add(left, right)
}
public static func + (left: VectorD, right: Double) -> VectorD {
return Vdsp.add(right, left)
}
public static func * (left: VectorD, right: VectorD) -> VectorD {
return Vdsp.mul(left, right)
}
public static func * (left: Double, right: VectorD) -> VectorD {
return Vdsp.mul(left, right)
}
public static func * (left: VectorD, right: Double) -> VectorD {
return Vdsp.mul(right, left)
}
// MARK: - vDSP routines as methods of VectorD
public func fill(value: Double){
var v = value
vDSP_vfillD(&v, &data + offset, stride, vDSP_Length(length))
}
public func ramp(start: Double, increment: Double){
var s = start
var i = increment
vDSP_vrampD(&s, &i, &data + offset, stride, vDSP_Length(length))
}
public var sumval : Double {
get {
var s : Double = 0.0
vDSP_sveD(&data + offset, stride, &s, vDSP_Length(length))
return s
}
}
}
// MARK: - vDSP routines as class functions of Vdsp
public static func add(_ v1: VectorD, _ v2: VectorD) -> VectorD {
let v3 = v1.empty
vDSP_vaddD( &v1.data + v1.offset, v1.stride, &v2.data + v2.offset , v2.stride, &v3.data, 1, vDSP_Length(v3.length))
return v3
}
public static func add(_ s: Double, _ v: VectorD) -> VectorD {
var sdta = s
let r = v.empty
vDSP_vsaddD( &v.data + v.offset, v.stride, &sdta, &r.data, 1, vDSP_Length(v.length))
return r
}
public static func mul(_ v1: VectorD, _ v2: VectorD) -> VectorD {
let v3 = v1.empty
vDSP_vmulD( &v1.data + v1.offset, v1.stride, &v2.data + v2.offset, v2.stride, &v3.data, 1, vDSP_Length(v3.length))
return v3
}
public static func mul(_ s: Double, _ v: VectorD) -> VectorD {
var sdta = s
let r = v.empty
vDSP_vsmulD( &v.data + v.offset, v.stride, &sdta, &r.data, 1, vDSP_Length(v.length))
return r
}
}
I am exercising this with
//: Playground for Accelerate
import UIKit
let V = Vdsp.VectorD(length: 10);V.ramp(start: 0.1, increment: 0.2)
print("Vector V after ramp(0.1,0.2)");print(V.display(decimals: 3))
V.length = 4
V.stride = 2
V.offset = 1
print("Vector V after attribute modification")
print(V.display(decimals: 3))
let Q = V.empty
Q.ramp(start: 1.0, increment: 1.0)
print("Vector Q after ramp(1.0,1.0)");print(Q.display(decimals: 3))
print("V * Q"); var R = V * Q
for i in 0..<V.length {
print("\(V[i]) * \(Q[i]) = \(R[i])")
}
R = V + Q; print("V + Q = R")
for i in 0..<V.length {
print("\(V[i]) + \(Q[i]) = \(R[i])")
}
print("\n")
for item in V.data {
print(item)
}
print("\n")
for item in V {
print(item)
}
print("\n")
V.offset = 3
for item in V {
print(item)
}
and I seem to get the proper output. The Sequence protocol is in the first few lines of the VectorD class.

Your implementation of the Sequence protocol is not correct.
First, your makeIterator() method is not used at all because it has the wrong signature,
it does not return an Iterator. (You can remove that function from your code without changing anything.) Iterating over the vector elements works
because there is a default implementation of makeIterator() for all
iterators which are declared to conform to Sequence.
Second, your next() method uses an instance variable vindex
which is reset to zero after reaching the end of the iteration.
In other words, it is assumed that all elements are retrieved before
iterating the same vector again. This gives the unexpected output:
let V = Vdsp.VectorD(length: 10)
V.ramp(start: 1.0, increment: 1.0)
print(Array(V.prefix(4))) // [1.0, 2.0, 3.0, 4.0]
print(Array(V.prefix(4))) // [5.0, 6.0, 7.0, 8.0]
print(Array(V.prefix(4))) // [9.0, 10.0]
print(Array(V.prefix(4))) // [1.0, 2.0, 3.0, 4.0]
Here is a possible implementation of the Sequence protocol:
public class VectorD: Sequence {
public func makeIterator() -> AnyIterator<Double> {
var vindex = 0
return AnyIterator {
let nextIndex = vindex * self.s + self.o
guard vindex < self.l && nextIndex < self.count else {
return nil
}
vindex += 1
return self.data[nextIndex]
}
}
// ...
}
Note that vindex is now a local variable of makeIterator()
and captured by the closure. Calling makeIterator() again
will start from the beginning even if the previous iteration did
not retrieve all elements:
print(Array(V.prefix(4))) // [1.0, 2.0, 3.0, 4.0]
print(Array(V.prefix(4))) // [1.0, 2.0, 3.0, 4.0]
Another possible implementation would be
public class VectorD: Sequence {
public func makeIterator() -> AnyIterator<Double> {
let upperBound = Swift.min(count, o + l * s)
let it = Swift.stride(from: o, to: upperBound, by: s)
.lazy.map { self.data[$0] }.makeIterator()
return AnyIterator(it)
}
// ...
}
using the stride() method from the Swift standard
library.

Related

Convert into generic function

I am writing an iOS app in Swift. My class has below functions for reading bytebuffer. Below all functions do same task but work on different number types. So, how to convert these functions into a single function using generics?
var array = [UInt8]()
private var currentIndex: Int = 0
private let hostEndianness: Endianness = OSHostByteOrder() == OSLittleEndian ? .little : .big
private var currentEndianness: Endianness = .big
public func getUInt16() -> UInt16 {
let check=(currentIndex + MemoryLayout<UInt16>.size) - 1
if array.indices.contains(check){
let result = from(Array(array[currentIndex..<currentIndex + MemoryLayout<UInt16>.size]), UInt16.self)
currentIndex += MemoryLayout<UInt16>.size
return result.littleEndian
}else{
return 0
}
}
public func getInt32() -> Int32 {
let check=(currentIndex + MemoryLayout<Int32>.size) - 1
if array.indices.contains(check){
let result = from(Array(array[currentIndex..<currentIndex + MemoryLayout<Int32>.size]), Int32.self)
currentIndex += MemoryLayout<Int32>.size
return result.littleEndian
}else{
return 0
}
}
public func getFloat() -> Float {
let check=(currentIndex + MemoryLayout<UInt32>.size) - 1
if array.indices.contains(check){
let result = from(Array(array[currentIndex..<currentIndex + MemoryLayout<UInt32>.size]), UInt32.self)
currentIndex += MemoryLayout<UInt32>.size
return Float(bitPattern: result.littleEndian)
}else{
return 0.0
}
}
public func getDouble() -> Double {
let check=(currentIndex + MemoryLayout<UInt64>.size) - 1
if array.indices.contains(check){
let result = from(Array(array[currentIndex..<currentIndex + MemoryLayout<UInt64>.size]), UInt64.self)
currentIndex += MemoryLayout<UInt64>.size
return Double(bitPattern: result.bigEndian)
}else{
return 0.0
}
}
The only difference in the above functions is types: Float, double, UInt16, Int32.
From Function:
private func from<T>(_ value: [UInt8], _: T.Type) -> T {
return value.withUnsafeBytes {
$0.load(fromByteOffset: 0, as: T.self)
}
}
My Solution:
public func getNumber<T:Numeric>() -> T {
let check=(currentIndex + MemoryLayout<T>.size) - 1
if array.indices.contains(check){
let result = from(Array(array[currentIndex..<currentIndex + MemoryLayout<T>.size]), T.self)
currentIndex += MemoryLayout<T>.size
return result.bigEndian
}else{
return 0
}
}
Error:
Value of type 'T' has no member 'bigEndian'

Swift: error: cannot use mutating member on immutable value

I'm getting the above error in the following code. The Heap struct is from the Swift Algorithm Club. I'm using the Heap to solve a Hackerrank challenge: Heaps: Find the Running Median.
import Foundation
// Enter your code here
struct Heap<Element> {
var elements : [Element]
let priorityFunction : (Element, Element) -> Bool
init(elements: [Element] = [], priorityFunction: #escaping (Element, Element) -> Bool) {
self.elements = elements
self.priorityFunction = priorityFunction
buildHeap()
}
mutating func buildHeap() {
for index in (0 ..< count / 2).reversed() {
siftDown(elementAtIndex: index)
}
}
var isEmpty : Bool {
return elements.isEmpty
}
var count : Int {
return elements.count
}
func peek() -> Element? {
return elements.first
}
func isRoot(_ index: Int) -> Bool {
return (index == 0)
}
func leftChildIndex(of index: Int) -> Int {
return (2 * index) + 1
}
func rightChildIndex(of index: Int) -> Int {
return (2 * index) + 2
}
func parentIndex(of index: Int) -> Int {
return (index - 1) / 2
}
func isHigherPriority(at firstIndex: Int, than secondIndex: Int) -> Bool {
return priorityFunction(elements[firstIndex], elements[secondIndex])
}
func highestPriorityIndex(of parentIndex: Int, and childIndex: Int) -> Int {
guard childIndex < count && isHigherPriority(at: childIndex, than: parentIndex)
else { return parentIndex }
return childIndex
}
func highestPriorityIndex(for parent: Int) -> Int {
return highestPriorityIndex(of: highestPriorityIndex(of: parent, and: leftChildIndex(of: parent)), and: rightChildIndex(of: parent))
}
mutating func swapElement(at firstIndex: Int, with secondIndex: Int) {
guard firstIndex != secondIndex
else { return }
elements.swapAt(firstIndex, secondIndex)
}
mutating func enqueue(_ element: Element) {
elements.append(element)
siftUp(elementAtIndex: count - 1)
}
mutating func siftUp(elementAtIndex index: Int) {
let parent = parentIndex(of: index)
guard !isRoot(index),
isHigherPriority(at: index, than: parent)
else { return }
swapElement(at: index, with: parent)
siftUp(elementAtIndex: parent)
}
mutating func dequeue() -> Element? {
guard !isEmpty // 1
else { return nil }
swapElement(at: 0, with: count - 1) // 2
let element = elements.removeLast() // 3
if !isEmpty { // 4
siftDown(elementAtIndex: 0) // 5
}
return element // 6
}
mutating func siftDown(elementAtIndex index: Int) {
let childIndex = highestPriorityIndex(for: index) // 1
if index == childIndex { // 2
return
}
swapElement(at: index, with: childIndex) // 3
siftDown(elementAtIndex: childIndex)
}
}
var topHeap = Heap<Int>(priorityFunction: >)
var bottomHeap = Heap<Int>(priorityFunction: <)
let n = Int(readLine(strippingNewline: true)!)!
let val1 = Int(readLine(strippingNewline: true)!)!
print(String(format: "%.1f", Float(val1)))
if n > 1 {
let val2 = Int(readLine(strippingNewline: true)!)!
print(String(format: "%.1f", (Float(val1) + Float(val2)) / 2.0))
if val1 < val2 {
topHeap.enqueue(val1);
bottomHeap.enqueue(val2);
} else {
topHeap.enqueue(val2);
bottomHeap.enqueue(val1);
}
for _ in 2..<n {
let val = Int(readLine(strippingNewline: true)!)!
// Put in the proper heap
if val < topHeap.peek()! {
topHeap.enqueue(val)
} else if val > bottomHeap.peek()! {
bottomHeap.enqueue(val)
} else if topHeap.count < bottomHeap.count {
topHeap.enqueue(val)
} else {
bottomHeap.enqueue(val)
}
// If one heap has two more than the other, move one value
if topHeap.count == bottomHeap.count + 2 {
var element: Int = bottomHeap.dequeue
error: cannot use mutating member on immutable value: 'bottomHeap' is immutable
topHeap.enqueue(element)
} else if bottomHeap.count == topHeap.count + 2 {
bottomHeap.enqueue(topHeap.dequeue)
error: cannot use mutating member on immutable value: 'topHeap' is immutable
}
// If one heap has one more than the other, the top node of the larger heap holds the median
if topHeap.count == bottomHeap.count + 1 {
print(String(format: "%.1f", Float(topHeap.peek()!)))
} else if bottomHeap.count == topHeap.count + 1 {
print(String(format: "%.1f", Float(bottomHeap.peek()!)))
} else {
print(String(format: "%.1f", (Float(topHeap.peek()!) + Float(bottomHeap.peek()!)) / 2.0))
}
}
}
dequeue is a function. You need to add () to the calls.
Then you need to deal with the fact that dequeue() returns an optional Int.

Compiler issues when chaining multiple calls to the same method

I'm trying to fix this bug by overloading prefix(_ maxLength) for all lazy sequences and collections, but I'm running into weird compiler issues.
I'm using Xcode 9.0 beta 6 (9M214v), but it's also reproducable in all of the latest snapshots for 4.0.
Given the following iterator,...
public struct LazyPrefixIterator <Base: IteratorProtocol>: IteratorProtocol {
public typealias Element = Base.Element
private var baseIterator: Base
private let maxLength: Int
private var taken = 0
internal init (_ baseIterator: Base, _ maxLength: Int) {
precondition(maxLength >= 0, "Can't take a prefix of negative length from an iterator")
self.baseIterator = baseIterator
self.maxLength = maxLength
}
public mutating func next () -> Element? {
if self.taken >= self.maxLength {
return nil
}
self.taken += 1
return self.baseIterator.next()
}
}
...the following sequence,...
public struct LazyPrefixSequence <Base: Sequence>: LazySequenceProtocol {
public typealias Iterator = LazyPrefixIterator<Base.Iterator>
private let baseSequence: Base
private let maxLength: Int
internal init (_ baseSequence: Base, _ maxLength: Int) {
precondition(maxLength >= 0, "Can't take a prefix of negative length from a sequence")
self.baseSequence = baseSequence
self.maxLength = maxLength
}
public func makeIterator() -> Iterator {
return LazyPrefixIterator(self.baseSequence.makeIterator(), self.maxLength)
}
}
...the following collection...
public struct LazyPrefixCollection <Base: Collection>: LazyCollectionProtocol {
public typealias Iterator = LazyPrefixIterator<Base.Iterator>
public typealias Index = Base.Index
public typealias Element = Base.Element
private let baseCollection: Base
private let maxLength: Int
internal init (_ baseCollection: Base, _ maxLength: Int) {
precondition(maxLength >= 0, "Can't take a prefix of negative length from a collection")
self.baseCollection = baseCollection
self.maxLength = maxLength
}
public func makeIterator() -> Iterator {
return LazyPrefixIterator(self.baseCollection.makeIterator(), self.maxLength)
}
public var startIndex: Index {
return self.baseCollection.startIndex
}
public var endIndex: Index {
var maxLength = 0
var index = self.baseCollection.startIndex
let baseCollectionEndIndex = self.baseCollection.endIndex
while maxLength < self.maxLength && index != baseCollectionEndIndex {
index = self.baseCollection.index(after: index)
maxLength += 1
}
return index
}
public func index (after i: Index) -> Index {
precondition(i != self.endIndex, "Can't advance past endIndex")
return self.baseCollection.index(after: i)
}
public subscript (position: Index) -> Element {
precondition(position >= self.startIndex && position < self.endIndex, "Index out of range")
return self.baseCollection[position]
}
}
...and the following overloads (to squash ambiguity issues),...
public extension LazySequence {
func prefix (_ maxLength: Int) -> LazyPrefixSequence<Elements> {
return LazyPrefixSequence(self.elements, maxLength)
}
}
public extension LazySequenceProtocol {
func prefix (_ maxLength: Int) -> LazyPrefixSequence<Self> {
return LazyPrefixSequence(self, maxLength)
}
}
public extension LazyCollection {
func prefix (_ maxLength: Int) -> LazyPrefixCollection<Base> {
return LazyPrefixCollection(self.elements, maxLength)
}
}
public extension LazyCollectionProtocol {
func prefix (_ maxLength: Int) -> LazyPrefixCollection<Self> {
return LazyPrefixCollection(self, maxLength)
}
}
public extension LazyDropWhileBidirectionalCollection {
func prefix (_ maxLength: Int) -> LazyPrefixCollection<LazyDropWhileBidirectionalCollection<Base>> {
return LazyPrefixCollection(self, maxLength)
}
}
public extension LazyPrefixWhileBidirectionalCollection {
func prefix (_ maxLength: Int) -> LazyPrefixCollection<LazyPrefixWhileBidirectionalCollection<Base>> {
return LazyPrefixCollection(self, maxLength)
}
}
public extension LazyRandomAccessCollection {
func prefix (_ maxLength: Int) -> LazyPrefixCollection<LazyRandomAccessCollection<Base>> {
return LazyPrefixCollection(self, maxLength)
}
}
...the following works as expected (each one of these prints true)...
print(Array(AnySequence(sequence(first: 0, next: {$0 + 1})).lazy.prefix(2)) == [0, 1])
print(Array(sequence(first: 0, next: {$0 + 1}).lazy.drop(while: {_ in false}).prefix(2)) == [0, 1])
print(Array(sequence(first: 0, next: {$0 + 1}).lazy.filter{_ in true}.prefix(2)) == [0, 1])
print(Array(sequence(first: 0, next: {$0 + 1}).lazy.map{$0}.prefix(2)) == [0, 1])
print(Array(sequence(first: 0, next: {$0 + 1}).lazy.prefix(while: {_ in true}).prefix(2)) == [0, 1])
print(Array(sequence(first: 0, next: {$0 + 1}).lazy.prefix(2)) == [0, 1])
print(Array(AnyCollection([0, 1, 2]).lazy.prefix(2)) == [0, 1])
print(Array(([0, 1, 2].lazy as LazyBidirectionalCollection).prefix(2)) == [0, 1])
print(Array([0, 1, 2].lazy.drop(while: {_ in false}).prefix(2)) == [0, 1])
print(Array(([0, 1, 2].lazy.drop(while: {_ in false}) as LazyDropWhileCollection).prefix(2)) == [0, 1])
print(Array([0, 1, 2].lazy.filter{_ in true}.prefix(2)) == [0, 1])
print(Array(([0, 1, 2].lazy.filter{_ in true} as LazyFilterCollection).prefix(2)) == [0, 1])
print(Array(([0, 1, 2].lazy.map{$0} as LazyMapBidirectionalCollection).prefix(2)) == [0, 1])
print(Array(([0, 1, 2].lazy.map{$0} as LazyMapCollection).prefix(2)) == [0, 1])
print(Array([0, 1, 2].lazy.map{$0}.prefix(2)) == [0, 1])
print(Array([0, 1, 2].lazy.prefix(while: {_ in true}).prefix(2)) == [0, 1])
print(Array(([0, 1, 2].lazy.prefix(while: {_ in true}) as LazyPrefixWhileCollection).prefix(2)) == [0, 1])
print(Array([0, 1, 2].lazy.prefix(2)) == [0, 1])
..., but, when chaining the method multiple times on a collection, weird compiler behaviour occurs. The following works with a return type of LazyPrefixCollection<LazyRandomAccessCollection<[Int]>>:
_ = [0, 1, 2].lazy.prefix(3)
The following works too, with a return type of LazyPrefixCollection<LazyPrefixCollection<LazyRandomAccessCollection<[Int]>>>:
_ = [0, 1, 2].lazy.prefix(3).prefix(3)
But once we add another method, it hiccups. It tells me that Expression type '()' is ambiguous without more context:
_ = [0, 1, 2].lazy.prefix(3).prefix(3).prefix(3)
If we add another one it segment faults while type-checking:
_ = [0, 1, 2].lazy.prefix(3).prefix(3).prefix(3).prefix(3)
Of course, creating intermediate variables for each 'step' works:
let a = [0, 1, 2].lazy.prefix(3)
let b = a.prefix(3)
let c = b.prefix(3)
let d = c.prefix(3)
// Etc.
It's also worth noting that it works when we use a sequence instead of a collection:
_ = sequence(first: 0, next: {(e: Int) -> Int in e + 1}).lazy.prefix(3).prefix(3).prefix(3).prefix(3).prefix(3)
Chaining multiple maps or any of the other methods from the standard library on a collection doesn't cause any issues. The compiler gladly excepts this monstrosity:
_ = [0, 1, 2].lazy.map{$0}.map{$0}.map{$0}.map{$0}.map{$0}.map{$0}
Which makes me believe I'm doing something wrong in my code, particularly in LazyPrefixCollection.
What could be causing this behaviour?
Adding overloads for prefix(_ maxLength) on LazyPrefixSequence and LazyPrefixCollection makes all compiler issues go away. The code then becomes the following:
public struct LazyPrefixIterator <Base: IteratorProtocol>: IteratorProtocol {
public typealias Element = Base.Element
private var baseIterator: Base
private let maxLength: Int
private var taken = 0
internal init (_ baseIterator: Base, _ maxLength: Int) {
precondition(maxLength >= 0, "Can't take a prefix of negative length from an iterator")
self.baseIterator = baseIterator
self.maxLength = maxLength
}
public mutating func next () -> Element? {
if self.taken >= self.maxLength {
return nil
}
self.taken += 1
return self.baseIterator.next()
}
}
public struct LazyPrefixSequence <Base: Sequence>: LazySequenceProtocol {
public typealias Iterator = LazyPrefixIterator<Base.Iterator>
private let baseSequence: Base
private let maxLength: Int
internal init (_ baseSequence: Base, _ maxLength: Int) {
precondition(maxLength >= 0, "Can't take a prefix of negative length from a sequence")
self.baseSequence = baseSequence
self.maxLength = maxLength
}
public func makeIterator() -> Iterator {
return LazyPrefixIterator(self.baseSequence.makeIterator(), self.maxLength)
}
}
public extension LazyPrefixSequence where Base.SubSequence: Sequence {
func prefix (_ maxLength: Int) -> LazyPrefixSequence {
return LazyPrefixSequence(self.baseSequence, Swift.min(self.maxLength, maxLength))
}
}
public struct LazyPrefixCollection <Base: Collection>: LazyCollectionProtocol {
public typealias Iterator = LazyPrefixIterator<Base.Iterator>
public typealias Index = Base.Index
public typealias Element = Base.Element
private let baseCollection: Base
private let maxLength: Int
internal init (_ baseCollection: Base, _ maxLength: Int) {
precondition(maxLength >= 0, "Can't take a prefix of negative length from a collection")
self.baseCollection = baseCollection
self.maxLength = maxLength
}
public func makeIterator() -> Iterator {
return LazyPrefixIterator(self.baseCollection.makeIterator(), self.maxLength)
}
public var startIndex: Index {
return self.baseCollection.startIndex
}
public var endIndex: Index {
var maxLength = 0
var index = self.baseCollection.startIndex
while maxLength < self.maxLength && index != self.baseCollection.endIndex {
index = self.baseCollection.index(after: index)
maxLength += 1
}
return index
}
public func index (after i: Index) -> Index {
precondition(i != self.endIndex, "Can't advance past endIndex")
return self.baseCollection.index(after: i)
}
public subscript (position: Index) -> Element {
precondition(position >= self.startIndex && position < self.endIndex, "Index out of range")
return self.baseCollection[position]
}
public func prefix (_ maxLength: Int) -> LazyPrefixCollection {
return LazyPrefixCollection(self.baseCollection, Swift.min(self.maxLength, maxLength))
}
}
public extension LazySequence {
func prefix (_ maxLength: Int) -> LazyPrefixSequence<Elements> {
return LazyPrefixSequence(self.elements, maxLength)
}
}
public extension LazySequenceProtocol {
func prefix (_ maxLength: Int) -> LazyPrefixSequence<Self> {
return LazyPrefixSequence(self, maxLength)
}
}
public extension LazyCollection {
func prefix (_ maxLength: Int) -> LazyPrefixCollection<Base> {
return LazyPrefixCollection(self.elements, maxLength)
}
}
public extension LazyCollectionProtocol {
func prefix (_ maxLength: Int) -> LazyPrefixCollection<Self> {
return LazyPrefixCollection(self, maxLength)
}
}
public extension LazyDropWhileBidirectionalCollection {
func prefix (_ maxLength: Int) -> LazyPrefixCollection<LazyDropWhileBidirectionalCollection<Base>> {
return LazyPrefixCollection(self, maxLength)
}
}
public extension LazyPrefixWhileBidirectionalCollection {
func prefix (_ maxLength: Int) -> LazyPrefixCollection<LazyPrefixWhileBidirectionalCollection<Base>> {
return LazyPrefixCollection(self, maxLength)
}
}
public extension LazyRandomAccessCollection {
func prefix (_ maxLength: Int) -> LazyPrefixCollection<LazyRandomAccessCollection<Base>> {
return LazyPrefixCollection(self, maxLength)
}
}
Testing it:
let xs = [0, 1, 2, 3, 4].lazy.prefix(3).prefix(10).prefix(100).prefix(10).prefix(5).prefix(1)
let ys = sequence(first: 0, next: {$0 + 1}).lazy.prefix(3).prefix(10).prefix(100).prefix(10).prefix(5).prefix(1)
print(Array(xs)) // [0]
print(type(of: xs)) // LazyPrefixCollection<LazyRandomAccessCollection<Array<Int>>>
print(Array(ys)) // [0]
print(type(of: ys)) // LazyPrefixSequence<UnfoldSequence<Int, (Optional<Int>, Bool)>>
Feedback appreciated. Especially when it comes to the correct typealiases and where clauses. That stuff still feels like arbitrary voodoo black magic to me; if I don't put in the where Base.SubSequence: Sequence restriction on LazyPrefixSequence then it will ask me for a whole bunch of useless overloads on other methods. Why SubSequence doesn't conform to Sequence makes no sense to me.

Swift: How to make this function generic

Here is what I have:
class func truncateTailsOfRange(range: Range<Int>, portion: Double) -> Range<Int> {
let start = range.startIndex + Int(portion * Double(range.count))
let end = range.endIndex - Int(portion * Double(range.count))
return Range(start: start, end: end)
}
I would like to make this generic for IntegerType:
class func truncateTailsOfRange<T: IntegerType>(range: Range<T>, portion: Double) -> Range<T> {
let start = range.startIndex + T(portion * Double(range.count))
let end = range.endIndex - T(portion * Double(range.count))
return Range(start: start, end: end)
}
But the error I get is:
Cannot invoke initializer for type Double with an argument list of type (T.Distance)
Is this possible to do?
First you need a CustomDoubleConvertible protocol. This mirrors CustomStringConvertible. You extend all Types which you want to be convertible to Double. Similar to description which returns a String representation of a Type.
protocol CustomDoubleConvertible {
var doubleValue : Double { get }
}
extension Int : CustomDoubleConvertible {
var doubleValue : Double { return Double(self) }
}
extension Int16 : CustomDoubleConvertible {
var doubleValue : Double { return Double(self) }
}
If you make the function an extension to Range itself you can make use of it's generic nature and it's typealiases.
extension Range where Element.Distance : CustomDoubleConvertible {
Now you can calculate the offsets of the indexes like so :
let startOffset = Int(portion * self.count.doubleValue)
let endOffset = Int(portion * self.count.doubleValue)
If you further constrain Range so that it's Element must be a BidirectionalIndexType you can use successor and predecessor.
extension Range where Element.Distance : CustomDoubleConvertible, Element : BidirectionalIndexType {
This allows you to get the full function by iterating over the offsets and calling successor and predecessor.
extension Range where Element.Distance : CustomDoubleConvertible, Element : BidirectionalIndexType {
func truncateTailsOfRange(portion: Double) -> Range<Element> {
let startOffset = Int(portion * self.count.doubleValue)
let endOffset = Int(portion * self.count.doubleValue)
var start = self.startIndex
var end = self.endIndex
for _ in 0..<startOffset { start = start.successor() }
for _ in 0..<endOffset { end = end.predecessor() }
return Range(start: start, end: end)
}
}
Some tests :
let rangeA = 1...4 // 1..<5
let rangeB = "a"..."g"
rangeA.truncateTailsOfRange(0.3) // 2..<4
rangeB.truncateTailsOfRange(0.3) // has no member ....
let w : Int16 = 3
let z : Int16 = 9
let rangeC = w...z // 3..<10
rangeC.truncateTailsOfRange(0.4) // 5..<8
This is an interesting but academic exercise.
Here's a method that is not very efficient but that will work with all range types:
func truncateTailsOfRange<T>(var range: Range<T>, portion: Double) -> Range<T>
{
let elementCount = Array(range).count
let truncationCount = Int( portion * Double(elementCount) )
let remainingCount = max(0, elementCount - 2 * truncationCount)
for _ in 0..<truncationCount
{ range.startIndex = range.startIndex.successor() }
range.endIndex = range.startIndex
for _ in 0..<remainingCount
{ range.endIndex = range.endIndex.successor() }
return range
}
and here's a much quicker one :
func truncateTailsOfRange2<T>(var range: Range<T>, portion: Double) -> Range<T>
{
if range.isEmpty {return range}
let elements = Array(range)
let truncationCount = Int( portion * Double(elements.count) )
let remainingCount = max(0, elements.count - 2 * truncationCount)
return elements[truncationCount]..<elements[truncationCount+remainingCount]
}

Swift for-in loop with enumerate on custom Array2D class?

How would I go about implementing a custom enumerate function that makes something like this work (Swift 2):
for ((column, row), item) in Array2D.enumerate() { ... }
In my simple Array2D struct:
struct Array2D<T> : SequenceType {
let columns: Int
let rows: Int
private var array: Array<T?>
init(columns: Int, rows: Int) {
self.columns = columns
self.rows = rows
array = Array(count: rows*columns, repeatedValue: nil)
}
subscript(column: Int, row: Int) -> T? {
get {
return array[columns*row + column]
}
set {
array[columns*row + column] = newValue
}
}
func generate() -> AnyGenerator<T?> {
var column = 0
var row = 0
return anyGenerator() {
guard row < self.rows else {
return nil
}
let item = self[column, row]
if ++column == self.columns {
column = 0
++row
}
return item
}
}
}
I couldn't find any good explanation on implementing an enumerate function in Swift
The enumerate() function in Swift returns integers starting from 0 for the first part of its tuple. Those have nothing to do with the sequence you're enumerating over. So, for instance, this won't work:
let word = "hello".characters
for (index, letter) in word.enumerate() {
print(word[index])
}
Because the indices of a characterView are String.Indexs.
So there are several ways to get what you're going for. The first is to just overload enumerate() for your struct. Again, there are a few days you could do this. First off, how about a function that uses your own generator, and uses its own logic to figure out the coordinates. This could work:
func enumerate() -> AnyGenerator<((Int, Int), T?)> {
let g = self.generate()
var coord = -1
return anyGenerator {
g.next().map { ((++coord % self.columns, coord / self.columns), $0) }
}
}
But you're duplicating code there, especially from your generate method. Seeing you're already using coordinates to return each element, why not just have your enumerate method be the default, and your generate method call on that. Something like this:
// Original generate method, now returns the coords it used
func enumerate() -> AnyGenerator<((Int, Int), T?)> {
var column = 0
var row = 0
return anyGenerator() {
guard row < self.rows else {
return nil
}
let item = self[column, row]
if ++column == self.columns {
column = 0
++row
}
return ((column, row), item)
}
}
// uses enumerate, ignores coords
func generate() -> AnyGenerator<T?> {
let g = self.enumerate()
return anyGenerator {
g.next().map { $1 }
}
}
If you wanted to go a little overboard, you could write an enumerate function that enumerates the specific indices of its base. Call it specEnumerate:
public struct SpecEnumerateGen<Base : CollectionType> : GeneratorType {
private var eG: Base.Generator
private let sI: Base.Index
private var i : Base.Index?
public mutating func next() -> (Base.Index, Base.Generator.Element)? {
i?._successorInPlace() ?? {self.i = self.sI}()
return eG.next().map { (i!, $0) }
}
private init(g: Base.Generator, i: Base.Index) {
self.eG = g
self.sI = i
self.i = nil
}
}
public struct SpecEnumerateSeq<Base : CollectionType> : SequenceType {
private let col: Base
public func generate() -> SpecEnumerateGen<Base> {
return SpecEnumerateGen(g: col.generate(), i: col.startIndex)
}
}
public extension CollectionType {
func specEnumerate() -> SpecEnumerateSeq<Self> {
return SpecEnumerateSeq(col: self)
}
}
With this function, this would work:
let word = "hello".characters
for (index, letter) in word.specEnumerate() {
print(word[index])
}
But your matrix struct is still a SequenceType, with no specific indices. For that, you'll have to implement your own MatrixIndex:
public struct MatrixIndex: BidirectionalIndexType {
public let x, y : Int
private let columns: Int
public func successor() -> MatrixIndex {
return (x + 1 == columns) ?
MatrixIndex(x: 0, y: y + 1, columns: columns) :
MatrixIndex(x: x + 1, y: y, columns: columns)
}
public func predecessor() -> MatrixIndex {
return (x == 0) ?
MatrixIndex(x: columns - 1, y: y - 1, columns: columns) :
MatrixIndex(x: x - 1, y: y, columns: columns)
}
}
public func == (lhs: MatrixIndex, rhs: MatrixIndex) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
extension MatrixIndex : CustomDebugStringConvertible {
public var debugDescription: String {
return "\(x), \(y)"
}
}
extension MatrixIndex: RandomAccessIndexType {
public func advancedBy(n: Int) -> MatrixIndex {
let total = (y * columns) + x + n
return MatrixIndex(x: total % columns, y: total / columns, columns: columns)
}
public func distanceTo(other: MatrixIndex) -> Int {
return (other.x - x) + (other.y - y) * columns
}
}
Right. Now you'll need another matrix struct:
public struct Matrix2D<T> : MutableCollectionType {
public var contents: [[T]]
public subscript(index: MatrixIndex) -> T {
get {
return contents[index.y][index.x]
} set {
self.contents[index.y][index.x] = newValue
}
}
public var count: Int { return contents[0].count * contents.count }
public var startIndex: MatrixIndex {
return MatrixIndex(x: 0, y: 0, columns: contents[0].count)
}
public var endIndex: MatrixIndex {
return MatrixIndex(x: 0, y: contents.endIndex, columns: contents[0].count)
}
}
Right. So now, after all of that, this works:
let myMatrix = Matrix2D(contents: [[1, 2], [3, 4]])
for (coordinate, value) in myMatrix.specEnumerate() {
value == myMatrix[coordinate] // True every time
}
It might suffice defining your own enumerate taking advantage of the one you already have:
func enumerate() -> AnyGenerator<((Int, Int), T?)> {
var index = 0
var g = array.generate()
return anyGenerator() {
if let item = g.next() {
let column = index % self.columns
let row = index / self.columns
++index
return ((column, row) , item)
}
return nil
}
}
Notice in this case you could avoid conforming to SequenceType since I use generate from the private array. Anyway it could be consistent to do so.
Here is how then you could use it:
var a2d = Array2D<Int>(columns: 2, rows: 4)
a2d[0,1] = 4
for ((column, row), item) in a2d.enumerate() {
print ("[\(column) : \(row)] = \(item)")
}
Hope this helps