OpenVDB  9.1.1
ForEach.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /*!
5  \file ForEach.h
6 
7  \author Ken Museth
8 
9  \date August 24, 2020
10 
11  \brief A unified wrapper for tbb::parallel_for and a naive std::thread fallback
12 */
13 
14 #ifndef NANOVDB_FOREACH_H_HAS_BEEN_INCLUDED
15 #define NANOVDB_FOREACH_H_HAS_BEEN_INCLUDED
16 
17 #include "Range.h"// for Range1D
18 
19 #ifdef NANOVDB_USE_TBB
20 #include <tbb/parallel_for.h>
21 #else
22 #include <thread>
23 #include <mutex>
24 #include <vector>
25 #endif
26 
27 namespace nanovdb {
28 
29 /// @brief simple wrapper for tbb::parallel_for with a naive std fallback
30 ///
31 /// @param range Range, CoordBBox, tbb::blocked_range, blocked_range2D, or blocked_range3D.
32 /// @param func functor with the signature [](const RangeT&){...},
33 ///
34 /// @code
35 /// std::vector<int> array(100);
36 /// auto func = [&array](auto &r){for (auto i=r.begin(); i!=r.end(); ++i) array[i]=i;};
37 /// forEach(array, func);
38 /// @endcode
39 template <typename RangeT, typename FuncT>
40 inline void forEach(RangeT range, const FuncT &func)
41 {
42  if (range.empty()) return;
43 #ifdef NANOVDB_USE_TBB
44  tbb::parallel_for(range, func);
45 #else// naive and likely slow alternative based on std::thread
46  if (const size_t threadCount = std::thread::hardware_concurrency()>>1) {
47  std::vector<RangeT> rangePool{ range };
48  while(rangePool.size() < threadCount) {
49  const size_t oldSize = rangePool.size();
50  for (size_t i = 0; i < oldSize && rangePool.size() < threadCount; ++i) {
51  auto &r = rangePool[i];
52  if (r.is_divisible()) rangePool.push_back(RangeT(r, Split()));
53  }
54  if (rangePool.size() == oldSize) break;// none of the ranges were divided so stop
55  }
56  std::vector<std::thread> threadPool;
57  for (auto &r : rangePool) threadPool.emplace_back(func, r);// launch threads
58  for (auto &t : threadPool) t.join();// synchronize threads
59  } else {//serial
60  func(range);
61  }
62 #endif
63 }
64 
65 /// @brief Simple wrapper for the function defined above
66 template <typename FuncT>
67 inline void forEach(size_t begin, size_t end, size_t grainSize, const FuncT& func)
68 {
69  forEach(Range1D(begin, end, grainSize), func);
70 }
71 
72 /// @brief Simple wrapper for the function defined above, which works with std::containers
73 template <template<typename...> class ContainerT, typename... T, typename FuncT>
74 inline void forEach(const ContainerT<T...> &c, const FuncT& func)
75 {
76  forEach(Range1D(0, c.size(), 1), func);
77 }
78 
79 /// @brief Simple wrapper for the function defined above, which works with std::containers
80 template <template<typename...> class ContainerT, typename... T, typename FuncT>
81 inline void forEach(const ContainerT<T...> &c, size_t grainSize, const FuncT& func)
82 {
83  forEach(Range1D(0, c.size(), grainSize), func);
84 }
85 
86 }// namespace nanovdb
87 
88 #endif // NANOVDB_FOREACH_H_HAS_BEEN_INCLUDED
void forEach(RangeT range, const FuncT &func)
simple wrapper for tbb::parallel_for with a naive std fallback
Definition: ForEach.h:40
Definition: NanoVDB.h:184
Custom Range class that is compatible with the tbb::blocked_range classes.
Range< 1, size_t > Range1D
Definition: Range.h:30
Definition: Range.h:25