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 |
58 | class OSD_Parallel |
59 | { |
00af0ebb |
60 | private: |
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 |
112 | protected: |
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 |
199 | private: |
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 | |
245 | private: |
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 | |
261 | public: //! @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 |