0028931: Eliminate dependency from TBB in OSD_Parallel header
[occt.git] / src / OSD / OSD_Parallel.hxx
CommitLineData
c7b59798 1// Copyright (c) 2013-2014 OPEN CASCADE SAS
2//
3// This file is part of Open CASCADE Technology software library.
4//
5// This library is free software; you can redistribute it and/or modify it under
6// the terms of the GNU Lesser General Public License version 2.1 as published
7// by the Free Software Foundation, with special exception defined in the file
8// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9// distribution for complete text of the license and disclaimer of any warranty.
10//
11// Alternatively, this file may be used under the terms of Open CASCADE
12// commercial license or contractual agreement.
13
14#ifndef OSD_Parallel_HeaderFile
15#define OSD_Parallel_HeaderFile
16
00af0ebb 17#include <Standard_Type.hxx>
18#include <memory>
19#include <type_traits>
c7b59798 20
00af0ebb 21//! @brief Simple tool for code parallelization.
22//!
23//! OSD_Parallel class provides simple interface for parallel processing of
24//! tasks that can be formulated in terms of "for" or "foreach" loops.
25//!
26//! To use this tool it is necessary to:
27//! - organize the data to be processed in a collection accessible by
28//! iteration (usually array or vector);
29//! - implement a functor class providing operator () accepting iterator
30//! (or index in array) that does the job;
31//! - call either For() or ForEach() providing begin and end iterators and
32//! a functor object.
c7b59798 33//!
00af0ebb 34//! Iterators should satisfy requirements of STL forward iterator.
35//! Functor
c7b59798 36//!
37//! @code
38//! class Functor
39//! {
40//! public:
41//! void operator() ([proccesing instance]) const
42//! {
43//! //...
44//! }
45//! };
46//! @endcode
47//!
00af0ebb 48//! The operator () should be implemented in a thread-safe way so that
49//! the same functor object can process different data items in parallel threads.
50//!
51//! Iteration by index (For) is expected to be more efficient than using iterators
52//! (ForEach).
53//!
54//! Implementation uses TBB if OCCT is built with support of TBB; otherwise it
55//! uses ad-hoc parallelization tool. In general, if TBB is available, it is
56//! more efficient to use it directly instead of using OSD_Parallel.
57
c7b59798 58class OSD_Parallel
59{
00af0ebb 60private:
61
62 //! Interface class defining API for polymorphic wrappers over iterators.
63 //! Intended to add polymorphic behaviour to For and ForEach functionality
64 //! for arbitrary objects and eliminate dependency on template parameters.
65 class IteratorInterface
c7b59798 66 {
00af0ebb 67 public:
68 virtual ~IteratorInterface() {}
c7b59798 69
00af0ebb 70 //! Returns true if iterators wrapped by this and theOther are equal
71 virtual bool IsEqual (const IteratorInterface& theOther) const = 0;
c7b59798 72
00af0ebb 73 //! Increments wrapped iterator
74 virtual void Increment () = 0;
75
76 //! Returns new instance of the wrapper containing copy
77 //! of the wrapped iterator.
78 virtual IteratorInterface* Clone() const = 0;
79 };
c7b59798 80
00af0ebb 81 //! Implementation of polymorphic iterator wrapper suitable for basic
82 //! types as well as for std iterators.
83 //! Wraps instance of actual iterator type Type.
84 template<class Type>
85 class IteratorWrapper : public IteratorInterface
86 {
87 public:
88 IteratorWrapper() {}
89 IteratorWrapper(const Type& theValue) : myValue(theValue) {}
90
91 virtual bool IsEqual (const IteratorInterface& theOther) const Standard_OVERRIDE
c7b59798 92 {
00af0ebb 93 return myValue == dynamic_cast<const IteratorWrapper<Type>&>(theOther).myValue;
c7b59798 94 }
95
00af0ebb 96 virtual void Increment () Standard_OVERRIDE
c7b59798 97 {
00af0ebb 98 ++myValue;
c7b59798 99 }
100
00af0ebb 101 virtual IteratorInterface* Clone() const Standard_OVERRIDE
c7b59798 102 {
00af0ebb 103 return new IteratorWrapper<Type>(myValue);
c7b59798 104 }
105
00af0ebb 106 const Type& Value() const { return myValue; }
c7b59798 107
00af0ebb 108 private:
109 Type myValue;
c7b59798 110 };
111
00af0ebb 112protected:
113 // Note: UniversalIterator and FunctorInterface are made protected to be
114 // accessible from specialization using threads (non-TBB).
115
116 //! Fixed-type iterator, implementing STL forward iterator interface, used for
117 //! iteration over objects subject to parallel processing.
118 //! It stores pointer to instance of polymorphic iterator inheriting from
119 //! IteratorInterface, which contains actual type-specific iterator.
120 class UniversalIterator :
121 // Note that TBB requires that value_type of iterator be copyable,
122 // thus we use its own type for that
123 public std::iterator<std::forward_iterator_tag, UniversalIterator, ptrdiff_t, UniversalIterator*, UniversalIterator&>
c7b59798 124 {
00af0ebb 125 public:
126 UniversalIterator() {}
c7b59798 127
00af0ebb 128 UniversalIterator(IteratorInterface* theOther)
129 : myPtr(theOther)
c7b59798 130 {
131 }
132
00af0ebb 133 UniversalIterator(const UniversalIterator& theOther)
134 : myPtr (theOther.myPtr->Clone())
c7b59798 135 {
00af0ebb 136 }
c7b59798 137
00af0ebb 138 UniversalIterator& operator= (const UniversalIterator& theOther)
139 {
140 myPtr.reset (theOther.myPtr->Clone());
141 return *this;
142 }
c7b59798 143
00af0ebb 144 bool operator!= (const UniversalIterator& theOther) const
145 {
146 return ! myPtr->IsEqual (*theOther.myPtr);
147 }
c7b59798 148
00af0ebb 149 bool operator== (const UniversalIterator& theOther) const
150 {
151 return myPtr->IsEqual (*theOther.myPtr);
c7b59798 152 }
153
00af0ebb 154 UniversalIterator& operator++()
c7b59798 155 {
00af0ebb 156 myPtr->Increment();
157 return *this;
158 }
159
160 UniversalIterator operator++(int)
161 {
162 UniversalIterator aValue(*this);
163 myPtr->Increment();
164 return aValue;
165 }
c7b59798 166
00af0ebb 167 const UniversalIterator& operator* () const { return *this; }
168 UniversalIterator& operator* () { return *this; }
c7b59798 169
00af0ebb 170 const UniversalIterator* operator->() const { return this; }
171 UniversalIterator* operator->() { return this; }
c7b59798 172
00af0ebb 173 // type cast to actual iterator
174 template <typename Iterator>
175 const Iterator& DownCast () const
176 {
177 return dynamic_cast<OSD_Parallel::IteratorWrapper<Iterator>*>(myPtr.get())->Value();
c7b59798 178 }
179
00af0ebb 180 private:
181#if (defined(_MSC_VER) && (_MSC_VER < 1600))
182 std::auto_ptr<IteratorInterface> myPtr;
183#else
184 std::unique_ptr<IteratorInterface> myPtr;
185#endif
186 };
c7b59798 187
00af0ebb 188 //! Interface class representing functor object.
189 //! Intended to add polymorphic behavour to For and ForEach functionality
190 //! enabling execution of arbitrary function in parallel mode.
191 class FunctorInterface
192 {
193 public:
194 virtual ~FunctorInterface() {}
c7b59798 195
00af0ebb 196 virtual void operator () (UniversalIterator& theIterator) const = 0;
197 };
c7b59798 198
00af0ebb 199private:
c7b59798 200
00af0ebb 201 //! Wrapper for functors manipulating on std iterators.
202 template<class Iterator, class Functor>
203 class FunctorWrapperIter : public FunctorInterface
204 {
205 public:
206 FunctorWrapperIter (const Functor& theFunctor)
207 : myFunctor(theFunctor)
208 {
209 }
210
211 virtual void operator() (UniversalIterator& theIterator) const Standard_OVERRIDE
212 {
213 const Iterator& anIt = theIterator.DownCast<Iterator>();
214 myFunctor(*anIt);
215 }
216
217 private:
218 FunctorWrapperIter (const FunctorWrapperIter&);
219 void operator = (const FunctorWrapperIter&);
220 const Functor& myFunctor;
c7b59798 221 };
222
00af0ebb 223 //! Wrapper for functors manipulating on integer index.
224 template<class Functor>
225 class FunctorWrapperInt : public FunctorInterface
226 {
227 public:
228 FunctorWrapperInt (const Functor& theFunctor)
229 : myFunctor(theFunctor)
230 {
231 }
c7b59798 232
00af0ebb 233 virtual void operator() (UniversalIterator& theIterator) const Standard_OVERRIDE
234 {
235 Standard_Integer anIndex = theIterator.DownCast<Standard_Integer>();
236 myFunctor(anIndex);
237 }
238
239 private:
240 FunctorWrapperInt (const FunctorWrapperInt&);
241 void operator = (const FunctorWrapperInt&);
242 const Functor& myFunctor;
243 };
244
245private:
c7b59798 246
5e3047fd 247 //! Simple primitive for parallelization of "foreach" loops, e.g.:
248 //! @code
249 //! for (std::iterator anIter = theBegin; anIter != theEnd; ++anIter) {}
250 //! @endcode
00af0ebb 251 //! Implementation of framework-dependent functionality should be provided by
252 //! forEach_impl function defined in opencascade::parallel namespace.
5e3047fd 253 //! @param theBegin the first index (incusive)
254 //! @param theEnd the last index (exclusive)
00af0ebb 255 //! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
256 //! performing task for the specified iterator position
257 Standard_EXPORT static void forEach (UniversalIterator& theBegin,
258 UniversalIterator& theEnd,
259 const FunctorInterface& theFunctor);
260
261public: //! @name public methods
262
263 //! Returns number of logical proccesrs.
264 Standard_EXPORT static Standard_Integer NbLogicalProcessors();
c7b59798 265
00af0ebb 266 //! Simple primitive for parallelization of "foreach" loops, equivalent to:
5e3047fd 267 //! @code
00af0ebb 268 //! for (auto anIter = theBegin; anIter != theEnd; ++anIter) {
269 //! theFunctor(*anIter);
270 //! }
5e3047fd 271 //! @endcode
272 //! @param theBegin the first index (incusive)
273 //! @param theEnd the last index (exclusive)
00af0ebb 274 //! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
275 //! performing task for specified iterator position
5e3047fd 276 //! @param isForceSingleThreadExecution if true, then no threads will be created
00af0ebb 277 template <typename InputIterator, typename Functor>
278 static void ForEach(InputIterator theBegin,
279 InputIterator theEnd,
280 const Functor& theFunctor,
281 const Standard_Boolean isForceSingleThreadExecution = Standard_False)
c7b59798 282 {
00af0ebb 283 if (isForceSingleThreadExecution)
c7b59798 284 {
00af0ebb 285 for (InputIterator it(theBegin); it != theEnd; ++it)
286 theFunctor(*it);
c7b59798 287 }
00af0ebb 288 else
c7b59798 289 {
00af0ebb 290 UniversalIterator aBegin(new IteratorWrapper<InputIterator>(theBegin));
291 UniversalIterator aEnd (new IteratorWrapper<InputIterator>(theEnd));
292 FunctorWrapperIter<InputIterator,Functor> aFunctor (theFunctor);
293 forEach(aBegin, aEnd, aFunctor);
c7b59798 294 }
295 }
c7b59798 296
00af0ebb 297 //! Simple primitive for parallelization of "for" loops, equivalent to:
298 //! @code
299 //! for (int anIter = theBegin; anIter != theEnd; ++anIter) {
300 //! theFunctor(anIter);
301 //! }
302 //! @endcode
303 //! @param theBegin the first index (incusive)
304 //! @param theEnd the last index (exclusive)
305 //! @param theFunctor functor providing an interface "void operator(int theIndex){}"
306 //! performing task for specified index
307 //! @param isForceSingleThreadExecution if true, then no threads will be created
308 template <typename Functor>
309 static void For(const Standard_Integer theBegin,
310 const Standard_Integer theEnd,
311 const Functor& theFunctor,
312 const Standard_Boolean isForceSingleThreadExecution = Standard_False)
c7b59798 313 {
00af0ebb 314 if (isForceSingleThreadExecution)
c7b59798 315 {
00af0ebb 316 for (Standard_Integer it (theBegin); it != theEnd; ++it)
317 theFunctor(it);
c7b59798 318 }
00af0ebb 319 else
c7b59798 320 {
00af0ebb 321 UniversalIterator aBegin(new IteratorWrapper<Standard_Integer>(theBegin));
322 UniversalIterator aEnd (new IteratorWrapper<Standard_Integer>(theEnd));
323 FunctorWrapperInt<Functor> aFunctor (theFunctor);
324 forEach(aBegin, aEnd, aFunctor);
c7b59798 325 }
326 }
c7b59798 327
00af0ebb 328};
c7b59798 329
330#endif