From 0a0572b983f0c52a144084013b5220f22e8764f3 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Thu, 1 May 2008 09:23:22 +0000 Subject: [PATCH] Add list.hpp which was missed from the merge. [SVN r44968] --- test/helpers/list.hpp | 266 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 test/helpers/list.hpp diff --git a/test/helpers/list.hpp b/test/helpers/list.hpp new file mode 100644 index 00000000..07e5daab --- /dev/null +++ b/test/helpers/list.hpp @@ -0,0 +1,266 @@ + +// Copyright 2008 Daniel James. +// 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 +#include +#include + +namespace test +{ + template class list; + + namespace test_detail + { + template struct list_node; + template class list_data; + template class list_iterator; + template class list_const_iterator; + + template + struct list_node + { + 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 + class list_data + { + public: + typedef list_node 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 + class list_iterator + : public boost::iterator< + std::forward_iterator_tag, T, + int, T*, T&> + { + friend class list_const_iterator; + friend class test::list; + typedef list_node node; + typedef list_const_iterator const_iterator; + + node* ptr_; + public: + list_iterator() : ptr_(0) {}; + 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; } + list_iterator& operator++(int) { + 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 + class list_const_iterator + : public boost::iterator< + std::forward_iterator_tag, T, + int, T const*, T const&> + { + friend class list_iterator; + friend class test::list; + typedef list_node node; + typedef list_iterator iterator; + typedef list_const_iterator const_iterator; + + node* ptr_; + public: + list_const_iterator() : ptr_(0) {} + list_const_iterator(list_iterator const& x) : ptr_(x.ptr_) {} + + T const& operator*() const { return ptr_->value_; } + T const* operator->() const { return &ptr_->value_; } + 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_; } + }; + } + + template + class list + { + typedef test::test_detail::list_data data; + typedef test::test_detail::list_node 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 iterator; + typedef test::test_detail::list_const_iterator const_iterator; + + list() : data_() {} + + list(list const& other) : data_() { + insert(other.begin(), other.end()); + } + + template + list(InputIterator i, InputIterator j) : data_() { + insert(i, j); + } + + list& operator=(list const& other) { + clear(); + insert(other.begin(), other.end()); + } + + 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 + 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_); + if(data_.size_) data_.last_ptr_ = &(*data_.last_ptr_)->next_; + ++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_; + } + + void erase(const_iterator start, const_iterator end) { + node** ptr = &data_.first_; + + while(*ptr != start.ptr_) { + ptr = &(*ptr)->next_; + } + + while(*ptr != end.ptr_) { + 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()); + } + + template + void sort(Less less = Less()) { + if(!empty()) merge_sort(&data_.first_, + (std::numeric_limits::max)(), less); + } + + bool operator==(list const& y) const { + return size() == y.size() && + std::equal(begin(), end(), y.begin()); + } + + bool operator!=(list const& y) const { + return !(*this == y); + } + + private: + template + 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 + node** merge_adjacent_ranges(node** first, node** second, + node** third, Less less) + { + while(first != second) { + if(less((*second)->value_, (*first)->value_)) { + swap_adjacent_ranges(first, second, third); + std::swap(second, third); + } + first = &(*first)->next_; + } + return third; + } + + 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