/** -*- C++ -*- ** ** KAI C++ Compiler ** ** Copyright (C) 1996-2001 Intel Corp. All rights reserved. **/ /** ** Lib++ : The Modena C++ Standard Library, ** Version 2.4, October 1997 ** ** Copyright (c) 1995-1997 Modena Software Inc. **/ #ifndef __KAI_LIST #define __KAI_LIST #include #include #include #include #include namespace __kai { struct list_node_base { list_node_base * next; list_node_base * prev; }; inline void list_transfer( list_node_base*p, list_node_base* q, list_node_base* r_next ) // Must not be called if q==r_next { if( p!=q && p!=r_next ) { // Cut [q,r] from source list. list_node_base* p_prev = p->prev; list_node_base* r = r_next->prev; list_node_base* q_prev = q->prev; q_prev->next = r_next; r_next->prev = q_prev; // Splice [q,r] in front of p. p->prev = r; p_prev->next = q; r->next = p; q->prev = p_prev; } } void list_reverse( list_node_base * p ) throw(); template class list_n_of_iterator { private: size_t n; const T* value; public: list_n_of_iterator( size_t n1, const T& value1 ) : n(n1), value(&value1) {} list_n_of_iterator() : n(0), value(0) {} const T& operator*() const {return *value;} const list_n_of_iterator& operator++() {--n; return *this;} bool operator==( const list_n_of_iterator& other ) {return n==0;} }; } // namespace kai namespace std { template > class list: public __kai::allocator_base { public: // types: typedef typename Allocator::reference reference; typedef typename Allocator::const_reference const_reference; class iterator; class const_iterator; // Note that the size of a list is unrelated to Allocator::size_type - ADR typedef unsigned long size_type; typedef long difference_type; typedef T value_type; typedef Allocator allocator_type; typedef typename Allocator::pointer pointer; typedef typename Allocator::const_pointer const_pointer; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; private: typedef __kai::list_node_base list_node_base; struct list_node: public list_node_base { T data; }; typedef __kai::allocator_base value_allocator_type; typedef typename Allocator:: template rebind::other list_node_allocator_type; template class _Helper {}; template void _disambiguate_assign(InputIterator first, InputIterator last, _Helper *) { _assign( __kai::list_n_of_iterator((size_type)first,(T)last), __kai::list_n_of_iterator() ); } template void _disambiguate_assign(InputIterator first, InputIterator last, _Helper *) { _assign( first, last ); } template void _insert(iterator position, InputIterator first, InputIterator last, _Helper *) { size_type n = static_cast(first); const T value = static_cast(last); insert(position, n, value); } template void _insert(iterator position, InputIterator first, InputIterator last, _Helper *) { for (; first != last; ++first) insert(position, *first); } template void _assign(InputIterator first, InputIterator last); public: // 23.2.2.1 construct/copy/destroy: explicit list(const Allocator& a=Allocator()) : value_allocator_type(a), length(0) {root.prev=root.next=&root;} list(size_type n, const T& value=T(), const Allocator& a=Allocator()) : value_allocator_type(a), length(0) { root.prev=root.next=&root; if(n>0) { _assign( __kai::list_n_of_iterator(n,value), __kai::list_n_of_iterator() ); } } template list(InputIterator first, InputIterator last, const Allocator& a=Allocator() ) : value_allocator_type(a), length(0) { root.prev=root.next=&root; _disambiguate_assign(first, last, (_Helper::is_integer> *)0); } list(const list& x) : value_allocator_type(x), length(0) { root.prev=root.next=&root; if( x.length ) { _assign( x.begin(), x.end() ); } } ~list(); list& operator=(const list& x); template void assign(InputIterator first2, InputIterator last2) {_disambiguate_assign(first2,last2,(_Helper::is_integer> *)0);} void assign(size_type n, const T& t) { _assign( __kai::list_n_of_iterator(n,t), __kai::list_n_of_iterator() ); } // Iterators: iterator begin() { return iterator(root.next); } const_iterator begin() const { return const_iterator(root.next); } iterator end() { return iterator(&root); } const_iterator end() const { return const_iterator(&root); } 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()); } // 23.2.2.2 bool empty() const { return(length == 0); } size_type size() const { return length; } void resize(size_type new_size) { resize(new_size, T()); } void resize(size_type new_size, T c); // element access: reference front() { return *begin(); } const_reference front() const { return *begin(); } reference back() { return *(--end()); } const_reference back() const { return *(--end()); } // 23.2.2.3 modifiers void push_front(const T& x) { insert(begin(), x); } void push_back(const T& x) { insert(end(), x); } void pop_front() { erase(begin()); } void pop_back() { erase(--end()); } iterator insert(iterator position, const T& x) { link_type tmp = get_node(); MSIPL_TRY { _get_allocator().construct(&((*tmp).data), x); } MSIPL_CATCH { free_node(tmp); MSIPL_RETHROW; } list_node_base * next = position.node; list_node_base * prev = next->prev; tmp->prev = prev; tmp->next = next; prev->next = tmp; next->prev = tmp; ++length; return iterator(tmp); } void insert(iterator position, size_type n, const T& x) { if( n>0 ) { list tmp( n, x ); __kai::list_transfer( position.node, tmp.root.next, &tmp.root ); length += tmp.length; tmp.root.next = tmp.root.prev = &tmp.root; tmp.length = 0; } } template void insert(iterator position, InputIterator first, InputIterator last) { if( first!=last ) { list tmp( first, last ); __kai::list_transfer( position.node, tmp.root.next, &tmp.root ); length += tmp.length; tmp.root.next = tmp.root.prev = &tmp.root; tmp.length = 0; } } iterator erase(iterator position) { link_type p = static_cast(position.node); list_node_base* next = p->next; list_node_base* prev = p->prev; prev->next = p->next; next->prev = p->prev; _get_allocator().destroy(&p->data); --length; free_node(p); return iterator(next); } iterator erase(iterator first, iterator last) { while(first != last) erase(first++); return last; } void swap(list& x) { std::swap( *(value_allocator_type*)this, *(value_allocator_type*)&x ); std::swap(length, x.length); std::swap(root, x.root); if( length ) { root.prev->next = root.next->prev = &root; } else { root.prev = root.next = &root; } if( x.length ) { x.root.prev->next = x.root.next->prev = &x.root; } else { x.root.prev = x.root.next = &x.root; } } void clear() { erase(begin(), end()); } // 23.2.2.4 list operations void splice(iterator position, list& x) { if (!x.empty() && &x != this) { __kai::list_transfer(position.node, x.begin().node, x.end().node ); length += x.length; x.length = 0; } } void splice(iterator position, list& x, iterator i) { __kai::list_transfer(position.node, i.node, i.node->next); ++length; --x.length; } void splice(iterator position, list& x, iterator first, iterator last) { if (first != last) { if (&x != this) { difference_type n = distance(first, last); x.length -= n; length += n; } __kai::list_transfer(position.node, first.node, last.node); } } void remove(const T& value); template void remove_if(Predicate pred); void unique(); template void unique(BinaryPredicate binary_pred); void merge(list& x) {merge(x,__kai::default_less());} template void merge(list& x, Compare comp); void sort() {sort(__kai::default_less());} template void sort(Compare comp); void reverse() {if( length>=2 ) __kai::list_reverse(&root);} private: void clean_up() { while( root.next != &root ) { link_type p = static_cast(root.next); root.next = p ->next; if( length>0 ) { --length; _get_allocator().destroy(&p->data); } free_node(p); } } private: friend class list::iterator; friend class list::const_iterator; typedef struct list::list_node * link_type; list_node_base root; size_type length; // Note on exception safety: the first "length" items in the list are always constructed. // When cleaning up after an exception, the first "length" items must be destroyed. // Then all items in the list must be deallocated. link_type get_node() { return _get_rebound_allocator().allocate((typename Allocator::size_type)1); } void free_node( list_node_base * p ) { return _get_rebound_allocator().deallocate(static_cast(p),(typename Allocator::size_type)1); } public: class iterator : public std::iterator { friend class list; friend class list::const_iterator; list_node_base* node; iterator(list_node_base* x) : node(x) {} public: iterator() : node(0) {} bool operator==(const iterator& x) const { return node == x.node; } bool operator==(const const_iterator& x) const { return node == x.node; } bool operator!=(const iterator& x) const { return node != x.node; } bool operator!=(const const_iterator& x) const { return node != x.node; } reference operator*() const { return static_cast(node)->data; } pointer operator->() const { return &(operator*()); } iterator& operator++() { node = node->next; return *this; } iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; } iterator& operator--() { node = node->prev; return *this; } iterator operator--(int) { iterator tmp = *this; --*this; return tmp; } }; // const_iterator class const_iterator : public std::iterator { friend class list; friend class list::iterator; const list_node_base* node; const_iterator(const list_node_base* x) : node(x) { } public: const_iterator(): node(0) { } const_iterator(const list::iterator& x) : node(x.node) { } bool operator==(const const_iterator& x) const { return node == x.node; } bool operator!=(const const_iterator& x) const { return node != x.node; } const_reference operator*() const { return static_cast(node)->data; } const_pointer operator->() const { return &(operator*()); } const_iterator& operator++() { node = node->next; return *this; } const_iterator operator++(int) { const_iterator tmp = *this; ++*this; return tmp; } const_iterator& operator--() { node = node->prev; return *this; } const_iterator operator--(int) { const_iterator tmp = *this; --*this; return tmp; } }; }; 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 inline bool operator!=(const list& x, const list& y) { return ! (x == y); } template inline bool operator>(const list& x, const list& y) { return(y < x); } template inline bool operator>=(const list& x, const list& y) { return ! (x < y); } template inline bool operator<=(const list& x, const list& y) { return ! (y < x); } template void swap(list& x, list& y) { x.swap(y); } template list::~list() { clean_up(); } template template void list::_assign( InputIterator first, InputIterator last ) { // Destroy any extra nodes. list_node_base * p=root.prev; while( length>0 ) { _get_allocator().destroy(&static_cast(p)->data); p = p->prev; --length; } p = root.next; if( !(first==last) ) { // Construct nodes MSIPL_TRY { do { if( p==&root ) { // Link in a new node at end of list. p = get_node(); list_node_base * q = root.prev; p->next = &root; p->prev = root.prev; q->next = p; root.prev = p; } _get_allocator().construct( &static_cast(p)->data, *first ); ++first; ++length; p = p->next; } while( !(first==last) ); } MSIPL_CATCH { clean_up(); MSIPL_RETHROW; } } // Free any extra nodes. while( p!=&root ) { list_node_base* p_next = p->next; list_node_base* p_prev = p->prev; p_next->prev = p_prev; p_prev->next = p_next; free_node( p ); p = p_next; } } template list& list::operator=(const list& x) { if (this == &x) return *this; iterator first1 = begin(); iterator last1 = end(); const_iterator first2 = x.begin(); const_iterator last2 = x.end(); for (; first1 != last1 && first2 != last2; ++first1, ++first2) *first1 = *first2; if (first2 == last2) erase(first1, last1); else insert(last1, first2, last2); return *this; } template void list::resize(size_type new_size, T c) { const size_type len = length; if (new_size < len) { iterator iter; if (new_size < len / 2) { iter = begin(); advance(iter, (difference_type)new_size); } else { iter = end(); advance(iter, (difference_type) (new_size - len)); } erase(iter, end()); } else if (new_size > len) insert(end(), new_size - len, c); } template void list::remove(const T& value) { iterator first = begin(); iterator last = end(); while (first != last) if (*first == value) erase(first++); else ++first; } 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); next = first; } else { first = next; } } } template template void list::remove_if(Predicate pred) { iterator first = begin(); iterator last = end(); while (first != last) if (pred(*first)) erase(first++); else first++; } template template void list::unique(BinaryPredicate binary_pred) { iterator first = begin(); iterator last = end(); if (first == last) return; iterator next = first; while (++next != last) if (binary_pred(*first, *next)) { erase(next); next =first; } else first = next; } template template void list::merge(list& x, Compare comp) { if( this == &x || x.empty()) return; list_node_base* first1 = root.next; list_node_base* last1 = &root; list_node_base* first2 = x.root.next; list_node_base* last2 = &x.root; while( first1 != last1 && first2 != last2 ) { list_node_base* p=first2; while( comp(static_cast(first2)->data,static_cast(first1)->data) ) { first2=first2->next; if( first2==last2 ) break; } if( p!=first2 ) { __kai::list_transfer(first1, p, first2); } first1 = first1->next; } if( first2 != last2 ) __kai::list_transfer( last1, first2, last2); length += x.length; x.length= 0; } template template void list::sort(Compare comp) { 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, comp); carry.swap(counter[i++]); } carry.swap(counter[i]); if (i == fill) ++fill; } while (fill--) merge(counter[fill], comp); } } // namespace std #endif /* __KAI_LIST */