1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-16 10:08:36 +03:00
occt/src/OSD/OSD_Parallel.hxx
oan 00af0ebb9d 0028931: Eliminate dependency from TBB in OSD_Parallel header
Implementation of methods OSD_Parallel::For() and ForEach() is moved to CXX files to avoid direct dependency of client code that uses OSD_Parallel on TBB headers, and necessity to link with TBB explicitly.
Runtime polymorphism (virtual methods) is used to hide implementation (TBB or threads-based).
2017-10-06 10:28:10 +03:00

331 lines
11 KiB
C++

// Copyright (c) 2013-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef OSD_Parallel_HeaderFile
#define OSD_Parallel_HeaderFile
#include <Standard_Type.hxx>
#include <memory>
#include <type_traits>
//! @brief Simple tool for code parallelization.
//!
//! OSD_Parallel class provides simple interface for parallel processing of
//! tasks that can be formulated in terms of "for" or "foreach" loops.
//!
//! To use this tool it is necessary to:
//! - organize the data to be processed in a collection accessible by
//! iteration (usually array or vector);
//! - implement a functor class providing operator () accepting iterator
//! (or index in array) that does the job;
//! - call either For() or ForEach() providing begin and end iterators and
//! a functor object.
//!
//! Iterators should satisfy requirements of STL forward iterator.
//! Functor
//!
//! @code
//! class Functor
//! {
//! public:
//! void operator() ([proccesing instance]) const
//! {
//! //...
//! }
//! };
//! @endcode
//!
//! The operator () should be implemented in a thread-safe way so that
//! the same functor object can process different data items in parallel threads.
//!
//! Iteration by index (For) is expected to be more efficient than using iterators
//! (ForEach).
//!
//! Implementation uses TBB if OCCT is built with support of TBB; otherwise it
//! uses ad-hoc parallelization tool. In general, if TBB is available, it is
//! more efficient to use it directly instead of using OSD_Parallel.
class OSD_Parallel
{
private:
//! Interface class defining API for polymorphic wrappers over iterators.
//! Intended to add polymorphic behaviour to For and ForEach functionality
//! for arbitrary objects and eliminate dependency on template parameters.
class IteratorInterface
{
public:
virtual ~IteratorInterface() {}
//! Returns true if iterators wrapped by this and theOther are equal
virtual bool IsEqual (const IteratorInterface& theOther) const = 0;
//! Increments wrapped iterator
virtual void Increment () = 0;
//! Returns new instance of the wrapper containing copy
//! of the wrapped iterator.
virtual IteratorInterface* Clone() const = 0;
};
//! Implementation of polymorphic iterator wrapper suitable for basic
//! types as well as for std iterators.
//! Wraps instance of actual iterator type Type.
template<class Type>
class IteratorWrapper : public IteratorInterface
{
public:
IteratorWrapper() {}
IteratorWrapper(const Type& theValue) : myValue(theValue) {}
virtual bool IsEqual (const IteratorInterface& theOther) const Standard_OVERRIDE
{
return myValue == dynamic_cast<const IteratorWrapper<Type>&>(theOther).myValue;
}
virtual void Increment () Standard_OVERRIDE
{
++myValue;
}
virtual IteratorInterface* Clone() const Standard_OVERRIDE
{
return new IteratorWrapper<Type>(myValue);
}
const Type& Value() const { return myValue; }
private:
Type myValue;
};
protected:
// Note: UniversalIterator and FunctorInterface are made protected to be
// accessible from specialization using threads (non-TBB).
//! Fixed-type iterator, implementing STL forward iterator interface, used for
//! iteration over objects subject to parallel processing.
//! It stores pointer to instance of polymorphic iterator inheriting from
//! IteratorInterface, which contains actual type-specific iterator.
class UniversalIterator :
// Note that TBB requires that value_type of iterator be copyable,
// thus we use its own type for that
public std::iterator<std::forward_iterator_tag, UniversalIterator, ptrdiff_t, UniversalIterator*, UniversalIterator&>
{
public:
UniversalIterator() {}
UniversalIterator(IteratorInterface* theOther)
: myPtr(theOther)
{
}
UniversalIterator(const UniversalIterator& theOther)
: myPtr (theOther.myPtr->Clone())
{
}
UniversalIterator& operator= (const UniversalIterator& theOther)
{
myPtr.reset (theOther.myPtr->Clone());
return *this;
}
bool operator!= (const UniversalIterator& theOther) const
{
return ! myPtr->IsEqual (*theOther.myPtr);
}
bool operator== (const UniversalIterator& theOther) const
{
return myPtr->IsEqual (*theOther.myPtr);
}
UniversalIterator& operator++()
{
myPtr->Increment();
return *this;
}
UniversalIterator operator++(int)
{
UniversalIterator aValue(*this);
myPtr->Increment();
return aValue;
}
const UniversalIterator& operator* () const { return *this; }
UniversalIterator& operator* () { return *this; }
const UniversalIterator* operator->() const { return this; }
UniversalIterator* operator->() { return this; }
// type cast to actual iterator
template <typename Iterator>
const Iterator& DownCast () const
{
return dynamic_cast<OSD_Parallel::IteratorWrapper<Iterator>*>(myPtr.get())->Value();
}
private:
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
std::auto_ptr<IteratorInterface> myPtr;
#else
std::unique_ptr<IteratorInterface> myPtr;
#endif
};
//! Interface class representing functor object.
//! Intended to add polymorphic behavour to For and ForEach functionality
//! enabling execution of arbitrary function in parallel mode.
class FunctorInterface
{
public:
virtual ~FunctorInterface() {}
virtual void operator () (UniversalIterator& theIterator) const = 0;
};
private:
//! Wrapper for functors manipulating on std iterators.
template<class Iterator, class Functor>
class FunctorWrapperIter : public FunctorInterface
{
public:
FunctorWrapperIter (const Functor& theFunctor)
: myFunctor(theFunctor)
{
}
virtual void operator() (UniversalIterator& theIterator) const Standard_OVERRIDE
{
const Iterator& anIt = theIterator.DownCast<Iterator>();
myFunctor(*anIt);
}
private:
FunctorWrapperIter (const FunctorWrapperIter&);
void operator = (const FunctorWrapperIter&);
const Functor& myFunctor;
};
//! Wrapper for functors manipulating on integer index.
template<class Functor>
class FunctorWrapperInt : public FunctorInterface
{
public:
FunctorWrapperInt (const Functor& theFunctor)
: myFunctor(theFunctor)
{
}
virtual void operator() (UniversalIterator& theIterator) const Standard_OVERRIDE
{
Standard_Integer anIndex = theIterator.DownCast<Standard_Integer>();
myFunctor(anIndex);
}
private:
FunctorWrapperInt (const FunctorWrapperInt&);
void operator = (const FunctorWrapperInt&);
const Functor& myFunctor;
};
private:
//! Simple primitive for parallelization of "foreach" loops, e.g.:
//! @code
//! for (std::iterator anIter = theBegin; anIter != theEnd; ++anIter) {}
//! @endcode
//! Implementation of framework-dependent functionality should be provided by
//! forEach_impl function defined in opencascade::parallel namespace.
//! @param theBegin the first index (incusive)
//! @param theEnd the last index (exclusive)
//! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
//! performing task for the specified iterator position
Standard_EXPORT static void forEach (UniversalIterator& theBegin,
UniversalIterator& theEnd,
const FunctorInterface& theFunctor);
public: //! @name public methods
//! Returns number of logical proccesrs.
Standard_EXPORT static Standard_Integer NbLogicalProcessors();
//! Simple primitive for parallelization of "foreach" loops, equivalent to:
//! @code
//! for (auto anIter = theBegin; anIter != theEnd; ++anIter) {
//! theFunctor(*anIter);
//! }
//! @endcode
//! @param theBegin the first index (incusive)
//! @param theEnd the last index (exclusive)
//! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
//! performing task for specified iterator position
//! @param isForceSingleThreadExecution if true, then no threads will be created
template <typename InputIterator, typename Functor>
static void ForEach(InputIterator theBegin,
InputIterator theEnd,
const Functor& theFunctor,
const Standard_Boolean isForceSingleThreadExecution = Standard_False)
{
if (isForceSingleThreadExecution)
{
for (InputIterator it(theBegin); it != theEnd; ++it)
theFunctor(*it);
}
else
{
UniversalIterator aBegin(new IteratorWrapper<InputIterator>(theBegin));
UniversalIterator aEnd (new IteratorWrapper<InputIterator>(theEnd));
FunctorWrapperIter<InputIterator,Functor> aFunctor (theFunctor);
forEach(aBegin, aEnd, aFunctor);
}
}
//! Simple primitive for parallelization of "for" loops, equivalent to:
//! @code
//! for (int anIter = theBegin; anIter != theEnd; ++anIter) {
//! theFunctor(anIter);
//! }
//! @endcode
//! @param theBegin the first index (incusive)
//! @param theEnd the last index (exclusive)
//! @param theFunctor functor providing an interface "void operator(int theIndex){}"
//! performing task for specified index
//! @param isForceSingleThreadExecution if true, then no threads will be created
template <typename Functor>
static void For(const Standard_Integer theBegin,
const Standard_Integer theEnd,
const Functor& theFunctor,
const Standard_Boolean isForceSingleThreadExecution = Standard_False)
{
if (isForceSingleThreadExecution)
{
for (Standard_Integer it (theBegin); it != theEnd; ++it)
theFunctor(it);
}
else
{
UniversalIterator aBegin(new IteratorWrapper<Standard_Integer>(theBegin));
UniversalIterator aEnd (new IteratorWrapper<Standard_Integer>(theEnd));
FunctorWrapperInt<Functor> aFunctor (theFunctor);
forEach(aBegin, aEnd, aFunctor);
}
}
};
#endif