diff --git a/Sources/MultiArray/ArrayData.swift b/Sources/MultiArray/ArrayData.swift index d683d6f..b4686b6 100644 --- a/Sources/MultiArray/ArrayData.swift +++ b/Sources/MultiArray/ArrayData.swift @@ -18,8 +18,8 @@ public protocol ArrayData { associatedtype Buffer - static func initialise(_ arrayData: Buffer, at: Int, to value: Self) - static func deinitialise(_ arrayData: Buffer, count: Int) + static func initialize(_ arrayData: Buffer, at: Int, to value: Self) + static func deinitialize(_ arrayData: Buffer, count: Int) static func read(_ arrayData: Buffer, at index: Int) -> Self static func write(_ arrayData: Buffer, at index: Int, to value: Self) @@ -32,12 +32,12 @@ public protocol ArrayData { // references (i.e. machine types) extension ArrayData where Buffer == UnsafeMutablePointer { @inlinable - public static func initialise(_ arrayData: Self.Buffer, at index: Int, to value: Self) { + public static func initialize(_ arrayData: Self.Buffer, at index: Int, to value: Self) { (arrayData + index).initialize(to: value) } @inlinable - public static func deinitialise(_: Self.Buffer, count _: Int) { /* no-op */ } + public static func deinitialize(_: Self.Buffer, count _: Int) { /* no-op */ } @inlinable // @inline(__always) @@ -113,10 +113,10 @@ extension Unit: ArrayData { public typealias Buffer = Void @inlinable - public static func initialise(_: Self.Buffer, at _: Int, to _: Self) { /* no-op */ } + public static func initialize(_: Self.Buffer, at _: Int, to _: Self) { /* no-op */ } @inlinable - public static func deinitialise(_: Self.Buffer, count _: Int) { /* no-op */ } + public static func deinitialize(_: Self.Buffer, count _: Int) { /* no-op */ } @inlinable // @inline(__always) @@ -146,12 +146,12 @@ extension Box: ArrayData { public typealias Buffer = UnsafeMutablePointer @inlinable - public static func initialise(_ arrayData: Self.Buffer, at index: Int, to value: Self) { + public static func initialize(_ arrayData: Self.Buffer, at index: Int, to value: Self) { (arrayData + index).initialize(to: value.unbox) } @inlinable - public static func deinitialise(_ arrayData: Self.Buffer, count: Int) { + public static func deinitialize(_ arrayData: Self.Buffer, count: Int) { arrayData.deinitialize(count: count) } @@ -192,15 +192,15 @@ extension Product: ArrayData where A: ArrayData, B: ArrayData { public typealias Buffer = (A.Buffer, B.Buffer) @inlinable - public static func initialise(_ arrayData: Self.Buffer, at index: Int, to value: Self) { - A.initialise(arrayData.0, at: index, to: value._0) - B.initialise(arrayData.1, at: index, to: value._1) + public static func initialize(_ arrayData: Self.Buffer, at index: Int, to value: Self) { + A.initialize(arrayData.0, at: index, to: value._0) + B.initialize(arrayData.1, at: index, to: value._1) } @inlinable - public static func deinitialise(_ arrayData: Self.Buffer, count: Int) { - A.deinitialise(arrayData.0, count: count) - B.deinitialise(arrayData.1, count: count) + public static func deinitialize(_ arrayData: Self.Buffer, count: Int) { + A.deinitialize(arrayData.0, count: count) + B.deinitialize(arrayData.1, count: count) } @inlinable diff --git a/Sources/MultiArray/MultiArray.swift b/Sources/MultiArray/MultiArray.swift index 06aeacb..ba70dd1 100644 --- a/Sources/MultiArray/MultiArray.swift +++ b/Sources/MultiArray/MultiArray.swift @@ -34,11 +34,23 @@ public struct MultiArray where Element: Generic, Element.RawRepresentat /// produce each value. @inlinable public init(count: Int, with generator: (Int) throws -> Element) rethrows { - precondition(count >= 0) - self.arrayData = .init(unsafeUninitializedCapacity: count) - for i in 0 ..< count { - let value = try generator(i) - Element.RawRepresentation.initialise(self.arrayData.storage, at: i, to: value.rawRepresentation) + try self.init(unsafeUninitializedCapacity: count) { buffer in + for i in 0 ..< count { + let value = try generator(i) + buffer.initializeElement(at: i, to: value) + } + } + } + + /// Create a new MultiArray by applying the given function to each index to + /// produce each value. + @inlinable + public init(count: Int, with generator: (Int) throws(E) -> Element) throws(E) { + try self.init(unsafeUninitializedCapacity: count) { buffer throws(E) in + for i in 0 ..< count { + let value = try generator(i) + buffer.initializeElement(at: i, to: value) + } } } @@ -66,6 +78,37 @@ public struct MultiArray where Element: Generic, Element.RawRepresentat self.init(Array(elements)) } } + + /// Creates an array with the specified capacity, then calls the given + /// closure with a buffer covering the array's uninitialized memory. + @inlinable + public init( + unsafeUninitializedCapacity count: Int, + initializingWith: (inout UninitializedMultiArrayData) throws(E) -> Void + ) throws(E) { + precondition(count >= 0) + self.arrayData = .init(unsafeUninitializedCapacity: count) + var buffer = UninitializedMultiArrayData(arrayData.storage) + try initializingWith(&buffer) + } +} + +// Wrapper so that we can expose the buffer using the surface Element type, +// rather than the underlying RawRepresentation type. +public struct UninitializedMultiArrayData where Element: Generic, Element.RawRepresentation: ArrayData { + @usableFromInline + let storage: Element.RawRepresentation.Buffer + + @usableFromInline + init(_ storage: Element.RawRepresentation.Buffer) { + self.storage = storage + } + + /// Initialises the element at the given `index` to the given `value` + @inlinable + public func initializeElement(at index: Int, to value: consuming Element) { + Element.RawRepresentation.initialize(self.storage, at: index, to: value.rawRepresentation) + } } // TODO: It would be better if this is generic over the underlying storage @@ -79,12 +122,12 @@ internal final class MultiArrayData { let count: Int @usableFromInline - var context: UnsafeMutableRawPointer + let context: UnsafeMutableRawPointer // Storing the internal pointers for speed(?), but we could also recompute // them from the base context. @usableFromInline - var storage: A.Buffer + let storage: A.Buffer @inlinable init(unsafeUninitializedCapacity count: Int) { @@ -106,7 +149,7 @@ internal final class MultiArrayData { } deinit { - A.deinitialise(self.storage, count: self.count) + A.deinitialize(self.storage, count: self.count) self.context.deallocate() } }