diff --git a/.sourcekit-lsp/config.json b/.sourcekit-lsp/config.json new file mode 100644 index 0000000..01bacd8 --- /dev/null +++ b/.sourcekit-lsp/config.json @@ -0,0 +1,5 @@ +{ + "swiftPM": { + "cCompilerFlags:" ["-DPFFFT_SCALVEC_ENABLED=1", "-DPFFFT_ENABLE_NEON", "_USE_MATH_DEFINES", "NDEBUG"], + } +} diff --git a/README.md b/README.md index 93f62be..af73687 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ performance with much simpler usage and a permissive 3 clause BSD license. let fft = try FFT>(n: 16) let signal = fft.makeSignalBuffer() -signal.mapInPlace { (i, v) in +signal.enumerateInPlace { (i, v) in v = Complex(Float(i) + 1.0, Float(i) - 2.0) } diff --git a/Sources/PFFFT/Buffer.swift b/Sources/PFFFT/Buffer.swift index d95b6be..3c7be98 100644 --- a/Sources/PFFFT/Buffer.swift +++ b/Sources/PFFFT/Buffer.swift @@ -3,6 +3,10 @@ import RealModule let bufferAlignment = 32 +/// Thin wrapper around `UnsafeMutableBufferPointer` providing correct alignment. +/// PFFFT internally assumes all buffers passed are aligned to 16 or 32 bytes +/// depending on the platform. Thie type provides correctly aligned buffers +/// and provides some in place mutating methods. @frozen public struct Buffer: ~Copyable { public let buffer: UnsafeMutableBufferPointer @@ -32,11 +36,19 @@ public struct Buffer: ~Copyable { try body(UnsafeMutableRawBufferPointer(buffer)) } + /// Return an array with results of mapping given closure over buffer elements. + /// - Parameter transform: A mapping closure. `transform` accepts an element of the buffer + /// as its parameter and returns a transformed value of any type. + /// - Returns: An array containing the transformed elements of the buffer. @inlinable public func map(_ transform: (T) throws -> U) rethrows -> [U] { try buffer.map(transform) } - @inlinable public func mapInPlace(_ body: (Int, inout T) throws -> Void) rethrows { + /// Calls the given closure on each element in the buffer for mutation in place. + /// - Parameter body: A closure that accepts a zero-based index and mutable element of the + /// buffer as a parameter. `body` may throw and the error will be propagated to the + /// caller. Any return value of the closure is discarded. + @inlinable public func enumerateInPlace(_ body: (Int, inout T) throws -> Void) rethrows { for i in 0 ..< buffer.count { try body(i, &buffer[i]) } @@ -52,7 +64,21 @@ public protocol ComplexType { extension Complex: ComplexType {} public extension Buffer where T: ComplexType { - @inlinable func mapInPlaceSwapLast(_ body: (Int, inout T) throws -> Void) rethrows { + /// Calls the given closure on each element in the buffer for mutation in place with + /// Nyquist replacement at the end. + /// + /// When operating on Complex->Real transforms PFFFT internally uses a slightly more compact + /// but less common encoding of the DC (0) and Nyquist (n/2) components. Since these two + /// spectral components are always real, PFFFT places the DC (0) component + /// in the real part of the 0th element as expected, but places the Nyquist `(n/2)` component + /// in the imaginary part of the 0th element. + /// This enumerator works like `enumerateInPlace` but at the end places the real part of the + /// n/2 component into the imaginary part of the 0th element. In normal use it is expected + /// that a spectral buffer of 1 extra element is created suct that `count == (n/2 + 1)`. + /// - Parameter body: A closure that accepts a zero-based index and mutable element of the + /// buffer as a parameter. `body` may throw and the error will be propagated to the + /// caller. Any return value of the closure is discarded. + @inlinable func enumerateInPlaceSwapLast(_ body: (Int, inout T) throws -> Void) rethrows { for i in 0 ..< buffer.count { try body(i, &buffer[i]) } diff --git a/Tests/PFFFTTests/PFFFTTests.swift b/Tests/PFFFTTests/PFFFTTests.swift index f7c54b2..9c37cfc 100644 --- a/Tests/PFFFTTests/PFFFTTests.swift +++ b/Tests/PFFFTTests/PFFFTTests.swift @@ -3,12 +3,12 @@ import ComplexModule import XCTest final class FFTTests: XCTestCase { - func testFftFloat() throws { + func testFftComplexFloat() throws { let fft = try FFT>(n: 16) let signal = fft.makeSignalBuffer() let spectrum = fft.makeSpectrumBuffer() - signal.mapInPlace { i, v in + signal.enumerateInPlace { i, v in v = Complex(Float(i) + 1.0, Float(i) - 2.0) }