diff --git a/Package.swift b/Package.swift index 8ca463a..ac8b170 100644 --- a/Package.swift +++ b/Package.swift @@ -13,21 +13,21 @@ let package = Package( ], products: [ .library( - name: "SwiftConcurrentSequence", - targets: ["SwiftConcurrentSequence"] + name: "ConcurrentSequence", + targets: ["ConcurrentSequence"] ), ], targets: [ .target( - name: "SwiftConcurrentSequence", + name: "ConcurrentSequence", dependencies: [], swiftSettings: [ .swiftLanguageMode(.v6), ] ), .testTarget( - name: "SwiftConcurrentSequenceTests", - dependencies: ["SwiftConcurrentSequence"], + name: "ConcurrentSequenceTests", + dependencies: ["ConcurrentSequence"], swiftSettings: [ .swiftLanguageMode(.v6), ] diff --git a/Sources/SwiftConcurrentSequence/ConcurrentMap.swift b/Sources/ConcurrentSequence/ConcurrentMap.swift similarity index 80% rename from Sources/SwiftConcurrentSequence/ConcurrentMap.swift rename to Sources/ConcurrentSequence/ConcurrentMap.swift index 5bc43a6..d9a8588 100644 --- a/Sources/SwiftConcurrentSequence/ConcurrentMap.swift +++ b/Sources/ConcurrentSequence/ConcurrentMap.swift @@ -30,25 +30,38 @@ extension Sequence where Element: Sendable { /// over the sequence's elements. The given closure is executed concurrently /// on multiple queues to reduce the wall-time consumed by the transform. /// + /// Example: + /// ```swift + /// let numbers = [1, 2, 3, 4, 5] + /// let squared = numbers.concurrentMap { $0 * $0 } + /// // Result: [1, 4, 9, 16, 25] + /// ``` + /// /// - Parameter transform: A mapping closure. `transform` accepts an /// element of this sequence as its parameter and returns a transformed /// value of the same or of a different type. - /// - Returns: An array containing the transformed elements of this - /// sequence. + /// - Returns: An array containing the transformed elements of this sequence in their original order. public func concurrentMap(_ transform: @Sendable (Element) -> T) -> [T] { Array(self).concurrentMap(transform) } #endif - /// Returns an array containing the results of mapping the given closure + /// Returns an array containing the results of mapping the given async closure /// over the sequence's elements. The given closure is executed concurrently - /// on multiple queues to reduce the wall-time consumed by the transform. + /// using Swift's structured concurrency to reduce wall-time. + /// + /// Example: + /// ```swift + /// let urls = ["url1", "url2", "url3"] + /// let responses = await urls.concurrentMap { url in + /// try await fetchData(from: url) + /// } + /// ``` /// - /// - Parameter transform: A mapping closure. `transform` accepts an + /// - Parameter transform: An async mapping closure. `transform` accepts an /// element of this sequence as its parameter and returns a transformed /// value of the same or of a different type. - /// - Returns: An array containing the transformed elements of this - /// sequence. + /// - Returns: An array containing the transformed elements of this sequence in their original order. @_disfavoredOverload public func concurrentMap(_ transform: @escaping @Sendable (Element) async throws -> T) async rethrows -> [T] { try await Array(self).concurrentMap(transform) @@ -63,11 +76,17 @@ extension Array where Element: Sendable { /// over the sequence's elements. The given closure is executed concurrently /// on multiple queues to reduce the wall-time consumed by the transform. /// + /// Example: + /// ```swift + /// let numbers = [1, 2, 3, 4, 5] + /// let squared = numbers.concurrentMap { $0 * $0 } + /// // Result: [1, 4, 9, 16, 25] + /// ``` + /// /// - Parameter transform: A mapping closure. `transform` accepts an /// element of this sequence as its parameter and returns a transformed /// value of the same or of a different type. - /// - Returns: An array containing the transformed elements of this - /// sequence. + /// - Returns: An array containing the transformed elements of this sequence in their original order. public func concurrentMap(_ transform: @Sendable (Element) -> T) -> [T] { // Create a buffer where we can store the transformed output. var transformed = [T?](repeating: nil, count: count) @@ -83,15 +102,22 @@ extension Array where Element: Sendable { } #endif - /// Returns an array containing the results of mapping the given closure + /// Returns an array containing the results of mapping the given async closure /// over the sequence's elements. The given closure is executed concurrently - /// on multiple queues to reduce the wall-time consumed by the transform. + /// using Swift's structured concurrency to reduce wall-time. + /// + /// Example: + /// ```swift + /// let endpoints: [URL] = […] + /// let responses = await endpoints.concurrentMap { url in + /// try await fetchData(from: url) + /// } + /// ``` /// - /// - Parameter transform: A mapping closure. `transform` accepts an + /// - Parameter transform: An async mapping closure. `transform` accepts an /// element of this sequence as its parameter and returns a transformed /// value of the same or of a different type. - /// - Returns: An array containing the transformed elements of this - /// sequence. + /// - Returns: An array containing the transformed elements of this sequence in their original order. @_disfavoredOverload public func concurrentMap(_ transform: @escaping @Sendable (Element) async throws -> T) async rethrows -> [T] { try await withThrowingTaskGroup( diff --git a/Sources/SwiftConcurrentSequence/ConcurrentReduce.swift b/Sources/ConcurrentSequence/ConcurrentReduce.swift similarity index 71% rename from Sources/SwiftConcurrentSequence/ConcurrentReduce.swift rename to Sources/ConcurrentSequence/ConcurrentReduce.swift index 2e9e22f..5680385 100644 --- a/Sources/SwiftConcurrentSequence/ConcurrentReduce.swift +++ b/Sources/ConcurrentSequence/ConcurrentReduce.swift @@ -30,9 +30,17 @@ extension Sequence where Element: Sendable { /// given closure. The given closure is executed concurrently /// on multiple queues to reduce the wall-time consumed by the reduction. /// - /// Use the `reduce(into:_:)` method to produce a single value from the - /// elements of an entire sequence. For example, you can use this method on an - /// array of integers to filter adjacent equal entries or count frequencies. + /// This synchronous method uses Grand Central Dispatch to parallelize the reduction + /// by recursively combining pairs of elements until a single result remains. + /// + /// Example: + /// ```swift + /// let numbers = [1, 2, 3, 4, 5] + /// let sum = numbers.concurrentReduce(defaultValue: 0) { accumulator, value in + /// accumulator += value + /// } + /// // Result: 15 + /// ``` /// /// - Parameters: /// - defaultValue: A default value for Element. This value is utilized only @@ -74,17 +82,24 @@ extension Sequence where Element: Sendable { /// using the given closure. The given closure is executed concurrently /// on multiple queues to reduce the wall-time consumed by the reduction. /// - /// Use the `reduce(into:_:)` method to produce a single value from the - /// elements of an entire sequence. For example, you can use this method on an - /// array of integers to filter adjacent equal entries or count frequencies. + /// This specialized method merges dictionaries with custom conflict resolution + /// for duplicate keys. /// - /// - Parameters: - /// - defaultValue: A default value for Element. This value is utilized only - /// when the receiver is empty. - /// - combine: A closure that returns the desired value for - /// the given key when multiple values are present for the given key. - /// - Returns: The final reduced value. If the sequence has no elements, - /// the result is `defaultValue`. + /// Example: + /// ```swift + /// let dictionaries = [ + /// ["apple": 1, "banana": 2], + /// ["apple": 3, "cherry": 5] + /// ] + /// let merged = dictionaries.concurrentReduce { key, first, second in + /// return first + second // Sum values for duplicate keys + /// } + /// // Result: ["apple": 4, "banana": 2, "cherry": 5] + /// ``` + /// + /// - Parameter combine: A closure that returns the desired value for + /// the given key when multiple values are present for the given key. + /// - Returns: The final reduced dictionary. public func concurrentReduce( combine: @Sendable (Key, Value, Value) -> Value ) -> Element where Element == [Key: Value] { @@ -101,20 +116,24 @@ extension Sequence where Element: Sendable { #endif /// Returns the result of combining the elements of the sequence using the - /// given closure. The given closure is executed concurrently - /// on multiple queues to reduce the wall-time consumed by the reduction. + /// given async closure. The given closure is executed concurrently + /// using Swift's structured concurrency to reduce wall-time. /// - /// Use the `reduce(into:_:)` method to produce a single value from the - /// elements of an entire sequence. For example, you can use this method on an - /// array of integers to filter adjacent equal entries or count frequencies. + /// This asynchronous method uses task groups to parallelize the reduction + /// by recursively combining pairs of elements until a single result remains. + /// + /// Example: + /// ```swift + /// let files: [URL] = […] + /// let mergedFileContents = await endpoints.concurrentReduce(defaultValue: FileContents()) { accumulated, file in + /// try await accumulated.merge(readData(from: file)) + /// } + /// ``` /// /// - Parameters: /// - defaultValue: A default value for Element. This value is utilized only /// when the receiver is empty. - /// - reducingIntoFirst: A closure that combines an accumulating value and - /// an element of the sequence into a new reduced value, to be used - /// in the next call of the `reducingIntoFirst` closure or returned to - /// the caller. + /// - reducer: A closure that combines two elements into a new reduced value. /// - Returns: The final reduced value. If the sequence has no elements, /// the result is `defaultValue`. public func concurrentReduce( @@ -155,20 +174,24 @@ extension Sequence where Element: Sendable { } /// Returns the result of combining the elements of the sequence of dictionaries - /// using the given closure. The given closure is executed concurrently - /// on multiple queues to reduce the wall-time consumed by the reduction. + /// using the given async closure. The given closure is executed concurrently + /// using Swift's structured concurrency to reduce wall-time. /// - /// Use the `reduce(into:_:)` method to produce a single value from the - /// elements of an entire sequence. For example, you can use this method on an - /// array of integers to filter adjacent equal entries or count frequencies. + /// This specialized async method merges dictionaries with custom conflict resolution + /// for duplicate keys. /// - /// - Parameters: - /// - defaultValue: A default value for Element. This value is utilized only - /// when the receiver is empty. - /// - combine: A closure that returns the desired value for - /// the given key when multiple values are present for the given key. - /// - Returns: The final reduced value. If the sequence has no elements, - /// the result is `defaultValue`. + /// Example: + /// ```swift + /// let userGroups = await fetchUserGroups() // Returns [[String: User]] + /// let mergedUsers = await userGroups.concurrentReduce { key, user1, user2 in + /// // Custom logic to merge duplicate users + /// return user1.updatedAt > user2.updatedAt ? user1 : user2 + /// } + /// ``` + /// + /// - Parameter combine: A closure that returns the desired value for + /// the given key when multiple values are present for the given key. + /// - Returns: The final reduced dictionary. public func concurrentReduce( combine: @escaping @Sendable (Key, Value, Value) throws -> Value ) async rethrows -> Element where Element == [Key: Value] { diff --git a/Tests/SwiftConcurrentSequenceTests/ConcurrentMapTests.swift b/Tests/ConcurrentSequenceTests/ConcurrentMapTests.swift similarity index 98% rename from Tests/SwiftConcurrentSequenceTests/ConcurrentMapTests.swift rename to Tests/ConcurrentSequenceTests/ConcurrentMapTests.swift index 1d2883a..f8ed9f7 100644 --- a/Tests/SwiftConcurrentSequenceTests/ConcurrentMapTests.swift +++ b/Tests/ConcurrentSequenceTests/ConcurrentMapTests.swift @@ -20,7 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import SwiftConcurrentSequence +import ConcurrentSequence import Testing struct ConcurrentMapTests { diff --git a/Tests/SwiftConcurrentSequenceTests/ConcurrentReduceTests.swift b/Tests/ConcurrentSequenceTests/ConcurrentReduceTests.swift similarity index 98% rename from Tests/SwiftConcurrentSequenceTests/ConcurrentReduceTests.swift rename to Tests/ConcurrentSequenceTests/ConcurrentReduceTests.swift index 6cf7370..3071d28 100644 --- a/Tests/SwiftConcurrentSequenceTests/ConcurrentReduceTests.swift +++ b/Tests/ConcurrentSequenceTests/ConcurrentReduceTests.swift @@ -20,7 +20,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import SwiftConcurrentSequence +import ConcurrentSequence import Testing struct ConcurrentReduceTests {