_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), &copy_array); internal_copy(vector, sizeof(T), &copy_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), &copy_a rray); internal_copy(vector.internal_vector_base(), sizeof(T), &copy_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, &copy_array); internal_assign(vector, sizeof(T), &destroy_array, &assign_arra y, &copy_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), &copy_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

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/