CommandLineToolkit

Форк
0
/
Collection+Concurrency.swift 
141 строка · 4.3 Кб
1
import Foundation
2
import Types
3

4
extension Collection where Self.Index == Int {
5
    public func throwingConcurrentMap<T, R>(
6
        mapping: (T) throws -> (R)
7
    ) throws -> [R] where T == Element {
8
        return try returnOutput(
9
            results: concurrentMap { arg -> Either<R, Error> in
10
                do {
11
                    return try Either.success(mapping(arg))
12
                } catch {
13
                    return Either.error(error)
14
                }
15
            }
16
        )
17
    }
18
    
19
    public func throwingConcurrentReduce<T, K, R>(
20
        _ initialValue: R,
21
        mapping: (T) throws -> (K),
22
        reduction: (inout R, K) throws -> ()
23
    ) throws -> R where T == Element {
24
        let result = concurrentReduce(
25
            ([Error](), initialValue),
26
            mapping: { arg -> Either<K, Error> in
27
                do {
28
                    return try Either.success(mapping(arg))
29
                } catch {
30
                    return Either.error(error)
31
                }
32
            },
33
            reduction: { errorsAndAccumulator, arg in
34
                switch arg {
35
                case let .left(output):
36
                    do {
37
                        try reduction(&errorsAndAccumulator.1, output)
38
                    } catch {
39
                        errorsAndAccumulator.0.append(error)
40
                    }
41
                case let .right(error):
42
                    errorsAndAccumulator.0.append(error)
43
                }
44
            }
45
        )
46
        let errors = result.0
47
        guard errors.isEmpty else {
48
            throw CompoundError(errors: errors)
49
        }
50
        return result.1
51
    }
52
    
53
    public func throwingConcurrentForEach<T>(
54
        perform: (T) throws -> ()
55
    ) throws where T == Element {
56
        _ = try throwingConcurrentMap(mapping: { try perform($0) })
57
    }
58
    
59
    public func concurrentMap<T, R>(
60
        mapping: (T) -> (R)
61
    ) -> [R] where T == Element {
62
        var mappingResult = [R?](repeating: nil, count: count)
63
        let lock = NSLock()
64
        DispatchQueue.concurrentPerform(
65
            iterations: count,
66
            execute: { index in
67
                let iterationResult = mapping(self[index])
68
                lock.lock()
69
                mappingResult[index] = iterationResult
70
                lock.unlock()
71
            }
72
        )
73
        return mappingResult.compactMap { $0 }
74
    }
75
    
76
    public func concurrentCompactMap<T, R>(
77
        mapping: (T) -> (R?)
78
    ) -> [R] where T == Element {
79
        var mappingResult = [R?](repeating: nil, count: count)
80
        let lock = NSLock()
81
        DispatchQueue.concurrentPerform(
82
            iterations: count,
83
            execute: { index in
84
                let optionalIterationResult = mapping(self[index])
85
                lock.lock()
86
                if let iterationResult = optionalIterationResult {
87
                    mappingResult[index] = iterationResult
88
                }
89
                lock.unlock()
90
            }
91
        )
92
        return mappingResult.compactMap { $0 }
93
    }
94

95
    public func concurrentReduce<T, K, R>(
96
        _ initialValue: R,
97
        mapping: (T) -> (K),
98
        reduction: (inout R, K) -> ()
99
    ) -> R where T == Element {
100
        var result = initialValue
101
        let lock = NSLock()
102
        DispatchQueue.concurrentPerform(
103
            iterations: count,
104
            execute: { index in
105
                let iterationResult = mapping(self[index])
106
                lock.lock()
107
                reduction(&result, iterationResult)
108
                lock.unlock()
109
            }
110
        )
111
        return result
112
    }
113
    
114
    public func concurrentForEach<T>(
115
        perform: (T) -> ()
116
    ) where T == Element {
117
        DispatchQueue.concurrentPerform(
118
            iterations: count,
119
            execute: { index in
120
                perform(self[index])
121
            }
122
        )
123
    }
124
    
125
    private func returnOutput<R>(
126
        results: [Either<R, Error>]
127
    ) throws -> [R] {
128
        let (errors, outputs) = results.reduce(into: ([Error](), [R]())) { errorsAndOutputs, result in
129
            switch result {
130
            case let .right(error):
131
                errorsAndOutputs.0.append(error)
132
            case let .left(output):
133
                errorsAndOutputs.1.append(output)
134
            }
135
        }
136
        guard errors.isEmpty else {
137
            throw CompoundError(errors: errors)
138
        }
139
        return outputs
140
    }
141
}
142

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.