A library for working with phylogenetic and population genetic data.
v0.32.0
multi_future.hpp
Go to the documentation of this file.
1 #ifndef GENESIS_UTILS_THREADING_MULTI_FUTURE_H_
2 #define GENESIS_UTILS_THREADING_MULTI_FUTURE_H_
3 
4 /*
5  Genesis - A toolkit for working with phylogenetic data.
6  Copyright (C) 2014-2024 Lucas Czech
7 
8  This program is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 3 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21  Contact:
22  Lucas Czech <lczech@carnegiescience.edu>
23  Department of Plant Biology, Carnegie Institution For Science
24  260 Panama Street, Stanford, CA 94305, USA
25 */
26 
27 /*
28  The code in this source file is inspired by BS::thread_pool,
29  see https://github.com/bshoshany/thread-pool, which we adapted it to our coding standards.
30 
31  We here hence need to include the following original license of BS::thread_pool:
32 
33  MIT License
34 
35  Copyright (c) 2022 Barak Shoshany
36 
37  Permission is hereby granted, free of charge, to any person obtaining a copy
38  of this software and associated documentation files (the "Software"), to deal
39  in the Software without restriction, including without limitation the rights
40  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
41  copies of the Software, and to permit persons to whom the Software is
42  furnished to do so, subject to the following conditions:
43 
44  The above copyright notice and this permission notice shall be included in all
45  copies or substantial portions of the Software.
46 
47  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
48  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
49  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
50  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
51  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
52  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
53  SOFTWARE.
54 */
55 
64 
65 #include <cassert>
66 #include <future>
67 #include <stdexcept>
68 #include <type_traits>
69 #include <utility>
70 #include <vector>
71 
72 namespace genesis {
73 namespace utils {
74 
75 // =================================================================================================
76 // Multi Future
77 // =================================================================================================
78 
82 template <typename T>
84 {
85 public:
86 
87  // -------------------------------------------------------------
88  // Constructors and Rule of Five
89  // -------------------------------------------------------------
90 
94  MultiFuture( size_t n = 0 )
95  : futures_( n )
96  {}
97 
98  // Copy construction deleted, as future cannot be copied
99  MultiFuture( MultiFuture const& ) = delete;
100  MultiFuture( MultiFuture&& ) = default;
101 
102  MultiFuture& operator= ( MultiFuture const& ) = delete;
103  MultiFuture& operator= ( MultiFuture&& ) = default;
104 
105  ~MultiFuture() = default;
106 
107  // -------------------------------------------------------------
108  // Members
109  // -------------------------------------------------------------
110 
115  {
116  futures_.push_back( std::move(future) );
117  }
118 
122  bool valid() const
123  {
124  for( auto const& fut : futures_ ) {
125  if( ! fut.valid() ) {
126  return false;
127  }
128  }
129  return true;
130  }
131 
138  template <typename U = T, typename std::enable_if<std::is_same<U, void>::value>::type* = nullptr>
139  void get()
140  {
141  // Internal check to see if we got the SFINAE right...
142  static_assert(
143  std::is_same<T, void>::value, "Function is meant for T == void"
144  );
145 
146  // Wait for all futures.
147  for( size_t i = 0; i < futures_.size(); ++i ) {
148  futures_[i].get();
149  }
150  return;
151  }
152 
160  template <typename U = T, typename std::enable_if< !std::is_same<U, void>::value>::type* = nullptr>
161  std::vector<T> get()
162  {
163  // Internal check to see if we got the SFINAE right...
164  static_assert(
165  ! std::is_same<T, void>::value, "Function is meant for T != void"
166  );
167 
168  // Get all futures
169  std::vector<T> result( futures_.size() );
170  for( size_t i = 0; i < futures_.size(); ++i ) {
171  result[i] = std::move( futures_[i].get() );
172  }
173  return result;
174  }
175 
179  void wait() const
180  {
181  for( size_t i = 0; i < futures_.size(); ++i ) {
182  futures_[i].wait();
183  }
184  }
185 
190  {
191  return futures_[i];
192  }
193 
197  ProactiveFuture<T> const& operator[]( size_t i ) const
198  {
199  return futures_[i];
200  }
201 
205  size_t size() const
206  {
207  return futures_.size();
208  }
209 
210  // -------------------------------------------------------------
211  // Internal Members
212  // -------------------------------------------------------------
213 
214 private:
215 
216  std::vector<ProactiveFuture<T>> futures_;
217 };
218 
219 } // namespace utils
220 } // namespace genesis
221 
222 #endif // include guard
genesis::utils::MultiFuture::operator[]
ProactiveFuture< T > const & operator[](size_t i) const
Get a const reference to one of the stored futures.
Definition: multi_future.hpp:197
genesis::utils::MultiFuture::MultiFuture
MultiFuture(size_t n=0)
Construct with the given number of futures.
Definition: multi_future.hpp:94
genesis::utils::MultiFuture::size
size_t size() const
Get the number of stored futures.
Definition: multi_future.hpp:205
genesis::utils::MultiFuture::operator[]
ProactiveFuture< T > & operator[](size_t i)
Get a reference to one of the stored futures.
Definition: multi_future.hpp:189
genesis::utils::MultiFuture
Helper class to facilitate waiting for and/or getting the results of multiple futures at once.
Definition: multi_future.hpp:83
genesis::utils::MultiFuture::wait
void wait() const
Wait for all the stored futures.
Definition: multi_future.hpp:179
genesis::utils::MultiFuture::get
std::vector< T > get()
Get the results from all the stored futures.
Definition: multi_future.hpp:161
genesis::utils::MultiFuture::valid
bool valid() const
Return whether all stored futures are valid.
Definition: multi_future.hpp:122
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::utils::MultiFuture::get
void get()
Get the results from all the stored futures.
Definition: multi_future.hpp:139
genesis::utils::MultiFuture::operator=
MultiFuture & operator=(MultiFuture const &)=delete
genesis::utils::ProactiveFuture
Wrapper around std::future that implements (pro-)active waiting, i.e., work stealing.
Definition: thread_pool.hpp:79
genesis::utils::MultiFuture::~MultiFuture
~MultiFuture()=default
thread_pool.hpp
genesis::utils::MultiFuture::push_back
void push_back(ProactiveFuture< T > future)
Append a future.
Definition: multi_future.hpp:114