| 117 | |
| 118 | template <typename T> |
| 119 | class CollectProcess : public Process<CollectProcess<T>> |
| 120 | { |
| 121 | public: |
| 122 | CollectProcess( |
| 123 | const std::vector<Future<T>>& _futures, |
| 124 | Promise<std::vector<T>>* _promise) |
| 125 | : ProcessBase(ID::generate("__collect__")), |
| 126 | futures(_futures), |
| 127 | promise(_promise), |
| 128 | ready(0) {} |
| 129 | |
| 130 | ~CollectProcess() override |
| 131 | { |
| 132 | delete promise; |
| 133 | } |
| 134 | |
| 135 | protected: |
| 136 | void initialize() override |
| 137 | { |
| 138 | // Stop this nonsense if nobody cares. |
| 139 | promise->future().onDiscard(defer(this, &CollectProcess::discarded)); |
| 140 | |
| 141 | foreach (const Future<T>& future, futures) { |
| 142 | future.onAny(defer(this, &CollectProcess::waited, lambda::_1)); |
| 143 | future.onAbandoned(defer(this, &CollectProcess::abandoned)); |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | private: |
| 148 | void abandoned() |
| 149 | { |
| 150 | // There is no use waiting because this future will never complete |
| 151 | // so terminate this process which will cause `promise` to get |
| 152 | // deleted and our future to also be abandoned. |
| 153 | terminate(this); |
| 154 | } |
| 155 | |
| 156 | void discarded() |
| 157 | { |
| 158 | foreach (Future<T> future, futures) { |
| 159 | future.discard(); |
| 160 | } |
| 161 | |
| 162 | // NOTE: we discard the promise after we set discard on each of |
| 163 | // the futures so that there is a happens-before relationship that |
| 164 | // can be assumed by callers. |
| 165 | promise->discard(); |
| 166 | |
| 167 | terminate(this); |
| 168 | } |
| 169 | |
| 170 | void waited(const Future<T>& future) |
| 171 | { |
| 172 | if (future.isFailed()) { |
| 173 | promise->fail("Collect failed: " + future.failure()); |
| 174 | terminate(this); |
| 175 | } else if (future.isDiscarded()) { |
| 176 | promise->fail("Collect failed: future discarded"); |
nothing calls this directly
no outgoing calls
no test coverage detected