This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[v3] rb_tree improvements


Gwain graciously donated some STL improvements back in the early parts
of this year. Afer a series of delays, this assignment is now valid.

This is the first of a couple fixups.

tested x86/linux

2003-07-04  Gawain Bolton  <gbolton@free.fr>

	* include/bits/stl_tree.h: Performance and memory usage
	improvements.

Index: include/bits/stl_tree.h
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/include/bits/stl_tree.h,v
retrieving revision 1.22
diff -c -p -r1.22 stl_tree.h
*** include/bits/stl_tree.h	4 Jul 2003 12:10:13 -0000	1.22
--- include/bits/stl_tree.h	4 Jul 2003 20:34:38 -0000
*************** namespace std
*** 192,198 ****
        typedef _Rb_tree_node<_Val>* _Link_type;
        
        _Rb_tree_iterator() {}
!       _Rb_tree_iterator(_Link_type __x) { _M_node = __x; }
        _Rb_tree_iterator(const iterator& __it) { _M_node = __it._M_node; }
  
        reference 
--- 192,198 ----
        typedef _Rb_tree_node<_Val>* _Link_type;
        
        _Rb_tree_iterator() {}
!       _Rb_tree_iterator(_Rb_tree_node_base* __x) { _M_node = __x; }
        _Rb_tree_iterator(const iterator& __it) { _M_node = __it._M_node; }
  
        reference 
*************** namespace std
*** 528,540 ****
        get_allocator() const { return _M_node_allocator; }
  
        _Rb_tree_alloc_base(const allocator_type& __a)
!       : _M_node_allocator(__a), _M_header(0) {}
  
      protected:
        typename _Alloc_traits<_Rb_tree_node<_Tp>, _Alloc>::allocator_type
        _M_node_allocator;
  
!       _Rb_tree_node<_Tp>* _M_header;
        
        _Rb_tree_node<_Tp>* 
        _M_get_node()  { return _M_node_allocator.allocate(1); }
--- 528,540 ----
        get_allocator() const { return _M_node_allocator; }
  
        _Rb_tree_alloc_base(const allocator_type& __a)
!       : _M_node_allocator(__a) {}
  
      protected:
        typename _Alloc_traits<_Rb_tree_node<_Tp>, _Alloc>::allocator_type
        _M_node_allocator;
  
!       _Rb_tree_node_base _M_header;
        
        _Rb_tree_node<_Tp>* 
        _M_get_node()  { return _M_node_allocator.allocate(1); }
*************** namespace std
*** 552,561 ****
      typedef typename _Alloc_traits<_Tp, _Alloc>::allocator_type allocator_type;
        allocator_type get_allocator() const { return allocator_type(); }
  
!       _Rb_tree_alloc_base(const allocator_type&) : _M_header(0) {}
  
      protected:
!       _Rb_tree_node<_Tp>* _M_header;
        
        typedef typename _Alloc_traits<_Rb_tree_node<_Tp>, _Alloc>::_Alloc_type
        _Alloc_type;
--- 552,561 ----
      typedef typename _Alloc_traits<_Tp, _Alloc>::allocator_type allocator_type;
        allocator_type get_allocator() const { return allocator_type(); }
  
!       _Rb_tree_alloc_base(const allocator_type&) {}
  
      protected:
!       _Rb_tree_node_base _M_header;
        
        typedef typename _Alloc_traits<_Rb_tree_node<_Tp>, _Alloc>::_Alloc_type
        _Alloc_type;
*************** namespace std
*** 576,583 ****
        typedef typename _Base::allocator_type allocator_type;
  
        _Rb_tree_base(const allocator_type& __a) 
!       : _Base(__a) { this->_M_header = _M_get_node(); }
!       ~_Rb_tree_base() { _M_put_node(this->_M_header); }
      };
  
  
--- 576,582 ----
        typedef typename _Base::allocator_type allocator_type;
  
        _Rb_tree_base(const allocator_type& __a) 
!       : _Base(__a) {}
      };
  
  
*************** namespace std
*** 645,658 ****
        _Compare _M_key_compare;
  
        _Link_type& 
!       _M_root() const { return (_Link_type&) this->_M_header->_M_parent; }
  
        _Link_type& 
!       _M_leftmost() const { return (_Link_type&) this->_M_header->_M_left; }
  
        _Link_type& 
!       _M_rightmost() const { return (_Link_type&) this->_M_header->_M_right; }
  
        static _Link_type& 
        _S_left(_Link_type __x) { return (_Link_type&)(__x->_M_left); }
  
--- 644,660 ----
        _Compare _M_key_compare;
  
        _Link_type& 
!       _M_root() const { return (_Link_type&) this->_M_header._M_parent; }
  
        _Link_type& 
!       _M_leftmost() const { return (_Link_type&) this->_M_header._M_left; }
  
        _Link_type& 
!       _M_rightmost() const { return (_Link_type&) this->_M_header._M_right; }
  
+       _Link_type
+       _M_end() const { return (_Link_type) &this->_M_header; }
+       
        static _Link_type& 
        _S_left(_Link_type __x) { return (_Link_type&)(__x->_M_left); }
  
*************** namespace std
*** 668,676 ****
        static const _Key& 
        _S_key(_Link_type __x) { return _KeyOfValue()(_S_value(__x)); }
  
-       static _Rb_tree_color& 
-       _S_color(_Link_type __x) { return __x->_M_color; }
- 
        static _Link_type& 
        _S_left(_Base_ptr __x) { return (_Link_type&)(__x->_M_left); }
  
--- 670,675 ----
*************** namespace std
*** 687,693 ****
        _S_key(_Base_ptr __x) { return _KeyOfValue()(_S_value(_Link_type(__x)));} 
  
        static _Rb_tree_color&
!       _S_color(_Base_ptr __x) { return (_Link_type(__x)->_M_color); }
  
        static _Link_type 
        _S_minimum(_Link_type __x) 
--- 686,692 ----
        _S_key(_Base_ptr __x) { return _KeyOfValue()(_S_value(_Link_type(__x)));} 
  
        static _Rb_tree_color&
!       _S_color(_Base_ptr __x) { return __x->_M_color; }
  
        static _Link_type 
        _S_minimum(_Link_type __x) 
*************** namespace std
*** 737,744 ****
  	  _M_empty_initialize();
  	else 
  	  {
! 	    _S_color(this->_M_header) = _S_red;
! 	    _M_root() = _M_copy(__x._M_root(), this->_M_header);
  	    _M_leftmost() = _S_minimum(_M_root());
  	    _M_rightmost() = _S_maximum(_M_root());
  	  }
--- 736,743 ----
  	  _M_empty_initialize();
  	else 
  	  {
! 	    _S_color(&this->_M_header) = _S_red;
! 	    _M_root() = _M_copy(__x._M_root(), _M_end());
  	    _M_leftmost() = _S_minimum(_M_root());
  	    _M_rightmost() = _S_maximum(_M_root());
  	  }
*************** namespace std
*** 753,763 ****
      private:
        void _M_empty_initialize() 
        {
! 	_S_color(this->_M_header) = _S_red; // used to distinguish header from 
! 	// __root, in iterator.operator++
  	_M_root() = 0;
! 	_M_leftmost() = this->_M_header;
! 	_M_rightmost() = this->_M_header;
        }
  
      public:    
--- 752,762 ----
      private:
        void _M_empty_initialize() 
        {
! 	// Used to distinguish header from __root, in iterator.operator++.
! 	_S_color(&this->_M_header) = _S_red; 
  	_M_root() = 0;
! 	_M_leftmost() = _M_end();
! 	_M_rightmost() = _M_end();
        }
  
      public:    
*************** namespace std
*** 772,781 ****
        begin() const { return _M_leftmost(); }
  
        iterator 
!       end() { return this->_M_header; }
  
!       const_iterator 
!       end() const { return this->_M_header; }
  
        reverse_iterator 
        rbegin() { return reverse_iterator(end()); }
--- 771,780 ----
        begin() const { return _M_leftmost(); }
  
        iterator 
!       end() { return &this->_M_header; }
  
!       const_iterator
!       end() const { return const_cast<_Base_ptr>(&this->_M_header); }
  
        reverse_iterator 
        rbegin() { return reverse_iterator(end()); }
*************** namespace std
*** 799,810 ****
        max_size() const { return size_type(-1); }
  
        void 
!       swap(_Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>& __t) 
!       {
! 	std::swap(this->_M_header, __t._M_header);
! 	std::swap(_M_node_count, __t._M_node_count);
! 	std::swap(_M_key_compare, __t._M_key_compare);
!       }
      
        // Insert/erase.
        pair<iterator,bool> 
--- 798,804 ----
        max_size() const { return size_type(-1); }
  
        void 
!       swap(_Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>& __t);
      
        // Insert/erase.
        pair<iterator,bool> 
*************** namespace std
*** 845,853 ****
  	if (_M_node_count != 0) 
  	  {
  	    _M_erase(_M_root());
! 	    _M_leftmost() = this->_M_header;
  	    _M_root() = 0;
! 	    _M_rightmost() = this->_M_header;
  	    _M_node_count = 0;
  	  }
        }      
--- 839,847 ----
  	if (_M_node_count != 0) 
  	  {
  	    _M_erase(_M_root());
! 	    _M_leftmost() = _M_end();
  	    _M_root() = 0;
! 	    _M_rightmost() = _M_end();
  	    _M_node_count = 0;
  	  }
        }      
*************** namespace std
*** 955,966 ****
  	  if (__x._M_root() == 0) 
  	    {
  	      _M_root() = 0;
! 	      _M_leftmost() = this->_M_header;
! 	      _M_rightmost() = this->_M_header;
  	    }
  	  else 
  	    {
! 	      _M_root() = _M_copy(__x._M_root(), this->_M_header);
  	      _M_leftmost() = _S_minimum(_M_root());
  	      _M_rightmost() = _S_maximum(_M_root());
  	      _M_node_count = __x._M_node_count;
--- 949,960 ----
  	  if (__x._M_root() == 0) 
  	    {
  	      _M_root() = 0;
! 	      _M_leftmost() = _M_end();
! 	      _M_rightmost() = _M_end();
  	    }
  	  else 
  	    {
! 	      _M_root() = _M_copy(__x._M_root(), _M_end());
  	      _M_leftmost() = _S_minimum(_M_root());
  	      _M_rightmost() = _S_maximum(_M_root());
  	      _M_node_count = __x._M_node_count;
*************** namespace std
*** 979,991 ****
        _Link_type __y = (_Link_type) __y_;
        _Link_type __z;
        
!       if (__y == this->_M_header || __x != 0 || 
  	  _M_key_compare(_KeyOfValue()(__v), _S_key(__y))) 
  	{
  	  __z = _M_create_node(__v);
  	  _S_left(__y) = __z;               // also makes _M_leftmost() = __z 
! 	  //    when __y == _M_header
! 	  if (__y == this->_M_header) 
  	    {
  	      _M_root() = __z;
  	      _M_rightmost() = __z;
--- 973,985 ----
        _Link_type __y = (_Link_type) __y_;
        _Link_type __z;
        
!       if (__y == &this->_M_header || __x != 0 || 
  	  _M_key_compare(_KeyOfValue()(__v), _S_key(__y))) 
  	{
  	  __z = _M_create_node(__v);
  	  _S_left(__y) = __z;               // also makes _M_leftmost() = __z 
! 	  //    when __y == &_M_header
! 	  if (__y == &this->_M_header) 
  	    {
  	      _M_root() = __z;
  	      _M_rightmost() = __z;
*************** namespace std
*** 1004,1010 ****
        _S_parent(__z) = __y;
        _S_left(__z) = 0;
        _S_right(__z) = 0;
!       _Rb_tree_rebalance(__z, this->_M_header->_M_parent);
        ++_M_node_count;
        return iterator(__z);
      }
--- 998,1004 ----
        _S_parent(__z) = __y;
        _S_left(__z) = 0;
        _S_right(__z) = 0;
!       _Rb_tree_rebalance(__z, this->_M_header._M_parent);
        ++_M_node_count;
        return iterator(__z);
      }
*************** namespace std
*** 1015,1021 ****
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      insert_equal(const _Val& __v)
      {
!       _Link_type __y = this->_M_header;
        _Link_type __x = _M_root();
        while (__x != 0) 
  	{
--- 1009,1015 ----
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      insert_equal(const _Val& __v)
      {
!       _Link_type __y = _M_end();
        _Link_type __x = _M_root();
        while (__x != 0) 
  	{
*************** namespace std
*** 1028,1039 ****
  
    template<typename _Key, typename _Val, typename _KeyOfValue, 
             typename _Compare, typename _Alloc>
      pair<typename _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::iterator, 
      bool>
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      insert_unique(const _Val& __v)
      {
!       _Link_type __y = this->_M_header;
        _Link_type __x = _M_root();
        bool __comp = true;
        while (__x != 0) 
--- 1022,1078 ----
  
    template<typename _Key, typename _Val, typename _KeyOfValue, 
             typename _Compare, typename _Alloc>
+     void
+     _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
+     swap(_Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>& __t)
+     {
+       if (_M_root() == 0)
+       {
+ 	if (__t._M_root() != 0)
+ 	{
+ 	  _M_root() = __t._M_root();
+ 	  _M_leftmost() = __t._M_leftmost();
+ 	  _M_rightmost() = __t._M_rightmost();
+           _M_root()->_M_parent = _M_end();
+ 
+ 	  __t._M_root() = 0;
+ 	  __t._M_leftmost() = __t._M_end();
+ 	  __t._M_rightmost() = __t._M_end();
+ 	}
+       }
+       else if (__t._M_root() == 0)
+       {
+ 	__t._M_root() = _M_root();
+ 	__t._M_leftmost() = _M_leftmost();
+ 	__t._M_rightmost() = _M_rightmost();
+         __t._M_root()->_M_parent = __t._M_end();
+ 
+ 	_M_root() = 0;
+ 	_M_leftmost() = _M_end();
+ 	_M_rightmost() = _M_end();
+       }
+       else
+       {
+ 	std::swap(_M_root(),__t._M_root());
+ 	std::swap(_M_leftmost(),__t._M_leftmost());
+ 	std::swap(_M_rightmost(),__t._M_rightmost());
+ 
+ 	_M_root()->_M_parent = _M_end();
+ 	__t._M_root()->_M_parent = __t._M_end();
+       }
+       // No need to swap header's color as it does not change.
+       std::swap(this->_M_node_count, __t._M_node_count);
+       std::swap(this->_M_key_compare, __t._M_key_compare);
+     }
+ 
+   template<typename _Key, typename _Val, typename _KeyOfValue, 
+            typename _Compare, typename _Alloc>
      pair<typename _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::iterator, 
      bool>
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      insert_unique(const _Val& __v)
      {
!       _Link_type __y = _M_end();
        _Link_type __x = _M_root();
        bool __comp = true;
        while (__x != 0) 
*************** namespace std
*** 1060,1066 ****
      _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
      insert_unique(iterator __position, const _Val& __v)
      {
!       if (__position._M_node == this->_M_header->_M_left) 
  	{ 
  	  // begin()
  	  if (size() > 0 && 
--- 1099,1105 ----
      _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
      insert_unique(iterator __position, const _Val& __v)
      {
!       if (__position._M_node == this->_M_header._M_left) 
  	{ 
  	  // begin()
  	  if (size() > 0 && 
*************** namespace std
*** 1070,1076 ****
  	  else
  	    return insert_unique(__v).first;
  	} 
!       else if (__position._M_node == this->_M_header) 
  	{ 
  	  // end()
  	  if (_M_key_compare(_S_key(_M_rightmost()), _KeyOfValue()(__v)))
--- 1109,1115 ----
  	  else
  	    return insert_unique(__v).first;
  	} 
!       else if (__position._M_node == &this->_M_header) 
  	{ 
  	  // end()
  	  if (_M_key_compare(_S_key(_M_rightmost()), _KeyOfValue()(__v)))
*************** namespace std
*** 1102,1108 ****
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      insert_equal(iterator __position, const _Val& __v)
      {
!       if (__position._M_node == this->_M_header->_M_left) 
  	{ 
  	  // begin()
  	  if (size() > 0 && 
--- 1141,1147 ----
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      insert_equal(iterator __position, const _Val& __v)
      {
!       if (__position._M_node == this->_M_header._M_left) 
  	{ 
  	  // begin()
  	  if (size() > 0 && 
*************** namespace std
*** 1112,1118 ****
  	  else
  	    return insert_equal(__v);
  	} 
!       else if (__position._M_node == this->_M_header) 
  	{
  	  // end()
  	  if (!_M_key_compare(_KeyOfValue()(__v), _S_key(_M_rightmost())))
--- 1151,1157 ----
  	  else
  	    return insert_equal(__v);
  	} 
!       else if (__position._M_node == &this->_M_header) 
  	{
  	  // end()
  	  if (!_M_key_compare(_KeyOfValue()(__v), _S_key(_M_rightmost())))
*************** namespace std
*** 1168,1176 ****
      {
        _Link_type __y = 
  	(_Link_type) _Rb_tree_rebalance_for_erase(__position._M_node,
! 						  this->_M_header->_M_parent,
! 						  this->_M_header->_M_left,
! 						  this->_M_header->_M_right);
        destroy_node(__y);
        --_M_node_count;
      }
--- 1207,1215 ----
      {
        _Link_type __y = 
  	(_Link_type) _Rb_tree_rebalance_for_erase(__position._M_node,
! 						  this->_M_header._M_parent,
! 						  this->_M_header._M_left,
! 						  this->_M_header._M_right);
        destroy_node(__y);
        --_M_node_count;
      }
*************** namespace std
*** 1264,1272 ****
      typename _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::iterator 
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::find(const _Key& __k)
      {
!       _Link_type __y
! 	= this->_M_header;  // Last node which is not less than __k. 
!       _Link_type __x = _M_root();  // Current node. 
        
        while (__x != 0) 
  	if (!_M_key_compare(_S_key(__x), __k))
--- 1303,1310 ----
      typename _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::iterator 
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::find(const _Key& __k)
      {
!       _Link_type __y = _M_end(); // Last node which is not less than __k. 
!       _Link_type __x = _M_root(); // Current node. 
        
        while (__x != 0) 
  	if (!_M_key_compare(_S_key(__x), __k))
*************** namespace std
*** 1285,1292 ****
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      find(const _Key& __k) const
      {
!       _Link_type __y
! 	= this->_M_header; // Last node which is not less than __k. 
        _Link_type __x = _M_root(); // Current node. 
   
       while (__x != 0) 
--- 1323,1329 ----
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      find(const _Key& __k) const
      {
!       _Link_type __y = _M_end(); // Last node which is not less than __k. 
        _Link_type __x = _M_root(); // Current node. 
   
       while (__x != 0) 
*************** namespace std
*** 1318,1326 ****
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      lower_bound(const _Key& __k)
      {
!       _Link_type __y
! 	= this->_M_header; /* Last node which is not less than __k. */
!       _Link_type __x = _M_root(); /* Current node. */
        
        while (__x != 0) 
  	if (!_M_key_compare(_S_key(__x), __k))
--- 1355,1362 ----
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      lower_bound(const _Key& __k)
      {
!       _Link_type __y = _M_end(); // Last node which is not less than __k
!       _Link_type __x = _M_root(); // Current node.
        
        while (__x != 0) 
  	if (!_M_key_compare(_S_key(__x), __k))
*************** namespace std
*** 1337,1345 ****
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      lower_bound(const _Key& __k) const
      {
!       _Link_type __y
! 	= this->_M_header; /* Last node which is not less than __k. */
!       _Link_type __x = _M_root(); /* Current node. */
        
        while (__x != 0) 
  	if (!_M_key_compare(_S_key(__x), __k))
--- 1373,1380 ----
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      lower_bound(const _Key& __k) const
      {
!       _Link_type __y = _M_end(); // Last node which is not less than __k.
!       _Link_type __x = _M_root(); // Current node.
        
        while (__x != 0) 
  	if (!_M_key_compare(_S_key(__x), __k))
*************** namespace std
*** 1356,1364 ****
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      upper_bound(const _Key& __k)
      {
!       _Link_type __y
! 	= this->_M_header; /* Last node which is greater than __k. */
!       _Link_type __x = _M_root(); /* Current node. */
        
        while (__x != 0) 
  	if (_M_key_compare(__k, _S_key(__x)))
--- 1391,1398 ----
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      upper_bound(const _Key& __k)
      {
!       _Link_type __y = _M_end(); // Last node which is greater than __k.
!       _Link_type __x = _M_root(); // Current node.
        
        while (__x != 0) 
  	if (_M_key_compare(__k, _S_key(__x)))
*************** namespace std
*** 1375,1383 ****
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      upper_bound(const _Key& __k) const
      {
!       _Link_type __y
! 	= this->_M_header; /* Last node which is greater than __k. */
!       _Link_type __x = _M_root(); /* Current node. */
        
        while (__x != 0) 
  	if (_M_key_compare(__k, _S_key(__x)))
--- 1409,1416 ----
      _Rb_tree<_Key,_Val,_KeyOfValue,_Compare,_Alloc>::
      upper_bound(const _Key& __k) const
      {
!       _Link_type __y = _M_end(); // Last node which is greater than __k.
!       _Link_type __x = _M_root(); // Current node.
        
        while (__x != 0) 
  	if (_M_key_compare(__k, _S_key(__x)))
*************** namespace std
*** 1434,1441 ****
      {
      if (_M_node_count == 0 || begin() == end())
        return _M_node_count == 0 && begin() == end() &&
! 	this->_M_header->_M_left == this->_M_header
! 	&& this->_M_header->_M_right == this->_M_header;
    
      int __len = __black_count(_M_leftmost(), _M_root());
      for (const_iterator __it = begin(); __it != end(); ++__it) 
--- 1467,1474 ----
      {
      if (_M_node_count == 0 || begin() == end())
        return _M_node_count == 0 && begin() == end() &&
! 	this->_M_header._M_left == &this->_M_header &&
! 	this->_M_header._M_right == &this->_M_header;
    
      int __len = __black_count(_M_leftmost(), _M_root());
      for (const_iterator __it = begin(); __it != end(); ++__it) 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]