_flow_graph_types_impl.h | _flow_graph_types_impl.h | |||
---|---|---|---|---|
skipping to change at line 167 | skipping to change at line 167 | |||
PT<typename tbb::flow::tuple_element<4,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<4,TypeTuple>::type>, | |||
PT<typename tbb::flow::tuple_element<5,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<5,TypeTuple>::type>, | |||
PT<typename tbb::flow::tuple_element<6,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<6,TypeTuple>::type>, | |||
PT<typename tbb::flow::tuple_element<7,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<7,TypeTuple>::type>, | |||
PT<typename tbb::flow::tuple_element<8,TypeTuple>::type>, | PT<typename tbb::flow::tuple_element<8,TypeTuple>::type>, | |||
PT<typename tbb::flow::tuple_element<9,TypeTuple>::type> > | PT<typename tbb::flow::tuple_element<9,TypeTuple>::type> > | |||
type; | type; | |||
}; | }; | |||
#endif | #endif | |||
#if TBB_PREVIEW_GRAPH_NODES | ||||
// support for variant type | ||||
// type we use when we're not storing a value | ||||
struct default_constructed { }; | ||||
// type which contains another type, tests for what type is contained, and | ||||
references to it. | ||||
// internal::Wrapper<T> | ||||
// void CopyTo( void *newSpace) : builds a Wrapper<T> copy of itself in | ||||
newSpace | ||||
// struct to allow us to copy and test the type of objects | ||||
struct WrapperBase { | ||||
virtual ~WrapperBase() {} | ||||
virtual void CopyTo(void* /*newSpace*/) const { } | ||||
}; | ||||
// Wrapper<T> contains a T, with the ability to test what T is. The Wrappe | ||||
r<T> can be | ||||
// constructed from a T, can be copy-constructed from another Wrapper<T>, a | ||||
nd can be | ||||
// examined via value(), but not modified. | ||||
template<typename T> | ||||
struct Wrapper: public WrapperBase { | ||||
typedef T value_type; | ||||
typedef T* pointer_type; | ||||
private: | ||||
T value_space; | ||||
public: | ||||
const value_type &value() const { return value_space; } | ||||
private: | ||||
Wrapper(); | ||||
// on exception will ensure the Wrapper will contain only a trivially-c | ||||
onstructed object | ||||
struct _unwind_space { | ||||
pointer_type space; | ||||
_unwind_space(pointer_type p) : space(p) {} | ||||
~_unwind_space() { | ||||
if(space) (void) new (space) Wrapper<default_constructed>(defau | ||||
lt_constructed()); | ||||
} | ||||
}; | ||||
public: | ||||
explicit Wrapper( const T& other ) : value_space(other) { } | ||||
explicit Wrapper(const Wrapper& other) : value_space(other.value_space) | ||||
{ } | ||||
/*override*/void CopyTo(void* newSpace) const { | ||||
_unwind_space guard((pointer_type)newSpace); | ||||
(void) new(newSpace) Wrapper(value_space); | ||||
guard.space = NULL; | ||||
} | ||||
/*override*/~Wrapper() { } | ||||
}; | ||||
// specialization for array objects | ||||
template<typename T, size_t N> | ||||
struct Wrapper<T[N]> : public WrapperBase { | ||||
typedef T value_type; | ||||
typedef T* pointer_type; | ||||
// space must be untyped. | ||||
typedef T ArrayType[N]; | ||||
private: | ||||
// The space is not of type T[N] because when copy-constructing, it wou | ||||
ld be | ||||
// default-initialized and then copied to in some fashion, resulting in | ||||
two | ||||
// constructions and one destruction per element. If the type is char[ | ||||
], we | ||||
// placement new into each element, resulting in one construction per e | ||||
lement. | ||||
static const size_t space_size = sizeof(ArrayType) / sizeof(char); | ||||
char value_space[space_size]; | ||||
// on exception will ensure the already-built objects will be destructe | ||||
d | ||||
// (the value_space is a char array, so it is already trivially-destruc | ||||
tible.) | ||||
struct _unwind_class { | ||||
pointer_type space; | ||||
int already_built; | ||||
_unwind_class(pointer_type p) : space(p), already_built(0) {} | ||||
~_unwind_class() { | ||||
if(space) { | ||||
for(size_t i = already_built; i > 0 ; --i ) space[i-1].~val | ||||
ue_type(); | ||||
(void) new(space) Wrapper<default_constructed>(default_cons | ||||
tructed()); | ||||
} | ||||
} | ||||
}; | ||||
public: | ||||
const ArrayType &value() const { | ||||
char *vp = const_cast<char *>(value_space); | ||||
return reinterpret_cast<ArrayType &>(*vp); | ||||
} | ||||
private: | ||||
Wrapper(); | ||||
public: | ||||
// have to explicitly construct because other decays to a const value_t | ||||
ype* | ||||
explicit Wrapper(const ArrayType& other) { | ||||
_unwind_class guard((pointer_type)value_space); | ||||
pointer_type vp = reinterpret_cast<pointer_type>(&value_space); | ||||
for(size_t i = 0; i < N; ++i ) { | ||||
(void) new(vp++) value_type(other[i]); | ||||
++(guard.already_built); | ||||
} | ||||
guard.space = NULL; | ||||
} | ||||
explicit Wrapper(const Wrapper& other) : WrapperBase() { | ||||
// we have to do the heavy lifting to copy contents | ||||
_unwind_class guard((pointer_type)value_space); | ||||
pointer_type dp = reinterpret_cast<pointer_type>(value_space); | ||||
pointer_type sp = reinterpret_cast<pointer_type>(const_cast<char *> | ||||
(other.value_space)); | ||||
for(size_t i = 0; i < N; ++i, ++dp, ++sp) { | ||||
(void) new(dp) value_type(*sp); | ||||
++(guard.already_built); | ||||
} | ||||
guard.space = NULL; | ||||
} | ||||
/*override*/void CopyTo(void* newSpace) const { | ||||
(void) new(newSpace) Wrapper(*this); // exceptions handled in copy | ||||
constructor | ||||
} | ||||
/*override*/~Wrapper() { | ||||
// have to destroy explicitly in reverse order | ||||
pointer_type vp = reinterpret_cast<pointer_type>(&value_space); | ||||
for(size_t i = N; i > 0 ; --i ) vp[i-1].~value_type(); | ||||
} | ||||
}; | ||||
// given a tuple, return the type of the element that has the maximum align | ||||
ment requirement. | ||||
// Given a tuple and that type, return the number of elements of the object | ||||
with the max | ||||
// alignment requirement that is at least as big as the largest object in t | ||||
he tuple. | ||||
template<bool, class T1, class T2> struct pick_one; | ||||
template<class T1, class T2> struct pick_one<true , T1, T2> { typedef T1 ty | ||||
pe; }; | ||||
template<class T1, class T2> struct pick_one<false, T1, T2> { typedef T2 ty | ||||
pe; }; | ||||
template< template<class> class Selector, typename T1, typename T2 > | ||||
struct pick_max { | ||||
typedef typename pick_one< (Selector<T1>::value > Selector<T2>::value), | ||||
T1, T2 >::type type; | ||||
}; | ||||
template<typename T> struct size_of { static const int value = sizeof(T); } | ||||
; | ||||
template<class T> struct alignment_of { | ||||
typedef struct { char t; T padded; } test_alignment; | ||||
static const size_t value = sizeof(test_alignment) - sizeof(T); | ||||
}; | ||||
template< size_t N, class Tuple, template<class> class Selector > struct pi | ||||
ck_tuple_max { | ||||
typedef typename pick_tuple_max<N-1, Tuple, Selector>::type LeftMaxType | ||||
; | ||||
typedef typename tuple_element<N-1, Tuple>::type ThisType; | ||||
typedef typename pick_max<Selector, LeftMaxType, ThisType>::type type; | ||||
}; | ||||
template< class Tuple, template<class> class Selector > struct pick_tuple_m | ||||
ax<0, Tuple, Selector> { | ||||
typedef typename tuple_element<0, Tuple>::type type; | ||||
}; | ||||
// is the specified type included in a tuple? | ||||
template<class U, class V> struct is_same_type { static const bool val | ||||
ue = false; }; | ||||
template<class W> struct is_same_type<W,W> { static const bool val | ||||
ue = true; }; | ||||
template<class Q, size_t N, class Tuple> | ||||
struct is_element_of { | ||||
typedef typename tuple_element<N-1, Tuple>::type T_i; | ||||
static const bool value = is_same_type<Q,T_i>::value || is_element_of<Q | ||||
,N-1,Tuple>::value; | ||||
}; | ||||
template<class Q, class Tuple> | ||||
struct is_element_of<Q,0,Tuple> { | ||||
typedef typename tuple_element<0, Tuple>::type T_i; | ||||
static const bool value = is_same_type<Q,T_i>::value; | ||||
}; | ||||
// allow the construction of types that are listed tuple. If a disallowed | ||||
type | ||||
// construction is written, a method involving this type is created. The | ||||
// type has no definition, so a syntax error is generated. | ||||
template<typename T> struct ERROR_Type_Not_allowed_In_Tagged_Msg_Not_Member | ||||
_Of_Tuple; | ||||
template<typename T, bool BUILD_IT> struct do_if; | ||||
template<typename T> | ||||
struct do_if<T, true> { | ||||
static void construct(void *mySpace, const T& x) { | ||||
(void) new(mySpace) Wrapper<T>(x); | ||||
} | ||||
}; | ||||
template<typename T> | ||||
struct do_if<T, false> { | ||||
static void construct(void * /*mySpace*/, const T& x) { | ||||
// This method is instantiated when the type T does not match any o | ||||
f the | ||||
// element types in the Tuple in variant<Tuple>. | ||||
ERROR_Type_Not_allowed_In_Tagged_Msg_Not_Member_Of_Tuple<T>::bad_ty | ||||
pe(x); | ||||
} | ||||
}; | ||||
// Tuple tells us the allowed types that variant can hold. It determines t | ||||
he alignment of the space in | ||||
// Wrapper, and how big Wrapper is. | ||||
// | ||||
// the object can only be tested for type, and a read-only reference can be | ||||
fetched by cast_to<T>(). | ||||
using tbb::internal::punned_cast; | ||||
struct tagged_null_type {}; | ||||
template<typename TagType, typename T0, typename T1=tagged_null_type, typen | ||||
ame T2=tagged_null_type, typename T3=tagged_null_type, | ||||
typename T4=tagged_null_type, typename T5=tagged | ||||
_null_type, typename T6=tagged_null_type, | ||||
typename T7=tagged_null_type, typename T8=tagged | ||||
_null_type, typename T9=tagged_null_type> | ||||
class tagged_msg { | ||||
typedef tuple<T0, T1, T2, T3, T4 | ||||
#if __TBB_VARIADIC_MAX >= 6 | ||||
, T5 | ||||
#endif | ||||
#if __TBB_VARIADIC_MAX >= 7 | ||||
, T6 | ||||
#endif | ||||
#if __TBB_VARIADIC_MAX >= 8 | ||||
, T7 | ||||
#endif | ||||
#if __TBB_VARIADIC_MAX >= 9 | ||||
, T8 | ||||
#endif | ||||
#if __TBB_VARIADIC_MAX >= 10 | ||||
, T9 | ||||
#endif | ||||
> Tuple; | ||||
private: | ||||
class variant { | ||||
static const size_t N = tuple_size<Tuple>::value; | ||||
typedef typename pick_tuple_max<N, Tuple, alignment_of>::type Align | ||||
Type; | ||||
typedef typename pick_tuple_max<N, Tuple, size_of>::type MaxSizeTyp | ||||
e; | ||||
static const size_t MaxNBytes = (sizeof(Wrapper<MaxSizeType>)+sizeo | ||||
f(AlignType)-1); | ||||
static const size_t MaxNElements = MaxNBytes/sizeof(AlignType); | ||||
typedef typename tbb::aligned_space<AlignType, MaxNElements> SpaceT | ||||
ype; | ||||
SpaceType my_space; | ||||
static const size_t MaxSize = sizeof(SpaceType); | ||||
public: | ||||
variant() { (void) new(&my_space) Wrapper<default_constructed>(defa | ||||
ult_constructed()); } | ||||
template<typename T> | ||||
variant( const T& x ) { | ||||
do_if<T, is_element_of<T, N, Tuple>::value>::construct(&my_spac | ||||
e,x); | ||||
} | ||||
variant(const variant& other) { | ||||
const WrapperBase * h = punned_cast<const WrapperBase *>(&(othe | ||||
r.my_space)); | ||||
h->CopyTo(&my_space); | ||||
} | ||||
// assignment must destroy and re-create the Wrapper type, as there | ||||
is no way | ||||
// to create a Wrapper-to-Wrapper assign even if we find they agree | ||||
in type. | ||||
void operator=( const variant& rhs ) { | ||||
if(&rhs != this) { | ||||
WrapperBase *h = punned_cast<WrapperBase *>(&my_space); | ||||
h->~WrapperBase(); | ||||
const WrapperBase *ch = punned_cast<const WrapperBase *>(&( | ||||
rhs.my_space)); | ||||
ch->CopyTo(&my_space); | ||||
} | ||||
} | ||||
template<typename U> | ||||
const U& variant_cast_to() const { | ||||
const Wrapper<U> *h = dynamic_cast<const Wrapper<U>*>(punned_ca | ||||
st<const WrapperBase *>(&my_space)); | ||||
if(!h) { | ||||
tbb::internal::throw_exception(tbb::internal::eid_bad_tagge | ||||
d_msg_cast); | ||||
} | ||||
return h->value(); | ||||
} | ||||
template<typename U> | ||||
bool variant_is_a() const { return dynamic_cast<const Wrapper<U>*>( | ||||
punned_cast<const WrapperBase *>(&my_space)) != NULL; } | ||||
bool variant_is_default_constructed() const {return variant_is_a<de | ||||
fault_constructed>();} | ||||
~variant() { | ||||
WrapperBase *h = punned_cast<WrapperBase *>(&my_space); | ||||
h->~WrapperBase(); | ||||
} | ||||
}; //class variant | ||||
TagType my_tag; | ||||
variant my_msg; | ||||
public: | ||||
tagged_msg(): my_tag(TagType(~0)), my_msg(){} | ||||
template<typename T, typename R> | ||||
tagged_msg(T const &index, R const &value) : my_tag(index), my_msg(valu | ||||
e) {} | ||||
void set_tag(TagType const &index) {my_tag = index;} | ||||
TagType tag() const {return my_tag;} | ||||
template<typename V> | ||||
const V& cast_to() const {return my_msg.template variant_cast_to<V>();} | ||||
template<typename V> | ||||
bool is_a() const {return my_msg.template variant_is_a<V>();} | ||||
bool is_default_constructed() const {return my_msg.variant_is_default_c | ||||
onstructed();} | ||||
}; //class tagged_msg | ||||
// template to simplify cast and test for tagged_msg in template contexts | ||||
template<typename T, typename V> | ||||
const T& cast_to(V const &v) { return v.template cast_to<T>(); } | ||||
template<typename T, typename V> | ||||
bool is_a(V const &v) { return v.template is_a<T>(); } | ||||
#endif // TBB_PREVIEW_GRAPH_NODES | ||||
} // namespace internal | } // namespace internal | |||
#endif /* __TBB__flow_graph_types_impl_H */ | #endif /* __TBB__flow_graph_types_impl_H */ | |||
End of changes. 2 change blocks. | ||||
0 lines changed or deleted | 356 lines changed or added | |||
_tbb_strings.h | _tbb_strings.h | |||
---|---|---|---|---|
skipping to change at line 38 | skipping to change at line 38 | |||
TBB_STRING_RESOURCE(FLOW_BROADCAST_NODE, "broadcast_node") | TBB_STRING_RESOURCE(FLOW_BROADCAST_NODE, "broadcast_node") | |||
TBB_STRING_RESOURCE(FLOW_BUFFER_NODE, "buffer_node") | TBB_STRING_RESOURCE(FLOW_BUFFER_NODE, "buffer_node") | |||
TBB_STRING_RESOURCE(FLOW_CONTINUE_NODE, "continue_node") | TBB_STRING_RESOURCE(FLOW_CONTINUE_NODE, "continue_node") | |||
TBB_STRING_RESOURCE(FLOW_FUNCTION_NODE, "function_node") | TBB_STRING_RESOURCE(FLOW_FUNCTION_NODE, "function_node") | |||
TBB_STRING_RESOURCE(FLOW_JOIN_NODE_QUEUEING, "join_node (queueing)") | TBB_STRING_RESOURCE(FLOW_JOIN_NODE_QUEUEING, "join_node (queueing)") | |||
TBB_STRING_RESOURCE(FLOW_JOIN_NODE_RESERVING, "join_node (reserving)") | TBB_STRING_RESOURCE(FLOW_JOIN_NODE_RESERVING, "join_node (reserving)") | |||
TBB_STRING_RESOURCE(FLOW_JOIN_NODE_TAG_MATCHING, "join_node (tag_matching)" ) | TBB_STRING_RESOURCE(FLOW_JOIN_NODE_TAG_MATCHING, "join_node (tag_matching)" ) | |||
TBB_STRING_RESOURCE(FLOW_LIMITER_NODE, "limiter_node") | TBB_STRING_RESOURCE(FLOW_LIMITER_NODE, "limiter_node") | |||
TBB_STRING_RESOURCE(FLOW_MULTIFUNCTION_NODE, "multifunction_node") | TBB_STRING_RESOURCE(FLOW_MULTIFUNCTION_NODE, "multifunction_node") | |||
TBB_STRING_RESOURCE(FLOW_OR_NODE, "or_node") | TBB_STRING_RESOURCE(FLOW_OR_NODE, "or_node") //no longer in use, kept for b ackward compatibilty | |||
TBB_STRING_RESOURCE(FLOW_OVERWRITE_NODE, "overwrite_node") | TBB_STRING_RESOURCE(FLOW_OVERWRITE_NODE, "overwrite_node") | |||
TBB_STRING_RESOURCE(FLOW_PRIORITY_QUEUE_NODE, "priority_queue_node") | TBB_STRING_RESOURCE(FLOW_PRIORITY_QUEUE_NODE, "priority_queue_node") | |||
TBB_STRING_RESOURCE(FLOW_QUEUE_NODE, "queue_node") | TBB_STRING_RESOURCE(FLOW_QUEUE_NODE, "queue_node") | |||
TBB_STRING_RESOURCE(FLOW_SEQUENCER_NODE, "sequencer_node") | TBB_STRING_RESOURCE(FLOW_SEQUENCER_NODE, "sequencer_node") | |||
TBB_STRING_RESOURCE(FLOW_SOURCE_NODE, "source_node") | TBB_STRING_RESOURCE(FLOW_SOURCE_NODE, "source_node") | |||
TBB_STRING_RESOURCE(FLOW_SPLIT_NODE, "split_node") | TBB_STRING_RESOURCE(FLOW_SPLIT_NODE, "split_node") | |||
TBB_STRING_RESOURCE(FLOW_WRITE_ONCE_NODE, "write_once_node") | TBB_STRING_RESOURCE(FLOW_WRITE_ONCE_NODE, "write_once_node") | |||
TBB_STRING_RESOURCE(FLOW_BODY, "body") | TBB_STRING_RESOURCE(FLOW_BODY, "body") | |||
TBB_STRING_RESOURCE(FLOW_GRAPH, "graph") | TBB_STRING_RESOURCE(FLOW_GRAPH, "graph") | |||
TBB_STRING_RESOURCE(FLOW_NODE, "node") | TBB_STRING_RESOURCE(FLOW_NODE, "node") | |||
skipping to change at line 73 | skipping to change at line 73 | |||
TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_2, "output_port_2") | TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_2, "output_port_2") | |||
TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_3, "output_port_3") | TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_3, "output_port_3") | |||
TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_4, "output_port_4") | TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_4, "output_port_4") | |||
TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_5, "output_port_5") | TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_5, "output_port_5") | |||
TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_6, "output_port_6") | TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_6, "output_port_6") | |||
TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_7, "output_port_7") | TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_7, "output_port_7") | |||
TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_8, "output_port_8") | TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_8, "output_port_8") | |||
TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_9, "output_port_9") | TBB_STRING_RESOURCE(FLOW_OUTPUT_PORT_9, "output_port_9") | |||
TBB_STRING_RESOURCE(FLOW_OBJECT_NAME, "object_name") | TBB_STRING_RESOURCE(FLOW_OBJECT_NAME, "object_name") | |||
TBB_STRING_RESOURCE(FLOW_NULL, "null") | TBB_STRING_RESOURCE(FLOW_NULL, "null") | |||
TBB_STRING_RESOURCE(FLOW_INDEXER_NODE, "indexer_node") | ||||
End of changes. 2 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
atomic.h | atomic.h | |||
---|---|---|---|---|
skipping to change at line 543 | skipping to change at line 543 | |||
template<typename T> | template<typename T> | |||
atomic<T> make_atomic(T t) { | atomic<T> make_atomic(T t) { | |||
atomic<T> a; | atomic<T> a; | |||
store<relaxed>(a,t); | store<relaxed>(a,t); | |||
return a; | return a; | |||
} | } | |||
} | } | |||
using interface6::make_atomic; | using interface6::make_atomic; | |||
namespace internal { | namespace internal { | |||
template<memory_semantics M, typename T > | ||||
void swap(atomic<T> & lhs, atomic<T> & rhs){ | ||||
T tmp = load<M>(lhs); | ||||
store<M>(lhs,load<M>(rhs)); | ||||
store<M>(rhs,tmp); | ||||
} | ||||
// only to aid in the gradual conversion of ordinary variables to proper at omics | // only to aid in the gradual conversion of ordinary variables to proper at omics | |||
template<typename T> | template<typename T> | |||
inline atomic<T>& as_atomic( T& t ) { | inline atomic<T>& as_atomic( T& t ) { | |||
return (atomic<T>&)t; | return (atomic<T>&)t; | |||
} | } | |||
} // namespace tbb::internal | } // namespace tbb::internal | |||
} // namespace tbb | } // namespace tbb | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 6 lines changed or added | |||
blocked_range.h | blocked_range.h | |||
---|---|---|---|---|
skipping to change at line 97 | skipping to change at line 97 | |||
//--------------------------------------------------------------------- --- | //--------------------------------------------------------------------- --- | |||
//! True if range is empty. | //! True if range is empty. | |||
bool empty() const {return !(my_begin<my_end);} | bool empty() const {return !(my_begin<my_end);} | |||
//! True if range is divisible. | //! True if range is divisible. | |||
/** Unspecified if end()<begin(). */ | /** Unspecified if end()<begin(). */ | |||
bool is_divisible() const {return my_grainsize<size();} | bool is_divisible() const {return my_grainsize<size();} | |||
//! Split range. | //! Split range. | |||
/** The new Range *this has the second half, the old range r has the fi rst half. | /** The new Range *this has the second part, the old range r has the fi rst part. | |||
Unspecified if end()<begin() or !is_divisible(). */ | Unspecified if end()<begin() or !is_divisible(). */ | |||
blocked_range( blocked_range& r, split ) : | blocked_range( blocked_range& r, split ) : | |||
my_end(r.my_end), | my_end(r.my_end), | |||
my_begin(do_split(r)), | my_begin(do_split(r, split())), | |||
my_grainsize(r.my_grainsize) | my_grainsize(r.my_grainsize) | |||
{} | { | |||
// only comparison 'less than' is required from values of blocked_r | ||||
ange objects | ||||
__TBB_ASSERT( !(my_begin < r.my_end) && !(r.my_end < my_begin), "bl | ||||
ocked_range has been split incorrectly" ); | ||||
} | ||||
#if !TBB_DEPRECATED | ||||
//! Static field to support proportional split | ||||
static const bool is_divisible_in_proportion = true; | ||||
//! Split range. | ||||
/** The new Range *this has the second part split according to specifie | ||||
d proportion, the old range r has the first part. | ||||
Unspecified if end()<begin() or !is_divisible(). */ | ||||
blocked_range( blocked_range& r, proportional_split& proportion ) : | ||||
my_end(r.my_end), | ||||
my_begin(do_split(r, proportion)), | ||||
my_grainsize(r.my_grainsize) | ||||
{ | ||||
// only comparison 'less than' is required from values of blocked_r | ||||
ange objects | ||||
__TBB_ASSERT( !(my_begin < r.my_end) && !(r.my_end < my_begin), "bl | ||||
ocked_range has been split incorrectly" ); | ||||
} | ||||
#endif | ||||
private: | private: | |||
/** NOTE: my_end MUST be declared before my_begin, otherwise the forkin g constructor will break. */ | /** NOTE: my_end MUST be declared before my_begin, otherwise the forkin g constructor will break. */ | |||
Value my_end; | Value my_end; | |||
Value my_begin; | Value my_begin; | |||
size_type my_grainsize; | size_type my_grainsize; | |||
//! Auxiliary function used by forking constructor. | //! Auxiliary function used by forking constructor. | |||
/** Using this function lets us not require that Value support assignme nt or default construction. */ | /** Using this function lets us not require that Value support assignme nt or default construction. */ | |||
static Value do_split( blocked_range& r ) { | static Value do_split( blocked_range& r, split ) | |||
{ | ||||
__TBB_ASSERT( r.is_divisible(), "cannot split blocked_range that is not divisible" ); | __TBB_ASSERT( r.is_divisible(), "cannot split blocked_range that is not divisible" ); | |||
Value middle = r.my_begin + (r.my_end-r.my_begin)/2u; | Value middle = r.my_begin + (r.my_end - r.my_begin) / 2u; | |||
r.my_end = middle; | r.my_end = middle; | |||
return middle; | return middle; | |||
} | } | |||
#if !TBB_DEPRECATED | ||||
static Value do_split( blocked_range& r, proportional_split& proportion | ||||
) | ||||
{ | ||||
__TBB_ASSERT( r.is_divisible(), "cannot split blocked_range that is | ||||
not divisible" ); | ||||
// usage of 32-bit floating point arithmetic is not enough to handl | ||||
e ranges of | ||||
// more than 2^24 iterations accurately. However, even on ranges wi | ||||
th 2^64 | ||||
// iterations the computational error approximately equals to 0.000 | ||||
001% which | ||||
// makes small impact on uniform distribution of such range's itera | ||||
tions (assuming | ||||
// all iterations take equal time to complete). See 'test_partition | ||||
er_whitebox' | ||||
// for implementation of an exact split algorithm | ||||
size_type right_part = size_type(float(r.size()) * float(proportion | ||||
.right()) | ||||
/ float(proportion.left() + propor | ||||
tion.right()) + 0.5f); | ||||
return r.my_end = Value(r.my_end - right_part); | ||||
} | ||||
#endif | ||||
template<typename RowValue, typename ColValue> | template<typename RowValue, typename ColValue> | |||
friend class blocked_range2d; | friend class blocked_range2d; | |||
template<typename RowValue, typename ColValue, typename PageValue> | template<typename RowValue, typename ColValue, typename PageValue> | |||
friend class blocked_range3d; | friend class blocked_range3d; | |||
}; | }; | |||
} // namespace tbb | } // namespace tbb | |||
#endif /* __TBB_blocked_range_H */ | #endif /* __TBB_blocked_range_H */ | |||
End of changes. 6 change blocks. | ||||
5 lines changed or deleted | 57 lines changed or added | |||
blocked_range2d.h | blocked_range2d.h | |||
---|---|---|---|---|
skipping to change at line 81 | skipping to change at line 81 | |||
//! True if range is divisible into two pieces. | //! True if range is divisible into two pieces. | |||
bool is_divisible() const { | bool is_divisible() const { | |||
return my_rows.is_divisible() || my_cols.is_divisible(); | return my_rows.is_divisible() || my_cols.is_divisible(); | |||
} | } | |||
blocked_range2d( blocked_range2d& r, split ) : | blocked_range2d( blocked_range2d& r, split ) : | |||
my_rows(r.my_rows), | my_rows(r.my_rows), | |||
my_cols(r.my_cols) | my_cols(r.my_cols) | |||
{ | { | |||
split split_obj; | ||||
do_split(r, split_obj); | ||||
} | ||||
#if !TBB_DEPRECATED | ||||
//! Static field to support proportional split | ||||
static const bool is_divisible_in_proportion = true; | ||||
blocked_range2d( blocked_range2d& r, proportional_split& proportion ) : | ||||
my_rows(r.my_rows), | ||||
my_cols(r.my_cols) | ||||
{ | ||||
do_split(r, proportion); | ||||
} | ||||
#endif | ||||
template <typename Split> | ||||
void do_split( blocked_range2d& r, Split& split_obj ) | ||||
{ | ||||
if( my_rows.size()*double(my_cols.grainsize()) < my_cols.size()*dou ble(my_rows.grainsize()) ) { | if( my_rows.size()*double(my_cols.grainsize()) < my_cols.size()*dou ble(my_rows.grainsize()) ) { | |||
my_cols.my_begin = col_range_type::do_split(r.my_cols); | my_cols.my_begin = col_range_type::do_split(r.my_cols, split_ob j); | |||
} else { | } else { | |||
my_rows.my_begin = row_range_type::do_split(r.my_rows); | my_rows.my_begin = row_range_type::do_split(r.my_rows, split_ob j); | |||
} | } | |||
} | } | |||
//! The rows of the iteration space | //! The rows of the iteration space | |||
const row_range_type& rows() const {return my_rows;} | const row_range_type& rows() const {return my_rows;} | |||
//! The columns of the iteration space | //! The columns of the iteration space | |||
const col_range_type& cols() const {return my_cols;} | const col_range_type& cols() const {return my_cols;} | |||
}; | }; | |||
End of changes. 3 change blocks. | ||||
2 lines changed or deleted | 21 lines changed or added | |||
blocked_range3d.h | blocked_range3d.h | |||
---|---|---|---|---|
skipping to change at line 88 | skipping to change at line 88 | |||
//! True if range is divisible into two pieces. | //! True if range is divisible into two pieces. | |||
bool is_divisible() const { | bool is_divisible() const { | |||
return my_pages.is_divisible() || my_rows.is_divisible() || my_col s.is_divisible(); | return my_pages.is_divisible() || my_rows.is_divisible() || my_col s.is_divisible(); | |||
} | } | |||
blocked_range3d( blocked_range3d& r, split ) : | blocked_range3d( blocked_range3d& r, split ) : | |||
my_pages(r.my_pages), | my_pages(r.my_pages), | |||
my_rows(r.my_rows), | my_rows(r.my_rows), | |||
my_cols(r.my_cols) | my_cols(r.my_cols) | |||
{ | { | |||
if( my_pages.size()*double(my_rows.grainsize()) < my_rows.size()*do | split split_obj; | |||
uble(my_pages.grainsize()) ) { | do_split(r, split_obj); | |||
} | ||||
#if !TBB_DEPRECATED | ||||
//! Static field to support proportional split | ||||
static const bool is_divisible_in_proportion = true; | ||||
blocked_range3d( blocked_range3d& r, proportional_split& proportion ) : | ||||
my_pages(r.my_pages), | ||||
my_rows(r.my_rows), | ||||
my_cols(r.my_cols) | ||||
{ | ||||
do_split(r, proportion); | ||||
} | ||||
#endif | ||||
template <typename Split> | ||||
void do_split( blocked_range3d& r, Split& split_obj) | ||||
{ | ||||
if ( my_pages.size()*double(my_rows.grainsize()) < my_rows.size()*d | ||||
ouble(my_pages.grainsize()) ) { | ||||
if ( my_rows.size()*double(my_cols.grainsize()) < my_cols.size( )*double(my_rows.grainsize()) ) { | if ( my_rows.size()*double(my_cols.grainsize()) < my_cols.size( )*double(my_rows.grainsize()) ) { | |||
my_cols.my_begin = col_range_type::do_split(r.my_cols); | my_cols.my_begin = col_range_type::do_split(r.my_cols, spli t_obj); | |||
} else { | } else { | |||
my_rows.my_begin = row_range_type::do_split(r.my_rows); | my_rows.my_begin = row_range_type::do_split(r.my_rows, spli t_obj); | |||
} | } | |||
} else { | } else { | |||
if ( my_pages.size()*double(my_cols.grainsize()) < my_cols.size ()*double(my_pages.grainsize()) ) { | if ( my_pages.size()*double(my_cols.grainsize()) < my_cols.size ()*double(my_pages.grainsize()) ) { | |||
my_cols.my_begin = col_range_type::do_split(r.my_cols); | my_cols.my_begin = col_range_type::do_split(r.my_cols, spli t_obj); | |||
} else { | } else { | |||
my_pages.my_begin = page_range_type::do_split(r.my_page s); | my_pages.my_begin = page_range_type::do_split(r.my_pages, s plit_obj); | |||
} | } | |||
} | } | |||
} | } | |||
//! The pages of the iteration space | //! The pages of the iteration space | |||
const page_range_type& pages() const {return my_pages;} | const page_range_type& pages() const {return my_pages;} | |||
//! The rows of the iteration space | //! The rows of the iteration space | |||
const row_range_type& rows() const {return my_rows;} | const row_range_type& rows() const {return my_rows;} | |||
End of changes. 5 change blocks. | ||||
6 lines changed or deleted | 26 lines changed or added | |||
concurrent_vector.h | concurrent_vector.h | |||
---|---|---|---|---|
skipping to change at line 107 | skipping to change at line 107 | |||
// Using enumerations due to Mac linking problems of static const v ariables | // Using enumerations due to Mac linking problems of static const v ariables | |||
enum { | enum { | |||
// Size constants | // Size constants | |||
default_initial_segments = 1, // 2 initial items | default_initial_segments = 1, // 2 initial items | |||
//! Number of slots for segment's pointers inside the class | //! Number of slots for segment's pointers inside the class | |||
pointers_per_short_table = 3, // to fit into 8 words of entire structure | pointers_per_short_table = 3, // to fit into 8 words of entire structure | |||
pointers_per_long_table = sizeof(segment_index_t) * 8 // one se gment per bit | pointers_per_long_table = sizeof(segment_index_t) * 8 // one se gment per bit | |||
}; | }; | |||
// Segment pointer. Can be zero-initialized | struct segment_not_used {}; | |||
struct segment_t { | struct segment_allocated {}; | |||
struct segment_allocation_failed {}; | ||||
class segment_t; | ||||
class segment_value_t { | ||||
void* array; | void* array; | |||
private: | ||||
//TODO: More elegant way to grant access to selected functions | ||||
_only_? | ||||
friend class segment_t; | ||||
segment_value_t(void* an_array):array(an_array) {} | ||||
public: | ||||
friend bool operator==(segment_value_t const& lhs, segment_not_ | ||||
used ) { return lhs.array == 0;} | ||||
friend bool operator==(segment_value_t const& lhs, segment_allo | ||||
cated) { return lhs.array > internal::vector_allocation_error_flag;} | ||||
friend bool operator==(segment_value_t const& lhs, segment_allo | ||||
cation_failed) { return lhs.array == internal::vector_allocation_error_flag | ||||
;} | ||||
template<typename argument_type> | ||||
friend bool operator!=(segment_value_t const& lhs, argument_typ | ||||
e arg) { return ! (lhs == arg);} | ||||
template<typename T> | ||||
T* pointer() const { return static_cast<T*>(const_cast<void*>( | ||||
array)); } | ||||
}; | ||||
// Segment pointer. | ||||
class segment_t { | ||||
atomic<void*> array; | ||||
public: | ||||
segment_t(){ store<relaxed>(segment_not_used());} | ||||
//Copy ctor and assignment operator are defined to ease using o | ||||
f stl algorithms. | ||||
//These algorithms usually not a synchronization point, so, sem | ||||
antic is | ||||
//intentionally relaxed here. | ||||
segment_t(segment_t const& rhs ){ array.store<relaxed>(rhs.arra | ||||
y.load<relaxed>());} | ||||
void swap(segment_t & rhs ){ | ||||
tbb::internal::swap<relaxed>(array, rhs.array); | ||||
} | ||||
segment_t& operator=(segment_t const& rhs ){ | ||||
array.store<relaxed>(rhs.array.load<relaxed>()); | ||||
return *this; | ||||
} | ||||
template<memory_semantics M> | ||||
segment_value_t load() const { return segment_value_t(array.loa | ||||
d<M>());} | ||||
template<memory_semantics M> | ||||
void store(segment_not_used) { | ||||
array.store<M>(0); | ||||
} | ||||
template<memory_semantics M> | ||||
void store(segment_allocation_failed) { | ||||
__TBB_ASSERT(load<relaxed>() != segment_allocated(),"transi | ||||
tion from \"allocated\" to \"allocation failed\" state looks non-logical"); | ||||
array.store<M>(internal::vector_allocation_error_flag); | ||||
} | ||||
template<memory_semantics M> | ||||
void store(void* allocated_segment_pointer) __TBB_NOEXCEPT(true | ||||
) { | ||||
__TBB_ASSERT(segment_value_t(allocated_segment_pointer) == | ||||
segment_allocated(), | ||||
"other overloads of store should be used for marking s | ||||
egment as not_used or allocation_failed" ); | ||||
array.store<M>(allocated_segment_pointer); | ||||
} | ||||
#if TBB_USE_ASSERT | #if TBB_USE_ASSERT | |||
~segment_t() { | ~segment_t() { | |||
__TBB_ASSERT( array <= internal::vector_allocation_error_fl ag, "should have been freed by clear" ); | __TBB_ASSERT(load<relaxed>() != segment_allocated(), "shoul d have been freed by clear" ); | |||
} | } | |||
#endif /* TBB_USE_ASSERT */ | #endif /* TBB_USE_ASSERT */ | |||
}; | }; | |||
friend void swap(segment_t & , segment_t & ) __TBB_NOEXCEPT(true); | ||||
// Data fields | // Data fields | |||
//! allocator function pointer | //! allocator function pointer | |||
void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t); | void* (*vector_allocator_ptr)(concurrent_vector_base_v3 &, size_t); | |||
//! count of segments in the first block | //! count of segments in the first block | |||
atomic<size_type> my_first_block; | atomic<size_type> my_first_block; | |||
//! Requested size of vector | //! Requested size of vector | |||
skipping to change at line 137 | skipping to change at line 197 | |||
//! Pointer to the segments table | //! Pointer to the segments table | |||
atomic<segment_t*> my_segment; | atomic<segment_t*> my_segment; | |||
//! embedded storage of segment pointers | //! embedded storage of segment pointers | |||
segment_t my_storage[pointers_per_short_table]; | segment_t my_storage[pointers_per_short_table]; | |||
// Methods | // Methods | |||
concurrent_vector_base_v3() { | concurrent_vector_base_v3() { | |||
my_early_size = 0; | //Here the semantic is intentionally relaxed. | |||
my_first_block = 0; // here is not default_initial_segments | //The reason this is next: | |||
for( segment_index_t i = 0; i < pointers_per_short_table; i++) | //Object that is in middle of construction (i.e. its constructo | |||
my_storage[i].array = NULL; | r is not yet finished) | |||
my_segment = my_storage; | //cannot be used concurrently until the construction is finishe | |||
d. | ||||
//Thus to flag other threads that construction is finished, som | ||||
e synchronization with | ||||
//acquire-release semantic should be done by the (external) cod | ||||
e that uses the vector. | ||||
//So, no need to do the synchronization inside the vector. | ||||
my_early_size.store<relaxed>(0); | ||||
my_first_block.store<relaxed>(0); // here is not default_initia | ||||
l_segments | ||||
my_segment.store<relaxed>(my_storage); | ||||
} | } | |||
__TBB_EXPORTED_METHOD ~concurrent_vector_base_v3(); | __TBB_EXPORTED_METHOD ~concurrent_vector_base_v3(); | |||
//these helpers methods use the fact that segments are allocated so | //these helpers methods use the fact that segments are allocated so | |||
//that every segment size is a (increasing) power of 2. | //that every segment size is a (increasing) power of 2. | |||
//with one exception 0 segment has size of 2 as well segment 1; | //with one exception 0 segment has size of 2 as well segment 1; | |||
//e.g. size of segment with index of 3 is 2^3=8; | //e.g. size of segment with index of 3 is 2^3=8; | |||
static segment_index_t segment_index_of( size_type index ) { | static segment_index_t segment_index_of( size_type index ) { | |||
return segment_index_t( __TBB_Log2( index|1 ) ); | return segment_index_t( __TBB_Log2( index|1 ) ); | |||
} | } | |||
skipping to change at line 185 | skipping to change at line 251 | |||
//! An operation on an n-element array starting at begin. | //! An operation on an n-element array starting at begin. | |||
typedef void (__TBB_EXPORTED_FUNC *internal_array_op1)(void* begin, size_type n ); | typedef void (__TBB_EXPORTED_FUNC *internal_array_op1)(void* begin, size_type n ); | |||
//! An operation on n-element destination array and n-element sourc e array. | //! An operation on n-element destination array and n-element sourc e array. | |||
typedef void (__TBB_EXPORTED_FUNC *internal_array_op2)(void* dst, c onst void* src, size_type n ); | typedef void (__TBB_EXPORTED_FUNC *internal_array_op2)(void* dst, c onst void* src, size_type n ); | |||
//! Internal structure for compact() | //! Internal structure for compact() | |||
struct internal_segments_table { | struct internal_segments_table { | |||
segment_index_t first_block; | segment_index_t first_block; | |||
void* table[pointers_per_long_table]; | segment_t table[pointers_per_long_table]; | |||
}; | }; | |||
void __TBB_EXPORTED_METHOD internal_reserve( size_type n, size_type element_size, size_type max_size ); | void __TBB_EXPORTED_METHOD internal_reserve( size_type n, size_type element_size, size_type max_size ); | |||
size_type __TBB_EXPORTED_METHOD internal_capacity() const; | size_type __TBB_EXPORTED_METHOD internal_capacity() const; | |||
void internal_grow( size_type start, size_type finish, size_type el ement_size, internal_array_op2 init, const void *src ); | void internal_grow( size_type start, size_type finish, size_type el ement_size, internal_array_op2 init, const void *src ); | |||
size_type __TBB_EXPORTED_METHOD internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src ); | size_type __TBB_EXPORTED_METHOD internal_grow_by( size_type delta, size_type element_size, internal_array_op2 init, const void *src ); | |||
void* __TBB_EXPORTED_METHOD internal_push_back( size_type element_s ize, size_type& index ); | void* __TBB_EXPORTED_METHOD internal_push_back( size_type element_s ize, size_type& index ); | |||
segment_index_t __TBB_EXPORTED_METHOD internal_clear( internal_arra y_op1 destroy ); | segment_index_t __TBB_EXPORTED_METHOD internal_clear( internal_arra y_op1 destroy ); | |||
void* __TBB_EXPORTED_METHOD internal_compact( size_type element_siz e, void *table, internal_array_op1 destroy, internal_array_op2 copy ); | void* __TBB_EXPORTED_METHOD internal_compact( size_type element_siz e, void *table, internal_array_op1 destroy, internal_array_op2 copy ); | |||
void __TBB_EXPORTED_METHOD internal_copy( const concurrent_vector_b ase_v3& src, size_type element_size, internal_array_op2 copy ); | void __TBB_EXPORTED_METHOD internal_copy( const concurrent_vector_b ase_v3& src, size_type element_size, internal_array_op2 copy ); | |||
skipping to change at line 218 | skipping to change at line 284 | |||
private: | private: | |||
//! Private functionality | //! Private functionality | |||
class helper; | class helper; | |||
friend class helper; | friend class helper; | |||
template<typename Container, typename Value> | template<typename Container, typename Value> | |||
friend class vector_iterator; | friend class vector_iterator; | |||
}; | }; | |||
inline void swap(concurrent_vector_base_v3::segment_t & lhs, concurrent | ||||
_vector_base_v3::segment_t & rhs) __TBB_NOEXCEPT(true) { | ||||
lhs.swap(rhs); | ||||
} | ||||
typedef concurrent_vector_base_v3 concurrent_vector_base; | typedef concurrent_vector_base_v3 concurrent_vector_base; | |||
//! Meets requirements of a forward iterator for STL and a Value for a blocked_range.*/ | //! Meets requirements of a forward iterator for STL and a Value for a blocked_range.*/ | |||
/** Value is either the T or const T type of the container. | /** Value is either the T or const T type of the container. | |||
@ingroup containers */ | @ingroup containers */ | |||
template<typename Container, typename Value> | template<typename Container, typename Value> | |||
class vector_iterator | class vector_iterator | |||
{ | { | |||
//! concurrent_vector over which we are iterating. | //! concurrent_vector over which we are iterating. | |||
Container* my_vector; | Container* my_vector; | |||
skipping to change at line 537 | skipping to change at line 607 | |||
// STL compatible constructors & destructors | // STL compatible constructors & destructors | |||
//--------------------------------------------------------------------- --- | //--------------------------------------------------------------------- --- | |||
//! Construct empty vector. | //! Construct empty vector. | |||
explicit concurrent_vector(const allocator_type &a = allocator_type()) | explicit concurrent_vector(const allocator_type &a = allocator_type()) | |||
: internal::allocator_base<T, A>(a), internal::concurrent_vector_ba se() | : internal::allocator_base<T, A>(a), internal::concurrent_vector_ba se() | |||
{ | { | |||
vector_allocator_ptr = &internal_allocator; | vector_allocator_ptr = &internal_allocator; | |||
} | } | |||
//Constructors are not required to have synchronization | ||||
//(for more details see comment in the concurrent_vector_base construct | ||||
or). | ||||
#if __TBB_INITIALIZER_LISTS_PRESENT | #if __TBB_INITIALIZER_LISTS_PRESENT | |||
//! Constructor from initializer_list | //! Constructor from initializer_list | |||
concurrent_vector(std::initializer_list<T> init_list, const allocator_t ype &a = allocator_type()) | concurrent_vector(std::initializer_list<T> init_list, const allocator_t ype &a = allocator_type()) | |||
: internal::allocator_base<T, A>(a), internal::concurrent_vector_ba se() | : internal::allocator_base<T, A>(a), internal::concurrent_vector_ba se() | |||
{ | { | |||
vector_allocator_ptr = &internal_allocator; | vector_allocator_ptr = &internal_allocator; | |||
__TBB_TRY { | __TBB_TRY { | |||
internal_assign_iterators(init_list.begin(), init_list.end()); | internal_assign_iterators(init_list.begin(), init_list.end()); | |||
} __TBB_CATCH(...) { | } __TBB_CATCH(...) { | |||
segment_t *table = my_segment; | segment_t *table = my_segment.load<relaxed>();; | |||
internal_free_segments( reinterpret_cast<void**>(table), intern | internal_free_segments( table, internal_clear(&destroy_array), | |||
al_clear(&destroy_array), my_first_block ); | my_first_block.load<relaxed>()); | |||
__TBB_RETHROW(); | __TBB_RETHROW(); | |||
} | } | |||
} | } | |||
#endif //# __TBB_INITIALIZER_LISTS_PRESENT | #endif //# __TBB_INITIALIZER_LISTS_PRESENT | |||
//! Copying constructor | //! Copying constructor | |||
concurrent_vector( const concurrent_vector& vector, const allocator_typ e& a = allocator_type() ) | concurrent_vector( const concurrent_vector& vector, const allocator_typ e& a = allocator_type() ) | |||
: internal::allocator_base<T, A>(a), internal::concurrent_vector_ba se() | : internal::allocator_base<T, A>(a), internal::concurrent_vector_ba se() | |||
{ | { | |||
vector_allocator_ptr = &internal_allocator; | vector_allocator_ptr = &internal_allocator; | |||
__TBB_TRY { | __TBB_TRY { | |||
internal_copy(vector, sizeof(T), ©_array); | internal_copy(vector, sizeof(T), ©_array); | |||
} __TBB_CATCH(...) { | } __TBB_CATCH(...) { | |||
segment_t *table = my_segment; | segment_t *table = my_segment.load<relaxed>(); | |||
internal_free_segments( reinterpret_cast<void**>(table), intern | internal_free_segments( table, internal_clear(&destroy_array), | |||
al_clear(&destroy_array), my_first_block ); | my_first_block.load<relaxed>()); | |||
__TBB_RETHROW(); | __TBB_RETHROW(); | |||
} | } | |||
} | } | |||
//! Copying constructor for vector with different allocator type | //! Copying constructor for vector with different allocator type | |||
template<class M> | template<class M> | |||
concurrent_vector( const concurrent_vector<T, M>& vector, const allocat or_type& a = allocator_type() ) | concurrent_vector( const concurrent_vector<T, M>& vector, const allocat or_type& a = allocator_type() ) | |||
: internal::allocator_base<T, A>(a), internal::concurrent_vector_ba se() | : internal::allocator_base<T, A>(a), internal::concurrent_vector_ba se() | |||
{ | { | |||
vector_allocator_ptr = &internal_allocator; | vector_allocator_ptr = &internal_allocator; | |||
__TBB_TRY { | __TBB_TRY { | |||
internal_copy(vector.internal_vector_base(), sizeof(T), ©_a rray); | internal_copy(vector.internal_vector_base(), sizeof(T), ©_a rray); | |||
} __TBB_CATCH(...) { | } __TBB_CATCH(...) { | |||
segment_t *table = my_segment; | segment_t *table = my_segment.load<relaxed>(); | |||
internal_free_segments( reinterpret_cast<void**>(table), intern | internal_free_segments( table, internal_clear(&destroy_array), | |||
al_clear(&destroy_array), my_first_block ); | my_first_block.load<relaxed>() ); | |||
__TBB_RETHROW(); | __TBB_RETHROW(); | |||
} | } | |||
} | } | |||
//! Construction with initial size specified by argument n | //! Construction with initial size specified by argument n | |||
explicit concurrent_vector(size_type n) | explicit concurrent_vector(size_type n) | |||
{ | { | |||
vector_allocator_ptr = &internal_allocator; | vector_allocator_ptr = &internal_allocator; | |||
__TBB_TRY { | __TBB_TRY { | |||
internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array , &initialize_array ); | internal_resize( n, sizeof(T), max_size(), NULL, &destroy_array , &initialize_array ); | |||
} __TBB_CATCH(...) { | } __TBB_CATCH(...) { | |||
segment_t *table = my_segment; | segment_t *table = my_segment.load<relaxed>(); | |||
internal_free_segments( reinterpret_cast<void**>(table), intern | internal_free_segments( table, internal_clear(&destroy_array), | |||
al_clear(&destroy_array), my_first_block ); | my_first_block.load<relaxed>() ); | |||
__TBB_RETHROW(); | __TBB_RETHROW(); | |||
} | } | |||
} | } | |||
//! Construction with initial size specified by argument n, initializat ion by copying of t, and given allocator instance | //! Construction with initial size specified by argument n, initializat ion by copying of t, and given allocator instance | |||
concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type()) | concurrent_vector(size_type n, const_reference t, const allocator_type& a = allocator_type()) | |||
: internal::allocator_base<T, A>(a) | : internal::allocator_base<T, A>(a) | |||
{ | { | |||
vector_allocator_ptr = &internal_allocator; | vector_allocator_ptr = &internal_allocator; | |||
__TBB_TRY { | __TBB_TRY { | |||
internal_resize( n, sizeof(T), max_size(), static_cast<const vo id*>(&t), &destroy_array, &initialize_array_by ); | internal_resize( n, sizeof(T), max_size(), static_cast<const vo id*>(&t), &destroy_array, &initialize_array_by ); | |||
} __TBB_CATCH(...) { | } __TBB_CATCH(...) { | |||
segment_t *table = my_segment; | segment_t *table = my_segment.load<relaxed>(); | |||
internal_free_segments( reinterpret_cast<void**>(table), intern | internal_free_segments( table, internal_clear(&destroy_array), | |||
al_clear(&destroy_array), my_first_block ); | my_first_block.load<relaxed>() ); | |||
__TBB_RETHROW(); | __TBB_RETHROW(); | |||
} | } | |||
} | } | |||
//! Construction with copying iteration range and given allocator insta nce | //! Construction with copying iteration range and given allocator insta nce | |||
template<class I> | template<class I> | |||
concurrent_vector(I first, I last, const allocator_type &a = allocator_ type()) | concurrent_vector(I first, I last, const allocator_type &a = allocator_ type()) | |||
: internal::allocator_base<T, A>(a) | : internal::allocator_base<T, A>(a) | |||
{ | { | |||
vector_allocator_ptr = &internal_allocator; | vector_allocator_ptr = &internal_allocator; | |||
__TBB_TRY { | __TBB_TRY { | |||
internal_assign_range(first, last, static_cast<is_integer_tag<s td::numeric_limits<I>::is_integer> *>(0) ); | internal_assign_range(first, last, static_cast<is_integer_tag<s td::numeric_limits<I>::is_integer> *>(0) ); | |||
} __TBB_CATCH(...) { | } __TBB_CATCH(...) { | |||
segment_t *table = my_segment; | segment_t *table = my_segment.load<relaxed>(); | |||
internal_free_segments( reinterpret_cast<void**>(table), intern | internal_free_segments( table, internal_clear(&destroy_array), | |||
al_clear(&destroy_array), my_first_block ); | my_first_block.load<relaxed>() ); | |||
__TBB_RETHROW(); | __TBB_RETHROW(); | |||
} | } | |||
} | } | |||
//! Assignment | //! Assignment | |||
concurrent_vector& operator=( const concurrent_vector& vector ) { | concurrent_vector& operator=( const concurrent_vector& vector ) { | |||
if( this != &vector ) | if( this != &vector ) | |||
internal_assign(vector, sizeof(T), &destroy_array, &assign_arra y, ©_array); | internal_assign(vector, sizeof(T), &destroy_array, &assign_arra y, ©_array); | |||
return *this; | return *this; | |||
} | } | |||
skipping to change at line 655 | skipping to change at line 727 | |||
concurrent_vector& operator=( const std::initializer_list<T> & init_lis t) { | concurrent_vector& operator=( const std::initializer_list<T> & init_lis t) { | |||
internal_clear(&destroy_array); | internal_clear(&destroy_array); | |||
internal_assign_iterators(init_list.begin(), init_list.end()); | internal_assign_iterators(init_list.begin(), init_list.end()); | |||
return *this; | return *this; | |||
} | } | |||
#endif //#if __TBB_INITIALIZER_LISTS_PRESENT | #endif //#if __TBB_INITIALIZER_LISTS_PRESENT | |||
//--------------------------------------------------------------------- --- | //--------------------------------------------------------------------- --- | |||
// Concurrent operations | // Concurrent operations | |||
//--------------------------------------------------------------------- --- | //--------------------------------------------------------------------- --- | |||
//TODO: consider adding overload of grow_by accepting range of iterator s: grow_by(iterator,iterator) | ||||
//TODO: consider adding overload of grow_by accepting initializer_list: grow_by(std::initializer_list<T>), as a analogy to std::vector::insert(in itializer_list) | //TODO: consider adding overload of grow_by accepting initializer_list: grow_by(std::initializer_list<T>), as a analogy to std::vector::insert(in itializer_list) | |||
//! Grow by "delta" elements. | //! Grow by "delta" elements. | |||
#if TBB_DEPRECATED | #if TBB_DEPRECATED | |||
/** Returns old size. */ | /** Returns old size. */ | |||
size_type grow_by( size_type delta ) { | size_type grow_by( size_type delta ) { | |||
return delta ? internal_grow_by( delta, sizeof(T), &initialize_arra y, NULL ) : my_early_size.load(); | return delta ? internal_grow_by( delta, sizeof(T), &initialize_arra y, NULL ) : my_early_size.load(); | |||
} | } | |||
#else | #else | |||
/** Returns iterator pointing to the first new element. */ | /** Returns iterator pointing to the first new element. */ | |||
iterator grow_by( size_type delta ) { | iterator grow_by( size_type delta ) { | |||
skipping to change at line 681 | skipping to change at line 752 | |||
#if TBB_DEPRECATED | #if TBB_DEPRECATED | |||
/** Returns old size. */ | /** Returns old size. */ | |||
size_type grow_by( size_type delta, const_reference t ) { | size_type grow_by( size_type delta, const_reference t ) { | |||
return delta ? internal_grow_by( delta, sizeof(T), &initialize_arra y_by, static_cast<const void*>(&t) ) : my_early_size.load(); | return delta ? internal_grow_by( delta, sizeof(T), &initialize_arra y_by, static_cast<const void*>(&t) ) : my_early_size.load(); | |||
} | } | |||
#else | #else | |||
/** Returns iterator pointing to the first new element. */ | /** Returns iterator pointing to the first new element. */ | |||
iterator grow_by( size_type delta, const_reference t ) { | iterator grow_by( size_type delta, const_reference t ) { | |||
return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size.load() ); | return iterator(*this, delta ? internal_grow_by( delta, sizeof(T), &initialize_array_by, static_cast<const void*>(&t) ) : my_early_size.load() ); | |||
} | } | |||
/** Returns iterator pointing to the first new element. */ | ||||
template<typename I> | ||||
iterator grow_by( I first, I last ) { | ||||
typename std::iterator_traits<I>::difference_type | ||||
delta = std::distance(first, last); | ||||
__TBB_ASSERT( delta > 0, NULL); | ||||
return iterator(*this, internal_grow_by( delta, sizeof(T), ©_r | ||||
ange<I>, static_cast<const void*>(&first) )); | ||||
} | ||||
#endif | #endif | |||
//! Append minimal sequence of elements such that size()>=n. | //! Append minimal sequence of elements such that size()>=n. | |||
#if TBB_DEPRECATED | #if TBB_DEPRECATED | |||
/** The new elements are default constructed. Blocks until all element s in range [0..n) are allocated. | /** The new elements are default constructed. Blocks until all element s in range [0..n) are allocated. | |||
May return while other elements are being constructed by other thre ads. */ | May return while other elements are being constructed by other thre ads. */ | |||
void grow_to_at_least( size_type n ) { | void grow_to_at_least( size_type n ) { | |||
if( n ) internal_grow_to_at_least_with_result( n, sizeof(T), &initi alize_array, NULL ); | if( n ) internal_grow_to_at_least_with_result( n, sizeof(T), &initi alize_array, NULL ); | |||
}; | }; | |||
#else | #else | |||
skipping to change at line 703 | skipping to change at line 784 | |||
Returns iterator that points to beginning of appended sequence. | Returns iterator that points to beginning of appended sequence. | |||
If no elements were appended, returns iterator pointing to nth elem ent. */ | If no elements were appended, returns iterator pointing to nth elem ent. */ | |||
iterator grow_to_at_least( size_type n ) { | iterator grow_to_at_least( size_type n ) { | |||
size_type m=0; | size_type m=0; | |||
if( n ) { | if( n ) { | |||
m = internal_grow_to_at_least_with_result( n, sizeof(T), &initi alize_array, NULL ); | m = internal_grow_to_at_least_with_result( n, sizeof(T), &initi alize_array, NULL ); | |||
if( m>n ) m=n; | if( m>n ) m=n; | |||
} | } | |||
return iterator(*this, m); | return iterator(*this, m); | |||
}; | }; | |||
/** Analogous to grow_to_at_least( size_type n ) with exception that th | ||||
e new | ||||
elements are initialized by copying of t instead of default constru | ||||
ction. */ | ||||
iterator grow_to_at_least( size_type n, const_reference t ) { | ||||
size_type m=0; | ||||
if( n ) { | ||||
m = internal_grow_to_at_least_with_result( n, sizeof(T), &initi | ||||
alize_array_by, &t); | ||||
if( m>n ) m=n; | ||||
} | ||||
return iterator(*this, m); | ||||
}; | ||||
#endif | #endif | |||
//! Push item | //! Push item | |||
#if TBB_DEPRECATED | #if TBB_DEPRECATED | |||
size_type push_back( const_reference item ) | size_type push_back( const_reference item ) | |||
#else | #else | |||
/** Returns iterator pointing to the new element. */ | /** Returns iterator pointing to the new element. */ | |||
iterator push_back( const_reference item ) | iterator push_back( const_reference item ) | |||
#endif | #endif | |||
{ | { | |||
skipping to change at line 831 | skipping to change at line 924 | |||
const_reverse_iterator rbegin() const {return const_reverse_iterator(en d());} | const_reverse_iterator rbegin() const {return const_reverse_iterator(en d());} | |||
//! reverse end const iterator | //! reverse end const iterator | |||
const_reverse_iterator rend() const {return const_reverse_iterator(begi n());} | const_reverse_iterator rend() const {return const_reverse_iterator(begi n());} | |||
//! reverse start const iterator | //! reverse start const iterator | |||
const_reverse_iterator crbegin() const {return const_reverse_iterator(e nd());} | const_reverse_iterator crbegin() const {return const_reverse_iterator(e nd());} | |||
//! reverse end const iterator | //! reverse end const iterator | |||
const_reverse_iterator crend() const {return const_reverse_iterator(beg in());} | const_reverse_iterator crend() const {return const_reverse_iterator(beg in());} | |||
//! the first item | //! the first item | |||
reference front() { | reference front() { | |||
__TBB_ASSERT( size()>0, NULL); | __TBB_ASSERT( size()>0, NULL); | |||
return static_cast<T*>(my_segment[0].array)[0]; | return (my_segment[0].template load<relaxed>().template pointer<T>( ))[0]; | |||
} | } | |||
//! the first item const | //! the first item const | |||
const_reference front() const { | const_reference front() const { | |||
__TBB_ASSERT( size()>0, NULL); | __TBB_ASSERT( size()>0, NULL); | |||
return static_cast<const T*>(my_segment[0].array)[0]; | return static_cast<const T*>(my_segment[0].array)[0]; | |||
} | } | |||
//! the last item | //! the last item | |||
reference back() { | reference back() { | |||
__TBB_ASSERT( size()>0, NULL); | __TBB_ASSERT( size()>0, NULL); | |||
return internal_subscript( size()-1 ); | return internal_subscript( size()-1 ); | |||
skipping to change at line 887 | skipping to change at line 980 | |||
} | } | |||
//! Clear container while keeping memory allocated. | //! Clear container while keeping memory allocated. | |||
/** To free up the memory, use in conjunction with method compact(). No t thread safe **/ | /** To free up the memory, use in conjunction with method compact(). No t thread safe **/ | |||
void clear() { | void clear() { | |||
internal_clear(&destroy_array); | internal_clear(&destroy_array); | |||
} | } | |||
//! Clear and destroy vector. | //! Clear and destroy vector. | |||
~concurrent_vector() { | ~concurrent_vector() { | |||
segment_t *table = my_segment; | segment_t *table = my_segment.load<relaxed>(); | |||
internal_free_segments( reinterpret_cast<void**>(table), internal_c | internal_free_segments( table, internal_clear(&destroy_array), my_f | |||
lear(&destroy_array), my_first_block ); | irst_block.load<relaxed>() ); | |||
// base class destructor call should be then | // base class destructor call should be then | |||
} | } | |||
const internal::concurrent_vector_base_v3 &internal_vector_base() const { return *this; } | const internal::concurrent_vector_base_v3 &internal_vector_base() const { return *this; } | |||
private: | private: | |||
//! Allocate k items | //! Allocate k items | |||
static void *internal_allocator(internal::concurrent_vector_base_v3 &vb , size_t k) { | static void *internal_allocator(internal::concurrent_vector_base_v3 &vb , size_t k) { | |||
return static_cast<concurrent_vector<T, A>&>(vb).my_allocator.alloc ate(k); | return static_cast<concurrent_vector<T, A>&>(vb).my_allocator.alloc ate(k); | |||
} | } | |||
//! Free k segments from table | //! Free k segments from table | |||
void internal_free_segments(void *table[], segment_index_t k, segment_i ndex_t first_block); | void internal_free_segments(segment_t table[], segment_index_t k, segme nt_index_t first_block); | |||
//! Get reference to element at given index. | //! Get reference to element at given index. | |||
T& internal_subscript( size_type index ) const; | T& internal_subscript( size_type index ) const; | |||
//! Get reference to element at given index with errors checks | //! Get reference to element at given index with errors checks | |||
T& internal_subscript_with_exceptions( size_type index ) const; | T& internal_subscript_with_exceptions( size_type index ) const; | |||
//! assign n items by copying t | //! assign n items by copying t | |||
void internal_assign_n(size_type n, const_pointer p) { | void internal_assign_n(size_type n, const_pointer p) { | |||
internal_resize( n, sizeof(T), max_size(), static_cast<const void*> (p), &destroy_array, p? &initialize_array_by : &initialize_array ); | internal_resize( n, sizeof(T), max_size(), static_cast<const void*> (p), &destroy_array, p? &initialize_array_by : &initialize_array ); | |||
skipping to change at line 929 | skipping to change at line 1022 | |||
} | } | |||
//! inline proxy assign by iterators | //! inline proxy assign by iterators | |||
template<class I> | template<class I> | |||
void internal_assign_range(I first, I last, is_integer_tag<false> *) { | void internal_assign_range(I first, I last, is_integer_tag<false> *) { | |||
internal_assign_iterators(first, last); | internal_assign_iterators(first, last); | |||
} | } | |||
//! assign by iterators | //! assign by iterators | |||
template<class I> | template<class I> | |||
void internal_assign_iterators(I first, I last); | void internal_assign_iterators(I first, I last); | |||
//these functions are marked __TBB_EXPORTED_FUNC as they are called fro | ||||
m within the library | ||||
//! Construct n instances of T, starting at "begin". | //! Construct n instances of T, starting at "begin". | |||
static void __TBB_EXPORTED_FUNC initialize_array( void* begin, const vo id*, size_type n ); | static void __TBB_EXPORTED_FUNC initialize_array( void* begin, const vo id*, size_type n ); | |||
//! Construct n instances of T, starting at "begin". | //! Construct n instances of T, starting at "begin". | |||
static void __TBB_EXPORTED_FUNC initialize_array_by( void* begin, const void* src, size_type n ); | static void __TBB_EXPORTED_FUNC initialize_array_by( void* begin, const void* src, size_type n ); | |||
//! Construct n instances of T, starting at "begin". | //! Construct n instances of T, starting at "begin". | |||
static void __TBB_EXPORTED_FUNC copy_array( void* dst, const void* src, size_type n ); | static void __TBB_EXPORTED_FUNC copy_array( void* dst, const void* src, size_type n ); | |||
//! Construct n instances of T, starting at "begin". | ||||
template<typename Iterator> | ||||
static void __TBB_EXPORTED_FUNC copy_range( void* dst, const void* p_ty | ||||
pe_erased_iterator, size_type n ); | ||||
//! Assign n instances of T, starting at "begin". | //! Assign n instances of T, starting at "begin". | |||
static void __TBB_EXPORTED_FUNC assign_array( void* dst, const void* sr c, size_type n ); | static void __TBB_EXPORTED_FUNC assign_array( void* dst, const void* sr c, size_type n ); | |||
//! Destroy n instances of T, starting at "begin". | //! Destroy n instances of T, starting at "begin". | |||
static void __TBB_EXPORTED_FUNC destroy_array( void* begin, size_type n ); | static void __TBB_EXPORTED_FUNC destroy_array( void* begin, size_type n ); | |||
//! Exception-aware helper class for filling a segment by exception-dan ger operators of user class | //! Exception-aware helper class for filling a segment by exception-dan ger operators of user class | |||
class internal_loop_guide : internal::no_copy { | class internal_loop_guide : internal::no_copy { | |||
public: | public: | |||
const pointer array; | const pointer array; | |||
skipping to change at line 986 | skipping to change at line 1085 | |||
if( old.first_block ) // free segment allocated for compacting. Onl y for support of exceptions in ctor of user T[ype] | if( old.first_block ) // free segment allocated for compacting. Onl y for support of exceptions in ctor of user T[ype] | |||
internal_free_segments( old.table, 1, old.first_block ); | internal_free_segments( old.table, 1, old.first_block ); | |||
__TBB_RETHROW(); | __TBB_RETHROW(); | |||
} | } | |||
} | } | |||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | |||
#pragma warning (pop) | #pragma warning (pop) | |||
#endif // warning 4701 is back | #endif // warning 4701 is back | |||
template<typename T, class A> | template<typename T, class A> | |||
void concurrent_vector<T, A>::internal_free_segments(void *table[], segment _index_t k, segment_index_t first_block) { | void concurrent_vector<T, A>::internal_free_segments(segment_t table[], seg ment_index_t k, segment_index_t first_block) { | |||
// Free the arrays | // Free the arrays | |||
while( k > first_block ) { | while( k > first_block ) { | |||
--k; | --k; | |||
T* array = static_cast<T*>(table[k]); | segment_value_t segment_value = table[k].load<relaxed>(); | |||
table[k] = NULL; | table[k].store<relaxed>(segment_not_used()); | |||
if( array > internal::vector_allocation_error_flag ) // check for c | if( segment_value == segment_allocated() ) // check for correct seg | |||
orrect segment pointer | ment pointer | |||
this->my_allocator.deallocate( array, segment_size(k) ); | this->my_allocator.deallocate( (segment_value.pointer<T>()), se | |||
gment_size(k) ); | ||||
} | } | |||
T* array = static_cast<T*>(table[0]); | segment_value_t segment_value = table[0].load<relaxed>(); | |||
if( array > internal::vector_allocation_error_flag ) { | if( segment_value == segment_allocated() ) { | |||
__TBB_ASSERT( first_block > 0, NULL ); | __TBB_ASSERT( first_block > 0, NULL ); | |||
while(k > 0) table[--k] = NULL; | while(k > 0) table[--k].store<relaxed>(segment_not_used()); | |||
this->my_allocator.deallocate( array, segment_size(first_block) ); | this->my_allocator.deallocate( (segment_value.pointer<T>()), segmen | |||
t_size(first_block) ); | ||||
} | } | |||
} | } | |||
template<typename T, class A> | template<typename T, class A> | |||
T& concurrent_vector<T, A>::internal_subscript( size_type index ) const { | T& concurrent_vector<T, A>::internal_subscript( size_type index ) const { | |||
//TODO: unify both versions of internal_subscript | ||||
__TBB_ASSERT( index < my_early_size, "index out of bounds" ); | __TBB_ASSERT( index < my_early_size, "index out of bounds" ); | |||
size_type j = index; | size_type j = index; | |||
segment_index_t k = segment_base_index_of( j ); | segment_index_t k = segment_base_index_of( j ); | |||
__TBB_ASSERT( (segment_t*)my_segment != my_storage || k < pointers_per_ | __TBB_ASSERT( my_segment.load<acquire>() != my_storage || k < pointers_ | |||
short_table, "index is being allocated" ); | per_short_table, "index is being allocated" ); | |||
// no need in __TBB_load_with_acquire since thread works in own space o | //no need in load with acquire (load<acquire>) since thread works in ow | |||
r gets | n space or gets | |||
T* array = static_cast<T*>( tbb::internal::itt_hide_load_word(my_segmen | //the information about added elements via some form of external synchr | |||
t[k].array)); | onization | |||
__TBB_ASSERT( array != internal::vector_allocation_error_flag, "the ins | //TODO: why not make a load of my_segment relaxed as well ? | |||
tance is broken by bad allocation. Use at() instead" ); | //TODO: add an assertion that my_segment[k] is properly aligned to plea | |||
__TBB_ASSERT( array, "index is being allocated" ); | se ITT | |||
return array[j]; | segment_value_t segment_value = my_segment[k].template load<relaxed>() | |||
; | ||||
__TBB_ASSERT( segment_value != segment_allocation_failed(), "the instan | ||||
ce is broken by bad allocation. Use at() instead" ); | ||||
__TBB_ASSERT( segment_value != segment_not_used(), "index is being allo | ||||
cated" ); | ||||
return (( segment_value.pointer<T>()))[j]; | ||||
} | } | |||
template<typename T, class A> | template<typename T, class A> | |||
T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type i ndex ) const { | T& concurrent_vector<T, A>::internal_subscript_with_exceptions( size_type i ndex ) const { | |||
if( index >= my_early_size ) | if( index >= my_early_size ) | |||
internal::throw_exception(internal::eid_out_of_range); // throw std ::out_of_range | internal::throw_exception(internal::eid_out_of_range); // throw std ::out_of_range | |||
size_type j = index; | size_type j = index; | |||
segment_index_t k = segment_base_index_of( j ); | segment_index_t k = segment_base_index_of( j ); | |||
if( (segment_t*)my_segment == my_storage && k >= pointers_per_short_tab | //TODO: refactor this condition into separate helper function, e.g. fit | |||
le ) | s_into_small_table | |||
if( my_segment.load<acquire>() == my_storage && k >= pointers_per_short | ||||
_table ) | ||||
internal::throw_exception(internal::eid_segment_range_error); // th row std::range_error | internal::throw_exception(internal::eid_segment_range_error); // th row std::range_error | |||
void *array = my_segment[k].array; // no need in __TBB_load_with_acquir | // no need in load with acquire (load<acquire>) since thread works in o | |||
e | wn space or gets | |||
if( array <= internal::vector_allocation_error_flag ) // check for corr | //the information about added elements via some form of external synchr | |||
ect segment pointer | onization | |||
//TODO: why not make a load of my_segment relaxed as well ? | ||||
//TODO: add an assertion that my_segment[k] is properly aligned to plea | ||||
se ITT | ||||
segment_value_t segment_value = my_segment[k].template load<relaxed>() | ||||
; | ||||
if( segment_value != segment_allocated() ) // check for correct segment | ||||
pointer | ||||
internal::throw_exception(internal::eid_index_range_error); // thro w std::range_error | internal::throw_exception(internal::eid_index_range_error); // thro w std::range_error | |||
return static_cast<T*>(array)[j]; | return (segment_value.pointer<T>())[j]; | |||
} | } | |||
template<typename T, class A> template<class I> | template<typename T, class A> template<class I> | |||
void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) { | void concurrent_vector<T, A>::internal_assign_iterators(I first, I last) { | |||
__TBB_ASSERT(my_early_size == 0, NULL); | __TBB_ASSERT(my_early_size == 0, NULL); | |||
size_type n = std::distance(first, last); | size_type n = std::distance(first, last); | |||
if( !n ) return; | if( !n ) return; | |||
internal_reserve(n, sizeof(T), max_size()); | internal_reserve(n, sizeof(T), max_size()); | |||
my_early_size = n; | my_early_size = n; | |||
segment_index_t k = 0; | segment_index_t k = 0; | |||
size_type sz = segment_size( my_first_block ); | size_type sz = segment_size( my_first_block ); | |||
while( sz < n ) { | while( sz < n ) { | |||
internal_loop_guide loop(sz, my_segment[k].array); | internal_loop_guide loop(sz, my_segment[k].template load<relaxed>() .template pointer<void>()); | |||
loop.iterate(first); | loop.iterate(first); | |||
n -= sz; | n -= sz; | |||
if( !k ) k = my_first_block; | if( !k ) k = my_first_block; | |||
else { ++k; sz <<= 1; } | else { ++k; sz <<= 1; } | |||
} | } | |||
internal_loop_guide loop(n, my_segment[k].array); | internal_loop_guide loop(n, my_segment[k].template load<relaxed>().temp late pointer<void>()); | |||
loop.iterate(first); | loop.iterate(first); | |||
} | } | |||
template<typename T, class A> | template<typename T, class A> | |||
void concurrent_vector<T, A>::initialize_array( void* begin, const void *, size_type n ) { | void concurrent_vector<T, A>::initialize_array( void* begin, const void *, size_type n ) { | |||
internal_loop_guide loop(n, begin); loop.init(); | internal_loop_guide loop(n, begin); loop.init(); | |||
} | } | |||
template<typename T, class A> | template<typename T, class A> | |||
void concurrent_vector<T, A>::initialize_array_by( void* begin, const void *src, size_type n ) { | void concurrent_vector<T, A>::initialize_array_by( void* begin, const void *src, size_type n ) { | |||
internal_loop_guide loop(n, begin); loop.init(src); | internal_loop_guide loop(n, begin); loop.init(src); | |||
} | } | |||
template<typename T, class A> | template<typename T, class A> | |||
void concurrent_vector<T, A>::copy_array( void* dst, const void* src, size_ type n ) { | void concurrent_vector<T, A>::copy_array( void* dst, const void* src, size_ type n ) { | |||
internal_loop_guide loop(n, dst); loop.copy(src); | internal_loop_guide loop(n, dst); loop.copy(src); | |||
} | } | |||
template<typename T, class A> | template<typename T, class A> | |||
template<typename I> | ||||
void concurrent_vector<T, A>::copy_range( void* dst, const void* p_type_era | ||||
sed_iterator, size_type n ){ | ||||
I & iterator ((*const_cast<I*>(static_cast<const I*>(p_type_erased_iter | ||||
ator)))); | ||||
internal_loop_guide loop(n, dst); loop.iterate(iterator); | ||||
} | ||||
template<typename T, class A> | ||||
void concurrent_vector<T, A>::assign_array( void* dst, const void* src, siz e_type n ) { | void concurrent_vector<T, A>::assign_array( void* dst, const void* src, siz e_type n ) { | |||
internal_loop_guide loop(n, dst); loop.assign(src); | internal_loop_guide loop(n, dst); loop.assign(src); | |||
} | } | |||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | |||
// Workaround for overzealous compiler warning | // Workaround for overzealous compiler warning | |||
#pragma warning (push) | #pragma warning (push) | |||
#pragma warning (disable: 4189) | #pragma warning (disable: 4189) | |||
#endif | #endif | |||
template<typename T, class A> | template<typename T, class A> | |||
End of changes. 34 change blocks. | ||||
62 lines changed or deleted | 216 lines changed or added | |||
flow_graph.h | flow_graph.h | |||
---|---|---|---|---|
skipping to change at line 2339 | skipping to change at line 2339 | |||
#if TBB_PREVIEW_FLOW_GRAPH_TRACE | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |||
/* override */ void set_name( const char *name ) { | /* override */ void set_name( const char *name ) { | |||
tbb::internal::fgt_node_desc( this, name ); | tbb::internal::fgt_node_desc( this, name ); | |||
} | } | |||
#endif | #endif | |||
}; | }; | |||
#if TBB_PREVIEW_GRAPH_NODES | #if TBB_PREVIEW_GRAPH_NODES | |||
// or node | // indexer node | |||
#include "internal/_flow_graph_or_impl.h" | #include "internal/_flow_graph_indexer_impl.h" | |||
template<typename InputTuple> | struct indexer_null_type {}; | |||
class or_node : public internal::unfolded_or_node<InputTuple> { | ||||
template<typename T0, typename T1=indexer_null_type, typename T2=indexer_nu | ||||
ll_type, typename T3=indexer_null_type, | ||||
typename T4=indexer_null_type, typename T5=indexer_nu | ||||
ll_type, typename T6=indexer_null_type, | ||||
typename T7=indexer_null_type, typename T8=indexer_nu | ||||
ll_type, typename T9=indexer_null_type> class indexer_node; | ||||
//indexer node specializations | ||||
template<typename T0> | ||||
class indexer_node<T0> : public internal::unfolded_indexer_node<tuple<T0> > | ||||
{ | ||||
private: | ||||
static const int N = 1; | ||||
public: | ||||
typedef tuple<T0> InputTuple; | ||||
typedef typename internal::tagged_msg<size_t, T0> output_type; | ||||
typedef typename internal::unfolded_indexer_node<InputTuple> unfolded_t | ||||
ype; | ||||
indexer_node(graph& g) : unfolded_type(g) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
// Copy constructor | ||||
indexer_node( const indexer_node& other ) : unfolded_type(other) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
#if TBB_PREVIEW_FLOW_GRAPH_TRACE | ||||
void set_name( const char *name ) { | ||||
tbb::internal::fgt_node_desc( this, name ); | ||||
} | ||||
#endif | ||||
}; | ||||
template<typename T0, typename T1> | ||||
class indexer_node<T0, T1> : public internal::unfolded_indexer_node<tuple<T | ||||
0, T1> > { | ||||
private: | ||||
static const int N = 2; | ||||
public: | ||||
typedef tuple<T0, T1> InputTuple; | ||||
typedef typename internal::tagged_msg<size_t, T0, T1> output_type; | ||||
typedef typename internal::unfolded_indexer_node<InputTuple> unfolded_t | ||||
ype; | ||||
indexer_node(graph& g) : unfolded_type(g) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
// Copy constructor | ||||
indexer_node( const indexer_node& other ) : unfolded_type(other) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
#if TBB_PREVIEW_FLOW_GRAPH_TRACE | ||||
void set_name( const char *name ) { | ||||
tbb::internal::fgt_node_desc( this, name ); | ||||
} | ||||
#endif | ||||
}; | ||||
template<typename T0, typename T1, typename T2> | ||||
class indexer_node<T0, T1, T2> : public internal::unfolded_indexer_node<tup | ||||
le<T0, T1, T2> > { | ||||
private: | private: | |||
static const int N = tbb::flow::tuple_size<InputTuple>::value; | static const int N = 3; | |||
public: | public: | |||
typedef typename internal::or_output_type<InputTuple>::type output_type | typedef tuple<T0, T1, T2> InputTuple; | |||
; | typedef typename internal::tagged_msg<size_t, T0, T1, T2> output_type; | |||
typedef typename internal::unfolded_or_node<InputTuple> unfolded_type; | typedef typename internal::unfolded_indexer_node<InputTuple> unfolded_t | |||
or_node(graph& g) : unfolded_type(g) { | ype; | |||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | indexer_node(graph& g) : unfolded_type(g) { | |||
OW_OR_NODE, &this->my_graph, | tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | |||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast < sender< output_type > *>(this) ); | this->input_ports(), static_cast < sender< output_type > *>(this) ); | |||
} | } | |||
// Copy constructor | // Copy constructor | |||
or_node( const or_node& other ) : unfolded_type(other) { | indexer_node( const indexer_node& other ) : unfolded_type(other) { | |||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | |||
OW_OR_NODE, &this->my_graph, | OW_INDEXER_NODE, &this->my_graph, | |||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
#if TBB_PREVIEW_FLOW_GRAPH_TRACE | ||||
void set_name( const char *name ) { | ||||
tbb::internal::fgt_node_desc( this, name ); | ||||
} | ||||
#endif | ||||
}; | ||||
template<typename T0, typename T1, typename T2, typename T3> | ||||
class indexer_node<T0, T1, T2, T3> : public internal::unfolded_indexer_node | ||||
<tuple<T0, T1, T2, T3> > { | ||||
private: | ||||
static const int N = 4; | ||||
public: | ||||
typedef tuple<T0, T1, T2, T3> InputTuple; | ||||
typedef typename internal::tagged_msg<size_t, T0, T1, T2, T3> output_ty | ||||
pe; | ||||
typedef typename internal::unfolded_indexer_node<InputTuple> unfolded_t | ||||
ype; | ||||
indexer_node(graph& g) : unfolded_type(g) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
// Copy constructor | ||||
indexer_node( const indexer_node& other ) : unfolded_type(other) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast < sender< output_type > *>(this) ); | this->input_ports(), static_cast < sender< output_type > *>(this) ); | |||
} | } | |||
#if TBB_PREVIEW_FLOW_GRAPH_TRACE | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |||
/* override */ void set_name( const char *name ) { | /* override */ void set_name( const char *name ) { | |||
tbb::internal::fgt_node_desc( this, name ); | tbb::internal::fgt_node_desc( this, name ); | |||
} | } | |||
#endif | #endif | |||
}; | ||||
template<typename T0, typename T1, typename T2, typename T3, typename T4> | ||||
class indexer_node<T0, T1, T2, T3, T4> : public internal::unfolded_indexer_ | ||||
node<tuple<T0, T1, T2, T3, T4> > { | ||||
private: | ||||
static const int N = 5; | ||||
public: | ||||
typedef tuple<T0, T1, T2, T3, T4> InputTuple; | ||||
typedef typename internal::tagged_msg<size_t, T0, T1, T2, T3, T4> outpu | ||||
t_type; | ||||
typedef typename internal::unfolded_indexer_node<InputTuple> unfolded_t | ||||
ype; | ||||
indexer_node(graph& g) : unfolded_type(g) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
// Copy constructor | ||||
indexer_node( const indexer_node& other ) : unfolded_type(other) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
#if TBB_PREVIEW_FLOW_GRAPH_TRACE | ||||
/* override */ void set_name( const char *name ) { | ||||
tbb::internal::fgt_node_desc( this, name ); | ||||
} | ||||
#endif | ||||
}; | }; | |||
#if __TBB_VARIADIC_MAX >= 6 | ||||
template<typename T0, typename T1, typename T2, typename T3, typename T4, t | ||||
ypename T5> | ||||
class indexer_node<T0, T1, T2, T3, T4, T5> : public internal::unfolded_inde | ||||
xer_node<tuple<T0, T1, T2, T3, T4, T5> > { | ||||
private: | ||||
static const int N = 6; | ||||
public: | ||||
typedef tuple<T0, T1, T2, T3, T4, T5> InputTuple; | ||||
typedef typename internal::tagged_msg<size_t, T0, T1, T2, T3, T4, T5> o | ||||
utput_type; | ||||
typedef typename internal::unfolded_indexer_node<InputTuple> unfolded_t | ||||
ype; | ||||
indexer_node(graph& g) : unfolded_type(g) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
// Copy constructor | ||||
indexer_node( const indexer_node& other ) : unfolded_type(other) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
#if TBB_PREVIEW_FLOW_GRAPH_TRACE | ||||
/* override */ void set_name( const char *name ) { | ||||
tbb::internal::fgt_node_desc( this, name ); | ||||
} | ||||
#endif | ||||
}; | ||||
#endif //variadic max 6 | ||||
#if __TBB_VARIADIC_MAX >= 7 | ||||
template<typename T0, typename T1, typename T2, typename T3, typename T4, t | ||||
ypename T5, | ||||
typename T6> | ||||
class indexer_node<T0, T1, T2, T3, T4, T5, T6> : public internal::unfolded_ | ||||
indexer_node<tuple<T0, T1, T2, T3, T4, T5, T6> > { | ||||
private: | ||||
static const int N = 7; | ||||
public: | ||||
typedef tuple<T0, T1, T2, T3, T4, T5, T6> InputTuple; | ||||
typedef typename internal::tagged_msg<size_t, T0, T1, T2, T3, T4, T5, T | ||||
6> output_type; | ||||
typedef typename internal::unfolded_indexer_node<InputTuple> unfolded_t | ||||
ype; | ||||
indexer_node(graph& g) : unfolded_type(g) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
// Copy constructor | ||||
indexer_node( const indexer_node& other ) : unfolded_type(other) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
#if TBB_PREVIEW_FLOW_GRAPH_TRACE | ||||
/* override */ void set_name( const char *name ) { | ||||
tbb::internal::fgt_node_desc( this, name ); | ||||
} | ||||
#endif | ||||
}; | ||||
#endif //variadic max 7 | ||||
#if __TBB_VARIADIC_MAX >= 8 | ||||
template<typename T0, typename T1, typename T2, typename T3, typename T4, t | ||||
ypename T5, | ||||
typename T6, typename T7> | ||||
class indexer_node<T0, T1, T2, T3, T4, T5, T6, T7> : public internal::unfol | ||||
ded_indexer_node<tuple<T0, T1, T2, T3, T4, T5, T6, T7> > { | ||||
private: | ||||
static const int N = 8; | ||||
public: | ||||
typedef tuple<T0, T1, T2, T3, T4, T5, T6, T7> InputTuple; | ||||
typedef typename internal::tagged_msg<size_t, T0, T1, T2, T3, T4, T5, T | ||||
6, T7> output_type; | ||||
typedef typename internal::unfolded_indexer_node<InputTuple> unfolded_t | ||||
ype; | ||||
indexer_node(graph& g) : unfolded_type(g) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
// Copy constructor | ||||
indexer_node( const indexer_node& other ) : unfolded_type(other) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
#if TBB_PREVIEW_FLOW_GRAPH_TRACE | ||||
/* override */ void set_name( const char *name ) { | ||||
tbb::internal::fgt_node_desc( this, name ); | ||||
} | ||||
#endif | ||||
}; | ||||
#endif //variadic max 8 | ||||
#if __TBB_VARIADIC_MAX >= 9 | ||||
template<typename T0, typename T1, typename T2, typename T3, typename T4, t | ||||
ypename T5, | ||||
typename T6, typename T7, typename T8> | ||||
class indexer_node<T0, T1, T2, T3, T4, T5, T6, T7, T8> : public internal::u | ||||
nfolded_indexer_node<tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8> > { | ||||
private: | ||||
static const int N = 9; | ||||
public: | ||||
typedef tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8> InputTuple; | ||||
typedef typename internal::tagged_msg<size_t, T0, T1, T2, T3, T4, T5, T | ||||
6, T7, T8> output_type; | ||||
typedef typename internal::unfolded_indexer_node<InputTuple> unfolded_t | ||||
ype; | ||||
indexer_node(graph& g) : unfolded_type(g) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
// Copy constructor | ||||
indexer_node( const indexer_node& other ) : unfolded_type(other) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
#if TBB_PREVIEW_FLOW_GRAPH_TRACE | ||||
/* override */ void set_name( const char *name ) { | ||||
tbb::internal::fgt_node_desc( this, name ); | ||||
} | ||||
#endif | ||||
}; | ||||
#endif //variadic max 9 | ||||
#if __TBB_VARIADIC_MAX >= 10 | ||||
template<typename T0, typename T1, typename T2, typename T3, typename T4, t | ||||
ypename T5, | ||||
typename T6, typename T7, typename T8, typename T9> | ||||
class indexer_node/*default*/ : public internal::unfolded_indexer_node<tupl | ||||
e<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> > { | ||||
private: | ||||
static const int N = 10; | ||||
public: | ||||
typedef tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> InputTuple; | ||||
typedef typename internal::tagged_msg<size_t, T0, T1, T2, T3, T4, T5, T | ||||
6, T7, T8, T9> output_type; | ||||
typedef typename internal::unfolded_indexer_node<InputTuple> unfolded_t | ||||
ype; | ||||
indexer_node(graph& g) : unfolded_type(g) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
// Copy constructor | ||||
indexer_node( const indexer_node& other ) : unfolded_type(other) { | ||||
tbb::internal::fgt_multiinput_node<InputTuple,N>( tbb::internal::FL | ||||
OW_INDEXER_NODE, &this->my_graph, | ||||
this->input_ports(), static_cast | ||||
< sender< output_type > *>(this) ); | ||||
} | ||||
#if TBB_PREVIEW_FLOW_GRAPH_TRACE | ||||
/* override */ void set_name( const char *name ) { | ||||
tbb::internal::fgt_node_desc( this, name ); | ||||
} | ||||
#endif | ||||
}; | ||||
#endif //variadic max 10 | ||||
#endif // TBB_PREVIEW_GRAPH_NODES | #endif // TBB_PREVIEW_GRAPH_NODES | |||
//! Makes an edge between a single predecessor and a single successor | //! Makes an edge between a single predecessor and a single successor | |||
template< typename T > | template< typename T > | |||
inline void make_edge( sender<T> &p, receiver<T> &s ) { | inline void make_edge( sender<T> &p, receiver<T> &s ) { | |||
p.register_successor( s ); | p.register_successor( s ); | |||
tbb::internal::fgt_make_edge( &p, &s ); | tbb::internal::fgt_make_edge( &p, &s ); | |||
} | } | |||
//! Makes an edge between a single predecessor and a single successor | //! Makes an edge between a single predecessor and a single successor | |||
skipping to change at line 2403 | skipping to change at line 2650 | |||
using interface7::sender; | using interface7::sender; | |||
using interface7::receiver; | using interface7::receiver; | |||
using interface7::continue_receiver; | using interface7::continue_receiver; | |||
using interface7::source_node; | using interface7::source_node; | |||
using interface7::function_node; | using interface7::function_node; | |||
using interface7::multifunction_node; | using interface7::multifunction_node; | |||
using interface7::split_node; | using interface7::split_node; | |||
using interface7::internal::output_port; | using interface7::internal::output_port; | |||
#if TBB_PREVIEW_GRAPH_NODES | #if TBB_PREVIEW_GRAPH_NODES | |||
using interface7::or_node; | using interface7::indexer_node; | |||
using interface7::internal::tagged_msg; | ||||
using interface7::internal::cast_to; | ||||
using interface7::internal::is_a; | ||||
#endif | #endif | |||
using interface7::continue_node; | using interface7::continue_node; | |||
using interface7::overwrite_node; | using interface7::overwrite_node; | |||
using interface7::write_once_node; | using interface7::write_once_node; | |||
using interface7::broadcast_node; | using interface7::broadcast_node; | |||
using interface7::buffer_node; | using interface7::buffer_node; | |||
using interface7::queue_node; | using interface7::queue_node; | |||
using interface7::sequencer_node; | using interface7::sequencer_node; | |||
using interface7::priority_queue_node; | using interface7::priority_queue_node; | |||
using interface7::limiter_node; | using interface7::limiter_node; | |||
End of changes. 9 change blocks. | ||||
15 lines changed or deleted | 335 lines changed or added | |||
gcc_ia32_common.h | gcc_ia32_common.h | |||
---|---|---|---|---|
skipping to change at line 66 | skipping to change at line 66 | |||
__asm__ __volatile__("pause;"); | __asm__ __volatile__("pause;"); | |||
} | } | |||
return; | return; | |||
} | } | |||
#define __TBB_Pause(V) __TBB_machine_pause(V) | #define __TBB_Pause(V) __TBB_machine_pause(V) | |||
#endif /* !__TBB_Pause */ | #endif /* !__TBB_Pause */ | |||
// API to retrieve/update FPU control setting | // API to retrieve/update FPU control setting | |||
#ifndef __TBB_CPU_CTL_ENV_PRESENT | #ifndef __TBB_CPU_CTL_ENV_PRESENT | |||
#define __TBB_CPU_CTL_ENV_PRESENT 1 | #define __TBB_CPU_CTL_ENV_PRESENT 1 | |||
namespace tbb { | ||||
struct __TBB_cpu_ctl_env_t { | namespace internal { | |||
class cpu_ctl_env { | ||||
private: | ||||
int mxcsr; | int mxcsr; | |||
short x87cw; | short x87cw; | |||
static const int MXCSR_CONTROL_MASK = ~0x3f; /* all except last six sta | ||||
tus bits */ | ||||
public: | ||||
bool operator!=( const cpu_ctl_env& ctl ) const { return mxcsr != ctl.m | ||||
xcsr || x87cw != ctl.x87cw; } | ||||
void get_env() { | ||||
#if __TBB_ICC_12_0_INL_ASM_FSTCW_BROKEN | ||||
cpu_ctl_env loc_ctl; | ||||
__asm__ __volatile__ ( | ||||
"stmxcsr %0\n\t" | ||||
"fstcw %1" | ||||
: "=m"(loc_ctl.mxcsr), "=m"(loc_ctl.x87cw) | ||||
); | ||||
*this = loc_ctl; | ||||
#else | ||||
__asm__ __volatile__ ( | ||||
"stmxcsr %0\n\t" | ||||
"fstcw %1" | ||||
: "=m"(mxcsr), "=m"(x87cw) | ||||
); | ||||
#endif | ||||
mxcsr &= MXCSR_CONTROL_MASK; | ||||
} | ||||
void set_env() const { | ||||
__asm__ __volatile__ ( | ||||
"ldmxcsr %0\n\t" | ||||
"fldcw %1" | ||||
: : "m"(mxcsr), "m"(x87cw) | ||||
); | ||||
} | ||||
}; | }; | |||
inline void __TBB_get_cpu_ctl_env ( __TBB_cpu_ctl_env_t* ctl ) { | } // namespace internal | |||
#if __TBB_ICC_12_0_INL_ASM_FSTCW_BROKEN | } // namespace tbb | |||
__TBB_cpu_ctl_env_t loc_ctl; | ||||
__asm__ __volatile__ ( | ||||
"stmxcsr %0\n\t" | ||||
"fstcw %1" | ||||
: "=m"(loc_ctl.mxcsr), "=m"(loc_ctl.x87cw) | ||||
); | ||||
*ctl = loc_ctl; | ||||
#else | ||||
__asm__ __volatile__ ( | ||||
"stmxcsr %0\n\t" | ||||
"fstcw %1" | ||||
: "=m"(ctl->mxcsr), "=m"(ctl->x87cw) | ||||
); | ||||
#endif | ||||
} | ||||
inline void __TBB_set_cpu_ctl_env ( const __TBB_cpu_ctl_env_t* ctl ) { | ||||
__asm__ __volatile__ ( | ||||
"ldmxcsr %0\n\t" | ||||
"fldcw %1" | ||||
: : "m"(ctl->mxcsr), "m"(ctl->x87cw) | ||||
); | ||||
} | ||||
#endif /* !__TBB_CPU_CTL_ENV_PRESENT */ | #endif /* !__TBB_CPU_CTL_ENV_PRESENT */ | |||
#include "gcc_itsx.h" | #include "gcc_itsx.h" | |||
#endif /* __TBB_machine_gcc_ia32_common_H */ | #endif /* __TBB_machine_gcc_ia32_common_H */ | |||
End of changes. 3 change blocks. | ||||
26 lines changed or deleted | 36 lines changed or added | |||
memory_pool.h | memory_pool.h | |||
---|---|---|---|---|
skipping to change at line 38 | skipping to change at line 38 | |||
#ifndef __TBB_memory_pool_H | #ifndef __TBB_memory_pool_H | |||
#define __TBB_memory_pool_H | #define __TBB_memory_pool_H | |||
#if !TBB_PREVIEW_MEMORY_POOL | #if !TBB_PREVIEW_MEMORY_POOL | |||
#error Set TBB_PREVIEW_MEMORY_POOL to include memory_pool.h | #error Set TBB_PREVIEW_MEMORY_POOL to include memory_pool.h | |||
#endif | #endif | |||
/** @file */ | /** @file */ | |||
#include "scalable_allocator.h" | #include "scalable_allocator.h" | |||
#include "tbb_stddef.h" | ||||
#include "tbb_machine.h" // TODO: avoid linkage with libtbb on IA-64 archit | ||||
ecture | ||||
#include "atomic.h" // for as_atomic | ||||
#include <new> // std::bad_alloc | #include <new> // std::bad_alloc | |||
#if __TBB_CPP11_RVALUE_REF_PRESENT && !__TBB_CPP11_STD_FORWARD_BROKEN | #if __TBB_CPP11_RVALUE_REF_PRESENT && !__TBB_CPP11_STD_FORWARD_BROKEN | |||
#include <utility> // std::forward | #include <utility> // std::forward | |||
#endif | #endif | |||
#if __TBB_EXTRA_DEBUG | #if __TBB_EXTRA_DEBUG | |||
#define __TBBMALLOC_ASSERT ASSERT | #define __TBBMALLOC_ASSERT ASSERT | |||
#else | #else | |||
#define __TBBMALLOC_ASSERT(a,b) ((void)0) | #define __TBBMALLOC_ASSERT(a,b) ((void)0) | |||
#endif | #endif | |||
skipping to change at line 260 | skipping to change at line 257 | |||
memory_pool<Alloc> &self = *reinterpret_cast<memory_pool<Alloc>*>(pool_ id); | memory_pool<Alloc> &self = *reinterpret_cast<memory_pool<Alloc>*>(pool_ id); | |||
const size_t unit_size = sizeof(typename Alloc::value_type); | const size_t unit_size = sizeof(typename Alloc::value_type); | |||
__TBBMALLOC_ASSERT( 0 == raw_bytes%unit_size, NULL); | __TBBMALLOC_ASSERT( 0 == raw_bytes%unit_size, NULL); | |||
self.my_alloc.deallocate( static_cast<typename Alloc::value_type*>(raw_ ptr), raw_bytes/unit_size ); | self.my_alloc.deallocate( static_cast<typename Alloc::value_type*>(raw_ ptr), raw_bytes/unit_size ); | |||
return 0; | return 0; | |||
} | } | |||
#if __TBB_MSVC_UNREACHABLE_CODE_IGNORED | #if __TBB_MSVC_UNREACHABLE_CODE_IGNORED | |||
#pragma warning (pop) | #pragma warning (pop) | |||
#endif | #endif | |||
inline fixed_pool::fixed_pool(void *buf, size_t size) : my_buffer(buf), my_ size(size) { | inline fixed_pool::fixed_pool(void *buf, size_t size) : my_buffer(buf), my_ size(size) { | |||
if( !buf || !size ) __TBB_THROW(std::bad_alloc()); | ||||
rml::MemPoolPolicy args(allocate_request, 0, size, /*fixedPool=*/true); | rml::MemPoolPolicy args(allocate_request, 0, size, /*fixedPool=*/true); | |||
rml::MemPoolError res = rml::pool_create_v1(intptr_t(this), &args, &my_ pool); | rml::MemPoolError res = rml::pool_create_v1(intptr_t(this), &args, &my_ pool); | |||
if( res!=rml::POOL_OK ) __TBB_THROW(std::bad_alloc()); | if( res!=rml::POOL_OK ) __TBB_THROW(std::bad_alloc()); | |||
} | } | |||
inline void *fixed_pool::allocate_request(intptr_t pool_id, size_t & bytes) { | inline void *fixed_pool::allocate_request(intptr_t pool_id, size_t & bytes) { | |||
fixed_pool &self = *reinterpret_cast<fixed_pool*>(pool_id); | fixed_pool &self = *reinterpret_cast<fixed_pool*>(pool_id); | |||
// TODO: we can implement "buffer for fixed pools used only once" polic | __TBBMALLOC_ASSERT(0 != self.my_size, "The buffer must not be used twic | |||
y | e."); | |||
// on low-level side, thus eliminate atomics here | bytes = self.my_size; | |||
if( !tbb::internal::as_atomic(self.my_size).compare_and_swap(0, (bytes= | self.my_size = 0; // remember that buffer has been used | |||
self.my_size)) ) | ||||
return 0; // all the memory was given already | ||||
return self.my_buffer; | return self.my_buffer; | |||
} | } | |||
} //namespace interface6 | } //namespace interface6 | |||
using interface6::memory_pool_allocator; | using interface6::memory_pool_allocator; | |||
using interface6::memory_pool; | using interface6::memory_pool; | |||
using interface6::fixed_pool; | using interface6::fixed_pool; | |||
} //namespace tbb | } //namespace tbb | |||
#undef __TBBMALLOC_ASSERT | #undef __TBBMALLOC_ASSERT | |||
End of changes. 3 change blocks. | ||||
10 lines changed or deleted | 5 lines changed or added | |||
mic_common.h | mic_common.h | |||
---|---|---|---|---|
skipping to change at line 56 | skipping to change at line 56 | |||
#define __TBB_cl_evict(p) _mm_clevict(p, _MM_HINT_T1) | #define __TBB_cl_evict(p) _mm_clevict(p, _MM_HINT_T1) | |||
#endif | #endif | |||
/** Intel(R) Many Integrated Core Architecture does not support mfence and pause instructions **/ | /** Intel(R) Many Integrated Core Architecture does not support mfence and pause instructions **/ | |||
#define __TBB_full_memory_fence() __asm__ __volatile__("lock; addl $0,(%%rs p)":::"memory") | #define __TBB_full_memory_fence() __asm__ __volatile__("lock; addl $0,(%%rs p)":::"memory") | |||
#define __TBB_Pause(x) _mm_delay_32(16*(x)) | #define __TBB_Pause(x) _mm_delay_32(16*(x)) | |||
#define __TBB_STEALING_PAUSE 1500/16 | #define __TBB_STEALING_PAUSE 1500/16 | |||
#include <sched.h> | #include <sched.h> | |||
#define __TBB_Yield() sched_yield() | #define __TBB_Yield() sched_yield() | |||
/** FPU control setting **/ | // low-level timing intrinsic and its type | |||
#define __TBB_CPU_CTL_ENV_PRESENT 0 | #define __TBB_machine_time_stamp() _rdtsc() | |||
typedef uint64_t machine_tsc_t; | ||||
/** Specifics **/ | /** Specifics **/ | |||
#define __TBB_STEALING_ABORT_ON_CONTENTION 1 | #define __TBB_STEALING_ABORT_ON_CONTENTION 1 | |||
#define __TBB_YIELD2P 1 | #define __TBB_YIELD2P 1 | |||
#define __TBB_HOARD_NONLOCAL_TASKS 1 | #define __TBB_HOARD_NONLOCAL_TASKS 1 | |||
#if ! ( __FreeBSD__ || __linux__ ) | #if ! ( __FreeBSD__ || __linux__ ) | |||
#error Intel(R) Many Integrated Core Compiler does not define __FreeBSD __ or __linux__ anymore. Check for the __TBB_XXX_BROKEN defined under __Fre eBSD__ or __linux__. | #error Intel(R) Many Integrated Core Compiler does not define __FreeBSD __ or __linux__ anymore. Check for the __TBB_XXX_BROKEN defined under __Fre eBSD__ or __linux__. | |||
#endif /* ! ( __FreeBSD__ || __linux__ ) */ | #endif /* ! ( __FreeBSD__ || __linux__ ) */ | |||
End of changes. 1 change blocks. | ||||
2 lines changed or deleted | 3 lines changed or added | |||
msvc_armv7.h | msvc_armv7.h | |||
---|---|---|---|---|
skipping to change at line 104 | skipping to change at line 104 | |||
inline void __TBB_machine_pause (int32_t delay ) | inline void __TBB_machine_pause (int32_t delay ) | |||
{ | { | |||
while(delay>0) | while(delay>0) | |||
{ | { | |||
__TBB_compiler_fence(); | __TBB_compiler_fence(); | |||
delay--; | delay--; | |||
} | } | |||
} | } | |||
// API to retrieve/update FPU control setting | ||||
#define __TBB_CPU_CTL_ENV_PRESENT 1 | ||||
namespace tbb { | namespace tbb { | |||
namespace internal { | namespace internal { | |||
template <typename T, size_t S> | ||||
struct machine_load_store_relaxed { | template <typename T, size_t S> | |||
static inline T load ( const volatile T& location ) { | struct machine_load_store_relaxed { | |||
const T value = location; | static inline T load ( const volatile T& location ) { | |||
const T value = location; | ||||
/* | ||||
* An extra memory barrier is required for errata #761319 | /* | |||
* Please see http://infocenter.arm.com/help/topic/com.arm.d | * An extra memory barrier is required for errata #761319 | |||
oc.uan0004a | * Please see http://infocenter.arm.com/help/topic/com.arm.doc.uan00 | |||
*/ | 04a | |||
__TBB_acquire_consistency_helper(); | */ | |||
return value; | __TBB_acquire_consistency_helper(); | |||
} | return value; | |||
} | ||||
static inline void store ( volatile T& location, T value ) { | ||||
location = value; | static inline void store ( volatile T& location, T value ) { | |||
} | location = value; | |||
}; | } | |||
}} // namespaces internal, tbb | }; | |||
class cpu_ctl_env { | ||||
private: | ||||
unsigned int my_ctl; | ||||
public: | ||||
bool operator!=( const cpu_ctl_env& ctl ) const { return my_ctl != ctl. | ||||
my_ctl; } | ||||
void get_env() { my_ctl = _control87(0, 0); } | ||||
void set_env() const { _control87( my_ctl, ~0U ); } | ||||
}; | ||||
} // namespace internal | ||||
} // namespaces tbb | ||||
// Machine specific atomic operations | // Machine specific atomic operations | |||
#define __TBB_CompareAndSwap4(P,V,C) __TBB_machine_cmpswp4(P,V,C) | #define __TBB_CompareAndSwap4(P,V,C) __TBB_machine_cmpswp4(P,V,C) | |||
#define __TBB_CompareAndSwap8(P,V,C) __TBB_machine_cmpswp8(P,V,C) | #define __TBB_CompareAndSwap8(P,V,C) __TBB_machine_cmpswp8(P,V,C) | |||
#define __TBB_Pause(V) __TBB_machine_pause(V) | #define __TBB_Pause(V) __TBB_machine_pause(V) | |||
// Use generics for some things | // Use generics for some things | |||
#define __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE 1 | #define __TBB_USE_FETCHSTORE_AS_FULL_FENCED_STORE 1 | |||
#define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE 1 | #define __TBB_USE_GENERIC_HALF_FENCED_LOAD_STORE 1 | |||
#define __TBB_USE_GENERIC_PART_WORD_FETCH_ADD 1 | #define __TBB_USE_GENERIC_PART_WORD_FETCH_ADD 1 | |||
skipping to change at line 151 | skipping to change at line 166 | |||
extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void ); | extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void ); | |||
#define __TBB_Yield() SwitchToThread() | #define __TBB_Yield() SwitchToThread() | |||
#else | #else | |||
#include<thread> | #include<thread> | |||
#define __TBB_Yield() std::this_thread::yield() | #define __TBB_Yield() std::this_thread::yield() | |||
#endif | #endif | |||
#else | #else | |||
#define __TBB_Yield() __yield() | #define __TBB_Yield() __yield() | |||
#endif | #endif | |||
// API to retrieve/update FPU control setting | ||||
#define __TBB_CPU_CTL_ENV_PRESENT 1 | ||||
typedef unsigned int __TBB_cpu_ctl_env_t; | ||||
inline void __TBB_get_cpu_ctl_env ( __TBB_cpu_ctl_env_t* ctl ) { | ||||
*ctl = _control87(0, 0); | ||||
} | ||||
inline void __TBB_set_cpu_ctl_env ( const __TBB_cpu_ctl_env_t* ctl ) { | ||||
_control87( *ctl, ~0U ); | ||||
} | ||||
// Machine specific atomic operations | // Machine specific atomic operations | |||
#define __TBB_AtomicOR(P,V) __TBB_machine_OR(P,V) | #define __TBB_AtomicOR(P,V) __TBB_machine_OR(P,V) | |||
#define __TBB_AtomicAND(P,V) __TBB_machine_AND(P,V) | #define __TBB_AtomicAND(P,V) __TBB_machine_AND(P,V) | |||
template <typename T1,typename T2> | template <typename T1,typename T2> | |||
inline void __TBB_machine_OR( T1 *operand, T2 addend ) { | inline void __TBB_machine_OR( T1 *operand, T2 addend ) { | |||
_InterlockedOr((long volatile *)operand, (long)addend); | _InterlockedOr((long volatile *)operand, (long)addend); | |||
} | } | |||
template <typename T1,typename T2> | template <typename T1,typename T2> | |||
End of changes. 3 change blocks. | ||||
32 lines changed or deleted | 36 lines changed or added | |||
msvc_ia32_common.h | msvc_ia32_common.h | |||
---|---|---|---|---|
skipping to change at line 143 | skipping to change at line 143 | |||
static inline intptr_t __TBB_machine_lg( uintptr_t i ) { | static inline intptr_t __TBB_machine_lg( uintptr_t i ) { | |||
#if __TBB_LOG2_USE_BSR_INTRINSIC | #if __TBB_LOG2_USE_BSR_INTRINSIC | |||
return tbb::internal::intrinsics::msvc::__TBB_machine_lg(i); | return tbb::internal::intrinsics::msvc::__TBB_machine_lg(i); | |||
#else | #else | |||
return tbb::internal::inline_asm::msvc::__TBB_machine_lg(i); | return tbb::internal::inline_asm::msvc::__TBB_machine_lg(i); | |||
#endif | #endif | |||
} | } | |||
// API to retrieve/update FPU control setting | // API to retrieve/update FPU control setting | |||
#define __TBB_CPU_CTL_ENV_PRESENT 1 | #define __TBB_CPU_CTL_ENV_PRESENT 1 | |||
struct __TBB_cpu_ctl_env_t { | ||||
int mxcsr; | namespace tbb { namespace internal { class cpu_ctl_env; } } | |||
short x87cw; | ||||
}; | ||||
#if __TBB_X86_MSVC_INLINE_ASM_AVAILABLE | #if __TBB_X86_MSVC_INLINE_ASM_AVAILABLE | |||
inline void __TBB_get_cpu_ctl_env ( __TBB_cpu_ctl_env_t* ctl ) { | inline void __TBB_get_cpu_ctl_env ( tbb::internal::cpu_ctl_env* ctl ) { | |||
__asm { | __asm { | |||
__asm mov __TBB_r(ax), ctl | __asm mov __TBB_r(ax), ctl | |||
__asm stmxcsr [__TBB_r(ax)] | __asm stmxcsr [__TBB_r(ax)] | |||
__asm fstcw [__TBB_r(ax)+4] | __asm fstcw [__TBB_r(ax)+4] | |||
} | } | |||
} | } | |||
inline void __TBB_set_cpu_ctl_env ( const __TBB_cpu_ctl_env_t* ctl ) { | inline void __TBB_set_cpu_ctl_env ( const tbb::internal::cpu_ctl_env* c tl ) { | |||
__asm { | __asm { | |||
__asm mov __TBB_r(ax), ctl | __asm mov __TBB_r(ax), ctl | |||
__asm ldmxcsr [__TBB_r(ax)] | __asm ldmxcsr [__TBB_r(ax)] | |||
__asm fldcw [__TBB_r(ax)+4] | __asm fldcw [__TBB_r(ax)+4] | |||
} | } | |||
} | } | |||
#else | #else | |||
extern "C" { | extern "C" { | |||
void __TBB_EXPORTED_FUNC __TBB_get_cpu_ctl_env ( __TBB_cpu_ctl_env_ | void __TBB_EXPORTED_FUNC __TBB_get_cpu_ctl_env ( tbb::internal::cpu | |||
t* ); | _ctl_env* ); | |||
void __TBB_EXPORTED_FUNC __TBB_set_cpu_ctl_env ( const __TBB_cpu_ct | void __TBB_EXPORTED_FUNC __TBB_set_cpu_ctl_env ( const tbb::interna | |||
l_env_t* ); | l::cpu_ctl_env* ); | |||
} | } | |||
#endif | #endif | |||
namespace tbb { | ||||
namespace internal { | ||||
class cpu_ctl_env { | ||||
private: | ||||
int mxcsr; | ||||
short x87cw; | ||||
static const int MXCSR_CONTROL_MASK = ~0x3f; /* all except last six sta | ||||
tus bits */ | ||||
public: | ||||
bool operator!=( const cpu_ctl_env& ctl ) const { return mxcsr != ctl.m | ||||
xcsr || x87cw != ctl.x87cw; } | ||||
void get_env() { | ||||
__TBB_get_cpu_ctl_env( this ); | ||||
mxcsr &= MXCSR_CONTROL_MASK; | ||||
} | ||||
void set_env() const { __TBB_set_cpu_ctl_env( this ); } | ||||
}; | ||||
} // namespace internal | ||||
} // namespace tbb | ||||
#if !__TBB_WIN8UI_SUPPORT | #if !__TBB_WIN8UI_SUPPORT | |||
extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void ); | extern "C" __declspec(dllimport) int __stdcall SwitchToThread( void ); | |||
#define __TBB_Yield() SwitchToThread() | #define __TBB_Yield() SwitchToThread() | |||
#else | #else | |||
#include<thread> | #include<thread> | |||
#define __TBB_Yield() std::this_thread::yield() | #define __TBB_Yield() std::this_thread::yield() | |||
#endif | #endif | |||
#define __TBB_Pause(V) __TBB_machine_pause(V) | #define __TBB_Pause(V) __TBB_machine_pause(V) | |||
#define __TBB_Log2(V) __TBB_machine_lg(V) | #define __TBB_Log2(V) __TBB_machine_lg(V) | |||
End of changes. 5 change blocks. | ||||
10 lines changed or deleted | 28 lines changed or added | |||
parallel_for.h | parallel_for.h | |||
---|---|---|---|---|
skipping to change at line 40 | skipping to change at line 40 | |||
#define __TBB_parallel_for_H | #define __TBB_parallel_for_H | |||
#include <new> | #include <new> | |||
#include "task.h" | #include "task.h" | |||
#include "partitioner.h" | #include "partitioner.h" | |||
#include "blocked_range.h" | #include "blocked_range.h" | |||
#include "tbb_exception.h" | #include "tbb_exception.h" | |||
namespace tbb { | namespace tbb { | |||
namespace interface6 { | namespace interface7 { | |||
//! @cond INTERNAL | //! @cond INTERNAL | |||
namespace internal { | namespace internal { | |||
//! allocate right task with new parent | //! allocate right task with new parent | |||
void* allocate_sibling(task* start_for_task, size_t bytes); | void* allocate_sibling(task* start_for_task, size_t bytes); | |||
//! Task type used in parallel_for | //! Task type used in parallel_for | |||
/** @ingroup algorithms */ | /** @ingroup algorithms */ | |||
template<typename Range, typename Body, typename Partitioner> | template<typename Range, typename Body, typename Partitioner> | |||
class start_for: public task { | class start_for: public task { | |||
skipping to change at line 71 | skipping to change at line 71 | |||
public: | public: | |||
//! Constructor for root task. | //! Constructor for root task. | |||
start_for( const Range& range, const Body& body, Partitioner& parti tioner ) : | start_for( const Range& range, const Body& body, Partitioner& parti tioner ) : | |||
my_range(range), | my_range(range), | |||
my_body(body), | my_body(body), | |||
my_partition(partitioner) | my_partition(partitioner) | |||
{ | { | |||
} | } | |||
//! Splitting constructor used to generate children. | //! Splitting constructor used to generate children. | |||
/** parent_ becomes left child. Newly constructed object is right child. */ | /** parent_ becomes left child. Newly constructed object is right child. */ | |||
start_for( start_for& parent_, split ) : | start_for( start_for& parent_, typename Partitioner::split_type& sp | |||
my_range(parent_.my_range, split()), | lit_obj) : | |||
my_range(parent_.my_range, split_obj), | ||||
my_body(parent_.my_body), | my_body(parent_.my_body), | |||
my_partition(parent_.my_partition, split()) | my_partition(parent_.my_partition, split_obj) | |||
{ | { | |||
my_partition.set_affinity(*this); | my_partition.set_affinity(*this); | |||
} | } | |||
//! Construct right child from the given range as response to the d emand. | //! Construct right child from the given range as response to the d emand. | |||
/** parent_ remains left child. Newly constructed object is right child. */ | /** parent_ remains left child. Newly constructed object is right child. */ | |||
start_for( start_for& parent_, const Range& r, depth_t d ) : | start_for( start_for& parent_, const Range& r, depth_t d ) : | |||
my_range(r), | my_range(r), | |||
my_body(parent_.my_body), | my_body(parent_.my_body), | |||
my_partition(parent_.my_partition,split()) | my_partition(parent_.my_partition, split()) | |||
{ | { | |||
my_partition.set_affinity(*this); | my_partition.set_affinity(*this); | |||
my_partition.align_depth( d ); | my_partition.align_depth( d ); | |||
} | } | |||
static void run( const Range& range, const Body& body, Partitioner & partitioner ) { | static void run( const Range& range, const Body& body, Partitioner & partitioner ) { | |||
if( !range.empty() ) { | if( !range.empty() ) { | |||
#if !__TBB_TASK_GROUP_CONTEXT || TBB_JOIN_OUTER_TASK_GROUP | #if !__TBB_TASK_GROUP_CONTEXT || TBB_JOIN_OUTER_TASK_GROUP | |||
start_for& a = *new(task::allocate_root()) start_for(range, body,partitioner); | start_for& a = *new(task::allocate_root()) start_for(range, body,partitioner); | |||
#else | #else | |||
// Bound context prevents exceptions from body to affect ne sting or sibling algorithms, | // Bound context prevents exceptions from body to affect ne sting or sibling algorithms, | |||
skipping to change at line 113 | skipping to change at line 113 | |||
if( !range.empty() ) { | if( !range.empty() ) { | |||
start_for& a = *new(task::allocate_root(context)) start_for (range,body,partitioner); | start_for& a = *new(task::allocate_root(context)) start_for (range,body,partitioner); | |||
task::spawn_root_and_wait(a); | task::spawn_root_and_wait(a); | |||
} | } | |||
} | } | |||
#endif /* __TBB_TASK_GROUP_CONTEXT */ | #endif /* __TBB_TASK_GROUP_CONTEXT */ | |||
//! Run body for range, serves as callback for partitioner | //! Run body for range, serves as callback for partitioner | |||
void run_body( Range &r ) { my_body( r ); } | void run_body( Range &r ) { my_body( r ); } | |||
//! spawn right task, serves as callback for partitioner | //! spawn right task, serves as callback for partitioner | |||
void offer_work(split) { | void offer_work(typename Partitioner::split_type& split_obj) { | |||
spawn( *new( allocate_sibling(static_cast<task*>(this), sizeof( | spawn( *new( allocate_sibling(static_cast<task*>(this), sizeof( | |||
start_for)) ) start_for(*this, split()) ); | start_for)) ) start_for(*this, split_obj) ); | |||
} | } | |||
//! spawn right task, serves as callback for partitioner | //! spawn right task, serves as callback for partitioner | |||
void offer_work(const Range& r, depth_t d = 0) { | void offer_work(const Range& r, depth_t d = 0) { | |||
spawn( *new( allocate_sibling(static_cast<task*>(this), sizeof( start_for)) ) start_for(*this, r, d) ); | spawn( *new( allocate_sibling(static_cast<task*>(this), sizeof( start_for)) ) start_for(*this, r, d) ); | |||
} | } | |||
}; | }; | |||
//! allocate right task with new parent | //! allocate right task with new parent | |||
// TODO: 'inline' here is to avoid multiple definition error but for sa ke of code size this should not be inlined | // TODO: 'inline' here is to avoid multiple definition error but for sa ke of code size this should not be inlined | |||
inline void* allocate_sibling(task* start_for_task, size_t bytes) { | inline void* allocate_sibling(task* start_for_task, size_t bytes) { | |||
skipping to change at line 144 | skipping to change at line 144 | |||
my_partition.check_being_stolen( *this ); | my_partition.check_being_stolen( *this ); | |||
my_partition.execute(*this, my_range); | my_partition.execute(*this, my_range); | |||
return NULL; | return NULL; | |||
} | } | |||
} // namespace internal | } // namespace internal | |||
//! @endcond | //! @endcond | |||
} // namespace interfaceX | } // namespace interfaceX | |||
//! @cond INTERNAL | //! @cond INTERNAL | |||
namespace internal { | namespace internal { | |||
using interface6::internal::start_for; | using interface7::internal::start_for; | |||
//! Calls the function with values from range [begin, end) with a step provided | //! Calls the function with values from range [begin, end) with a step provided | |||
template<typename Function, typename Index> | template<typename Function, typename Index> | |||
class parallel_for_body : internal::no_assign { | class parallel_for_body : internal::no_assign { | |||
const Function &my_func; | const Function &my_func; | |||
const Index my_begin; | const Index my_begin; | |||
const Index my_step; | const Index my_step; | |||
public: | public: | |||
parallel_for_body( const Function& _func, Index& _begin, Index& _st ep ) | parallel_for_body( const Function& _func, Index& _begin, Index& _st ep ) | |||
: my_func(_func), my_begin(_begin), my_step(_step) {} | : my_func(_func), my_begin(_begin), my_step(_step) {} | |||
End of changes. 6 change blocks. | ||||
9 lines changed or deleted | 10 lines changed or added | |||
parallel_reduce.h | parallel_reduce.h | |||
---|---|---|---|---|
skipping to change at line 40 | skipping to change at line 40 | |||
#define __TBB_parallel_reduce_H | #define __TBB_parallel_reduce_H | |||
#include <new> | #include <new> | |||
#include "task.h" | #include "task.h" | |||
#include "aligned_space.h" | #include "aligned_space.h" | |||
#include "partitioner.h" | #include "partitioner.h" | |||
#include "tbb_profiling.h" | #include "tbb_profiling.h" | |||
namespace tbb { | namespace tbb { | |||
namespace interface6 { | namespace interface7 { | |||
//! @cond INTERNAL | //! @cond INTERNAL | |||
namespace internal { | namespace internal { | |||
using namespace tbb::internal; | using namespace tbb::internal; | |||
/** Values for reduction_context. */ | /** Values for reduction_context. */ | |||
enum { | enum { | |||
root_task, left_child, right_child | root_task, left_child, right_child | |||
}; | }; | |||
skipping to change at line 119 | skipping to change at line 119 | |||
//! Constructor used for root task | //! Constructor used for root task | |||
start_reduce( const Range& range, Body* body, Partitioner& partitio ner ) : | start_reduce( const Range& range, Body* body, Partitioner& partitio ner ) : | |||
my_body(body), | my_body(body), | |||
my_range(range), | my_range(range), | |||
my_partition(partitioner), | my_partition(partitioner), | |||
my_context(root_task) | my_context(root_task) | |||
{ | { | |||
} | } | |||
//! Splitting constructor used to generate children. | //! Splitting constructor used to generate children. | |||
/** parent_ becomes left child. Newly constructed object is right child. */ | /** parent_ becomes left child. Newly constructed object is right child. */ | |||
start_reduce( start_reduce& parent_, split ) : | start_reduce( start_reduce& parent_, typename Partitioner::split_ty pe& split_obj ) : | |||
my_body(parent_.my_body), | my_body(parent_.my_body), | |||
my_range(parent_.my_range, split()), | my_range(parent_.my_range, split_obj), | |||
my_partition(parent_.my_partition, split()), | my_partition(parent_.my_partition, split_obj), | |||
my_context(right_child) | my_context(right_child) | |||
{ | { | |||
my_partition.set_affinity(*this); | my_partition.set_affinity(*this); | |||
parent_.my_context = left_child; | parent_.my_context = left_child; | |||
} | } | |||
//! Construct right child from the given range as response to the d emand. | //! Construct right child from the given range as response to the d emand. | |||
/** parent_ remains left child. Newly constructed object is right child. */ | /** parent_ remains left child. Newly constructed object is right child. */ | |||
start_reduce( start_reduce& parent_, const Range& r, depth_t d ) : | start_reduce( start_reduce& parent_, const Range& r, depth_t d ) : | |||
my_body(parent_.my_body), | my_body(parent_.my_body), | |||
my_range(r), | my_range(r), | |||
skipping to change at line 163 | skipping to change at line 163 | |||
static void run( const Range& range, Body& body, Partitioner& parti tioner, task_group_context& context ) { | static void run( const Range& range, Body& body, Partitioner& parti tioner, task_group_context& context ) { | |||
if( !range.empty() ) | if( !range.empty() ) | |||
task::spawn_root_and_wait( *new(task::allocate_root(context )) start_reduce(range,&body,partitioner) ); | task::spawn_root_and_wait( *new(task::allocate_root(context )) start_reduce(range,&body,partitioner) ); | |||
} | } | |||
#endif /* __TBB_TASK_GROUP_CONTEXT */ | #endif /* __TBB_TASK_GROUP_CONTEXT */ | |||
//! Run body for range | //! Run body for range | |||
void run_body( Range &r ) { (*my_body)( r ); } | void run_body( Range &r ) { (*my_body)( r ); } | |||
//! spawn right task, serves as callback for partitioner | //! spawn right task, serves as callback for partitioner | |||
// TODO: remove code duplication from 'offer_work' methods | // TODO: remove code duplication from 'offer_work' methods | |||
void offer_work(split) { | void offer_work(typename Partitioner::split_type& split_obj) { | |||
task *tasks[2]; | task *tasks[2]; | |||
allocate_sibling(static_cast<task*>(this), tasks, sizeof(start_ reduce), sizeof(finish_type)); | allocate_sibling(static_cast<task*>(this), tasks, sizeof(start_ reduce), sizeof(finish_type)); | |||
new((void*)tasks[0]) finish_type(my_context); | new((void*)tasks[0]) finish_type(my_context); | |||
new((void*)tasks[1]) start_reduce(*this, split()); | new((void*)tasks[1]) start_reduce(*this, split_obj); | |||
spawn(*tasks[1]); | spawn(*tasks[1]); | |||
} | } | |||
//! spawn right task, serves as callback for partitioner | //! spawn right task, serves as callback for partitioner | |||
void offer_work(const Range& r, depth_t d = 0) { | void offer_work(const Range& r, depth_t d = 0) { | |||
task *tasks[2]; | task *tasks[2]; | |||
allocate_sibling(static_cast<task*>(this), tasks, sizeof(start_ reduce), sizeof(finish_type)); | allocate_sibling(static_cast<task*>(this), tasks, sizeof(start_ reduce), sizeof(finish_type)); | |||
new((void*)tasks[0]) finish_type(my_context); | new((void*)tasks[0]) finish_type(my_context); | |||
new((void*)tasks[1]) start_reduce(*this, r, d); | new((void*)tasks[1]) start_reduce(*this, r, d); | |||
spawn(*tasks[1]); | spawn(*tasks[1]); | |||
} | } | |||
skipping to change at line 292 | skipping to change at line 292 | |||
task::spawn(b); | task::spawn(b); | |||
return this; | return this; | |||
} | } | |||
} | } | |||
} // namespace internal | } // namespace internal | |||
//! @endcond | //! @endcond | |||
} //namespace interfaceX | } //namespace interfaceX | |||
//! @cond INTERNAL | //! @cond INTERNAL | |||
namespace internal { | namespace internal { | |||
using interface6::internal::start_reduce; | using interface7::internal::start_reduce; | |||
using interface6::internal::start_deterministic_reduce; | using interface7::internal::start_deterministic_reduce; | |||
//! Auxiliary class for parallel_reduce; for internal use only. | //! Auxiliary class for parallel_reduce; for internal use only. | |||
/** The adaptor class that implements \ref parallel_reduce_body_req "pa rallel_reduce Body" | /** The adaptor class that implements \ref parallel_reduce_body_req "pa rallel_reduce Body" | |||
using given \ref parallel_reduce_lambda_req "anonymous function obj ects". | using given \ref parallel_reduce_lambda_req "anonymous function obj ects". | |||
**/ | **/ | |||
/** @ingroup algorithms */ | /** @ingroup algorithms */ | |||
template<typename Range, typename Value, typename RealBody, typename Re duction> | template<typename Range, typename Value, typename RealBody, typename Re duction> | |||
class lambda_reduce_body { | class lambda_reduce_body { | |||
//FIXME: decide if my_real_body, my_reduction, and identity_element should be copied or referenced | //FIXME: decide if my_real_body, my_reduction, and identity_element should be copied or referenced | |||
// (might require some performance measurements) | // (might require some performance measurements) | |||
End of changes. 6 change blocks. | ||||
8 lines changed or deleted | 8 lines changed or added | |||
partitioner.h | partitioner.h | |||
---|---|---|---|---|
skipping to change at line 33 | skipping to change at line 33 | |||
file does not by itself cause the resulting executable to be covered by | file does not by itself cause the resulting executable to be covered by | |||
the GNU General Public License. This exception does not however | the GNU General Public License. This exception does not however | |||
invalidate any other reasons why the executable file might be covered b y | invalidate any other reasons why the executable file might be covered b y | |||
the GNU General Public License. | the GNU General Public License. | |||
*/ | */ | |||
#ifndef __TBB_partitioner_H | #ifndef __TBB_partitioner_H | |||
#define __TBB_partitioner_H | #define __TBB_partitioner_H | |||
#ifndef __TBB_INITIAL_CHUNKS | #ifndef __TBB_INITIAL_CHUNKS | |||
// initial task divisions per thread | ||||
#define __TBB_INITIAL_CHUNKS 2 | #define __TBB_INITIAL_CHUNKS 2 | |||
#endif | #endif | |||
#ifndef __TBB_RANGE_POOL_CAPACITY | #ifndef __TBB_RANGE_POOL_CAPACITY | |||
// maximum number of elements in range pool | ||||
#define __TBB_RANGE_POOL_CAPACITY 8 | #define __TBB_RANGE_POOL_CAPACITY 8 | |||
#endif | #endif | |||
#ifndef __TBB_INIT_DEPTH | #ifndef __TBB_INIT_DEPTH | |||
// initial value for depth of range pool | ||||
#define __TBB_INIT_DEPTH 5 | #define __TBB_INIT_DEPTH 5 | |||
#endif | #endif | |||
#ifndef __TBB_DEMAND_DEPTH_ADD | ||||
// when imbalance is found range splits this value times more | ||||
#define __TBB_DEMAND_DEPTH_ADD 2 | ||||
#endif | ||||
#ifndef __TBB_STATIC_THRESHOLD | ||||
// necessary number of clocks for the work to be distributed among all task | ||||
s | ||||
#define __TBB_STATIC_THRESHOLD 40000 | ||||
#endif | ||||
#if __TBB_DEFINE_MIC | ||||
#define __TBB_NONUNIFORM_TASK_CREATION 1 | ||||
#ifdef __TBB_machine_time_stamp | ||||
#define __TBB_USE_MACHINE_TIME_STAMPS 1 | ||||
#define __TBB_task_duration() __TBB_STATIC_THRESHOLD | ||||
#endif // __TBB_machine_time_stamp | ||||
#endif // __TBB_DEFINE_MIC | ||||
#include "task.h" | #include "task.h" | |||
#include "aligned_space.h" | #include "aligned_space.h" | |||
#include "atomic.h" | #include "atomic.h" | |||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | |||
// Workaround for overzealous compiler warnings | // Workaround for overzealous compiler warnings | |||
#pragma warning (push) | #pragma warning (push) | |||
#pragma warning (disable: 4244) | #pragma warning (disable: 4244) | |||
#endif | #endif | |||
namespace tbb { | namespace tbb { | |||
class auto_partitioner; | class auto_partitioner; | |||
class simple_partitioner; | class simple_partitioner; | |||
class affinity_partitioner; | class affinity_partitioner; | |||
namespace interface6 { | namespace interface7 { | |||
namespace internal { | namespace internal { | |||
class affinity_partition_type; | class affinity_partition_type; | |||
} | } | |||
} | } | |||
namespace internal { //< @cond INTERNAL | namespace internal { //< @cond INTERNAL | |||
size_t __TBB_EXPORTED_FUNC get_initial_auto_partitioner_divisor(); | size_t __TBB_EXPORTED_FUNC get_initial_auto_partitioner_divisor(); | |||
//! Defines entry point for affinity partitioner into tbb run-time library. | //! Defines entry point for affinity partitioner into tbb run-time library. | |||
class affinity_partitioner_base_v3: no_copy { | class affinity_partitioner_base_v3: no_copy { | |||
friend class tbb::affinity_partitioner; | friend class tbb::affinity_partitioner; | |||
friend class tbb::interface6::internal::affinity_partition_type; | friend class tbb::interface7::internal::affinity_partition_type; | |||
//! Array that remembers affinities of tree positions to affinity_id. | //! Array that remembers affinities of tree positions to affinity_id. | |||
/** NULL if my_size==0. */ | /** NULL if my_size==0. */ | |||
affinity_id* my_array; | affinity_id* my_array; | |||
//! Number of elements in my_array. | //! Number of elements in my_array. | |||
size_t my_size; | size_t my_size; | |||
//! Zeros the fields. | //! Zeros the fields. | |||
affinity_partitioner_base_v3() : my_array(NULL), my_size(0) {} | affinity_partitioner_base_v3() : my_array(NULL), my_size(0) {} | |||
//! Deallocates my_array. | //! Deallocates my_array. | |||
~affinity_partitioner_base_v3() {resize(0);} | ~affinity_partitioner_base_v3() {resize(0);} | |||
//! Resize my_array. | //! Resize my_array. | |||
skipping to change at line 101 | skipping to change at line 119 | |||
void spawn_or_delay( bool, task& b ) { | void spawn_or_delay( bool, task& b ) { | |||
task::spawn(b); | task::spawn(b); | |||
} | } | |||
}; | }; | |||
template<typename Range, typename Body, typename Partitioner> class start_s can; | template<typename Range, typename Body, typename Partitioner> class start_s can; | |||
} //< namespace internal @endcond | } //< namespace internal @endcond | |||
namespace serial { | namespace serial { | |||
namespace interface6 { | namespace interface7 { | |||
template<typename Range, typename Body, typename Partitioner> class start_f or; | template<typename Range, typename Body, typename Partitioner> class start_f or; | |||
} | } | |||
} | } | |||
namespace interface6 { | namespace interface7 { | |||
//! @cond INTERNAL | //! @cond INTERNAL | |||
namespace internal { | namespace internal { | |||
using namespace tbb::internal; | using namespace tbb::internal; | |||
template<typename Range, typename Body, typename Partitioner> class start_f or; | template<typename Range, typename Body, typename Partitioner> class start_f or; | |||
template<typename Range, typename Body, typename Partitioner> class start_r educe; | template<typename Range, typename Body, typename Partitioner> class start_r educe; | |||
//! Join task node that contains shared flag for stealing feedback | //! Join task node that contains shared flag for stealing feedback | |||
class flag_task: public task { | class flag_task: public task { | |||
public: | public: | |||
tbb::atomic<bool> my_child_stolen; | tbb::atomic<bool> my_child_stolen; | |||
skipping to change at line 151 | skipping to change at line 169 | |||
depth_t my_head; | depth_t my_head; | |||
depth_t my_tail; | depth_t my_tail; | |||
depth_t my_size; | depth_t my_size; | |||
depth_t my_depth[MaxCapacity]; // relative depths of stored ranges | depth_t my_depth[MaxCapacity]; // relative depths of stored ranges | |||
tbb::aligned_space<T, MaxCapacity> my_pool; | tbb::aligned_space<T, MaxCapacity> my_pool; | |||
public: | public: | |||
//! initialize via first range in pool | //! initialize via first range in pool | |||
range_vector(const T& elem) : my_head(0), my_tail(0), my_size(1) { | range_vector(const T& elem) : my_head(0), my_tail(0), my_size(1) { | |||
my_depth[0] = 0; | my_depth[0] = 0; | |||
new( my_pool.begin() ) T(elem);//TODO: std::move? | new( static_cast<void *>(my_pool.begin()) ) T(elem);//TODO: std::mo ve? | |||
} | } | |||
~range_vector() { | ~range_vector() { | |||
while( !empty() ) pop_back(); | while( !empty() ) pop_back(); | |||
} | } | |||
bool empty() const { return my_size == 0; } | bool empty() const { return my_size == 0; } | |||
depth_t size() const { return my_size; } | depth_t size() const { return my_size; } | |||
//! Populates range pool via ranges up to max depth or while divisible | //! Populates range pool via ranges up to max depth or while divisible | |||
//! max_depth starts from 0, e.g. value 2 makes 3 ranges in the pool up to two 1/4 pieces | //! max_depth starts from 0, e.g. value 2 makes 3 ranges in the pool up to two 1/4 pieces | |||
void split_to_fill(depth_t max_depth) { | void split_to_fill(depth_t max_depth) { | |||
while( my_size < MaxCapacity && my_depth[my_head] < max_depth | while( my_size < MaxCapacity && is_divisible(max_depth) ) { | |||
&& my_pool.begin()[my_head].is_divisible() ) { | ||||
depth_t prev = my_head; | depth_t prev = my_head; | |||
my_head = (my_head + 1) % MaxCapacity; | my_head = (my_head + 1) % MaxCapacity; | |||
new(my_pool.begin()+my_head) T(my_pool.begin()[prev]); // copy TODO: std::move? | new(my_pool.begin()+my_head) T(my_pool.begin()[prev]); // copy TODO: std::move? | |||
my_pool.begin()[prev].~T(); // instead of assignment | my_pool.begin()[prev].~T(); // instead of assignment | |||
new(my_pool.begin()+prev) T(my_pool.begin()[my_head], split()); // do 'inverse' split | new(my_pool.begin()+prev) T(my_pool.begin()[my_head], split()); // do 'inverse' split | |||
my_depth[my_head] = ++my_depth[prev]; | my_depth[my_head] = ++my_depth[prev]; | |||
my_size++; | my_size++; | |||
} | } | |||
} | } | |||
void pop_back() { | void pop_back() { | |||
skipping to change at line 197 | skipping to change at line 214 | |||
} | } | |||
T& front() { | T& front() { | |||
__TBB_ASSERT(my_size > 0, "range_vector::front() with empty size"); | __TBB_ASSERT(my_size > 0, "range_vector::front() with empty size"); | |||
return my_pool.begin()[my_tail]; | return my_pool.begin()[my_tail]; | |||
} | } | |||
//! similarly to front(), returns depth of the first range in the pool | //! similarly to front(), returns depth of the first range in the pool | |||
depth_t front_depth() { | depth_t front_depth() { | |||
__TBB_ASSERT(my_size > 0, "range_vector::front_depth() with empty s ize"); | __TBB_ASSERT(my_size > 0, "range_vector::front_depth() with empty s ize"); | |||
return my_depth[my_tail]; | return my_depth[my_tail]; | |||
} | } | |||
depth_t back_depth() { | ||||
__TBB_ASSERT(my_size > 0, "range_vector::back_depth() with empty si | ||||
ze"); | ||||
return my_depth[my_head]; | ||||
} | ||||
bool is_divisible(depth_t max_depth) { | ||||
return back_depth() < max_depth && back().is_divisible(); | ||||
} | ||||
}; | }; | |||
//! Provides default methods for partition objects and common algorithm blo cks. | //! Provides default methods for partition objects and common algorithm blo cks. | |||
template <typename Partition> | template <typename Partition> | |||
struct partition_type_base { | struct partition_type_base { | |||
typedef split split_type; | ||||
// decision makers | // decision makers | |||
void set_affinity( task & ) {} | void set_affinity( task & ) {} | |||
void note_affinity( task::affinity_id ) {} | void note_affinity( task::affinity_id ) {} | |||
bool check_being_stolen(task &) { return false; } // part of old should _execute_range() | bool check_being_stolen(task &) { return false; } // part of old should _execute_range() | |||
bool check_for_demand(task &) { return false; } | bool check_for_demand(task &) { return false; } | |||
bool is_divisible() { return true; } // part of old should_execute_rang e() | bool is_divisible() { return true; } // part of old should_execute_rang e() | |||
depth_t max_depth() { return 0; } | depth_t max_depth() { return 0; } | |||
void align_depth(depth_t) { } | void align_depth(depth_t) { } | |||
template <typename Range> split_type get_split() { return split(); } | ||||
// common function blocks | // common function blocks | |||
Partition& self() { return *static_cast<Partition*>(this); } // CRTP he lper | Partition& self() { return *static_cast<Partition*>(this); } // CRTP he lper | |||
template<typename StartType, typename Range> | template<typename StartType, typename Range> | |||
void execute(StartType &start, Range &range) { | void execute(StartType &start, Range &range) { | |||
// The algorithm in a few words ([]-denotes calls to decision metho ds of partitioner): | // The algorithm in a few words ([]-denotes calls to decision metho ds of partitioner): | |||
// [If this task is stolen, adjust depth and divisions if necessary , set flag]. | // [If this task is stolen, adjust depth and divisions if necessary , set flag]. | |||
// If range is divisible { | // If range is divisible { | |||
// Spread the work while [initial divisions left]; | // Spread the work while [initial divisions left]; | |||
// Create trap task [if necessary]; | // Create trap task [if necessary]; | |||
// } | // } | |||
// If not divisible or [max depth is reached], execute, else do the range pool part | // If not divisible or [max depth is reached], execute, else do the range pool part | |||
if ( range.is_divisible() ) { | if ( range.is_divisible() ) { | |||
if ( self().is_divisible() ) | if ( self().is_divisible() ) { | |||
do start.offer_work( split() ); // split until is divisible | do { // split until is divisible | |||
while ( range.is_divisible() && self().is_divisible() ); | typename Partition::split_type split_obj = self().templ | |||
ate get_split<Range>(); | ||||
start.offer_work( split_obj ); | ||||
} while ( range.is_divisible() && self().is_divisible() ); | ||||
} | ||||
} | } | |||
if( !range.is_divisible() || !self().max_depth() ) | if( !range.is_divisible() || !self().max_depth() ) | |||
start.run_body( range ); // simple partitioner goes always here | start.run_body( range ); // simple partitioner goes always here | |||
else { // do range pool | else { // do range pool | |||
internal::range_vector<Range, Partition::range_pool_size> range _pool(range); | internal::range_vector<Range, Partition::range_pool_size> range _pool(range); | |||
do { | do { | |||
range_pool.split_to_fill(self().max_depth()); // fill range pool | range_pool.split_to_fill(self().max_depth()); // fill range pool | |||
if( self().check_for_demand( start ) ) { | if( self().check_for_demand( start ) ) { | |||
if( range_pool.size() > 1 ) { | if( range_pool.size() > 1 ) { | |||
start.offer_work( range_pool.front(), range_pool.fr ont_depth() ); | start.offer_work( range_pool.front(), range_pool.fr ont_depth() ); | |||
range_pool.pop_front(); | range_pool.pop_front(); | |||
continue; | continue; | |||
} | } | |||
if( range_pool.back().is_divisible() ) // was not enoug | if( range_pool.is_divisible(self().max_depth()) ) // wa | |||
h depth to fork a task | s not enough depth to fork a task | |||
continue; // note: check_for_demand() should guaran | continue; // note: next split_to_fill() should spli | |||
tee increasing max_depth() next time | t range at least once | |||
} | } | |||
start.run_body( range_pool.back() ); | start.run_body( range_pool.back() ); | |||
range_pool.pop_back(); | range_pool.pop_back(); | |||
} while( !range_pool.empty() && !start.is_cancelled() ); | } while( !range_pool.empty() && !start.is_cancelled() ); | |||
} | } | |||
} | } | |||
}; | }; | |||
//! Provides default methods for auto (adaptive) partition objects. | //! Provides default methods for auto (adaptive) partition objects. | |||
template <typename Partition> | template <typename Partition> | |||
struct auto_partition_type_base : partition_type_base<Partition> { | struct adaptive_partition_type_base : partition_type_base<Partition> { | |||
size_t my_divisor; | size_t my_divisor; | |||
depth_t my_max_depth; | depth_t my_max_depth; | |||
auto_partition_type_base() : my_max_depth(__TBB_INIT_DEPTH) { | adaptive_partition_type_base() : my_max_depth(__TBB_INIT_DEPTH) { | |||
my_divisor = tbb::internal::get_initial_auto_partitioner_divisor()* | my_divisor = tbb::internal::get_initial_auto_partitioner_divisor() | |||
__TBB_INITIAL_CHUNKS/4; | / 4; | |||
__TBB_ASSERT(my_divisor, "initial value of get_initial_auto_partiti oner_divisor() is not valid"); | __TBB_ASSERT(my_divisor, "initial value of get_initial_auto_partiti oner_divisor() is not valid"); | |||
} | } | |||
auto_partition_type_base(auto_partition_type_base &src, split) { | adaptive_partition_type_base(adaptive_partition_type_base &src, split) { | |||
my_max_depth = src.my_max_depth; | my_max_depth = src.my_max_depth; | |||
#if TBB_USE_ASSERT | ||||
size_t old_divisor = src.my_divisor; | ||||
#endif | ||||
#if __TBB_INITIAL_TASK_IMBALANCE | #if __TBB_INITIAL_TASK_IMBALANCE | |||
if( src.my_divisor <= 1 ) my_divisor = 0; | if( src.my_divisor <= 1 ) my_divisor = 0; | |||
else my_divisor = src.my_divisor = (src.my_divisor+1u) / 2u; | else my_divisor = src.my_divisor = (src.my_divisor + 1u) / 2u; | |||
#else | #else | |||
my_divisor = src.my_divisor / 2u; | my_divisor = src.my_divisor / 2u; | |||
src.my_divisor = src.my_divisor - my_divisor; // TODO: check the ef fect separately | src.my_divisor = src.my_divisor - my_divisor; // TODO: check the ef fect separately | |||
if(my_divisor) src.my_max_depth += static_cast<depth_t>(__TBB_Log2( src.my_divisor/my_divisor)); | if (my_divisor) src.my_max_depth += static_cast<depth_t>(__TBB_Log2 (src.my_divisor / my_divisor)); | |||
#endif | #endif | |||
// For affinity_partitioner, my_divisor indicates the number of aff | ||||
inity array indices the task reserves. | ||||
// A task which has only one index must produce the right split wit | ||||
hout reserved index in order to avoid | ||||
// it to be overwritten in note_affinity() of the created (right) t | ||||
ask. | ||||
// I.e. a task created deeper than the affinity array can remember | ||||
must not save its affinity (LIFO order) | ||||
__TBB_ASSERT( (old_divisor <= 1 && my_divisor == 0) || | ||||
(old_divisor > 1 && my_divisor != 0), NULL); | ||||
} | ||||
adaptive_partition_type_base(adaptive_partition_type_base &src, const p | ||||
roportional_split& split_obj) { | ||||
my_max_depth = src.my_max_depth; | ||||
my_divisor = size_t(float(src.my_divisor) * float(split_obj.right() | ||||
) | ||||
/ float(split_obj.left() + split_obj.right())); | ||||
src.my_divisor -= my_divisor; | ||||
} | } | |||
bool check_being_stolen( task &t) { // part of old should_execute_range () | bool check_being_stolen( task &t) { // part of old should_execute_range () | |||
if( !my_divisor ) { // if not from the top P tasks of binary tree | if( !my_divisor ) { // if not from the top P tasks of binary tree | |||
my_divisor = 1; // TODO: replace by on-stack flag (partition_st ate's member)? | my_divisor = 1; // TODO: replace by on-stack flag (partition_st ate's member)? | |||
if( t.is_stolen_task() ) { | if( t.is_stolen_task() && t.parent()->ref_count() >= 2 ) { // r uns concurrently with the left task | |||
#if TBB_USE_EXCEPTIONS | #if TBB_USE_EXCEPTIONS | |||
// RTTI is available, check whether the cast is valid | // RTTI is available, check whether the cast is valid | |||
__TBB_ASSERT(dynamic_cast<flag_task*>(t.parent()), 0); | __TBB_ASSERT(dynamic_cast<flag_task*>(t.parent()), 0); | |||
// correctness of the cast relies on avoiding the root task for which: | // correctness of the cast relies on avoiding the root task for which: | |||
// - initial value of my_divisor != 0 (protected by separat e assertion) | // - initial value of my_divisor != 0 (protected by separat e assertion) | |||
// - is_stolen_task() always returns false for the root tas k. | // - is_stolen_task() always returns false for the root tas k. | |||
#endif | #endif | |||
flag_task::mark_task_stolen(t); | flag_task::mark_task_stolen(t); | |||
my_max_depth++; | if( !my_max_depth ) my_max_depth++; | |||
my_max_depth += __TBB_DEMAND_DEPTH_ADD; | ||||
return true; | return true; | |||
} | } | |||
} | } | |||
return false; | return false; | |||
} | } | |||
bool is_divisible() { // part of old should_execute_range() | ||||
if( my_divisor > 1 ) return true; | ||||
if( my_divisor && my_max_depth > 1 ) { // can split the task and on | ||||
ce more internally. TODO: on-stack flag instead | ||||
// keep same fragmentation while splitting for the local task p | ||||
ool | ||||
my_max_depth--; | ||||
my_divisor = 0; // decrease max_depth once per task | ||||
return true; | ||||
} else return false; | ||||
} | ||||
bool check_for_demand(task &t) { | ||||
if( flag_task::is_peer_stolen(t) ) { | ||||
my_max_depth++; | ||||
return true; | ||||
} else return false; | ||||
} | ||||
void align_depth(depth_t base) { | void align_depth(depth_t base) { | |||
__TBB_ASSERT(base <= my_max_depth, 0); | __TBB_ASSERT(base <= my_max_depth, 0); | |||
my_max_depth -= base; | my_max_depth -= base; | |||
} | } | |||
depth_t max_depth() { return my_max_depth; } | depth_t max_depth() { return my_max_depth; } | |||
}; | }; | |||
//! Helper that enables one or the other code branches (see example in is_r | ||||
ange_divisible_in_proportion) | ||||
template<bool C, typename T = void> struct enable_if { typedef T type; }; | ||||
template<typename T> struct enable_if<false, T> { }; | ||||
//! Class determines whether template parameter has static boolean | ||||
//! constant 'is_divisible_in_proportion' initialized with value of | ||||
//! 'true' or not. | ||||
/** If template parameter has such field that has been initialized | ||||
* with non-zero value then class field will be set to 'true', | ||||
* otherwise - 'false' | ||||
*/ | ||||
template <typename Range> | ||||
class is_range_divisible_in_proportion { | ||||
private: | ||||
typedef char yes[1]; | ||||
typedef char no [2]; | ||||
template <typename range_type> static yes& decide(typename enable_if<ra | ||||
nge_type::is_divisible_in_proportion>::type *); | ||||
template <typename range_type> static no& decide(...); | ||||
public: | ||||
// equals to 'true' if and only if static const variable 'is_divisible_ | ||||
in_proportion' of template parameter | ||||
// initialized with the value of 'true' | ||||
static const bool value = (sizeof(decide<Range>(0)) == sizeof(yes)); | ||||
}; | ||||
//! Provides default methods for affinity (adaptive) partition objects. | //! Provides default methods for affinity (adaptive) partition objects. | |||
class affinity_partition_type : public auto_partition_type_base<affinity_pa rtition_type> { | class affinity_partition_type : public adaptive_partition_type_base<affinit y_partition_type> { | |||
static const unsigned factor_power = 4; | static const unsigned factor_power = 4; | |||
static const unsigned factor = 1<<factor_power; | static const unsigned factor = 1<<factor_power; // number of slots in | |||
bool my_delay; | affinity array per task | |||
unsigned map_begin, map_end, map_mid; | enum { | |||
start = 0, | ||||
run, | ||||
pass | ||||
} my_delay; | ||||
#ifdef __TBB_USE_MACHINE_TIME_STAMPS | ||||
machine_tsc_t my_dst_tsc; | ||||
#endif | ||||
size_t my_begin; | ||||
tbb::internal::affinity_id* my_array; | tbb::internal::affinity_id* my_array; | |||
void set_mid() { | ||||
unsigned d = (map_end - map_begin)/2; // we could add 1 but it is r | ||||
ather for LIFO affinity | ||||
if( d > factor ) | ||||
d &= 0u-factor; | ||||
map_mid = map_end - d; | ||||
} | ||||
public: | public: | |||
affinity_partition_type( tbb::internal::affinity_partitioner_base_v3& a | typedef proportional_split split_type; | |||
p ) { | ||||
affinity_partition_type( tbb::internal::affinity_partitioner_base_v3& a | ||||
p ) | ||||
: adaptive_partition_type_base<affinity_partition_type>(), | ||||
my_delay(start) | ||||
#ifdef __TBB_USE_MACHINE_TIME_STAMPS | ||||
, my_dst_tsc(0) | ||||
#endif | ||||
{ | ||||
__TBB_ASSERT( (factor&(factor-1))==0, "factor must be power of two" ); | __TBB_ASSERT( (factor&(factor-1))==0, "factor must be power of two" ); | |||
my_divisor *= factor; | ||||
ap.resize(factor); | ap.resize(factor); | |||
my_array = ap.my_array; | my_array = ap.my_array; | |||
map_begin = 0; | my_begin = 0; | |||
map_end = unsigned(ap.my_size); | my_max_depth = factor_power + 1; // the first factor_power ranges w | |||
set_mid(); | ill be spawned, and >=1 ranges should be left | |||
my_delay = true; | ||||
my_divisor /= __TBB_INITIAL_CHUNKS; // let exactly P tasks to be di | ||||
stributed across workers | ||||
my_max_depth = factor_power+1; // the first factor_power ranges wil | ||||
l be spawned, and >=1 ranges should be left | ||||
__TBB_ASSERT( my_max_depth < __TBB_RANGE_POOL_CAPACITY, 0 ); | __TBB_ASSERT( my_max_depth < __TBB_RANGE_POOL_CAPACITY, 0 ); | |||
} | } | |||
affinity_partition_type(affinity_partition_type& p, split) | affinity_partition_type(affinity_partition_type& p, split) | |||
: auto_partition_type_base<affinity_partition_type>(p, split()), my | : adaptive_partition_type_base<affinity_partition_type>(p, split()) | |||
_array(p.my_array) { | , | |||
__TBB_ASSERT( p.map_end-p.map_begin<factor || (p.map_end-p.map_begi | my_delay(pass), | |||
n)%factor==0, NULL ); | #ifdef __TBB_USE_MACHINE_TIME_STAMPS | |||
map_end = p.map_end; | my_dst_tsc(0), | |||
map_begin = p.map_end = p.map_mid; | #endif | |||
set_mid(); p.set_mid(); | my_array(p.my_array) { | |||
my_delay = p.my_delay; | // the sum of the divisors represents original value of p.my_diviso | |||
r before split | ||||
__TBB_ASSERT(my_divisor + p.my_divisor <= factor, NULL); | ||||
my_begin = p.my_begin + p.my_divisor; | ||||
} | ||||
affinity_partition_type(affinity_partition_type& p, const proportional_ | ||||
split& split_obj) | ||||
: adaptive_partition_type_base<affinity_partition_type>(p, split_ob | ||||
j), | ||||
my_delay(start), | ||||
#ifdef __TBB_USE_MACHINE_TIME_STAMPS | ||||
my_dst_tsc(0), | ||||
#endif | ||||
my_array(p.my_array) { | ||||
size_t total_divisor = my_divisor + p.my_divisor; | ||||
__TBB_ASSERT(total_divisor % factor == 0, NULL); | ||||
my_divisor = (my_divisor + factor/2) & (0u - factor); | ||||
if (!my_divisor) | ||||
my_divisor = factor; | ||||
else if (my_divisor == total_divisor) | ||||
my_divisor = total_divisor - factor; | ||||
p.my_divisor = total_divisor - my_divisor; | ||||
__TBB_ASSERT(my_divisor && p.my_divisor, NULL); | ||||
my_begin = p.my_begin + p.my_divisor; | ||||
} | } | |||
void set_affinity( task &t ) { | void set_affinity( task &t ) { | |||
if( map_begin<map_end ) | if( my_divisor ) { | |||
t.set_affinity( my_array[map_begin] ); | if( !my_array[my_begin] ) { | |||
// TODO: consider code reuse for static_paritioner | ||||
my_array[my_begin] = affinity_id(my_begin / factor + 1); | ||||
} | ||||
t.set_affinity( my_array[my_begin] ); | ||||
} | ||||
} | } | |||
void note_affinity( task::affinity_id id ) { | void note_affinity( task::affinity_id id ) { | |||
if( map_begin<map_end ) | if( my_divisor ) | |||
my_array[map_begin] = id; | my_array[my_begin] = id; | |||
} | } | |||
bool check_for_demand( task &t ) { | bool check_for_demand( task &t ) { | |||
if( !my_delay ) { | if( pass == my_delay ) { | |||
if( map_mid<map_end ) { | if( my_divisor > 1 ) // produce affinitized tasks while they ha | |||
__TBB_ASSERT(my_max_depth>__TBB_Log2(map_end-map_mid), 0); | ve slot in array | |||
return true;// do not do my_max_depth++ here, but be sure m | return true; // do not do my_max_depth++ here, but be sure | |||
y_max_depth is big enough | range_pool is splittable once more | |||
else if( my_divisor && my_max_depth ) { // make balancing task | ||||
my_divisor = 0; // once for each task; depth will be decrea | ||||
sed in align_depth() | ||||
return true; | ||||
} | } | |||
if( flag_task::is_peer_stolen(t) ) { | else if( flag_task::is_peer_stolen(t) ) { | |||
my_max_depth++; | my_max_depth += __TBB_DEMAND_DEPTH_ADD; | |||
return true; | return true; | |||
} | } | |||
} else my_delay = false; | } else if( start == my_delay ) { | |||
#ifndef __TBB_USE_MACHINE_TIME_STAMPS | ||||
my_delay = pass; | ||||
#else | ||||
my_dst_tsc = __TBB_machine_time_stamp() + __TBB_task_duration() | ||||
; | ||||
my_delay = run; | ||||
} else if( run == my_delay ) { | ||||
if( __TBB_machine_time_stamp() < my_dst_tsc ) { | ||||
__TBB_ASSERT(my_max_depth > 0, NULL); | ||||
return false; | ||||
} | ||||
my_delay = pass; | ||||
return true; | ||||
#endif // __TBB_USE_MACHINE_TIME_STAMPS | ||||
} | ||||
return false; | return false; | |||
} | } | |||
bool is_divisible() { | bool is_divisible() { // part of old should_execute_range() | |||
return my_divisor > 1; | return my_divisor > factor; | |||
} | } | |||
#if _MSC_VER && !defined(__INTEL_COMPILER) | ||||
// Suppress "conditional expression is constant" warning. | ||||
#pragma warning( push ) | ||||
#pragma warning( disable: 4127 ) | ||||
#endif | ||||
template <typename Range> | ||||
split_type get_split() { | ||||
if (is_range_divisible_in_proportion<Range>::value) { | ||||
size_t size = my_divisor / factor; | ||||
#if __TBB_NONUNIFORM_TASK_CREATION | ||||
size_t right = (size + 2) / 3; | ||||
#else | ||||
size_t right = size / 2; | ||||
#endif | ||||
size_t left = size - right; | ||||
return split_type(left, right); | ||||
} else { | ||||
return split_type(1, 1); | ||||
} | ||||
} | ||||
#if _MSC_VER && !defined(__INTEL_COMPILER) | ||||
#pragma warning( pop ) | ||||
#endif // warning 4127 is back | ||||
static const unsigned range_pool_size = __TBB_RANGE_POOL_CAPACITY; | static const unsigned range_pool_size = __TBB_RANGE_POOL_CAPACITY; | |||
}; | }; | |||
class auto_partition_type: public auto_partition_type_base<auto_partition_t ype> { | class auto_partition_type: public adaptive_partition_type_base<auto_partiti on_type> { | |||
public: | public: | |||
auto_partition_type( const auto_partitioner& ) {} | auto_partition_type( const auto_partitioner& ) { | |||
my_divisor *= __TBB_INITIAL_CHUNKS; | ||||
} | ||||
auto_partition_type( auto_partition_type& src, split) | auto_partition_type( auto_partition_type& src, split) | |||
: auto_partition_type_base<auto_partition_type>(src, split()) {} | : adaptive_partition_type_base<auto_partition_type>(src, split()) {} | |||
bool is_divisible() { // part of old should_execute_range() | ||||
if( my_divisor > 1 ) return true; | ||||
if( my_divisor && my_max_depth ) { // can split the task. TODO: on- | ||||
stack flag instead | ||||
// keep same fragmentation while splitting for the local task p | ||||
ool | ||||
my_max_depth--; | ||||
my_divisor = 0; // decrease max_depth once per task | ||||
return true; | ||||
} else return false; | ||||
} | ||||
bool check_for_demand(task &t) { | ||||
if( flag_task::is_peer_stolen(t) ) { | ||||
my_max_depth += __TBB_DEMAND_DEPTH_ADD; | ||||
return true; | ||||
} else return false; | ||||
} | ||||
static const unsigned range_pool_size = __TBB_RANGE_POOL_CAPACITY; | static const unsigned range_pool_size = __TBB_RANGE_POOL_CAPACITY; | |||
}; | }; | |||
class simple_partition_type: public partition_type_base<simple_partition_ty pe> { | class simple_partition_type: public partition_type_base<simple_partition_ty pe> { | |||
public: | public: | |||
simple_partition_type( const simple_partitioner& ) {} | simple_partition_type( const simple_partitioner& ) {} | |||
simple_partition_type( const simple_partition_type&, split ) {} | simple_partition_type( const simple_partition_type&, split ) {} | |||
//! simplified algorithm | //! simplified algorithm | |||
template<typename StartType, typename Range> | template<typename StartType, typename Range> | |||
void execute(StartType &start, Range &range) { | void execute(StartType &start, Range &range) { | |||
split_type split_obj = split(); // start.offer_work accepts split_t ype as reference | ||||
while( range.is_divisible() ) | while( range.is_divisible() ) | |||
start.offer_work( split() ); | start.offer_work( split_obj ); | |||
start.run_body( range ); | start.run_body( range ); | |||
} | } | |||
//static const unsigned range_pool_size = 1; - not necessary because ex ecute() is overridden | //static const unsigned range_pool_size = 1; - not necessary because ex ecute() is overridden | |||
}; | }; | |||
//! Backward-compatible partition for auto and affinity partition objects. | //! Backward-compatible partition for auto and affinity partition objects. | |||
class old_auto_partition_type: public tbb::internal::partition_type_base { | class old_auto_partition_type: public tbb::internal::partition_type_base { | |||
size_t num_chunks; | size_t num_chunks; | |||
static const size_t VICTIM_CHUNKS = 4; | static const size_t VICTIM_CHUNKS = 4; | |||
public: | public: | |||
skipping to change at line 421 | skipping to change at line 571 | |||
//! @endcond | //! @endcond | |||
} // namespace interfaceX | } // namespace interfaceX | |||
//! A simple partitioner | //! A simple partitioner | |||
/** Divides the range until the range is not divisible. | /** Divides the range until the range is not divisible. | |||
@ingroup algorithms */ | @ingroup algorithms */ | |||
class simple_partitioner { | class simple_partitioner { | |||
public: | public: | |||
simple_partitioner() {} | simple_partitioner() {} | |||
private: | private: | |||
template<typename Range, typename Body, typename Partitioner> friend cl | template<typename Range, typename Body, typename Partitioner> friend cl | |||
ass serial::interface6::start_for; | ass serial::interface7::start_for; | |||
template<typename Range, typename Body, typename Partitioner> friend cl | template<typename Range, typename Body, typename Partitioner> friend cl | |||
ass interface6::internal::start_for; | ass interface7::internal::start_for; | |||
template<typename Range, typename Body, typename Partitioner> friend cl | template<typename Range, typename Body, typename Partitioner> friend cl | |||
ass interface6::internal::start_reduce; | ass interface7::internal::start_reduce; | |||
template<typename Range, typename Body, typename Partitioner> friend cl ass internal::start_scan; | template<typename Range, typename Body, typename Partitioner> friend cl ass internal::start_scan; | |||
// backward compatibility | // backward compatibility | |||
class partition_type: public internal::partition_type_base { | class partition_type: public internal::partition_type_base { | |||
public: | public: | |||
bool should_execute_range(const task& ) {return false;} | bool should_execute_range(const task& ) {return false;} | |||
partition_type( const simple_partitioner& ) {} | partition_type( const simple_partitioner& ) {} | |||
partition_type( const partition_type&, split ) {} | partition_type( const partition_type&, split ) {} | |||
}; | }; | |||
// new implementation just extends existing interface | // new implementation just extends existing interface | |||
typedef interface6::internal::simple_partition_type task_partition_type | typedef interface7::internal::simple_partition_type task_partition_type | |||
; | ; | |||
// TODO: consider to make split_type public | ||||
typedef interface7::internal::simple_partition_type::split_type split_t | ||||
ype; | ||||
}; | }; | |||
//! An auto partitioner | //! An auto partitioner | |||
/** The range is initial divided into several large chunks. | /** The range is initial divided into several large chunks. | |||
Chunks are further subdivided into smaller pieces if demand detected an d they are divisible. | Chunks are further subdivided into smaller pieces if demand detected an d they are divisible. | |||
@ingroup algorithms */ | @ingroup algorithms */ | |||
class auto_partitioner { | class auto_partitioner { | |||
public: | public: | |||
auto_partitioner() {} | auto_partitioner() {} | |||
private: | private: | |||
template<typename Range, typename Body, typename Partitioner> friend cl | template<typename Range, typename Body, typename Partitioner> friend cl | |||
ass serial::interface6::start_for; | ass serial::interface7::start_for; | |||
template<typename Range, typename Body, typename Partitioner> friend cl | template<typename Range, typename Body, typename Partitioner> friend cl | |||
ass interface6::internal::start_for; | ass interface7::internal::start_for; | |||
template<typename Range, typename Body, typename Partitioner> friend cl | template<typename Range, typename Body, typename Partitioner> friend cl | |||
ass interface6::internal::start_reduce; | ass interface7::internal::start_reduce; | |||
template<typename Range, typename Body, typename Partitioner> friend cl ass internal::start_scan; | template<typename Range, typename Body, typename Partitioner> friend cl ass internal::start_scan; | |||
// backward compatibility | // backward compatibility | |||
typedef interface6::internal::old_auto_partition_type partition_type; | typedef interface7::internal::old_auto_partition_type partition_type; | |||
// new implementation just extends existing interface | // new implementation just extends existing interface | |||
typedef interface6::internal::auto_partition_type task_partition_type; | typedef interface7::internal::auto_partition_type task_partition_type; | |||
// TODO: consider to make split_type public | ||||
typedef interface7::internal::auto_partition_type::split_type split_typ | ||||
e; | ||||
}; | }; | |||
//! An affinity partitioner | //! An affinity partitioner | |||
class affinity_partitioner: internal::affinity_partitioner_base_v3 { | class affinity_partitioner: internal::affinity_partitioner_base_v3 { | |||
public: | public: | |||
affinity_partitioner() {} | affinity_partitioner() {} | |||
private: | private: | |||
template<typename Range, typename Body, typename Partitioner> friend cl | template<typename Range, typename Body, typename Partitioner> friend cl | |||
ass serial::interface6::start_for; | ass serial::interface7::start_for; | |||
template<typename Range, typename Body, typename Partitioner> friend cl | template<typename Range, typename Body, typename Partitioner> friend cl | |||
ass interface6::internal::start_for; | ass interface7::internal::start_for; | |||
template<typename Range, typename Body, typename Partitioner> friend cl | template<typename Range, typename Body, typename Partitioner> friend cl | |||
ass interface6::internal::start_reduce; | ass interface7::internal::start_reduce; | |||
template<typename Range, typename Body, typename Partitioner> friend cl ass internal::start_scan; | template<typename Range, typename Body, typename Partitioner> friend cl ass internal::start_scan; | |||
// backward compatibility - for parallel_scan only | // backward compatibility - for parallel_scan only | |||
typedef interface6::internal::old_auto_partition_type partition_type; | typedef interface7::internal::old_auto_partition_type partition_type; | |||
// new implementation just extends existing interface | // new implementation just extends existing interface | |||
typedef interface6::internal::affinity_partition_type task_partition_ty | typedef interface7::internal::affinity_partition_type task_partition_ty | |||
pe; | pe; | |||
// TODO: consider to make split_type public | ||||
typedef interface7::internal::affinity_partition_type::split_type split | ||||
_type; | ||||
}; | }; | |||
} // namespace tbb | } // namespace tbb | |||
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) | |||
#pragma warning (pop) | #pragma warning (pop) | |||
#endif // warning 4244 is back | #endif // warning 4244 is back | |||
#undef __TBB_INITIAL_CHUNKS | #undef __TBB_INITIAL_CHUNKS | |||
#undef __TBB_RANGE_POOL_CAPACITY | #undef __TBB_RANGE_POOL_CAPACITY | |||
#undef __TBB_INIT_DEPTH | #undef __TBB_INIT_DEPTH | |||
End of changes. 53 change blocks. | ||||
112 lines changed or deleted | 290 lines changed or added | |||
task.h | task.h | |||
---|---|---|---|---|
skipping to change at line 67 | skipping to change at line 67 | |||
class allocate_additional_child_of_proxy: no_assign { | class allocate_additional_child_of_proxy: no_assign { | |||
//! No longer used, but retained for binary layout compatibility. Always NULL. | //! No longer used, but retained for binary layout compatibility. Always NULL. | |||
task* self; | task* self; | |||
task& parent; | task& parent; | |||
public: | public: | |||
explicit allocate_additional_child_of_proxy( task& parent_ ) : self (NULL), parent(parent_) {} | explicit allocate_additional_child_of_proxy( task& parent_ ) : self (NULL), parent(parent_) {} | |||
task& __TBB_EXPORTED_METHOD allocate( size_t size ) const; | task& __TBB_EXPORTED_METHOD allocate( size_t size ) const; | |||
void __TBB_EXPORTED_METHOD free( task& ) const; | void __TBB_EXPORTED_METHOD free( task& ) const; | |||
}; | }; | |||
struct cpu_ctl_env_space { int space[sizeof(internal::uint64_t)/sizeof( int)]; }; | ||||
} //< namespace internal @endcond | } //< namespace internal @endcond | |||
namespace interface5 { | namespace interface5 { | |||
namespace internal { | namespace internal { | |||
//! Base class for methods that became static in TBB 3.0. | //! Base class for methods that became static in TBB 3.0. | |||
/** TBB's evolution caused the "this" argument for several methods to become obsolete. | /** TBB's evolution caused the "this" argument for several methods to become obsolete. | |||
However, for backwards binary compatibility, the new methods ne ed distinct names, | However, for backwards binary compatibility, the new methods ne ed distinct names, | |||
otherwise the One Definition Rule would be broken. Hence the n ew methods are | otherwise the One Definition Rule would be broken. Hence the n ew methods are | |||
defined in this private base class, and then exposed in class t ask via | defined in this private base class, and then exposed in class t ask via | |||
using declarations. */ | using declarations. */ | |||
skipping to change at line 336 | skipping to change at line 337 | |||
}; | }; | |||
public: | public: | |||
enum kind_type { | enum kind_type { | |||
isolated, | isolated, | |||
bound | bound | |||
}; | }; | |||
enum traits_type { | enum traits_type { | |||
exact_exception = 0x0001ul << traits_offset, | exact_exception = 0x0001ul << traits_offset, | |||
#if __TBB_FP_CONTEXT | ||||
fp_settings = 0x0002ul << traits_offset, | ||||
#endif | ||||
concurrent_wait = 0x0004ul << traits_offset, | concurrent_wait = 0x0004ul << traits_offset, | |||
#if TBB_USE_CAPTURED_EXCEPTION | #if TBB_USE_CAPTURED_EXCEPTION | |||
default_traits = 0 | default_traits = 0 | |||
#else | #else | |||
default_traits = exact_exception | default_traits = exact_exception | |||
#endif /* !TBB_USE_CAPTURED_EXCEPTION */ | #endif /* !TBB_USE_CAPTURED_EXCEPTION */ | |||
}; | }; | |||
private: | private: | |||
enum state { | enum state { | |||
skipping to change at line 373 | skipping to change at line 377 | |||
//! Used to set and maintain stack stitching point for Intel Performanc e Tools. | //! Used to set and maintain stack stitching point for Intel Performanc e Tools. | |||
__itt_caller itt_caller; | __itt_caller itt_caller; | |||
//! Leading padding protecting accesses to frequently used members from false sharing. | //! Leading padding protecting accesses to frequently used members from false sharing. | |||
/** Read accesses to the field my_cancellation_requested are on the hot path inside | /** Read accesses to the field my_cancellation_requested are on the hot path inside | |||
the scheduler. This padding ensures that this field never shares th e same cache | the scheduler. This padding ensures that this field never shares th e same cache | |||
line with a local variable that is frequently written to. **/ | line with a local variable that is frequently written to. **/ | |||
char _leading_padding[internal::NFS_MaxLineSize | char _leading_padding[internal::NFS_MaxLineSize | |||
- 2 * sizeof(uintptr_t)- sizeof(void*) - sizeof(i nternal::context_list_node_t) | - 2 * sizeof(uintptr_t)- sizeof(void*) - sizeof(i nternal::context_list_node_t) | |||
- sizeof(__itt_caller)]; | - sizeof(__itt_caller) | |||
#if __TBB_FP_CONTEXT | ||||
- sizeof(internal::cpu_ctl_env_space) | ||||
#endif | ||||
]; | ||||
#if __TBB_FP_CONTEXT | ||||
//! Space for platform-specific FPU settings. | ||||
/** Must only be accessed inside TBB binaries, and never directly in us | ||||
er | ||||
code or inline methods. */ | ||||
internal::cpu_ctl_env_space my_cpu_ctl_env; | ||||
#endif | ||||
//! Specifies whether cancellation was requested for this task group. | //! Specifies whether cancellation was requested for this task group. | |||
uintptr_t my_cancellation_requested; | uintptr_t my_cancellation_requested; | |||
//! Version for run-time checks and behavioral traits of the context. | //! Version for run-time checks and behavioral traits of the context. | |||
/** Version occupies low 16 bits, and traits (zero or more ORed enumera tors | /** Version occupies low 16 bits, and traits (zero or more ORed enumera tors | |||
from the traits_type enumerations) take the next 16 bits. | from the traits_type enumerations) take the next 16 bits. | |||
Original (zeroth) version of the context did not support any traits . **/ | Original (zeroth) version of the context did not support any traits . **/ | |||
uintptr_t my_version_and_traits; | uintptr_t my_version_and_traits; | |||
skipping to change at line 439 | skipping to change at line 454 | |||
entirely out-of-line because the run-time version must be set by th e user | entirely out-of-line because the run-time version must be set by th e user | |||
code. This will become critically important for binary compatibilit y, if | code. This will become critically important for binary compatibilit y, if | |||
we ever have to change the size of the context object. | we ever have to change the size of the context object. | |||
Boosting the runtime version will also be necessary if new data fie lds are | Boosting the runtime version will also be necessary if new data fie lds are | |||
introduced in the currently unused padding areas and these fields a re updated | introduced in the currently unused padding areas and these fields a re updated | |||
by inline methods. **/ | by inline methods. **/ | |||
task_group_context ( kind_type relation_with_parent = bound, | task_group_context ( kind_type relation_with_parent = bound, | |||
uintptr_t traits = default_traits ) | uintptr_t traits = default_traits ) | |||
: my_kind(relation_with_parent) | : my_kind(relation_with_parent) | |||
, my_version_and_traits(1 | traits) | , my_version_and_traits(2 | traits) | |||
{ | { | |||
init(); | init(); | |||
} | } | |||
// Do not introduce standalone unbind method since it will break state propagation assumptions | // Do not introduce standalone unbind method since it will break state propagation assumptions | |||
__TBB_EXPORTED_METHOD ~task_group_context (); | __TBB_EXPORTED_METHOD ~task_group_context (); | |||
//! Forcefully reinitializes the context after the task tree it was ass ociated with is completed. | //! Forcefully reinitializes the context after the task tree it was ass ociated with is completed. | |||
/** Because the method assumes that all the tasks that used to be assoc iated with | /** Because the method assumes that all the tasks that used to be assoc iated with | |||
this context have already finished, calling it while the context is still | this context have already finished, calling it while the context is still | |||
skipping to change at line 479 | skipping to change at line 494 | |||
//! Records the pending exception, and cancels the task group. | //! Records the pending exception, and cancels the task group. | |||
/** May be called only from inside a catch-block. If the context is alr eady | /** May be called only from inside a catch-block. If the context is alr eady | |||
cancelled, does nothing. | cancelled, does nothing. | |||
The method brings the task group associated with this context exact ly into | The method brings the task group associated with this context exact ly into | |||
the state it would be in, if one of its tasks threw the currently p ending | the state it would be in, if one of its tasks threw the currently p ending | |||
exception during its execution. In other words, it emulates the act ions | exception during its execution. In other words, it emulates the act ions | |||
of the scheduler's dispatch loop exception handler. **/ | of the scheduler's dispatch loop exception handler. **/ | |||
void __TBB_EXPORTED_METHOD register_pending_exception (); | void __TBB_EXPORTED_METHOD register_pending_exception (); | |||
#if __TBB_FP_CONTEXT | ||||
//! Captures the current FPU control settings to the context. | ||||
/** Because the method assumes that all the tasks that used to be assoc | ||||
iated with | ||||
this context have already finished, calling it while the context is | ||||
still | ||||
in use somewhere in the task hierarchy leads to undefined behavior. | ||||
IMPORTANT: This method is not thread safe! | ||||
The method does not change the FPU control settings of the context' | ||||
s parent. **/ | ||||
void __TBB_EXPORTED_METHOD capture_fp_settings (); | ||||
#endif | ||||
#if __TBB_TASK_PRIORITY | #if __TBB_TASK_PRIORITY | |||
//! Changes priority of the task group | //! Changes priority of the task group | |||
void set_priority ( priority_t ); | void set_priority ( priority_t ); | |||
//! Retrieves current priority of the current task group | //! Retrieves current priority of the current task group | |||
priority_t priority () const; | priority_t priority () const; | |||
#endif /* __TBB_TASK_PRIORITY */ | #endif /* __TBB_TASK_PRIORITY */ | |||
protected: | protected: | |||
//! Out-of-line part of the constructor. | //! Out-of-line part of the constructor. | |||
End of changes. 5 change blocks. | ||||
2 lines changed or deleted | 33 lines changed or added | |||
task_group.h | task_group.h | |||
---|---|---|---|---|
skipping to change at line 119 | skipping to change at line 119 | |||
} | } | |||
public: | public: | |||
task_group_base( uintptr_t traits = 0 ) | task_group_base( uintptr_t traits = 0 ) | |||
: my_context(task_group_context::bound, task_group_context::default _traits | traits) | : my_context(task_group_context::bound, task_group_context::default _traits | traits) | |||
{ | { | |||
my_root = new( task::allocate_root(my_context) ) empty_task; | my_root = new( task::allocate_root(my_context) ) empty_task; | |||
my_root->set_ref_count(1); | my_root->set_ref_count(1); | |||
} | } | |||
~task_group_base() { | ~task_group_base() __TBB_NOEXCEPT(false) { | |||
if( my_root->ref_count() > 1 ) { | if( my_root->ref_count() > 1 ) { | |||
bool stack_unwinding_in_progress = std::uncaught_exception(); | bool stack_unwinding_in_progress = std::uncaught_exception(); | |||
// Always attempt to do proper cleanup to avoid inevitable memo ry corruption | // Always attempt to do proper cleanup to avoid inevitable memo ry corruption | |||
// in case of missing wait (for the sake of better testability & debuggability) | // in case of missing wait (for the sake of better testability & debuggability) | |||
if ( !is_canceling() ) | if ( !is_canceling() ) | |||
cancel(); | cancel(); | |||
__TBB_TRY { | __TBB_TRY { | |||
my_root->wait_for_all(); | my_root->wait_for_all(); | |||
} __TBB_CATCH (...) { | } __TBB_CATCH (...) { | |||
task::destroy(*my_root); | task::destroy(*my_root); | |||
End of changes. 1 change blocks. | ||||
1 lines changed or deleted | 1 lines changed or added | |||
task_scheduler_observer.h | task_scheduler_observer.h | |||
---|---|---|---|---|
skipping to change at line 99 | skipping to change at line 99 | |||
Obsolete semantics. For global observers it is called by a thread b efore | Obsolete semantics. For global observers it is called by a thread b efore | |||
the first steal since observation became enabled. **/ | the first steal since observation became enabled. **/ | |||
virtual void on_scheduler_exit( bool /*is_worker*/ ) {} | virtual void on_scheduler_exit( bool /*is_worker*/ ) {} | |||
//! Destructor automatically switches observation off if it is enabled. | //! Destructor automatically switches observation off if it is enabled. | |||
virtual ~task_scheduler_observer_v3() { if(my_proxy) observe(false);} | virtual ~task_scheduler_observer_v3() { if(my_proxy) observe(false);} | |||
}; | }; | |||
} // namespace internal | } // namespace internal | |||
#if TBB_PREVIEW_LOCAL_OBSERVER | #if __TBB_ARENA_OBSERVER | |||
namespace interface6 { | namespace interface6 { | |||
class task_scheduler_observer : public internal::task_scheduler_observer_v3 { | class task_scheduler_observer : public internal::task_scheduler_observer_v3 { | |||
friend class internal::task_scheduler_observer_v3; | friend class internal::task_scheduler_observer_v3; | |||
friend class internal::observer_proxy; | friend class internal::observer_proxy; | |||
friend class internal::observer_list; | friend class internal::observer_list; | |||
/** Negative numbers with the largest absolute value to minimize probab ility | /** Negative numbers with the largest absolute value to minimize probab ility | |||
of coincidence in case of a bug in busy count usage. **/ | of coincidence in case of a bug in busy count usage. **/ | |||
// TODO: take more high bits for version number | // TODO: take more high bits for version number | |||
static const intptr_t v6_trait = (intptr_t)((~(uintptr_t)0 >> 1) + 1); | static const intptr_t v6_trait = (intptr_t)((~(uintptr_t)0 >> 1) + 1); | |||
skipping to change at line 127 | skipping to change at line 127 | |||
/** For a local observer entry/exit notifications are invoked whenever a worker | /** For a local observer entry/exit notifications are invoked whenever a worker | |||
thread joins/leaves the arena of the observer's owner thread. If a thread is | thread joins/leaves the arena of the observer's owner thread. If a thread is | |||
already in the arena when the observer is activated, the entry noti fication is | already in the arena when the observer is activated, the entry noti fication is | |||
called before it executes the first stolen task. **/ | called before it executes the first stolen task. **/ | |||
/** TODO: Obsolete. | /** TODO: Obsolete. | |||
Global observer semantics is obsolete as it violates master thread isolation | Global observer semantics is obsolete as it violates master thread isolation | |||
guarantees and is not composable. Thus the current default behavior of the | guarantees and is not composable. Thus the current default behavior of the | |||
constructor is obsolete too and will be changed in one of the futur e versions | constructor is obsolete too and will be changed in one of the futur e versions | |||
of the library. **/ | of the library. **/ | |||
task_scheduler_observer( bool local = false ) { | task_scheduler_observer( bool local = false ) { | |||
my_busy_count.store<relaxed>(v6_trait); | ||||
my_context_tag = local? implicit_tag : global_tag; | my_context_tag = local? implicit_tag : global_tag; | |||
} | } | |||
#if __TBB_TASK_ARENA | #if __TBB_TASK_ARENA | |||
//! Construct local observer for a given arena in inactive state (obser vation disabled). | //! Construct local observer for a given arena in inactive state (obser vation disabled). | |||
/** entry/exit notifications are invoked whenever a thread joins/leaves arena. | /** entry/exit notifications are invoked whenever a thread joins/leaves arena. | |||
If a thread is already in the arena when the observer is activated, the entry notification | If a thread is already in the arena when the observer is activated, the entry notification | |||
is called before it executes the first stolen task. **/ | is called before it executes the first stolen task. **/ | |||
task_scheduler_observer( task_arena & a) { | task_scheduler_observer( task_arena & a) { | |||
my_busy_count.store<relaxed>(v6_trait); | ||||
my_context_tag = (intptr_t)&a; | my_context_tag = (intptr_t)&a; | |||
} | } | |||
#endif //__TBB_TASK_ARENA | #endif //__TBB_TASK_ARENA | |||
//! Destructor additionally protects concurrent on_scheduler_leaving no | /** Destructor protects instance of the observer from concurrent notifi | |||
tification | cation. | |||
// It is recommended to disable observation before destructor of a deri | It is recommended to disable observation before destructor of a deri | |||
ved class starts, | ved class starts, | |||
// otherwise it can lead to concurrent notification callback on partly | otherwise it can lead to concurrent notification callback on partly | |||
destroyed object | destroyed object **/ | |||
virtual ~task_scheduler_observer() { if(my_proxy) observe(false); } | virtual ~task_scheduler_observer() { if(my_proxy) observe(false); } | |||
//! The callback can be invoked in a worker thread before it leaves an | //! Enable or disable observation | |||
arena. | /** Warning: concurrent invocations of this method are not safe. | |||
/** If it returns false, the thread remains in the arena. Will not be c | Repeated calls with the same state are no-ops. **/ | |||
alled for masters | void observe( bool state=true ) { | |||
or if the worker leaves arena due to rebalancing or priority change | if( state && !my_proxy ) { | |||
s, etc. | __TBB_ASSERT( !my_busy_count, "Inconsistent state of task_sched | |||
NOTE: The preview library must be linked for this method to take ef | uler_observer instance"); | |||
fect **/ | my_busy_count.store<relaxed>(v6_trait); | |||
virtual bool on_scheduler_leaving() { return true; } | } | |||
internal::task_scheduler_observer_v3::observe(state); | ||||
} | ||||
//! Return commands for may_sleep() | ||||
enum { keep_awake = false, allow_sleep = true }; | ||||
//! The callback can be invoked by a worker thread before it goes to sl | ||||
eep. | ||||
/** If it returns false ('keep_awake'), the thread will keep spinning a | ||||
nd looking for work. | ||||
It will not be called for master threads. **/ | ||||
virtual bool may_sleep() { return allow_sleep; } | ||||
}; | }; | |||
} //namespace interface6 | } //namespace interface6 | |||
using interface6::task_scheduler_observer; | using interface6::task_scheduler_observer; | |||
#else /*TBB_PREVIEW_LOCAL_OBSERVER*/ | #else /*__TBB_ARENA_OBSERVER*/ | |||
typedef tbb::internal::task_scheduler_observer_v3 task_scheduler_observer; | typedef tbb::internal::task_scheduler_observer_v3 task_scheduler_observer; | |||
#endif /*TBB_PREVIEW_LOCAL_OBSERVER*/ | #endif /*__TBB_ARENA_OBSERVER*/ | |||
} // namespace tbb | } // namespace tbb | |||
#endif /* __TBB_SCHEDULER_OBSERVER */ | #endif /* __TBB_SCHEDULER_OBSERVER */ | |||
#endif /* __TBB_task_scheduler_observer_H */ | #endif /* __TBB_task_scheduler_observer_H */ | |||
End of changes. 7 change blocks. | ||||
20 lines changed or deleted | 30 lines changed or added | |||
tbb_config.h | tbb_config.h | |||
---|---|---|---|---|
skipping to change at line 120 | skipping to change at line 120 | |||
#if (__has_feature(__cxx_generalized_initializers__) && __has_inclu de(<initializer_list>)) | #if (__has_feature(__cxx_generalized_initializers__) && __has_inclu de(<initializer_list>)) | |||
#define __TBB_INITIALIZER_LISTS_PRESENT 1 | #define __TBB_INITIALIZER_LISTS_PRESENT 1 | |||
#endif | #endif | |||
#else | #else | |||
/** TODO: when MSVC2013 is supported by Intel C++ compiler, it will be enabled silently by compiler, so rule will need to be updated.**/ | /** TODO: when MSVC2013 is supported by Intel C++ compiler, it will be enabled silently by compiler, so rule will need to be updated.**/ | |||
#define __TBB_INITIALIZER_LISTS_PRESENT __INTEL_CXX11_MODE__ && __INTEL_COMPILER >= 1400 && (_MSC_VER >= 1800 || __TBB_GCC_VERSION >= 40 400 || _LIBCPP_VERSION) | #define __TBB_INITIALIZER_LISTS_PRESENT __INTEL_CXX11_MODE__ && __INTEL_COMPILER >= 1400 && (_MSC_VER >= 1800 || __TBB_GCC_VERSION >= 40 400 || _LIBCPP_VERSION) | |||
#endif | #endif | |||
#define __TBB_CONSTEXPR_PRESENT __INTEL_CXX11_MODE__ && __INTEL_COMPILER >= 1400 | #define __TBB_CONSTEXPR_PRESENT __INTEL_CXX11_MODE__ && __INTEL_COMPILER >= 1400 | |||
#define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT __INTEL_CXX11_MODE__ && __INTEL_COMPILER >= 1200 | #define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT __INTEL_CXX11_MODE__ && __INTEL_COMPILER >= 1200 | |||
/** ICC seems to disable support of noexcept event in c++11 when compil | ||||
ing in compatibility mode for gcc <4.6 **/ | ||||
#define __TBB_NOEXCEPT_PRESENT __INTEL_CXX11_MODE__ | ||||
&& __INTEL_COMPILER >= 1300 && (__TBB_GCC_VERSION >= 40600 || _LIBCPP_VERSI | ||||
ON || _MSC_VER) | ||||
#elif __clang__ | #elif __clang__ | |||
//TODO: these options need to be rechecked | //TODO: these options need to be rechecked | |||
/** on OS X* the only way to get C++11 is to use clang. For library feature s (e.g. exception_ptr) libc++ is also | /** on OS X* the only way to get C++11 is to use clang. For library feature s (e.g. exception_ptr) libc++ is also | |||
* required. So there is no need to check GCC version for clang**/ | * required. So there is no need to check GCC version for clang**/ | |||
#define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT __has_feature(__cxx_ variadic_templates__) | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT __has_feature(__cxx_ variadic_templates__) | |||
#define __TBB_CPP11_RVALUE_REF_PRESENT __has_feature(__cxx_ rvalue_references__) | #define __TBB_CPP11_RVALUE_REF_PRESENT __has_feature(__cxx_ rvalue_references__) | |||
/** TODO: extend exception_ptr related conditions to cover libstdc++ **/ | /** TODO: extend exception_ptr related conditions to cover libstdc++ **/ | |||
#define __TBB_EXCEPTION_PTR_PRESENT (__cplusplus >= 20110 3L && _LIBCPP_VERSION) | #define __TBB_EXCEPTION_PTR_PRESENT (__cplusplus >= 20110 3L && _LIBCPP_VERSION) | |||
#define __TBB_MAKE_EXCEPTION_PTR_PRESENT (__cplusplus >= 20110 3L && _LIBCPP_VERSION) | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (__cplusplus >= 20110 3L && _LIBCPP_VERSION) | |||
#define __TBB_STATIC_ASSERT_PRESENT __has_feature(__cxx_s tatic_assert__) | #define __TBB_STATIC_ASSERT_PRESENT __has_feature(__cxx_s tatic_assert__) | |||
/**Clang (preprocessor) has problems with dealing with expression havin g __has_include in #if's | /**Clang (preprocessor) has problems with dealing with expression havin g __has_include in #if's | |||
* used inside C++ code. (At least version that comes with OS X 10.8) * */ | * used inside C++ code. (At least version that comes with OS X 10.8) * */ | |||
#if (__GXX_EXPERIMENTAL_CXX0X__ && __has_include(<tuple>)) | #if (__GXX_EXPERIMENTAL_CXX0X__ && __has_include(<tuple>)) | |||
#define __TBB_CPP11_TUPLE_PRESENT 1 | #define __TBB_CPP11_TUPLE_PRESENT 1 | |||
#endif | #endif | |||
#if (__has_feature(__cxx_generalized_initializers__) && __has_include(< initializer_list>)) | #if (__has_feature(__cxx_generalized_initializers__) && __has_include(< initializer_list>)) | |||
#define __TBB_INITIALIZER_LISTS_PRESENT 1 | #define __TBB_INITIALIZER_LISTS_PRESENT 1 | |||
#endif | #endif | |||
#define __TBB_CONSTEXPR_PRESENT __has_feature(__cxx_c onstexpr__) | #define __TBB_CONSTEXPR_PRESENT __has_feature(__cxx_c onstexpr__) | |||
#define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT (__has_feature(__cxx_ defaulted_functions__) && __has_feature(__cxx_deleted_functions__)) | #define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT (__has_feature(__cxx_ defaulted_functions__) && __has_feature(__cxx_deleted_functions__)) | |||
/**For some unknown reason __has_feature(__cxx_noexcept) does not yiel | ||||
d true for all cases. Compiler bug ? **/ | ||||
#define __TBB_NOEXCEPT_PRESENT (__cplusplus >= 20110 | ||||
3L) | ||||
#elif __GNUC__ | #elif __GNUC__ | |||
#define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT __GXX_EXPERIMENTAL_CX X0X__ | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT __GXX_EXPERIMENTAL_CX X0X__ | |||
#define __TBB_CPP11_RVALUE_REF_PRESENT __GXX_EXPERIMENTAL_CX X0X__ | #define __TBB_CPP11_RVALUE_REF_PRESENT __GXX_EXPERIMENTAL_CX X0X__ | |||
/** __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 here is a substitution for _GLIB CXX_ATOMIC_BUILTINS_4, which is a prerequisite | /** __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 here is a substitution for _GLIB CXX_ATOMIC_BUILTINS_4, which is a prerequisite | |||
for exception_ptr but cannot be used in this file because it is def ined in a header, not by the compiler. | for exception_ptr but cannot be used in this file because it is def ined in a header, not by the compiler. | |||
If the compiler has no atomic intrinsics, the C++ library should no t expect those as well. **/ | If the compiler has no atomic intrinsics, the C++ library should no t expect those as well. **/ | |||
#define __TBB_EXCEPTION_PTR_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40404 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) | #define __TBB_EXCEPTION_PTR_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40404 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) | |||
#define __TBB_MAKE_EXCEPTION_PTR_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40600) | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40600) | |||
#define __TBB_STATIC_ASSERT_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40300) | #define __TBB_STATIC_ASSERT_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40300) | |||
#define __TBB_CPP11_TUPLE_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40300) | #define __TBB_CPP11_TUPLE_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40300) | |||
#define __TBB_INITIALIZER_LISTS_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40400) | #define __TBB_INITIALIZER_LISTS_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40400) | |||
/** gcc seems have to support constexpr from 4.4 but tests in (test_ato mic) seeming reasonable fail to compile prior 4.6**/ | /** gcc seems have to support constexpr from 4.4 but tests in (test_ato mic) seeming reasonable fail to compile prior 4.6**/ | |||
#define __TBB_CONSTEXPR_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40400) | #define __TBB_CONSTEXPR_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40400) | |||
#define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40400) | #define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40400) | |||
#define __TBB_NOEXCEPT_PRESENT (__GXX_EXPERIMENTAL_C XX0X__ && __TBB_GCC_VERSION >= 40600) | ||||
#elif _MSC_VER | #elif _MSC_VER | |||
#define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT (_MSC_VER >= 1800) | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT (_MSC_VER >= 1800) | |||
#define __TBB_CPP11_RVALUE_REF_PRESENT (_MSC_VER >= 1600) | #define __TBB_CPP11_RVALUE_REF_PRESENT (_MSC_VER >= 1600) | |||
#define __TBB_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1600) | #define __TBB_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1600) | |||
#define __TBB_STATIC_ASSERT_PRESENT (_MSC_VER >= 1600) | #define __TBB_STATIC_ASSERT_PRESENT (_MSC_VER >= 1600) | |||
#define __TBB_MAKE_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1700) | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT (_MSC_VER >= 1700) | |||
#define __TBB_CPP11_TUPLE_PRESENT (_MSC_VER >= 1600) | #define __TBB_CPP11_TUPLE_PRESENT (_MSC_VER >= 1600) | |||
#define __TBB_INITIALIZER_LISTS_PRESENT (_MSC_VER >= 1800) | #define __TBB_INITIALIZER_LISTS_PRESENT (_MSC_VER >= 1800) | |||
#define __TBB_CONSTEXPR_PRESENT 0 | #define __TBB_CONSTEXPR_PRESENT 0 | |||
#define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT (_MSC_VER >= 1800) | #define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT (_MSC_VER >= 1800) | |||
#define __TBB_NOEXCEPT_PRESENT 0 /*for _MSC_VER == 1 800*/ | ||||
#else | #else | |||
#define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT 0 | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT 0 | |||
#define __TBB_CPP11_RVALUE_REF_PRESENT 0 | #define __TBB_CPP11_RVALUE_REF_PRESENT 0 | |||
#define __TBB_EXCEPTION_PTR_PRESENT 0 | #define __TBB_EXCEPTION_PTR_PRESENT 0 | |||
#define __TBB_STATIC_ASSERT_PRESENT 0 | #define __TBB_STATIC_ASSERT_PRESENT 0 | |||
#define __TBB_MAKE_EXCEPTION_PTR_PRESENT 0 | #define __TBB_MAKE_EXCEPTION_PTR_PRESENT 0 | |||
#define __TBB_CPP11_TUPLE_PRESENT 0 | #define __TBB_CPP11_TUPLE_PRESENT 0 | |||
#define __TBB_INITIALIZER_LISTS_PRESENT 0 | #define __TBB_INITIALIZER_LISTS_PRESENT 0 | |||
#define __TBB_CONSTEXPR_PRESENT 0 | #define __TBB_CONSTEXPR_PRESENT 0 | |||
#define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT 0 | #define __TBB_DEFAULTED_AND_DELETED_FUNC_PRESENT 0 | |||
#define __TBB_NOEXCEPT_PRESENT 0 | ||||
#endif | #endif | |||
//TODO: not clear how exactly this macro affects exception_ptr - investigat e | //TODO: not clear how exactly this macro affects exception_ptr - investigat e | |||
// On linux ICC fails to find existing std::exception_ptr in libstdc++ with out this define | // On linux ICC fails to find existing std::exception_ptr in libstdc++ with out this define | |||
#if __INTEL_COMPILER && __GNUC__ && __TBB_EXCEPTION_PTR_PRESENT && !defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) | #if __INTEL_COMPILER && __GNUC__ && __TBB_EXCEPTION_PTR_PRESENT && !defined (__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) | |||
#define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 | #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 1 | |||
#endif | #endif | |||
// Work around a bug in MinGW32 | // Work around a bug in MinGW32 | |||
#if __MINGW32__ && __TBB_EXCEPTION_PTR_PRESENT && !defined(_GLIBCXX_ATOMIC_ BUILTINS_4) | #if __MINGW32__ && __TBB_EXCEPTION_PTR_PRESENT && !defined(_GLIBCXX_ATOMIC_ BUILTINS_4) | |||
skipping to change at line 322 | skipping to change at line 329 | |||
#endif | #endif | |||
/** __TBB_DYNAMIC_LOAD_ENABLED describes the system possibility to load sha red libraries at run time **/ | /** __TBB_DYNAMIC_LOAD_ENABLED describes the system possibility to load sha red libraries at run time **/ | |||
#ifndef __TBB_DYNAMIC_LOAD_ENABLED | #ifndef __TBB_DYNAMIC_LOAD_ENABLED | |||
#define __TBB_DYNAMIC_LOAD_ENABLED 1 | #define __TBB_DYNAMIC_LOAD_ENABLED 1 | |||
#endif | #endif | |||
/** __TBB_SOURCE_DIRECTLY_INCLUDED is a mode used in whitebox testing when | /** __TBB_SOURCE_DIRECTLY_INCLUDED is a mode used in whitebox testing when | |||
it's necessary to test internal functions not exported from TBB DLLs | it's necessary to test internal functions not exported from TBB DLLs | |||
**/ | **/ | |||
#if (_WIN32||_WIN64) && __TBB_SOURCE_DIRECTLY_INCLUDED | #if (_WIN32||_WIN64) && (__TBB_SOURCE_DIRECTLY_INCLUDED || TBB_USE_PREVIEW_ BINARY) | |||
#define __TBB_NO_IMPLICIT_LINKAGE 1 | #define __TBB_NO_IMPLICIT_LINKAGE 1 | |||
#define __TBBMALLOC_NO_IMPLICIT_LINKAGE 1 | #define __TBBMALLOC_NO_IMPLICIT_LINKAGE 1 | |||
#endif | #endif | |||
#ifndef __TBB_COUNT_TASK_NODES | #ifndef __TBB_COUNT_TASK_NODES | |||
#define __TBB_COUNT_TASK_NODES TBB_USE_ASSERT | #define __TBB_COUNT_TASK_NODES TBB_USE_ASSERT | |||
#endif | #endif | |||
#ifndef __TBB_TASK_GROUP_CONTEXT | #ifndef __TBB_TASK_GROUP_CONTEXT | |||
#define __TBB_TASK_GROUP_CONTEXT 1 | #define __TBB_TASK_GROUP_CONTEXT 1 | |||
#endif /* __TBB_TASK_GROUP_CONTEXT */ | #endif /* __TBB_TASK_GROUP_CONTEXT */ | |||
#ifndef __TBB_SCHEDULER_OBSERVER | #ifndef __TBB_SCHEDULER_OBSERVER | |||
#define __TBB_SCHEDULER_OBSERVER 1 | #define __TBB_SCHEDULER_OBSERVER 1 | |||
#endif /* __TBB_SCHEDULER_OBSERVER */ | #endif /* __TBB_SCHEDULER_OBSERVER */ | |||
#ifndef __TBB_FP_CONTEXT | ||||
#define __TBB_FP_CONTEXT __TBB_TASK_GROUP_CONTEXT | ||||
#endif /* __TBB_FP_CONTEXT */ | ||||
#if __TBB_FP_CONTEXT && !__TBB_TASK_GROUP_CONTEXT | ||||
#error __TBB_FP_CONTEXT requires __TBB_TASK_GROUP_CONTEXT to be enabled | ||||
#endif | ||||
#ifndef __TBB_TASK_ARENA | #ifndef __TBB_TASK_ARENA | |||
#define __TBB_TASK_ARENA (__TBB_BUILD||TBB_PREVIEW_TASK_ARENA) | #define __TBB_TASK_ARENA (__TBB_BUILD||TBB_PREVIEW_TASK_ARENA) | |||
#endif /* __TBB_TASK_ARENA */ | #endif /* __TBB_TASK_ARENA */ | |||
#if __TBB_TASK_ARENA | #if __TBB_TASK_ARENA | |||
#define __TBB_RECYCLE_TO_ENQUEUE __TBB_BUILD // keep non-official | #define __TBB_RECYCLE_TO_ENQUEUE __TBB_BUILD // keep non-official | |||
#if !__TBB_SCHEDULER_OBSERVER | #if !__TBB_SCHEDULER_OBSERVER | |||
#error TBB_PREVIEW_TASK_ARENA requires __TBB_SCHEDULER_OBSERVER to be enabled | #error TBB_PREVIEW_TASK_ARENA requires __TBB_SCHEDULER_OBSERVER to be enabled | |||
#endif | #endif | |||
#endif /* __TBB_TASK_ARENA */ | #endif /* __TBB_TASK_ARENA */ | |||
#if !defined(TBB_PREVIEW_LOCAL_OBSERVER) && __TBB_BUILD && __TBB_SCHEDULER_ | #ifndef __TBB_ARENA_OBSERVER | |||
OBSERVER | #define __TBB_ARENA_OBSERVER ((__TBB_BUILD||TBB_PREVIEW_LOCAL_OBSERVER) | |||
#define TBB_PREVIEW_LOCAL_OBSERVER 1 | && __TBB_SCHEDULER_OBSERVER) | |||
#endif /* TBB_PREVIEW_LOCAL_OBSERVER */ | #endif /* __TBB_ARENA_OBSERVER */ | |||
#ifndef __TBB_SLEEP_PERMISSION | ||||
#define __TBB_SLEEP_PERMISSION ((__TBB_CPF_BUILD||TBB_PREVIEW_LOCAL_OBS | ||||
ERVER)&& __TBB_SCHEDULER_OBSERVER) | ||||
#endif /* __TBB_SLEEP_PERMISSION */ | ||||
#if TBB_PREVIEW_FLOW_GRAPH_TRACE | ||||
#define __TBB_NO_IMPLICIT_LINKAGE 1 | ||||
#endif /* TBB_PREVIEW_FLOW_GRAPH_TRACE */ | ||||
#ifndef __TBB_ITT_STRUCTURE_API | #ifndef __TBB_ITT_STRUCTURE_API | |||
#define __TBB_ITT_STRUCTURE_API ( !__TBB_DEFINE_MIC && (__TBB_CPF_BUILD || TBB_PREVIEW_FLOW_GRAPH_TRACE) ) | #define __TBB_ITT_STRUCTURE_API ( !__TBB_DEFINE_MIC && (__TBB_CPF_BUILD || TBB_PREVIEW_FLOW_GRAPH_TRACE) ) | |||
#endif | #endif | |||
#if TBB_USE_EXCEPTIONS && !__TBB_TASK_GROUP_CONTEXT | #if TBB_USE_EXCEPTIONS && !__TBB_TASK_GROUP_CONTEXT | |||
#error TBB_USE_EXCEPTIONS requires __TBB_TASK_GROUP_CONTEXT to be enabl ed | #error TBB_USE_EXCEPTIONS requires __TBB_TASK_GROUP_CONTEXT to be enabl ed | |||
#endif | #endif | |||
#ifndef __TBB_TASK_PRIORITY | #ifndef __TBB_TASK_PRIORITY | |||
#define __TBB_TASK_PRIORITY (!__TBB_CPF_BUILD&&__TBB_TASK_GROUP_CONTEXT ) // TODO: it will be enabled for CPF in the next versions | #define __TBB_TASK_PRIORITY (!(__TBB_CPF_BUILD||TBB_USE_PREVIEW_BINARY) &&__TBB_TASK_GROUP_CONTEXT) // TODO: it will be enabled for CPF in the next versions | |||
#endif /* __TBB_TASK_PRIORITY */ | #endif /* __TBB_TASK_PRIORITY */ | |||
#if __TBB_TASK_PRIORITY && !__TBB_TASK_GROUP_CONTEXT | #if __TBB_TASK_PRIORITY && !__TBB_TASK_GROUP_CONTEXT | |||
#error __TBB_TASK_PRIORITY requires __TBB_TASK_GROUP_CONTEXT to be enab led | #error __TBB_TASK_PRIORITY requires __TBB_TASK_GROUP_CONTEXT to be enab led | |||
#endif | #endif | |||
#if TBB_PREVIEW_WAITING_FOR_WORKERS || __TBB_BUILD | #if TBB_PREVIEW_WAITING_FOR_WORKERS || __TBB_BUILD | |||
#define __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE 1 | #define __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE 1 | |||
#endif | #endif | |||
skipping to change at line 402 | skipping to change at line 425 | |||
#define __TBB_VARIADIC_MAX 5 /* current VS11 setting, may change. */ | #define __TBB_VARIADIC_MAX 5 /* current VS11 setting, may change. */ | |||
#else | #else | |||
#define __TBB_VARIADIC_MAX 10 | #define __TBB_VARIADIC_MAX 10 | |||
#endif | #endif | |||
#endif | #endif | |||
#if !defined(TBB_PREVIEW_SPECULATIVE_SPIN_RW_MUTEX) | #if !defined(TBB_PREVIEW_SPECULATIVE_SPIN_RW_MUTEX) | |||
#define TBB_PREVIEW_SPECULATIVE_SPIN_RW_MUTEX __TBB_CPF_BUILD | #define TBB_PREVIEW_SPECULATIVE_SPIN_RW_MUTEX __TBB_CPF_BUILD | |||
#endif /* TBB_PREVIEW_SPECULATIVE_SPIN_RW_MUTEX */ | #endif /* TBB_PREVIEW_SPECULATIVE_SPIN_RW_MUTEX */ | |||
#if TBB_PREVIEW_SPECULATIVE_SPIN_RW_MUTEX && !__TBB_CPF_BUILD | ||||
#define __TBB_NO_IMPLICIT_LINKAGE 1 | ||||
#endif /* TBB_PREVIEW_SPECULATIVE_SPIN_RW_MUTEX && !__TBB_CPF_BUILD */ | ||||
/** __TBB_WIN8UI_SUPPORT enables support of New Windows*8 Store Apps and li mit a possibility to load | /** __TBB_WIN8UI_SUPPORT enables support of New Windows*8 Store Apps and li mit a possibility to load | |||
shared libraries at run time only from application container **/ | shared libraries at run time only from application container **/ | |||
#if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_APP | #if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_APP | |||
#define __TBB_WIN8UI_SUPPORT 1 | #define __TBB_WIN8UI_SUPPORT 1 | |||
#else | #else | |||
#define __TBB_WIN8UI_SUPPORT 0 | #define __TBB_WIN8UI_SUPPORT 0 | |||
#endif | #endif | |||
// Define preprocessor symbols used to determine architecture | // Define preprocessor symbols used to determine architecture | |||
#if _WIN32||_WIN64 | #if _WIN32||_WIN64 | |||
End of changes. 10 change blocks. | ||||
6 lines changed or deleted | 39 lines changed or added | |||
tbb_exception.h | tbb_exception.h | |||
---|---|---|---|---|
skipping to change at line 112 | skipping to change at line 112 | |||
eid_invalid_swap, | eid_invalid_swap, | |||
eid_reservation_length_error, | eid_reservation_length_error, | |||
eid_invalid_key, | eid_invalid_key, | |||
eid_user_abort, | eid_user_abort, | |||
eid_reserved1, | eid_reserved1, | |||
#if __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE | #if __TBB_SUPPORTS_WORKERS_WAITING_IN_TERMINATE | |||
// This id is used only inside library and only for support of CPF func tionality. | // This id is used only inside library and only for support of CPF func tionality. | |||
// So, if we drop the functionality, eid_reserved1 can be safely rename d and reused. | // So, if we drop the functionality, eid_reserved1 can be safely rename d and reused. | |||
eid_blocking_sch_init = eid_reserved1, | eid_blocking_sch_init = eid_reserved1, | |||
#endif | #endif | |||
eid_bad_tagged_msg_cast, | ||||
//! The last enumerator tracks the number of defined IDs. It must remai n the last one. | //! The last enumerator tracks the number of defined IDs. It must remai n the last one. | |||
/** When adding new IDs, place them immediately _before_ this comment ( that is | /** When adding new IDs, place them immediately _before_ this comment ( that is | |||
_after_ all the existing IDs. NEVER insert new IDs between the exis ting ones. **/ | _after_ all the existing IDs. NEVER insert new IDs between the exis ting ones. **/ | |||
eid_max | eid_max | |||
}; | }; | |||
//! Gathers all throw operators in one place. | //! Gathers all throw operators in one place. | |||
/** Its purpose is to minimize code bloat that can be caused by throw opera tors | /** Its purpose is to minimize code bloat that can be caused by throw opera tors | |||
scattered in multiple places, especially in templates. **/ | scattered in multiple places, especially in templates. **/ | |||
void __TBB_EXPORTED_FUNC throw_exception_v4 ( exception_id ); | void __TBB_EXPORTED_FUNC throw_exception_v4 ( exception_id ); | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 1 lines changed or added | |||
tbb_machine.h | tbb_machine.h | |||
---|---|---|---|---|
skipping to change at line 180 | skipping to change at line 180 | |||
template<> struct atomic_selector<8> { | template<> struct atomic_selector<8> { | |||
typedef int64_t word; | typedef int64_t word; | |||
inline static word fetch_store ( volatile void* location, word value ); | inline static word fetch_store ( volatile void* location, word value ); | |||
}; | }; | |||
}} //< namespaces internal @endcond, tbb | }} //< namespaces internal @endcond, tbb | |||
#define __TBB_MACHINE_DEFINE_STORE8_GENERIC_FENCED(M) \ | #define __TBB_MACHINE_DEFINE_STORE8_GENERIC_FENCED(M) \ | |||
inline void __TBB_machine_generic_store8##M(volatile void *ptr, int64_t value) { \ | inline void __TBB_machine_generic_store8##M(volatile void *ptr, int64_t value) { \ | |||
for(;;) { \ | for(;;) { \ | |||
int64_t result = *(volatile int64_t *)ptr; \ | int64_t result = *(volatile int64_t *)ptr; \ | |||
if( __TBB_machine_cmpswp8##M(ptr,value,result)==result ) break; \ | if( __TBB_machine_cmpswp8##M(ptr,value,result)==result ) break; \ | |||
} \ | } \ | |||
} \ | } \ | |||
#define __TBB_MACHINE_DEFINE_LOAD8_GENERIC_FENCED(M) \ | #define __TBB_MACHINE_DEFINE_LOAD8_GENERIC_FENCED(M) \ | |||
inline int64_t __TBB_machine_generic_load8##M(const volatile void *ptr) { \ | inline int64_t __TBB_machine_generic_load8##M(const volatile void *ptr) { \ | |||
/* Comparand and new value may be anything, they only must be equal , and */ \ | /* Comparand and new value may be anything, they only must be equal , and */ \ | |||
/* the value should have a low probability to be actually found in 'location'.*/ \ | /* the value should have a low probability to be actually found in 'location'.*/ \ | |||
const int64_t anyvalue = 2305843009213693951LL; \ | const int64_t anyvalue = 2305843009213693951LL; \ | |||
return __TBB_machine_cmpswp8##M(const_cast<volatile void *>(ptr),an yvalue,anyvalue); \ | return __TBB_machine_cmpswp8##M(const_cast<volatile void *>(ptr),an yvalue,anyvalue); \ | |||
skipping to change at line 415 | skipping to change at line 415 | |||
} | } | |||
//! Spin UNTIL the value of the variable is equal to a given value | //! Spin UNTIL the value of the variable is equal to a given value | |||
/** T and U should be comparable types. */ | /** T and U should be comparable types. */ | |||
template<typename T, typename U> | template<typename T, typename U> | |||
void spin_wait_until_eq( const volatile T& location, const U value ) { | void spin_wait_until_eq( const volatile T& location, const U value ) { | |||
atomic_backoff backoff; | atomic_backoff backoff; | |||
while( location!=value ) backoff.pause(); | while( location!=value ) backoff.pause(); | |||
} | } | |||
template <typename predicate_type> | ||||
void spin_wait_while(predicate_type condition){ | ||||
atomic_backoff backoff; | ||||
while( condition() ) backoff.pause(); | ||||
} | ||||
/////////////////////////////////////////////////////////////////////////// ///// | /////////////////////////////////////////////////////////////////////////// ///// | |||
// Generic compare-and-swap applied to only a part of a machine word. | // Generic compare-and-swap applied to only a part of a machine word. | |||
// | // | |||
#ifndef __TBB_ENDIANNESS | #ifndef __TBB_ENDIANNESS | |||
#define __TBB_ENDIANNESS __TBB_ENDIAN_DETECT | #define __TBB_ENDIANNESS __TBB_ENDIAN_DETECT | |||
#endif | #endif | |||
#if __TBB_USE_GENERIC_PART_WORD_CAS && __TBB_ENDIANNESS==__TBB_ENDIAN_UNSUP PORTED | #if __TBB_USE_GENERIC_PART_WORD_CAS && __TBB_ENDIANNESS==__TBB_ENDIAN_UNSUP PORTED | |||
#error Generic implementation of part-word CAS may not be used with __TBB_E NDIAN_UNSUPPORTED | #error Generic implementation of part-word CAS may not be used with __TBB_E NDIAN_UNSUPPORTED | |||
#endif | #endif | |||
End of changes. 2 change blocks. | ||||
1 lines changed or deleted | 7 lines changed or added | |||
tbb_profiling.h | tbb_profiling.h | |||
---|---|---|---|---|
skipping to change at line 220 | skipping to change at line 220 | |||
__TBB_ASSERT(sizeof(T) == sizeof(void *), "Type must be word-si zed"); | __TBB_ASSERT(sizeof(T) == sizeof(void *), "Type must be word-si zed"); | |||
return (T)itt_load_pointer_with_acquire_v3(&src); | return (T)itt_load_pointer_with_acquire_v3(&src); | |||
#else | #else | |||
return __TBB_load_with_acquire(src); | return __TBB_load_with_acquire(src); | |||
#endif // TBB_USE_THREADING_TOOLS | #endif // TBB_USE_THREADING_TOOLS | |||
} | } | |||
template <typename T> | template <typename T> | |||
inline void itt_hide_store_word(T& dst, T src) { | inline void itt_hide_store_word(T& dst, T src) { | |||
#if TBB_USE_THREADING_TOOLS | #if TBB_USE_THREADING_TOOLS | |||
// This assertion should be replaced with static_assert | //TODO: This assertion should be replaced with static_assert | |||
__TBB_ASSERT(sizeof(T) == sizeof(void *), "Type must be word-si zed"); | __TBB_ASSERT(sizeof(T) == sizeof(void *), "Type must be word-si zed"); | |||
itt_store_pointer_with_release_v3(&dst, (void *)src); | itt_store_pointer_with_release_v3(&dst, (void *)src); | |||
#else | #else | |||
dst = src; | dst = src; | |||
#endif | #endif | |||
} | } | |||
//TODO: rename to itt_hide_load_word_relaxed | ||||
template <typename T> | template <typename T> | |||
inline T itt_hide_load_word(const T& src) { | inline T itt_hide_load_word(const T& src) { | |||
#if TBB_USE_THREADING_TOOLS | #if TBB_USE_THREADING_TOOLS | |||
// This assertion should be replaced with static_assert | //TODO: This assertion should be replaced with static_assert | |||
__TBB_ASSERT(sizeof(T) == sizeof(void *), "Type must be word-si zed."); | __TBB_ASSERT(sizeof(T) == sizeof(void *), "Type must be word-si zed."); | |||
return (T)itt_load_pointer_v3(&src); | return (T)itt_load_pointer_v3(&src); | |||
#else | #else | |||
return src; | return src; | |||
#endif | #endif | |||
} | } | |||
#if TBB_USE_THREADING_TOOLS | #if TBB_USE_THREADING_TOOLS | |||
inline void call_itt_notify(notify_type t, void *ptr) { | inline void call_itt_notify(notify_type t, void *ptr) { | |||
call_itt_notify_v5((int)t, ptr); | call_itt_notify_v5((int)t, ptr); | |||
End of changes. 3 change blocks. | ||||
2 lines changed or deleted | 3 lines changed or added | |||
tbb_stddef.h | tbb_stddef.h | |||
---|---|---|---|---|
skipping to change at line 37 | skipping to change at line 37 | |||
*/ | */ | |||
#ifndef __TBB_tbb_stddef_H | #ifndef __TBB_tbb_stddef_H | |||
#define __TBB_tbb_stddef_H | #define __TBB_tbb_stddef_H | |||
// Marketing-driven product version | // Marketing-driven product version | |||
#define TBB_VERSION_MAJOR 4 | #define TBB_VERSION_MAJOR 4 | |||
#define TBB_VERSION_MINOR 2 | #define TBB_VERSION_MINOR 2 | |||
// Engineering-focused interface version | // Engineering-focused interface version | |||
#define TBB_INTERFACE_VERSION 7003 | #define TBB_INTERFACE_VERSION 7004 | |||
#define TBB_INTERFACE_VERSION_MAJOR TBB_INTERFACE_VERSION/1000 | #define TBB_INTERFACE_VERSION_MAJOR TBB_INTERFACE_VERSION/1000 | |||
// The oldest major interface version still supported | // The oldest major interface version still supported | |||
// To be used in SONAME, manifests, etc. | // To be used in SONAME, manifests, etc. | |||
#define TBB_COMPATIBLE_INTERFACE_VERSION 2 | #define TBB_COMPATIBLE_INTERFACE_VERSION 2 | |||
#define __TBB_STRING_AUX(x) #x | #define __TBB_STRING_AUX(x) #x | |||
#define __TBB_STRING(x) __TBB_STRING_AUX(x) | #define __TBB_STRING(x) __TBB_STRING_AUX(x) | |||
// We do not need defines below for resource processing on windows | // We do not need defines below for resource processing on windows | |||
skipping to change at line 121 | skipping to change at line 121 | |||
#endif | #endif | |||
#if __INTEL_COMPILER || _MSC_VER | #if __INTEL_COMPILER || _MSC_VER | |||
#define __TBB_NOINLINE(decl) __declspec(noinline) decl | #define __TBB_NOINLINE(decl) __declspec(noinline) decl | |||
#elif __GNUC__ | #elif __GNUC__ | |||
#define __TBB_NOINLINE(decl) decl __attribute__ ((noinline)) | #define __TBB_NOINLINE(decl) decl __attribute__ ((noinline)) | |||
#else | #else | |||
#define __TBB_NOINLINE(decl) decl | #define __TBB_NOINLINE(decl) decl | |||
#endif | #endif | |||
#if __TBB_NOEXCEPT_PRESENT | ||||
#define __TBB_NOEXCEPT(expression) noexcept(expression) | ||||
#else | ||||
#define __TBB_NOEXCEPT(expression) | ||||
#endif | ||||
#include <cstddef> /* Need size_t and ptrdiff_t */ | #include <cstddef> /* Need size_t and ptrdiff_t */ | |||
#if _MSC_VER | #if _MSC_VER | |||
#define __TBB_tbb_windef_H | #define __TBB_tbb_windef_H | |||
#include "internal/_tbb_windef.h" | #include "internal/_tbb_windef.h" | |||
#undef __TBB_tbb_windef_H | #undef __TBB_tbb_windef_H | |||
#endif | #endif | |||
#if !defined(_MSC_VER) || _MSC_VER>=1600 | #if !defined(_MSC_VER) || _MSC_VER>=1600 | |||
#include <stdint.h> | #include <stdint.h> | |||
#endif | #endif | |||
skipping to change at line 220 | skipping to change at line 226 | |||
extern "C" int __TBB_EXPORTED_FUNC TBB_runtime_interface_version(); | extern "C" int __TBB_EXPORTED_FUNC TBB_runtime_interface_version(); | |||
//! Dummy type that distinguishes splitting constructor from copy construct or. | //! Dummy type that distinguishes splitting constructor from copy construct or. | |||
/** | /** | |||
* See description of parallel_for and parallel_reduce for example usages. | * See description of parallel_for and parallel_reduce for example usages. | |||
* @ingroup algorithms | * @ingroup algorithms | |||
*/ | */ | |||
class split { | class split { | |||
}; | }; | |||
//! Type enables transmission of splitting proportion from partitioners to | ||||
range objects | ||||
/** | ||||
* In order to make use of such facility Range objects must implement | ||||
* splitting constructor with this type passed and initialize static | ||||
* constant boolean field 'is_divisible_in_proportion' with the value | ||||
* of 'true' | ||||
*/ | ||||
class proportional_split { | ||||
public: | ||||
proportional_split(size_t _left = 1, size_t _right = 1) : my_left(_left | ||||
), my_right(_right) { } | ||||
proportional_split(split) : my_left(1), my_right(1) { } | ||||
size_t left() const { return my_left; } | ||||
size_t right() const { return my_right; } | ||||
void set_proportion(size_t _left, size_t _right) { | ||||
my_left = _left; | ||||
my_right = _right; | ||||
} | ||||
// used when range does not support proportional split | ||||
operator split() const { return split(); } | ||||
private: | ||||
size_t my_left, my_right; | ||||
}; | ||||
/** | /** | |||
* @cond INTERNAL | * @cond INTERNAL | |||
* @brief Identifiers declared inside namespace internal should never be us ed directly by client code. | * @brief Identifiers declared inside namespace internal should never be us ed directly by client code. | |||
*/ | */ | |||
namespace internal { | namespace internal { | |||
//! Compile-time constant that is upper bound on cache line/sector size. | //! Compile-time constant that is upper bound on cache line/sector size. | |||
/** It should be used only in situations where having a compile-time upper | /** It should be used only in situations where having a compile-time upper | |||
bound is more useful than a run-time exact answer. | bound is more useful than a run-time exact answer. | |||
@ingroup memory_allocation */ | @ingroup memory_allocation */ | |||
skipping to change at line 253 | skipping to change at line 285 | |||
Note however that, with some architecture/compiler combinations, e.g. o n IA-64 architecture, "volatile" | Note however that, with some architecture/compiler combinations, e.g. o n IA-64 architecture, "volatile" | |||
also has non-portable memory semantics that are needlessly expensive fo r "relaxed" operations. | also has non-portable memory semantics that are needlessly expensive fo r "relaxed" operations. | |||
Note that this must only be applied to data that will not change bit pa tterns when cast to/from | Note that this must only be applied to data that will not change bit pa tterns when cast to/from | |||
an integral type of the same length; tbb::atomic must be used instead f or, e.g., floating-point types. | an integral type of the same length; tbb::atomic must be used instead f or, e.g., floating-point types. | |||
TODO: apply wherever relevant **/ | TODO: apply wherever relevant **/ | |||
#define __TBB_atomic // intentionally empty, see above | #define __TBB_atomic // intentionally empty, see above | |||
template<class T, int S> | template<class T, size_t S, size_t R> | |||
struct padded_base : T { | struct padded_base : T { | |||
char pad[NFS_MaxLineSize - sizeof(T) % NFS_MaxLineSize]; | char pad[S - R]; | |||
}; | }; | |||
template<class T> struct padded_base<T, 0> : T {}; | template<class T, size_t S> struct padded_base<T, S, 0> : T {}; | |||
//! Pads type T to fill out to a multiple of cache line size. | //! Pads type T to fill out to a multiple of cache line size. | |||
template<class T> | template<class T, size_t S = NFS_MaxLineSize> | |||
struct padded : padded_base<T, sizeof(T)> {}; | struct padded : padded_base<T, S, sizeof(T) % S> {}; | |||
//! Extended variant of the standard offsetof macro | //! Extended variant of the standard offsetof macro | |||
/** The standard offsetof macro is not sufficient for TBB as it can be used for | /** The standard offsetof macro is not sufficient for TBB as it can be used for | |||
POD-types only. The constant 0x1000 (not NULL) is necessary to appease GCC. **/ | POD-types only. The constant 0x1000 (not NULL) is necessary to appease GCC. **/ | |||
#define __TBB_offsetof(class_name, member_name) \ | #define __TBB_offsetof(class_name, member_name) \ | |||
((ptrdiff_t)&(reinterpret_cast<class_name*>(0x1000)->member_name) - 0x1 000) | ((ptrdiff_t)&(reinterpret_cast<class_name*>(0x1000)->member_name) - 0x1 000) | |||
//! Returns address of the object containing a member with the given name a nd address | //! Returns address of the object containing a member with the given name a nd address | |||
#define __TBB_get_object_ref(class_name, member_name, member_addr) \ | #define __TBB_get_object_ref(class_name, member_name, member_addr) \ | |||
(*reinterpret_cast<class_name*>((char*)member_addr - __TBB_offsetof(cla ss_name, member_name))) | (*reinterpret_cast<class_name*>((char*)member_addr - __TBB_offsetof(cla ss_name, member_name))) | |||
End of changes. 7 change blocks. | ||||
6 lines changed or deleted | 40 lines changed or added | |||