/* * * Copyright (c) 1994 * Hewlett-Packard Company * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Hewlett-Packard Company makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * */ #ifndef LIST_H #define LIST_H #include #include #include #include #ifndef Allocator #define Allocator allocator #include #endif #ifndef list #define list list #endif template class list { protected: typedef Allocator::pointer void_pointer; struct list_node; friend list_node; struct list_node { void_pointer next; void_pointer prev; T data; }; static Allocator list_node_allocator; static Allocator value_allocator; public: typedef T value_type; typedef Allocator value_allocator_type; typedef Allocator::pointer pointer; typedef Allocator::reference reference; typedef Allocator::const_reference const_reference; typedef Allocator list_node_allocator_type; typedef Allocator::pointer link_type; typedef Allocator::size_type size_type; typedef Allocator::difference_type difference_type; protected: size_type buffer_size() { return list_node_allocator.init_page_size(); } struct list_node_buffer; friend list_node_buffer; struct list_node_buffer { void_pointer next_buffer; link_type buffer; }; public: typedef Allocator buffer_allocator_type; typedef Allocator::pointer buffer_pointer; protected: static Allocator buffer_allocator; static buffer_pointer buffer_list; static link_type free_list; static link_type next_avail; static link_type last; void add_new_buffer() { buffer_pointer tmp = buffer_allocator.allocate((size_type)1); tmp->buffer = list_node_allocator.allocate(buffer_size()); tmp->next_buffer = buffer_list; buffer_list = tmp; next_avail = buffer_list->buffer; last = next_avail + buffer_size(); } static size_type number_of_lists; void deallocate_buffers(); link_type get_node() { link_type tmp = free_list; return free_list ? (free_list = (link_type)(free_list->next), tmp) : (next_avail == last ? (add_new_buffer(), next_avail++) : next_avail++); // ugly code for inlining - avoids multiple returns } void put_node(link_type p) { p->next = free_list; free_list = p; } protected: link_type node; size_type length; public: class iterator; class const_iterator; class iterator : public bidirectional_iterator { friend class list; friend class const_iterator; // friend bool operator==(const iterator& x, const iterator& y); protected: link_type node; iterator(link_type x) : node(x) {} public: iterator() {} bool operator==(const iterator& x) const { return node == x.node; } reference operator*() const { return (*node).data; } iterator& operator++() { node = (link_type)((*node).next); return *this; } iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; } iterator& operator--() { node = (link_type)((*node).prev); return *this; } iterator operator--(int) { iterator tmp = *this; --*this; return tmp; } }; class const_iterator : public bidirectional_iterator { friend class list; protected: link_type node; const_iterator(link_type x) : node(x) {} public: const_iterator() {} const_iterator(const iterator& x) : node(x.node) {} bool operator==(const const_iterator& x) const { return node == x.node; } const_reference operator*() const { return (*node).data; } const_iterator& operator++() { node = (link_type)((*node).next); return *this; } const_iterator operator++(int) { const_iterator tmp = *this; ++*this; return tmp; } const_iterator& operator--() { node = (link_type)((*node).prev); return *this; } const_iterator operator--(int) { const_iterator tmp = *this; --*this; return tmp; } }; typedef reverse_bidirectional_iterator const_reverse_iterator; typedef reverse_bidirectional_iterator reverse_iterator; list() : length(0) { ++number_of_lists; node = get_node(); (*node).next = node; (*node).prev = node; } iterator begin() { return (link_type)((*node).next); } const_iterator begin() const { return (link_type)((*node).next); } iterator end() { return node; } const_iterator end() const { return node; } reverse_iterator rbegin() { return reverse_iterator(end()); } const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } bool empty() const { return length == 0; } size_type size() const { return length; } size_type max_size() const { return list_node_allocator.max_size(); } reference front() { return *begin(); } const_reference front() const { return *begin(); } reference back() { return *(--end()); } const_reference back() const { return *(--end()); } void swap(list& x) { ::swap(node, x.node); ::swap(length, x.length); } iterator insert(iterator position, const T& x) { link_type tmp = get_node(); construct(value_allocator.address((*tmp).data), x); (*tmp).next = position.node; (*tmp).prev = (*position.node).prev; (*(link_type((*position.node).prev))).next = tmp; (*position.node).prev = tmp; ++length; return tmp; } void insert(iterator position, const T* first, const T* last); void insert(iterator position, const_iterator first, const_iterator last); void insert(iterator position, size_type n, const T& x); void push_front(const T& x) { insert(begin(), x); } void push_back(const T& x) { insert(end(), x); } void erase(iterator position) { (*(link_type((*position.node).prev))).next = (*position.node).next; (*(link_type((*position.node).next))).prev = (*position.node).prev; destroy(value_allocator.address((*position.node).data)); put_node(position.node); --length; } void erase(iterator first, iterator last); void pop_front() { erase(begin()); } void pop_back() { iterator tmp = end(); erase(--tmp); } list(size_type n, const T& value = T()) : length(0) { ++number_of_lists; node = get_node(); (*node).next = node; (*node).prev = node; insert(begin(), n, value); } list(const T* first, const T* last) : length(0) { ++number_of_lists; node = get_node(); (*node).next = node; (*node).prev = node; insert(begin(), first, last); } list(const list& x) : length(0) { ++number_of_lists; node = get_node(); (*node).next = node; (*node).prev = node; insert(begin(), x.begin(), x.end()); } ~list() { erase(begin(), end()); put_node(node); if (--number_of_lists == 0) deallocate_buffers(); } list& operator=(const list& x); protected: void transfer(iterator position, iterator first, iterator last) { (*(link_type((*last.node).prev))).next = position.node; (*(link_type((*first.node).prev))).next = last.node; (*(link_type((*position.node).prev))).next = first.node; link_type tmp = link_type((*position.node).prev); (*position.node).prev = (*last.node).prev; (*last.node).prev = (*first.node).prev; (*first.node).prev = tmp; } public: void splice(iterator position, list& x) { if (!x.empty()) { transfer(position, x.begin(), x.end()); length += x.length; x.length = 0; } } void splice(iterator position, list& x, iterator i) { iterator j = i; if (position == i || position == ++j) return; transfer(position, i, j); ++length; --x.length; } void splice(iterator position, list& x, iterator first, iterator last) { if (first != last) { if (&x != this) { difference_type n = 0; distance(first, last, n); x.length -= n; length += n; } transfer(position, first, last); } } void remove(const T& value); void unique(); void merge(list& x); void reverse(); void sort(); }; template list::buffer_pointer list::buffer_list = 0; template list::link_type list::free_list = 0; template list::link_type list::next_avail = 0; template list::link_type list::last = 0; template list::size_type list::number_of_lists = 0; template list::list_node_allocator_type list::list_node_allocator; template list::value_allocator_type list::value_allocator; template list::buffer_allocator_type list::buffer_allocator; /* * currently the following does not work - made into a member function template inline bool operator==(const list::iterator& x, const list::iterator& y) { return x.node == y.node; } */ template inline bool operator==(const list& x, const list& y) { return x.size() == y.size() && equal(x.begin(), x.end(), y.begin()); } template inline bool operator<(const list& x, const list& y) { return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } template void list::deallocate_buffers() { while (buffer_list) { buffer_pointer tmp = buffer_list; buffer_list = (buffer_pointer)(buffer_list->next_buffer); list_node_allocator.deallocate(tmp->buffer); buffer_allocator.deallocate(tmp); } free_list = 0; next_avail = 0; last = 0; } template void list::insert(iterator position, const T* first, const T* last) { while (first != last) insert(position, *first++); } template void list::insert(iterator position, const_iterator first, const_iterator last) { while (first != last) insert(position, *first++); } template void list::insert(iterator position, size_type n, const T& x) { while (n--) insert(position, x); } template void list::erase(iterator first, iterator last) { while (first != last) erase(first++); } template list& list::operator=(const list& x) { if (this != &x) { iterator first1 = begin(); iterator last1 = end(); const_iterator first2 = x.begin(); const_iterator last2 = x.end(); while (first1 != last1 && first2 != last2) *first1++ = *first2++; if (first2 == last2) erase(first1, last1); else insert(last1, first2, last2); } return *this; } template void list::remove(const T& value) { iterator first = begin(); iterator last = end(); while (first != last) { iterator next = first; ++next; if (*first == value) erase(first); first = next; } } template void list::unique() { iterator first = begin(); iterator last = end(); if (first == last) return; iterator next = first; while (++next != last) { if (*first == *next) erase(next); else first = next; next = first; } } template void list::merge(list& x) { iterator first1 = begin(); iterator last1 = end(); iterator first2 = x.begin(); iterator last2 = x.end(); while (first1 != last1 && first2 != last2) if (*first2 < *first1) { iterator next = first2; transfer(first1, first2, ++next); first2 = next; } else ++first1; if (first2 != last2) transfer(last1, first2, last2); length += x.length; x.length= 0; } template void list::reverse() { if (size() < 2) return; for (iterator first = ++begin(); first != end();) { iterator old = first++; transfer(begin(), old, first); } } template void list::sort() { if (size() < 2) return; list carry; list counter[64]; int fill = 0; while (!empty()) { carry.splice(carry.begin(), *this, begin()); int i = 0; while(i < fill && !counter[i].empty()) { counter[i].merge(carry); carry.swap(counter[i++]); } carry.swap(counter[i]); if (i == fill) ++fill; } for (int i = 1; i < fill; ++i) counter[i].merge(counter[i-1]); swap(counter[fill-1]); } #undef Allocator #undef list #endif