| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-09 20:56:23 +00:00
										 |  |  | // Copyright 2008-2009 Daniel James.
 | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  | // 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)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Gratuitous single linked list.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Sadly some STL implementations aren't up to scratch and I need a simple
 | 
					
						
							|  |  |  | // cross-platform container. So here it is.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if !defined(UNORDERED_TEST_LIST_HEADER)
 | 
					
						
							|  |  |  | #define UNORDERED_TEST_LIST_HEADER
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <boost/iterator.hpp>
 | 
					
						
							|  |  |  | #include <boost/limits.hpp>
 | 
					
						
							|  |  |  | #include <functional>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace test | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2009-11-10 08:15:55 +00:00
										 |  |  |     template <typename It1, typename It2> | 
					
						
							|  |  |  |     bool equal(It1 begin, It1 end, It2 compare) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for(;begin != end; ++begin, ++compare) | 
					
						
							|  |  |  |             if(*begin != *compare) return false; | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template <typename It1, typename It2, typename Pred> | 
					
						
							|  |  |  |     bool equal(It1 begin, It1 end, It2 compare, Pred predicate) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for(;begin != end; ++begin, ++compare) | 
					
						
							|  |  |  |             if(!predicate(*begin, *compare)) return false; | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  |     template <typename T> class list; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     namespace test_detail | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         template <typename T> class list_node; | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  |         template <typename T> class list_data; | 
					
						
							|  |  |  |         template <typename T> class list_iterator; | 
					
						
							|  |  |  |         template <typename T> class list_const_iterator; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         template <typename T> | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         class list_node | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  |         { | 
					
						
							| 
									
										
										
										
											2009-10-04 10:37:56 +00:00
										 |  |  |             list_node(list_node const&); | 
					
						
							|  |  |  |             list_node& operator=(list_node const&); | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |         public: | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  |             T value_; | 
					
						
							|  |  |  |             list_node* next_; | 
					
						
							|  |  |  |                      | 
					
						
							|  |  |  |             list_node(T const& v) : value_(v), next_(0) {} | 
					
						
							|  |  |  |             list_node(T const& v, list_node* n) : value_(v), next_(n) {} | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         template <typename T> | 
					
						
							|  |  |  |         class list_data | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         public: | 
					
						
							|  |  |  |             typedef list_node<T> node; | 
					
						
							|  |  |  |             typedef unsigned int size_type; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             node* first_; | 
					
						
							|  |  |  |             node** last_ptr_; | 
					
						
							|  |  |  |             size_type size_; | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             list_data() : first_(0), last_ptr_(&first_), size_(0) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             ~list_data() { | 
					
						
							|  |  |  |                 while(first_) { | 
					
						
							|  |  |  |                     node* tmp = first_; | 
					
						
							|  |  |  |                     first_ = first_->next_; | 
					
						
							|  |  |  |                     delete tmp; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         private: | 
					
						
							|  |  |  |             list_data(list_data const&); | 
					
						
							|  |  |  |             list_data& operator=(list_data const&); | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         template <typename T> | 
					
						
							|  |  |  |         class list_iterator | 
					
						
							|  |  |  |             : public boost::iterator< | 
					
						
							|  |  |  |                 std::forward_iterator_tag, T, | 
					
						
							|  |  |  |                   int, T*, T&> | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             friend class list_const_iterator<T>; | 
					
						
							|  |  |  |             friend class test::list<T>; | 
					
						
							|  |  |  |             typedef list_node<T> node; | 
					
						
							|  |  |  |             typedef list_const_iterator<T> const_iterator; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             node* ptr_; | 
					
						
							|  |  |  |         public: | 
					
						
							| 
									
										
										
										
											2010-04-23 07:26:43 +00:00
										 |  |  |             list_iterator() : ptr_(0) {} | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  |             explicit list_iterator(node* x) : ptr_(x) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             T& operator*() const { return ptr_->value_; } | 
					
						
							|  |  |  |             T* operator->() const { return &ptr_->value_; } | 
					
						
							|  |  |  |             list_iterator& operator++() { | 
					
						
							|  |  |  |                 ptr_ = ptr_->next_; return *this; } | 
					
						
							| 
									
										
										
										
											2009-05-27 18:19:32 +00:00
										 |  |  |             list_iterator operator++(int) { | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  |                 list_iterator tmp = *this; ptr_ = ptr_->next_; return tmp; } | 
					
						
							|  |  |  |             bool operator==(const_iterator y) const { return ptr_ == y.ptr_; } | 
					
						
							|  |  |  |             bool operator!=(const_iterator y) const { return ptr_ != y.ptr_; } | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         template <typename T> | 
					
						
							|  |  |  |         class list_const_iterator | 
					
						
							|  |  |  |             : public boost::iterator< | 
					
						
							|  |  |  |                 std::forward_iterator_tag, T, | 
					
						
							|  |  |  |                   int, T const*, T const&> | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             friend class list_iterator<T>; | 
					
						
							|  |  |  |             friend class test::list<T>; | 
					
						
							|  |  |  |             typedef list_node<T> node; | 
					
						
							|  |  |  |             typedef list_iterator<T> iterator; | 
					
						
							|  |  |  |             typedef list_const_iterator<T> const_iterator; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             node* ptr_; | 
					
						
							|  |  |  |         public: | 
					
						
							|  |  |  |             list_const_iterator() : ptr_(0) {} | 
					
						
							|  |  |  |             list_const_iterator(list_iterator<T> const& x) : ptr_(x.ptr_) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             T const& operator*() const { return ptr_->value_; } | 
					
						
							|  |  |  |             T const* operator->() const { return &ptr_->value_; } | 
					
						
							| 
									
										
										
										
											2010-01-04 22:49:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             list_const_iterator& operator++() | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 ptr_ = ptr_->next_; | 
					
						
							|  |  |  |                 return *this; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             list_const_iterator operator++(int) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 list_const_iterator tmp = *this; | 
					
						
							|  |  |  |                 ptr_ = ptr_->next_; | 
					
						
							|  |  |  |                 return tmp; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             bool operator==(const_iterator y) const | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 return ptr_ == y.ptr_; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             bool operator!=(const_iterator y) const | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 return ptr_ != y.ptr_; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  |         }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template <typename T> | 
					
						
							|  |  |  |     class list | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         typedef test::test_detail::list_data<T> data; | 
					
						
							|  |  |  |         typedef test::test_detail::list_node<T> node; | 
					
						
							|  |  |  |         data data_; | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |         typedef T value_type; | 
					
						
							|  |  |  |         typedef value_type& reference; | 
					
						
							|  |  |  |         typedef value_type const& const_reference; | 
					
						
							|  |  |  |         typedef unsigned int size_type; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         typedef test::test_detail::list_iterator<T> iterator; | 
					
						
							|  |  |  |         typedef test::test_detail::list_const_iterator<T> const_iterator; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         list() : data_() {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         list(list const& other) : data_() { | 
					
						
							|  |  |  |             insert(other.begin(), other.end()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         template <class InputIterator> | 
					
						
							|  |  |  |         list(InputIterator i, InputIterator j) : data_() { | 
					
						
							|  |  |  |             insert(i, j); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         list& operator=(list const& other) { | 
					
						
							|  |  |  |             clear(); | 
					
						
							|  |  |  |             insert(other.begin(), other.end()); | 
					
						
							| 
									
										
										
										
											2009-03-01 14:15:09 +00:00
										 |  |  |             return *this; | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         iterator begin() { return iterator(data_.first_); } | 
					
						
							|  |  |  |         iterator end() { return iterator(); } | 
					
						
							|  |  |  |         const_iterator begin() const { return iterator(data_.first_); } | 
					
						
							|  |  |  |         const_iterator end() const { return iterator(); } | 
					
						
							|  |  |  |         const_iterator cbegin() const { return iterator(data_.first_); } | 
					
						
							|  |  |  |         const_iterator cend() const { return iterator(); } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         template <class InputIterator> | 
					
						
							|  |  |  |         void insert(InputIterator i, InputIterator j) { | 
					
						
							|  |  |  |             for(; i != j; ++i) | 
					
						
							|  |  |  |                 push_back(*i); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         void push_front(value_type const& v) { | 
					
						
							|  |  |  |             data_.first_ = new node(v, data_.first_); | 
					
						
							| 
									
										
										
										
											2008-05-10 13:52:14 +00:00
										 |  |  |             if(!data_.size_) data_.last_ptr_ = &(*data_.last_ptr_)->next_; | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  |             ++data_.size_; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         void push_back(value_type const& v) { | 
					
						
							|  |  |  |             *data_.last_ptr_ = new node(v); | 
					
						
							|  |  |  |             data_.last_ptr_ = &(*data_.last_ptr_)->next_; | 
					
						
							|  |  |  |             ++data_.size_; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         void clear() { | 
					
						
							|  |  |  |             while(data_.first_) { | 
					
						
							|  |  |  |                 node* tmp = data_.first_; | 
					
						
							|  |  |  |                 data_.first_ = data_.first_->next_; | 
					
						
							|  |  |  |                 --data_.size_; | 
					
						
							|  |  |  |                 delete tmp; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             data_.last_ptr_ = &data_.first_; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-07 10:57:35 +00:00
										 |  |  |         void erase(const_iterator i, const_iterator j) { | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  |             node** ptr = &data_.first_; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-07 10:57:35 +00:00
										 |  |  |             while(*ptr != i.ptr_) { | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  |                 ptr = &(*ptr)->next_; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-07 10:57:35 +00:00
										 |  |  |             while(*ptr != j.ptr_) { | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  |                 node* to_delete = *ptr; | 
					
						
							|  |  |  |                 *ptr = (*ptr)->next_; | 
					
						
							|  |  |  |                 --data_.size_; | 
					
						
							|  |  |  |                 delete to_delete; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if(!*ptr) data_.last_ptr_ = ptr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bool empty() const { | 
					
						
							|  |  |  |             return !data_.size_; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         size_type size() const { | 
					
						
							|  |  |  |             return data_.size_; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         void sort() { | 
					
						
							|  |  |  |             sort(std::less<T>()); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         template <typename Less> | 
					
						
							|  |  |  |         void sort(Less less = Less()) { | 
					
						
							|  |  |  |             if(!empty()) merge_sort(&data_.first_, | 
					
						
							|  |  |  |                     (std::numeric_limits<size_type>::max)(), less); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bool operator==(list const& y) const { | 
					
						
							|  |  |  |             return size() == y.size() && | 
					
						
							| 
									
										
										
										
											2009-11-10 08:15:55 +00:00
										 |  |  |                 test::equal(begin(), end(), y.begin()); | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bool operator!=(list const& y) const { | 
					
						
							|  |  |  |             return !(*this == y); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private: | 
					
						
							|  |  |  |         template <typename Less> | 
					
						
							|  |  |  |         node** merge_sort(node** l, size_type recurse_limit, Less less) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             node** ptr = &(*l)->next_; | 
					
						
							|  |  |  |             for(size_type count = 0; count < recurse_limit && *ptr; ++count) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 ptr = merge_adjacent_ranges(l, ptr, | 
					
						
							|  |  |  |                         merge_sort(ptr, count, less), less); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return ptr; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         template <typename Less> | 
					
						
							|  |  |  |         node** merge_adjacent_ranges(node** first, node** second, | 
					
						
							|  |  |  |                 node** third, Less less) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |             for(;;) { | 
					
						
							|  |  |  |                 for(;;) { | 
					
						
							| 
									
										
										
										
											2009-03-08 09:44:51 +00:00
										 |  |  |                     if(first == second) return third; | 
					
						
							|  |  |  |                     if(less((*second)->value_, (*first)->value_)) break; | 
					
						
							|  |  |  |                     first = &(*first)->next_; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 swap_adjacent_ranges(first, second, third); | 
					
						
							|  |  |  |                 first = &(*first)->next_; | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |                 // Since the two ranges we just swapped, the order is now:
 | 
					
						
							|  |  |  |                 // first...third...second
 | 
					
						
							|  |  |  |                  | 
					
						
							| 
									
										
										
										
											2009-09-20 21:55:15 +00:00
										 |  |  |                 for(;;) { | 
					
						
							| 
									
										
										
										
											2009-03-08 09:44:51 +00:00
										 |  |  |                     if(first == third) return second; | 
					
						
							|  |  |  |                     if(!less((*first)->value_, (*third)->value_)) break; | 
					
						
							|  |  |  |                     first = &(*first)->next_; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 swap_adjacent_ranges(first, third, second); | 
					
						
							|  |  |  |                 first = &(*first)->next_; | 
					
						
							| 
									
										
										
										
											2008-05-01 09:23:22 +00:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         void swap_adjacent_ranges(node** first, node** second, node** third) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             node* tmp = *first; | 
					
						
							|  |  |  |             *first = *second; | 
					
						
							|  |  |  |             *second = *third; | 
					
						
							|  |  |  |             *third = tmp; | 
					
						
							|  |  |  |             if(!*second) data_.last_ptr_ = second; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 |