OpenVDB 9.0.0
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
27namespace 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
39template <typename RangeT, typename FuncT>
40inline 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
66template <typename FuncT>
67inline 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
73template <template<typename...> class ContainerT, typename... T, typename FuncT>
74inline 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
80template <template<typename...> class ContainerT, typename... T, typename FuncT>
81inline 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
Custom Range class that is compatible with the tbb::blocked_range classes.
Definition: Range.h:25
Definition: Camera.h:16
void forEach(RangeT range, const FuncT &func)
simple wrapper for tbb::parallel_for with a naive std fallback
Definition: ForEach.h:40
Range< 1, size_t > Range1D
Definition: Range.h:30