Added the repeater feature we wanted for so long.

This commit is contained in:
Adam Laszlo Rocska 2023-03-01 23:23:28 +01:00
parent 49abbea360
commit 64705e7bb7
No known key found for this signature in database
GPG Key ID: D9EC1E93111AFFA7
4 changed files with 151 additions and 6 deletions

View File

@ -13,8 +13,16 @@ let package = Package(
.library(name: "Beton", targets: ["Beton"]),
.library(name: "XCTBeton", targets: ["XCTBeton"]),
],
dependencies: [
.package(url: "https://github.com/apple/swift-async-algorithms.git", from: "0.1.0"),
],
targets: [
.target(name: "Beton"),
.target(
name: "Beton",
dependencies: [
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
]
),
.target(
name: "XCTBeton",
dependencies: [

View File

@ -0,0 +1,91 @@
import Foundation
import AsyncAlgorithms
// MARK: Mappers
/// Runs the provided callback consecutively one after another,
/// passing the current iteration count as an argument,
/// and returning the array of results in iteration order.
/// - Parameters:
/// - count: Number of times to run the given function.
/// - function: The callback to execute mapping its results to the final result.
/// - Returns: An array of all the values returned by the callback.
public func repeating<T>(count: Int, _ function: (Int) -> T) -> [T] {
(0..<count).map { function($0) }
}
public typealias AsyncRepeatingChannel<T: Sendable> = AsyncChannel<(iteration: Int, result: T)> where T: Sendable
/// Runs the provided callback asynchronously,
/// passing the current iteration count as an argument,
/// and returning an AsyncSequence of the results.
/// **This function is by design out-of-order.**
/// - Parameters:
/// - count: Number of times to run the given function.
/// - function: The callback to execute, mapping results to the final result.
/// - Returns: A channel of results.
public func repeating<T>(
count: Int,
_ function: @escaping (Int) async -> T
) async -> AsyncRepeatingChannel<T> where T: Sendable {
let channel = AsyncRepeatingChannel<T>()
Task {
await withTaskGroup(of: Void.self) { group in
for i in 0..<count {
group.addTask { await channel.send((i, function(i))) }
}
}
channel.finish()
}
return channel
}
// MARK: Resolvers
/// Runs the provided callback consecutively one after another, returning the array of results in iteration order.
/// - Parameters:
/// - count: Number of times to run the given function.
/// - function: The callback to execute mapping its results to the final result.
/// - Returns: An array of all the values returned by the callback.
public func repeating<T>(
count: Int,
_ function: @autoclosure () -> T
) -> [T] {
repeating(count: count) { _ in function() }
}
/// Runs the provided callback asynchronously, returning the results.
/// **This function is by design out-of-order.**
/// - Parameters:
/// - count: Number of times to run the given function.
/// - function: The callback to execute mapping its results to the final result.
/// - Returns: A channel of all the values returned by the callback.
public func repeating<T>(
count: Int,
_ function: @escaping @autoclosure () async -> T
) async -> AsyncRepeatingChannel<T> where T: Sendable {
await repeating(count: count) { _ in await function()}
}
// MARK: Performers
/// Runs the provided callback `count` number of times, ignoring its results.
/// - Parameters:
/// - count: Number of times to run the given function.
/// - function: The callback to execute `count` times.
public func repeating(count: Int, _ function: @autoclosure () -> ()) {
let _ = repeating(count: count) { [function] _ in function() }
}
/// Runs asynchronously the provided callback `count` number of times, ignoring the results.
/// - Parameters:
/// - count: Number of times to run the given function.
/// - function: The callback to execute `count` times
public func repeating(
count: Int,
_ function: @autoclosure @escaping () async -> ()
) async {
let _ = await repeating(count: count) { _ in await function() }
}

View File

@ -5,7 +5,7 @@ class BundleTest: XCTestCase {
override func tearDown() {
super.tearDown()
XCTAssertMetric(.cpu, .cycles, .average(maximum: 5000))
XCTAssertMetric(.cpu, .instructionsRetired, .average(maximum: 4500))
XCTAssertMetric(.cpu, .instructionsRetired, .average(maximum: 10_000))
XCTAssertMetric(.cpu, .time, .average(maximum: 0.002))
XCTAssertMetric(.memory, .physical, .average(maximum: 60))
XCTAssertMetric(.memory, .physicalPeak, .average(maximum: 0))
@ -15,25 +15,25 @@ class BundleTest: XCTestCase {
func testLocalizationBundles() {
measure(metrics: .defaults) {
Bundle.module.localizationBundles
let _ = Bundle.module.localizationBundles
}
}
func testLocalizedString_keyOnly() {
measure(metrics: .defaults) {
Bundle.module.localizedString("Test")
let _ = Bundle.module.localizedString("Test")
}
}
func testLocalizedString_keyAndTableOnly() {
measure(metrics: .defaults) {
Bundle.module.localizedString("Test", from: "Test")
let _ = Bundle.module.localizedString("Test", from: "Test")
}
}
func testLocalizedString_keyAndValueOnly() {
measure(metrics: .defaults) {
Bundle.module.localizedString("Test", fallback: "Test")
let _ = Bundle.module.localizedString("Test", fallback: "Test")
}
}

View File

@ -0,0 +1,46 @@
@testable import Beton
import XCTBeton
class RepeatingTests: XCTestCase {
func testRepeating_sync_mapper () {
XCTAssertEqual(repeating(count: 3) { $0 + 5 }, [5, 6, 7])
XCTAssertEqual(repeating(count: 3) { $0 + 10 }, [10, 11, 12])
XCTAssertEqual(repeating(count: 5) { $0 + 5 }, [5, 6, 7, 8, 9])
XCTAssertEqual(repeating(count: 5) { $0 + 10 }, [10, 11, 12, 13, 14])
}
func testRepeating_sync_resolver () {
XCTAssertEqual(repeating(count: 3, 5), [5, 5, 5,])
XCTAssertEqual(repeating(count: 3, 10), [10, 10, 10])
XCTAssertEqual(repeating(count: 5, 5), [5, 5, 5, 5, 5,])
XCTAssertEqual(repeating(count: 5, 10), [10, 10, 10, 10, 10])
}
func testRepeating_sync_performer() {
var counter = 0
repeating(count: 3, counter += 1)
XCTAssertEqual(counter, 3)
repeating(count: 5, counter += 2)
XCTAssertEqual(counter, 13)
}
func testRepeating_async_mapper() async throws {
for try await item in await repeating(count: 10, { $0 + 5 }) {
XCTAssertEqual(item.result, item.iteration + 5)
}
}
func testRepeating_async_resolver() async throws {
for try await item in await repeating(count: 10, 100) {
XCTAssertEqual(item.result, 100)
}
}
func testRepeating_async_performer() async throws {
var a = [Int]()
await repeating(count: 13, a.append(1))
print(a)
}
}