// test program for Concurrent_compact_container. #include #ifndef CGAL_LINKED_WITH_TBB int main() { std::cout << "NOTICE: this test needs CGAL_LINKED_WITH_TBB, and will not be tested." << std::endl; return 0; } #else #include #include #include #include #include #include #include #include #define TBB_PREVIEW_GLOBAL_CONTROL 1 # include # include # include #include struct Node_1 : public CGAL::Compact_container_base { Node_1() {} bool operator==(const Node_1 &) const { return true; } bool operator!=(const Node_1 &) const { return false; } bool operator< (const Node_1 &) const { return false; } typedef CGAL::Tag_true Has_timestamp; std::size_t time_stamp() const { return time_stamp_; } void set_time_stamp(const std::size_t& ts) { time_stamp_ = ts; } std::size_t time_stamp_; }; class Node_2 { union { Node_2 * p; void * p_cc; }; public: int rnd; Node_2() : p(nullptr), rnd(CGAL::get_default_random().get_int(0, 100)) {} bool operator==(const Node_2 &n) const { return rnd == n.rnd; } bool operator!=(const Node_2 &n) const { return rnd != n.rnd; } bool operator< (const Node_2 &n) const { return rnd < n.rnd; } void * for_compact_container() const { return p_cc; } void for_compact_container(void *p) { p_cc = p; } }; template < class Cont > inline bool check_empty(const Cont &c) { return c.empty() && c.size() == 0 && c.begin() == c.end(); } // For parallel_for template class Insert_in_CCC_functor { typedef std::vector Iterators_vec; public: Insert_in_CCC_functor( const Values_vec &values, Cont &cont, Iterators_vec &iterators) : m_values(values), m_cont(cont), m_iterators(iterators) {} void operator() (const tbb::blocked_range& r) const { for( size_t i = r.begin() ; i != r.end() ; ++i) m_iterators[i] = m_cont.insert(m_values[i]); } private: const Values_vec & m_values; Cont & m_cont; Iterators_vec & m_iterators; }; // For parallel_for template class Erase_in_CCC_functor { typedef std::vector Iterators_vec; public: Erase_in_CCC_functor( Cont &cont, Iterators_vec &iterators) : m_cont(cont), m_iterators(iterators) {} void operator() (const tbb::blocked_range& r) const { for( size_t i = r.begin() ; i != r.end() ; ++i) m_cont.erase(m_iterators[i]); } private: Cont & m_cont; Iterators_vec & m_iterators; }; // For parallel_for template class Insert_and_erase_in_CCC_functor { typedef std::vector Iterators_vec; typedef std::vector > Free_elts_vec; public: Insert_and_erase_in_CCC_functor( const Values_vec &values, Cont &cont, Iterators_vec &iterators, Free_elts_vec &free_elements, std::atomic &num_erasures) : m_values(values), m_cont(cont), m_iterators(iterators), m_free_elements(free_elements), m_num_erasures(num_erasures) {} void operator() (const tbb::blocked_range& r) const { for( size_t i = r.begin() ; i != r.end() ; ++i) { m_iterators[i] = m_cont.insert(m_values[i]); // Random-pick an element to erase auto index_to_erase = rand() % m_values.size(); // If it exists bool comparand = false; if (m_free_elements[index_to_erase].compare_exchange_weak(comparand, true) ) { m_cont.erase(m_iterators[index_to_erase]); ++m_num_erasures; } } } private: const Values_vec & m_values; Cont & m_cont; Iterators_vec & m_iterators; Free_elts_vec & m_free_elements; std::atomic & m_num_erasures; }; template < class Cont > void test(const Cont &) { static_assert(std::is_nothrow_move_constructible::value, "move cstr is missing"); static_assert(std::is_nothrow_move_assignable::value, "move assignment is missing"); // Testing if all types are provided. typename Cont::value_type t0; typename Cont::reference t1 = t0; CGAL_USE(t1); typename Cont::const_reference t2 = t0; CGAL_USE(t2); typename Cont::pointer t3 = &t0; typename Cont::const_pointer t4 = &t0; CGAL_USE(t4); typename Cont::size_type t5 = 0; CGAL_USE(t5); typename Cont::difference_type t6 = t3-t3; CGAL_USE(t6); typename Cont::iterator t7; CGAL_USE(t7); typename Cont::const_iterator t8; CGAL_USE(t8); typename Cont::reverse_iterator t9; CGAL_USE(t9); typename Cont::const_reverse_iterator t10; CGAL_USE(t10); typename Cont::allocator_type t15; std::cout << "Testing empty containers." << std::endl; Cont c0, c1; Cont c2(t15); Cont c3(c2); Cont c4; c4 = c2; typedef std::vector Vect; Vect v0; const Cont c5(v0.begin(), v0.end()); Cont c6(c5.begin(), c5.end()); typename Cont::allocator_type Al; Cont c7(c0.begin(), c0.end(), Al); Cont c8; c8.insert(c0.rbegin(), c0.rend()); // test conversion iterator-> const_iterator. typename Cont::const_iterator t16 = c5.begin(); CGAL_USE(t16); assert(t16 == c5.begin()); assert(c0 == c1); assert(! (c0 < c1)); assert(check_empty(c0)); assert(check_empty(c1)); assert(check_empty(c2)); assert(check_empty(c3)); assert(check_empty(c4)); assert(check_empty(c5)); assert(check_empty(c6)); assert(check_empty(c7)); assert(check_empty(c8)); c1.swap(c0); assert(check_empty(c0)); assert(check_empty(c1)); c1.merge(c0); assert(check_empty(c0)); assert(check_empty(c1)); c0.get_allocator(); std::cout << "Now filling some containers" << std::endl; Vect v1(10000); Cont c9(v1.begin(), v1.end()); assert(c9.size() == v1.size()); assert(c9.max_size() >= v1.size()); assert(c9.capacity() >= c9.size()); Cont c10 = c9; assert(c10 == c9); assert(c10.size() == v1.size()); assert(c10.max_size() >= v1.size()); assert(c10.capacity() >= c10.size()); c9.clear(); assert(check_empty(c9)); assert(c9.capacity() >= c9.size()); assert(c0 == c9); c9.merge(c10); c10.swap(c9); assert(check_empty(c9)); assert(c9.capacity() >= c9.size()); assert(c10.size() == v1.size()); assert(c10.max_size() >= v1.size()); assert(c10.capacity() >= c10.size()); std::cout << "Testing insertion methods" << std::endl; c9.assign(c10.begin(), c10.end()); assert(c9 == c10); c10.assign(c9.begin(), c9.end()); assert(c9 == c10); c9.insert(c10.begin(), c10.end()); assert(c9.size() == 2*v1.size()); c9.clear(); assert(c9 != c10); c9.insert(c10.begin(), c10.end()); assert(c9.size() == v1.size()); assert(c9 == c10); typename Cont::iterator it = c9.iterator_to(*c9.begin()); assert(it == c9.begin()); typename Cont::const_iterator cit = c9.iterator_to(const_cast(*c9.begin())); assert(cit == c9.begin()); typename Cont::iterator s_it = Cont::s_iterator_to(*c9.begin()); assert(s_it == c9.begin()); typename Cont::const_iterator s_cit = Cont::s_iterator_to(const_cast(*c9.begin())); assert(s_cit == c9.begin()); c10 = Cont(); assert(check_empty(c10)); for(typename Vect::const_iterator it = v1.begin(); it != v1.end(); ++it) c10.insert(*it); assert(c10.size() == v1.size()); assert(c9 == c10); c9.erase(c9.begin()); c9.erase(c9.begin()); assert(c9.size() == v1.size() - 2); // test reserve /*Cont c11; c11.reserve(v1.size()); for(typename Vect::const_iterator it = v1.begin(); it != v1.end(); ++it) c11.insert(*it); assert(c11.size() == v1.size()); assert(c10 == c11);*/ // owns() and owns_dereferenceable(). for(typename Cont::const_iterator it = c9.begin(), end = c9.end(); it != end; ++it) { assert(c9.owns(it)); assert(c9.owns_dereferenceable(it)); assert(! c10.owns(it)); assert(! c10.owns_dereferenceable(it)); } assert(c9.owns(c9.end())); assert(! c9.owns_dereferenceable(c9.end())); c9.erase(c9.begin(), c9.end()); assert(check_empty(c9)); std::cout << "Testing parallel insertion" << std::endl; { Cont c11; Vect v11(1000000); std::vector iterators(v11.size()); tbb::parallel_for( tbb::blocked_range( 0, v11.size() ), Insert_in_CCC_functor(v11, c11, iterators) ); assert(c11.size() == v11.size()); std::cout << "Testing parallel erasure" << std::endl; tbb::parallel_for( tbb::blocked_range( 0, v11.size() ), Erase_in_CCC_functor(c11, iterators) ); assert(c11.empty()); } std::cout << "Testing parallel insertion AND erasure" << std::endl; { Cont c12; Vect v12(1000000); std::vector > free_elements(v12.size()); for(typename std::vector >::iterator it = free_elements.begin(), end = free_elements.end(); it != end; ++it) { *it = true; } std::atomic num_erasures; num_erasures = 0; std::vector iterators(v12.size()); tbb::parallel_for( tbb::blocked_range( 0, v12.size() ), Insert_and_erase_in_CCC_functor( v12, c12, iterators, free_elements, num_erasures) ); assert(c12.size() == v12.size() - num_erasures); } } template < class Cont > void test_time_stamps() { Cont c1; for (std::size_t i = 0 ; i < 10 ; ++i) c1.emplace(); typename Cont::iterator it = c1.begin(); for (std::size_t i = 0 ; i < 10 ; ++i) { assert(i == it++->time_stamp()); } Cont c2(c1); it = c2.begin(); for (std::size_t i = 0 ; i < 10 ; ++i) { assert(i == it++->time_stamp()); } } int main() { CGAL::Concurrent_compact_container C1; CGAL::Concurrent_compact_container C2; test(C1); test(C2); /* // Verbose merging test typedef CGAL::Concurrent_compact_container CCC; CCC cc1, cc2; tbb::parallel_for( tbb::blocked_range( 0, 100, 1 ), [&] (const tbb::blocked_range& r) // TODO: lambdas ok? { for( size_t i = r.begin() ; i != r.end() ; ++i) { Node_2 n; n.rnd = i; cc1.insert(n); } }); for (int i = 10 ; i < 14 ; ++i) { Node_2 n; n.rnd = i; cc2.insert(n); } std::cout << "cc1 capacity: " << cc1.capacity() << std::endl; std::cout << "cc1 size: " << cc1.size() << std::endl; for(CCC::const_iterator it = cc1.begin(), end = cc1.end(); it != end; ++it) { std::cout << "cc1: " << it->rnd << " / " << std::endl; } std::cout << "cc2 capacity: " << cc2.capacity() << std::endl; std::cout << "cc2 size: " << cc2.size() << std::endl; for(CCC::const_iterator it = cc2.begin(), end = cc2.end(); it != end; ++it) { std::cout << "cc2: " << it->rnd << " / " << std::endl; } std::cout << "Merging..."; //cc1.merge(cc2); cc2.merge(cc1); std::cout << " done." << std::endl; std::cout << "cc1 capacity: " << cc1.capacity() << std::endl; std::cout << "cc1 size: " << cc1.size() << std::endl; for(CCC::const_iterator it = cc1.begin(), end = cc1.end(); it != end; ++it) { std::cout << "cc1: " << it->rnd << " / " << std::endl; } std::cout << "cc2 capacity: " << cc2.capacity() << std::endl; std::cout << "cc2 size: " << cc2.size() << std::endl; for(CCC::const_iterator it = cc2.begin(), end = cc2.end(); it != end; ++it) { std::cout << "cc2: " << it->rnd << " / " << std::endl; }*/ tbb::global_control c(tbb::global_control::max_allowed_parallelism, 1); test_time_stamps >(); return 0; } #endif // CGAL_LINKED_WITH_TBB // EOF //