import Accelerate
struct Vector<T> {
private let data: DataBuffer<T>
var buffer: UnsafeMutableBufferPointer<T> {
get { self.data.buffer }
set { self.data.buffer = newValue }
}
var length: Int {
self.buffer.count
}
init(_ values: [T]) {
self.data = DataBuffer(array: values)
}
subscript(item: Int) -> T {
get { return self.buffer[item] }
set { self.buffer[item] = newValue }
}
static func range(_ r: Range<Int>) -> Vector where T == Float {
let c = r.upperBound - r.lowerBound
let v = vDSP.ramp(withInitialValue: Float(r.lowerBound), increment: 1.0, count: c)
let vec = Vector(v)
return vec
}
static func range(_ r: Range<Int>) -> Vector where T == Double {
let c = r.upperBound - r.lowerBound
let v = vDSP.ramp(withInitialValue: Double(r.lowerBound), increment: 1.0, count: c)
let vec = Vector(v)
return vec
}
}
The underlying data for a Vector is handled with a mutable buffer:
class DataBuffer<T> {
var buffer: UnsafeMutableBufferPointer<T>
init(count: Int) {
let start = UnsafeMutablePointer<T>.allocate(capacity: count)
self.buffer = UnsafeMutableBufferPointer(start: start, count: count)
}
init(array: [T]) {
let count = array.count
let start = UnsafeMutablePointer<T>.allocate(capacity: count)
self.buffer = UnsafeMutableBufferPointer(start: start, count: count)
_ = self.buffer.initialize(fromContentsOf: array)
}
deinit {
self.buffer.deinitialize()
self.buffer.deallocate()
}
}
This allows me to create a Vector from an open-ended range as shown here:
let vec = Vector<Float>.range(0..<10)
for i in 0..<vec.length {
print(vec[i], terminator: " ")
}
print()
// This prints the following:
// 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0
However, I would like to initialize a Vector from a range as shown below. I want to support Int, Float, and Double for the Vector values. Any ideas on how I could accomplish this?
// I would like to initialize a vector from a Range
let vec = Vector<Float>(0..<10)
// I also want to initialize a vector from a ClosedRange
let vec = Vector<Float>(2...11)
Small improvement: UnsafeMutableBufferPointer has allocate(capacity:) so you can skip a step and not accidentally use the unbounded pointer.
(I assume the reason to use a custom type and not Array is so you can have a stable buffer address between statements? If you don’t need that, you might as well just use Array.)
You can use vDSP as you do in your initial example to add support for floating-point ranges in an additional init() overload that takes a some RangeExpression<some FloatingPoint>.
I couldn't get RangeExpression and FloatingPoint to work. But I can use stride to create Int, Float, and Double vectors from a range.
init(_ r: Range<Int>) where T == Int {
self.data = DataBuffer(array: Array(r))
}
init(_ r: Range<Int>) where T == Double {
let s = Double(r.lowerBound)
let e = Double(r.upperBound)
let arr = Array(stride(from: s, to: e, by: 1.0))
self.data = DataBuffer(array: arr)
}
init(_ r: Range<Int>) where T == Float {
let s = Float(r.lowerBound)
let e = Float(r.upperBound)
let arr = Array(stride(from: s, to: e, by: 1.0))
self.data = DataBuffer(array: arr)
}
This allows the following:
let vec1 = Vector<Int>(0..<10)
let vec2 = Vector<Float>(0..<10)
let vec3 = Vector<Double>(0..<10)