| _concurrent_unordered_impl.h | | _concurrent_unordered_impl.h | |
| | | | |
| skipping to change at line 259 | | skipping to change at line 259 | |
| // in the hash table to quickly index into the right subsection of
the split-ordered list. | | // in the hash table to quickly index into the right subsection of
the split-ordered list. | |
| bool is_dummy() const { | | bool is_dummy() const { | |
| return (my_order_key & 0x1) == 0; | | return (my_order_key & 0x1) == 0; | |
| } | | } | |
| | | | |
| nodeptr_t my_next; // Next element in the list | | nodeptr_t my_next; // Next element in the list | |
| value_type my_element; // Element storage | | value_type my_element; // Element storage | |
| sokey_t my_order_key; // Order key for this element | | sokey_t my_order_key; // Order key for this element | |
| }; | | }; | |
| | | | |
|
| | | // Allocate a new node with the given order key; used to allocate dummy | |
| | | nodes | |
| | | nodeptr_t create_node(sokey_t order_key) { | |
| | | nodeptr_t pnode = my_node_allocator.allocate(1); | |
| | | pnode->init(order_key); | |
| | | return (pnode); | |
| | | } | |
| | | | |
| // Allocate a new node with the given order key and value | | // Allocate a new node with the given order key and value | |
|
| nodeptr_t create_node(sokey_t order_key, const T &value) { | | template<typename Arg> | |
| | | nodeptr_t create_node(sokey_t order_key, __TBB_FORWARDING_REF(Arg) t){ | |
| nodeptr_t pnode = my_node_allocator.allocate(1); | | nodeptr_t pnode = my_node_allocator.allocate(1); | |
| | | | |
|
| | | //TODO: use RAII scoped guard instead of explicit catch | |
| __TBB_TRY { | | __TBB_TRY { | |
|
| new(static_cast<void*>(&pnode->my_element)) T(value); | | new(static_cast<void*>(&pnode->my_element)) T(tbb::internal::fo
rward<Arg>(t)); | |
| pnode->init(order_key); | | pnode->init(order_key); | |
| } __TBB_CATCH(...) { | | } __TBB_CATCH(...) { | |
| my_node_allocator.deallocate(pnode, 1); | | my_node_allocator.deallocate(pnode, 1); | |
| __TBB_RETHROW(); | | __TBB_RETHROW(); | |
| } | | } | |
| | | | |
| return (pnode); | | return (pnode); | |
| } | | } | |
| | | | |
|
| #if __TBB_CPP11_RVALUE_REF_PRESENT | | // Allocate a new node with the given parameters for constructing value | |
| //TODO: try to combine both implementations using poor man forward | | template<typename __TBB_PARAMETER_PACK Args> | |
| //TODO: use RAII scoped guard instead of explicit catch | | nodeptr_t create_node_v( __TBB_FORWARDING_REF(Args) __TBB_PARAMETER_PAC | |
| // Allocate a new node with the given order key and value | | K args){ | |
| nodeptr_t create_node(sokey_t order_key, T &&value) { | | | |
| nodeptr_t pnode = my_node_allocator.allocate(1); | | nodeptr_t pnode = my_node_allocator.allocate(1); | |
| | | | |
|
| | | //TODO: use RAII scoped guard instead of explicit catch | |
| __TBB_TRY { | | __TBB_TRY { | |
|
| new(static_cast<void*>(&pnode->my_element)) T(std::move(value)) | | new(static_cast<void*>(&pnode->my_element)) T(__TBB_PACK_EXPANS | |
| ; | | ION(tbb::internal::forward<Args>(args))); | |
| pnode->init(order_key); | | | |
| } __TBB_CATCH(...) { | | } __TBB_CATCH(...) { | |
| my_node_allocator.deallocate(pnode, 1); | | my_node_allocator.deallocate(pnode, 1); | |
| __TBB_RETHROW(); | | __TBB_RETHROW(); | |
| } | | } | |
| | | | |
| return (pnode); | | return (pnode); | |
| } | | } | |
|
| #endif //__TBB_CPP11_RVALUE_REF_PRESENT | | | |
| | | | |
| // Allocate a new node with the given order key; used to allocate dummy | | | |
| nodes | | | |
| nodeptr_t create_node(sokey_t order_key) { | | | |
| nodeptr_t pnode = my_node_allocator.allocate(1); | | | |
| pnode->init(order_key); | | | |
| return (pnode); | | | |
| } | | | |
| | | | |
| split_ordered_list(allocator_type a = allocator_type()) | | split_ordered_list(allocator_type a = allocator_type()) | |
| : my_node_allocator(a), my_element_count(0) | | : my_node_allocator(a), my_element_count(0) | |
| { | | { | |
| // Immediately allocate a dummy node with order key of 0. This node | | // Immediately allocate a dummy node with order key of 0. This node | |
| // will always be the head of the list. | | // will always be the head of the list. | |
|
| my_head = create_node(0); | | my_head = create_node(sokey_t(0)); | |
| } | | } | |
| | | | |
| ~split_ordered_list() | | ~split_ordered_list() | |
| { | | { | |
| // Clear the list | | // Clear the list | |
| clear(); | | clear(); | |
| | | | |
| // Remove the head element which is not cleared by clear() | | // Remove the head element which is not cleared by clear() | |
| nodeptr_t pnode = my_head; | | nodeptr_t pnode = my_head; | |
| my_head = NULL; | | my_head = NULL; | |
| | | | |
| skipping to change at line 482 | | skipping to change at line 481 | |
| | | | |
| return const_iterator(it.get_node_ptr(), this); | | return const_iterator(it.get_node_ptr(), this); | |
| } | | } | |
| | | | |
| // Erase an element using the allocator | | // Erase an element using the allocator | |
| void destroy_node(nodeptr_t pnode) { | | void destroy_node(nodeptr_t pnode) { | |
| if (!pnode->is_dummy()) my_node_allocator.destroy(pnode); | | if (!pnode->is_dummy()) my_node_allocator.destroy(pnode); | |
| my_node_allocator.deallocate(pnode, 1); | | my_node_allocator.deallocate(pnode, 1); | |
| } | | } | |
| | | | |
|
| // Try to insert a new element in the list. If insert fails, return the | | // Try to insert a new element in the list. | |
| node that | | // If insert fails, return the node that was inserted instead. | |
| // was inserted instead. | | static nodeptr_t try_insert_atomic(nodeptr_t previous, nodeptr_t new_no | |
| nodeptr_t try_insert(nodeptr_t previous, nodeptr_t new_node, nodeptr_t | | de, nodeptr_t current_node) { | |
| current_node) { | | | |
| new_node->my_next = current_node; | | new_node->my_next = current_node; | |
| return previous->atomic_set_next(new_node, current_node); | | return previous->atomic_set_next(new_node, current_node); | |
| } | | } | |
| | | | |
| // Insert a new element between passed in iterators | | // Insert a new element between passed in iterators | |
|
| std::pair<iterator, bool> try_insert(raw_iterator it, raw_iterator next
, const value_type &value, sokey_t order_key, size_type *new_count) | | std::pair<iterator, bool> try_insert(raw_iterator it, raw_iterator next
, nodeptr_t pnode, size_type *new_count) | |
| { | | { | |
|
| nodeptr_t pnode = create_node(order_key, value); | | nodeptr_t inserted_node = try_insert_atomic(it.get_node_ptr(), pnod | |
| nodeptr_t inserted_node = try_insert(it.get_node_ptr(), pnode, next | | e, next.get_node_ptr()); | |
| .get_node_ptr()); | | | |
| | | | |
| if (inserted_node == pnode) | | if (inserted_node == pnode) | |
| { | | { | |
| // If the insert succeeded, check that the order is correct and
increment the element count | | // If the insert succeeded, check that the order is correct and
increment the element count | |
| check_range(it, next); | | check_range(it, next); | |
|
| *new_count = __TBB_FetchAndAddW((uintptr_t*)&my_element_count,
uintptr_t(1)); | | *new_count = tbb::internal::as_atomic(my_element_count).fetch_a
nd_increment(); | |
| return std::pair<iterator, bool>(iterator(pnode, this), true); | | return std::pair<iterator, bool>(iterator(pnode, this), true); | |
| } | | } | |
| else | | else | |
| { | | { | |
|
| // If the insert failed (element already there), then delete th | | | |
| e new one | | | |
| destroy_node(pnode); | | | |
| return std::pair<iterator, bool>(end(), false); | | return std::pair<iterator, bool>(end(), false); | |
| } | | } | |
| } | | } | |
| | | | |
| // Insert a new dummy element, starting search at a parent dummy elemen
t | | // Insert a new dummy element, starting search at a parent dummy elemen
t | |
| raw_iterator insert_dummy(raw_iterator it, sokey_t order_key) | | raw_iterator insert_dummy(raw_iterator it, sokey_t order_key) | |
| { | | { | |
| raw_iterator last = raw_end(); | | raw_iterator last = raw_end(); | |
| raw_iterator where = it; | | raw_iterator where = it; | |
| | | | |
| | | | |
| skipping to change at line 534 | | skipping to change at line 530 | |
| { | | { | |
| __TBB_ASSERT(it != last, "Invalid head list node"); | | __TBB_ASSERT(it != last, "Invalid head list node"); | |
| | | | |
| // If the head iterator is at the end of the list, or past the
point where this dummy | | // If the head iterator is at the end of the list, or past the
point where this dummy | |
| // node needs to be inserted, then try to insert it. | | // node needs to be inserted, then try to insert it. | |
| if (where == last || get_order_key(where) > order_key) | | if (where == last || get_order_key(where) > order_key) | |
| { | | { | |
| __TBB_ASSERT(get_order_key(it) < order_key, "Invalid node o
rder in the list"); | | __TBB_ASSERT(get_order_key(it) < order_key, "Invalid node o
rder in the list"); | |
| | | | |
| // Try to insert it in the right place | | // Try to insert it in the right place | |
|
| nodeptr_t inserted_node = try_insert(it.get_node_ptr(), dum
my_node, where.get_node_ptr()); | | nodeptr_t inserted_node = try_insert_atomic(it.get_node_ptr
(), dummy_node, where.get_node_ptr()); | |
| | | | |
| if (inserted_node == dummy_node) | | if (inserted_node == dummy_node) | |
| { | | { | |
| // Insertion succeeded, check the list for order violat
ions | | // Insertion succeeded, check the list for order violat
ions | |
| check_range(it, where); | | check_range(it, where); | |
| return raw_iterator(dummy_node); | | return raw_iterator(dummy_node); | |
| } | | } | |
| else | | else | |
| { | | { | |
| // Insertion failed: either dummy node was inserted by
another thread, or | | // Insertion failed: either dummy node was inserted by
another thread, or | |
| | | | |
| skipping to change at line 607 | | skipping to change at line 603 | |
| | | | |
| nodeptr_t previous_node = my_head; | | nodeptr_t previous_node = my_head; | |
| raw_const_iterator begin_iterator = first++; | | raw_const_iterator begin_iterator = first++; | |
| | | | |
| // Move all elements one by one, including dummy ones | | // Move all elements one by one, including dummy ones | |
| for (raw_const_iterator it = first; it != last;) | | for (raw_const_iterator it = first; it != last;) | |
| { | | { | |
| nodeptr_t pnode = it.get_node_ptr(); | | nodeptr_t pnode = it.get_node_ptr(); | |
| | | | |
| nodeptr_t dummy_node = pnode->is_dummy() ? create_node(pnode->g
et_order_key()) : create_node(pnode->get_order_key(), pnode->my_element); | | nodeptr_t dummy_node = pnode->is_dummy() ? create_node(pnode->g
et_order_key()) : create_node(pnode->get_order_key(), pnode->my_element); | |
|
| previous_node = try_insert(previous_node, dummy_node, NULL); | | previous_node = try_insert_atomic(previous_node, dummy_node, NU
LL); | |
| __TBB_ASSERT(previous_node != NULL, "Insertion must succeed"); | | __TBB_ASSERT(previous_node != NULL, "Insertion must succeed"); | |
| raw_const_iterator where = it++; | | raw_const_iterator where = it++; | |
| source.erase_node(get_iterator(begin_iterator), where); | | source.erase_node(get_iterator(begin_iterator), where); | |
| } | | } | |
| check_range(); | | check_range(); | |
| } | | } | |
| | | | |
| private: | | private: | |
| //Need to setup private fields of split_ordered_list in move constructo
r and assignment of concurrent_unordered_base | | //Need to setup private fields of split_ordered_list in move constructo
r and assignment of concurrent_unordered_base | |
| template <typename Traits> | | template <typename Traits> | |
| | | | |
| skipping to change at line 792 | | skipping to change at line 788 | |
| const nodeptr_t pnode = it.get_node_ptr(); | | const nodeptr_t pnode = it.get_node_ptr(); | |
| nodeptr_t node; | | nodeptr_t node; | |
| if (pnode->is_dummy()) { | | if (pnode->is_dummy()) { | |
| node = my_solist.create_node(pnode->get_order_key()
); | | node = my_solist.create_node(pnode->get_order_key()
); | |
| size_type bucket = __TBB_ReverseBits(pnode->get_ord
er_key()) % my_number_of_buckets; | | size_type bucket = __TBB_ReverseBits(pnode->get_ord
er_key()) % my_number_of_buckets; | |
| set_bucket(bucket, node); | | set_bucket(bucket, node); | |
| }else{ | | }else{ | |
| node = my_solist.create_node(pnode->get_order_key()
, std::move(pnode->my_element)); | | node = my_solist.create_node(pnode->get_order_key()
, std::move(pnode->my_element)); | |
| } | | } | |
| | | | |
|
| previous_node = my_solist.try_insert(previous_node, nod
e, NULL); | | previous_node = my_solist.try_insert_atomic(previous_no
de, node, NULL); | |
| __TBB_ASSERT(previous_node != NULL, "Insertion of node
failed. Concurrent inserts in constructor ?"); | | __TBB_ASSERT(previous_node != NULL, "Insertion of node
failed. Concurrent inserts in constructor ?"); | |
| } | | } | |
| my_solist.check_range(); | | my_solist.check_range(); | |
| } | | } | |
| } | | } | |
| | | | |
| clear_buckets_on_exception.dismiss(); | | clear_buckets_on_exception.dismiss(); | |
| } | | } | |
| | | | |
|
| #endif //__TBB_CPP11_RVALUE_REF_PRESENT | | #endif // __TBB_CPP11_RVALUE_REF_PRESENT | |
| | | | |
| concurrent_unordered_base& operator=(const concurrent_unordered_base& r
ight) { | | concurrent_unordered_base& operator=(const concurrent_unordered_base& r
ight) { | |
| if (this != &right) | | if (this != &right) | |
| internal_copy(right); | | internal_copy(right); | |
| return (*this); | | return (*this); | |
| } | | } | |
| | | | |
| #if __TBB_CPP11_RVALUE_REF_PRESENT | | #if __TBB_CPP11_RVALUE_REF_PRESENT | |
| concurrent_unordered_base& operator=(concurrent_unordered_base&& other) | | concurrent_unordered_base& operator=(concurrent_unordered_base&& other) | |
| { | | { | |
| | | | |
| skipping to change at line 832 | | skipping to change at line 828 | |
| swap(this->my_allocator, other.my_allocator); | | swap(this->my_allocator, other.my_allocator); | |
| } | | } | |
| } else { | | } else { | |
| concurrent_unordered_base moved_copy(std::move(other),this-
>my_allocator); | | concurrent_unordered_base moved_copy(std::move(other),this-
>my_allocator); | |
| this->swap(moved_copy); | | this->swap(moved_copy); | |
| } | | } | |
| } | | } | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
|
| #endif //__TBB_CPP11_RVALUE_REF_PRESENT | | #endif // __TBB_CPP11_RVALUE_REF_PRESENT | |
| | | | |
| #if __TBB_INITIALIZER_LISTS_PRESENT | | #if __TBB_INITIALIZER_LISTS_PRESENT | |
| //! assignment operator from initializer_list | | //! assignment operator from initializer_list | |
| concurrent_unordered_base& operator=(std::initializer_list<value_type>
il) | | concurrent_unordered_base& operator=(std::initializer_list<value_type>
il) | |
| { | | { | |
| this->clear(); | | this->clear(); | |
| this->insert(il.begin(),il.end()); | | this->insert(il.begin(),il.end()); | |
| return (*this); | | return (*this); | |
| } | | } | |
|
| #endif //# __TBB_INITIALIZER_LISTS_PRESENT | | #endif // __TBB_INITIALIZER_LISTS_PRESENT | |
| | | | |
| ~concurrent_unordered_base() { | | ~concurrent_unordered_base() { | |
| // Delete all node segments | | // Delete all node segments | |
| internal_clear(); | | internal_clear(); | |
| } | | } | |
| | | | |
| public: | | public: | |
| allocator_type get_allocator() const { | | allocator_type get_allocator() const { | |
| return my_solist.get_allocator(); | | return my_solist.get_allocator(); | |
| } | | } | |
| | | | |
| skipping to change at line 993 | | skipping to change at line 989 | |
| // Modifiers | | // Modifiers | |
| std::pair<iterator, bool> insert(const value_type& value) { | | std::pair<iterator, bool> insert(const value_type& value) { | |
| return internal_insert(value); | | return internal_insert(value); | |
| } | | } | |
| | | | |
| iterator insert(const_iterator, const value_type& value) { | | iterator insert(const_iterator, const value_type& value) { | |
| // Ignore hint | | // Ignore hint | |
| return insert(value).first; | | return insert(value).first; | |
| } | | } | |
| | | | |
|
| | | #if __TBB_CPP11_RVALUE_REF_PRESENT | |
| | | std::pair<iterator, bool> insert(value_type&& value) { | |
| | | return internal_insert(std::move(value)); | |
| | | } | |
| | | | |
| | | iterator insert(const_iterator, value_type&& value) { | |
| | | // Ignore hint | |
| | | return insert(std::move(value)).first; | |
| | | } | |
| | | | |
| | | #if __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT | |
| | | template<typename... Args> | |
| | | std::pair<iterator, bool> emplace(Args&&... args) { | |
| | | nodeptr_t pnode = my_solist.create_node_v(tbb::internal::forward<Ar | |
| | | gs>(args)...); | |
| | | const sokey_t hashed_element_key = (sokey_t) my_hash_compare(get_ke | |
| | | y(pnode->my_element)); | |
| | | const sokey_t order_key = split_order_key_regular(hashed_element_ke | |
| | | y); | |
| | | pnode->init(order_key); | |
| | | | |
| | | return internal_insert(pnode->my_element, pnode); | |
| | | } | |
| | | | |
| | | template<typename... Args> | |
| | | iterator emplace_hint(const_iterator, Args&&... args) { | |
| | | // Ignore hint | |
| | | return emplace(tbb::internal::forward<Args>(args)...).first; | |
| | | } | |
| | | | |
| | | #endif // __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT | |
| | | #endif // __TBB_CPP11_RVALUE_REF_PRESENT | |
| | | | |
| template<class Iterator> | | template<class Iterator> | |
| void insert(Iterator first, Iterator last) { | | void insert(Iterator first, Iterator last) { | |
| for (Iterator it = first; it != last; ++it) | | for (Iterator it = first; it != last; ++it) | |
| insert(*it); | | insert(*it); | |
| } | | } | |
| | | | |
| #if __TBB_INITIALIZER_LISTS_PRESENT | | #if __TBB_INITIALIZER_LISTS_PRESENT | |
| //! Insert initializer list | | //! Insert initializer list | |
| void insert(std::initializer_list<value_type> il) { | | void insert(std::initializer_list<value_type> il) { | |
| insert(il.begin(), il.end()); | | insert(il.begin(), il.end()); | |
| | | | |
| skipping to change at line 1246 | | skipping to change at line 1272 | |
| for (size_type index = 0; index < pointers_per_table; ++index) | | for (size_type index = 0; index < pointers_per_table; ++index) | |
| { | | { | |
| raw_iterator * iterator_pointer = my_buckets[index]; | | raw_iterator * iterator_pointer = my_buckets[index]; | |
| my_buckets[index] = right.my_buckets[index]; | | my_buckets[index] = right.my_buckets[index]; | |
| right.my_buckets[index] = iterator_pointer; | | right.my_buckets[index] = iterator_pointer; | |
| } | | } | |
| } | | } | |
| | | | |
| //TODO: why not use std::distance? | | //TODO: why not use std::distance? | |
| // Hash APIs | | // Hash APIs | |
|
| size_type internal_distance(const_iterator first, const_iterator last)
const | | static size_type internal_distance(const_iterator first, const_iterator
last) | |
| { | | { | |
| size_type num = 0; | | size_type num = 0; | |
| | | | |
| for (const_iterator it = first; it != last; ++it) | | for (const_iterator it = first; it != last; ++it) | |
| ++num; | | ++num; | |
| | | | |
| return num; | | return num; | |
| } | | } | |
| | | | |
| // Insert an element in the hash given its value | | // Insert an element in the hash given its value | |
|
| std::pair<iterator, bool> internal_insert(const value_type& value) | | template< typename ValueType> | |
| | | std::pair<iterator, bool> internal_insert( __TBB_FORWARDING_REF(ValueTy | |
| | | pe) value, nodeptr_t pnode = NULL) | |
| { | | { | |
| sokey_t order_key = (sokey_t) my_hash_compare(get_key(value)); | | sokey_t order_key = (sokey_t) my_hash_compare(get_key(value)); | |
| size_type bucket = order_key % my_number_of_buckets; | | size_type bucket = order_key % my_number_of_buckets; | |
| | | | |
|
| | | //TODO:refactor the get_bucket related staff into separate function
something like aqcuire_bucket(key_type) | |
| // If bucket is empty, initialize it first | | // If bucket is empty, initialize it first | |
| if (!is_initialized(bucket)) | | if (!is_initialized(bucket)) | |
| init_bucket(bucket); | | init_bucket(bucket); | |
| | | | |
| size_type new_count = 0; | | size_type new_count = 0; | |
| order_key = split_order_key_regular(order_key); | | order_key = split_order_key_regular(order_key); | |
| raw_iterator it = get_bucket(bucket); | | raw_iterator it = get_bucket(bucket); | |
| raw_iterator last = my_solist.raw_end(); | | raw_iterator last = my_solist.raw_end(); | |
| raw_iterator where = it; | | raw_iterator where = it; | |
| | | | |
| __TBB_ASSERT(where != last, "Invalid head node"); | | __TBB_ASSERT(where != last, "Invalid head node"); | |
| | | | |
| // First node is a dummy node | | // First node is a dummy node | |
| ++where; | | ++where; | |
| | | | |
| for (;;) | | for (;;) | |
| { | | { | |
| if (where == last || solist_t::get_order_key(where) > order_key
) | | if (where == last || solist_t::get_order_key(where) > order_key
) | |
| { | | { | |
|
| | | if (!pnode) | |
| | | pnode = my_solist.create_node(order_key, tbb::internal | |
| | | ::forward<ValueType>(value)); | |
| | | | |
| // Try to insert it in the right place | | // Try to insert it in the right place | |
|
| std::pair<iterator, bool> result = my_solist.try_insert(it,
where, value, order_key, &new_count); | | std::pair<iterator, bool> result = my_solist.try_insert(it,
where, pnode, &new_count); | |
| | | | |
| if (result.second) | | if (result.second) | |
| { | | { | |
| // Insertion succeeded, adjust the table size, if neede
d | | // Insertion succeeded, adjust the table size, if neede
d | |
| adjust_table_size(new_count, my_number_of_buckets); | | adjust_table_size(new_count, my_number_of_buckets); | |
| return result; | | return result; | |
| } | | } | |
| else | | else | |
| { | | { | |
| // Insertion failed: either the same node was inserted
by another thread, or | | // Insertion failed: either the same node was inserted
by another thread, or | |
| | | | |
| skipping to change at line 1304 | | skipping to change at line 1335 | |
| // Proceed with the search from the previous location w
here order key was | | // Proceed with the search from the previous location w
here order key was | |
| // known to be larger (note: this is legal only because
there is no safe | | // known to be larger (note: this is legal only because
there is no safe | |
| // concurrent erase operation supported). | | // concurrent erase operation supported). | |
| where = it; | | where = it; | |
| ++where; | | ++where; | |
| continue; | | continue; | |
| } | | } | |
| } | | } | |
| else if (!allow_multimapping && solist_t::get_order_key(where)
== order_key && my_hash_compare(get_key(*where), get_key(value)) == 0) | | else if (!allow_multimapping && solist_t::get_order_key(where)
== order_key && my_hash_compare(get_key(*where), get_key(value)) == 0) | |
| { | | { | |
|
| | | if (pnode) | |
| | | my_solist.destroy_node(pnode); | |
| // Element already in the list, return it | | // Element already in the list, return it | |
| return std::pair<iterator, bool>(my_solist.get_iterator(whe
re), false); | | return std::pair<iterator, bool>(my_solist.get_iterator(whe
re), false); | |
| } | | } | |
| | | | |
| // Move the iterator forward | | // Move the iterator forward | |
| it = where; | | it = where; | |
| ++where; | | ++where; | |
| } | | } | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 1351 | | skipping to change at line 1384 | |
| return my_solist.get_iterator(it); | | return my_solist.get_iterator(it); | |
| } | | } | |
| } | | } | |
| | | | |
| return end(); | | return end(); | |
| } | | } | |
| | | | |
| // Erase an element from the list. This is not a concurrency safe funct
ion. | | // Erase an element from the list. This is not a concurrency safe funct
ion. | |
| iterator internal_erase(const_iterator it) | | iterator internal_erase(const_iterator it) | |
| { | | { | |
|
| key_type key = get_key(*it); | | //const reference extends lifetime of possible temporary coming fro | |
| | | m get_key | |
| | | const key_type& key = get_key(*it); | |
| sokey_t order_key = (sokey_t) my_hash_compare(key); | | sokey_t order_key = (sokey_t) my_hash_compare(key); | |
| size_type bucket = order_key % my_number_of_buckets; | | size_type bucket = order_key % my_number_of_buckets; | |
| | | | |
| // If bucket is empty, initialize it first | | // If bucket is empty, initialize it first | |
| if (!is_initialized(bucket)) | | if (!is_initialized(bucket)) | |
| init_bucket(bucket); | | init_bucket(bucket); | |
| | | | |
| order_key = split_order_key_regular(order_key); | | order_key = split_order_key_regular(order_key); | |
| | | | |
| raw_iterator previous = get_bucket(bucket); | | raw_iterator previous = get_bucket(bucket); | |
| | | | |
| skipping to change at line 1568 | | skipping to change at line 1602 | |
| public: | | public: | |
| tbb_hash() {} | | tbb_hash() {} | |
| | | | |
| size_t operator()(const Key& key) const | | size_t operator()(const Key& key) const | |
| { | | { | |
| return tbb_hasher(key); | | return tbb_hasher(key); | |
| } | | } | |
| }; | | }; | |
| | | | |
| } // namespace tbb | | } // namespace tbb | |
|
| #endif// __TBB__concurrent_unordered_impl_H | | #endif // __TBB__concurrent_unordered_impl_H | |
| | | | |
End of changes. 29 change blocks. |
| 43 lines changed or deleted | | 82 lines changed or added | |
|
| _flow_graph_join_impl.h | | _flow_graph_join_impl.h | |
| | | | |
| skipping to change at line 204 | | skipping to change at line 204 | |
| } | | } | |
| }; | | }; | |
| | | | |
| //! The two-phase join port | | //! The two-phase join port | |
| template< typename T > | | template< typename T > | |
| class reserving_port : public receiver<T> { | | class reserving_port : public receiver<T> { | |
| public: | | public: | |
| typedef T input_type; | | typedef T input_type; | |
| typedef sender<T> predecessor_type; | | typedef sender<T> predecessor_type; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| typedef std::vector<predecessor_type *> predecessor_vector_type; | | typedef typename receiver<input_type>::predecessor_list_type predec
essor_list_type; | |
| #endif | | #endif | |
| private: | | private: | |
| // ----------- Aggregator ------------ | | // ----------- Aggregator ------------ | |
| enum op_type { reg_pred, rem_pred, res_item, rel_res, con_res | | enum op_type { reg_pred, rem_pred, res_item, rel_res, con_res | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| , add_blt_pred, del_blt_pred, blt_pred_cnt, blt_pred_cpy | | , add_blt_pred, del_blt_pred, blt_pred_cnt, blt_pred_cpy | |
| #endif | | #endif | |
| }; | | }; | |
| enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |
| typedef reserving_port<T> my_class; | | typedef reserving_port<T> my_class; | |
| | | | |
| class reserving_port_operation : public aggregated_operation<reserv
ing_port_operation> { | | class reserving_port_operation : public aggregated_operation<reserv
ing_port_operation> { | |
| public: | | public: | |
| char type; | | char type; | |
| union { | | union { | |
| T *my_arg; | | T *my_arg; | |
| predecessor_type *my_pred; | | predecessor_type *my_pred; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| size_t cnt_val; | | size_t cnt_val; | |
|
| predecessor_vector_type *pvec; | | predecessor_list_type *plist; | |
| #endif | | #endif | |
| }; | | }; | |
| reserving_port_operation(const T& e, op_type t) : | | reserving_port_operation(const T& e, op_type t) : | |
| type(char(t)), my_arg(const_cast<T*>(&e)) {} | | type(char(t)), my_arg(const_cast<T*>(&e)) {} | |
| reserving_port_operation(const predecessor_type &s, op_type t)
: type(char(t)), | | reserving_port_operation(const predecessor_type &s, op_type t)
: type(char(t)), | |
| my_pred(const_cast<predecessor_type *>(&s)) {} | | my_pred(const_cast<predecessor_type *>(&s)) {} | |
| reserving_port_operation(op_type t) : type(char(t)) {} | | reserving_port_operation(op_type t) : type(char(t)) {} | |
| }; | | }; | |
| | | | |
| typedef internal::aggregating_functor<my_class, reserving_port_oper
ation> my_handler; | | typedef internal::aggregating_functor<my_class, reserving_port_oper
ation> my_handler; | |
| | | | |
| skipping to change at line 296 | | skipping to change at line 296 | |
| break; | | break; | |
| case del_blt_pred: | | case del_blt_pred: | |
| my_predecessors.internal_delete_built_predecessor(*(cur
rent->my_pred)); | | my_predecessors.internal_delete_built_predecessor(*(cur
rent->my_pred)); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| case blt_pred_cnt: | | case blt_pred_cnt: | |
| current->cnt_val = my_predecessors.predecessor_count(); | | current->cnt_val = my_predecessors.predecessor_count(); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| case blt_pred_cpy: | | case blt_pred_cpy: | |
|
| my_predecessors.copy_predecessors(*(current->pvec)); | | my_predecessors.copy_predecessors(*(current->plist)); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | | #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| protected: | | protected: | |
| template< typename R, typename B > friend class run_and_put_task; | | template< typename R, typename B > friend class run_and_put_task; | |
| template<typename X, typename Y> friend class internal::broadcast_c
ache; | | template<typename X, typename Y> friend class internal::broadcast_c
ache; | |
| | | | |
| skipping to change at line 383 | | skipping to change at line 383 | |
| reserving_port_operation op_data(src, del_blt_pred); | | reserving_port_operation op_data(src, del_blt_pred); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| } | | } | |
| | | | |
| /*override*/size_t predecessor_count() { | | /*override*/size_t predecessor_count() { | |
| reserving_port_operation op_data(blt_pred_cnt); | | reserving_port_operation op_data(blt_pred_cnt); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| return op_data.cnt_val; | | return op_data.cnt_val; | |
| } | | } | |
| | | | |
|
| /*override*/void copy_predecessors(predecessor_vector_type &v) { | | /*override*/void copy_predecessors(predecessor_list_type &l) { | |
| reserving_port_operation op_data(blt_pred_cpy); | | reserving_port_operation op_data(blt_pred_cpy); | |
|
| op_data.pvec = &v; | | op_data.plist = &l; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| } | | } | |
| #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | | #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | |
| | | | |
| /*override*/void reset_receiver( __TBB_PFG_RESET_ARG(reset_flags f)
) { | | /*override*/void reset_receiver( __TBB_PFG_RESET_ARG(reset_flags f)
) { | |
| my_predecessors.reset(__TBB_PFG_RESET_ARG(f)); | | my_predecessors.reset(__TBB_PFG_RESET_ARG(f)); | |
| reserved = false; | | reserved = false; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| __TBB_ASSERT(!(f&rf_extract) || my_predecessors.empty(), "port
edges not removed"); | | __TBB_ASSERT(!(f&rf_extract) || my_predecessors.empty(), "port
edges not removed"); | |
| #endif | | #endif | |
| | | | |
| skipping to change at line 412 | | skipping to change at line 412 | |
| }; | | }; | |
| | | | |
| //! queueing join_port | | //! queueing join_port | |
| template<typename T> | | template<typename T> | |
| class queueing_port : public receiver<T>, public item_buffer<T> { | | class queueing_port : public receiver<T>, public item_buffer<T> { | |
| public: | | public: | |
| typedef T input_type; | | typedef T input_type; | |
| typedef sender<T> predecessor_type; | | typedef sender<T> predecessor_type; | |
| typedef queueing_port<T> my_node_type; | | typedef queueing_port<T> my_node_type; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| typedef std::vector<predecessor_type *> predecessor_vector_type; | | typedef typename receiver<input_type>::predecessor_list_type predec
essor_list_type; | |
| #endif | | #endif | |
| | | | |
| // ----------- Aggregator ------------ | | // ----------- Aggregator ------------ | |
| private: | | private: | |
| enum op_type { get__item, res_port, try__put_task | | enum op_type { get__item, res_port, try__put_task | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| , add_blt_pred, del_blt_pred, blt_pred_cnt, blt_pred_cpy | | , add_blt_pred, del_blt_pred, blt_pred_cnt, blt_pred_cpy | |
| #endif | | #endif | |
| }; | | }; | |
| enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |
| typedef queueing_port<T> my_class; | | typedef queueing_port<T> my_class; | |
| | | | |
| class queueing_port_operation : public aggregated_operation<queuein
g_port_operation> { | | class queueing_port_operation : public aggregated_operation<queuein
g_port_operation> { | |
| public: | | public: | |
| char type; | | char type; | |
| T my_val; | | T my_val; | |
| T *my_arg; | | T *my_arg; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| sender<T> *pred; | | sender<T> *pred; | |
| size_t cnt_val; | | size_t cnt_val; | |
|
| predecessor_vector_type *pvec; | | predecessor_list_type *plist; | |
| #endif | | #endif | |
| task * bypass_t; | | task * bypass_t; | |
| // constructor for value parameter | | // constructor for value parameter | |
| queueing_port_operation(const T& e, op_type t) : | | queueing_port_operation(const T& e, op_type t) : | |
| type(char(t)), my_val(e) | | type(char(t)), my_val(e) | |
| , bypass_t(NULL) | | , bypass_t(NULL) | |
| {} | | {} | |
| // constructor for pointer parameter | | // constructor for pointer parameter | |
| queueing_port_operation(const T* p, op_type t) : | | queueing_port_operation(const T* p, op_type t) : | |
| type(char(t)), my_arg(const_cast<T*>(p)) | | type(char(t)), my_arg(const_cast<T*>(p)) | |
| | | | |
| skipping to change at line 505 | | skipping to change at line 505 | |
| break; | | break; | |
| case del_blt_pred: | | case del_blt_pred: | |
| my_built_predecessors.delete_edge(*(current->pred)); | | my_built_predecessors.delete_edge(*(current->pred)); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| case blt_pred_cnt: | | case blt_pred_cnt: | |
| current->cnt_val = my_built_predecessors.edge_count(); | | current->cnt_val = my_built_predecessors.edge_count(); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| case blt_pred_cpy: | | case blt_pred_cpy: | |
|
| my_built_predecessors.copy_edges(*(current->pvec)); | | my_built_predecessors.copy_edges(*(current->plist)); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | | #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | |
| } | | } | |
| } | | } | |
| } | | } | |
| // ------------ End Aggregator --------------- | | // ------------ End Aggregator --------------- | |
| | | | |
| protected: | | protected: | |
| template< typename R, typename B > friend class run_and_put_task; | | template< typename R, typename B > friend class run_and_put_task; | |
| | | | |
| skipping to change at line 578 | | skipping to change at line 578 | |
| op_data.pred = &p; | | op_data.pred = &p; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| } | | } | |
| | | | |
| /*override*/size_t predecessor_count() { | | /*override*/size_t predecessor_count() { | |
| queueing_port_operation op_data(blt_pred_cnt); | | queueing_port_operation op_data(blt_pred_cnt); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| return op_data.cnt_val; | | return op_data.cnt_val; | |
| } | | } | |
| | | | |
|
| /*override*/void copy_predecessors(predecessor_vector_type &v) { | | /*override*/void copy_predecessors(predecessor_list_type &l) { | |
| queueing_port_operation op_data(blt_pred_cpy); | | queueing_port_operation op_data(blt_pred_cpy); | |
|
| op_data.pvec = &v; | | op_data.plist = &l; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| } | | } | |
| | | | |
| /*override*/void reset_receiver(__TBB_PFG_RESET_ARG(reset_flags f))
{ | | /*override*/void reset_receiver(__TBB_PFG_RESET_ARG(reset_flags f))
{ | |
| item_buffer<T>::reset(); | | item_buffer<T>::reset(); | |
| if (f & rf_extract) | | if (f & rf_extract) | |
| my_built_predecessors.receiver_extract(*this); | | my_built_predecessors.receiver_extract(*this); | |
| } | | } | |
| #else | | #else | |
| /*override*/void reset_receiver(__TBB_PFG_RESET_ARG(reset_flags /*f
*/)) { item_buffer<T>::reset(); } | | /*override*/void reset_receiver(__TBB_PFG_RESET_ARG(reset_flags /*f
*/)) { item_buffer<T>::reset(); } | |
| | | | |
| skipping to change at line 611 | | skipping to change at line 611 | |
| | | | |
| template< typename T > | | template< typename T > | |
| class tag_matching_port : public receiver<T>, public tagged_buffer< tag
_value, T, NO_TAG > { | | class tag_matching_port : public receiver<T>, public tagged_buffer< tag
_value, T, NO_TAG > { | |
| public: | | public: | |
| typedef T input_type; | | typedef T input_type; | |
| typedef sender<T> predecessor_type; | | typedef sender<T> predecessor_type; | |
| typedef tag_matching_port<T> my_node_type; // for forwarding, if n
eeded | | typedef tag_matching_port<T> my_node_type; // for forwarding, if n
eeded | |
| typedef function_body<input_type, tag_value> my_tag_func_type; | | typedef function_body<input_type, tag_value> my_tag_func_type; | |
| typedef tagged_buffer<tag_value,T,NO_TAG> my_buffer_type; | | typedef tagged_buffer<tag_value,T,NO_TAG> my_buffer_type; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| typedef std::vector<predecessor_type *> predecessor_vector_type; | | typedef typename receiver<input_type>::predecessor_list_type predec
essor_list_type; | |
| #endif | | #endif | |
| private: | | private: | |
| // ----------- Aggregator ------------ | | // ----------- Aggregator ------------ | |
| private: | | private: | |
| enum op_type { try__put, get__item, res_port, | | enum op_type { try__put, get__item, res_port, | |
| add_blt_pred, del_blt_pred, blt_pred_cnt, blt_pred_cpy | | add_blt_pred, del_blt_pred, blt_pred_cnt, blt_pred_cpy | |
| }; | | }; | |
| enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |
| typedef tag_matching_port<T> my_class; | | typedef tag_matching_port<T> my_class; | |
| | | | |
| class tag_matching_port_operation : public aggregated_operation<tag
_matching_port_operation> { | | class tag_matching_port_operation : public aggregated_operation<tag
_matching_port_operation> { | |
| public: | | public: | |
| char type; | | char type; | |
| T my_val; | | T my_val; | |
| T *my_arg; | | T *my_arg; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| predecessor_type *pred; | | predecessor_type *pred; | |
| size_t cnt_val; | | size_t cnt_val; | |
|
| predecessor_vector_type *pvec; | | predecessor_list_type *plist; | |
| #endif | | #endif | |
| tag_value my_tag_value; | | tag_value my_tag_value; | |
| // constructor for value parameter | | // constructor for value parameter | |
| tag_matching_port_operation(const T& e, op_type t) : | | tag_matching_port_operation(const T& e, op_type t) : | |
| type(char(t)), my_val(e) {} | | type(char(t)), my_val(e) {} | |
| // constructor for pointer parameter | | // constructor for pointer parameter | |
| tag_matching_port_operation(const T* p, op_type t) : | | tag_matching_port_operation(const T* p, op_type t) : | |
| type(char(t)), my_arg(const_cast<T*>(p)) {} | | type(char(t)), my_arg(const_cast<T*>(p)) {} | |
| // constructor with no parameter | | // constructor with no parameter | |
| tag_matching_port_operation(op_type t) : type(char(t)) {} | | tag_matching_port_operation(op_type t) : type(char(t)) {} | |
| | | | |
| skipping to change at line 685 | | skipping to change at line 685 | |
| break; | | break; | |
| case del_blt_pred: | | case del_blt_pred: | |
| my_built_predecessors.delete_edge(*(current->pred)); | | my_built_predecessors.delete_edge(*(current->pred)); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| case blt_pred_cnt: | | case blt_pred_cnt: | |
| current->cnt_val = my_built_predecessors.edge_count(); | | current->cnt_val = my_built_predecessors.edge_count(); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| case blt_pred_cpy: | | case blt_pred_cpy: | |
|
| my_built_predecessors.copy_edges(*(current->pvec)); | | my_built_predecessors.copy_edges(*(current->plist)); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| #endif | | #endif | |
| } | | } | |
| } | | } | |
| } | | } | |
| // ------------ End Aggregator --------------- | | // ------------ End Aggregator --------------- | |
| protected: | | protected: | |
| template< typename R, typename B > friend class run_and_put_task; | | template< typename R, typename B > friend class run_and_put_task; | |
| template<typename X, typename Y> friend class internal::broadcast_c
ache; | | template<typename X, typename Y> friend class internal::broadcast_c
ache; | |
| | | | |
| skipping to change at line 770 | | skipping to change at line 770 | |
| op_data.pred = &p; | | op_data.pred = &p; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| } | | } | |
| | | | |
| /*override*/size_t predecessor_count() { | | /*override*/size_t predecessor_count() { | |
| tag_matching_port_operation op_data(blt_pred_cnt); | | tag_matching_port_operation op_data(blt_pred_cnt); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| return op_data.cnt_val; | | return op_data.cnt_val; | |
| } | | } | |
| | | | |
|
| /*override*/void copy_predecessors(predecessor_vector_type &v) { | | /*override*/void copy_predecessors(predecessor_list_type &l) { | |
| tag_matching_port_operation op_data(blt_pred_cpy); | | tag_matching_port_operation op_data(blt_pred_cpy); | |
|
| op_data.pvec = &v; | | op_data.plist = &l; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| // reset_port is called when item is accepted by successor, but | | // reset_port is called when item is accepted by successor, but | |
| // is initiated by join_node. | | // is initiated by join_node. | |
| void reset_port() { | | void reset_port() { | |
| tag_matching_port_operation op_data(res_port); | | tag_matching_port_operation op_data(res_port); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| return; | | return; | |
| | | | |
| skipping to change at line 1179 | | skipping to change at line 1179 | |
| public: | | public: | |
| typedef OutputTuple output_type; | | typedef OutputTuple output_type; | |
| | | | |
| typedef receiver<output_type> successor_type; | | typedef receiver<output_type> successor_type; | |
| typedef join_node_FE<JP, InputTuple, OutputTuple> input_ports_type; | | typedef join_node_FE<JP, InputTuple, OutputTuple> input_ports_type; | |
| using input_ports_type::tuple_build_may_succeed; | | using input_ports_type::tuple_build_may_succeed; | |
| using input_ports_type::try_to_make_tuple; | | using input_ports_type::try_to_make_tuple; | |
| using input_ports_type::tuple_accepted; | | using input_ports_type::tuple_accepted; | |
| using input_ports_type::tuple_rejected; | | using input_ports_type::tuple_rejected; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| typedef std::vector<successor_type *> successor_vector_type; | | typedef typename sender<output_type>::successor_list_type successor
_list_type; | |
| #endif | | #endif | |
| | | | |
| private: | | private: | |
| // ----------- Aggregator ------------ | | // ----------- Aggregator ------------ | |
| enum op_type { reg_succ, rem_succ, try__get, do_fwrd, do_fwrd_bypas
s | | enum op_type { reg_succ, rem_succ, try__get, do_fwrd, do_fwrd_bypas
s | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| , add_blt_succ, del_blt_succ, blt_succ_cnt, blt_succ_cpy | | , add_blt_succ, del_blt_succ, blt_succ_cnt, blt_succ_cpy | |
| #endif | | #endif | |
| }; | | }; | |
| enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | | enum op_stat {WAIT=0, SUCCEEDED, FAILED}; | |
| typedef join_node_base<JP,InputTuple,OutputTuple> my_class; | | typedef join_node_base<JP,InputTuple,OutputTuple> my_class; | |
| | | | |
| class join_node_base_operation : public aggregated_operation<join_n
ode_base_operation> { | | class join_node_base_operation : public aggregated_operation<join_n
ode_base_operation> { | |
| public: | | public: | |
| char type; | | char type; | |
| union { | | union { | |
| output_type *my_arg; | | output_type *my_arg; | |
| successor_type *my_succ; | | successor_type *my_succ; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| size_t cnt_val; | | size_t cnt_val; | |
|
| successor_vector_type *svec; | | successor_list_type *slist; | |
| #endif | | #endif | |
| }; | | }; | |
| task *bypass_t; | | task *bypass_t; | |
| join_node_base_operation(const output_type& e, op_type t) : typ
e(char(t)), | | join_node_base_operation(const output_type& e, op_type t) : typ
e(char(t)), | |
| my_arg(const_cast<output_type*>(&e)), bypass_t(NULL) {} | | my_arg(const_cast<output_type*>(&e)), bypass_t(NULL) {} | |
| join_node_base_operation(const successor_type &s, op_type t) :
type(char(t)), | | join_node_base_operation(const successor_type &s, op_type t) :
type(char(t)), | |
| my_succ(const_cast<successor_type *>(&s)), bypass_t(NULL) {
} | | my_succ(const_cast<successor_type *>(&s)), bypass_t(NULL) {
} | |
| join_node_base_operation(op_type t) : type(char(t)), bypass_t(N
ULL) {} | | join_node_base_operation(op_type t) : type(char(t)), bypass_t(N
ULL) {} | |
| }; | | }; | |
| | | | |
| | | | |
| skipping to change at line 1288 | | skipping to change at line 1288 | |
| break; | | break; | |
| case del_blt_succ: | | case del_blt_succ: | |
| my_successors.internal_delete_built_successor(*(current
->my_succ)); | | my_successors.internal_delete_built_successor(*(current
->my_succ)); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| case blt_succ_cnt: | | case blt_succ_cnt: | |
| current->cnt_val = my_successors.successor_count(); | | current->cnt_val = my_successors.successor_count(); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| case blt_succ_cpy: | | case blt_succ_cpy: | |
|
| my_successors.copy_successors(*(current->svec)); | | my_successors.copy_successors(*(current->slist)); | |
| __TBB_store_with_release(current->status, SUCCEEDED); | | __TBB_store_with_release(current->status, SUCCEEDED); | |
| break; | | break; | |
| #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | | #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | |
| } | | } | |
| } | | } | |
| } | | } | |
| // ---------- end aggregator ----------- | | // ---------- end aggregator ----------- | |
| public: | | public: | |
| join_node_base(graph &g) : graph_node(g), input_ports_type(g), forw
arder_busy(false) { | | join_node_base(graph &g) : graph_node(g), input_ports_type(g), forw
arder_busy(false) { | |
| my_successors.set_owner(this); | | my_successors.set_owner(this); | |
| | | | |
| skipping to change at line 1353 | | skipping to change at line 1353 | |
| join_node_base_operation op_data(r, del_blt_succ); | | join_node_base_operation op_data(r, del_blt_succ); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| } | | } | |
| | | | |
| /*override*/size_t successor_count() { | | /*override*/size_t successor_count() { | |
| join_node_base_operation op_data(blt_succ_cnt); | | join_node_base_operation op_data(blt_succ_cnt); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| return op_data.cnt_val; | | return op_data.cnt_val; | |
| } | | } | |
| | | | |
|
| /*override*/ void copy_successors(successor_vector_type &v) { | | /*override*/ void copy_successors(successor_list_type &l) { | |
| join_node_base_operation op_data(blt_succ_cpy); | | join_node_base_operation op_data(blt_succ_cpy); | |
|
| op_data.svec = &v; | | op_data.slist = &l; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| } | | } | |
| #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | | #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | |
| | | | |
| protected: | | protected: | |
| | | | |
| /*override*/void reset(__TBB_PFG_RESET_ARG(reset_flags f)) { | | /*override*/void reset(__TBB_PFG_RESET_ARG(reset_flags f)) { | |
| input_ports_type::reset(__TBB_PFG_RESET_ARG(f)); | | input_ports_type::reset(__TBB_PFG_RESET_ARG(f)); | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| my_successors.reset(f); | | my_successors.reset(f); | |
| | | | |
End of changes. 20 change blocks. |
| 20 lines changed or deleted | | 20 lines changed or added | |
|
| enumerable_thread_specific.h | | enumerable_thread_specific.h | |
| | | | |
| skipping to change at line 30 | | skipping to change at line 30 | |
| | | | |
| #ifndef __TBB_enumerable_thread_specific_H | | #ifndef __TBB_enumerable_thread_specific_H | |
| #define __TBB_enumerable_thread_specific_H | | #define __TBB_enumerable_thread_specific_H | |
| | | | |
| #include "concurrent_vector.h" | | #include "concurrent_vector.h" | |
| #include "tbb_thread.h" | | #include "tbb_thread.h" | |
| #include "tbb_allocator.h" | | #include "tbb_allocator.h" | |
| #include "tbb_profiling.h" | | #include "tbb_profiling.h" | |
| #include "cache_aligned_allocator.h" | | #include "cache_aligned_allocator.h" | |
| #include "aligned_space.h" | | #include "aligned_space.h" | |
|
| | | #include "internal/_template_helpers.h" | |
| #include <string.h> // for memcpy | | #include <string.h> // for memcpy | |
| | | | |
| #if _WIN32||_WIN64 | | #if _WIN32||_WIN64 | |
| #include "machine/windows_api.h" | | #include "machine/windows_api.h" | |
| #else | | #else | |
| #include <pthread.h> | | #include <pthread.h> | |
| #endif | | #endif | |
| | | | |
|
| | | #define __TBB_ETS_USE_CPP11 \ | |
| | | (__TBB_CPP11_RVALUE_REF_PRESENT && __TBB_CPP11_VARIADIC_TEMPLATES_PRESE | |
| | | NT \ | |
| | | && __TBB_CPP11_DECLTYPE_PRESENT && __TBB_CPP11_LAMBDAS_PRESENT) | |
| | | | |
| namespace tbb { | | namespace tbb { | |
| | | | |
| //! enum for selecting between single key and key-per-instance versions | | //! enum for selecting between single key and key-per-instance versions | |
| enum ets_key_usage_type { ets_key_per_instance, ets_no_key }; | | enum ets_key_usage_type { ets_key_per_instance, ets_no_key }; | |
| | | | |
| namespace interface6 { | | namespace interface6 { | |
| | | | |
|
| | | // Forward declaration to use in internal classes | |
| | | template <typename T, typename Allocator, ets_key_usage_type ETS_key_ty | |
| | | pe> | |
| | | class enumerable_thread_specific; | |
| | | | |
| //! @cond | | //! @cond | |
| namespace internal { | | namespace internal { | |
| | | | |
| using namespace tbb::internal; | | using namespace tbb::internal; | |
| | | | |
| template<ets_key_usage_type ETS_key_type> | | template<ets_key_usage_type ETS_key_type> | |
| class ets_base: tbb::internal::no_copy { | | class ets_base: tbb::internal::no_copy { | |
| protected: | | protected: | |
| #if _WIN32||_WIN64 | | #if _WIN32||_WIN64 | |
| typedef DWORD key_type; | | typedef DWORD key_type; | |
| | | | |
| skipping to change at line 82 | | skipping to change at line 91 | |
| return h>>(8*sizeof(size_t)-lg_size); | | return h>>(8*sizeof(size_t)-lg_size); | |
| } | | } | |
| }; | | }; | |
| struct slot { | | struct slot { | |
| key_type key; | | key_type key; | |
| void* ptr; | | void* ptr; | |
| bool empty() const {return !key;} | | bool empty() const {return !key;} | |
| bool match( key_type k ) const {return key==k;} | | bool match( key_type k ) const {return key==k;} | |
| bool claim( key_type k ) { | | bool claim( key_type k ) { | |
| __TBB_ASSERT(sizeof(tbb::atomic<key_type>)==sizeof(key_
type), NULL); | | __TBB_ASSERT(sizeof(tbb::atomic<key_type>)==sizeof(key_
type), NULL); | |
|
| | | // TODO: maybe claim ptr, because key_type is not guara
nteed to match word size | |
| return tbb::internal::punned_cast<tbb::atomic<key_type>
*>(&key)->compare_and_swap(k,0)==0; | | return tbb::internal::punned_cast<tbb::atomic<key_type>
*>(&key)->compare_and_swap(k,0)==0; | |
| } | | } | |
| }; | | }; | |
| #if __TBB_PROTECTED_NESTED_CLASS_BROKEN | | #if __TBB_PROTECTED_NESTED_CLASS_BROKEN | |
| protected: | | protected: | |
| #endif | | #endif | |
| | | | |
| static key_type key_of_current_thread() { | | static key_type key_of_current_thread() { | |
|
| | | // TODO: replace key_type with tbb::tbb_thread::id | |
| tbb::tbb_thread::id id = tbb::this_tbb_thread::get_id(); | | tbb::tbb_thread::id id = tbb::this_tbb_thread::get_id(); | |
| key_type k; | | key_type k; | |
| memcpy( &k, &id, sizeof(k) ); | | memcpy( &k, &id, sizeof(k) ); | |
| return k; | | return k; | |
| } | | } | |
| | | | |
| //! Root of linked list of arrays of decreasing size. | | //! Root of linked list of arrays of decreasing size. | |
| /** NULL if and only if my_count==0. | | /** NULL if and only if my_count==0. | |
| Each array in the list is half the size of its predecessor.
*/ | | Each array in the list is half the size of its predecessor.
*/ | |
| atomic<array*> my_root; | | atomic<array*> my_root; | |
| | | | |
| skipping to change at line 118 | | skipping to change at line 129 | |
| std::memset( a+1, 0, n*sizeof(slot) ); | | std::memset( a+1, 0, n*sizeof(slot) ); | |
| return a; | | return a; | |
| } | | } | |
| void free(array* a) { | | void free(array* a) { | |
| size_t n = 1<<(a->lg_size); | | size_t n = 1<<(a->lg_size); | |
| free_array( (void *)a, size_t(sizeof(array)+n*sizeof(slot))
); | | free_array( (void *)a, size_t(sizeof(array)+n*sizeof(slot))
); | |
| } | | } | |
| static size_t hash( key_type k ) { | | static size_t hash( key_type k ) { | |
| // Multiplicative hashing. Client should use *upper* bits. | | // Multiplicative hashing. Client should use *upper* bits. | |
| // casts required for Mac gcc4.* compiler | | // casts required for Mac gcc4.* compiler | |
|
| | | // TODO: casting of key_type to uintptr_t is not portable;
implement and use hashing of thread::id | |
| return uintptr_t(k)*tbb::internal::select_size_t_constant<0
x9E3779B9,0x9E3779B97F4A7C15ULL>::value; | | return uintptr_t(k)*tbb::internal::select_size_t_constant<0
x9E3779B9,0x9E3779B97F4A7C15ULL>::value; | |
| } | | } | |
| | | | |
| ets_base() {my_root=NULL; my_count=0;} | | ets_base() {my_root=NULL; my_count=0;} | |
| virtual ~ets_base(); // g++ complains if this is not virtual..
. | | virtual ~ets_base(); // g++ complains if this is not virtual..
. | |
| void* table_lookup( bool& exists ); | | void* table_lookup( bool& exists ); | |
| void table_clear(); | | void table_clear(); | |
| // table_find is used in copying ETS, so is not used in concurr
ent context. So | | // table_find is used in copying ETS, so is not used in concurr
ent context. So | |
| // we don't need itt annotations for it. | | // we don't need itt annotations for it. | |
| slot& table_find( key_type k ) { | | slot& table_find( key_type k ) { | |
| | | | |
| skipping to change at line 352 | | skipping to change at line 364 | |
| | | | |
| enumerable_thread_specific_iterator &operator-=( ptrdiff_t offs
et ) { | | enumerable_thread_specific_iterator &operator-=( ptrdiff_t offs
et ) { | |
| my_index -= offset; | | my_index -= offset; | |
| my_value = NULL; | | my_value = NULL; | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| Value& operator*() const { | | Value& operator*() const { | |
| Value* value = my_value; | | Value* value = my_value; | |
| if( !value ) { | | if( !value ) { | |
|
| value = my_value = reinterpret_cast<Value *>(&(*my_cont
ainer)[my_index].value); | | value = my_value = (*my_container)[my_index].value(); | |
| } | | } | |
|
| __TBB_ASSERT( value==reinterpret_cast<Value *>(&(*my_contai
ner)[my_index].value), "corrupt cache" ); | | __TBB_ASSERT( value==(*my_container)[my_index].value(), "co
rrupt cache" ); | |
| return *value; | | return *value; | |
| } | | } | |
| | | | |
| Value& operator[]( ptrdiff_t k ) const { | | Value& operator[]( ptrdiff_t k ) const { | |
| return (*my_container)[my_index + k].value; | | return (*my_container)[my_index + k].value; | |
| } | | } | |
| | | | |
| Value* operator->() const {return &operator*();} | | Value* operator->() const {return &operator*();} | |
| | | | |
| enumerable_thread_specific_iterator& operator++() { | | enumerable_thread_specific_iterator& operator++() { | |
| | | | |
| skipping to change at line 589 | | skipping to change at line 601 | |
| } | | } | |
| | | | |
| // != | | // != | |
| template<typename SegmentedContainer, typename T, typename U> | | template<typename SegmentedContainer, typename T, typename U> | |
| bool operator!=( const segmented_iterator<SegmentedContainer,T>& i, | | bool operator!=( const segmented_iterator<SegmentedContainer,T>& i, | |
| const segmented_iterator<SegmentedContainer,U>& j
) { | | const segmented_iterator<SegmentedContainer,U>& j
) { | |
| return !(i==j); | | return !(i==j); | |
| } | | } | |
| | | | |
| template<typename T> | | template<typename T> | |
|
| struct destruct_only: tbb::internal::no_copy { | | | |
| tbb::aligned_space<T> value; | | | |
| ~destruct_only() {value.begin()[0].~T();} | | | |
| }; | | | |
| | | | |
| template<typename T> | | | |
| struct construct_by_default: tbb::internal::no_assign { | | struct construct_by_default: tbb::internal::no_assign { | |
| void construct(void*where) {new(where) T();} // C++ note: the (
) in T() ensure zero initialization. | | void construct(void*where) {new(where) T();} // C++ note: the (
) in T() ensure zero initialization. | |
| construct_by_default( int ) {} | | construct_by_default( int ) {} | |
| }; | | }; | |
| | | | |
| template<typename T> | | template<typename T> | |
| struct construct_by_exemplar: tbb::internal::no_assign { | | struct construct_by_exemplar: tbb::internal::no_assign { | |
| const T exemplar; | | const T exemplar; | |
| void construct(void*where) {new(where) T(exemplar);} | | void construct(void*where) {new(where) T(exemplar);} | |
| construct_by_exemplar( const T& t ) : exemplar(t) {} | | construct_by_exemplar( const T& t ) : exemplar(t) {} | |
|
| | | #if __TBB_ETS_USE_CPP11 | |
| | | construct_by_exemplar( T&& t ) : exemplar(std::move(t)) {} | |
| | | #endif | |
| }; | | }; | |
| | | | |
| template<typename T, typename Finit> | | template<typename T, typename Finit> | |
| struct construct_by_finit: tbb::internal::no_assign { | | struct construct_by_finit: tbb::internal::no_assign { | |
| Finit f; | | Finit f; | |
| void construct(void* where) {new(where) T(f());} | | void construct(void* where) {new(where) T(f());} | |
| construct_by_finit( const Finit& f_ ) : f(f_) {} | | construct_by_finit( const Finit& f_ ) : f(f_) {} | |
|
| | | #if __TBB_ETS_USE_CPP11 | |
| | | construct_by_finit( Finit&& f_ ) : f(std::move(f_)) {} | |
| | | #endif | |
| }; | | }; | |
| | | | |
|
| | | #if __TBB_ETS_USE_CPP11 | |
| | | template<typename T, typename... P> | |
| | | struct construct_by_args: tbb::internal::no_assign { | |
| | | internal::stored_pack<P...> pack; | |
| | | void construct(void* where) { | |
| | | internal::call( [where](const typename strip<P>::type&... a | |
| | | rgs ){ | |
| | | new(where) T(args...); | |
| | | }, pack ); | |
| | | } | |
| | | construct_by_args( P&& ... args ) : pack(std::forward<P>(args). | |
| | | ..) {} | |
| | | }; | |
| | | #endif | |
| | | | |
| // storage for initialization function pointer | | // storage for initialization function pointer | |
| template<typename T> | | template<typename T> | |
| class callback_base { | | class callback_base { | |
| public: | | public: | |
| // Clone *this | | // Clone *this | |
|
| virtual callback_base* clone() = 0; | | virtual callback_base* clone() const = 0; | |
| // Destruct and free *this | | // Destruct and free *this | |
| virtual void destroy() = 0; | | virtual void destroy() = 0; | |
| // Need virtual destructor to satisfy GCC compiler warning | | // Need virtual destructor to satisfy GCC compiler warning | |
| virtual ~callback_base() { } | | virtual ~callback_base() { } | |
| // Construct T at where | | // Construct T at where | |
| virtual void construct(void* where) = 0; | | virtual void construct(void* where) = 0; | |
| }; | | }; | |
| | | | |
| template <typename T, typename Constructor> | | template <typename T, typename Constructor> | |
| class callback_leaf: public callback_base<T>, Constructor { | | class callback_leaf: public callback_base<T>, Constructor { | |
|
| | | #if __TBB_ETS_USE_CPP11 | |
| | | template<typename... P> callback_leaf( P&& ... params ) : Const | |
| | | ructor(std::forward<P>(params)...) {} | |
| | | #else | |
| template<typename X> callback_leaf( const X& x ) : Constructor(
x) {} | | template<typename X> callback_leaf( const X& x ) : Constructor(
x) {} | |
|
| | | #endif | |
| | | | |
| typedef typename tbb::tbb_allocator<callback_leaf> my_allocator
_type; | | typedef typename tbb::tbb_allocator<callback_leaf> my_allocator
_type; | |
| | | | |
|
| /*override*/ callback_base<T>* clone() { | | /*override*/ callback_base<T>* clone() const { | |
| return make(*this); | | return make(*this); | |
| } | | } | |
| | | | |
| /*override*/ void destroy() { | | /*override*/ void destroy() { | |
| my_allocator_type().destroy(this); | | my_allocator_type().destroy(this); | |
| my_allocator_type().deallocate(this,1); | | my_allocator_type().deallocate(this,1); | |
| } | | } | |
| | | | |
| /*override*/ void construct(void* where) { | | /*override*/ void construct(void* where) { | |
| Constructor::construct(where); | | Constructor::construct(where); | |
| } | | } | |
| public: | | public: | |
|
| | | #if __TBB_ETS_USE_CPP11 | |
| | | template<typename... P> | |
| | | static callback_base<T>* make( P&& ... params ) { | |
| | | void* where = my_allocator_type().allocate(1); | |
| | | return new(where) callback_leaf( std::forward<P>(params)... | |
| | | ); | |
| | | } | |
| | | #else | |
| template<typename X> | | template<typename X> | |
| static callback_base<T>* make( const X& x ) { | | static callback_base<T>* make( const X& x ) { | |
| void* where = my_allocator_type().allocate(1); | | void* where = my_allocator_type().allocate(1); | |
| return new(where) callback_leaf(x); | | return new(where) callback_leaf(x); | |
| } | | } | |
|
| | | #endif | |
| }; | | }; | |
| | | | |
|
| //! Template for adding padding in order to avoid false sharing | | //! Template for recording construction of objects in table | |
| /** ModularSize should be sizeof(U) modulo the cache line size. | | /** All maintenance of the space will be done explicitly on push_ba | |
| All maintenance of the space will be done explicitly on push_ba | | ck, | |
| ck, | | | |
| and all thread local copies must be destroyed before the concur
rent | | and all thread local copies must be destroyed before the concur
rent | |
| vector is deleted. | | vector is deleted. | |
|
| | | | |
| | | The flag is_built is initialized to false. When the local is | |
| | | successfully-constructed, set the flag to true. If the constru | |
| | | ctor | |
| | | throws, the flag will be false. | |
| */ | | */ | |
|
| template<typename U, size_t ModularSize> | | template<typename U> | |
| struct ets_element { | | struct ets_element { | |
|
| ets_element() { /* avoid cl warning C4345 about default initial | | tbb::aligned_space<U> my_space; | |
| ization of POD types */ } | | bool is_built; | |
| char value[ModularSize==0 ? sizeof(U) : sizeof(U)+(tbb::interna | | ets_element() { is_built = false; } // not currently-built | |
| l::NFS_MaxLineSize-ModularSize)]; | | U *value() { return my_space.begin(); } | |
| void unconstruct() { | | void unconstruct() { | |
|
| tbb::internal::punned_cast<U*>(&value)->~U(); | | if(is_built) { | |
| } | | my_space.begin()->~U(); | |
| | | is_built = false; | |
| | | } | |
| | | } | |
| | | ~ets_element() {unconstruct();} | |
| | | }; | |
| | | | |
| | | // A predicate that can be used for a compile-time compatibility ch | |
| | | eck of ETS instances | |
| | | // Ideally, it should have been declared inside the ETS class, but | |
| | | unfortunately | |
| | | // in that case VS2013 does not enable the variadic constructor. | |
| | | template<typename T, typename ETS> struct is_compatible_ets { stati | |
| | | c const bool value = false; }; | |
| | | template<typename T, typename U, typename A, ets_key_usage_type C> | |
| | | struct is_compatible_ets< T, enumerable_thread_specific<U,A,C> > { | |
| | | static const bool value = internal::is_same_type<T,U>::value; }; | |
| | | | |
| | | #if __TBB_ETS_USE_CPP11 | |
| | | // A predicate that checks whether, for a variable 'foo' of type T, | |
| | | foo() is a valid expression | |
| | | template <typename T> | |
| | | class is_callable_no_args { | |
| | | private: | |
| | | typedef char yes[1]; | |
| | | typedef char no [2]; | |
| | | | |
| | | template<typename U> static yes& decide( decltype(declval<U>()( | |
| | | ))* ); | |
| | | template<typename U> static no& decide(...); | |
| | | public: | |
| | | static const bool value = (sizeof(decide<T>(NULL)) == sizeof(ye | |
| | | s)); | |
| }; | | }; | |
|
| | | #endif | |
| | | | |
| } // namespace internal | | } // namespace internal | |
| //! @endcond | | //! @endcond | |
| | | | |
| //! The enumerable_thread_specific container | | //! The enumerable_thread_specific container | |
| /** enumerable_thread_specific has the following properties: | | /** enumerable_thread_specific has the following properties: | |
| - thread-local copies are lazily created, with default, exemplar or
function initialization. | | - thread-local copies are lazily created, with default, exemplar or
function initialization. | |
| - thread-local copies do not move (during lifetime, and excepting c
lear()) so the address of a copy is invariant. | | - thread-local copies do not move (during lifetime, and excepting c
lear()) so the address of a copy is invariant. | |
| - the contained objects need not have operator=() defined if combin
e is not used. | | - the contained objects need not have operator=() defined if combin
e is not used. | |
| - enumerable_thread_specific containers may be copy-constructed or
assigned. | | - enumerable_thread_specific containers may be copy-constructed or
assigned. | |
| - thread-local copies can be managed by hash-table, or can be acces
sed via TLS storage for speed. | | - thread-local copies can be managed by hash-table, or can be acces
sed via TLS storage for speed. | |
| - outside of parallel contexts, the contents of all thread-local co
pies are accessible by iterator or using combine or combine_each methods | | - outside of parallel contexts, the contents of all thread-local co
pies are accessible by iterator or using combine or combine_each methods | |
| | | | |
| @par Segmented iterator | | @par Segmented iterator | |
| When the thread-local objects are containers with input_iterators d
efined, a segmented iterator may | | When the thread-local objects are containers with input_iterators d
efined, a segmented iterator may | |
| be used to iterate over all the elements of all thread-local copies
. | | be used to iterate over all the elements of all thread-local copies
. | |
| | | | |
| @par combine and combine_each | | @par combine and combine_each | |
| - Both methods are defined for enumerable_thread_specific. | | - Both methods are defined for enumerable_thread_specific. | |
|
| - combine() requires the the type T have operator=() defined. | | - combine() requires the type T have operator=() defined. | |
| - neither method modifies the contents of the object (though there
is no guarantee that the applied methods do not modify the object.) | | - neither method modifies the contents of the object (though there
is no guarantee that the applied methods do not modify the object.) | |
| - Both are evaluated in serial context (the methods are assumed to
be non-benign.) | | - Both are evaluated in serial context (the methods are assumed to
be non-benign.) | |
| | | | |
| @ingroup containers */ | | @ingroup containers */ | |
| template <typename T, | | template <typename T, | |
| typename Allocator=cache_aligned_allocator<T>, | | typename Allocator=cache_aligned_allocator<T>, | |
| ets_key_usage_type ETS_key_type=ets_no_key > | | ets_key_usage_type ETS_key_type=ets_no_key > | |
| class enumerable_thread_specific: internal::ets_base<ETS_key_type> { | | class enumerable_thread_specific: internal::ets_base<ETS_key_type> { | |
| | | | |
| template<typename U, typename A, ets_key_usage_type C> friend class
enumerable_thread_specific; | | template<typename U, typename A, ets_key_usage_type C> friend class
enumerable_thread_specific; | |
| | | | |
|
| typedef internal::ets_element<T,sizeof(T)%tbb::internal::NFS_MaxLin
eSize> padded_element; | | typedef internal::padded< internal::ets_element<T> > padded_element
; | |
| | | | |
| //! A generic range, used to create range objects from the iterator
s | | //! A generic range, used to create range objects from the iterator
s | |
| template<typename I> | | template<typename I> | |
| class generic_range_type: public blocked_range<I> { | | class generic_range_type: public blocked_range<I> { | |
| public: | | public: | |
| typedef T value_type; | | typedef T value_type; | |
| typedef T& reference; | | typedef T& reference; | |
| typedef const T& const_reference; | | typedef const T& const_reference; | |
| typedef I iterator; | | typedef I iterator; | |
| typedef ptrdiff_t difference_type; | | typedef ptrdiff_t difference_type; | |
| | | | |
| skipping to change at line 724 | | skipping to change at line 792 | |
| }; | | }; | |
| | | | |
| typedef typename Allocator::template rebind< padded_element >::othe
r padded_allocator_type; | | typedef typename Allocator::template rebind< padded_element >::othe
r padded_allocator_type; | |
| typedef tbb::concurrent_vector< padded_element, padded_allocator_ty
pe > internal_collection_type; | | typedef tbb::concurrent_vector< padded_element, padded_allocator_ty
pe > internal_collection_type; | |
| | | | |
| internal::callback_base<T> *my_construct_callback; | | internal::callback_base<T> *my_construct_callback; | |
| | | | |
| internal_collection_type my_locals; | | internal_collection_type my_locals; | |
| | | | |
| /*override*/ void* create_local() { | | /*override*/ void* create_local() { | |
|
| void* lref = &*my_locals.grow_by(1); | | padded_element* lref = &*my_locals.grow_by(1); | |
| my_construct_callback->construct(lref); | | my_construct_callback->construct(lref->value()); | |
| | | lref->is_built = true; | |
| return lref; | | return lref; | |
| } | | } | |
| | | | |
| void unconstruct_locals() { | | void unconstruct_locals() { | |
| for(typename internal_collection_type::iterator cvi = my_locals
.begin(); cvi != my_locals.end(); ++cvi) { | | for(typename internal_collection_type::iterator cvi = my_locals
.begin(); cvi != my_locals.end(); ++cvi) { | |
| cvi->unconstruct(); | | cvi->unconstruct(); | |
| } | | } | |
| } | | } | |
| | | | |
| typedef typename Allocator::template rebind< uintptr_t >::other arr
ay_allocator_type; | | typedef typename Allocator::template rebind< uintptr_t >::other arr
ay_allocator_type; | |
| | | | |
| skipping to change at line 774 | | skipping to change at line 843 | |
| // Parallel range types | | // Parallel range types | |
| typedef generic_range_type< iterator > range_type; | | typedef generic_range_type< iterator > range_type; | |
| typedef generic_range_type< const_iterator > const_range_type; | | typedef generic_range_type< const_iterator > const_range_type; | |
| | | | |
| //! Default constructor. Each local instance of T is default const
ructed. | | //! Default constructor. Each local instance of T is default const
ructed. | |
| enumerable_thread_specific() : my_construct_callback( | | enumerable_thread_specific() : my_construct_callback( | |
| internal::callback_leaf<T,internal::construct_by_default<T> >::
make(/*dummy argument*/0) | | internal::callback_leaf<T,internal::construct_by_default<T> >::
make(/*dummy argument*/0) | |
| ){} | | ){} | |
| | | | |
| //! Constructor with initializer functor. Each local instance of T
is constructed by T(finit()). | | //! Constructor with initializer functor. Each local instance of T
is constructed by T(finit()). | |
|
| template <typename Finit> | | template <typename Finit | |
| | | #if __TBB_ETS_USE_CPP11 | |
| | | , typename = typename internal::enable_if<internal::is_ca | |
| | | llable_no_args<typename internal::strip<Finit>::type>::value>::type | |
| | | #endif | |
| | | > | |
| enumerable_thread_specific( Finit finit ) : my_construct_callback( | | enumerable_thread_specific( Finit finit ) : my_construct_callback( | |
|
| internal::callback_leaf<T,internal::construct_by_finit<T,Finit>
>::make( finit ) | | internal::callback_leaf<T,internal::construct_by_finit<T,Finit>
>::make( tbb::internal::move(finit) ) | |
| ){} | | ){} | |
| | | | |
| //! Constructor with exemplar. Each local instance of T is copy-con
structed from the exemplar. | | //! Constructor with exemplar. Each local instance of T is copy-con
structed from the exemplar. | |
| enumerable_thread_specific( const T& exemplar ) : my_construct_call
back( | | enumerable_thread_specific( const T& exemplar ) : my_construct_call
back( | |
| internal::callback_leaf<T,internal::construct_by_exemplar<T> >:
:make( exemplar ) | | internal::callback_leaf<T,internal::construct_by_exemplar<T> >:
:make( exemplar ) | |
| ){} | | ){} | |
| | | | |
|
| | | #if __TBB_ETS_USE_CPP11 | |
| | | enumerable_thread_specific( T&& exemplar ) : my_construct_callback( | |
| | | internal::callback_leaf<T,internal::construct_by_exemplar<T> >: | |
| | | :make( std::move(exemplar) ) | |
| | | ){} | |
| | | | |
| | | //! Variadic constructor with initializer arguments. Each local in | |
| | | stance of T is constructed by T(args...) | |
| | | template <typename P1, typename... P, | |
| | | typename = typename internal::enable_if<!internal::is_cal | |
| | | lable_no_args<typename internal::strip<P1>::type>::value | |
| | | && !internal::is_ | |
| | | compatible_ets<T, typename internal::strip<P1>::type>::value | |
| | | && !internal::is_ | |
| | | same_type<T, typename internal::strip<P1>::type>::value | |
| | | >::type> | |
| | | enumerable_thread_specific( P1&& arg1, P&& ... args ) : my_construc | |
| | | t_callback( | |
| | | internal::callback_leaf<T,internal::construct_by_args<T,P1,P... | |
| | | > >::make( std::forward<P1>(arg1), std::forward<P>(args)... ) | |
| | | ){} | |
| | | #endif | |
| | | | |
| //! Destructor | | //! Destructor | |
| ~enumerable_thread_specific() { | | ~enumerable_thread_specific() { | |
| my_construct_callback->destroy(); | | my_construct_callback->destroy(); | |
| this->clear(); // deallocation before the derived class is fin
ished destructing | | this->clear(); // deallocation before the derived class is fin
ished destructing | |
| // So free(array *) is still accessible | | // So free(array *) is still accessible | |
| } | | } | |
| | | | |
| //! returns reference to local, discarding exists | | //! returns reference to local, discarding exists | |
| reference local() { | | reference local() { | |
| bool exists; | | bool exists; | |
| | | | |
| skipping to change at line 852 | | skipping to change at line 941 | |
| template<typename Alloc, ets_key_usage_type Cachetype> | | template<typename Alloc, ets_key_usage_type Cachetype> | |
| enumerable_thread_specific( const enumerable_thread_specific<T, All
oc, Cachetype>& other ) : internal::ets_base<ETS_key_type> () | | enumerable_thread_specific( const enumerable_thread_specific<T, All
oc, Cachetype>& other ) : internal::ets_base<ETS_key_type> () | |
| { | | { | |
| internal_copy(other); | | internal_copy(other); | |
| } | | } | |
| | | | |
| enumerable_thread_specific( const enumerable_thread_specific& other
) : internal::ets_base<ETS_key_type> () | | enumerable_thread_specific( const enumerable_thread_specific& other
) : internal::ets_base<ETS_key_type> () | |
| { | | { | |
| internal_copy(other); | | internal_copy(other); | |
| } | | } | |
|
| | | // TODO: add move constructors | |
| | | | |
| private: | | private: | |
| | | | |
| template<typename A2, ets_key_usage_type C2> | | template<typename A2, ets_key_usage_type C2> | |
| enumerable_thread_specific & | | enumerable_thread_specific & | |
| internal_assign(const enumerable_thread_specific<T, A2, C2>& other)
{ | | internal_assign(const enumerable_thread_specific<T, A2, C2>& other)
{ | |
| if(static_cast<void *>( this ) != static_cast<const void *>( &o
ther )) { | | if(static_cast<void *>( this ) != static_cast<const void *>( &o
ther )) { | |
| this->clear(); | | this->clear(); | |
| my_construct_callback->destroy(); | | my_construct_callback->destroy(); | |
| my_construct_callback = 0; | | my_construct_callback = 0; | |
| | | | |
| skipping to change at line 879 | | skipping to change at line 969 | |
| // assignment | | // assignment | |
| enumerable_thread_specific& operator=(const enumerable_thread_speci
fic& other) { | | enumerable_thread_specific& operator=(const enumerable_thread_speci
fic& other) { | |
| return internal_assign(other); | | return internal_assign(other); | |
| } | | } | |
| | | | |
| template<typename Alloc, ets_key_usage_type Cachetype> | | template<typename Alloc, ets_key_usage_type Cachetype> | |
| enumerable_thread_specific& operator=(const enumerable_thread_speci
fic<T, Alloc, Cachetype>& other) | | enumerable_thread_specific& operator=(const enumerable_thread_speci
fic<T, Alloc, Cachetype>& other) | |
| { | | { | |
| return internal_assign(other); | | return internal_assign(other); | |
| } | | } | |
|
| | | // TODO: add move assignments | |
| | | | |
| // combine_func_t has signature T(T,T) or T(const T&, const T&) | | // combine_func_t has signature T(T,T) or T(const T&, const T&) | |
| template <typename combine_func_t> | | template <typename combine_func_t> | |
| T combine(combine_func_t f_combine) { | | T combine(combine_func_t f_combine) { | |
| if(begin() == end()) { | | if(begin() == end()) { | |
|
| internal::destruct_only<T> location; | | internal::ets_element<T> location; | |
| my_construct_callback->construct(location.value.begin()); | | my_construct_callback->construct(location.value()); | |
| return *location.value.begin(); | | location.is_built = true; | |
| | | return *location.value(); | |
| } | | } | |
| const_iterator ci = begin(); | | const_iterator ci = begin(); | |
| T my_result = *ci; | | T my_result = *ci; | |
| while(++ci != end()) | | while(++ci != end()) | |
| my_result = f_combine( my_result, *ci ); | | my_result = f_combine( my_result, *ci ); | |
| return my_result; | | return my_result; | |
| } | | } | |
| | | | |
|
| // combine_func_t has signature void(T) or void(const T&) | | // combine_func_t takes T by value or by [const] reference, and ret
urns nothing | |
| template <typename combine_func_t> | | template <typename combine_func_t> | |
| void combine_each(combine_func_t f_combine) { | | void combine_each(combine_func_t f_combine) { | |
|
| for(const_iterator ci = begin(); ci != end(); ++ci) { | | for(iterator ci = begin(); ci != end(); ++ci) { | |
| f_combine( *ci ); | | f_combine( *ci ); | |
| } | | } | |
| } | | } | |
| | | | |
| }; // enumerable_thread_specific | | }; // enumerable_thread_specific | |
| | | | |
| template <typename T, typename Allocator, ets_key_usage_type ETS_key_ty
pe> | | template <typename T, typename Allocator, ets_key_usage_type ETS_key_ty
pe> | |
| template<typename A2, ets_key_usage_type C2> | | template<typename A2, ets_key_usage_type C2> | |
| void enumerable_thread_specific<T,Allocator,ETS_key_type>::internal_cop
y( const enumerable_thread_specific<T, A2, C2>& other) { | | void enumerable_thread_specific<T,Allocator,ETS_key_type>::internal_cop
y( const enumerable_thread_specific<T, A2, C2>& other) { | |
|
| | | #if __TBB_ETS_USE_CPP11 | |
| | | __TBB_STATIC_ASSERT( (internal::is_compatible_ets<T, typename inter | |
| | | nal::strip<decltype(other)>::type>::value), "Maybe is_compatible_ets works | |
| | | incorrectly" ); | |
| | | #endif | |
| // Initialize my_construct_callback first, so that it is valid even
if rest of this routine throws an exception. | | // Initialize my_construct_callback first, so that it is valid even
if rest of this routine throws an exception. | |
| my_construct_callback = other.my_construct_callback->clone(); | | my_construct_callback = other.my_construct_callback->clone(); | |
| | | | |
| typedef internal::ets_base<ets_no_key> base; | | typedef internal::ets_base<ets_no_key> base; | |
| __TBB_ASSERT(my_locals.size()==0,NULL); | | __TBB_ASSERT(my_locals.size()==0,NULL); | |
| this->table_reserve_for_copy( other ); | | this->table_reserve_for_copy( other ); | |
| for( base::array* r=other.my_root; r; r=r->next ) { | | for( base::array* r=other.my_root; r; r=r->next ) { | |
| for( size_t i=0; i<r->size(); ++i ) { | | for( size_t i=0; i<r->size(); ++i ) { | |
| base::slot& s1 = r->at(i); | | base::slot& s1 = r->at(i); | |
| if( !s1.empty() ) { | | if( !s1.empty() ) { | |
| | | | |
End of changes. 36 change blocks. |
| 32 lines changed or deleted | | 149 lines changed or added | |
|
| flow_graph.h | | flow_graph.h | |
| | | | |
| skipping to change at line 33 | | skipping to change at line 33 | |
| | | | |
| #include "tbb_stddef.h" | | #include "tbb_stddef.h" | |
| #include "atomic.h" | | #include "atomic.h" | |
| #include "spin_mutex.h" | | #include "spin_mutex.h" | |
| #include "null_mutex.h" | | #include "null_mutex.h" | |
| #include "spin_rw_mutex.h" | | #include "spin_rw_mutex.h" | |
| #include "null_rw_mutex.h" | | #include "null_rw_mutex.h" | |
| #include "task.h" | | #include "task.h" | |
| #include "cache_aligned_allocator.h" | | #include "cache_aligned_allocator.h" | |
| #include "tbb_exception.h" | | #include "tbb_exception.h" | |
|
| | | #include "internal/_template_helpers.h" | |
| #include "internal/_aggregator_impl.h" | | #include "internal/_aggregator_impl.h" | |
| #include "tbb_profiling.h" | | #include "tbb_profiling.h" | |
| | | | |
| #if TBB_DEPRECATED_FLOW_ENQUEUE | | #if TBB_DEPRECATED_FLOW_ENQUEUE | |
| #define FLOW_SPAWN(a) tbb::task::enqueue((a)) | | #define FLOW_SPAWN(a) tbb::task::enqueue((a)) | |
| #else | | #else | |
| #define FLOW_SPAWN(a) tbb::task::spawn((a)) | | #define FLOW_SPAWN(a) tbb::task::spawn((a)) | |
| #endif | | #endif | |
| | | | |
| // use the VC10 or gcc version of tuple if it is available. | | // use the VC10 or gcc version of tuple if it is available. | |
| | | | |
| skipping to change at line 82 | | skipping to change at line 83 | |
| | | | |
| //! An enumeration the provides the two most common concurrency levels: unl
imited and serial | | //! An enumeration the provides the two most common concurrency levels: unl
imited and serial | |
| enum concurrency { unlimited = 0, serial = 1 }; | | enum concurrency { unlimited = 0, serial = 1 }; | |
| | | | |
| namespace interface7 { | | namespace interface7 { | |
| | | | |
| namespace internal { | | namespace internal { | |
| template<typename T, typename M> class successor_cache; | | template<typename T, typename M> class successor_cache; | |
| template<typename T, typename M> class broadcast_cache; | | template<typename T, typename M> class broadcast_cache; | |
| template<typename T, typename M> class round_robin_cache; | | template<typename T, typename M> class round_robin_cache; | |
|
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| | | template< typename C> class edge_container; | |
| | | #endif | |
| } | | } | |
| | | | |
|
| | | //A generic null type | |
| | | struct null_type {}; | |
| | | | |
| //! An empty class used for messages that mean "I'm done" | | //! An empty class used for messages that mean "I'm done" | |
| class continue_msg {}; | | class continue_msg {}; | |
| | | | |
| template< typename T > class sender; | | template< typename T > class sender; | |
| template< typename T > class receiver; | | template< typename T > class receiver; | |
| class continue_receiver; | | class continue_receiver; | |
| | | | |
| //! Pure virtual template class that defines a sender of messages of type T | | //! Pure virtual template class that defines a sender of messages of type T | |
| template< typename T > | | template< typename T > | |
| class sender { | | class sender { | |
| | | | |
| skipping to change at line 123 | | skipping to change at line 131 | |
| virtual bool try_reserve( T & ) { return false; } | | virtual bool try_reserve( T & ) { return false; } | |
| | | | |
| //! Releases the reserved item | | //! Releases the reserved item | |
| virtual bool try_release( ) { return false; } | | virtual bool try_release( ) { return false; } | |
| | | | |
| //! Consumes the reserved item | | //! Consumes the reserved item | |
| virtual bool try_consume( ) { return false; } | | virtual bool try_consume( ) { return false; } | |
| | | | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| //! interface to record edges for traversal & deletion | | //! interface to record edges for traversal & deletion | |
|
| | | typedef typename internal::edge_container<successor_type>::edge_list_t
ype successor_list_type; | |
| virtual void internal_add_built_successor( successor_type & ) = 0
; | | virtual void internal_add_built_successor( successor_type & ) = 0
; | |
| virtual void internal_delete_built_successor( successor_type & ) = 0
; | | virtual void internal_delete_built_successor( successor_type & ) = 0
; | |
|
| virtual void copy_successors( std::vector<successor_type *> &) = 0
; | | virtual void copy_successors( successor_list_type &) = 0
; | |
| virtual size_t successor_count() = 0
; | | virtual size_t successor_count() = 0
; | |
| #endif | | #endif | |
| }; | | }; | |
| | | | |
| template< typename T > class limiter_node; // needed for resetting decreme
nter | | template< typename T > class limiter_node; // needed for resetting decreme
nter | |
| template< typename R, typename B > class run_and_put_task; | | template< typename R, typename B > class run_and_put_task; | |
| | | | |
| static tbb::task * const SUCCESSFULLY_ENQUEUED = (task *)-1; | | static tbb::task * const SUCCESSFULLY_ENQUEUED = (task *)-1; | |
| | | | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| | | | |
| skipping to change at line 202 | | skipping to change at line 211 | |
| virtual task *try_put_task(const T& t) = 0; | | virtual task *try_put_task(const T& t) = 0; | |
| public: | | public: | |
| | | | |
| //! Add a predecessor to the node | | //! Add a predecessor to the node | |
| virtual bool register_predecessor( predecessor_type & ) { return false;
} | | virtual bool register_predecessor( predecessor_type & ) { return false;
} | |
| | | | |
| //! Remove a predecessor from the node | | //! Remove a predecessor from the node | |
| virtual bool remove_predecessor( predecessor_type & ) { return false; } | | virtual bool remove_predecessor( predecessor_type & ) { return false; } | |
| | | | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| | | typedef typename internal::edge_container<predecessor_type>::edge_list_
type predecessor_list_type; | |
| virtual void internal_add_built_predecessor( predecessor_type & )
= 0; | | virtual void internal_add_built_predecessor( predecessor_type & )
= 0; | |
| virtual void internal_delete_built_predecessor( predecessor_type & )
= 0; | | virtual void internal_delete_built_predecessor( predecessor_type & )
= 0; | |
|
| virtual void copy_predecessors( std::vector<predecessor_type *> & )
= 0; | | virtual void copy_predecessors( predecessor_list_type & )
= 0; | |
| virtual size_t predecessor_count()
= 0; | | virtual size_t predecessor_count()
= 0; | |
| #endif | | #endif | |
| | | | |
| protected: | | protected: | |
| //! put receiver back in initial state | | //! put receiver back in initial state | |
| template<typename U> friend class limiter_node; | | template<typename U> friend class limiter_node; | |
| virtual void reset_receiver(__TBB_PFG_RESET_ARG(reset_flags f = rf_rese
t_protocol ) ) = 0; | | virtual void reset_receiver(__TBB_PFG_RESET_ARG(reset_flags f = rf_rese
t_protocol ) ) = 0; | |
| | | | |
| template<typename TT, typename M> | | template<typename TT, typename M> | |
| friend class internal::successor_cache; | | friend class internal::successor_cache; | |
| virtual bool is_continue_receiver() { return false; } | | virtual bool is_continue_receiver() { return false; } | |
| }; | | }; | |
| | | | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| //* holder of edges both for caches and for those nodes which do not have p
redecessor caches. | | //* holder of edges both for caches and for those nodes which do not have p
redecessor caches. | |
| // C == receiver< ... > or sender< ... >, depending. | | // C == receiver< ... > or sender< ... >, depending. | |
|
| | | namespace internal { | |
| template<typename C> | | template<typename C> | |
| class edge_container { | | class edge_container { | |
| | | | |
| public: | | public: | |
|
| typedef std::vector<C *> edge_vector; | | typedef std::list<C *, tbb::tbb_allocator<C *> > edge_list_type; | |
| | | | |
| void add_edge( C &s) { | | void add_edge( C &s) { | |
| built_edges.push_back( &s ); | | built_edges.push_back( &s ); | |
| } | | } | |
| | | | |
| void delete_edge( C &s) { | | void delete_edge( C &s) { | |
|
| for ( typename edge_vector::iterator i = built_edges.begin(); i !=
built_edges.end(); ++i ) { | | for ( typename edge_list_type::iterator i = built_edges.begin(); i
!= built_edges.end(); ++i ) { | |
| if ( *i == &s ) { | | if ( *i == &s ) { | |
| (void)built_edges.erase(i); | | (void)built_edges.erase(i); | |
| return; // only remove one predecessor per request | | return; // only remove one predecessor per request | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
|
| void copy_edges( edge_vector &v) { | | void copy_edges( edge_list_type &v) { | |
| v = built_edges; | | v = built_edges; | |
| } | | } | |
| | | | |
| size_t edge_count() { | | size_t edge_count() { | |
| return (size_t)(built_edges.size()); | | return (size_t)(built_edges.size()); | |
| } | | } | |
| | | | |
| void clear() { | | void clear() { | |
| built_edges.clear(); | | built_edges.clear(); | |
| } | | } | |
| | | | |
| template< typename S > void sender_extract( S &s ); | | template< typename S > void sender_extract( S &s ); | |
| template< typename R > void receiver_extract( R &r ); | | template< typename R > void receiver_extract( R &r ); | |
| | | | |
| private: | | private: | |
|
| edge_vector built_edges; | | edge_list_type built_edges; | |
| }; | | }; | |
|
| | | } // namespace internal | |
| #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | | #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | |
| | | | |
| //! Base class for receivers of completion messages | | //! Base class for receivers of completion messages | |
| /** These receivers automatically reset, but cannot be explicitly waited on
*/ | | /** These receivers automatically reset, but cannot be explicitly waited on
*/ | |
| class continue_receiver : public receiver< continue_msg > { | | class continue_receiver : public receiver< continue_msg > { | |
| public: | | public: | |
| | | | |
| //! The input type | | //! The input type | |
| typedef continue_msg input_type; | | typedef continue_msg input_type; | |
| | | | |
| | | | |
| skipping to change at line 304 | | skipping to change at line 316 | |
| /** Does not check to see if the removal of the predecessor now makes t
he current count | | /** Does not check to see if the removal of the predecessor now makes t
he current count | |
| exceed the new threshold. So removing a predecessor while the grap
h is active can cause | | exceed the new threshold. So removing a predecessor while the grap
h is active can cause | |
| unexpected results. */ | | unexpected results. */ | |
| /* override */ bool remove_predecessor( predecessor_type & ) { | | /* override */ bool remove_predecessor( predecessor_type & ) { | |
| spin_mutex::scoped_lock l(my_mutex); | | spin_mutex::scoped_lock l(my_mutex); | |
| --my_predecessor_count; | | --my_predecessor_count; | |
| return true; | | return true; | |
| } | | } | |
| | | | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| typedef std::vector<predecessor_type *> predecessor_vector_type; | | typedef receiver<input_type>::predecessor_list_type predecessor_list_ty
pe; | |
| | | | |
| /*override*/ void internal_add_built_predecessor( predecessor_type &s)
{ | | /*override*/ void internal_add_built_predecessor( predecessor_type &s)
{ | |
| spin_mutex::scoped_lock l(my_mutex); | | spin_mutex::scoped_lock l(my_mutex); | |
| my_built_predecessors.add_edge( s ); | | my_built_predecessors.add_edge( s ); | |
| } | | } | |
| | | | |
| /*override*/ void internal_delete_built_predecessor( predecessor_type &
s) { | | /*override*/ void internal_delete_built_predecessor( predecessor_type &
s) { | |
| spin_mutex::scoped_lock l(my_mutex); | | spin_mutex::scoped_lock l(my_mutex); | |
| my_built_predecessors.delete_edge(s); | | my_built_predecessors.delete_edge(s); | |
| } | | } | |
| | | | |
|
| /*override*/ void copy_predecessors( predecessor_vector_type &v) { | | /*override*/ void copy_predecessors( predecessor_list_type &v) { | |
| spin_mutex::scoped_lock l(my_mutex); | | spin_mutex::scoped_lock l(my_mutex); | |
| my_built_predecessors.copy_edges(v); | | my_built_predecessors.copy_edges(v); | |
| } | | } | |
| | | | |
| /*override*/ size_t predecessor_count() { | | /*override*/ size_t predecessor_count() { | |
| spin_mutex::scoped_lock l(my_mutex); | | spin_mutex::scoped_lock l(my_mutex); | |
| return my_built_predecessors.edge_count(); | | return my_built_predecessors.edge_count(); | |
| } | | } | |
| #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | | #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | |
| | | | |
| | | | |
| skipping to change at line 346 | | skipping to change at line 358 | |
| return SUCCESSFULLY_ENQUEUED; | | return SUCCESSFULLY_ENQUEUED; | |
| else | | else | |
| my_current_count = 0; | | my_current_count = 0; | |
| } | | } | |
| task * res = execute(); | | task * res = execute(); | |
| if(!res) return SUCCESSFULLY_ENQUEUED; | | if(!res) return SUCCESSFULLY_ENQUEUED; | |
| return res; | | return res; | |
| } | | } | |
| | | | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| edge_container<predecessor_type> my_built_predecessors; | | internal::edge_container<predecessor_type> my_built_predecessors; | |
| #endif | | #endif | |
| spin_mutex my_mutex; | | spin_mutex my_mutex; | |
| int my_predecessor_count; | | int my_predecessor_count; | |
| int my_current_count; | | int my_current_count; | |
| int my_initial_predecessor_count; | | int my_initial_predecessor_count; | |
| // the friend declaration in the base class did not eliminate the "prot
ected class" | | // the friend declaration in the base class did not eliminate the "prot
ected class" | |
| // error in gcc 4.1.2 | | // error in gcc 4.1.2 | |
| template<typename U> friend class limiter_node; | | template<typename U> friend class limiter_node; | |
| /*override*/void reset_receiver( __TBB_PFG_RESET_ARG(reset_flags f) ) | | /*override*/void reset_receiver( __TBB_PFG_RESET_ARG(reset_flags f) ) | |
| { | | { | |
| | | | |
| skipping to change at line 767 | | skipping to change at line 779 | |
| class source_node : public graph_node, public sender< Output > { | | class source_node : public graph_node, public sender< Output > { | |
| protected: | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| //! The type of the output message, which is complete | | //! The type of the output message, which is complete | |
| typedef Output output_type; | | typedef Output output_type; | |
| | | | |
| //! The type of successors of this node | | //! The type of successors of this node | |
| typedef receiver< Output > successor_type; | | typedef receiver< Output > successor_type; | |
| | | | |
|
| | | //Source node has no input type | |
| | | typedef null_type input_type; | |
| | | | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| typedef std::vector<successor_type *> successor_vector_type; | | typedef typename sender<output_type>::successor_list_type successor_lis
t_type; | |
| #endif | | #endif | |
| | | | |
| //! Constructor for a node with a successor | | //! Constructor for a node with a successor | |
| template< typename Body > | | template< typename Body > | |
| source_node( graph &g, Body body, bool is_active = true ) | | source_node( graph &g, Body body, bool is_active = true ) | |
| : graph_node(g), my_active(is_active), init_my_active(is_active), | | : graph_node(g), my_active(is_active), init_my_active(is_active), | |
| my_body( new internal::source_body_leaf< output_type, Body>(body) )
, | | my_body( new internal::source_body_leaf< output_type, Body>(body) )
, | |
| my_reserved(false), my_has_cached_item(false) | | my_reserved(false), my_has_cached_item(false) | |
| { | | { | |
| my_successors.set_owner(this); | | my_successors.set_owner(this); | |
| | | | |
| skipping to change at line 836 | | skipping to change at line 851 | |
| /*override*/void internal_delete_built_successor( successor_type &r) { | | /*override*/void internal_delete_built_successor( successor_type &r) { | |
| spin_mutex::scoped_lock lock(my_mutex); | | spin_mutex::scoped_lock lock(my_mutex); | |
| my_successors.internal_delete_built_successor(r); | | my_successors.internal_delete_built_successor(r); | |
| } | | } | |
| | | | |
| /*override*/size_t successor_count() { | | /*override*/size_t successor_count() { | |
| spin_mutex::scoped_lock lock(my_mutex); | | spin_mutex::scoped_lock lock(my_mutex); | |
| return my_successors.successor_count(); | | return my_successors.successor_count(); | |
| } | | } | |
| | | | |
|
| /*override*/void copy_successors(successor_vector_type &v) { | | /*override*/void copy_successors(successor_list_type &v) { | |
| spin_mutex::scoped_lock l(my_mutex); | | spin_mutex::scoped_lock l(my_mutex); | |
| my_successors.copy_successors(v); | | my_successors.copy_successors(v); | |
| } | | } | |
| #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | | #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | |
| | | | |
| //! Request an item from the node | | //! Request an item from the node | |
| /*override */ bool try_get( output_type &v ) { | | /*override */ bool try_get( output_type &v ) { | |
| spin_mutex::scoped_lock lock(my_mutex); | | spin_mutex::scoped_lock lock(my_mutex); | |
| if ( my_reserved ) | | if ( my_reserved ) | |
| return false; | | return false; | |
| | | | |
| skipping to change at line 998 | | skipping to change at line 1013 | |
| protected: | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| typedef Input input_type; | | typedef Input input_type; | |
| typedef Output output_type; | | typedef Output output_type; | |
| typedef sender< input_type > predecessor_type; | | typedef sender< input_type > predecessor_type; | |
| typedef receiver< output_type > successor_type; | | typedef receiver< output_type > successor_type; | |
| typedef internal::function_input<input_type,output_type,Allocator> fInp
ut_type; | | typedef internal::function_input<input_type,output_type,Allocator> fInp
ut_type; | |
| typedef internal::function_output<output_type> fOutput_type; | | typedef internal::function_output<output_type> fOutput_type; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| using typename internal::function_input<Input,Output,Allocator>::predec | | using typename internal::function_input<Input,Output,Allocator>::predec | |
| essor_vector_type; | | essor_list_type; | |
| using typename internal::function_output<Output>::successor_vector_type | | using typename internal::function_output<Output>::successor_list_type; | |
| ; | | | |
| #endif | | #endif | |
| | | | |
| //! Constructor | | //! Constructor | |
| template< typename Body > | | template< typename Body > | |
| function_node( graph &g, size_t concurrency, Body body ) : | | function_node( graph &g, size_t concurrency, Body body ) : | |
| graph_node(g), internal::function_input<input_type,output_type,Allo
cator>(g, concurrency, body) { | | graph_node(g), internal::function_input<input_type,output_type,Allo
cator>(g, concurrency, body) { | |
| tbb::internal::fgt_node_with_body( tbb::internal::FLOW_FUNCTION_NOD
E, &this->graph_node::my_graph, static_cast<receiver<input_type> *>(this), | | tbb::internal::fgt_node_with_body( tbb::internal::FLOW_FUNCTION_NOD
E, &this->graph_node::my_graph, static_cast<receiver<input_type> *>(this), | |
| static_cast<sender<output_type>
*>(this), this->my_body ); | | static_cast<sender<output_type>
*>(this), this->my_body ); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 1057 | | skipping to change at line 1072 | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| typedef Input input_type; | | typedef Input input_type; | |
| typedef Output output_type; | | typedef Output output_type; | |
| typedef sender< input_type > predecessor_type; | | typedef sender< input_type > predecessor_type; | |
| typedef receiver< output_type > successor_type; | | typedef receiver< output_type > successor_type; | |
| typedef internal::function_input<input_type,output_type,Allocator> fInp
ut_type; | | typedef internal::function_input<input_type,output_type,Allocator> fInp
ut_type; | |
| typedef internal::function_input_queue<input_type, Allocator> queue_typ
e; | | typedef internal::function_input_queue<input_type, Allocator> queue_typ
e; | |
| typedef internal::function_output<output_type> fOutput_type; | | typedef internal::function_output<output_type> fOutput_type; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| using typename internal::function_input<Input,Output,Allocator>::predec | | using typename internal::function_input<Input,Output,Allocator>::predec | |
| essor_vector_type; | | essor_list_type; | |
| using typename internal::function_output<Output>::successor_vector_type | | using typename internal::function_output<Output>::successor_list_type; | |
| ; | | | |
| #endif | | #endif | |
| | | | |
| //! Constructor | | //! Constructor | |
| template< typename Body > | | template< typename Body > | |
| function_node( graph &g, size_t concurrency, Body body ) : | | function_node( graph &g, size_t concurrency, Body body ) : | |
| graph_node(g), fInput_type( g, concurrency, body, new queue_type()
) { | | graph_node(g), fInput_type( g, concurrency, body, new queue_type()
) { | |
| tbb::internal::fgt_node_with_body( tbb::internal::FLOW_FUNCTION_NOD
E, &this->graph_node::my_graph, static_cast<receiver<input_type> *>(this), | | tbb::internal::fgt_node_with_body( tbb::internal::FLOW_FUNCTION_NOD
E, &this->graph_node::my_graph, static_cast<receiver<input_type> *>(this), | |
| static_cast<sender<output_type>
*>(this), this->my_body ); | | static_cast<sender<output_type>
*>(this), this->my_body ); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 1122 | | skipping to change at line 1137 | |
| Output // the tuple providing the types | | Output // the tuple providing the types | |
| >::type, | | >::type, | |
| Allocator | | Allocator | |
| > { | | > { | |
| protected: | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| private: | | private: | |
| static const int N = tbb::flow::tuple_size<Output>::value; | | static const int N = tbb::flow::tuple_size<Output>::value; | |
| public: | | public: | |
| typedef Input input_type; | | typedef Input input_type; | |
|
| | | typedef null_type output_type; | |
| typedef typename internal::wrap_tuple_elements<N,internal::multifunctio
n_output, Output>::type output_ports_type; | | typedef typename internal::wrap_tuple_elements<N,internal::multifunctio
n_output, Output>::type output_ports_type; | |
| private: | | private: | |
| typedef typename internal::multifunction_input<input_type, output_ports
_type, Allocator> base_type; | | typedef typename internal::multifunction_input<input_type, output_ports
_type, Allocator> base_type; | |
| typedef typename internal::function_input_queue<input_type,Allocator> q
ueue_type; | | typedef typename internal::function_input_queue<input_type,Allocator> q
ueue_type; | |
| public: | | public: | |
| template<typename Body> | | template<typename Body> | |
| multifunction_node( graph &g, size_t concurrency, Body body ) : | | multifunction_node( graph &g, size_t concurrency, Body body ) : | |
| graph_node(g), base_type(g,concurrency, body) { | | graph_node(g), base_type(g,concurrency, body) { | |
| tbb::internal::fgt_multioutput_node_with_body<Output,N>( tbb::inter
nal::FLOW_MULTIFUNCTION_NODE, | | tbb::internal::fgt_multioutput_node_with_body<Output,N>( tbb::inter
nal::FLOW_MULTIFUNCTION_NODE, | |
| &this->gra
ph_node::my_graph, static_cast<receiver<input_type> *>(this), | | &this->gra
ph_node::my_graph, static_cast<receiver<input_type> *>(this), | |
| | | | |
| skipping to change at line 1161 | | skipping to change at line 1177 | |
| }; // multifunction_node | | }; // multifunction_node | |
| | | | |
| template < typename Input, typename Output, typename Allocator > | | template < typename Input, typename Output, typename Allocator > | |
| class multifunction_node<Input,Output,queueing,Allocator> : public graph_no
de, public internal::multifunction_input<Input, | | class multifunction_node<Input,Output,queueing,Allocator> : public graph_no
de, public internal::multifunction_input<Input, | |
| typename internal::wrap_tuple_elements<tbb::flow::tuple_size<Output>::v
alue, internal::multifunction_output, Output>::type, Allocator> { | | typename internal::wrap_tuple_elements<tbb::flow::tuple_size<Output>::v
alue, internal::multifunction_output, Output>::type, Allocator> { | |
| protected: | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| static const int N = tbb::flow::tuple_size<Output>::value; | | static const int N = tbb::flow::tuple_size<Output>::value; | |
| public: | | public: | |
| typedef Input input_type; | | typedef Input input_type; | |
|
| | | typedef null_type output_type; | |
| typedef typename internal::wrap_tuple_elements<N, internal::multifuncti
on_output, Output>::type output_ports_type; | | typedef typename internal::wrap_tuple_elements<N, internal::multifuncti
on_output, Output>::type output_ports_type; | |
| private: | | private: | |
| typedef typename internal::multifunction_input<input_type, output_ports
_type, Allocator> base_type; | | typedef typename internal::multifunction_input<input_type, output_ports
_type, Allocator> base_type; | |
| typedef typename internal::function_input_queue<input_type,Allocator> q
ueue_type; | | typedef typename internal::function_input_queue<input_type,Allocator> q
ueue_type; | |
| public: | | public: | |
| template<typename Body> | | template<typename Body> | |
| multifunction_node( graph &g, size_t concurrency, Body body) : | | multifunction_node( graph &g, size_t concurrency, Body body) : | |
| graph_node(g), base_type(g,concurrency, body, new queue_type()) { | | graph_node(g), base_type(g,concurrency, body, new queue_type()) { | |
| tbb::internal::fgt_multioutput_node_with_body<Output,N>( tbb::inter
nal::FLOW_MULTIFUNCTION_NODE, | | tbb::internal::fgt_multioutput_node_with_body<Output,N>( tbb::inter
nal::FLOW_MULTIFUNCTION_NODE, | |
| &this->gra
ph_node::my_graph, static_cast<receiver<input_type> *>(this), | | &this->gra
ph_node::my_graph, static_cast<receiver<input_type> *>(this), | |
| | | | |
| skipping to change at line 1201 | | skipping to change at line 1218 | |
| | | | |
| //! split_node: accepts a tuple as input, forwards each element of the tupl
e to its | | //! split_node: accepts a tuple as input, forwards each element of the tupl
e to its | |
| // successors. The node has unlimited concurrency, so though it is marked
as | | // successors. The node has unlimited concurrency, so though it is marked
as | |
| // "rejecting" it does not reject inputs. | | // "rejecting" it does not reject inputs. | |
| template<typename TupleType, typename Allocator=cache_aligned_allocator<Tup
leType> > | | template<typename TupleType, typename Allocator=cache_aligned_allocator<Tup
leType> > | |
| class split_node : public multifunction_node<TupleType, TupleType, rejectin
g, Allocator> { | | class split_node : public multifunction_node<TupleType, TupleType, rejectin
g, Allocator> { | |
| static const int N = tbb::flow::tuple_size<TupleType>::value; | | static const int N = tbb::flow::tuple_size<TupleType>::value; | |
| typedef multifunction_node<TupleType,TupleType,rejecting,Allocator> bas
e_type; | | typedef multifunction_node<TupleType,TupleType,rejecting,Allocator> bas
e_type; | |
| public: | | public: | |
| typedef typename base_type::output_ports_type output_ports_type; | | typedef typename base_type::output_ports_type output_ports_type; | |
|
| | | typedef typename base_type::output_type output_type; | |
| private: | | private: | |
| struct splitting_body { | | struct splitting_body { | |
| void operator()(const TupleType& t, output_ports_type &p) { | | void operator()(const TupleType& t, output_ports_type &p) { | |
| internal::emit_element<N>::emit_this(t, p); | | internal::emit_element<N>::emit_this(t, p); | |
| } | | } | |
| }; | | }; | |
| public: | | public: | |
| typedef TupleType input_type; | | typedef TupleType input_type; | |
| typedef Allocator allocator_type; | | typedef Allocator allocator_type; | |
| split_node(graph &g) : base_type(g, unlimited, splitting_body()) { | | split_node(graph &g) : base_type(g, unlimited, splitting_body()) { | |
| | | | |
| skipping to change at line 1301 | | skipping to change at line 1319 | |
| template< typename T > | | template< typename T > | |
| class overwrite_node : public graph_node, public receiver<T>, public sender
<T> { | | class overwrite_node : public graph_node, public receiver<T>, public sender
<T> { | |
| protected: | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| typedef T input_type; | | typedef T input_type; | |
| typedef T output_type; | | typedef T output_type; | |
| typedef sender< input_type > predecessor_type; | | typedef sender< input_type > predecessor_type; | |
| typedef receiver< output_type > successor_type; | | typedef receiver< output_type > successor_type; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| typedef std::vector<predecessor_type *> predecessor_vector_type; | | typedef typename receiver<input_type>::predecessor_list_type predecesso | |
| typedef std::vector<successor_type *> successor_vector_type; | | r_list_type; | |
| | | typedef typename sender<output_type>::successor_list_type successor_lis | |
| | | t_type; | |
| #endif | | #endif | |
| | | | |
| overwrite_node(graph &g) : graph_node(g), my_buffer_is_valid(false) { | | overwrite_node(graph &g) : graph_node(g), my_buffer_is_valid(false) { | |
| my_successors.set_owner( this ); | | my_successors.set_owner( this ); | |
| tbb::internal::fgt_node( tbb::internal::FLOW_OVERWRITE_NODE, &this-
>my_graph, | | tbb::internal::fgt_node( tbb::internal::FLOW_OVERWRITE_NODE, &this-
>my_graph, | |
| static_cast<receiver<input_type> *>(this),
static_cast<sender<output_type> *>(this) ); | | static_cast<receiver<input_type> *>(this),
static_cast<sender<output_type> *>(this) ); | |
| } | | } | |
| | | | |
| // Copy constructor; doesn't take anything from src; default won't work | | // Copy constructor; doesn't take anything from src; default won't work | |
| overwrite_node( const overwrite_node& src ) : | | overwrite_node( const overwrite_node& src ) : | |
| | | | |
| skipping to change at line 1369 | | skipping to change at line 1387 | |
| /*override*/void internal_delete_built_successor( successor_type &s) { | | /*override*/void internal_delete_built_successor( successor_type &s) { | |
| spin_mutex::scoped_lock l( my_mutex ); | | spin_mutex::scoped_lock l( my_mutex ); | |
| my_successors.internal_delete_built_successor(s); | | my_successors.internal_delete_built_successor(s); | |
| } | | } | |
| | | | |
| /*override*/size_t successor_count() { | | /*override*/size_t successor_count() { | |
| spin_mutex::scoped_lock l( my_mutex ); | | spin_mutex::scoped_lock l( my_mutex ); | |
| return my_successors.successor_count(); | | return my_successors.successor_count(); | |
| } | | } | |
| | | | |
|
| /*override*/ void copy_successors(successor_vector_type &v) { | | /*override*/ void copy_successors(successor_list_type &v) { | |
| spin_mutex::scoped_lock l( my_mutex ); | | spin_mutex::scoped_lock l( my_mutex ); | |
| my_successors.copy_successors(v); | | my_successors.copy_successors(v); | |
| } | | } | |
| | | | |
| /*override*/ void internal_add_built_predecessor( predecessor_type &p)
{ | | /*override*/ void internal_add_built_predecessor( predecessor_type &p)
{ | |
| spin_mutex::scoped_lock l( my_mutex ); | | spin_mutex::scoped_lock l( my_mutex ); | |
| my_built_predecessors.add_edge(p); | | my_built_predecessors.add_edge(p); | |
| } | | } | |
| | | | |
| /*override*/ void internal_delete_built_predecessor( predecessor_type &
p) { | | /*override*/ void internal_delete_built_predecessor( predecessor_type &
p) { | |
| spin_mutex::scoped_lock l( my_mutex ); | | spin_mutex::scoped_lock l( my_mutex ); | |
| my_built_predecessors.delete_edge(p); | | my_built_predecessors.delete_edge(p); | |
| } | | } | |
| | | | |
| /*override*/size_t predecessor_count() { | | /*override*/size_t predecessor_count() { | |
| spin_mutex::scoped_lock l( my_mutex ); | | spin_mutex::scoped_lock l( my_mutex ); | |
| return my_built_predecessors.edge_count(); | | return my_built_predecessors.edge_count(); | |
| } | | } | |
| | | | |
|
| /*override*/void copy_predecessors(predecessor_vector_type &v) { | | /*override*/void copy_predecessors(predecessor_list_type &v) { | |
| spin_mutex::scoped_lock l( my_mutex ); | | spin_mutex::scoped_lock l( my_mutex ); | |
| my_built_predecessors.copy_edges(v); | | my_built_predecessors.copy_edges(v); | |
| } | | } | |
| #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | | #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | |
| | | | |
| /* override */ bool try_get( input_type &v ) { | | /* override */ bool try_get( input_type &v ) { | |
| spin_mutex::scoped_lock l( my_mutex ); | | spin_mutex::scoped_lock l( my_mutex ); | |
| if ( my_buffer_is_valid ) { | | if ( my_buffer_is_valid ) { | |
| v = my_buffer; | | v = my_buffer; | |
| return true; | | return true; | |
| | | | |
| skipping to change at line 1440 | | skipping to change at line 1458 | |
| my_successors.reset(f); | | my_successors.reset(f); | |
| if (f&rf_extract) { | | if (f&rf_extract) { | |
| my_built_predecessors.receiver_extract(*this); | | my_built_predecessors.receiver_extract(*this); | |
| } | | } | |
| #endif | | #endif | |
| } | | } | |
| | | | |
| spin_mutex my_mutex; | | spin_mutex my_mutex; | |
| internal::broadcast_cache< input_type, null_rw_mutex > my_successors; | | internal::broadcast_cache< input_type, null_rw_mutex > my_successors; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| edge_container<sender<input_type> > my_built_predecessors; | | internal::edge_container<predecessor_type> my_built_predecessors; | |
| #endif | | #endif | |
| input_type my_buffer; | | input_type my_buffer; | |
| bool my_buffer_is_valid; | | bool my_buffer_is_valid; | |
| /*override*/void reset_receiver(__TBB_PFG_RESET_ARG(reset_flags /*f*/))
{} | | /*override*/void reset_receiver(__TBB_PFG_RESET_ARG(reset_flags /*f*/))
{} | |
| }; // overwrite_node | | }; // overwrite_node | |
| | | | |
| template< typename T > | | template< typename T > | |
| class write_once_node : public overwrite_node<T> { | | class write_once_node : public overwrite_node<T> { | |
| public: | | public: | |
| typedef T input_type; | | typedef T input_type; | |
| | | | |
| skipping to change at line 1504 | | skipping to change at line 1522 | |
| template <typename T> | | template <typename T> | |
| class broadcast_node : public graph_node, public receiver<T>, public sender
<T> { | | class broadcast_node : public graph_node, public receiver<T>, public sender
<T> { | |
| protected: | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| typedef T input_type; | | typedef T input_type; | |
| typedef T output_type; | | typedef T output_type; | |
| typedef sender< input_type > predecessor_type; | | typedef sender< input_type > predecessor_type; | |
| typedef receiver< output_type > successor_type; | | typedef receiver< output_type > successor_type; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| typedef std::vector<predecessor_type *> predecessor_vector_type; | | typedef typename receiver<input_type>::predecessor_list_type predecesso | |
| typedef std::vector<successor_type *> successor_vector_type; | | r_list_type; | |
| | | typedef typename sender<output_type>::successor_list_type successor_lis | |
| | | t_type; | |
| #endif | | #endif | |
| private: | | private: | |
| internal::broadcast_cache<input_type> my_successors; | | internal::broadcast_cache<input_type> my_successors; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| edge_container<predecessor_type> my_built_predecessors; | | internal::edge_container<predecessor_type> my_built_predecessors; | |
| spin_mutex pred_mutex; | | spin_mutex pred_mutex; | |
| #endif | | #endif | |
| public: | | public: | |
| | | | |
| broadcast_node(graph& g) : graph_node(g) { | | broadcast_node(graph& g) : graph_node(g) { | |
| my_successors.set_owner( this ); | | my_successors.set_owner( this ); | |
| tbb::internal::fgt_node( tbb::internal::FLOW_BROADCAST_NODE, &this-
>my_graph, | | tbb::internal::fgt_node( tbb::internal::FLOW_BROADCAST_NODE, &this-
>my_graph, | |
| static_cast<receiver<input_type> *>(this),
static_cast<sender<output_type> *>(this) ); | | static_cast<receiver<input_type> *>(this),
static_cast<sender<output_type> *>(this) ); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 1561 | | skipping to change at line 1579 | |
| } | | } | |
| | | | |
| /*override*/ void internal_delete_built_successor(successor_type &r) { | | /*override*/ void internal_delete_built_successor(successor_type &r) { | |
| my_successors.internal_delete_built_successor(r); | | my_successors.internal_delete_built_successor(r); | |
| } | | } | |
| | | | |
| /*override*/ size_t successor_count() { | | /*override*/ size_t successor_count() { | |
| return my_successors.successor_count(); | | return my_successors.successor_count(); | |
| } | | } | |
| | | | |
|
| /*override*/ void copy_successors(successor_vector_type &v) { | | /*override*/ void copy_successors(successor_list_type &v) { | |
| my_successors.copy_successors(v); | | my_successors.copy_successors(v); | |
| } | | } | |
| | | | |
| /*override*/ void internal_add_built_predecessor( predecessor_type &p)
{ | | /*override*/ void internal_add_built_predecessor( predecessor_type &p)
{ | |
| my_built_predecessors.add_edge(p); | | my_built_predecessors.add_edge(p); | |
| } | | } | |
| | | | |
| /*override*/ void internal_delete_built_predecessor( predecessor_type &
p) { | | /*override*/ void internal_delete_built_predecessor( predecessor_type &
p) { | |
| my_built_predecessors.delete_edge(p); | | my_built_predecessors.delete_edge(p); | |
| } | | } | |
| | | | |
| /*override*/ size_t predecessor_count() { | | /*override*/ size_t predecessor_count() { | |
| return my_built_predecessors.edge_count(); | | return my_built_predecessors.edge_count(); | |
| } | | } | |
| | | | |
|
| /*override*/ void copy_predecessors(predecessor_vector_type &v) { | | /*override*/ void copy_predecessors(predecessor_list_type &v) { | |
| my_built_predecessors.copy_edges(v); | | my_built_predecessors.copy_edges(v); | |
| } | | } | |
| #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | | #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | |
| | | | |
| protected: | | protected: | |
| template< typename R, typename B > friend class run_and_put_task; | | template< typename R, typename B > friend class run_and_put_task; | |
| template<typename X, typename Y> friend class internal::broadcast_cache
; | | template<typename X, typename Y> friend class internal::broadcast_cache
; | |
| template<typename X, typename Y> friend class internal::round_robin_cac
he; | | template<typename X, typename Y> friend class internal::round_robin_cac
he; | |
| //! build a task to run the successor if possible. Default is old beha
vior. | | //! build a task to run the successor if possible. Default is old beha
vior. | |
| /*override*/ task *try_put_task(const T& t) { | | /*override*/ task *try_put_task(const T& t) { | |
| | | | |
| skipping to change at line 1617 | | skipping to change at line 1635 | |
| class buffer_node : public graph_node, public internal::reservable_item_buf
fer<T, A>, public receiver<T>, public sender<T> { | | class buffer_node : public graph_node, public internal::reservable_item_buf
fer<T, A>, public receiver<T>, public sender<T> { | |
| protected: | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| typedef T input_type; | | typedef T input_type; | |
| typedef T output_type; | | typedef T output_type; | |
| typedef sender< input_type > predecessor_type; | | typedef sender< input_type > predecessor_type; | |
| typedef receiver< output_type > successor_type; | | typedef receiver< output_type > successor_type; | |
| typedef buffer_node<T, A> my_class; | | typedef buffer_node<T, A> my_class; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| typedef std::vector<predecessor_type *> predecessor_vector_type; | | typedef typename receiver<input_type>::predecessor_list_type predecesso | |
| typedef std::vector<successor_type *> successor_vector_type; | | r_list_type; | |
| | | typedef typename sender<output_type>::successor_list_type successor_lis | |
| | | t_type; | |
| #endif | | #endif | |
| protected: | | protected: | |
| typedef size_t size_type; | | typedef size_t size_type; | |
| internal::round_robin_cache< T, null_rw_mutex > my_successors; | | internal::round_robin_cache< T, null_rw_mutex > my_successors; | |
| | | | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| edge_container<predecessor_type> my_built_predecessors; | | internal::edge_container<predecessor_type> my_built_predecessors; | |
| #endif | | #endif | |
| | | | |
| friend class internal::forward_task_bypass< buffer_node< T, A > >; | | friend class internal::forward_task_bypass< buffer_node< T, A > >; | |
| | | | |
| enum op_type {reg_succ, rem_succ, req_item, res_item, rel_res, con_res,
put_item, try_fwd_task | | enum op_type {reg_succ, rem_succ, req_item, res_item, rel_res, con_res,
put_item, try_fwd_task | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| , add_blt_succ, del_blt_succ, | | , add_blt_succ, del_blt_succ, | |
| add_blt_pred, del_blt_pred, | | add_blt_pred, del_blt_pred, | |
| blt_succ_cnt, blt_pred_cnt, | | blt_succ_cnt, blt_pred_cnt, | |
| blt_succ_cpy, blt_pred_cpy // create vector copies of preds and s
uccs | | blt_succ_cpy, blt_pred_cpy // create vector copies of preds and s
uccs | |
| | | | |
| skipping to change at line 1651 | | skipping to change at line 1669 | |
| class buffer_operation : public internal::aggregated_operation< buffer_
operation > { | | class buffer_operation : public internal::aggregated_operation< buffer_
operation > { | |
| public: | | public: | |
| char type; | | char type; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| task * ltask; | | task * ltask; | |
| union { | | union { | |
| input_type *elem; | | input_type *elem; | |
| successor_type *r; | | successor_type *r; | |
| predecessor_type *p; | | predecessor_type *p; | |
| size_t cnt_val; | | size_t cnt_val; | |
|
| successor_vector_type *svec; | | successor_list_type *svec; | |
| predecessor_vector_type *pvec; | | predecessor_list_type *pvec; | |
| }; | | }; | |
| #else | | #else | |
| T *elem; | | T *elem; | |
| task * ltask; | | task * ltask; | |
| successor_type *r; | | successor_type *r; | |
| #endif | | #endif | |
| buffer_operation(const T& e, op_type t) : type(char(t)) | | buffer_operation(const T& e, op_type t) : type(char(t)) | |
| | | | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| , ltask(NULL), elem(const
_cast<T*>(&e)) | | , ltask(NULL), elem(const
_cast<T*>(&e)) | |
| | | | |
| skipping to change at line 1941 | | skipping to change at line 1959 | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| return op_data.cnt_val; | | return op_data.cnt_val; | |
| } | | } | |
| | | | |
| /*override*/ size_t successor_count() { | | /*override*/ size_t successor_count() { | |
| buffer_operation op_data(blt_succ_cnt); | | buffer_operation op_data(blt_succ_cnt); | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| return op_data.cnt_val; | | return op_data.cnt_val; | |
| } | | } | |
| | | | |
|
| /*override*/ void copy_predecessors( predecessor_vector_type &v ) { | | /*override*/ void copy_predecessors( predecessor_list_type &v ) { | |
| buffer_operation op_data(blt_pred_cpy); | | buffer_operation op_data(blt_pred_cpy); | |
| op_data.pvec = &v; | | op_data.pvec = &v; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| } | | } | |
| | | | |
|
| /*override*/ void copy_successors( successor_vector_type &v ) { | | /*override*/ void copy_successors( successor_list_type &v ) { | |
| buffer_operation op_data(blt_succ_cpy); | | buffer_operation op_data(blt_succ_cpy); | |
| op_data.svec = &v; | | op_data.svec = &v; | |
| my_aggregator.execute(&op_data); | | my_aggregator.execute(&op_data); | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| //! Removes a successor. | | //! Removes a successor. | |
| /** Removes successor r from the list of successors. | | /** Removes successor r from the list of successors. | |
| It also calls r.remove_predecessor(*this) to remove this node as a
predecessor. */ | | It also calls r.remove_predecessor(*this) to remove this node as a
predecessor. */ | |
| /* override */ bool remove_successor( successor_type &r ) { | | /* override */ bool remove_successor( successor_type &r ) { | |
| | | | |
| skipping to change at line 2487 | | skipping to change at line 2505 | |
| template< typename T > | | template< typename T > | |
| class limiter_node : public graph_node, public receiver< T >, public sender
< T > { | | class limiter_node : public graph_node, public receiver< T >, public sender
< T > { | |
| protected: | | protected: | |
| using graph_node::my_graph; | | using graph_node::my_graph; | |
| public: | | public: | |
| typedef T input_type; | | typedef T input_type; | |
| typedef T output_type; | | typedef T output_type; | |
| typedef sender< input_type > predecessor_type; | | typedef sender< input_type > predecessor_type; | |
| typedef receiver< output_type > successor_type; | | typedef receiver< output_type > successor_type; | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
|
| typedef std::vector<successor_type *> successor_vector_type; | | typedef typename receiver<input_type>::predecessor_list_type predecesso | |
| typedef std::vector<predecessor_type *> predecessor_vector_type; | | r_list_type; | |
| | | typedef typename sender<output_type>::successor_list_type successor_lis | |
| | | t_type; | |
| #endif | | #endif | |
| | | | |
| private: | | private: | |
| size_t my_threshold; | | size_t my_threshold; | |
| size_t my_count; //number of successful puts | | size_t my_count; //number of successful puts | |
| size_t my_tries; //number of active put attempts | | size_t my_tries; //number of active put attempts | |
| internal::reservable_predecessor_cache< T, spin_mutex > my_predecessors
; | | internal::reservable_predecessor_cache< T, spin_mutex > my_predecessors
; | |
| spin_mutex my_mutex; | | spin_mutex my_mutex; | |
| internal::broadcast_cache< T > my_successors; | | internal::broadcast_cache< T > my_successors; | |
| int init_decrement_predecessors; | | int init_decrement_predecessors; | |
| | | | |
| skipping to change at line 2652 | | skipping to change at line 2670 | |
| /*override*/void internal_add_built_successor(receiver<output_type> &sr
c) { | | /*override*/void internal_add_built_successor(receiver<output_type> &sr
c) { | |
| my_successors.internal_add_built_successor(src); | | my_successors.internal_add_built_successor(src); | |
| } | | } | |
| | | | |
| /*override*/void internal_delete_built_successor(receiver<output_type>
&src) { | | /*override*/void internal_delete_built_successor(receiver<output_type>
&src) { | |
| my_successors.internal_delete_built_successor(src); | | my_successors.internal_delete_built_successor(src); | |
| } | | } | |
| | | | |
| /*override*/size_t successor_count() { return my_successors.successor_c
ount(); } | | /*override*/size_t successor_count() { return my_successors.successor_c
ount(); } | |
| | | | |
|
| /*override*/ void copy_successors(successor_vector_type &v) { | | /*override*/ void copy_successors(successor_list_type &v) { | |
| my_successors.copy_successors(v); | | my_successors.copy_successors(v); | |
| } | | } | |
| | | | |
| /*override*/void internal_add_built_predecessor(sender<output_type> &sr
c) { | | /*override*/void internal_add_built_predecessor(sender<output_type> &sr
c) { | |
| my_predecessors.internal_add_built_predecessor(src); | | my_predecessors.internal_add_built_predecessor(src); | |
| } | | } | |
| | | | |
| /*override*/void internal_delete_built_predecessor(sender<output_type>
&src) { | | /*override*/void internal_delete_built_predecessor(sender<output_type>
&src) { | |
| my_predecessors.internal_delete_built_predecessor(src); | | my_predecessors.internal_delete_built_predecessor(src); | |
| } | | } | |
| | | | |
| /*override*/size_t predecessor_count() { return my_predecessors.predece
ssor_count(); } | | /*override*/size_t predecessor_count() { return my_predecessors.predece
ssor_count(); } | |
| | | | |
|
| /*override*/ void copy_predecessors(predecessor_vector_type &v) { | | /*override*/ void copy_predecessors(predecessor_list_type &v) { | |
| my_predecessors.copy_predecessors(v); | | my_predecessors.copy_predecessors(v); | |
| } | | } | |
| #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | | #endif /* TBB_PREVIEW_FLOW_GRAPH_FEATURES */ | |
| | | | |
| //! Adds src to the list of cached predecessors. | | //! Adds src to the list of cached predecessors. | |
| /* override */ bool register_predecessor( predecessor_type &src ) { | | /* override */ bool register_predecessor( predecessor_type &src ) { | |
| spin_mutex::scoped_lock lock(my_mutex); | | spin_mutex::scoped_lock lock(my_mutex); | |
| my_predecessors.add( src ); | | my_predecessors.add( src ); | |
| task* tp = this->my_graph.root_task(); | | task* tp = this->my_graph.root_task(); | |
| if ( my_count + my_tries < my_threshold && !my_successors.empty() &
& tp ) { | | if ( my_count + my_tries < my_threshold && !my_successors.empty() &
& tp ) { | |
| | | | |
| skipping to change at line 2889 | | skipping to change at line 2907 | |
| /* 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 | |
| | | | |
| }; | | }; | |
| | | | |
| // indexer node | | // indexer node | |
| #include "internal/_flow_graph_indexer_impl.h" | | #include "internal/_flow_graph_indexer_impl.h" | |
| | | | |
|
| struct indexer_null_type {}; | | template<typename T0, typename T1=null_type, typename T2=null_type, typenam | |
| | | e T3=null_type, | |
| template<typename T0, typename T1=indexer_null_type, typename T2=indexer_nu | | typename T4=null_type, typename T5=null_type, typenam | |
| ll_type, typename T3=indexer_null_type, | | e T6=null_type, | |
| typename T4=indexer_null_type, typename T5=indexer_nu | | typename T7=null_type, typename T8=null_type, typenam | |
| ll_type, typename T6=indexer_null_type, | | e T9=null_type> class indexer_node; | |
| typename T7=indexer_null_type, typename T8=indexer_nu | | | |
| ll_type, typename T9=indexer_null_type> class indexer_node; | | | |
| | | | |
| //indexer node specializations | | //indexer node specializations | |
| template<typename T0> | | template<typename T0> | |
| class indexer_node<T0> : public internal::unfolded_indexer_node<tuple<T0> >
{ | | class indexer_node<T0> : public internal::unfolded_indexer_node<tuple<T0> >
{ | |
| private: | | private: | |
| static const int N = 1; | | static const int N = 1; | |
| public: | | public: | |
| typedef tuple<T0> InputTuple; | | typedef tuple<T0> InputTuple; | |
| typedef typename internal::tagged_msg<size_t, T0> output_type; | | typedef typename internal::tagged_msg<size_t, T0> output_type; | |
| typedef typename internal::unfolded_indexer_node<InputTuple> unfolded_t
ype; | | typedef typename internal::unfolded_indexer_node<InputTuple> unfolded_t
ype; | |
| | | | |
| skipping to change at line 3171 | | skipping to change at line 3187 | |
| 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 ) { | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| s.internal_add_built_predecessor(p); | | s.internal_add_built_predecessor(p); | |
| p.internal_add_built_successor(s); | | p.internal_add_built_successor(s); | |
| #endif | | #endif | |
| 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 | | #if __TBB_PREVIEW_COMPOSITE_NODE | |
| | | //Makes an edge from port 0 of a multi-output predecessor to port 0 of a mu | |
| | | lti-input successor. | |
| | | template< typename T, typename V, | |
| | | bool = tbb::internal::is_same_type< typename tuple_element<0,type | |
| | | name T::output_ports_type>::type, | |
| | | typename tuple_element<0,type | |
| | | name V::input_ports_type>::type | |
| | | >::value > | |
| | | inline void make_edge( T& output, V& input) { | |
| | | make_edge(get<0>(output.output_ports()), get<0>(input.input_ports())); | |
| | | } | |
| | | | |
| | | //Makes an edge from port 0 of a multi-output predecessor to a receiver. | |
| | | template< typename T, typename R, | |
| | | bool = tbb::internal::is_same_type<typename tuple_element<0,typen | |
| | | ame T::output_ports_type>::type, receiver<R> >::value > | |
| | | inline void make_edge( T& output, receiver<R>& input) { | |
| | | make_edge(get<0>(output.output_ports()), input); | |
| | | } | |
| | | | |
| | | //Makes an edge from a sender to port 0 of a multi-input successor. | |
| | | template<typename S, typename V, | |
| | | bool = tbb::internal::is_same_type<sender<S>, typename tuple_elem | |
| | | ent<0,typename V::input_ports_type>::type >::value > | |
| | | inline void make_edge( sender<S>& output, V& input) { | |
| | | make_edge(output, get<0>(input.input_ports())); | |
| | | } | |
| | | #endif | |
| | | | |
| | | //! Removes an edge between a single predecessor and a single successor | |
| template< typename T > | | template< typename T > | |
| inline void remove_edge( sender<T> &p, receiver<T> &s ) { | | inline void remove_edge( sender<T> &p, receiver<T> &s ) { | |
| p.remove_successor( s ); | | p.remove_successor( s ); | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| // TODO: should we try to remove p from the predecessor list of s, in c
ase the edge is reversed? | | // TODO: should we try to remove p from the predecessor list of s, in c
ase the edge is reversed? | |
| p.internal_delete_built_successor(s); | | p.internal_delete_built_successor(s); | |
| s.internal_delete_built_predecessor(p); | | s.internal_delete_built_predecessor(p); | |
| #endif | | #endif | |
| tbb::internal::fgt_remove_edge( &p, &s ); | | tbb::internal::fgt_remove_edge( &p, &s ); | |
| } | | } | |
| | | | |
|
| | | #if __TBB_PREVIEW_COMPOSITE_NODE | |
| | | //Removes an edge between port 0 of a multi-output predecessor and port 0 o | |
| | | f a multi-input successor. | |
| | | template< typename T, typename V, | |
| | | bool = tbb::internal::is_same_type< typename tuple_element<0,type | |
| | | name T::output_ports_type>::type, | |
| | | typename tuple_element<0,type | |
| | | name V::input_ports_type>::type | |
| | | >::value > | |
| | | inline void remove_edge( T& output, V& input) { | |
| | | remove_edge(get<0>(output.output_ports()), get<0>(input.input_ports())) | |
| | | ; | |
| | | } | |
| | | | |
| | | //Removes an edge between port 0 of a multi-output predecessor and a receiv | |
| | | er. | |
| | | template< typename T, typename R, | |
| | | bool = tbb::internal::is_same_type<typename tuple_element<0,typen | |
| | | ame T::output_ports_type>::type, receiver<R> >::value > | |
| | | inline void remove_edge( T& output, receiver<R>& input) { | |
| | | remove_edge(get<0>(output.output_ports()), input); | |
| | | } | |
| | | //Removes an edge between a sender and port 0 of a multi-input successor. | |
| | | template<typename S, typename V, | |
| | | bool = tbb::internal::is_same_type<sender<S>, typename tuple_elem | |
| | | ent<0,typename V::input_ports_type>::type >::value > | |
| | | inline void remove_edge( sender<S>& output, V& input) { | |
| | | remove_edge(output, get<0>(input.input_ports())); | |
| | | } | |
| | | #endif | |
| | | | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| template<typename C > | | template<typename C > | |
| template< typename S > | | template< typename S > | |
|
| void edge_container<C>::sender_extract( S &s ) { | | void internal::edge_container<C>::sender_extract( S &s ) { | |
| edge_vector e = built_edges; | | edge_list_type e = built_edges; | |
| for ( typename edge_vector::iterator i = e.begin(); i != e.end(); ++i ) | | for ( typename edge_list_type::iterator i = e.begin(); i != e.end(); ++ | |
| { | | i ) { | |
| remove_edge(s, **i); | | remove_edge(s, **i); | |
| } | | } | |
| } | | } | |
| | | | |
| template<typename C > | | template<typename C > | |
| template< typename R > | | template< typename R > | |
|
| void edge_container<C>::receiver_extract( R &r ) { | | void internal::edge_container<C>::receiver_extract( R &r ) { | |
| edge_vector e = built_edges; | | edge_list_type e = built_edges; | |
| for ( typename edge_vector::iterator i = e.begin(); i != e.end(); ++i ) | | for ( typename edge_list_type::iterator i = e.begin(); i != e.end(); ++ | |
| { | | i ) { | |
| remove_edge(**i, r); | | remove_edge(**i, r); | |
| } | | } | |
| } | | } | |
| #endif | | #endif | |
| | | | |
| //! Returns a copy of the body from a function or continue node | | //! Returns a copy of the body from a function or continue node | |
| template< typename Body, typename Node > | | template< typename Body, typename Node > | |
| Body copy_body( Node &n ) { | | Body copy_body( Node &n ) { | |
| return n.template copy_function_object<Body>(); | | return n.template copy_function_object<Body>(); | |
| } | | } | |
| | | | |
|
| | | #if __TBB_PREVIEW_COMPOSITE_NODE | |
| | | | |
| | | //composite_node | |
| | | template< typename InputTuple, typename OutputTuple > class composite_node; | |
| | | | |
| | | template< typename... InputTypes, typename... OutputTypes> | |
| | | class composite_node <tbb::flow::tuple<InputTypes...>, tbb::flow::tuple<Out | |
| | | putTypes...> > : public graph_node { | |
| | | | |
| | | public: | |
| | | typedef tbb::flow::tuple< receiver<InputTypes>&... > input_ports_type; | |
| | | typedef tbb::flow::tuple< sender<OutputTypes>&... > output_ports_type; | |
| | | | |
| | | private: | |
| | | input_ports_type *my_input_ports; | |
| | | output_ports_type *my_output_ports; | |
| | | const char *type_name; | |
| | | | |
| | | static const size_t NUM_INPUTS = sizeof...(InputTypes); | |
| | | static const size_t NUM_OUTPUTS = sizeof...(OutputTypes); | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | //TODO: extend to include multiinput-multioutput nodes | |
| | | template<typename NodeType> | |
| | | auto sender_cast(const NodeType &n)-> sender< typename NodeType::output | |
| | | _type >* { | |
| | | return dynamic_cast< sender< typename NodeType::output_type > * >(c | |
| | | onst_cast< NodeType *>(&n)); | |
| | | } | |
| | | | |
| | | template<typename NodeType> | |
| | | auto receiver_cast(const NodeType &n)-> receiver< typename NodeType::in | |
| | | put_type >* { | |
| | | return dynamic_cast< receiver< typename NodeType::input_type > * >( | |
| | | const_cast< NodeType *>(&n)) ; | |
| | | } | |
| | | | |
| | | bool add_nodes_impl(bool) {return true; } | |
| | | | |
| | | template< typename NodeType1, typename... NodeTypes > | |
| | | bool add_nodes_impl(bool visible, const NodeType1& n1, const NodeTypes& | |
| | | ... n) { | |
| | | // try to dynamic cast to sender< NodeType::output_type >; if succe | |
| | | ssful, its a single-output node | |
| | | void *addr = sender_cast(n1); | |
| | | | |
| | | if(!addr) | |
| | | addr = receiver_cast(n1); | |
| | | | |
| | | if(addr) { | |
| | | if (visible) | |
| | | tbb::internal::itt_relation_add( tbb::internal::ITT_DOMAIN_ | |
| | | FLOW, this, tbb::internal::FLOW_NODE, tbb::internal::__itt_relation_is_pare | |
| | | nt_of, addr, tbb::internal::FLOW_NODE ); | |
| | | else | |
| | | tbb::internal::itt_relation_add( tbb::internal::ITT_DOMAIN_ | |
| | | FLOW, addr, tbb::internal::FLOW_NODE, tbb::internal::__itt_relation_is_chil | |
| | | d_of, this, tbb::internal::FLOW_NODE ); | |
| | | return add_nodes_impl(visible, n...); | |
| | | } else { | |
| | | return false; | |
| | | } | |
| | | } | |
| | | #endif | |
| | | | |
| | | protected: | |
| | | /*override*/void reset(__TBB_PFG_RESET_ARG(reset_flags)) {} | |
| | | | |
| | | public: | |
| | | composite_node( graph &g, const char *my_type_name = " ") : graph_node( | |
| | | g), type_name(my_type_name) { | |
| | | my_input_ports = NULL; | |
| | | my_output_ports = NULL; | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | tbb::internal::itt_make_task_group( tbb::internal::ITT_DOMAIN_FLOW, | |
| | | this, tbb::internal::FLOW_NODE, &g, tbb::internal::FLOW_GRAPH, tbb::intern | |
| | | al::FLOW_COMPOSITE_NODE ); | |
| | | tbb::internal::fgt_multiinput_multioutput_node_desc( this, type_nam | |
| | | e ); | |
| | | #endif | |
| | | } | |
| | | | |
| | | void set_external_ports(input_ports_type&& input_ports_tuple, output_por | |
| | | ts_type&& output_ports_tuple) { | |
| | | __TBB_STATIC_ASSERT(NUM_INPUTS == tbb::flow::tuple_size<input_ports_ | |
| | | type>::value, "number of arguments does not match number of input ports"); | |
| | | __TBB_STATIC_ASSERT(NUM_OUTPUTS == tbb::flow::tuple_size<output_port | |
| | | s_type>::value, "number of arguments does not match number of output ports" | |
| | | ); | |
| | | | |
| | | my_input_ports = new input_ports_type(std::move(input_ports_tuple)); | |
| | | my_output_ports = new output_ports_type(std::move(output_ports_tuple) | |
| | | ); | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | tbb::internal::fgt_internal_input_helper<input_ports_type, input_port | |
| | | s_type, NUM_INPUTS>::register_port( this, input_ports_tuple ); | |
| | | tbb::internal::fgt_internal_output_helper<output_ports_type, output_p | |
| | | orts_type, NUM_OUTPUTS>::register_port( this, output_ports_tuple); | |
| | | #endif | |
| | | } | |
| | | | |
| | | void set_external_ports(const input_ports_type& input_ports_tuple, const | |
| | | output_ports_type& output_ports_tuple) { | |
| | | __TBB_STATIC_ASSERT(NUM_INPUTS == tbb::flow::tuple_size<input_ports_ | |
| | | type>::value, "number of arguments does not match number of input ports"); | |
| | | __TBB_STATIC_ASSERT(NUM_OUTPUTS == tbb::flow::tuple_size<output_port | |
| | | s_type>::value, "number of arguments does not match number of output ports" | |
| | | ); | |
| | | | |
| | | my_input_ports = new input_ports_type(input_ports_tuple); | |
| | | my_output_ports = new output_ports_type(output_ports_tuple); | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | tbb::internal::fgt_internal_input_helper<input_ports_type, input_port | |
| | | s_type, NUM_INPUTS>::register_port( this, input_ports_tuple ); | |
| | | tbb::internal::fgt_internal_output_helper<output_ports_type, output_p | |
| | | orts_type, NUM_OUTPUTS>::register_port( this, output_ports_tuple); | |
| | | #endif | |
| | | } | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | template< typename... NodeTypes > | |
| | | bool add_visible_nodes(const NodeTypes&... n) { | |
| | | return add_nodes_impl(true, n...); | |
| | | } | |
| | | | |
| | | template< typename... NodeTypes > | |
| | | bool add_nodes(const NodeTypes&... n) { | |
| | | return add_nodes_impl(false, n...); | |
| | | } | |
| | | #else | |
| | | template<typename... Nodes> bool add_nodes(Nodes&...) { return true; } | |
| | | template<typename... Nodes> bool add_visible_nodes(Nodes&...) { return | |
| | | true; } | |
| | | #endif | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | /* override */ void set_name( const char *name ) { | |
| | | tbb::internal::fgt_multiinput_multioutput_node_desc( this, name ); | |
| | | } | |
| | | #endif | |
| | | | |
| | | input_ports_type input_ports() { | |
| | | __TBB_ASSERT(my_input_ports, "input ports not set, call set_extern | |
| | | al_ports to set input ports"); | |
| | | return *my_input_ports; | |
| | | } | |
| | | | |
| | | output_ports_type output_ports() { | |
| | | __TBB_ASSERT(my_output_ports, "output ports not set, call set_exte | |
| | | rnal_ports to set output ports"); | |
| | | return *my_output_ports; | |
| | | } | |
| | | | |
| | | virtual ~composite_node() { | |
| | | if(my_input_ports) delete my_input_ports; | |
| | | if(my_output_ports) delete my_output_ports; | |
| | | } | |
| | | }; | |
| | | | |
| | | //composite_node with only input ports | |
| | | //TODO: trim specializations | |
| | | | |
| | | template< typename... InputTypes> | |
| | | class composite_node <tbb::flow::tuple<InputTypes...>, tbb::flow::tuple<> > | |
| | | : public graph_node { | |
| | | public: | |
| | | typedef tbb::flow::tuple< receiver<InputTypes>&... > input_ports_type; | |
| | | | |
| | | private: | |
| | | input_ports_type *my_input_ports; | |
| | | static const size_t NUM_INPUTS = sizeof...(InputTypes); | |
| | | const char *type_name; | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | template<typename NodeType> | |
| | | auto sender_cast(const NodeType &n)-> sender< typename NodeType::output | |
| | | _type >* { | |
| | | return dynamic_cast< sender< typename NodeType::output_type > * >(c | |
| | | onst_cast< NodeType *>(&n)); | |
| | | } | |
| | | | |
| | | template<typename NodeType> | |
| | | auto receiver_cast(const NodeType &n)-> receiver< typename NodeType::in | |
| | | put_type >* { | |
| | | return dynamic_cast< receiver< typename NodeType::input_type > * >( | |
| | | const_cast< NodeType *>(&n)) ; | |
| | | } | |
| | | | |
| | | bool add_nodes_impl(bool) { return true; } | |
| | | | |
| | | template< typename NodeType1, typename... NodeTypes > | |
| | | bool add_nodes_impl(bool visible, const NodeType1& n1, const NodeTypes& | |
| | | ... n) { | |
| | | // try to dynamic cast to sender< NodeType::output_type >; if succe | |
| | | ssful, its a single-output node | |
| | | void *addr = sender_cast(n1); | |
| | | | |
| | | if(!addr) | |
| | | addr = receiver_cast(n1); | |
| | | | |
| | | if(addr) { | |
| | | if (visible) | |
| | | tbb::internal::itt_relation_add( tbb::internal::ITT_DOMAIN_ | |
| | | FLOW, this, tbb::internal::FLOW_NODE, tbb::internal::__itt_relation_is_pare | |
| | | nt_of, addr, tbb::internal::FLOW_NODE ); | |
| | | else | |
| | | tbb::internal::itt_relation_add( tbb::internal::ITT_DOMAIN_ | |
| | | FLOW, addr, tbb::internal::FLOW_NODE, tbb::internal::__itt_relation_is_chil | |
| | | d_of, this, tbb::internal::FLOW_NODE ); | |
| | | return add_nodes_impl(visible, n...); | |
| | | } else { | |
| | | return false; | |
| | | } | |
| | | } | |
| | | #endif | |
| | | | |
| | | protected: | |
| | | /*override*/void reset(__TBB_PFG_RESET_ARG(reset_flags)) {} | |
| | | | |
| | | public: | |
| | | composite_node( graph &g, const char *my_type_name = " ") : graph_node( | |
| | | g), type_name(my_type_name) { | |
| | | my_input_ports = NULL; | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | tbb::internal::itt_make_task_group( tbb::internal::ITT_DOMAIN_FLOW, | |
| | | this, tbb::internal::FLOW_NODE, &g, tbb::internal::FLOW_GRAPH, tbb::intern | |
| | | al::FLOW_COMPOSITE_NODE ); | |
| | | tbb::internal::fgt_multiinput_multioutput_node_desc( this, type_nam | |
| | | e ); | |
| | | #endif | |
| | | } | |
| | | | |
| | | void set_external_ports(input_ports_type&& input_ports_tuple) { | |
| | | __TBB_STATIC_ASSERT(NUM_INPUTS == tbb::flow::tuple_size<input_ports_ | |
| | | type>::value, "number of arguments does not match number of input ports"); | |
| | | | |
| | | my_input_ports = new input_ports_type(std::move(input_ports_tuple)); | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | tbb::internal::fgt_internal_input_helper<input_ports_type, input_port | |
| | | s_type, NUM_INPUTS>::register_port( this, input_ports_tuple ); | |
| | | #endif | |
| | | } | |
| | | | |
| | | void set_external_ports(const input_ports_type& input_ports_tuple) { | |
| | | __TBB_STATIC_ASSERT(NUM_INPUTS == tbb::flow::tuple_size<input_ports_ | |
| | | type>::value, "number of arguments does not match number of input ports"); | |
| | | | |
| | | my_input_ports = new input_ports_type(input_ports_tuple); | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | tbb::internal::fgt_internal_input_helper<input_ports_type, input_port | |
| | | s_type, NUM_INPUTS>::register_port( this, input_ports_tuple ); | |
| | | #endif | |
| | | } | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | template< typename... NodeTypes > | |
| | | bool add_visible_nodes(const NodeTypes&... n) { | |
| | | return add_nodes_impl(true, n...); | |
| | | } | |
| | | | |
| | | template< typename... NodeTypes > | |
| | | bool add_nodes( const NodeTypes&... n) { | |
| | | return add_nodes_impl(false, n...); | |
| | | } | |
| | | #else | |
| | | template<typename... Nodes> bool add_nodes(Nodes&...) { return true; } | |
| | | template<typename... Nodes> bool add_visible_nodes(Nodes&...) { return | |
| | | true; } | |
| | | #endif | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | /* override */ void set_name( const char *name ) { | |
| | | tbb::internal::fgt_multiinput_multioutput_node_desc( this, name ); | |
| | | } | |
| | | #endif | |
| | | | |
| | | input_ports_type input_ports() { | |
| | | __TBB_ASSERT(my_input_ports, "input ports not set, call set_extern | |
| | | al_ports to set input ports"); | |
| | | return *my_input_ports; | |
| | | } | |
| | | | |
| | | virtual ~composite_node() { | |
| | | if(my_input_ports) delete my_input_ports; | |
| | | } | |
| | | }; | |
| | | | |
| | | //composite_nodes with only output_ports | |
| | | template<typename... OutputTypes> | |
| | | class composite_node <tbb::flow::tuple<>, tbb::flow::tuple<OutputTypes...> | |
| | | > : public graph_node { | |
| | | public: | |
| | | typedef tbb::flow::tuple< sender<OutputTypes>&... > output_ports_type; | |
| | | | |
| | | private: | |
| | | output_ports_type *my_output_ports; | |
| | | static const size_t NUM_OUTPUTS = sizeof...(OutputTypes); | |
| | | const char *type_name; | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | template<typename NodeType> | |
| | | auto sender_cast(const NodeType &n)-> sender< typename NodeType::output | |
| | | _type >* { | |
| | | return dynamic_cast< sender< typename NodeType::output_type > * >(c | |
| | | onst_cast< NodeType *>(&n)); | |
| | | } | |
| | | | |
| | | template<typename NodeType> | |
| | | auto receiver_cast(const NodeType &n)-> receiver< typename NodeType::in | |
| | | put_type >* { | |
| | | return dynamic_cast< receiver< typename NodeType::input_type > * >( | |
| | | const_cast< NodeType *>(&n)) ; | |
| | | } | |
| | | | |
| | | bool add_nodes_impl(bool) {return true;} | |
| | | | |
| | | template< typename NodeType1, typename... NodeTypes > | |
| | | bool add_nodes_impl(bool visible, const NodeType1& n1, const NodeTypes& | |
| | | ... n) { | |
| | | // try to dynamic cast to sender< NodeType::output_type >; if succe | |
| | | ssful, its a single-output node | |
| | | void *addr = sender_cast(n1); | |
| | | | |
| | | if(!addr) | |
| | | addr = receiver_cast(n1); | |
| | | | |
| | | if(addr) { | |
| | | if (visible) | |
| | | tbb::internal::itt_relation_add( tbb::internal::ITT_DOMAIN_ | |
| | | FLOW, this, tbb::internal::FLOW_NODE, tbb::internal::__itt_relation_is_pare | |
| | | nt_of, addr, tbb::internal::FLOW_NODE ); | |
| | | else | |
| | | tbb::internal::itt_relation_add( tbb::internal::ITT_DOMAIN_ | |
| | | FLOW, addr, tbb::internal::FLOW_NODE, tbb::internal::__itt_relation_is_chil | |
| | | d_of, this, tbb::internal::FLOW_NODE ); | |
| | | return add_nodes_impl(visible, n...); | |
| | | } else { | |
| | | return false; | |
| | | } | |
| | | } | |
| | | #endif | |
| | | | |
| | | protected: | |
| | | /*override*/void reset(__TBB_PFG_RESET_ARG(reset_flags)) {} | |
| | | | |
| | | public: | |
| | | composite_node( graph &g, const char *my_type_name = " ") : graph_node( | |
| | | g), type_name(my_type_name) { | |
| | | my_output_ports = NULL; | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | tbb::internal::itt_make_task_group( tbb::internal::ITT_DOMAIN_FLOW, | |
| | | this, tbb::internal::FLOW_NODE, &g, tbb::internal::FLOW_GRAPH, tbb::intern | |
| | | al::FLOW_COMPOSITE_NODE ); | |
| | | tbb::internal::fgt_multiinput_multioutput_node_desc( this, type_nam | |
| | | e ); | |
| | | #endif | |
| | | } | |
| | | | |
| | | void set_external_ports(output_ports_type&& output_ports_tuple) { | |
| | | __TBB_STATIC_ASSERT(NUM_OUTPUTS == tbb::flow::tuple_size<output_port | |
| | | s_type>::value, "number of arguments does not match number of output ports" | |
| | | ); | |
| | | | |
| | | my_output_ports = new output_ports_type(std::move(output_ports_tuple) | |
| | | ); | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | tbb::internal::fgt_internal_output_helper<output_ports_type, output_p | |
| | | orts_type, NUM_OUTPUTS>::register_port( this, output_ports_tuple); | |
| | | #endif | |
| | | } | |
| | | | |
| | | void set_external_ports(const output_ports_type& output_ports_tuple) { | |
| | | __TBB_STATIC_ASSERT(NUM_OUTPUTS == tbb::flow::tuple_size<output_port | |
| | | s_type>::value, "number of arguments does not match number of output ports" | |
| | | ); | |
| | | | |
| | | my_output_ports = new output_ports_type(output_ports_tuple); | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | tbb::internal::fgt_internal_output_helper<output_ports_type, output_p | |
| | | orts_type, NUM_OUTPUTS>::register_port( this, output_ports_tuple); | |
| | | #endif | |
| | | } | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | template<typename... NodeTypes > | |
| | | bool add_visible_nodes(const NodeTypes&... n) { | |
| | | return add_nodes_impl(true, n...); | |
| | | } | |
| | | | |
| | | template<typename... NodeTypes > | |
| | | bool add_nodes(const NodeTypes&... n) { | |
| | | return add_nodes_impl(false, n...); | |
| | | } | |
| | | #else | |
| | | template<typename... Nodes> bool add_nodes(Nodes&...) { return true; } | |
| | | template<typename... Nodes> bool add_visible_nodes(Nodes&...) { return | |
| | | true; } | |
| | | #endif | |
| | | | |
| | | #if TBB_PREVIEW_FLOW_GRAPH_TRACE | |
| | | /* override */ void set_name( const char *name ) { | |
| | | tbb::internal::fgt_multiinput_multioutput_node_desc( this, name ); | |
| | | } | |
| | | #endif | |
| | | | |
| | | output_ports_type output_ports() { | |
| | | __TBB_ASSERT(my_output_ports, "output ports not set, call set_exte | |
| | | rnal_ports to set output ports"); | |
| | | return *my_output_ports; | |
| | | } | |
| | | | |
| | | virtual ~composite_node() { | |
| | | if(my_output_ports) delete my_output_ports; | |
| | | } | |
| | | }; | |
| | | | |
| | | #endif // __TBB_PREVIEW_COMPOSITE_NODE | |
| | | | |
| } // interface7 | | } // interface7 | |
| | | | |
| #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | | #if TBB_PREVIEW_FLOW_GRAPH_FEATURES | |
| using interface7::reset_flags; | | using interface7::reset_flags; | |
| using interface7::rf_reset_protocol; | | using interface7::rf_reset_protocol; | |
| using interface7::rf_reset_bodies; | | using interface7::rf_reset_bodies; | |
| using interface7::rf_extract; | | using interface7::rf_extract; | |
| #endif | | #endif | |
| | | | |
| using interface7::graph; | | using interface7::graph; | |
| | | | |
| skipping to change at line 3251 | | skipping to change at line 3664 | |
| using interface7::priority_queue_node; | | using interface7::priority_queue_node; | |
| using interface7::limiter_node; | | using interface7::limiter_node; | |
| using namespace interface7::internal::graph_policy_namespace; | | using namespace interface7::internal::graph_policy_namespace; | |
| using interface7::join_node; | | using interface7::join_node; | |
| using interface7::input_port; | | using interface7::input_port; | |
| using interface7::copy_body; | | using interface7::copy_body; | |
| using interface7::make_edge; | | using interface7::make_edge; | |
| using interface7::remove_edge; | | using interface7::remove_edge; | |
| using interface7::internal::NO_TAG; | | using interface7::internal::NO_TAG; | |
| using interface7::internal::tag_value; | | using interface7::internal::tag_value; | |
|
| | | #if __TBB_PREVIEW_COMPOSITE_NODE | |
| | | using interface7::composite_node; | |
| | | #endif | |
| } // flow | | } // flow | |
| } // tbb | | } // tbb | |
| | | | |
| #undef __TBB_PFG_RESET_ARG | | #undef __TBB_PFG_RESET_ARG | |
| #undef __TBB_COMMA | | #undef __TBB_COMMA | |
| | | | |
| #endif // __TBB_flow_graph_H | | #endif // __TBB_flow_graph_H | |
| | | | |
End of changes. 47 change blocks. |
| 58 lines changed or deleted | | 567 lines changed or added | |
|
| tbb_config.h | | tbb_config.h | |
| | | | |
| skipping to change at line 153 | | skipping to change at line 153 | |
| #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 **/ | | /** 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) | | #define __TBB_NOEXCEPT_PRESENT __INTEL_CXX11_MODE__
&& __INTEL_COMPILER >= 1300 && (__TBB_GCC_VERSION >= 40600 || _LIBCPP_VERSI
ON || _MSC_VER) | |
| #define __TBB_CPP11_STD_BEGIN_END_PRESENT (_MSC_VER >= 1700 ||
__GXX_EXPERIMENTAL_CXX0X__ && __INTEL_COMPILER >= 1310 && (__TBB_GCC_VERSIO
N >= 40600 || _LIBCPP_VERSION)) | | #define __TBB_CPP11_STD_BEGIN_END_PRESENT (_MSC_VER >= 1700 ||
__GXX_EXPERIMENTAL_CXX0X__ && __INTEL_COMPILER >= 1310 && (__TBB_GCC_VERSIO
N >= 40600 || _LIBCPP_VERSION)) | |
| #define __TBB_CPP11_AUTO_PRESENT (_MSC_VER >= 1600 ||
__GXX_EXPERIMENTAL_CXX0X__ && __INTEL_COMPILER >= 1210) | | #define __TBB_CPP11_AUTO_PRESENT (_MSC_VER >= 1600 ||
__GXX_EXPERIMENTAL_CXX0X__ && __INTEL_COMPILER >= 1210) | |
| #define __TBB_CPP11_DECLTYPE_PRESENT (_MSC_VER >= 1600 ||
__GXX_EXPERIMENTAL_CXX0X__ && __INTEL_COMPILER >= 1210) | | #define __TBB_CPP11_DECLTYPE_PRESENT (_MSC_VER >= 1600 ||
__GXX_EXPERIMENTAL_CXX0X__ && __INTEL_COMPILER >= 1210) | |
|
| | | #define __TBB_CPP11_LAMBDAS_PRESENT (__INTEL_CXX11_MODE__
&& __INTEL_COMPILER >= 1200) | |
| #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 | | #define __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT (__has_feature(__cxx_ | |
| _variadic_templates__)) | | variadic_templates__)) | |
| #define __TBB_CPP11_RVALUE_REF_PRESENT (__has_feature(__cxx | | #define __TBB_CPP11_RVALUE_REF_PRESENT (__has_feature(__cxx_ | |
| _rvalue_references__) && (__TBB_GCC_VERSION >= 40300 || _LIBCPP_VERSION)) | | rvalue_references__) && (__TBB_GCC_VERSION >= 40300 || _LIBCPP_VERSION)) | |
| /** 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_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 #ifs | | /**Clang (preprocessor) has problems with dealing with expression havin
g __has_include in #ifs | |
| * used inside C++ code. (At least version that comes with OS X 10.8 :
Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)) **/ | | * used inside C++ code. (At least version that comes with OS X 10.8 :
Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)) **/ | |
| #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 ? **/ | | /**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) | | #define __TBB_NOEXCEPT_PRESENT (__cplusplus >= 20110
3L) | |
| #define __TBB_CPP11_STD_BEGIN_END_PRESENT (__has_feature(__cxx_
range_for__) && _LIBCPP_VERSION) | | #define __TBB_CPP11_STD_BEGIN_END_PRESENT (__has_feature(__cxx_
range_for__) && _LIBCPP_VERSION) | |
| #define __TBB_CPP11_AUTO_PRESENT __has_feature(__cxx_a
uto_type__) | | #define __TBB_CPP11_AUTO_PRESENT __has_feature(__cxx_a
uto_type__) | |
| #define __TBB_CPP11_DECLTYPE_PRESENT __has_feature(__cxx_d
ecltype__) | | #define __TBB_CPP11_DECLTYPE_PRESENT __has_feature(__cxx_d
ecltype__) | |
|
| | | #define __TBB_CPP11_LAMBDAS_PRESENT __has_feature(cxx_lam
bdas) | |
| #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_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) | | #define __TBB_NOEXCEPT_PRESENT (__GXX_EXPERIMENTAL_C
XX0X__ && __TBB_GCC_VERSION >= 40600) | |
| #define __TBB_CPP11_STD_BEGIN_END_PRESENT (__GXX_EXPERIMENTAL_C
XX0X__ && __TBB_GCC_VERSION >= 40600) | | #define __TBB_CPP11_STD_BEGIN_END_PRESENT (__GXX_EXPERIMENTAL_C
XX0X__ && __TBB_GCC_VERSION >= 40600) | |
| #define __TBB_CPP11_AUTO_PRESENT (__GXX_EXPERIMENTAL_C
XX0X__ && __TBB_GCC_VERSION >= 40400) | | #define __TBB_CPP11_AUTO_PRESENT (__GXX_EXPERIMENTAL_C
XX0X__ && __TBB_GCC_VERSION >= 40400) | |
| #define __TBB_CPP11_DECLTYPE_PRESENT (__GXX_EXPERIMENTAL_C
XX0X__ && __TBB_GCC_VERSION >= 40400) | | #define __TBB_CPP11_DECLTYPE_PRESENT (__GXX_EXPERIMENTAL_C
XX0X__ && __TBB_GCC_VERSION >= 40400) | |
|
| | | #define __TBB_CPP11_LAMBDAS_PRESENT (__GXX_EXPERIMENTAL_C
XX0X__ && __TBB_GCC_VERSION >= 40500) | |
| #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_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*/ | | #define __TBB_NOEXCEPT_PRESENT 0 /*for _MSC_VER == 1
800*/ | |
| #define __TBB_CPP11_STD_BEGIN_END_PRESENT (_MSC_VER >= 1700) | | #define __TBB_CPP11_STD_BEGIN_END_PRESENT (_MSC_VER >= 1700) | |
| #define __TBB_CPP11_AUTO_PRESENT (_MSC_VER >= 1600) | | #define __TBB_CPP11_AUTO_PRESENT (_MSC_VER >= 1600) | |
| #define __TBB_CPP11_DECLTYPE_PRESENT (_MSC_VER >= 1600) | | #define __TBB_CPP11_DECLTYPE_PRESENT (_MSC_VER >= 1600) | |
|
| | | #define __TBB_CPP11_LAMBDAS_PRESENT (_MSC_VER >= 1600) | |
| #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_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 | | #define __TBB_NOEXCEPT_PRESENT 0 | |
| #define __TBB_CPP11_STD_BEGIN_END_PRESENT 0 | | #define __TBB_CPP11_STD_BEGIN_END_PRESENT 0 | |
| #define __TBB_CPP11_AUTO_PRESENT 0 | | #define __TBB_CPP11_AUTO_PRESENT 0 | |
| #define __TBB_CPP11_DECLTYPE_PRESENT 0 | | #define __TBB_CPP11_DECLTYPE_PRESENT 0 | |
|
| | | #define __TBB_CPP11_LAMBDAS_PRESENT 0 | |
| #endif | | #endif | |
| | | | |
| // C++11 standard library features | | // C++11 standard library features | |
| | | | |
|
| | | #define __TBB_CPP11_VARIADIC_TUPLE_PRESENT (!_MSC_VER || _MSC_VER
>=1800) | |
| #define __TBB_CPP11_TYPE_PROPERTIES_PRESENT (_LIBCPP_VERSION || _MS
C_VER >= 1700) | | #define __TBB_CPP11_TYPE_PROPERTIES_PRESENT (_LIBCPP_VERSION || _MS
C_VER >= 1700) | |
| #define __TBB_TR1_TYPE_PROPERTIES_IN_STD_PRESENT (__GXX_EXPERIMENTAL_CXX
0X__ && __TBB_GCC_VERSION >= 40300 || _MSC_VER >= 1600) | | #define __TBB_TR1_TYPE_PROPERTIES_IN_STD_PRESENT (__GXX_EXPERIMENTAL_CXX
0X__ && __TBB_GCC_VERSION >= 40300 || _MSC_VER >= 1600) | |
| // GCC has a partial support of type properties | | // GCC has a partial support of type properties | |
| #define __TBB_CPP11_IS_COPY_CONSTRUCTIBLE_PRESENT (__GXX_EXPERIMENTAL_CXX
0X__ && __TBB_GCC_VERSION >= 40700 || __TBB_CPP11_TYPE_PROPERTIES_PRESENT) | | #define __TBB_CPP11_IS_COPY_CONSTRUCTIBLE_PRESENT (__GXX_EXPERIMENTAL_CXX
0X__ && __TBB_GCC_VERSION >= 40700 || __TBB_CPP11_TYPE_PROPERTIES_PRESENT) | |
| | | | |
| // In GCC and MSVC, implementation of std::move_if_noexcept is not aligned
with noexcept | | // In GCC and MSVC, implementation of std::move_if_noexcept is not aligned
with noexcept | |
| #define __TBB_MOVE_IF_NOEXCEPT_PRESENT (__GXX_EXPERIMENTAL_CXX0X__
&& __TBB_GCC_VERSION >= 40700 || _MSC_VER >= 1800 || __clang__ && _LIBCPP_
VERSION && __TBB_NOEXCEPT_PRESENT) | | #define __TBB_MOVE_IF_NOEXCEPT_PRESENT (__GXX_EXPERIMENTAL_CXX0X__
&& __TBB_GCC_VERSION >= 40700 || _MSC_VER >= 1800 || __clang__ && _LIBCPP_
VERSION && __TBB_NOEXCEPT_PRESENT) | |
| //TODO: Probably more accurate way is to analyze version of stdlibc++ via__
GLIBCXX__ instead of __TBB_GCC_VERSION | | //TODO: Probably more accurate way is to analyze version of stdlibc++ via__
GLIBCXX__ instead of __TBB_GCC_VERSION | |
| #define __TBB_ALLOCATOR_TRAITS_PRESENT (__cplusplus >= 201103L
&& _LIBCPP_VERSION || _MSC_VER >= 1700 ||
\ | | #define __TBB_ALLOCATOR_TRAITS_PRESENT (__cplusplus >= 201103L
&& _LIBCPP_VERSION || _MSC_VER >= 1700 ||
\ | |
| __GXX_EXPERIMENTAL_CXX
0X__ && __TBB_GCC_VERSION >= 40700 && !(__TBB_GCC_VERSION == 40700 && __TBB
_DEFINE_MIC) \ | | __GXX_EXPERIMENTAL_CXX
0X__ && __TBB_GCC_VERSION >= 40700 && !(__TBB_GCC_VERSION == 40700 && __TBB
_DEFINE_MIC) \ | |
| | | | |
| skipping to change at line 458 | | skipping to change at line 464 | |
| | | | |
| #ifndef __TBB_USE_PROPORTIONAL_SPLIT_IN_BLOCKED_RANGES | | #ifndef __TBB_USE_PROPORTIONAL_SPLIT_IN_BLOCKED_RANGES | |
| #define __TBB_USE_PROPORTIONAL_SPLIT_IN_BLOCKED_RANGES 1 | | #define __TBB_USE_PROPORTIONAL_SPLIT_IN_BLOCKED_RANGES 1 | |
| #endif | | #endif | |
| | | | |
| #ifndef __TBB_ENABLE_RANGE_FEEDBACK | | #ifndef __TBB_ENABLE_RANGE_FEEDBACK | |
| #define __TBB_ENABLE_RANGE_FEEDBACK 0 | | #define __TBB_ENABLE_RANGE_FEEDBACK 0 | |
| #endif | | #endif | |
| | | | |
| #ifdef _VARIADIC_MAX | | #ifdef _VARIADIC_MAX | |
|
| #define __TBB_VARIADIC_MAX _VARIADIC_MAX | | #define __TBB_VARIADIC_MAX _VARIADIC_MAX | |
| #else | | #else | |
|
| #if _MSC_VER >= 1700 | | #if _MSC_VER == 1700 | |
| #define __TBB_VARIADIC_MAX 5 /* current VS11 setting, may change. */ | | #define __TBB_VARIADIC_MAX 5 // VS11 setting, issue resolved in VS1 | |
| #else | | 2 | |
| #define __TBB_VARIADIC_MAX 10 | | #elif _MSC_VER == 1600 | |
| #endif | | #define __TBB_VARIADIC_MAX 10 // VS10 setting | |
| | | #else | |
| | | #define __TBB_VARIADIC_MAX 15 | |
| | | #endif | |
| #endif | | #endif | |
| | | | |
| /** __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 | |
| | | | |
| | | | |
| skipping to change at line 632 | | skipping to change at line 640 | |
| // With MSVC, when an array is passed by const reference to a template
function, | | // With MSVC, when an array is passed by const reference to a template
function, | |
| // constness from the function parameter may get propagated to the temp
late parameter. | | // constness from the function parameter may get propagated to the temp
late parameter. | |
| #define __TBB_CONST_REF_TO_ARRAY_TEMPLATE_PARAM_BROKEN 1 | | #define __TBB_CONST_REF_TO_ARRAY_TEMPLATE_PARAM_BROKEN 1 | |
| #endif | | #endif | |
| | | | |
| // A compiler bug: a disabled copy constructor prevents use of the moving c
onstructor | | // A compiler bug: a disabled copy constructor prevents use of the moving c
onstructor | |
| #define __TBB_IF_NO_COPY_CTOR_MOVE_SEMANTICS_BROKEN (_MSC_VER && (__INTEL_C
OMPILER >= 1300 && __INTEL_COMPILER <= 1310) && !__INTEL_CXX11_MODE__) | | #define __TBB_IF_NO_COPY_CTOR_MOVE_SEMANTICS_BROKEN (_MSC_VER && (__INTEL_C
OMPILER >= 1300 && __INTEL_COMPILER <= 1310) && !__INTEL_CXX11_MODE__) | |
| | | | |
| // MSVC 2013 and ICC 15 seems do not generate implicit move constructor for
empty derived class while should | | // MSVC 2013 and ICC 15 seems do not generate implicit move constructor for
empty derived class while should | |
| #define __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_FOR_DERIVED_BROKEN (_
_TBB_CPP11_RVALUE_REF_PRESENT && \ | | #define __TBB_CPP11_IMPLICIT_MOVE_MEMBERS_GENERATION_FOR_DERIVED_BROKEN (_
_TBB_CPP11_RVALUE_REF_PRESENT && \ | |
|
| ( !__INTEL_COMPILER && _MSC_VER && _MSC_VER <=1800 || __INTEL_COMPILE | | ( !__INTEL_COMPILER && _MSC_VER && _MSC_VER <= 1800 || __INTEL_COMPIL | |
| R && __INTEL_COMPILER <= 1500 )) | | ER && __INTEL_COMPILER <= 1500 )) | |
| | | | |
| | | #define __TBB_CPP11_DECLVAL_BROKEN (_MSC_VER == 1600 || (__GNUC__ && __TBB_ | |
| | | GCC_VERSION < 40500) ) | |
| | | | |
| | | //The implicit upcasting of the tuple of a reference of a derived class to | |
| | | a base class fails on icc 13.X | |
| | | //if the system's gcc environment is 4.8 | |
| | | #if (__INTEL_COMPILER >=1300 && __INTEL_COMPILER <=1310) && __TBB_GCC_VERSI | |
| | | ON>=40700 && __GXX_EXPERIMENTAL_CXX0X__ | |
| | | #define __TBB_UPCAST_OF_TUPLE_OF_REF_BROKEN 1 | |
| | | #endif | |
| | | | |
| /** End of __TBB_XXX_BROKEN macro section **/ | | /** End of __TBB_XXX_BROKEN macro section **/ | |
| | | | |
| #if defined(_MSC_VER) && _MSC_VER>=1500 && !defined(__INTEL_COMPILER) | | #if defined(_MSC_VER) && _MSC_VER>=1500 && !defined(__INTEL_COMPILER) | |
| // A macro to suppress erroneous or benign "unreachable code" MSVC warn
ing (4702) | | // A macro to suppress erroneous or benign "unreachable code" MSVC warn
ing (4702) | |
| #define __TBB_MSVC_UNREACHABLE_CODE_IGNORED 1 | | #define __TBB_MSVC_UNREACHABLE_CODE_IGNORED 1 | |
| #endif | | #endif | |
| | | | |
| #define __TBB_ATOMIC_CTORS (__TBB_CONSTEXPR_PRESENT && __TBB_DEFAULTED_
AND_DELETED_FUNC_PRESENT && (!__TBB_ZERO_INIT_WITH_DEFAULTED_CTOR_BROKEN)) | | #define __TBB_ATOMIC_CTORS (__TBB_CONSTEXPR_PRESENT && __TBB_DEFAULTED_
AND_DELETED_FUNC_PRESENT && (!__TBB_ZERO_INIT_WITH_DEFAULTED_CTOR_BROKEN)) | |
| | | | |
| #define __TBB_ALLOCATOR_CONSTRUCT_VARIADIC (__TBB_CPP11_VARIADIC_TEMPL
ATES_PRESENT && __TBB_CPP11_RVALUE_REF_PRESENT) | | #define __TBB_ALLOCATOR_CONSTRUCT_VARIADIC (__TBB_CPP11_VARIADIC_TEMPL
ATES_PRESENT && __TBB_CPP11_RVALUE_REF_PRESENT) | |
| | | | |
| #define __TBB_VARIADIC_PARALLEL_INVOKE (TBB_PREVIEW_VARIADIC_PARAL
LEL_INVOKE && __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT && __TBB_CPP11_RVALUE_
REF_PRESENT) | | #define __TBB_VARIADIC_PARALLEL_INVOKE (TBB_PREVIEW_VARIADIC_PARAL
LEL_INVOKE && __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT && __TBB_CPP11_RVALUE_
REF_PRESENT) | |
|
| | | #define __TBB_PREVIEW_COMPOSITE_NODE (TBB_PREVIEW_FLOW_GRAPH_NOD | |
| | | ES && __TBB_CPP11_VARIADIC_TEMPLATES_PRESENT \ | |
| | | && __TBB_CPP11_RVALUE_REF_ | |
| | | PRESENT && __TBB_CPP11_AUTO_PRESENT) \ | |
| | | && __TBB_CPP11_VARIADIC_TU | |
| | | PLE_PRESENT && !__TBB_UPCAST_OF_TUPLE_OF_REF_BROKEN | |
| #endif /* __TBB_tbb_config_H */ | | #endif /* __TBB_tbb_config_H */ | |
| | | | |
End of changes. 11 change blocks. |
| 12 lines changed or deleted | | 38 lines changed or added | |
|