Discuss Swift.

Swift Documentation

Post

Replies

Boosts

Views

Activity

Bug Report: 'consume' Applied to Unsupported Value
'consume' applied to value that the compiler does not support. This is a compiler bug. Please file a bug with a small example of the bug. public func requestTopicsAndSubTopics() async throws -> (topics: [Topic], subTopics: [String: [SubTopic]]) { var subTopics = [String: [SubTopic]]() let topics = try await getTopics().sorted { $0.index < $1.index } try await withThrowingTaskGroup(of: ([SubTopic], String).self) { [weak self] group in guard let self else { return } for topic in topics { guard let topicId = topic.id else { throw Error.missingId } group.addTask { let subTopics = try await self.getSubtopics(topicId: topicId).sorted { $0.name < $1.name } return (consume subTopics, topicId) } } for try await (resultedSubTopics, topicId) in group { subTopics.updateValue(resultedSubTopics, forKey: topicId) } } return (consume topics, consume subTopics) }
0
0
30
8h
Bonjour permissions in Xcode 15.4
Hi, I'm using Multipeer Connectivity in my application and when I run it on my physical device, I receive following warning: NSNetServiceBrowser did not search with error dict [{ NSNetServicesErrorCode = "-72008"; NSNetServicesErrorDomain = 10; }]. I've found out that this is associated with not having proper permissions in info.plist according to https://developer.apple.com/forums/thread/653316 I've set description for Privacy - Local Network Usage Description, however, I'm not able to find any key for setting my Bonjour Services. Also, I do not see any popup on my device displaying request to approve local network usage. Could you please provide me an information how can I register my privileges properly?
0
0
42
10h
Decoding JSON with a reserved property name
I need to decode JSON into a class. The JSON has a field called "Type", and I cannot declare a property with that name in my class since Type is a reserved word. I tried declaring CodingKeys, but that doesn't work unless I declare EVERY property in the CodingKeys. This class has about a hundred properties and I have others like it, I do not want to do this. Is there a better solution?
2
0
68
1d
Failed to produce diagnostic for expression; please submit a bug report
I got the error and I don’t how can I fix it help please struct MovieDetail: View { var movie: Movie let screen = UIScreen.main.bounds @State private var showSeasonPicker = true @State private var selectedSeason = 0 var body: some View { ZStack { Color.black .ignoresSafeArea() ZStack { VStack { HStack { Spacer() Button() { // Closing Button }label: { Image(systemName: "xmark.circle") .font(.system(size: 28)) } } .padding(.horizontal, 22) ScrollView (.vertical, showsIndicators: false){ VStack { StandardHomeMovie(movie: movie) .frame(width: screen.width / 2.5) MovieInfoSubheadline(movie: movie) if movie.promotionHeadline != nil { Text(movie.promotionHeadline!) .bold() .font(.headline) } PlayButton(text: "Play", imagename: "play.fill", backgroundColor: .red) { // } CurrentEpisodeInformation(movie: movie) CastInfo(movie: movie) HStack(spacing: 60){ SmallVerticalButton(text: "My List", isOnImage: "checkmark", isOffImage: "plus", isOn: true) { // } SmallVerticalButton(text: "Rate", isOnImage: "hand.thumbsup.fill", isOffImage: "hand.thumbsup", isOn: true) { // } SmallVerticalButton(text: "Share", isOnImage: "square.and.arrow.up", isOffImage: "square.and.arrow.up", isOn: true) { // } Spacer() } .padding(.leading, 20) CustomTabSwitcher(tabs: [.episodes, .trailers, .more], movie: movie, showSeasonPicker: $showSeasonPicker, selectedSeason: $selectedSeason) } .padding(.horizontal, 10) } Spacer() } .foregroundStyle(.white) if showSeasonPicker { Group { Color.black.opacity(0.9) VStack(spacing: 40){ Spacer() ForEach(0..<(movie.numberOfSeasons ?? 0)) { season in Button(action: { self.selectedSeason = (season != 0) self.showSeasonPicker = false }, label: { Text("Season: \(season + 1)") .foregroundStyle(selectedSeason == season + 1 ? .white : .gray) .bold() .font(.title2) }) } Spacer() Button(action: { self.showSeasonPicker = false }, label: { Image(systemName: "xmark.circle.fill") .foregroundStyle(.white) .font(.system(size: 40)) .scaleEffect(x: 1.1) }) .padding(.bottom, 30) } } .ignoresSafeArea() } } } } } #Preview { MovieDetail(movie: exampleMovie2) } struct MovieInfoSubheadline: View { var movie: Movie var body: some View { HStack(spacing: 20){ Image(systemName: "hand.thumbsup.fill") .foregroundStyle(.white) Text(String(movie.year)) RatingView(rating: movie.rating) Text(movie.numberOfSeasonsDisplay) ZStack{ Text("HD") .foregroundStyle(.white) .font(.system(size: 12)) .bold() Rectangle() .stroke(.gray, lineWidth: 2) .frame(width: 30, height: 20) } } .foregroundStyle(.gray) .padding(.vertical, 6) } } struct RatingView: View { var rating: String var body: some View { ZStack { Rectangle() .foregroundStyle(.gray) Text(rating) .foregroundStyle(.white) .font(.system(size: 12)) .bold() } .frame(width: 50, height: 20) } } struct CastInfo: View { var movie: Movie var body: some View { VStack(spacing: 3) { HStack { Text("Cast: \(movie.cast)") Spacer() } HStack { Text("Creaters: \(movie.creaters)") Spacer() } } .font(.caption) .foregroundStyle(.gray) .padding(.vertical, 10) } } struct CurrentEpisodeInformation: View { var movie: Movie var body: some View { Group { HStack { Text(movie.episodeInfoDisplay) .bold() Spacer() } .padding(.vertical, 4) HStack { Text(movie.episodeDescriptionDisplay) .font(.subheadline) Spacer() } } } }
2
0
79
1d
Multiple async lets crash the app
Usage of multiple async lets crashes the app in a nondeterministic fashion. We are experiencing this crash in production, but it is rare. 0 libswift_Concurrency.dylib 0x20a8b89b4 swift_task_create_commonImpl(unsigned long, swift::TaskOptionRecord*, swift::TargetMetadata<swift::InProcess> const*, void (swift::AsyncContext* swift_async_context) swiftasynccall*, void*, unsigned long) + 384 1 libswift_Concurrency.dylib 0x20a8b6970 swift_asyncLet_begin + 36 We managed to isolate the issue, and we submitted a technical incident (Case-ID: 8007727). However, we were completely ignored, and referred to the developer forums. To reproduce the bug you need to run the code on a physical device and under instruments (we used swift concurrency). This bug is present on iOS 17 and 18, Xcode 15.1, 15.4 and 16 beta, swift 5 and 6, including strict concurrency. Here's the code for Swift 6 / Xcode 16 / strict concurrency: (I wanted to attach the project but for some reason I am unable to) typealias VoidHandler = () -> Void enum Fetching { case inProgress, idle } protocol PersonProviding: Sendable { func getPerson() async throws -> Person } actor PersonProvider: PersonProviding { func getPerson() async throws -> Person { async let first = getFirstName() async let last = getLastName() async let age = getAge() async let role = getRole() return try await Person(firstName: first, lastName: last, age: age, familyMemberRole: role) } private func getFirstName() async throws -> String { try await Task.sleep(nanoseconds: 1_000_000_000) return ["John", "Kate", "Alex"].randomElement()! } private func getLastName() async throws -> String { try await Task.sleep(nanoseconds: 1_400_000_000) return ["Kowalski", "McMurphy", "Grimm"].randomElement()! } private func getAge() async throws -> Int { try await Task.sleep(nanoseconds: 2_100_000_000) return [56, 24, 11].randomElement()! } private func getRole() async throws -> Person.Role { try await Task.sleep(nanoseconds: 500_000_000) return Person.Role.allCases.randomElement()! } } @MainActor final class ViewModel { private let provider: PersonProviding = PersonProvider() private var fetchingTask: Task<Void, Never>? let onFetchingChanged: (Fetching) -> Void let onPersonFetched: (Person) -> Void init(onFetchingChanged: @escaping (Fetching) -> Void, onPersonFetched: @escaping (Person) -> Void) { self.onFetchingChanged = onFetchingChanged self.onPersonFetched = onPersonFetched } func fetchData() { fetchingTask?.cancel() fetchingTask = Task { do { onFetchingChanged(.inProgress) let person = try await provider.getPerson() guard !Task.isCancelled else { return } onPersonFetched(person) onFetchingChanged(.idle) } catch { print(error) } } } } struct Person { enum Role: String, CaseIterable { case mum, dad, brother, sister } let firstName: String let lastName: String let age: Int let familyMemberRole: Role init(firstName: String, lastName: String, age: Int, familyMemberRole: Person.Role) { self.firstName = firstName self.lastName = lastName self.age = age self.familyMemberRole = familyMemberRole } } import UIKit class ViewController: UIViewController { @IBOutlet private var first: UILabel! @IBOutlet private var last: UILabel! @IBOutlet private var age: UILabel! @IBOutlet private var role: UILabel! @IBOutlet private var spinner: UIActivityIndicatorView! private lazy var viewModel = ViewModel(onFetchingChanged: { [weak self] state in switch state { case .idle: self?.spinner.stopAnimating() case .inProgress: self?.spinner.startAnimating() } }, onPersonFetched: { [weak self] person in guard let self else { return } first.text = person.firstName last.text = person.lastName age.text = "\(person.age)" role.text = person.familyMemberRole.rawValue }) @IBAction private func onTap() { viewModel.fetchData() } }
1
0
56
1d
LOCALIZED_STRING_MACRO_NAMES for Swift package targets?
I have a custom localisation function in my project that enforces the inclusion of the bundle parameter (specifically so that Swift packages are forced to include the Bundle.module value). While migrating to String Catalogs, I noticed that my custom localisation function wasn't being recognised by the automatic extraction that the Swift compiler is doing, but only in my Swift package targets. Is there a way to set something like LOCALIZED_STRING_MACRO_NAMES in Swift Packages?
1
0
152
4d
Link to a Precompiled Static C Library in a Swift Library Package
I want to build a Swift library package that uses modified build of OpenSSL and Curl. I have already statically compiled both and verified I can use them in an Objective-C framework on my target platform (iOS & iOS Simulator). I'm using XCFramework files that contain the static library binaries and headers: openssl.xcframework/ ios-arm64/ openssl.framework/ Headers/ [...] openssl ios-arm64_x86_64-simulator/ openssl.framework/ Headers/ [...] openssl Info.plist I'm not sure how I'm supposed to set up my Swift package to import these libraries. I can use .systemLibrary but that seems to use the embedded copies of libssl and libcurl on my system, and I can't figure out how to use the path: parameter to that. I also tried using a .binaryTarget pointing to the XCFramework files, but that didn't seem to work as there is no module generated and I'm not sure how to make one myself. At a basic high level, this is what I'm trying to accomplish: where libcrypto & libssl come from the provided openssl.xcframework file, and libcurl from curl.xcframework
6
0
134
5d
Swift app is failing to build with Xcode 15.4 on Sonoma Silicon
HI, I have a app with Swift Programming language. It is built successfully on my Monterey Intel by using Xcode 14. I am trying to built same app on Sonoma Silicon arm64 by using Xcode 15.4. But app is failing to build with below errors. Can anyone suggest reason for this? Copy /Users/testuser/git/agent/out/Darwin/Release/TESTFileProvider.appex/Contents/Resources/swift-nio__NIOFileSystem.bundle /Users/testuser/git/agent/out/Darwin/Release/swift-nio__NIOFileSystem.bundle (in target 'TESTFileProvider' from project 'TEST') cd /Users/testuser/git/agent/dgagent/agent/macosx/dgc/TEST builtin-copy -exclude .DS_Store -exclude CVS -exclude .svn -exclude .git -exclude .hg -resolve-src-symlinks /Users/testuser/git/agent/out/Darwin/Release/swift-nio__NIOFileSystem.bundle /Users/testuser/git/agent/out/Darwin/Release/TESTFileProvider.appex/Contents/Resources error: /Users/testuser/git/agent/out/Darwin/Release/swift-nio__NIOFileSystem.bundle: No such file or directory (in target 'TESTFileProvider' from project 'TEST') Copy /Users/testuser/git/agent/out/Darwin/Release/TESTFileProvider.appex/Contents/Resources/swift-nio_NIOPosix.bundle /Users/testuser/git/agent/out/Darwin/Release/swift-nio_NIOPosix.bundle (in target 'TESTFileProvider' from project 'TEST') cd /Users/testuser/git/agent/dgagent/agent/macosx/dgc/TEST builtin-copy -exclude .DS_Store -exclude CVS -exclude .svn -exclude .git -exclude .hg -resolve-src-symlinks /Users/testuser/git/agent/out/Darwin/Release/swift-nio_NIOPosix.bundle /Users/testuser/git/agent/out/Darwin/Release/TESTFileProvider.appex/Contents/Resources error: /Users/testuser/git/agent/out/Darwin/Release/swift-nio_NIOPosix.bundle: No such file or directory (in target 'TESTFileProvider' from project 'TEST')
1
0
126
5d
Cast Any to Sendable
I'm continuing with the migration towards Swift 6. Within one of our libraries, I want to check whether a parameter object: Any? confirms to Sendable. I tried the most obvious one: if let sendable = object as? Sendable { } But that results into the compiler error "Marker protocol 'Sendable' cannot be used in a conditional cast". Is there an other way to do this?
1
0
128
1w
iOS Developer Beta 18
I want to ask about NSDecimalNumber. is it any changes for use this function ? i test use number like this. example: a = "1000000.0" var a i make number formatter use NumberFormatter b = NSDecimalNumber(string: a with number formatter).decimalValue i try to print b. the value return 1. Anyone can help ?
4
0
117
1w
Peculiar EXC_BAD_ACCESS, involving sparse matrices
Helo all, Currently, I'm working on an iOS app that performs measurement and shows the results to the user in a graph. I use a Savitzky-Golay filter to filter out noise, so that the graph is nice and smooth. However, the code that calculates the Savitzky-Golay coefficients using sparse matrices crashes sometimes, throwing an EXC_BAD_ACCESS. I tried to find out what the problem is by turning on Address Sanitizer and Thread Sanitizer, but, for some reason, the bad access exception isn't thrown when either of these is on. What else could I try to trace back the problem? Thanks in advance, CaS To reproduce the error, run the following: import SwiftUI import Accelerate struct ContentView: View { var body: some View { VStack { Button("Try", action: test) } .padding() } func test() { for windowLength in 3...100 { let coeffs = SavitzkyGolay.coefficients(windowLength: windowLength, polynomialOrder: 2) print(coeffs) } } } class SavitzkyGolay { static func coefficients(windowLength: Int, polynomialOrder: Int, derivativeOrder: Int = 0, delta: Int = 1) -> [Double] { let (halfWindow, remainder) = windowLength.quotientAndRemainder(dividingBy: 2) var pos = Double(halfWindow) if remainder == 0 { pos -= 0.5 } let X = [Double](stride(from: Double(windowLength) - pos - 1, through: -pos, by: -1)) let P = [Double](stride(from: 0, through: Double(polynomialOrder), by: 1)) let A = P.map { exponent in X.map { pow($0, exponent) } } var B = [Double](repeating: 0, count: polynomialOrder + 1) B[derivativeOrder] = Double(factorial(derivativeOrder)) / pow(Double(delta), Double(derivativeOrder)) return leastSquaresSolution(A: A, B: B) } static func leastSquaresSolution(A: [[Double]], B: [Double]) -> [Double] { let sparseA = A.sparseMatrix() var sparseAValuesCopy = sparseA.values var xValues = [Double](repeating: 0, count: A.transpose().count) var bValues = B sparseAValuesCopy.withUnsafeMutableBufferPointer { valuesPtr in let a = SparseMatrix_Double( structure: sparseA.structure, data: valuesPtr.baseAddress! ) bValues.withUnsafeMutableBufferPointer { bPtr in xValues.withUnsafeMutableBufferPointer { xPtr in let b = DenseVector_Double( count: Int32(B.count), data: bPtr.baseAddress! ) let x = DenseVector_Double( count: Int32(A.transpose().count), data: xPtr.baseAddress! ) #warning("EXC_BAD_ACCESS is thrown below") print("This code is executed...") let status = SparseSolve(SparseLSMR(), a, b, x, SparsePreconditionerDiagScaling) print("...but, if an EXC_BAD_ACCESS is thrown, this code isn't") if status != SparseIterativeConverged { fatalError("Failed to converge. Returned with error \(status).") } } } } return xValues } } func factorial(_ n: Int) -> Int { n < 2 ? 1 : n * factorial(n - 1) } extension Array where Element == [Double] { func sparseMatrix() -> (structure: SparseMatrixStructure, values: [Double]) { let columns = self.transpose() var rowIndices: [Int32] = columns.map { column in column.indices.compactMap { indexInColumn in if column[indexInColumn] != 0 { return Int32(indexInColumn) } return nil } }.reduce([], +) let sparseColumns = columns.map { column in column.compactMap { if $0 != 0 { return $0 } return nil } } var counter = 0 var columnStarts = [Int]() for sparseColumn in sparseColumns { columnStarts.append(counter) counter += sparseColumn.count } let reducedSparseColumns = sparseColumns.reduce([], +) columnStarts.append(reducedSparseColumns.count) let structure: SparseMatrixStructure = rowIndices.withUnsafeMutableBufferPointer { rowIndicesPtr in columnStarts.withUnsafeMutableBufferPointer { columnStartsPtr in let attributes = SparseAttributes_t() return SparseMatrixStructure( rowCount: Int32(self.count), columnCount: Int32(columns.count), columnStarts: columnStartsPtr.baseAddress!, rowIndices: rowIndicesPtr.baseAddress!, attributes: attributes, blockSize: 1 ) } } return (structure, reducedSparseColumns) } func transpose() -> Self { let columns = self.count let rows = self.reduce(0) { Swift.max($0, $1.count) } return (0 ..< rows).reduce(into: []) { result, row in result.append((0 ..< columns).reduce(into: []) { result, column in result.append(row < self[column].count ? self[column][row] : 0) }) } } }
11
0
215
1w
Swift Syntax Comment Trivia - Expected prefixes
Hello! I am working on a project that does some automatic code generation using SwiftSyntax and SwiftSyntaxBuilder. As part of this project, I want to put in a comment at the top of the file warning users to not modify the file and make it obvious that the code was automatically generated. I was trying to use the .lineComment(String) static member of the Trivia (or TriviaPiece) types and I expected that the comment would automatically be prefixed with the expected // and space for use in code. (For example, Trivia.lineComment("No comment") would be written as // No Comment when sent through a BasicFormat Object or similar SyntaxRewriter). I was surprised to find that this is not the case and was wondering before I write an issue on GitHub whether this behavior is intentional or a bug. If it is intentional, I'm not entirely sure if I'm missing something regarding this to more easily generate these comments. At the moment my comment generation consists of constructing the comment in the leadingTrivia of the syntax node that appears after the comment. For example: VariableDeclSyntax(leadingTrivia: [.newlines(2), .lineComment("// These members are always generated irrespective of the contents of the generated files. They are intended to exclusively centralize code symbols that would otherwise be repeated frequently."), .newlines(1)], modifiers: [DeclModifierSyntax(name: .keyword(.private)), DeclModifierSyntax(name: .keyword(.static))], .let, name: PatternSyntax(IdentifierPatternSyntax(identifier: "decoder")), initializer: InitializerClauseSyntax(value: ExprSyntax(stringLiteral: "\(configuration.decoderExpression)"))) outputs // These members are always generated irrespective of the contents of the generated files. They are intended to exclusively centralize code symbols that would otherwise be repeated frequently. private static let decoder = JSONDecoder() in this project (with example data having been added).
1
0
157
1w
Automatic Grammar Agreement with formatted number: use integer value to switch categories
Hello, I want to use Automatic Grammar Agreement to localise a string in my app, let say "three remaining activities". The string "three" is obtained by using a NumberFormatter with a numberStyle set to .spellOut (so I'm not using an Integer) var formatter: NumberFormatter = NumberFormatter() formatter.numberStyle = .spellOut let formattedCount: String = numberFormatter.string(from: count as NSNumber)! Text("key_with_string_\(formattedCount)") In my string catalog, I have translated the key key_with_string_%@ like this ^[%@ remaining activity](inflect: true), but it does not work. I've tried to add the integer value used by the number formatter in the key key_with_string_%@_%lld but it does not work. Should Automatic Grammar Agreement work normally just by using the formatted string provided by the NumberFormatter? If not, is there a way to specify to use a secondary variable (my count integer) to switch between different categories like one and other automatically? Thanks ! Axel
1
0
161
1w
Issue with Swift and C++ Interoperability: Passing void pointer between Swift and C++
Hello everyone, I'm encountering an issue with Swift and C++ interoperability when passing a void pointer between Swift and C++ functions. When I pass pMessageBuffer (an UnsafeMutableRawPointer) from Swift to MyCppClass.NFCompletion (a static c++ function), which expects a reference to void pointer, Swift throws an error "Cannot convert value of type 'UnsafeMutableRawPointer' to expected argument type 'Optional' ". Here is a sample code to help in better visualization of the usecase. Cpp Code class MyCppClass { public: static void SendData(void *pMessage, TUInt16 pMessageLength) { // Assume vSocket is my Swift object held in C++. vSocket.Send(pMessage, pMessageLength); } static void NFCompletion(void * & pBuffer, TInt64 pErrorCode, VPtr pCompletionFunction) { // Process the buffer. } }; Swift Code: public class MySwiftClass { var vConnection: NWConnection? public init() {} public func Send(_ pMessageBuffer: UnsafeMutableRawPointer, _ pMessageLength: TSUInt16) { let messageData = Data(bytesNoCopy: pMessageBuffer, count: Int(pMessageLength), deallocator: .none) self.vConnection?.send(content: messageData, completion: .contentProcessed { nw_error in var error_code: TSInt64 = 0 if let nw_error = nw_error { error_code = self.InternalGetNetworkErrorCode(nw_error) } // Here's where the issue arises: MyCppClass.NFCompletion(pMessageBuffer, TInt64(error_code), self.uCompletionHandler) }) } // Example function to handle network errors private func InternalGetNetworkErrorCode(_ error: Error) -> TSInt64 { // Implementation to convert nw_error to TSInt64 error code return 0 // Placeholder return value } } Could someone please help me understand why this conversion error occurs? How should I correctly handle passing a void pointer between Swift and C++ functions, ensuring compatibility and proper memory management? Note: TSInt64 is typealias for swift Int and TInt64 is alias of c++ int_64t. Thank you in advance for your assistance! Regards, Harshal
1
2
144
1w
Data storage for a Matrix struct when working with Accelerate
I have a Matrix structure as defined below for working with 2D numerical data in Accelerate. The underlying numerical data in this Matrix struct is stored as an Array. struct Matrix<T> { let rows: Int let columns: Int var data: [T] init(rows: Int, columns: Int, fill: T) { self.rows = rows self.columns = columns self.data = Array(repeating: fill, count: rows * columns) } init(rows: Int, columns: Int, source: (inout UnsafeMutableBufferPointer<T>) -> Void) { self.rows = rows self.columns = columns self.data = Array(unsafeUninitializedCapacity: rows * columns) { buffer, initializedCount in source(&buffer) initializedCount = rows * columns } } subscript(row: Int, column: Int) -> T { get { return self.data[(row * self.columns) + column] } set { self.data[(row * self.columns) + column] = newValue } } } Multiplication is implemented by the functions shown below. import Accelerate infix operator .* func .* (lhs: Matrix<Double>, rhs: Matrix<Double>) -> Matrix<Double> { precondition(lhs.rows == rhs.rows && lhs.columns == rhs.columns, "Matrices must have same dimensions") let result = Matrix<Double>(rows: lhs.rows, columns: rhs.columns) { buffer in vDSP.multiply(lhs.data, rhs.data, result: &buffer) } return result } func * (lhs: Matrix<Double>, rhs: Matrix<Double>) -> Matrix<Double> { precondition(lhs.columns == rhs.rows, "Number of columns in left matrix must equal number of rows in right matrix") var a = lhs.data var b = rhs.data let m = lhs.rows // number of rows in matrices A and C let n = rhs.columns // number of columns in matrices B and C let k = lhs.columns // number of columns in matrix A; number of rows in matrix B let alpha = 1.0 let beta = 0.0 // matrix multiplication where C ← αAB + βC let c = Matrix<Double>(rows: lhs.rows, columns: rhs.columns) { buffer in cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, m, n, k, alpha, &a, k, &b, n, beta, buffer.baseAddress, n) } return c } I can also define a Matrix structure where the underlying data is an UnsafeMutableBufferPointer. The buffer is handled by the MatrixData class. struct Matrix<T> { let rows: Int let columns: Int var data: MatrixData<T> init(rows: Int, columns: Int, fill: T) { self.rows = rows self.columns = columns self.data = MatrixData(count: rows * columns, fill: fill) } init(rows: Int, columns: Int) { self.rows = rows self.columns = columns self.data = MatrixData(count: rows * columns) } subscript(row: Int, column: Int) -> T { get { return self.data.buffer[(row * self.columns) + column] } set { self.data.buffer[(row * self.columns) + column] = newValue } } } class MatrixData<T> { var buffer: UnsafeMutableBufferPointer<T> var baseAddress: UnsafeMutablePointer<T> { get { self.buffer.baseAddress! } } init(count: Int, fill: T) { let start = UnsafeMutablePointer<T>.allocate(capacity: count) self.buffer = UnsafeMutableBufferPointer(start: start, count: count) self.buffer.initialize(repeating: fill) } init(count: Int) { let start = UnsafeMutablePointer<T>.allocate(capacity: count) self.buffer = UnsafeMutableBufferPointer(start: start, count: count) } deinit { self.buffer.deinitialize() self.buffer.deallocate() } } Multiplication for this approach is implemented by the functions shown here. import Accelerate infix operator .* func .* (lhs: Matrix<Double>, rhs: Matrix<Double>) -> Matrix<Double> { precondition(lhs.rows == rhs.rows && lhs.columns == rhs.columns, "Matrices must have same dimensions") let result = Matrix<Double>(rows: lhs.rows, columns: lhs.columns) vDSP.multiply(lhs.data.buffer, rhs.data.buffer, result: &result.data.buffer) return result } func * (lhs: Matrix<Double>, rhs: Matrix<Double>) -> Matrix<Double> { precondition(lhs.columns == rhs.rows, "Number of columns in left matrix must equal number of rows in right matrix") let a = lhs.data.baseAddress let b = rhs.data.baseAddress let m = lhs.rows // number of rows in matrices A and C let n = rhs.columns // number of columns in matrices B and C let k = lhs.columns // number of columns in matrix A; number of rows in matrix B let alpha = 1.0 let beta = 0.0 // matrix multiplication where C ← αAB + βC let c = Matrix<Double>(rows: lhs.rows, columns: rhs.columns) cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, m, n, k, alpha, a, k, b, n, beta, c.data.baseAddress, n) return c } Both of these approaches give me similar performance. The only difference that I have noticed is the matrix buffer approach allows for reference semantics. For example, the code below uses half the memory with the matrix buffer approach compared to the matrix array approach. This is because b acts as a reference to a using the matrix buffer approach; otherwise, the matrix array approach makes a full copy of a. let n = 10_000 let a = Matrix<Double>(rows: n, columns: n, fill: 0) var b = a b[0, 0] = 99 b[0, 1] = 22 Other than reference semantics, are there any reasons to use one of these approaches over the other?
3
0
184
2w