//
// Created by Pierre Lebeaupin on 17/01/2021.
// Copyright © 2021 Pierre Lebeaupin. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
import Foundation;
@available(macOS 12.0.0, iOS 15.0, *)
struct ReadyValueNonGCD:Sendable {
let value: UInt32;
let op: Op?;
let description: @Sendable () -> String;
// Note that as a closure, it can depend on more than the stored properties, contrary to a
// computed property.
init(_ inValue: UInt32) {
value = inValue;
op = nil;
description = { return inValue.description;};
}
init(value inValue: UInt32, op inOp: Op, description indescription: @escaping @Sendable () -> String) {
value = inValue;
op = inOp;
description = indescription;
}
}
@available(macOS 12.0.0, iOS 15.0, *)
func resolveCoreNonGCD(_ injectedDispatcher: DispatcherAsync, _ primitives: [UInt32]) async {
var referenceL = [ReadyValueNonGCD]();
var referenceComposedCount = 0;
var referenceOtherComposedCount = 0;
for element in primitives {
referenceL.append(.init(element));
}
await exploreAdditionOfFloorAsync(&referenceL,
&referenceComposedCount,
&referenceOtherComposedCount,
injectedDispatcher,
kind: .additive);
await exploreAdditionOfFloorAsync(&referenceL,
&referenceComposedCount,
&referenceOtherComposedCount,
injectedDispatcher,
kind: .multiplicative);
}
//
// Created by Pierre Lebeaupin on 16/07/2021.
// Copyright © 2021 Pierre Lebeaupin. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
import Foundation;
import os;
typealias DispatcherAsync = (_ l: inout [ReadyValueNonGCD],
_ composedCount: inout Int,
_ otherComposedCount: inout Int,
_ decomposedValue: inout [Bool:UInt32],
_ downstreamSiblingsRecruitmentSkip: inout Int,
_ kind: Op,
_ startingFrom: Int,
_ walkOperands: @escaping @Sendable (_ action: (_ value: ReadyValueNonGCD, _ reverse: Bool) -> Void?) -> Void?) async -> Void;
typealias DispatcherPseudoReasync = (_ l: inout [ReadyValueNonGCD],
_ composedCount: inout Int,
_ otherComposedCount: inout Int,
_ decomposedValue: inout [Bool:UInt32],
_ downstreamSiblingsRecruitmentSkip: inout Int,
_ kind: Op,
_ startingFrom: Int,
_ walkOperands: @escaping @Sendable (_ action: (_ value: ReadyValueNonGCD, _ reverse: Bool) -> Void?) -> Void?) -> Void;
// Despite https://github.com/apple/swift-evolution/blob/main/proposals/0309-unlock-existential-types-for-all-protocols.md
// I am unable to do the following, even with Xcode 13.2.1: I get the error that:
// "Protocol 'AsyncStringIteratorProtocol' can only be used as a generic constraint because it has Self or associated type requirements"
// Update: with Xcode 14.2 I get "No type for 'Self.AsyncIterator' can satisfy both 'Self.AsyncIterator == any AsyncStringIteratorProtocol' and 'Self.AsyncIterator : AsyncIteratorProtocol'"
#if false
protocol AsyncStringIteratorProtocol: AsyncIteratorProtocol where Element == String {
}
protocol AsyncStringSequence: AsyncSequence where Element == String, AsyncIterator == any AsyncStringIteratorProtocol {
}
#endif
struct AnyAsyncIterator<A>: AsyncIteratorProtocol {
typealias Element = A;
mutating func next() async throws -> A? {
return await inner.next();
}
fileprivate var inner: AsyncStream<A>.AsyncIterator;
}
struct AnyAsyncSequence<A>: AsyncSequence {
typealias Element = A;
typealias AsyncIterator = AnyAsyncIterator<A>;
__consuming func makeAsyncIterator() -> AnyAsyncIterator<A> {
return .init(inner: inner.makeAsyncIterator());
}
fileprivate var inner: AsyncStream<A>;
}
@available(macOS 12.0, iOS 15.0, *) struct Channel: BatchIteratorProtocol {
enum PayloadOrOutOfBand<Payload, OutOfBand> {
case payload(Payload)
case outOfBand(OutOfBand)
}
struct Sink {
var limiter: AsyncStream<Void>.Iterator;
var sinkHole: AsyncStream<PayloadOrOutOfBand<Task<Void, Never>, AsyncStream<Void>.Continuation>>.Continuation;
mutating func yield(microbatch: Task<Void, Never>) async {
sinkHole.yield(.payload(microbatch));
_ = await limiter.next();
}
}
var source: AsyncStream<PayloadOrOutOfBand<Task<Void, Never>, AsyncStream<Void>.Continuation>>.Iterator;
var limiterContinuation: AsyncStream<Void>.Continuation;
//var rootTask: Task<Void, Never>;
init(exec: @Sendable @escaping (_ sink: inout Sink) async -> Void) async {
var tempsource = AsyncStream(PayloadOrOutOfBand<Task<Void, Never>, AsyncStream<Void>.Continuation>.self,
bufferingPolicy: .bufferingNewest(1),
{ (firstContinuaton) in
/*let localRoot =*/ Task {
var param = Sink(limiter: AsyncStream(Void.self,
bufferingPolicy: .bufferingNewest(1),
{
firstContinuaton.yield(.outOfBand($0));
}).makeAsyncIterator(),
sinkHole: firstContinuaton);
_ = await param.limiter.next();
await exec(¶m);
param.sinkHole.finish();
}
//firstContinuaton.yield(.outOfBand(.outOfBand(localRoot)));
}).makeAsyncIterator();
var tempLimiterContinuation: AsyncStream<Void>.Continuation?;
//var tempRootTask: Task<Void, Never>?;
//while (tempLimiterContinuation == nil) || (tempRootTask == nil) {
// The two types of out of band data may come in any order…
guard case let .outOfBand(drop) = await tempsource.next() else {
fatalError();
}
tempLimiterContinuation = drop;
/*switch drop {
case let .payload(inContinuation):
guard tempLimiterContinuation == nil else {
fatalError();
}
tempLimiterContinuation = inContinuation;
case let .outOfBand(inTask):
guard tempRootTask == nil else {
fatalError();
}
tempRootTask = inTask;
}*/
//}
//rootTask = tempRootTask!
limiterContinuation = tempLimiterContinuation!;
source = tempsource;
}
mutating func provide() async -> Task<Void, Never>? {
limiterContinuation.yield(());
guard let rawDrop = await source.next() else {
return nil;
}
guard case let .payload(drop) = rawDrop else {
fatalError();
}
return drop;
}
/*mutating func invalidate() {
rootTask.cancel();
}*/
}
@available(macOS 12.0, iOS 15.0, *) func resolveAsync(_ startGoal: UInt32, _ primitives: UInt32...) async -> AnyAsyncSequence<String> {
return .init(inner: .init(String.self) { resultContinuation in
let _ = Computer(exec: { () -> Channel in
return await Channel(exec: { (sink) in
let resultReceiver = { @Sendable (result: String) -> Void in resultContinuation.yield(result);};
@Sendable func iteratePossibleLeftNodesFakeDispatchAsync(_ l: inout [ReadyValueNonGCD],
_ composedCount: inout Int,
_ otherComposedCount: inout Int,
_ decomposedValue: inout [Bool:UInt32],
_ downstreamSiblingsRecruitmentSkip: inout Int,
_ kind: Op,
_ startingFrom: Int,
_ walkOperands: @escaping @Sendable (_ action: (_ value: ReadyValueNonGCD, _ reverse: Bool) -> Void?) -> Void?) async {
await iteratePossibleLeftNodesAsync(&l,
&composedCount,
&otherComposedCount,
&decomposedValue,
&downstreamSiblingsRecruitmentSkip,
resultReceiver,
startGoal,
kind,
startingFrom,
walkOperands,
iteratePossibleLeftNodesFakeDispatchAsync);
}
@Sendable func iteratePossibleLeftNodesFakeDispatchPseudoReasync(_ l: inout [ReadyValueNonGCD],
_ composedCount: inout Int,
_ otherComposedCount: inout Int,
_ decomposedValue: inout [Bool:UInt32],
_ downstreamSiblingsRecruitmentSkip: inout Int,
_ kind: Op,
_ startingFrom: Int,
_ walkOperands: @escaping @Sendable (_ action: (_ value: ReadyValueNonGCD, _ reverse: Bool) -> Void?) -> Void?) {
iteratePossibleLeftNodesPseudoReasync(&l,
&composedCount,
&otherComposedCount,
&decomposedValue,
&downstreamSiblingsRecruitmentSkip,
resultReceiver,
startGoal,
kind,
startingFrom,
walkOperands,
iteratePossibleLeftNodesFakeDispatchPseudoReasync);
}
/* We need to maintain our own task group so that we may properly signal to resultContinuation
when no more result is to be expected. */
await withTaskGroup(of: Void.self) { group in
func iteratePossibleLeftNodesDispatch(_ l: inout [ReadyValueNonGCD],
_ composedCount: inout Int,
_ otherComposedCount: inout Int,
_ decomposedValue: inout [Bool:UInt32],
_ downstreamSiblingsRecruitmentSkip: inout Int,
_ kind: Op,
_ startingFrom: Int,
_ walkOperands: @escaping @Sendable (_ action: (_ value: ReadyValueNonGCD, _ reverse: Bool) -> Void?) -> Void?) async {
// reseat this divergence over a copy of the whole state
let paramL = l;
let paramComposedCount = composedCount;
let paramOtherComposedCount = otherComposedCount;
let paramDecomposedValue = decomposedValue;
let paramDownstreamSiblingsRecruitmentSkip = downstreamSiblingsRecruitmentSkip;
let task = Task {
/* Note that it is safe to key on the current thread, for the reason that
there is no suspension point between .begin and .end: this implies that this
is a single partial function which therefore is still on the same thread
from beginning to end, and which cannot be interspesed with other such
partial functions on the same thread either. */
os_signpost(.begin, log: LogWrapper.gObservationHandle, name: "micro-batch", signpostID: OSSignpostID(log: LogWrapper.gObservationHandle, object: Thread.current));
var childL = paramL;
var childComposedCount = paramComposedCount;
var childOtherComposedCount = paramOtherComposedCount;
var childDecomposedValue = paramDecomposedValue;
var childDownstreamSiblingsRecruitmentSkip = paramDownstreamSiblingsRecruitmentSkip;
iteratePossibleLeftNodesPseudoReasync(&childL,
&childComposedCount,
&childOtherComposedCount,
&childDecomposedValue,
&childDownstreamSiblingsRecruitmentSkip,
resultReceiver,
startGoal,
kind,
startingFrom,
walkOperands,
iteratePossibleLeftNodesFakeDispatchPseudoReasync);
os_signpost(.end, log: LogWrapper.gObservationHandle, name: "micro-batch", signpostID: OSSignpostID(log: LogWrapper.gObservationHandle, object: Thread.current));
}
group.addTask {
return await withTaskCancellationHandler(operation: {return await task.value;},
onCancel: {task.cancel(); return;});
}
await sink.yield(microbatch: task);
}
func iteratePossibleLeftNodesDispatchLoop(_ l: inout [ReadyValueNonGCD],
_ composedCount: inout Int,
_ otherComposedCount: inout Int,
_ decomposedValue: inout [Bool:UInt32],
_ downstreamSiblingsRecruitmentSkip: inout Int,
_ kind: Op,
_ startingFrom: Int,
_ walkOperands: @escaping @Sendable (_ action: (_ value: ReadyValueNonGCD, _ reverse: Bool) -> Void?) -> Void?) async {
/* 1: Peek a bit: if we find out from startingFrom that no further left node is
going to be able to be added anyway (and remember: closing the composition as
it stands is performed in our caller), don't bother spawning a micro-batch.
2: Use a workload estimator heuristic to try and spawn Goldilocks-sized
micro-batches:
- 6 may be too many computations to fit in a tick (1/60th of a second)
- 4 already means too few possibilities to explore
- 3 is right out
Note that among other properties, this estimator value is monotonic. */
guard startingFrom < (l.count - composedCount),
l.count + (walkOperands({_,_ in return ();}) != nil ? 1 : 0) == 5 else {
await iteratePossibleLeftNodesAsync(&l,
&composedCount,
&otherComposedCount,
&decomposedValue,
&downstreamSiblingsRecruitmentSkip,
resultReceiver,
startGoal,
kind,
startingFrom,
walkOperands,
iteratePossibleLeftNodesDispatchLoop);
return;
}
await iteratePossibleLeftNodesDispatch(&l,
&composedCount,
&otherComposedCount,
&decomposedValue,
&downstreamSiblingsRecruitmentSkip,
kind,
startingFrom,
walkOperands);
}
await resolveCoreNonGCD(iteratePossibleLeftNodesDispatchLoop, primitives);
// outstanding tasks in the group are awaited at that point, according to the spec
// https://github.com/DougGregor/swift-evolution/blob/structured-concurrency/proposals/nnnn-structured-concurrency.md
};
resultContinuation.finish();
});
});
});
}
//
// Created by Pierre Lebeaupin on 13/03/2022.
// Copyright © 2022 Pierre Lebeaupin. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
import Foundation
@available(macOS 12.0, iOS 15.0, *) protocol BatchIteratorProtocol {
mutating func provide() async -> Task<Void, Never>?;
}
@available(macOS 12.0, iOS 15.0, *) struct Computer<BatchIterator: BatchIteratorProtocol> {
init(exec: @Sendable @escaping () async -> BatchIterator) {
Task {
await withTaskGroup(of: Void.self) { group in
var outstandingTasks = UInt(0);
var iterator = await exec();
while (true) {
guard outstandingTasks < ProcessInfo.processInfo.activeProcessorCount else {
_ = await group.next();
outstandingTasks -= 1;
continue;
}
guard let newBatch = await iterator.provide() else {
break;
/* No need to manage a wind down: outstanding tasks in group are awaited
before withTaskGroup() is allowed to return. */
}
group.addTask {
return await withTaskCancellationHandler(operation: {return await newBatch.value;},
onCancel: {newBatch.cancel(); return;});
}
outstandingTasks += 1;
}
/* Note that as a result, the code will adapt in case activeProcessorCount changes.
At least, it will do so eventually, not with any sort of timeliness: for example,
if activeProcessorCount increases somehow, we will have to wait for one task to
complete before the code will work towards making outstandingTasks equal the new
value. */
};
}
}
}
//
// Created by Pierre Lebeaupin on 16/07/2021.
// Copyright © 2021 Pierre Lebeaupin. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
import Foundation
enum Op: String {
case additive = "+", multiplicative = "*";
func neutralValue() -> UInt32 {
return ((self == .additive) ? 0 : 1);
}
func combine(_ a: UInt32, _ b: UInt32) -> UInt32 {
return ((self == .additive) ? (a + b) : (a * b));
}
func uncombine(_ a: UInt32, _ b: UInt32) -> UInt32 {
return ((self == .additive) ? (a - b) : (a / b));
}
}
//
// Created by Pierre Lebeaupin on 17/01/2021.
// Copyright © 2021 Pierre Lebeaupin. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
import Foundation
import os
class LogWrapper {
static let gObservationHandle = (((getenv("net_wanderingcoder_observed")?[0] ?? 0) == 0) ? .disabled
: OSLog(subsystem: "net.wanderingcoder.projects.AsyncCountdown.AlternateParallelized",
category: "PointsOfInterest"));
}
os_log(.`default`, log: LogWrapper.gObservationHandle,
"Force resolution of log object while we still have one thread");
/* Can't even solve that with pthread_once or dispatch_once:
they are forbidden from Swift, which redirects me to lazy
global properties, which are not thread-safe. */
let fallback = {
let completion = DispatchGroup();
completion.enter();
let pseudoMainQueue = DispatchQueue(label: "pseudo main queue");
let proc = ResolveObject(6372,
pseudoMainQueue, {print($0);}, { completion.leave();}, 10, 5, 8, 3, 25, 1, 42);
//let proc = ResolveObject(4471,
// pseudoMainQueue, {print($0);}, { completion.leave();}, 75, 10, 2, 6, 7, 1, 1);
//let proc = ResolveObject(952,
// pseudoMainQueue, {print($0);}, { completion.leave();}, 25, 50, 75, 100, 3, 6);
proc.start();
completion.wait();
};
#if true
if #available(macOS 12.0, *) {
let handle = Task.detached {
let seq = await resolveAsync(4471, 75, 10, 2, 6, 7, 1, 1);
for try await result in seq {
print(result);
}
}
try! await handle.value;
} else {
fallback();
}
#else
fallback();
#endif