diff --git a/example/doc_advanced_value_traits.cpp b/example/doc_advanced_value_traits.cpp index bdcd4ca..f4caafb 100644 --- a/example/doc_advanced_value_traits.cpp +++ b/example/doc_advanced_value_traits.cpp @@ -10,7 +10,7 @@ // ///////////////////////////////////////////////////////////////////////////// //[doc_advanced_value_traits_code -#include +#include #include #include @@ -46,7 +46,7 @@ struct simple_node_traits //A templatized value traits for value_1 and value_2 template -struct value_traits +struct simple_value_traits { typedef simple_node_traits node_traits; typedef node_traits::node_ptr node_ptr; @@ -54,7 +54,7 @@ struct value_traits typedef ValueType value_type; typedef ValueType * pointer; typedef const ValueType * const_pointer; - enum { linking_policy = boost::intrusive::normal_link }; + static const boost::intrusive::link_mode_type link_mode = boost::intrusive::normal_link; static node_ptr to_node_ptr (value_type &value) { return node_ptr(&value); } static const_node_ptr to_node_ptr (const value_type &value) { return const_node_ptr(&value); } static pointer to_value_ptr(node_ptr n) { return static_cast(n); } @@ -65,8 +65,10 @@ struct value_traits //[doc_advanced_value_traits_containers //Now define two intrusive lists. Both lists will use the same algorithms: // circular_list_algorithms -typedef boost::intrusive::list > Value1List; -typedef boost::intrusive::list > Value2List; + +using namespace boost::intrusive; +typedef list > > Value1List; +typedef list > > Value2List; //] //[doc_advanced_value_traits_test diff --git a/example/doc_advanced_value_traits2.cpp b/example/doc_advanced_value_traits2.cpp index bfc852a..6367af0 100644 --- a/example/doc_advanced_value_traits2.cpp +++ b/example/doc_advanced_value_traits2.cpp @@ -9,7 +9,7 @@ // See http://www.boost.org/libs/intrusive for documentation. // ///////////////////////////////////////////////////////////////////////////// -#include +#include #include #include #include @@ -57,8 +57,8 @@ typedef member_value_traits //Now define two intrusive lists. Both lists will use the same algorithms: // circular_list_algorithms -typedef boost::intrusive::list Value1List; -typedef boost::intrusive::list Value2List; +typedef list > Value1List; +typedef list > Value2List; //] //[doc_advanced_value_traits2_test diff --git a/example/doc_assoc_optimized_code.cpp b/example/doc_assoc_optimized_code.cpp index 18dfe70..8af780c 100644 --- a/example/doc_assoc_optimized_code.cpp +++ b/example/doc_assoc_optimized_code.cpp @@ -51,24 +51,21 @@ class Expensive : public set_base_hook<>, public unordered_set_base_hook<> }; // A set and unordered_set that store Expensive objects -typedef set::value_traits > Set; -typedef unordered_set:: - value_traits > UnorderedSet; +typedef set Set; +typedef unordered_set UnorderedSet; // Search functions -Expensive *get_from_set(const char* key, Set &set) +Expensive *get_from_set(const char* key, Set &set_object) { - Set::iterator it = set.find(Expensive(key)); - if( it == set.end() ) return 0; + Set::iterator it = set_object.find(Expensive(key)); + if( it == set_object.end() ) return 0; return &*it; } -Expensive *get_from_unordered_set - (const char* key, UnorderedSet &unordered_set) +Expensive *get_from_uset(const char* key, UnorderedSet &uset_object) { - UnorderedSet::iterator it = - unordered_set.find(Expensive (key)); - if( it == unordered_set.end() ) return 0; + UnorderedSet::iterator it = uset_object.find(Expensive (key)); + if( it == uset_object.end() ) return 0; return &*it; } //] @@ -94,38 +91,35 @@ struct StrExpEqual }; // Optimized search functions -Expensive *get_from_set_optimized(const char* key, Set &set) +Expensive *get_from_set_optimized(const char* key, Set &set_object) { - Set::iterator it = set.find(key, StrExpComp()); - if( it == set.end() ) return 0; + Set::iterator it = set_object.find(key, StrExpComp()); + if( it == set_object.end() ) return 0; return &*it; } -Expensive *get_from_unordered_set_optimized - (const char* key, UnorderedSet &unordered_set) +Expensive *get_from_uset_optimized(const char* key, UnorderedSet &uset_object) { - UnorderedSet::iterator it = - unordered_set.find(key, StrHasher(), StrExpEqual()); - if( it == unordered_set.end() ) return 0; + UnorderedSet::iterator it = uset_object.find(key, StrHasher(), StrExpEqual()); + if( it == uset_object.end() ) return 0; return &*it; } //] //[doc_assoc_optimized_code_normal_insert // Insertion functions -bool insert_to_set(const char* key, Set &set) +bool insert_to_set(const char* key, Set &set_object) { Expensive *pobject = new Expensive(key); - bool success = set.insert(*pobject).second; + bool success = set_object.insert(*pobject).second; if(!success) delete pobject; return success; } -bool insert_to_unordered_set - (const char* key, UnorderedSet &unordered_set) +bool insert_to_uset(const char* key, UnorderedSet &uset_object) { Expensive *pobject = new Expensive(key); - bool success = unordered_set.insert(*pobject).second; + bool success = uset_object.insert(*pobject).second; if(!success) delete pobject; return success; } @@ -133,24 +127,20 @@ bool insert_to_unordered_set //[doc_assoc_optimized_code_optimized_insert // Optimized insertion functions -bool insert_to_set_optimized(const char* key, Set &set) +bool insert_to_set_optimized(const char* key, Set &set_object) { Set::insert_commit_data insert_data; - bool success = set.insert_check - (key, StrExpComp(), insert_data).second; - if(success) - set.insert_commit(*new Expensive(key), insert_data); + bool success = set_object.insert_check(key, StrExpComp(), insert_data).second; + if(success) set_object.insert_commit(*new Expensive(key), insert_data); return success; } -bool insert_to_unordered_set_optimized - (const char* key, UnorderedSet &unordered_set) +bool insert_to_uset_optimized(const char* key, UnorderedSet &uset_object) { UnorderedSet::insert_commit_data insert_data; - bool success = unordered_set.insert_check + bool success = uset_object.insert_check (key, StrHasher(), StrExpEqual(), insert_data).second; - if(success) - unordered_set.insert_commit(*new Expensive(key), insert_data); + if(success) uset_object.insert_commit(*new Expensive(key), insert_data); return success; } //] @@ -159,7 +149,7 @@ int main() { Set set; UnorderedSet::bucket_type buckets[10]; - UnorderedSet unordered_set(buckets, 10); + UnorderedSet unordered_set(UnorderedSet::bucket_traits(buckets, 10)); const char * const expensive_key = "A long string that avoids small string optimization"; @@ -170,7 +160,7 @@ int main() return 1; } - if(get_from_unordered_set(expensive_key, unordered_set)){ + if(get_from_uset(expensive_key, unordered_set)){ return 1; } @@ -178,7 +168,7 @@ int main() return 1; } - if(get_from_unordered_set_optimized(expensive_key, unordered_set)){ + if(get_from_uset_optimized(expensive_key, unordered_set)){ return 1; } @@ -189,7 +179,7 @@ int main() return 1; } - if(!get_from_unordered_set(expensive_key, unordered_set)){ + if(!get_from_uset(expensive_key, unordered_set)){ return 1; } @@ -197,7 +187,7 @@ int main() return 1; } - if(!get_from_unordered_set_optimized(expensive_key, unordered_set)){ + if(!get_from_uset_optimized(expensive_key, unordered_set)){ return 1; } @@ -208,7 +198,7 @@ int main() return 1; } - if(!insert_to_unordered_set(expensive_key, unordered_set)){ + if(!insert_to_uset(expensive_key, unordered_set)){ return 1; } @@ -228,7 +218,7 @@ int main() return 1; } - if(!insert_to_unordered_set_optimized(expensive_key, unordered_set)){ + if(!insert_to_uset_optimized(expensive_key, unordered_set)){ return 1; } @@ -251,7 +241,7 @@ int main() return 1; } - if(insert_to_unordered_set(expensive_key, unordered_set)){ + if(insert_to_uset(expensive_key, unordered_set)){ return 1; } @@ -259,7 +249,7 @@ int main() return 1; } - if(insert_to_unordered_set_optimized(expensive_key, unordered_set)){ + if(insert_to_uset_optimized(expensive_key, unordered_set)){ return 1; } diff --git a/example/doc_auto_unlink.cpp b/example/doc_auto_unlink.cpp index 7e048a7..848b973 100644 --- a/example/doc_auto_unlink.cpp +++ b/example/doc_auto_unlink.cpp @@ -15,39 +15,38 @@ using namespace boost::intrusive; -class MyClass : public list_base_hook +typedef list_base_hook > auto_unlink_hook; + +class MyClass : public auto_unlink_hook //This hook removes the node in the destructor { int int_; public: MyClass(int i = 0) : int_(i) {} - void unlink() { list_base_hook::unlink(); } - bool is_linked() { return list_base_hook::is_linked(); } - int get() const { return int_; } + void unlink() { auto_unlink_hook::unlink(); } + bool is_linked() { return auto_unlink_hook::is_linked(); } }; -//Define a list that will store MyClass -//using the public base hook +//Define a list that will store values using the base hook //The list can't have constant-time size! -typedef list< list_base_hook:: - value_traits, false > List; +typedef list< MyClass, constant_time_size > List; int main() { //Create the list - List list; + List l; { //Create myclass and check it's linked MyClass myclass; assert(myclass.is_linked() == false); //Insert the object - list.push_back(myclass); + l.push_back(myclass); //Check that we have inserted the object - assert(list.empty() == false); - assert(&list.front() == &myclass); + assert(l.empty() == false); + assert(&l.front() == &myclass); assert(myclass.is_linked() == true); //Now myclass' destructor will unlink it @@ -55,7 +54,7 @@ int main() } //Check auto-unlink has been executed - assert(list.empty() == true); + assert(l.empty() == true); { //Now test the unlink() function @@ -65,18 +64,18 @@ int main() assert(myclass.is_linked() == false); //Insert the object - list.push_back(myclass); + l.push_back(myclass); //Check that we have inserted the object - assert(list.empty() == false); - assert(&list.front() == &myclass); + assert(l.empty() == false); + assert(&l.front() == &myclass); assert(myclass.is_linked() == true); //Now unlink the node myclass.unlink(); //Check auto-unlink has been executed - assert(list.empty() == true); + assert(l.empty() == true); } return 0; } diff --git a/example/doc_bucket_traits.cpp b/example/doc_bucket_traits.cpp new file mode 100644 index 0000000..c03c125 --- /dev/null +++ b/example/doc_bucket_traits.cpp @@ -0,0 +1,83 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +//[doc_bucket_traits +#include +#include +#include + +using namespace boost::intrusive; + +//A class to be inserted in an unordered_set +class MyClass : public unordered_set_base_hook<> +{ + int int_; + + public: + MyClass(int i = 0) : int_(i) + {} + + friend bool operator==(const MyClass &l, const MyClass &r) + { return l.int_ == r.int_; } + friend std::size_t hash_value(const MyClass &v) + { return boost::hash_value(v.int_); } +}; + +//Define the base hook option +typedef base_hook< unordered_set_base_hook<> > BaseHookOption; + +//Obtain the types of the bucket and the bucket pointer +typedef unordered_bucket::type BucketType; +typedef unordered_bucket_ptr::type BucketPtr; + +//The custom bucket traits. +class custom_bucket_traits +{ + public: + static const int NumBuckets = 100; + + custom_bucket_traits(BucketPtr buckets) + : buckets_(buckets) + {} + + //Functions to be implemented by custom bucket traits + BucketPtr bucket_begin() const { return buckets_; } + std::size_t bucket_count() const { return NumBuckets;} + + private: + BucketPtr buckets_; +}; + +//Define the container using the custom bucket traits +typedef unordered_set > BucketTraitsUset; + +int main() +{ + typedef std::vector::iterator VectIt; + std::vector values; + + //Fill values + for(int i = 0; i < 100; ++i) values.push_back(MyClass(i)); + + //Now create the bucket array and the custom bucket traits object + BucketType buckets[custom_bucket_traits::NumBuckets]; + custom_bucket_traits btraits(buckets); + + //Now create the unordered set + BucketTraitsUset uset(btraits); + + //Insert the values in the unordered set + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it) + uset.insert(*it); + + return 0; +} +//] diff --git a/example/doc_clone_from.cpp b/example/doc_clone_from.cpp index e1da728..94c0668 100644 --- a/example/doc_clone_from.cpp +++ b/example/doc_clone_from.cpp @@ -14,9 +14,10 @@ #include #include +using namespace boost::intrusive; + //A class that can be inserted in an intrusive list -class my_class - : public boost::intrusive::list_base_hook<> +class my_class : public list_base_hook<> { public: friend bool operator==(const my_class &a, const my_class &b) @@ -28,20 +29,18 @@ class my_class }; //Definition of the intrusive list -typedef boost::intrusive::list< my_class::value_traits > my_class_list; +typedef list my_class_list; //Cloner object function -class new_cloner +struct new_cloner { - public: my_class *operator()(const my_class &clone_this) { return new my_class(clone_this); } }; //The disposer object function -class delete_disposer +struct delete_disposer { - public: void operator()(my_class *delete_this) { delete delete_this; } }; @@ -54,9 +53,8 @@ int main() //Fill all the nodes and insert them in the list my_class_list list; - for(int i = 0; i < MaxElem; ++i){ - nodes[i].int_ = i; - } + for(int i = 0; i < MaxElem; ++i) nodes[i].int_ = i; + list.insert(list.end(), nodes.begin(), nodes.end()); //Now clone "list" using "new" and "delete" object functions @@ -64,12 +62,10 @@ int main() cloned_list.clone_from(list, new_cloner(), delete_disposer()); //Test that both are equal - if(cloned_list != list){ + if(cloned_list != list) std::cout << "Both lists are different" << std::endl; - } - else{ + else std::cout << "Both lists are equal" << std::endl; - } //Don't forget to free the memory from the second list cloned_list.clear_and_dispose(delete_disposer()); diff --git a/example/doc_entity.cpp b/example/doc_entity.cpp index 4df09e4..0e2fc54 100644 --- a/example/doc_entity.cpp +++ b/example/doc_entity.cpp @@ -12,9 +12,10 @@ //[doc_entity_code #include +using namespace boost::intrusive; + //A class that can be inserted in an intrusive list -class entity - : public boost::intrusive::list_base_hook<> +class entity : public list_base_hook<> { public: virtual ~entity(); @@ -26,25 +27,25 @@ class some_entity : public entity {/**/}; //Definition of the intrusive list -typedef boost::intrusive::list< entity::value_traits > entity_list; +typedef list entity_list; //A global list -entity_list list; +entity_list global_list; -//The destructor removes itself from the list +//The destructor removes itself from the global list entity::~entity() -{ list.erase(entity_list::iterator_to(*this)); } +{ global_list.erase(entity_list::s_iterator_to(*this)); } -//Function to insert a new "some_entity" in the list +//Function to insert a new "some_entity" in the global list void insert_some_entity() -{ list.push_back (*new some_entity(/*...*/)); } +{ global_list.push_back (*new some_entity(/*...*/)); } -//Function to clear an entity from the intrusive list +//Function to clear an entity from the intrusive global list void clear_list () { - // entity's destructor removes itself from the list implicitly - while (!list.empty()) - delete &list.front(); + // entity's destructor removes itself from the global list implicitly + while (!global_list.empty()) + delete &global_list.front(); } int main() @@ -52,7 +53,7 @@ int main() //Insert some new entities insert_some_entity(); insert_some_entity(); - //list's destructor will free objects + //global_list's destructor will free objects return 0; } diff --git a/example/doc_erasing_and_disposing.cpp b/example/doc_erasing_and_disposing.cpp index 171c517..51d737f 100644 --- a/example/doc_erasing_and_disposing.cpp +++ b/example/doc_erasing_and_disposing.cpp @@ -12,9 +12,10 @@ //[doc_erasing_and_disposing #include +using namespace boost::intrusive; + //A class that can be inserted in an intrusive list -class my_class - : public boost::intrusive::list_base_hook<> +class my_class : public list_base_hook<> { public: my_class(int i) @@ -26,20 +27,18 @@ class my_class }; //Definition of the intrusive list -typedef boost::intrusive::list< my_class::value_traits > my_class_list; +typedef list my_class_list; //The predicate function -class is_even +struct is_even { - public: bool operator()(const my_class &c) const { return 0 == (c.int_ % 2); } }; //The disposer object function -class delete_disposer +struct delete_disposer { - public: void operator()(my_class *delete_this) { delete delete_this; } }; @@ -53,9 +52,7 @@ int main() try{ //Insert new objects in the container - for(int i = 0; i < MaxElem; ++i){ - list.push_back(*new my_class(i)); - } + for(int i = 0; i < MaxElem; ++i) list.push_back(*new my_class(i)); //Now use remove_and_dispose_if to erase and delete the objects list.remove_and_dispose_if(is_even(), delete_disposer()); diff --git a/example/doc_external_value_traits.cpp b/example/doc_external_value_traits.cpp new file mode 100644 index 0000000..80d366e --- /dev/null +++ b/example/doc_external_value_traits.cpp @@ -0,0 +1,129 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +//[doc_external_value_traits +#include +#include + +using namespace boost::intrusive; + +//This type is not modifiable so we can't store hooks or custom nodes +typedef int identifier_t; + +//This value traits will associate elements from an array of identifiers with +//elements of an array of nodes. The element i of the value array will use the +//node i of the node array: +class external_traits +{ + //Non-copyable + external_traits(const external_traits &); + external_traits& operator=(const external_traits &); + + public: + typedef list_node_traits node_traits; + typedef node_traits::node node; + typedef node * node_ptr; + typedef const node * const_node_ptr; + typedef identifier_t value_type; + typedef identifier_t * pointer; + typedef const identifier_t * const_pointer; + static const link_mode_type link_mode = normal_link; + + external_traits(pointer ids, std::size_t NumElements) + : ids_(ids), nodes_(NumElements) + {} + + ///Note: non static functions! + node_ptr to_node_ptr (value_type &value) + { return &this->nodes_[0] + (&value - this->ids_); } + const_node_ptr to_node_ptr (const value_type &value) const + { return &this->nodes_[0] + (&value - this->ids_); } + pointer to_value_ptr(node_ptr n) + { return this->ids_ + (n - &this->nodes_[0]); } + const_pointer to_value_ptr(const_node_ptr n) const + { return this->ids_ + (n - &this->nodes_[0]); } + + private: + pointer ids_; + //This is an array of nodes that is necessary to form the linked list + std::vector::node> nodes_; +}; + +//This is the value traits class that will be stored in the container +//and that will lead to the external traits using the address +//of the container. +struct internal_traits +{ + static const bool external_value_traits = true; + typedef external_traits value_traits; + + template + value_traits &get_value_traits(Container &cont); + + template + const value_traits &get_value_traits(const Container &cont) const; +}; + +//The intrusive list that will use external value traits +typedef list > List; + +class data_holder + : public List +{ + public: + data_holder(identifier_t *ids, std::size_t NumElements) + : List() + , external_traits_(ids, NumElements) + {} + external_traits external_traits_; +}; + +template +internal_traits::value_traits &internal_traits::get_value_traits(Container &cont) +{ return static_cast(cont).external_traits_; } + +template +const internal_traits::value_traits &internal_traits::get_value_traits(const Container &cont) const +{ return static_cast(cont).external_traits_; } + +int main() +{ + const int NumElements = 100; + + //This is an array of ids that we want to "store" + identifier_t ids [NumElements]; + + //Initialize id objects, each one with a different number + for(int i = 0; i != NumElements; ++i) ids[i] = i; + + //The data holding the list and the external traits + data_holder data(ids, NumElements); + + //This list will store ids without modifying identifier_t instances + //Stateful value traits must be explicitly passed in the constructor. + List &my_list = data; + + //Insert ids in reverse order in the list + for(identifier_t * it(&ids[0]), *itend(&ids[NumElements]); it != itend; ++it) + my_list.push_front(*it); + + //Now test lists + List::const_iterator list_it (my_list.cbegin()); + identifier_t *it_val(&ids[NumElements]-1), *it_rbeg_val(&ids[0] -1); + + //Test the objects inserted in the base hook list + for(; it_val != it_rbeg_val; --it_val, ++list_it){ + if(&*list_it != &*it_val) return 1; + } + + return 0; +} +//] diff --git a/example/doc_how_to_use.cpp b/example/doc_how_to_use.cpp index 30933a9..8284bd0 100644 --- a/example/doc_how_to_use.cpp +++ b/example/doc_how_to_use.cpp @@ -15,7 +15,7 @@ using namespace boost::intrusive; -class MyClass : public list_base_hook<> +class MyClass : public list_base_hook<> { int int_; @@ -23,62 +23,51 @@ class MyClass : public list_base_hook<> list_member_hook<> member_hook_; MyClass(int i) : int_(i) {} - int get() const { return int_; } }; //Define a list that will store MyClass using the base hook -typedef list< list_base_hook<>::value_traits > - BaseList; +typedef list BaseList; //Define a list that will store MyClass using the member hook -typedef list< list_member_hook<>:: - value_traits - > MemberList; +typedef member_hook + < MyClass, list_member_hook<>, &MyClass::member_hook_> MemberOption; +typedef list MemberList; int main() { - typedef std::vector Vect; - typedef Vect::iterator VectIt; - typedef Vect::reverse_iterator VectRit; + typedef std::vector::iterator VectIt; + typedef std::vector::reverse_iterator VectRit; - //Create several MyClass objects, each one - //with a different internal number - Vect myclassvector; - for(int i = 0; i < 100; ++i) - myclassvector.push_back(MyClass(i)); + //Create several MyClass objects, each one with a different value + std::vector values; + for(int i = 0; i < 100; ++i) values.push_back(MyClass(i)); BaseList baselist; MemberList memberlist; - //Now insert them in the reverse order - //in the base hook intrusive list - for(VectIt it(myclassvector.begin()), itend(myclassvector.end()) + //Now insert them in the reverse order in the base hook list + for(VectIt it(values.begin()), itend(values.end()) ; it != itend ; ++it){ baselist.push_front(*it); } - //Now insert them in the same order as in vector in the - //member hook intrusive list - for(VectIt it(myclassvector.begin()), itend(myclassvector.end()) - ; it != itend; ++it){ + //Now insert them in the same order as in vector in the member hook list + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it) memberlist.push_back(*it); - } //Now test lists { BaseList::reverse_iterator rbit(baselist.rbegin()), rbitend(baselist.rend()); MemberList::iterator mit(memberlist.begin()), mitend(memberlist.end()); - VectIt it(myclassvector.begin()), itend(myclassvector.end()); + VectIt it(values.begin()), itend(values.end()); //Test the objects inserted in the base hook list - for(; it != itend; ++it, ++rbit){ + for(; it != itend; ++it, ++rbit) if(&*rbit != &*it) return 1; - } //Test the objects inserted in the member hook list - for(it = myclassvector.begin(); it != itend; ++it, ++mit){ + for(it = values.begin(); it != itend; ++it, ++mit) if(&*mit != &*it) return 1; - } } return 0; diff --git a/example/doc_iterator_from_value.cpp b/example/doc_iterator_from_value.cpp index 4b935a6..b212a49 100644 --- a/example/doc_iterator_from_value.cpp +++ b/example/doc_iterator_from_value.cpp @@ -15,43 +15,44 @@ #include #include +using namespace boost::intrusive; + class intrusive_data { int data_id_; public: - int get() const { return data_id_; } void set(int id) { data_id_ = id; } //This class can be inserted in an intrusive list - typedef boost::intrusive:: - list_member_hook<> list_member_hook_t; - list_member_hook_t list_hook_; + list_member_hook<> list_hook_; //This class can be inserted in an intrusive unordered_set - typedef boost::intrusive:: - unordered_set_member_hook<> unordered_set_member_hook_t; - unordered_set_member_hook_t unordered_set_hook_; + unordered_set_member_hook<> unordered_set_hook_; //Comparison operators friend bool operator==(const intrusive_data &a, const intrusive_data &b) - { return a.get() == b.get(); } + { return a.data_id_ == b.data_id_; } friend bool operator!=(const intrusive_data &a, const intrusive_data &b) - { return a.get() != b.get(); } + { return a.data_id_ != b.data_id_; } + + //The hash function + friend std::size_t hash_value(const intrusive_data &i) + { return boost::hash()(i.data_id_); } }; -//The hash function -std::size_t hash_value(const intrusive_data &i) -{ return boost::hash()(i.get()); } - //Definition of the intrusive list that will hold intrusive_data -typedef boost::intrusive::list< intrusive_data::list_member_hook_t:: - value_traits > list_t; +typedef member_hook + , &intrusive_data::list_hook_> MemberListOption; +typedef list list_t; //Definition of the intrusive unordered_set that will hold intrusive_data -typedef boost::intrusive::unordered_set< intrusive_data::unordered_set_member_hook_t:: - value_traits > unordered_set_t; +typedef member_hook + < intrusive_data, unordered_set_member_hook<> + , &intrusive_data::unordered_set_hook_> MemberUsetOption; +typedef boost::intrusive::unordered_set + < intrusive_data, MemberUsetOption> unordered_set_t; int main() { @@ -62,30 +63,32 @@ int main() //Declare the intrusive containers list_t list; unordered_set_t::bucket_type buckets[MaxElem]; - unordered_set_t unordered_set(buckets, MaxElem); + unordered_set_t unordered_set + (unordered_set_t::bucket_traits(buckets, MaxElem)); //Initialize all the nodes - for(int i = 0; i < MaxElem; ++i) - nodes[i].set(i); + for(int i = 0; i < MaxElem; ++i) nodes[i].set(i); //Now insert them in both intrusive containers list.insert(list.end(), nodes.begin(), nodes.end()); unordered_set.insert(nodes.begin(), nodes.end()); - //Now check list::iterator_to - //which is an static member function + //Now check the iterator_to function list_t::iterator list_it(list.begin()); for(int i = 0; i < MaxElem; ++i, ++list_it) - if(list_t::iterator_to(nodes[i]) != list_it) + if(list.iterator_to(nodes[i]) != list_it || + list_t::s_iterator_to(nodes[i]) != list_it) return 1; - //Now check unordered_set::iterator_to (which is a member function) - //and unordered_set::local_current (which is an static member function) + //Now check unordered_set::s_iterator_to (which is a member function) + //and unordered_set::s_local_iterator_to (which is an static member function) unordered_set_t::iterator unordered_set_it(unordered_set.begin()); - for(int i = 0; i < MaxElem; ++i, ++unordered_set_it){ - if(unordered_set.iterator_to(nodes[i]) != unordered_set.find(nodes[i])) + for(int i = 0; i < MaxElem; ++i){ + unordered_set_it = unordered_set.find(nodes[i]); + if(unordered_set.iterator_to(nodes[i]) != unordered_set_it) return 1; - if(*unordered_set_t::local_iterator_to(nodes[i]) != *unordered_set.find(nodes[i])) + if(*unordered_set.local_iterator_to(nodes[i]) != *unordered_set_it || + *unordered_set_t::s_local_iterator_to(nodes[i]) != *unordered_set_it ) return 1; } diff --git a/example/doc_list.cpp b/example/doc_list.cpp index e923419..7137fcc 100644 --- a/example/doc_list.cpp +++ b/example/doc_list.cpp @@ -15,7 +15,7 @@ using namespace boost::intrusive; -class MyClass : public list_base_hook<> //This is a derivation hook +class MyClass : public list_base_hook<> //This is a derivation hook { int int_; @@ -26,63 +26,49 @@ class MyClass : public list_base_hook<> //This is a derivation hook MyClass(int i) : int_(i) {} - - int get() const - { return int_; } }; //Define a list that will store MyClass using the public base hook -typedef list< list_base_hook<>::value_traits > BaseList; +typedef list BaseList; //Define a list that will store MyClass using the public member hook -typedef list< list_member_hook<>::value_traits > MemberList; +typedef list< MyClass + , member_hook< MyClass, list_member_hook<>, &MyClass::member_hook_> + > MemberList; int main() { - typedef std::vector Vect; - typedef Vect::iterator VectIt; - typedef Vect::reverse_iterator VectRit; + typedef std::vector::iterator VectIt; + typedef std::vector::reverse_iterator VectRit; - //Create several MyClass objects, each one - //with a different internal number - Vect myclassvector; - for(int i = 0; i < 100; ++i) - myclassvector.push_back(MyClass(i)); + //Create several MyClass objects, each one with a different value + std::vector values; + for(int i = 0; i < 100; ++i) values.push_back(MyClass(i)); BaseList baselist; MemberList memberlist; - //Now insert them in the reverse order - //in the base hook intrusive list - for(VectIt it(myclassvector.begin()), itend(myclassvector.end()) - ; it != itend - ; ++it){ + //Now insert them in the reverse order in the base hook list + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it) baselist.push_front(*it); - } - //Now insert them in the same order as in vector in the - //member hook intrusive list - for(VectIt it(myclassvector.begin()), itend(myclassvector.end()) - ; it != itend - ; ++it){ + //Now insert them in the same order as in vector in the member hook list + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it) memberlist.push_back(*it); - } //Now test lists { BaseList::reverse_iterator rbit(baselist.rbegin()), rbitend(baselist.rend()); MemberList::iterator mit(memberlist.begin()), mitend(memberlist.end()); - VectIt it(myclassvector.begin()), itend(myclassvector.end()); + VectIt it(values.begin()), itend(values.end()); //Test the objects inserted in the base hook list - for(; it != itend; ++it, ++rbit){ + for(; it != itend; ++it, ++rbit) if(&*rbit != &*it) return 1; - } //Test the objects inserted in the member hook list - for(it = myclassvector.begin(); it != itend; ++it, ++mit){ + for(it = values.begin(); it != itend; ++it, ++mit) if(&*mit != &*it) return 1; - } } return 0; diff --git a/example/doc_offset_ptr.cpp b/example/doc_offset_ptr.cpp index ddaaa8c..1d7e87e 100644 --- a/example/doc_offset_ptr.cpp +++ b/example/doc_offset_ptr.cpp @@ -9,35 +9,49 @@ // See http://www.boost.org/libs/intrusive for documentation. // ///////////////////////////////////////////////////////////////////////////// + +//This is needed to allow concurrent test execution in +//several platforms. The shared memory must be unique +//for each process... +#include +#include + +const char *get_shared_memory_name() +{ + std::stringstream s; + s << "process_" << boost::interprocess::detail::get_current_process_id(); + static std::string str = s.str(); + return str.c_str(); +} + //[doc_offset_ptr_0 #include #include +using namespace boost::intrusive; +namespace ip = boost::interprocess; + class shared_memory_data + //Declare the hook with an offset_ptr from Boost.Interprocess + //to make this class compatible with shared memory + : public list_base_hook< void_pointer< ip::offset_ptr > > { int data_id_; public: int get() const { return data_id_; } void set(int id) { data_id_ = id; } - - //Declare the hook with an offset_ptr from Boost.Interprocess - //to make this class compatible with shared memory - typedef boost::intrusive::list_member_hook - < boost::intrusive::safe_link - , boost::interprocess::offset_ptr > member_hook_t; - member_hook_t list_hook_; }; //] //[doc_offset_ptr_1 #include #include +#include #include //Definition of the shared memory friendly intrusive list -typedef boost::intrusive::list< shared_memory_data::member_hook_t:: - value_traits > shm_list_t; +typedef ip::list shm_list_t; int main() { @@ -45,45 +59,42 @@ int main() //nodes and the container itself must be created in shared memory const int MaxElem = 100; const int ShmSize = 50000; - const char *ShmName = "SharedMemoryName"; + const char *ShmName = get_shared_memory_name(); + { + //Erase all old shared memory + ip::shared_memory_object::remove(ShmName); + ip::managed_shared_memory shm(ip::create_only, ShmName, ShmSize); - using namespace boost::interprocess; + //Create all nodes in shared memory using a shared memory vector + //See Boost.Interprocess documentation for more information on this + typedef ip::allocator + < shared_memory_data, ip::managed_shared_memory::segment_manager> + shm_allocator_t; + typedef ip::vector shm_vector_t; + shm_allocator_t shm_alloc(shm.get_segment_manager()); + shm_vector_t *pshm_vect = + shm.construct(ip::anonymous_instance)(shm_alloc); + pshm_vect->resize(MaxElem); - //Erase all old shared memory - shared_memory_object::remove(ShmName); - managed_shared_memory shm(create_only, ShmName, ShmSize); + //Initialize all the nodes + for(int i = 0; i < MaxElem; ++i) (*pshm_vect)[i].set(i); - //Create all nodes in shared memory using a shared memory vector - //See Boost.Interprocess documentation for more information on this - typedef allocator< shared_memory_data - , managed_shared_memory::segment_manager> shm_allocator_t; - typedef vector shm_vector_t; - shm_allocator_t shm_alloc(shm.get_segment_manager()); - shm_vector_t *pshm_vect = shm.construct(anonymous_instance)(shm_alloc); - pshm_vect->resize(MaxElem); + //Now create the shared memory intrusive list + shm_list_t *plist = shm.construct(ip::anonymous_instance)(); + plist->insert(plist->end(), pshm_vect->begin(), pshm_vect->end()); - //Initialize all the nodes - for(int i = 0; i < MaxElem; ++i){ - (*pshm_vect)[i].set(i); - } - - //Now create the shared memory intrusive list - shm_list_t *plist = shm.construct(anonymous_instance)(); - plist->insert(plist->end(), pshm_vect->begin(), pshm_vect->end()); - - //Check all the inserted nodes - int checker = 0; - for( shm_list_t::const_iterator it = plist->begin(), itend(plist->end()) - ; it != itend - ; ++it, ++checker){ - if(it->get() != checker){ - return false; + //Check all the inserted nodes + int checker = 0; + for( shm_list_t::const_iterator it = plist->begin(), itend(plist->end()) + ; it != itend; ++it, ++checker){ + if(it->get() != checker) return false; } - } - //Now delete the list and after that, the nodes - shm.destroy_ptr(plist); - shm.destroy_ptr(pshm_vect); + //Now delete the list and after that, the nodes + shm.destroy_ptr(plist); + shm.destroy_ptr(pshm_vect); + } + ip::shared_memory_object::remove(ShmName); return 0; } //] diff --git a/example/doc_set.cpp b/example/doc_set.cpp index 443fd48..6180e8b 100644 --- a/example/doc_set.cpp +++ b/example/doc_set.cpp @@ -17,7 +17,7 @@ using namespace boost::intrusive; //This is a base hook -class MyClass : public set_base_hook<> +class MyClass : public set_base_hook<> { int int_; @@ -28,69 +28,54 @@ class MyClass : public set_base_hook<> MyClass(int i) : int_(i) {} - int get() const - { return int_; } friend bool operator< (const MyClass &a, const MyClass &b) - { return a.get() < b.get(); } + { return a.int_ < b.int_; } friend bool operator> (const MyClass &a, const MyClass &b) - { return a.get() > b.get(); } + { return a.int_ > b.int_; } friend bool operator== (const MyClass &a, const MyClass &b) - { return a.get() < b.get(); } + { return a.int_ < b.int_; } }; -//Define an set that will store MyClass -//in reverse order using the public base hook -typedef set< set_base_hook<>::value_traits - , std::greater > BaseSet; +//Define an set using the base hook that will store values in reverse order +typedef set< MyClass, compare > > BaseSet; -//Define an multiset that will store MyClass -//using the public member hook -typedef multiset< set_member_hook<>:: - value_traits - , std::less > MemberIMultiset; +//Define an multiset using the member hook +typedef member_hook, &MyClass::member_hook_> MemberOption; +typedef multiset< MyClass, MemberOption> MemberIMultiset; int main() { - typedef std::vector Vect; - typedef Vect::iterator VectIt; - typedef Vect::reverse_iterator VectRit; + typedef std::vector::iterator VectIt; + typedef std::vector::reverse_iterator VectRit; - //Create several MyClass objects, each one - //with a different internal number - Vect myclassvector; - for(int i = 0; i < 100; ++i) - myclassvector.push_back(MyClass(i)); + //Create several MyClass objects, each one with a different value + std::vector values; + for(int i = 0; i < 100; ++i) values.push_back(MyClass(i)); BaseSet baseset; MemberIMultiset membermultiset; - //Now insert them in the reverse order - //in the base hook intrusive set - for(VectIt it(myclassvector.begin()), itend(myclassvector.end()) - ; it != itend; ++it) + //Now insert them in the reverse order in the base hook set + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it) baseset.insert(*it); - //Now insert them in the same order as in vector in the - //member hook intrusive set - for(VectIt it(myclassvector.begin()), itend(myclassvector.end()) - ; it != itend; ++it) + //Now insert them in the same order as in vector in the member hook set + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it) membermultiset.insert(*it); //Now test sets { BaseSet::reverse_iterator rbit(baseset.rbegin()), rbitend(baseset.rend()); MemberIMultiset::iterator mit(membermultiset.begin()), mitend(membermultiset.end()); - VectIt it(myclassvector.begin()), itend(myclassvector.end()); + VectIt it(values.begin()), itend(values.end()); //Test the objects inserted in the base hook set - for(; it != itend; ++it, ++rbit){ + for(; it != itend; ++it, ++rbit) if(&*rbit != &*it) return 1; - } //Test the objects inserted in the member hook set - for(it = myclassvector.begin(); it != itend; ++it, ++mit){ + for(it = values.begin(); it != itend; ++it, ++mit) if(&*mit != &*it) return 1; - } } return 0; } diff --git a/example/doc_slist.cpp b/example/doc_slist.cpp index d408662..f8164bd 100644 --- a/example/doc_slist.cpp +++ b/example/doc_slist.cpp @@ -16,7 +16,7 @@ using namespace boost::intrusive; //This is a base hook -class MyClass : public slist_base_hook<> +class MyClass : public slist_base_hook<> { int int_; @@ -27,45 +27,34 @@ class MyClass : public slist_base_hook<> MyClass(int i) : int_(i) {} - - int get() const - { return int_; } }; //Define an slist that will store MyClass using the public base hook -typedef slist< slist_base_hook<>::value_traits > BaseList; +typedef slist BaseList; //Define an slist that will store MyClass using the public member hook -typedef slist< slist_member_hook<>::value_traits > MemberList; +typedef member_hook, &MyClass::member_hook_> MemberOption; +typedef slist MemberList; int main() { - typedef std::vector Vect; - typedef Vect::iterator VectIt; - typedef Vect::reverse_iterator VectRit; + typedef std::vector::iterator VectIt; + typedef std::vector::reverse_iterator VectRit; - //Create several MyClass objects, each one - //with a different internal number - Vect myclassvector; - for(int i = 0; i < 100; ++i) - myclassvector.push_back(MyClass(i)); + //Create several MyClass objects, each one with a different value + std::vector values; + for(int i = 0; i < 100; ++i) values.push_back(MyClass(i)); BaseList baselist; MemberList memberlist; - //Now insert them in the reverse order - //in the base hook intrusive list - for(VectIt it(myclassvector.begin()), itend(myclassvector.end()) - ; it != itend - ; ++it){ + //Now insert them in the reverse order in the base hook list + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it) baselist.push_front(*it); - } - //Now insert them in the same order as in vector in the - //member hook intrusive list + //Now insert them in the same order as in vector in the member hook list for(BaseList::iterator it(baselist.begin()), itend(baselist.end()) - ; it != itend - ; ++it){ + ; it != itend; ++it){ memberlist.push_front(*it); } @@ -73,18 +62,16 @@ int main() { BaseList::iterator bit(baselist.begin()), bitend(baselist.end()); MemberList::iterator mit(memberlist.begin()), mitend(memberlist.end()); - VectRit rit(myclassvector.rbegin()), ritend(myclassvector.rend()); - VectIt it(myclassvector.begin()), itend(myclassvector.end()); + VectRit rit(values.rbegin()), ritend(values.rend()); + VectIt it(values.begin()), itend(values.end()); //Test the objects inserted in the base hook list - for(; rit != ritend; ++rit, ++bit){ + for(; rit != ritend; ++rit, ++bit) if(&*bit != &*rit) return 1; - } //Test the objects inserted in the member hook list - for(; it != itend; ++it, ++mit){ + for(; it != itend; ++it, ++mit) if(&*mit != &*it) return 1; - } } return 0; diff --git a/example/doc_stateful_value_traits.cpp b/example/doc_stateful_value_traits.cpp new file mode 100644 index 0000000..96d16f3 --- /dev/null +++ b/example/doc_stateful_value_traits.cpp @@ -0,0 +1,87 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +//[doc_stateful_value_traits +#include + +using namespace boost::intrusive; + +//This type is not modifiable so we can't store hooks or custom nodes +typedef int identifier_t; + +//This value traits will associate elements from an array of identifiers with +//elements of an array of nodes. The element i of the value array will use the +//node i of the node array: +struct stateful_value_traits +{ + typedef list_node_traits node_traits; + typedef node_traits::node node; + typedef node * node_ptr; + typedef const node * const_node_ptr; + typedef identifier_t value_type; + typedef identifier_t * pointer; + typedef const identifier_t * const_pointer; + static const link_mode_type link_mode = normal_link; + + stateful_value_traits(pointer ids, node_ptr node_array) + : ids_(ids), nodes_(node_array) + {} + + ///Note: non static functions! + node_ptr to_node_ptr (value_type &value) + { return this->nodes_ + (&value - this->ids_); } + const_node_ptr to_node_ptr (const value_type &value) const + { return this->nodes_ + (&value - this->ids_); } + pointer to_value_ptr(node_ptr n) + { return this->ids_ + (n - this->nodes_); } + const_pointer to_value_ptr(const_node_ptr n) const + { return this->ids_ + (n - this->nodes_); } + + private: + pointer ids_; + node_ptr nodes_; +}; + +int main() +{ + const int NumElements = 100; + + //This is an array of ids that we want to "store" + identifier_t ids [NumElements]; + + //This is an array of nodes that is necessary to form the linked list + list_node_traits::node nodes [NumElements]; + + //Initialize id objects, each one with a different number + for(int i = 0; i != NumElements; ++i) ids[i] = i; + + //Define a list that will "link" identifiers using external nodes + typedef list > List; + + //This list will store ids without modifying identifier_t instances + //Stateful value traits must be explicitly passed in the constructor. + List my_list (stateful_value_traits (ids, nodes)); + + //Insert ids in reverse order in the list + for(identifier_t * it(&ids[0]), *itend(&ids[NumElements]); it != itend; ++it) + my_list.push_front(*it); + + //Now test lists + List::const_iterator list_it (my_list.cbegin()); + identifier_t *it_val(&ids[NumElements-1]), *it_rbeg_val(&ids[0]-1); + + //Test the objects inserted in the base hook list + for(; it_val != it_rbeg_val; --it_val, ++list_it) + if(&*list_it != &*it_val) return 1; + + return 0; +} +//] diff --git a/example/doc_unordered_set.cpp b/example/doc_unordered_set.cpp index f561596..531ef10 100644 --- a/example/doc_unordered_set.cpp +++ b/example/doc_unordered_set.cpp @@ -17,56 +17,43 @@ using namespace boost::intrusive; - //This is a derivation hook -class MyClass : public unordered_set_base_hook<> -{ +class MyClass : public unordered_set_base_hook<> +{ //This is a derivation hook int int_; public: - //This is a member hook - unordered_set_member_hook<> member_hook_; + unordered_set_member_hook<> member_hook_; //This is a member hook MyClass(int i) : int_(i) {} - int get() const - { return int_; } - friend bool operator== (const MyClass &a, const MyClass &b) - { return a.get() == b.get(); } + { return a.int_ == b.int_; } - friend bool operator> (const MyClass &a, const MyClass &b) - { return a.get() > b.get(); } + friend std::size_t hash_value(const MyClass &value) + { return std::size_t(value.int_); } }; -std::size_t hash_value(const MyClass &value) -{ return std::size_t(value.get()); } +//Define an unordered_set that will store MyClass objects using the base hook +typedef unordered_set BaseSet; -//Define an unordered_set that will store MyClass -//in reverse order using the public base hook -typedef unordered_set< unordered_set_base_hook<>:: - value_traits > BaseSet; - -//Define an unordered_multiset that will store MyClass -//using the public member hook -typedef unordered_multiset< unordered_set_member_hook<>:: - value_traits > MemberMultiSet; +//Define an unordered_multiset that will store MyClass using the member hook +typedef member_hook, &MyClass::member_hook_> + MemberOption; +typedef unordered_multiset< MyClass, MemberOption> MemberMultiSet; int main() { - typedef std::vector Vect; - typedef Vect::iterator VectIt; - typedef Vect::reverse_iterator VectRit; + typedef std::vector::iterator VectIt; + typedef std::vector::reverse_iterator VectRit; - //Create a vector with 100 different MyClass objects, - //each one with a different internal number - Vect myclassvector; - for(int i = 0; i < 100; ++i) - myclassvector.push_back(MyClass(i)); + //Create a vector with 100 different MyClass objects + std::vector values; + for(int i = 0; i < 100; ++i) values.push_back(MyClass(i)); //Create a copy of the vector - Vect myclassvector2(myclassvector); + std::vector values2(values); //Create a bucket array for base_set BaseSet::bucket_type base_buckets[100]; @@ -74,20 +61,18 @@ int main() //Create a bucket array for member_multi_set MemberMultiSet::bucket_type member_buckets[200]; - //Create a the unordered_set and unordered_multiset, - //taking buckets as arguments - BaseSet base_set(base_buckets, 100); - MemberMultiSet member_multi_set(member_buckets, 200); + //Create unordered containers taking buckets as arguments + BaseSet base_set(BaseSet::bucket_traits(base_buckets, 100)); + MemberMultiSet member_multi_set + (MemberMultiSet::bucket_traits(member_buckets, 200)); - //Now insert myclassvector's elements in the unordered_set - for(VectIt it(myclassvector.begin()), itend(myclassvector.end()) - ; it != itend; ++it){ + //Now insert values's elements in the unordered_set + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it) base_set.insert(*it); - } - //Now insert myclassvector's and myclassvector2's elements in the unordered_multiset - for(VectIt it(myclassvector.begin()), itend(myclassvector.end()), - it2(myclassvector2.begin()),itend2(myclassvector2.end()) + //Now insert values's and values2's elements in the unordered_multiset + for(VectIt it(values.begin()), itend(values.end()), + it2(values2.begin()),itend2(values2.end()) ; it != itend; ++it, ++it2){ member_multi_set.insert(*it); member_multi_set.insert(*it2); @@ -95,7 +80,7 @@ int main() //Now find every element { - VectIt it(myclassvector.begin()), itend(myclassvector.end()); + VectIt it(values.begin()), itend(values.end()); for(; it != itend; ++it){ //base_set should contain one element for each key diff --git a/example/doc_value_traits.cpp b/example/doc_value_traits.cpp index 7b33662..e50e23b 100644 --- a/example/doc_value_traits.cpp +++ b/example/doc_value_traits.cpp @@ -10,7 +10,7 @@ // ///////////////////////////////////////////////////////////////////////////// //[doc_value_traits_code_legacy -#include +#include #include #include #include @@ -30,6 +30,9 @@ struct legacy_value //Define our own NodeTraits that will configure singly and doubly linked //list algorithms. Note that this node traits is compatible with //circular_slist_algorithms and circular_list_algorithms. + +namespace bi = boost::intrusive; + struct legacy_node_traits { typedef legacy_value node; @@ -54,7 +57,7 @@ struct legacy_value_traits typedef legacy_value value_type; typedef legacy_value * pointer; typedef const legacy_value * const_pointer; - enum { linking_policy = boost::intrusive::normal_link }; + static const bi::link_mode_type link_mode = bi::normal_link; static node_ptr to_node_ptr (value_type &value) { return node_ptr(&value); } static const_node_ptr to_node_ptr (const value_type &value) { return const_node_ptr(&value); } static pointer to_value_ptr(node_ptr n) { return pointer(n); } @@ -65,8 +68,9 @@ struct legacy_value_traits //[doc_value_traits_test //Now define an intrusive list and slist that will store legacy_value objects -typedef boost::intrusive::list LegacyAbiList; -typedef boost::intrusive::slist LegacyAbiSlist; +typedef bi::value_traits ValueTraitsOption; +typedef bi::list LegacyAbiList; +typedef bi::slist LegacyAbiSlist; template bool test_list() @@ -87,9 +91,8 @@ bool test_list() typename Vect::const_iterator it(legacy_vector.begin()), itend(legacy_vector.end()); //Test the objects inserted in our list - for(; it != itend; ++it, ++bit){ + for(; it != itend; ++it, ++bit) if(&*bit != &*it) return false; - } return true; } diff --git a/example/doc_window.cpp b/example/doc_window.cpp index dcb4875..9f49e9e 100644 --- a/example/doc_window.cpp +++ b/example/doc_window.cpp @@ -15,11 +15,11 @@ using namespace boost::intrusive; //An abstract class that can be inserted in an intrusive list -class Window : public list_base_hook<> +class Window : public list_base_hook<> { public: //This is a container those value is an abstract class: you can't do this with std::list. - typedef list< list_base_hook<>::value_traits > win_list; + typedef list win_list; //An static intrusive list declaration static win_list all_windows; @@ -27,7 +27,7 @@ class Window : public list_base_hook<> //Constructor. Includes this window in the list Window() { all_windows.push_back(*this); } //Destructor. Removes this node from the list - virtual ~Window() { all_windows.erase(win_list::iterator_to(*this)); } + virtual ~Window() { all_windows.erase(win_list::s_iterator_to(*this)); } //Pure virtual function to be implemented by derived classes virtual void Paint() = 0; }; @@ -71,15 +71,13 @@ class MainWindow : public Window //Main function int main() { - //When each Window class is created, is - //automatically registered in the global list + //When a Window class is created, is automatically registered in the global list MainWindow window; //Paint all the windows, sub-windows and so on paint_all_windows(); - //All the windows are automatically unregistered - //in their destructors. + //All the windows are automatically unregistered in their destructors. return 0; } //] diff --git a/perf/perf_list.cpp b/perf/perf_list.cpp index 2f542bb..99f3b25 100644 --- a/perf/perf_list.cpp +++ b/perf/perf_list.cpp @@ -11,6 +11,7 @@ ///////////////////////////////////////////////////////////////////////////// //Includes for tests +#include #include #include #include @@ -26,11 +27,8 @@ const int NumElements = 100000; using namespace boost::intrusive; -template -struct filler { int dummy[10]; }; - -template <> -struct filler {}; +template struct filler { int dummy[10]; }; +template <> struct filler {}; template //The object for non-intrusive containers struct test_class : private filler @@ -42,8 +40,9 @@ struct test_class : private filler friend bool operator >(const test_class &l, const test_class &r) { return l.i_ > r.i_; } }; -template //The object for intrusive containers -struct itest_class : public list_base_hook, public test_class +template +struct itest_class //The object for intrusive containers + : public list_base_hook >, public test_class { itest_class() {} itest_class(int i) : test_class(i) {} @@ -60,11 +59,10 @@ struct func_ptr_adaptor : public FuncObj }; //] -template +template struct get_ilist //Helps to define an intrusive list from a policy { - typedef list_base_hook hook; - typedef list >, false> type; + typedef list, constant_time_size > type; }; template //Helps to define an std list @@ -73,17 +71,16 @@ struct get_list { typedef std::list > type; }; template //Helps to define an std pointer list struct get_ptrlist { typedef std::list*> type; }; - //////////////////////////////////////////////////////////////////////// // // PUSH_BACK // //////////////////////////////////////////////////////////////////////// -template +template void test_intrusive_list_push_back() { - typedef typename get_ilist::type ilist; + typedef typename get_ilist::type ilist; ptime tini = microsec_clock::universal_time(); for(int i = 0; i < NumIter; ++i){ //First create the elements and insert them in the intrusive list @@ -93,11 +90,12 @@ void test_intrusive_list_push_back() for(int i = 0; i < NumElements; ++i) l.push_back(objects[i]); //Elements are unlinked in ilist's destructor - //Elements are disposed in vector's destructor + //Elements are destroyed in vector's destructor //] } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "link_mode: " << LinkMode << ", usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } template @@ -111,11 +109,12 @@ void test_std_list_push_back() stdlist l; for(int i = 0; i < NumElements; ++i) l.push_back(typename stdlist::value_type(i)); - //Elements unlinked and disposed in stdlist's destructor + //Elements unlinked and destroyed in stdlist's destructor //] } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "std::list usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } template @@ -132,12 +131,13 @@ void test_compact_std_ptrlist_push_back() stdptrlist l; for(int i = 0; i < NumElements; ++i) l.push_back(&objects[i]); - //Pointers to elements unlinked and disposed in stdptrlist's destructor - //Elements disposed in vector's destructor + //Pointers to elements unlinked and destroyed in stdptrlist's destructor + //Elements destroyed in vector's destructor //] } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "compact std::list usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } template @@ -155,12 +155,13 @@ void test_disperse_std_ptrlist_push_back() objects.push_back(typename stdlist::value_type(i)); l.push_back(&objects.back()); } - //Pointers to elements unlinked and disposed in stdptrlist's destructor - //Elements unlinked and disposed in stdlist's destructor + //Pointers to elements unlinked and destroyed in stdptrlist's destructor + //Elements unlinked and destroyed in stdlist's destructor //] } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "disperse std::list usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } //////////////////////////////////////////////////////////////////////// @@ -170,10 +171,10 @@ void test_disperse_std_ptrlist_push_back() //////////////////////////////////////////////////////////////////////// //[perf_list_reverse -template +template void test_intrusive_list_reverse() { - typedef typename get_ilist::type ilist; + typedef typename get_ilist::type ilist; //First create the elements std::vector objects(NumElements); @@ -186,7 +187,8 @@ void test_intrusive_list_reverse() l.reverse(); } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "link_mode: " << LinkMode << ", usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } template @@ -205,7 +207,8 @@ void test_std_list_reverse() l.reverse(); } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "std::list usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } template @@ -228,7 +231,8 @@ void test_compact_std_ptrlist_reverse() l.reverse(); } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "compact std::list usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } template @@ -252,7 +256,8 @@ void test_disperse_std_ptrlist_reverse() l.reverse(); } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "disperse std::list usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } //] @@ -263,10 +268,10 @@ void test_disperse_std_ptrlist_reverse() //////////////////////////////////////////////////////////////////////// //[perf_list_sort -template +template void test_intrusive_list_sort() { - typedef typename get_ilist::type ilist; + typedef typename get_ilist::type ilist; //First create the elements std::vector objects(NumElements); @@ -287,7 +292,8 @@ void test_intrusive_list_sort() } } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "link_mode: " << LinkMode << ", usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } template @@ -311,7 +317,8 @@ void test_std_list_sort() } } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "std::list usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } template @@ -340,7 +347,8 @@ void test_compact_std_ptrlist_sort() } } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "compact std::list usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } template @@ -368,7 +376,8 @@ void test_disperse_std_ptrlist_sort() } } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "disperse std::list usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } //] @@ -378,10 +387,10 @@ void test_disperse_std_ptrlist_sort() // //////////////////////////////////////////////////////////////////////// //[perf_list_write_access -template +template void test_intrusive_list_write_access() { - typedef typename get_ilist::type ilist; + typedef typename get_ilist::type ilist; //First create the elements std::vector objects(NumElements); @@ -401,7 +410,8 @@ void test_intrusive_list_write_access() } } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "link_mode: " << LinkMode << ", usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } template @@ -423,7 +433,8 @@ void test_std_list_write_access() } } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "std::list usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } template @@ -452,7 +463,8 @@ void test_compact_std_ptrlist_write_access() } } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "compact std::list usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } template @@ -479,7 +491,8 @@ void test_disperse_std_ptrlist_write_access() } } ptime tend = microsec_clock::universal_time(); - std::cout << "usecs/iteration: " << (tend-tini).total_microseconds()/NumIter << std::endl; + std::cout << "disperse std::list usecs/iteration: " + << (tend-tini).total_microseconds()/NumIter << std::endl; } //] @@ -491,7 +504,7 @@ void test_disperse_std_ptrlist_write_access() template void do_all_tests() { - std::cout << "Testing push back() with BigSize:" << BigSize << std::endl; + std::cout << "\n\nTesting push back() with BigSize:" << BigSize << std::endl; test_intrusive_list_push_back(); test_intrusive_list_push_back(); test_intrusive_list_push_back(); @@ -499,7 +512,7 @@ void do_all_tests() test_compact_std_ptrlist_push_back(); test_disperse_std_ptrlist_push_back(); //reverse - std::cout << "Testing reverse() with BigSize:" << BigSize << std::endl; + std::cout << "\n\nTesting reverse() with BigSize:" << BigSize << std::endl; test_intrusive_list_reverse(); test_intrusive_list_reverse(); test_intrusive_list_reverse(); @@ -507,7 +520,7 @@ void do_all_tests() test_compact_std_ptrlist_reverse(); test_disperse_std_ptrlist_reverse(); //sort - std::cout << "Testing sort() with BigSize:" << BigSize << std::endl; + std::cout << "\n\nTesting sort() with BigSize:" << BigSize << std::endl; test_intrusive_list_sort(); test_intrusive_list_sort(); test_intrusive_list_sort(); @@ -515,7 +528,7 @@ void do_all_tests() test_compact_std_ptrlist_sort(); test_disperse_std_ptrlist_sort(); //write_access - std::cout << "Testing write_access() with BigSize:" << BigSize << std::endl; + std::cout << "\n\nTesting write_access() with BigSize:" << BigSize << std::endl; test_intrusive_list_write_access(); test_intrusive_list_write_access(); test_intrusive_list_write_access(); diff --git a/test/custom_bucket_traits_test.cpp b/test/custom_bucket_traits_test.cpp new file mode 100644 index 0000000..7539b9c --- /dev/null +++ b/test/custom_bucket_traits_test.cpp @@ -0,0 +1,127 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include + +using namespace boost::intrusive; + +class MyClass : public unordered_set_base_hook<> +{ + int int_; + + public: + MyClass(int i = 0) : int_(i) + {} + unordered_set_member_hook<> member_hook_; + + friend bool operator==(const MyClass &l, const MyClass &r) + { return l.int_ == r.int_; } + + friend std::size_t hash_value(const MyClass &v) + { return boost::hash_value(v.int_); } +}; + +struct uset_value_traits +{ + typedef slist_node_traits node_traits; + typedef node_traits::node_ptr node_ptr; + typedef node_traits::const_node_ptr const_node_ptr; + typedef MyClass value_type; + typedef MyClass * pointer; + typedef const MyClass * const_pointer; + static const link_mode_type link_mode = normal_link; + + static node_ptr to_node_ptr (value_type &value) + { return node_ptr(&value); } + static const_node_ptr to_node_ptr (const value_type &value) + { return const_node_ptr(&value); } + static pointer to_value_ptr(node_ptr n) + { return static_cast(n); } + static const_pointer to_value_ptr(const_node_ptr n) + { return static_cast(n); } +}; + +//Base +typedef base_hook< unordered_set_base_hook<> > BaseHook; +typedef unordered_bucket::type BaseBucketType; +typedef unordered_set BaseUset; +//Member +typedef member_hook + < MyClass, unordered_set_member_hook<> + , &MyClass::member_hook_ > MemberHook; +typedef unordered_bucket::type MemberBucketType; +typedef unordered_set MemberUset; +//Explicit +typedef value_traits< uset_value_traits > Traits; +typedef unordered_bucket::type TraitsBucketType; +typedef unordered_set TraitsUset; + +struct uset_bucket_traits +{ + //Power of two bucket length + static const std::size_t NumBuckets = 128; + + uset_bucket_traits(BaseBucketType *buckets) + : buckets_(buckets) + {} + + uset_bucket_traits(const uset_bucket_traits &other) + : buckets_(other.buckets_) + {} + + BaseBucketType * bucket_begin() const + { return buckets_; } + + std::size_t bucket_count() const + { return NumBuckets; } + + BaseBucketType *buckets_; +}; + +typedef unordered_set + , power_2_buckets > + BucketTraitsUset; + +int main() +{ + if(!detail::is_same::value) + return 1; + if(!detail::is_same::value) + return 1; + if(!detail::is_same::value) + return 1; + if(!detail::is_same::value) + return 1; + if(!detail::is_same::value) + return 1; + + typedef std::vector::iterator VectIt; + typedef std::vector::reverse_iterator VectRit; + std::vector values; + + for(int i = 0; i < 100; ++i) values.push_back(MyClass(i)); + + BaseBucketType buckets[uset_bucket_traits::NumBuckets]; + uset_bucket_traits btraits(buckets); + BucketTraitsUset uset(btraits); + + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it) + uset.insert(*it); + + for( VectRit it(values.rbegin()), itend(values.rend()); it != itend; ++it){ + if(uset.find(*it) == uset.cend()) return 1; + } + + return 0; +} diff --git a/test/default_hook_test.cpp b/test/default_hook_test.cpp new file mode 100644 index 0000000..938095f --- /dev/null +++ b/test/default_hook_test.cpp @@ -0,0 +1,97 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include "smart_ptr.hpp" +#include + +using namespace boost::intrusive; + +class MyClass + +: public list_base_hook + < void_pointer >, link_mode > +, public slist_base_hook + < void_pointer >, link_mode > +, public set_base_hook + < void_pointer >, link_mode > +, public unordered_set_base_hook + < void_pointer >, link_mode > +{ + int int_; + + public: + MyClass(int i) + : int_(i) + {} + + friend bool operator<(const MyClass &l, const MyClass &r) + { return l.int_ < r.int_; } + + friend bool operator==(const MyClass &l, const MyClass &r) + { return l.int_ == r.int_; } + + friend std::size_t hash_value(const MyClass &v) + { return boost::hash_value(v.int_); } +}; + +//Define a list that will store MyClass using the public base hook +typedef list List; +typedef slist Slist; +typedef set Set; +typedef unordered_set USet; + +int main() +{ + typedef std::vector::iterator VectIt; + typedef std::vector::reverse_iterator VectRit; + + //Create several MyClass objects, each one with a different value + std::vector values; + for(int i = 0; i < 100; ++i) values.push_back(MyClass(i)); + + USet::bucket_type buckets[100]; + + List my_list; + Slist my_slist; + Set my_set; + USet my_uset(USet::bucket_traits(buckets, 100)); + + //Now insert them in the reverse order + //in the base hook intrusive list + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it){ + my_list.push_front(*it); + my_slist.push_front(*it); + my_set.insert(*it); + my_uset.insert(*it); + } + + //Now test lists + { + List::const_iterator list_it(my_list.cbegin()); + Slist::const_iterator slist_it(my_slist.cbegin()); + Set::const_reverse_iterator set_rit(my_set.crbegin()); + VectRit vect_it(values.rbegin()), vect_itend(values.rend()); + + //Test the objects inserted in the base hook list + for(; vect_it != vect_itend; ++vect_it, ++list_it, ++slist_it, ++set_rit){ + if(&*list_it != &*vect_it) return 1; + if(&*slist_it != &*vect_it) return 1; + if(&*set_rit != &*vect_it) return 1; + if(my_uset.find(*set_rit) == my_uset.cend()) return 1; + } + } + + return 0; +} diff --git a/test/external_value_traits_test.cpp b/test/external_value_traits_test.cpp new file mode 100644 index 0000000..c27177a --- /dev/null +++ b/test/external_value_traits_test.cpp @@ -0,0 +1,240 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::intrusive; + +class MyClass +{ + public: + int int_; + + MyClass(int i = 0) + : int_(i) + {} + friend bool operator > (const MyClass &l, const MyClass &r) + { return l.int_ > r.int_; } + friend bool operator == (const MyClass &l, const MyClass &r) + { return l.int_ == r.int_; } + friend std::size_t hash_value(const MyClass &v) + { return boost::hash_value(v.int_); } +}; + +const int NumElements = 100; + +template +struct external_traits +{ + typedef NodeTraits node_traits; + typedef typename node_traits::node node; + typedef typename node_traits::node_ptr node_ptr; + typedef typename node_traits::const_node_ptr const_node_ptr; + typedef MyClass value_type; + typedef typename boost::pointer_to_other + ::type pointer; + typedef typename boost::pointer_to_other + ::type const_pointer; + static const link_mode_type link_mode = normal_link; + + external_traits(pointer values, std::size_t NumElem) + : values_(values), node_array_(NumElem) + {} + + node_ptr to_node_ptr (value_type &value) + { return (&node_array_[0]) + (&value - values_); } + + const_node_ptr to_node_ptr (const value_type &value) const + { return &node_array_[0] + (&value - values_); } + + pointer to_value_ptr(node_ptr n) + { return values_ + (n - &node_array_[0]); } + + const_pointer to_value_ptr(const_node_ptr n) const + { return values_ + (n - &node_array_[0]); } + + pointer values_; + std::vector node_array_; +}; + +template +struct value_traits_proxy; + +template +struct traits_holder + : public T +{}; + +typedef value_traits_proxy > list_value_traits_proxy; +typedef value_traits_proxy > slist_value_traits_proxy; +typedef value_traits_proxy > rbtree_value_traits_proxy; +typedef value_traits_proxy > > hash_value_traits_proxy; + +struct uset_bucket_traits +{ + private: + typedef unordered_bucket > > > >::type bucket_type; + + //Non-copyable + uset_bucket_traits(const uset_bucket_traits &other); + uset_bucket_traits & operator=(const uset_bucket_traits &other); + + public: + static const std::size_t NumBuckets = 100; + + uset_bucket_traits(){} + + bucket_type * bucket_begin() const + { return buckets_; } + + std::size_t bucket_count() const + { return NumBuckets; } + + mutable bucket_type buckets_[NumBuckets]; +}; + +struct bucket_traits_proxy +{ + static const bool external_bucket_traits = true; + typedef uset_bucket_traits bucket_traits; + + template + bucket_traits &get_bucket_traits(Container &cont); + + template + const bucket_traits &get_bucket_traits(const Container &cont) const; +}; + +//Define a list that will store MyClass using the external hook +typedef list > List; +//Define a slist that will store MyClass using the external hook +typedef slist > Slist; +//Define a rbtree that will store MyClass using the external hook +typedef rbtree< MyClass + , value_traits + , compare > > Rbtree; +//Define a hashtable that will store MyClass using the external hook +typedef hashtable< MyClass + , value_traits + , bucket_traits + > Hash; + +template +struct value_traits_proxy +{ + static const bool external_value_traits = true; + typedef external_traits value_traits; + + template + const value_traits &get_value_traits(const Container &cont) const; + + template + value_traits &get_value_traits(Container &cont); +}; + +struct ContainerHolder + : public uset_bucket_traits + , public List + , public external_traits > + , public Slist + , public external_traits > + , public Rbtree + , public external_traits > + , public Hash + , public external_traits > > +{ + static const std::size_t NumBucket = 100; + ContainerHolder(MyClass *values, std::size_t num_elem) + : uset_bucket_traits() + , List() + , external_traits >(values, num_elem) + , Slist() + , external_traits >(values, num_elem) + , Rbtree() + , external_traits >(values, num_elem) + , Hash(Hash::bucket_traits()) + , external_traits > >(values, num_elem) + {} +}; + +template +template +typename value_traits_proxy::value_traits & + value_traits_proxy::get_value_traits(Container &cont) +{ return static_cast(static_cast(cont)); } + +template +template +const typename value_traits_proxy::value_traits & + value_traits_proxy::get_value_traits(const Container &cont) const +{ return static_cast(static_cast(cont)); } + +template +typename bucket_traits_proxy::bucket_traits & + bucket_traits_proxy::get_bucket_traits(Container &cont) +{ return static_cast(static_cast(cont)); } + +template +const typename bucket_traits_proxy::bucket_traits & + bucket_traits_proxy::get_bucket_traits(const Container &cont) const +{ return static_cast(static_cast(cont)); } + +int main() +{ + MyClass values [NumElements]; + //Create several MyClass objects, each one with a different value + for(int i = 0; i < NumElements; ++i) + values[i].int_ = i; + + ContainerHolder cont_holder(values, NumElements); + List &my_list = static_cast (cont_holder); + Slist &my_slist = static_cast (cont_holder); + Rbtree &my_rbtree = static_cast (cont_holder); + Hash &my_hash = static_cast (cont_holder); + + //Now insert them in the reverse order + //in the base hook intrusive list + for(MyClass * it(&values[0]), *itend(&values[NumElements]) + ; it != itend; ++it){ + my_list.push_front(*it); + my_slist.push_front(*it); + my_rbtree.insert_unique(*it); + my_hash.insert_unique(*it); + } + + //Now test lists + { + List::const_iterator list_it (my_list.cbegin()); + Slist::const_iterator slist_it (my_slist.cbegin()); + Rbtree::const_iterator rbtree_it (my_rbtree.cbegin()); + Hash::const_iterator hash_it (my_hash.cbegin()); + MyClass *it_val(&values[NumElements] - 1), *it_rbeg_val(&values[0]-1); + + //Test the objects inserted in the base hook list + for(; it_val != it_rbeg_val; --it_val, ++list_it, ++slist_it, ++rbtree_it){ + if(&*list_it != &*it_val) return 1; + if(&*slist_it != &*it_val) return 1; + if(&*rbtree_it != &*it_val) return 1; + hash_it = my_hash.find(*it_val); + if(hash_it == my_hash.cend() || &*hash_it != &*it_val) + return 1; + } + } + + return 0; +} diff --git a/test/list_test.cpp b/test/list_test.cpp index bdb752c..7b28289 100644 --- a/test/list_test.cpp +++ b/test/list_test.cpp @@ -35,17 +35,19 @@ struct test_list static void test_shift(std::vector& values); static void test_swap(std::vector& values); static void test_clone(std::vector& values); + static void test_container_from_end(std::vector& values); }; template void test_list::test_all(std::vector& values) { - typedef boost::intrusive::list - < ValueTraits - , ValueTraits::value_type::constant_time_size - , std::size_t + typedef typename ValueTraits::value_type value_type; + typedef list + < value_type + , value_traits + , size_type + , constant_time_size > list_type; - { list_type list(values.begin(), values.end()); test::test_container(list); @@ -60,9 +62,15 @@ void test_list::test_all(std::vector void test_list ::test_front_back(std::vector& values) { - typedef boost::intrusive::list - < ValueTraits - , ValueTraits::value_type::constant_time_size - , std::size_t + typedef typename ValueTraits::value_type value_type; + typedef list + < value_type + , value_traits + , size_type + , constant_time_size > list_type; list_type testlist; BOOST_TEST (testlist.empty()); @@ -104,12 +114,12 @@ template void test_list ::test_sort(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - std::vector expected; - typedef boost::intrusive::list - < ValueTraits - , ValueTraits::value_type::constant_time_size - , std::size_t + typedef typename ValueTraits::value_type value_type; + typedef list + < value_type + , value_traits + , size_type + , constant_time_size > list_type; list_type testlist(values.begin(), values.end()); @@ -125,17 +135,17 @@ void test_list TEST_INTRUSIVE_SEQUENCE( init_values, testlist.begin() ); } } -//test: assign, insert, const_iterator, const_reverse_iterator, erase, iterator_to: +//test: assign, insert, const_iterator, const_reverse_iterator, erase, s_iterator_to: template void test_list ::test_insert(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - std::vector expected; - typedef boost::intrusive::list - < ValueTraits - , ValueTraits::value_type::constant_time_size - , std::size_t + typedef typename ValueTraits::value_type value_type; + typedef list + < value_type + , value_traits + , size_type + , constant_time_size > list_type; list_type testlist; testlist.assign (&values[0] + 2, &values[0] + 5); @@ -159,6 +169,9 @@ void test_list i = testlist.iterator_to (values[4]); BOOST_TEST (&*i == &values[4]); + i = list_type::s_iterator_to (values[4]); + BOOST_TEST (&*i == &values[4]); + i = testlist.erase (i); BOOST_TEST (i == testlist.end()); @@ -170,15 +183,14 @@ template void test_list ::test_shift(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::list - < ValueTraits - , ValueTraits::value_type::constant_time_size - , std::size_t + typedef typename ValueTraits::value_type value_type; + typedef list + < value_type + , value_traits + , size_type + , constant_time_size > list_type; list_type testlist; - std::vector expected; - const int num_values = (int)values.size(); std::vector expected_values(num_values); @@ -210,12 +222,13 @@ template void test_list ::test_swap(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::list - + , size_type + , constant_time_size > list_type; - std::vector expected; { list_type testlist1 (&values[0], &values[0] + 2); list_type testlist2; @@ -267,23 +280,40 @@ void test_list } } +template +void test_list + ::test_container_from_end(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef list + < value_type + , value_traits + , size_type + , constant_time_size + > list_type; + list_type testlist1 (&values[0], &values[0] + values.size()); + BOOST_TEST (testlist1 == list_type::container_from_end_iterator(testlist1.end())); + BOOST_TEST (testlist1 == list_type::container_from_end_iterator(testlist1.cend())); +} + + template void test_list ::test_clone(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - std::vector expected; - typedef boost::intrusive::list - + , size_type + , constant_time_size > list_type; - list_type testlist1 (&values[0], &values[0] + values.size()); list_type testlist2; - testlist2.clone_from(testlist1, test::new_cloner(), test::delete_disposer()); + testlist2.clone_from(testlist1, test::new_cloner(), test::delete_disposer()); BOOST_TEST (testlist2 == testlist1); - testlist2.clear_and_dispose(test::delete_disposer()); + testlist2.clear_and_dispose(test::delete_disposer()); BOOST_TEST (testlist2.empty()); } @@ -293,17 +323,24 @@ class test_main_template public: int operator()() { - typedef testvalue testvalue_t; - std::vector data (5); + typedef testvalue value_type; + std::vector data (5); for (int i = 0; i < 5; ++i) data[i].value_ = i + 1; - test_list >::test_all(data); - - test_list >::test_all(data); - + test_list < typename detail::get_base_value_traits + < value_type + , typename value_type::list_base_hook_t + >::type + >::test_all(data); + test_list < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::list_member_hook_t + , &value_type::list_node_ + > + >::type + >::test_all(data); return 0; } }; @@ -314,48 +351,64 @@ class test_main_template public: int operator()() { - typedef testvalue testvalue_t; - std::vector data (5); + typedef testvalue value_type; + std::vector data (5); for (int i = 0; i < 5; ++i) data[i].value_ = i + 1; - test_list >::test_all(data); + test_list < typename detail::get_base_value_traits + < value_type + , typename value_type::list_base_hook_t + >::type + >::test_all(data); - test_list >::test_all(data); + test_list < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::list_member_hook_t + , &value_type::list_node_ + > + >::type + >::test_all(data); +/* + test_list + , safe_link> + >::test_all(data); +*/ + test_list < typename detail::get_base_value_traits + < value_type + , typename value_type::list_auto_base_hook_t + >::type + >::test_all(data); - test_list >::test_all(data); - - test_list >::test_all(data); + test_list < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::list_auto_member_hook_t + , &value_type::list_auto_node_ + > + >::type + >::test_all(data); +/* + test_list + , auto_unlink> + >::test_all(data); +*/ return 0; } }; -//Explicit instantiations of non-counted classes -//template class boost::intrusive::list; -//template class boost::intrusive::list; -//template class boost::intrusive::list; -//template class boost::intrusive::list; -//template class boost::intrusive::list; -//template class boost::intrusive::list; -//template class boost::intrusive::list; -//template class boost::intrusive::list; - -//Explicit instantiation of counted classes -//template class boost::intrusive::list; -//template class boost::intrusive::list; -//template class boost::intrusive::list; -//template class boost::intrusive::list; - int main( int, char* [] ) { test_main_template()(); - test_main_template, false>()(); + test_main_template, false>()(); test_main_template()(); - test_main_template, true>()(); + test_main_template, true>()(); + return boost::report_errors(); } #include diff --git a/test/make_functions_test.cpp b/test/make_functions_test.cpp new file mode 100644 index 0000000..3c9b4a1 --- /dev/null +++ b/test/make_functions_test.cpp @@ -0,0 +1,148 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include "smart_ptr.hpp" +#include + +using namespace boost::intrusive; + +class MyClass +: public make_list_base_hook + < void_pointer >, link_mode >::type +, public make_slist_base_hook + < void_pointer >, link_mode >::type +, public make_set_base_hook + < void_pointer >, link_mode >::type +, public make_unordered_set_base_hook + < void_pointer >, link_mode >::type +{ + int int_; + + public: + MyClass(int i) + : int_(i) + {} + + friend bool operator<(const MyClass &l, const MyClass &r) + { return l.int_ < r.int_; } + + friend bool operator==(const MyClass &l, const MyClass &r) + { return l.int_ == r.int_; } + + friend std::size_t hash_value(const MyClass &v) + { return boost::hash_value(v.int_); } +}; + +//Define a list that will store MyClass using the public base hook +typedef make_list::type List; +typedef make_slist::type Slist; +typedef make_set::type Set; +typedef make_unordered_set::type USet; + +int main() +{ + typedef std::vector::iterator VectIt; + typedef std::vector::reverse_iterator VectRit; + + //Create several MyClass objects, each one with a different value + std::vector values; + for(int i = 0; i < 100; ++i) values.push_back(MyClass(i)); + + USet::bucket_type buckets[100]; + + List my_list; + Slist my_slist; + Set my_set; + USet my_uset(USet::bucket_traits(buckets, 100)); + + //Now insert them in the reverse order + //in the base hook intrusive list + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it){ + my_list.push_front(*it); + my_slist.push_front(*it); + my_set.insert(*it); + my_uset.insert(*it); + } + + //Now test lists + { + List::const_iterator list_it(my_list.cbegin()); + Slist::const_iterator slist_it(my_slist.cbegin()); + Set::const_reverse_iterator set_rit(my_set.crbegin()); + VectRit vect_it(values.rbegin()), vect_itend(values.rend()); + + //Test the objects inserted in the base hook list + for(; vect_it != vect_itend; ++vect_it, ++list_it, ++slist_it, ++set_rit){ + if(&*list_it != &*vect_it) return 1; + if(&*slist_it != &*vect_it) return 1; + if(&*set_rit != &*vect_it) return 1; + if(my_uset.find(*set_rit) == my_uset.cend()) return 1; + } + } + + //Check defined types and implicitly defined types are equal + if(detail::is_same, link_mode >::type + ,make_list_base_hook<>::type + >::value == false){ + return 1; + } + + if(detail::is_same, link_mode >::type + ,make_slist_base_hook<>::type + >::value == false){ + return 1; + } + + if(detail::is_same, link_mode >::type + ,make_set_base_hook<>::type + >::value == false){ + return 1; + } + + if(detail::is_same, link_mode >::type + ,make_unordered_set_base_hook<>::type + >::value == false){ + return 1; + } + + //Check defined types and implicitly defined types are unequal + if(detail::is_same, link_mode >::type + ,make_list_base_hook<>::type + >::value == true){ + return 1; + } + + if(detail::is_same, link_mode >::type + ,make_slist_base_hook<>::type + >::value == true){ + return 1; + } + + if(detail::is_same, link_mode >::type + ,make_set_base_hook<>::type + >::value == true){ + return 1; + } + + if(detail::is_same, link_mode >::type + ,make_unordered_set_base_hook<>::type + >::value == true){ + return 1; + } + + + return 0; +} diff --git a/test/multiset_test.cpp b/test/multiset_test.cpp index 99d803b..93c9d73 100644 --- a/test/multiset_test.cpp +++ b/test/multiset_test.cpp @@ -10,6 +10,7 @@ // See http://www.boost.org/libs/intrusive for documentation. // ///////////////////////////////////////////////////////////////////////////// + #include #include #include @@ -22,7 +23,6 @@ #include "test_container.hpp" using namespace boost::intrusive; - template struct test_multiset { @@ -34,15 +34,17 @@ struct test_multiset static void test_find(std::vector& values); static void test_impl(); static void test_clone(std::vector& values); + static void test_container_from_end(std::vector& values); }; template void test_multiset::test_all (std::vector& values) { + typedef typename ValueTraits::value_type value_type; typedef multiset - - ,ValueTraits::value_type::constant_time_size, std::size_t + < value_type + , value_traits + , constant_time_size > multiset_type; { multiset_type testset(values.begin(), values.end()); @@ -63,21 +65,24 @@ void test_multiset::test_all (std::vector void test_multiset::test_impl() { - typedef typename ValueTraits::value_type testvalue_t; - std::vector values (5); + typedef typename ValueTraits::value_type value_type; + std::vector values (5); for (int i = 0; i < 5; ++i) values[i].value_ = i; + typedef typename ValueTraits::value_type value_type; typedef multiset - - ,ValueTraits::value_type::constant_time_size, std::size_t + < value_type + , value_traits + , constant_time_size > multiset_type; + multiset_type testset; for (int i = 0; i < 5; ++i) testset.insert (values[i]); @@ -94,12 +99,13 @@ void test_multiset::test_impl() template void test_multiset::test_sort(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; + typedef typename ValueTraits::value_type value_type; typedef multiset - - ,ValueTraits::value_type::constant_time_size, std::size_t + < value_type + , value_traits + , constant_time_size > multiset_type; + multiset_type testset1 (values.begin(), values.end()); { int init_values [] = { 1, 2, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } @@ -108,9 +114,10 @@ void test_multiset::test_sort(std::vector + , value_traits + , constant_time_size > multiset_type2; multiset_type2 testset2 (&values[0], &values[0] + 6); { int init_values [] = { 5, 3, 1, 4, 2, 2 }; @@ -124,11 +131,12 @@ void test_multiset::test_sort(std::vector void test_multiset::test_insert(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; + typedef typename ValueTraits::value_type value_type; typedef multiset - - ,ValueTraits::value_type::constant_time_size, std::size_t + < value_type + , value_traits + , size_type + , constant_time_size > multiset_type; multiset_type testset; @@ -147,6 +155,10 @@ void test_multiset::test_insert(std::vector::test_insert(std::vector void test_multiset::test_swap(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; + typedef typename ValueTraits::value_type value_type; typedef multiset - - ,ValueTraits::value_type::constant_time_size, std::size_t + < value_type + , value_traits + , size_type + , constant_time_size > multiset_type; multiset_type testset1 (&values[0], &values[0] + 2); multiset_type testset2; @@ -182,16 +195,17 @@ void test_multiset::test_swap(std::vector void test_multiset::test_find(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; + typedef typename ValueTraits::value_type value_type; typedef multiset - - ,ValueTraits::value_type::constant_time_size, std::size_t + < value_type + , value_traits + , size_type + , constant_time_size > multiset_type; multiset_type testset (values.begin(), values.end()); typedef typename multiset_type::iterator iterator; - testvalue_t cmp_val; + value_type cmp_val; cmp_val.value_ = 2; iterator i = testset.find (cmp_val); BOOST_TEST (i->value_ == 2); @@ -210,20 +224,37 @@ template void test_multiset ::test_clone(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; + typedef typename ValueTraits::value_type value_type; typedef multiset - - ,ValueTraits::value_type::constant_time_size, std::size_t + < value_type + , value_traits + , size_type + , constant_time_size + > multiset_type; + multiset_type testmultiset1 (&values[0], &values[0] + values.size()); + multiset_type testmultiset2; + + testmultiset2.clone_from(testmultiset1, test::new_cloner(), test::delete_disposer()); + BOOST_TEST (testmultiset2 == testmultiset1); + testmultiset2.clear_and_dispose(test::delete_disposer()); + BOOST_TEST (testmultiset2.empty()); +} + +template +void test_multiset + ::test_container_from_end(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef multiset + < value_type + , value_traits + , size_type + , constant_time_size > multiset_type; - multiset_type testmultiset1 (&values[0], &values[0] + values.size()); - multiset_type testmultiset2; - - testmultiset2.clone_from(testmultiset1, test::new_cloner(), test::delete_disposer()); - BOOST_TEST (testmultiset2 == testmultiset1); - testmultiset2.clear_and_dispose(test::delete_disposer()); - BOOST_TEST (testmultiset2.empty()); + multiset_type testmultiset (&values[0], &values[0] + values.size()); + BOOST_TEST (testmultiset == multiset_type::container_from_end_iterator(testmultiset.end())); + BOOST_TEST (testmultiset == multiset_type::container_from_end_iterator(testmultiset.cend())); } template @@ -232,18 +263,25 @@ class test_main_template public: int operator()() { - typedef testvalue testvalue_t; + typedef testvalue value_type; static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; std::vector > data (6); for (int i = 0; i < 6; ++i) data[i].value_ = random_init[i]; - test_multiset >::test_all(data); - - test_multiset >::test_all(data); - + test_multiset < typename detail::get_base_value_traits + < value_type + , typename value_type::set_base_hook_t + >::type + >::test_all(data); + test_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::set_member_hook_t + , &value_type::set_node_ + > + >::type + >::test_all(data); return 0; } }; @@ -254,55 +292,73 @@ class test_main_template public: int operator()() { - typedef testvalue testvalue_t; + typedef testvalue value_type; static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; std::vector > data (6); for (int i = 0; i < 6; ++i) data[i].value_ = random_init[i]; - test_multiset >::test_all(data); + test_multiset < typename detail::get_base_value_traits + < value_type + , typename value_type::set_base_hook_t + >::type + >::test_all(data); - test_multiset >::test_all(data); + test_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::set_member_hook_t + , &value_type::set_node_ + > + >::type + >::test_all(data); - test_multiset >::test_all(data); + test_multiset < typename detail::get_base_value_traits + < value_type + , typename value_type::set_auto_base_hook_t + >::type + >::test_all(data); - test_multiset >::test_all(data); + test_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::set_auto_member_hook_t + , &value_type::set_auto_node_ + > + >::type + >::test_all(data); return 0; } }; -/* + //Explicit instantiations of non-counted classes -template class multiset - , false>; -template class multiset - , false>; -template class multiset - , false>; -template class multiset - , false>; -template class multiset - , false>; -template class multiset - , false>; -template class multiset - , false>; -template class multiset - , false>; +//template class multiset +// , false>; +//template class multiset +// , false>; +//template class multiset +// , false>; +//template class multiset +// , false>; +//template class multiset +// , false>; +//template class multiset +// , false>; +//template class multiset +// , false>; +//template class multiset +// , false>; //Explicit instantiation of counted classes -template class multiset - , true>; -template class multiset - , true>; -template class multiset - , true>; -template class multiset - , true>; -*/ +//template class multiset +// , true>; +//template class multiset +// , true>; +//template class multiset +// , true>; +//template class multiset +// , true>; + int main( int, char* [] ) { test_main_template()(); @@ -311,5 +367,3 @@ int main( int, char* [] ) test_main_template, true>()(); return boost::report_errors(); } - -#include diff --git a/test/set_test.cpp b/test/set_test.cpp index 6b95383..15f8e7d 100644 --- a/test/set_test.cpp +++ b/test/set_test.cpp @@ -34,15 +34,17 @@ struct test_set static void test_find(std::vector& values); static void test_impl(); static void test_clone(std::vector& values); + static void test_container_from_end(std::vector& values); }; template void test_set::test_all(std::vector& values) { - typedef boost::intrusive::set - - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef set + < value_type + , value_traits + , constant_time_size > set_type; { set_type testset(values.begin(), values.end()); @@ -63,21 +65,23 @@ void test_set::test_all(std::vector void test_set::test_impl() { - typedef typename ValueTraits::value_type testvalue_t; - std::vector values (5); + typedef typename ValueTraits::value_type value_type; + std::vector values (5); for (int i = 0; i < 5; ++i) values[i].value_ = i; - typedef boost::intrusive::set - - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef set + < value_type + , value_traits + , constant_time_size > set_type; set_type testset; for (int i = 0; i < 5; ++i) @@ -95,11 +99,11 @@ void test_set::test_impl() template void test_set::test_sort(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::set - - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef set + < value_type + , value_traits + , constant_time_size > set_type; set_type testset1 (values.begin(), values.end()); { int init_values [] = { 1, 2, 3, 4, 5 }; @@ -108,10 +112,12 @@ void test_set::test_sort(std::vector + , value_traits + , constant_time_size > set_type2; set_type2 testset2 (&values[0], &values[0] + 6); { int init_values [] = { 5, 3, 1, 4, 2 }; @@ -120,15 +126,15 @@ void test_set::test_sort(std::vectorvalue_ == 5); } -//test: insert, const_iterator, const_reverse_iterator, erase, iterator_to: +//test: insert, const_iterator, const_reverse_iterator, erase, s_iterator_to: template void test_set::test_insert(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::set - - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef set + < value_type + , value_traits + , constant_time_size > set_type; set_type testset; testset.insert(&values[0] + 2, &values[0] + 5); @@ -149,6 +155,9 @@ void test_set::test_insert(std::vector::test_insert(std::vector void test_set::test_swap(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::set - - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef set + < value_type + , value_traits + , constant_time_size > set_type; set_type testset1 (&values[0], &values[0] + 2); set_type testset2; @@ -185,16 +194,16 @@ void test_set::test_swap(std::vector void test_set::test_find(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::set - - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef set + < value_type + , value_traits + , constant_time_size > set_type; set_type testset (values.begin(), values.end()); typedef typename set_type::iterator iterator; - testvalue_t cmp_val; + value_type cmp_val; cmp_val.value_ = 2; iterator i = testset.find (cmp_val); BOOST_TEST (i->value_ == 2); @@ -213,20 +222,35 @@ template void test_set ::test_clone(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::set - - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef set + < value_type + , value_traits + , constant_time_size > set_type; - set_type testset1 (&values[0], &values[0] + values.size()); - set_type testset2; + set_type testset1 (&values[0], &values[0] + values.size()); + set_type testset2; - testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); - BOOST_TEST (testset2 == testset1); - testset2.clear_and_dispose(test::delete_disposer()); - BOOST_TEST (testset2.empty()); + testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); + BOOST_TEST (testset2 == testset1); + testset2.clear_and_dispose(test::delete_disposer()); + BOOST_TEST (testset2.empty()); +} + +template +void test_set + ::test_container_from_end(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef set + < value_type + , value_traits + , constant_time_size + > set_type; + set_type testset (&values[0], &values[0] + values.size()); + BOOST_TEST (testset == set_type::container_from_end_iterator(testset.end())); + BOOST_TEST (testset == set_type::container_from_end_iterator(testset.cend())); } template @@ -235,18 +259,25 @@ class test_main_template public: int operator()() { - typedef testvalue testvalue_t; + typedef testvalue value_type; static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; std::vector > data (6); for (int i = 0; i < 6; ++i) data[i].value_ = random_init[i]; - test_set >::test_all(data); - - test_set >::test_all(data); - + test_set < typename detail::get_base_value_traits + < value_type + , typename value_type::set_base_hook_t + >::type + >::test_all(data); + test_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::set_member_hook_t + , &value_type::set_node_ + > + >::type + >::test_all(data); return 0; } }; @@ -257,61 +288,53 @@ class test_main_template public: int operator()() { - typedef testvalue testvalue_t; + typedef testvalue value_type; static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; std::vector > data (6); for (int i = 0; i < 6; ++i) data[i].value_ = random_init[i]; - test_set >::test_all(data); + test_set < typename detail::get_base_value_traits + < value_type + , typename value_type::set_base_hook_t + >::type + >::test_all(data); - test_set >::test_all(data); + test_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::set_member_hook_t + , &value_type::set_node_ + > + >::type + >::test_all(data); - test_set >::test_all(data); + test_set < typename detail::get_base_value_traits + < value_type + , typename value_type::set_auto_base_hook_t + >::type + >::test_all(data); + + test_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::set_auto_member_hook_t + , &value_type::set_auto_node_ + > + >::type + >::test_all(data); - test_set >::test_all(data); return 0; } }; -/* -//Explicit instantiations of non-counted classes -template class boost::intrusive::set - , false>; -template class boost::intrusive::set - , false>; -template class boost::intrusive::set - , false>; -template class boost::intrusive::set - , false>; -template class boost::intrusive::set - , false>; -template class boost::intrusive::set - , false>; -template class boost::intrusive::set - , false>; -template class boost::intrusive::set - , false>; -//Explicit instantiation of counted classes -template class boost::intrusive::set - , true>; -template class boost::intrusive::set - , true>; -template class boost::intrusive::set - , true>; -template class boost::intrusive::set - , true>; -*/ int main( int, char* [] ) { + test_main_template()(); - test_main_template, false>()(); + test_main_template, false>()(); test_main_template()(); - test_main_template, true>()(); + test_main_template, true>()(); return boost::report_errors(); } #include diff --git a/test/slist_test.cpp b/test/slist_test.cpp index bb67700..06fc38c 100644 --- a/test/slist_test.cpp +++ b/test/slist_test.cpp @@ -10,6 +10,7 @@ // See http://www.boost.org/libs/intrusive for documentation. // ///////////////////////////////////////////////////////////////////////////// + #include #include #include @@ -36,15 +37,19 @@ struct test_slist static void test_swap(std::vector& values); static void test_slow_insert (std::vector& values); static void test_clone (std::vector& values); + static void test_container_from_end(std::vector &values); }; template void test_slist ::test_all (std::vector& values) { - typedef boost::intrusive::slist - + , size_type + , constant_time_size > list_type; { list_type list(values.begin(), values.end()); @@ -61,6 +66,7 @@ void test_slist test_slow_insert (values); test_swap(values); test_clone(values); + test_container_from_end(values); } //test: push_front, pop_front, front, size, empty: @@ -68,9 +74,12 @@ template void test_slist ::test_front_back (std::vector& values) { - typedef boost::intrusive::slist - + , size_type + , constant_time_size > list_type; list_type testlist; BOOST_TEST (testlist.empty()); @@ -96,10 +105,12 @@ template void test_slist ::test_merge (std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::slist - + , size_type + , constant_time_size > list_type; list_type testlist1, testlist2; testlist1.push_front (values[0]); @@ -117,10 +128,12 @@ template void test_slist ::test_sort(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::slist - + , size_type + , constant_time_size > list_type; list_type testlist (values.begin(), values.end()); @@ -136,15 +149,17 @@ void test_slist TEST_INTRUSIVE_SEQUENCE( init_values, testlist.begin() ); } } -//test: assign, insert_after, const_iterator, erase_after, iterator_to, previous: +//test: assign, insert_after, const_iterator, erase_after, s_iterator_to, previous: template void test_slist ::test_insert(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::slist - + , size_type + , constant_time_size > list_type; list_type testlist; testlist.assign (&values[0] + 2, &values[0] + 5); @@ -162,6 +177,8 @@ void test_slist i = testlist.iterator_to (values[4]); BOOST_TEST (&*i == &values[4]); + i = list_type::s_iterator_to (values[4]); + BOOST_TEST (&*i == &values[4]); i = testlist.previous (i); BOOST_TEST (&*i == &values[0]); @@ -171,15 +188,17 @@ void test_slist TEST_INTRUSIVE_SEQUENCE( init_values, const_testlist.begin() ); } } -//test: insert, const_iterator, erase, iterator_to: +//test: insert, const_iterator, erase, siterator_to: template void test_slist ::test_slow_insert (std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::slist - + , size_type + , constant_time_size > list_type; list_type testlist; testlist.push_front (values[4]); @@ -199,6 +218,9 @@ void test_slist i = testlist.iterator_to (values[4]); BOOST_TEST (&*i == &values[4]); + i = list_type::s_iterator_to (values[4]); + BOOST_TEST (&*i == &values[4]); + i = testlist.erase (i); BOOST_TEST (i == testlist.end()); @@ -214,10 +236,12 @@ template void test_slist ::test_shift(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::slist - + , size_type + , constant_time_size > list_type; list_type testlist; @@ -254,10 +278,12 @@ template void test_slist ::test_swap(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::slist - + , size_type + , constant_time_size > list_type; { list_type testlist1 (&values[0], &values[0] + 2); @@ -306,37 +332,63 @@ template void test_slist ::test_clone(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::slist - + , size_type + , constant_time_size > list_type; list_type testlist1 (&values[0], &values[0] + values.size()); list_type testlist2; - testlist2.clone_from(testlist1, test::new_cloner(), test::delete_disposer()); + testlist2.clone_from(testlist1, test::new_cloner(), test::delete_disposer()); BOOST_TEST (testlist2 == testlist1); - testlist2.clear_and_dispose(test::delete_disposer()); + testlist2.clear_and_dispose(test::delete_disposer()); BOOST_TEST (testlist2.empty()); } +template +void test_slist + ::test_container_from_end(std::vector& values) +{ + typedef typename ValueTraits::value_type value_type; + typedef slist + < value_type + , value_traits + , size_type + , constant_time_size + > list_type; + list_type testlist1 (&values[0], &values[0] + values.size()); + BOOST_TEST (testlist1 == list_type::container_from_end_iterator(testlist1.end())); + BOOST_TEST (testlist1 == list_type::container_from_end_iterator(testlist1.cend())); +} + template class test_main_template { public: int operator()() { - typedef testvalue testvalue_t; - std::vector data (5); + typedef testvalue value_type; + std::vector data (5); for (int i = 0; i < 5; ++i) data[i].value_ = i + 1; - test_slist >::test_all(data); - - test_slist >::test_all(data); + test_slist < typename detail::get_base_value_traits + < value_type + , typename value_type::slist_base_hook_t + >::type + >::test_all(data); + test_slist < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::slist_member_hook_t + , &value_type::slist_node_ + > + >::type + >::test_all(data); return 0; } @@ -348,48 +400,50 @@ class test_main_template public: int operator()() { - typedef testvalue testvalue_t; - std::vector data (5); + typedef testvalue value_type; + std::vector data (5); for (int i = 0; i < 5; ++i) data[i].value_ = i + 1; - test_slist >::test_all(data); + test_slist < typename detail::get_base_value_traits + < value_type + , typename value_type::slist_base_hook_t + >::type + >::test_all(data); - test_slist >::test_all(data); + test_slist < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::slist_member_hook_t + , &value_type::slist_node_ + > + >::type + >::test_all(data); - test_slist >::test_all(data); + test_slist < typename detail::get_base_value_traits + < value_type + , typename value_type::slist_auto_base_hook_t + >::type + >::test_all(data); - test_slist >::test_all(data); + test_slist < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::slist_auto_member_hook_t + , &value_type::slist_auto_node_ + > + >::type + >::test_all(data); return 0; } }; -/* -//Explicit instantiations of non-counted classes -template class boost::intrusive::slist; -template class boost::intrusive::slist; -template class boost::intrusive::slist; -template class boost::intrusive::slist; -template class boost::intrusive::slist; -template class boost::intrusive::slist; -template class boost::intrusive::slist; -template class boost::intrusive::slist; -//Explicit instantiation of counted classes -template class boost::intrusive::slist; -template class boost::intrusive::slist; -template class boost::intrusive::slist; -template class boost::intrusive::slist; -*/ int main(int, char* []) { test_main_template()(); - test_main_template, false>()(); + test_main_template, false>()(); test_main_template()(); - test_main_template, true>()(); + test_main_template, true>()(); return boost::report_errors(); } #include diff --git a/test/stateful_value_traits_test.cpp b/test/stateful_value_traits_test.cpp new file mode 100644 index 0000000..d544ac0 --- /dev/null +++ b/test/stateful_value_traits_test.cpp @@ -0,0 +1,148 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include + +using namespace boost::intrusive; + +class MyClass +{ + public: + int int_; + + MyClass(int i = 0) + : int_(i) + {} + + friend bool operator<(const MyClass &l, const MyClass &r) + { return l.int_ < r.int_; } + + friend bool operator==(const MyClass &l, const MyClass &r) + { return l.int_ == r.int_; } + + friend std::size_t hash_value(const MyClass &v) + { return boost::hash_value(v.int_); } +}; + +template +struct stateful_value_traits +{ + typedef NodeTraits node_traits; + typedef typename node_traits::node node; + typedef typename node_traits::node_ptr node_ptr; + typedef typename node_traits::const_node_ptr const_node_ptr; + typedef T value_type; + typedef typename boost::pointer_to_other + ::type pointer; + typedef typename boost::pointer_to_other + ::type const_pointer; + static const link_mode_type link_mode = normal_link; + + stateful_value_traits(pointer values, node_ptr node_array) + : values_(values), node_array_(node_array) + {} + + node_ptr to_node_ptr (value_type &value) + { return node_array_ + (&value - values_); } + + const_node_ptr to_node_ptr (const value_type &value) const + { return node_array_ + (&value - values_); } + + pointer to_value_ptr(node_ptr n) + { return values_ + (n - node_array_); } + + const_pointer to_value_ptr(const_node_ptr n) const + { return values_ + (n - node_array_); } + + pointer values_; + node_ptr node_array_; +}; + +//Define a list that will store MyClass using the external hook +typedef stateful_value_traits< MyClass, list_node_traits > list_traits; +typedef list > List; + +//Define a slist that will store MyClass using the external hook +typedef stateful_value_traits< MyClass, slist_node_traits > slist_traits; +typedef slist > Slist; + +//Define a set that will store MyClass using the external hook +typedef stateful_value_traits< MyClass, rbtree_node_traits > rbtree_traits; +typedef set > Set; + +//uset uses the same traits as slist +typedef unordered_set > Uset; + + +typedef list_traits::node list_node_t; +typedef slist_traits::node slist_node_t; +typedef rbtree_traits::node rbtree_node_t; + +const int NumElements = 100; + +MyClass values [NumElements]; +list_node_t list_hook_array [NumElements]; +slist_node_t slist_hook_array [NumElements]; +rbtree_node_t rbtree_hook_array [NumElements]; +slist_node_t uset_hook_array [NumElements]; + +int main() +{ + //Create several MyClass objects, each one with a different value + for(int i = 0; i < NumElements; ++i) + values[i].int_ = i; + + Uset::bucket_type buckets[NumElements]; + + List my_list (list_traits (values, list_hook_array)); + Slist my_slist(slist_traits(values, slist_hook_array)); + Set my_set (std::less(), rbtree_traits(values, rbtree_hook_array)); + Uset my_uset ( Uset::bucket_traits(buckets, NumElements) + , boost::hash() + , std::equal_to() + , slist_traits(values, uset_hook_array) + ); + + //Now insert them in the reverse order + //in the base hook intrusive list + for(MyClass * it(&values[0]), *itend(&values[NumElements]) + ; it != itend + ; ++it){ + my_list.push_front(*it); + my_slist.push_front(*it); + my_set.insert(*it); + my_uset.insert(*it); + } + + //Now test lists + { + List::const_iterator list_it (my_list.cbegin()); + Slist::const_iterator slist_it(my_slist.cbegin()); + Set::const_reverse_iterator set_rit(my_set.crbegin()); + MyClass *it_val(&values[NumElements-1]), *it_rbeg_val(&values[0]-1); + + //Test the objects inserted in the base hook list + for(; it_val != it_rbeg_val; --it_val, ++list_it, ++slist_it, ++set_rit){ + if(&*list_it != &*it_val) return 1; + if(&*slist_it != &*it_val) return 1; + if(&*set_rit != &*it_val) return 1; + if(my_uset.find(*it_val) == my_uset.cend()) return 1; + } + } + + return 0; +} diff --git a/test/unordered_multiset_test.cpp b/test/unordered_multiset_test.cpp index b78aeee..5b42784 100644 --- a/test/unordered_multiset_test.cpp +++ b/test/unordered_multiset_test.cpp @@ -44,15 +44,16 @@ struct test_unordered_multiset template void test_unordered_multiset::test_all (std::vector& values) { - typedef boost::intrusive::unordered_multiset - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef unordered_multiset + + , constant_time_size > unordered_multiset_type; { + typedef typename unordered_multiset_type::bucket_traits bucket_traits; typename unordered_multiset_type::bucket_type buckets [BucketSize]; - unordered_multiset_type testset(buckets, BucketSize); + unordered_multiset_type testset(bucket_traits(buckets, BucketSize)); testset.insert(values.begin(), values.end()); test::test_container(testset); testset.clear(); @@ -78,18 +79,20 @@ void test_unordered_multiset::test_all (std::vector void test_unordered_multiset::test_impl() { - typedef typename ValueTraits::value_type testvalue_t; - std::vector values (5); + typedef typename ValueTraits::value_type value_type; + typedef unordered_multiset + + , constant_time_size + > unordered_multiset_type; + typedef typename unordered_multiset_type::bucket_traits bucket_traits; + + std::vector values (5); for (int i = 0; i < 5; ++i) values[i].value_ = i; - typedef boost::intrusive::unordered_multiset - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t - > unordered_multiset_type; + typename unordered_multiset_type::bucket_type buckets [BucketSize]; - unordered_multiset_type testset(buckets, BucketSize); + unordered_multiset_type testset(bucket_traits(buckets, BucketSize)); for (int i = 0; i < 5; ++i) testset.insert (values[i]); @@ -106,15 +109,16 @@ void test_unordered_multiset::test_impl() template void test_unordered_multiset::test_sort(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::unordered_multiset - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef unordered_multiset + + , constant_time_size > unordered_multiset_type; + typedef typename unordered_multiset_type::bucket_traits bucket_traits; + typename unordered_multiset_type::bucket_type buckets [BucketSize]; - unordered_multiset_type testset1(buckets, BucketSize, values.begin(), values.end()); + unordered_multiset_type testset1(values.begin(), values.end(), bucket_traits(buckets, BucketSize)); { int init_values [] = { 1, 2, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } @@ -126,16 +130,16 @@ void test_unordered_multiset::test_sort(std::vector void test_unordered_multiset::test_insert(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::unordered_multiset - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef unordered_multiset + + , constant_time_size > unordered_multiset_type; + typedef typename unordered_multiset_type::bucket_traits bucket_traits; + typename unordered_multiset_type::bucket_type buckets [BucketSize]; - unordered_multiset_type testset(buckets, BucketSize); - typedef typename unordered_multiset_type::value_type value_type; + unordered_multiset_type testset(bucket_traits(buckets, BucketSize)); testset.insert(&values[0] + 2, &values[0] + 5); @@ -170,7 +174,7 @@ void test_unordered_multiset::test_insert(std::vector::test_insert(std::vector void test_unordered_multiset::test_swap(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::unordered_multiset - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef unordered_multiset + + , constant_time_size > unordered_multiset_type; - typename unordered_multiset_type::bucket_type buckets [BucketSize]; - unordered_multiset_type testset1(buckets, BucketSize, &values[0], &values[0] + 2); + typedef typename unordered_multiset_type::bucket_traits bucket_traits; + typename unordered_multiset_type::bucket_type buckets [BucketSize]; typename unordered_multiset_type::bucket_type buckets2 [BucketSize]; - unordered_multiset_type testset2(buckets2, BucketSize); + unordered_multiset_type testset1(&values[0], &values[0] + 2, bucket_traits(buckets, BucketSize)); + unordered_multiset_type testset2(bucket_traits(buckets2, BucketSize)); testset2.insert (&values[0] + 2, &values[0] + 6); testset1.swap (testset2); @@ -216,40 +220,41 @@ void test_unordered_multiset::test_swap(std::vector void test_unordered_multiset::test_rehash(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::unordered_multiset - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef unordered_multiset + + , constant_time_size > unordered_multiset_type; + typedef typename unordered_multiset_type::bucket_traits bucket_traits; typename unordered_multiset_type::bucket_type buckets1 [BucketSize]; - unordered_multiset_type testset1(buckets1, BucketSize, &values[0], &values[0] + 6); + typename unordered_multiset_type::bucket_type buckets2 [2]; + typename unordered_multiset_type::bucket_type buckets3 [BucketSize*2]; + + unordered_multiset_type testset1(&values[0], &values[0] + 6, bucket_traits(buckets1, BucketSize)); BOOST_TEST (testset1.size() == 6); { int init_values [] = { 1, 2, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } - typename unordered_multiset_type::bucket_type buckets2 [2]; - testset1.rehash(buckets2, 2); + testset1.rehash(bucket_traits(buckets2, 2)); BOOST_TEST (testset1.size() == 6); { int init_values [] = { 4, 2, 2, 5, 3, 1 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } - typename unordered_multiset_type::bucket_type buckets3 [BucketSize*2]; - testset1.rehash(buckets3, BucketSize*2); + testset1.rehash(bucket_traits(buckets3, BucketSize*2)); BOOST_TEST (testset1.size() == 6); { int init_values [] = { 1, 2, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } //Now rehash reducing the buckets - testset1.rehash(buckets3, 2); + testset1.rehash(bucket_traits(buckets3, 2)); BOOST_TEST (testset1.size() == 6); { int init_values [] = { 4, 2, 2, 5, 3, 1 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } //Now rehash increasing the buckets - testset1.rehash(buckets3, BucketSize*2); + testset1.rehash(bucket_traits(buckets3, BucketSize*2)); BOOST_TEST (testset1.size() == 6); { int init_values [] = { 1, 2, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } @@ -259,19 +264,20 @@ void test_unordered_multiset::test_rehash(std::vector void test_unordered_multiset::test_find(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::unordered_multiset - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef unordered_multiset + + , constant_time_size > unordered_multiset_type; + typedef typename unordered_multiset_type::bucket_traits bucket_traits; + typename unordered_multiset_type::bucket_type buckets[BucketSize]; - unordered_multiset_type testset(buckets, BucketSize, values.begin(), values.end()); + unordered_multiset_type testset(values.begin(), values.end(), bucket_traits(buckets, BucketSize)); typedef typename unordered_multiset_type::iterator iterator; - testvalue_t cmp_val; + value_type cmp_val; cmp_val.value_ = 2; iterator i = testset.find (cmp_val); BOOST_TEST (i->value_ == 2); @@ -291,61 +297,62 @@ template void test_unordered_multiset ::test_clone(std::vector& values) { - typedef boost::intrusive::unordered_multiset - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef unordered_multiset + + , constant_time_size > unordered_multiset_type; + typedef typename unordered_multiset_type::bucket_traits bucket_traits; { //Test with equal bucket arrays typename unordered_multiset_type::bucket_type buckets1 [BucketSize]; typename unordered_multiset_type::bucket_type buckets2 [BucketSize]; - unordered_multiset_type testset1 (buckets1, BucketSize, values.begin(), values.end()); - unordered_multiset_type testset2 (buckets2, BucketSize); + unordered_multiset_type testset1 (values.begin(), values.end(), bucket_traits(buckets1, BucketSize)); + unordered_multiset_type testset2 (bucket_traits(buckets2, BucketSize)); - testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); + testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); //Ordering is not guarantee in the cloning so insert data in a set and test std::multiset src(testset1.begin(), testset1.end()); std::multiset dst(testset2.begin(), testset2.end()); BOOST_TEST (src == dst); - testset2.clear_and_dispose(test::delete_disposer()); + testset2.clear_and_dispose(test::delete_disposer()); BOOST_TEST (testset2.empty()); } { //Test with bigger source bucket arrays typename unordered_multiset_type::bucket_type buckets1 [BucketSize*2]; typename unordered_multiset_type::bucket_type buckets2 [BucketSize]; - unordered_multiset_type testset1 (buckets1, BucketSize*2, values.begin(), values.end()); - unordered_multiset_type testset2 (buckets2, BucketSize); + unordered_multiset_type testset1 (values.begin(), values.end(), bucket_traits(buckets1, BucketSize*2)); + unordered_multiset_type testset2 (bucket_traits(buckets2, BucketSize)); - testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); + testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); //Ordering is not guarantee in the cloning so insert data in a set and test std::multiset src(testset1.begin(), testset1.end()); std::multiset dst(testset2.begin(), testset2.end()); BOOST_TEST (src == dst); - testset2.clear_and_dispose(test::delete_disposer()); + testset2.clear_and_dispose(test::delete_disposer()); BOOST_TEST (testset2.empty()); } { //Test with smaller source bucket arrays typename unordered_multiset_type::bucket_type buckets1 [BucketSize]; typename unordered_multiset_type::bucket_type buckets2 [BucketSize*2]; - unordered_multiset_type testset1 (buckets1, BucketSize, values.begin(), values.end()); - unordered_multiset_type testset2 (buckets2, BucketSize*2); + unordered_multiset_type testset1 (values.begin(), values.end(), bucket_traits(buckets1, BucketSize)); + unordered_multiset_type testset2 (bucket_traits(buckets2, BucketSize*2)); - testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); + testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); //Ordering is not guarantee in the cloning so insert data in a set and test std::multiset src(testset1.begin(), testset1.end()); std::multiset dst(testset2.begin(), testset2.end()); BOOST_TEST (src == dst); - testset2.clear_and_dispose(test::delete_disposer()); + testset2.clear_and_dispose(test::delete_disposer()); BOOST_TEST (testset2.empty()); } } @@ -356,17 +363,26 @@ class test_main_template public: int operator()() { - typedef testvalue testvalue_t; + typedef testvalue value_type; static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; std::vector > data (6); for (int i = 0; i < 6; ++i) data[i].value_ = random_init[i]; - test_unordered_multiset >::test_all(data); + test_unordered_multiset < typename detail::get_base_value_traits + < value_type + , typename value_type::unordered_set_base_hook_t + >::type + >::test_all(data); - test_unordered_multiset >::test_all(data); + test_unordered_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::unordered_set_member_hook_t + , &value_type::unordered_set_node_ + > + >::type + >::test_all(data); return 0; } @@ -378,87 +394,51 @@ class test_main_template public: int operator()() { - typedef testvalue testvalue_t; + typedef testvalue value_type; static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; std::vector > data (6); for (int i = 0; i < 6; ++i) data[i].value_ = random_init[i]; - test_unordered_multiset >::test_all(data); + test_unordered_multiset < typename detail::get_base_value_traits + < value_type + , typename value_type::unordered_set_base_hook_t + >::type + >::test_all(data); - test_unordered_multiset >::test_all(data); + test_unordered_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::unordered_set_member_hook_t + , &value_type::unordered_set_node_ + > + >::type + >::test_all(data); - test_unordered_multiset >::test_all(data); + test_unordered_multiset < typename detail::get_base_value_traits + < value_type + , typename value_type::unordered_set_auto_base_hook_t + >::type + >::test_all(data); - test_unordered_multiset >::test_all(data); + test_unordered_multiset < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::unordered_set_auto_member_hook_t + , &value_type::unordered_set_auto_node_ + > + >::type + >::test_all(data); return 0; } }; -/* -//Explicit instantiations of non-counted classes -template class boost::intrusive::unordered_multiset - < unordered_set_base_raw_t - , boost::hash - , std::equal_to, false>; -template class boost::intrusive::unordered_multiset - < unordered_set_member_raw_t - , boost::hash - , std::equal_to, false>; -template class boost::intrusive::unordered_multiset - < unordered_set_auto_base_raw - , boost::hash - , std::equal_to, false>; -template class boost::intrusive::unordered_multiset - < unordered_set_auto_member_raw - , boost::hash - , std::equal_to, false>; -template class boost::intrusive::unordered_multiset - < unordered_set_base_smart - , boost::hash - , std::equal_to, false>; -template class boost::intrusive::unordered_multiset - < unordered_set_member_smart - , boost::hash - , std::equal_to, false>; -template class boost::intrusive::unordered_multiset - < unordered_set_auto_base_smart - , boost::hash - , std::equal_to, false>; -template class boost::intrusive::unordered_multiset - < unordered_set_auto_member_smart - , boost::hash - , std::equal_to, false>; - -//Explicit instantiation of counted classes -template class boost::intrusive::unordered_multiset - < unordered_set_base_raw_t - , boost::hash - , std::equal_to, true>; -template class boost::intrusive::unordered_multiset - < unordered_set_member_raw_t - , boost::hash - , std::equal_to, true>; -template class boost::intrusive::unordered_multiset - < unordered_set_base_smart_t - , boost::hash - , std::equal_to, true>; -template class boost::intrusive::unordered_multiset - < unordered_set_member_smart_t - , boost::hash - , std::equal_to, true>; -*/ - int main( int, char* [] ) { test_main_template()(); - test_main_template, false>()(); + test_main_template, false>()(); test_main_template()(); - test_main_template, true>()(); + test_main_template, true>()(); return boost::report_errors(); } diff --git a/test/unordered_set_test.cpp b/test/unordered_set_test.cpp index e0c1c5e..1d75250 100644 --- a/test/unordered_set_test.cpp +++ b/test/unordered_set_test.cpp @@ -43,15 +43,16 @@ struct test_unordered_set template void test_unordered_set::test_all(std::vector& values) { - typedef boost::intrusive::unordered_set - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef unordered_set + + , constant_time_size > unordered_set_type; + typedef typename unordered_set_type::bucket_traits bucket_traits; { typename unordered_set_type::bucket_type buckets [BucketSize]; - unordered_set_type testset(buckets, BucketSize); + unordered_set_type testset(bucket_traits(buckets, BucketSize)); testset.insert(values.begin(), values.end()); test::test_container(testset); testset.clear(); @@ -77,19 +78,20 @@ void test_unordered_set::test_all(std::vector void test_unordered_set::test_impl() { - typedef typename ValueTraits::value_type testvalue_t; - std::vector values (5); + typedef typename ValueTraits::value_type value_type; + typedef unordered_set + + , constant_time_size + > unordered_set_type; + typedef typename unordered_set_type::bucket_traits bucket_traits; + + std::vector values (5); for (int i = 0; i < 5; ++i) values[i].value_ = i; - typedef boost::intrusive::unordered_set - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t - > unordered_set_type; typename unordered_set_type::bucket_type buckets [BucketSize]; - unordered_set_type testset(buckets, BucketSize); + unordered_set_type testset(bucket_traits(buckets, BucketSize)); for (int i = 0; i < 5; ++i) testset.insert (values[i]); @@ -104,15 +106,16 @@ void test_unordered_set::test_impl() template void test_unordered_set::test_sort(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::unordered_set - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef unordered_set + + , constant_time_size > unordered_set_type; + typedef typename unordered_set_type::bucket_traits bucket_traits; + typename unordered_set_type::bucket_type buckets [BucketSize]; - unordered_set_type testset1(buckets, BucketSize, values.begin(), values.end()); + unordered_set_type testset1(values.begin(), values.end(), bucket_traits(buckets, BucketSize)); BOOST_TEST (5 == std::distance(testset1.begin(), testset1.end())); { int init_values [] = { 1, 2, 3, 4, 5 }; @@ -126,15 +129,16 @@ void test_unordered_set::test_sort(std::vector void test_unordered_set::test_insert(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::unordered_set - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef unordered_set + + , constant_time_size > unordered_set_type; + typedef typename unordered_set_type::bucket_traits bucket_traits; + typename unordered_set_type::bucket_type buckets [BucketSize]; - unordered_set_type testset(buckets, BucketSize); + unordered_set_type testset(bucket_traits(buckets, BucketSize)); testset.insert(&values[0] + 2, &values[0] + 5); const unordered_set_type& const_testset = testset; @@ -160,19 +164,18 @@ void test_unordered_set::test_insert(std::vector void test_unordered_set::test_swap(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::unordered_set - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef unordered_set + + , constant_time_size > unordered_set_type; + typedef typename unordered_set_type::bucket_traits bucket_traits; typename unordered_set_type::bucket_type buckets1 [BucketSize]; - unordered_set_type testset1(buckets1, BucketSize, &values[0], &values[0] + 2); - typename unordered_set_type::bucket_type buckets2 [BucketSize]; - unordered_set_type testset2(buckets2, BucketSize); + unordered_set_type testset1(&values[0], &values[0] + 2, bucket_traits(buckets1, BucketSize)); + unordered_set_type testset2(bucket_traits(buckets2, BucketSize)); testset2.insert (&values[0] + 2, &values[0] + 6); testset1.swap (testset2); @@ -192,40 +195,41 @@ void test_unordered_set::test_swap(std::vector void test_unordered_set::test_rehash(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::unordered_set - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef unordered_set + + , constant_time_size > unordered_set_type; + typedef typename unordered_set_type::bucket_traits bucket_traits; typename unordered_set_type::bucket_type buckets1 [BucketSize]; - unordered_set_type testset1(buckets1, BucketSize, &values[0], &values[0] + 6); + typename unordered_set_type::bucket_type buckets2 [2]; + typename unordered_set_type::bucket_type buckets3 [BucketSize*2]; + + unordered_set_type testset1(&values[0], &values[0] + 6, bucket_traits(buckets1, BucketSize)); BOOST_TEST (testset1.size() == 5); { int init_values [] = { 1, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } - typename unordered_set_type::bucket_type buckets2 [2]; - testset1.rehash(buckets2, 2); + testset1.rehash(bucket_traits(buckets2, 2)); BOOST_TEST (testset1.size() == 5); { int init_values [] = { 4, 2, 5, 3, 1 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } - typename unordered_set_type::bucket_type buckets3 [BucketSize*2]; - testset1.rehash(buckets3, BucketSize*2); + testset1.rehash(bucket_traits(buckets3, BucketSize*2)); BOOST_TEST (testset1.size() == 5); { int init_values [] = { 1, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } //Now rehash reducing the buckets - testset1.rehash(buckets3, 2); + testset1.rehash(bucket_traits(buckets3, 2)); BOOST_TEST (testset1.size() == 5); { int init_values [] = { 4, 2, 5, 3, 1 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } //Now rehash increasing the buckets - testset1.rehash(buckets3, BucketSize*2); + testset1.rehash(bucket_traits(buckets3, BucketSize*2)); BOOST_TEST (testset1.size() == 5); { int init_values [] = { 1, 2, 3, 4, 5 }; TEST_INTRUSIVE_SEQUENCE( init_values, testset1.begin() ); } @@ -236,18 +240,19 @@ void test_unordered_set::test_rehash(std::vector void test_unordered_set::test_find(std::vector& values) { - typedef typename ValueTraits::value_type testvalue_t; - typedef boost::intrusive::unordered_set - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef unordered_set + + , constant_time_size > unordered_set_type; + typedef typename unordered_set_type::bucket_traits bucket_traits; + typename unordered_set_type::bucket_type buckets [BucketSize]; - unordered_set_type testset (buckets, BucketSize, values.begin(), values.end()); + unordered_set_type testset (values.begin(), values.end(), bucket_traits(buckets, BucketSize)); typedef typename unordered_set_type::iterator iterator; - testvalue_t cmp_val; + value_type cmp_val; cmp_val.value_ = 2; iterator i = testset.find (cmp_val); BOOST_TEST (i->value_ == 2); @@ -266,61 +271,62 @@ template void test_unordered_set ::test_clone(std::vector& values) { - typedef boost::intrusive::unordered_set - - ,std::equal_to - ,ValueTraits::value_type::constant_time_size, std::size_t + typedef typename ValueTraits::value_type value_type; + typedef unordered_set + + , constant_time_size > unordered_set_type; + typedef typename unordered_set_type::bucket_traits bucket_traits; { //Test with equal bucket arrays typename unordered_set_type::bucket_type buckets1 [BucketSize]; typename unordered_set_type::bucket_type buckets2 [BucketSize]; - unordered_set_type testset1 (buckets1, BucketSize, values.begin(), values.end()); - unordered_set_type testset2 (buckets2, BucketSize); + unordered_set_type testset1 (values.begin(), values.end(), bucket_traits(buckets1, BucketSize)); + unordered_set_type testset2 (bucket_traits(buckets2, BucketSize)); - testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); + testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); //Ordering is not guarantee in the cloning so insert data in a set and test std::set src(testset1.begin(), testset1.end()); std::set dst(testset2.begin(), testset2.end()); BOOST_TEST (src == dst ); - testset2.clear_and_dispose(test::delete_disposer()); + testset2.clear_and_dispose(test::delete_disposer()); BOOST_TEST (testset2.empty()); } { //Test with bigger source bucket arrays typename unordered_set_type::bucket_type buckets1 [BucketSize*2]; typename unordered_set_type::bucket_type buckets2 [BucketSize]; - unordered_set_type testset1 (buckets1, BucketSize*2, values.begin(), values.end()); - unordered_set_type testset2 (buckets2, BucketSize); + unordered_set_type testset1 (values.begin(), values.end(), bucket_traits(buckets1, BucketSize*2)); + unordered_set_type testset2 (bucket_traits(buckets2, BucketSize)); - testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); + testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); //Ordering is not guarantee in the cloning so insert data in a set and test std::set src(testset1.begin(), testset1.end()); std::set dst(testset2.begin(), testset2.end()); BOOST_TEST (src == dst ); - testset2.clear_and_dispose(test::delete_disposer()); + testset2.clear_and_dispose(test::delete_disposer()); BOOST_TEST (testset2.empty()); } { //Test with smaller source bucket arrays typename unordered_set_type::bucket_type buckets1 [BucketSize]; typename unordered_set_type::bucket_type buckets2 [BucketSize*2]; - unordered_set_type testset1 (buckets1, BucketSize, values.begin(), values.end()); - unordered_set_type testset2 (buckets2, BucketSize*2); + unordered_set_type testset1 (values.begin(), values.end(), bucket_traits(buckets1, BucketSize)); + unordered_set_type testset2 (bucket_traits(buckets2, BucketSize*2)); - testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); + testset2.clone_from(testset1, test::new_cloner(), test::delete_disposer()); //Ordering is not guarantee in the cloning so insert data in a set and test std::set src(testset1.begin(), testset1.end()); std::set dst(testset2.begin(), testset2.end()); BOOST_TEST (src == dst ); - testset2.clear_and_dispose(test::delete_disposer()); + testset2.clear_and_dispose(test::delete_disposer()); BOOST_TEST (testset2.empty()); } } @@ -331,17 +337,25 @@ class test_main_template public: int operator()() { - typedef testvalue testvalue_t; + typedef testvalue value_type; static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; std::vector > data (6); for (int i = 0; i < 6; ++i) data[i].value_ = random_init[i]; - test_unordered_set >::test_all(data); - - test_unordered_set >::test_all(data); + test_unordered_set < typename detail::get_base_value_traits + < value_type + , typename value_type::unordered_set_base_hook_t + >::type + >::test_all(data); + test_unordered_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::unordered_set_member_hook_t + , &value_type::unordered_set_node_ + > + >::type + >::test_all(data); return 0; } @@ -353,84 +367,51 @@ class test_main_template public: int operator()() { - typedef testvalue testvalue_t; + typedef testvalue value_type; static const int random_init[6] = { 3, 2, 4, 1, 5, 2 }; std::vector > data (6); for (int i = 0; i < 6; ++i) data[i].value_ = random_init[i]; - test_unordered_set >::test_all(data); + test_unordered_set < typename detail::get_base_value_traits + < value_type + , typename value_type::unordered_set_base_hook_t + >::type + >::test_all(data); - test_unordered_set >::test_all(data); + test_unordered_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::unordered_set_member_hook_t + , &value_type::unordered_set_node_ + > + >::type + >::test_all(data); - test_unordered_set >::test_all(data); + test_unordered_set < typename detail::get_base_value_traits + < value_type + , typename value_type::unordered_set_auto_base_hook_t + >::type + >::test_all(data); - test_unordered_set >::test_all(data); + test_unordered_set < typename detail::get_member_value_traits + < value_type + , member_hook< value_type + , typename value_type::unordered_set_auto_member_hook_t + , &value_type::unordered_set_auto_node_ + > + >::type + >::test_all(data); return 0; } }; -/* -template class boost::intrusive::unordered_set - < unordered_set_base_raw_t - , boost::hash - , std::equal_to, false>; -template class boost::intrusive::unordered_set - < unordered_set_member_raw_t - , boost::hash - , std::equal_to, false>; -template class boost::intrusive::unordered_set - < unordered_set_auto_base_raw - , boost::hash - , std::equal_to, false>; -template class boost::intrusive::unordered_set - < unordered_set_auto_member_raw - , boost::hash - , std::equal_to, false>; -template class boost::intrusive::unordered_set - < unordered_set_base_smart - , boost::hash - , std::equal_to, false>; -template class boost::intrusive::unordered_set - < unordered_set_member_smart - , boost::hash - , std::equal_to, false>; -template class boost::intrusive::unordered_set - < unordered_set_auto_base_smart - , boost::hash - , std::equal_to, false>; -template class boost::intrusive::unordered_set - < unordered_set_auto_member_smart - , boost::hash - , std::equal_to, false>; -//Explicit instantiation of counted classes -template class boost::intrusive::unordered_set - < unordered_set_base_raw_t - , boost::hash - , std::equal_to, true>; -template class boost::intrusive::unordered_set - < unordered_set_member_raw_t - , boost::hash - , std::equal_to, true>; -template class boost::intrusive::unordered_set - < unordered_set_base_smart_t - , boost::hash - , std::equal_to, true>; -template class boost::intrusive::unordered_set - < unordered_set_member_smart_t - , boost::hash - , std::equal_to, true>; -*/ int main( int, char* [] ) { test_main_template()(); - test_main_template, false>()(); + test_main_template, false>()(); test_main_template()(); - test_main_template, true>()(); + test_main_template, true>()(); return boost::report_errors(); } #include diff --git a/test/virtual_base_test.cpp b/test/virtual_base_test.cpp new file mode 100644 index 0000000..14bd885 --- /dev/null +++ b/test/virtual_base_test.cpp @@ -0,0 +1,85 @@ +///////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/intrusive for documentation. +// +///////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include + +using namespace boost::intrusive; + +struct VirtualBase +{ + virtual ~VirtualBase(){} +}; + +struct VirtualBase2 +{ + virtual ~VirtualBase2(){} +}; + +struct VirtualBase3 +{ +}; + +class NonVirtualBase + : public virtual VirtualBase + , public virtual VirtualBase2 +{ + public: + int dummy[10]; +}; + +class MyClass + : public NonVirtualBase + , public virtual VirtualBase3 +{ + int int_; + public: + list_member_hook<> list_hook_; + MyClass(int i = 0) + : int_(i) + {} +}; + +//Define a list that will store MyClass using the public base hook +typedef member_hook< MyClass, list_member_hook<>, &MyClass::list_hook_ > MemberHook; +typedef list List; + +int main() +{ + typedef std::vector::iterator VectIt; + typedef std::vector::reverse_iterator VectRit; + + //Create several MyClass objects, each one with a different value + std::vector values; + for(int i = 0; i < 100; ++i) values.push_back(MyClass(i)); + + List my_list; + + //Now insert them in the reverse order + //in the base hook intrusive list + for(VectIt it(values.begin()), itend(values.end()); it != itend; ++it) + my_list.push_front(*it); + + //Now test lists + { + List::const_iterator list_it(my_list.cbegin()); + VectRit vect_it(values.rbegin()), vect_itend(values.rend()); + + //Test the objects inserted in the base hook list + for(; vect_it != vect_itend; ++vect_it, ++list_it) + if(&*list_it != &*vect_it) return 1; + } + + return 0; +}