1  // -*- C++ -*-
       2  
       3  // Copyright (C) 2009-2023 Free Software Foundation, Inc.
       4  //
       5  // This file is part of the GNU ISO C++ Library.  This library is free
       6  // software; you can redistribute it and/or modify it under the terms
       7  // of the GNU General Public License as published by the Free Software
       8  // Foundation; either version 3, or (at your option) any later
       9  // version.
      10  
      11  // This library is distributed in the hope that it will be useful, but
      12  // WITHOUT ANY WARRANTY; without even the implied warranty of
      13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14  // General Public License for more details.
      15  
      16  // You should have received a copy of the GNU General Public License along
      17  // with this library; see the file COPYING3.  If not see
      18  // <http://www.gnu.org/licenses/>.
      19  
      20  #ifndef _GLIBCXX_TESTSUITE_CONTAINERS_H
      21  #define _GLIBCXX_TESTSUITE_CONTAINERS_H
      22  
      23  #include <bits/boost_concept_check.h>
      24  #include <cassert>
      25  #include <testsuite_container_traits.h>
      26  #include <utility> // for rel_ops.
      27  
      28  // Container requirement testing.
      29  namespace __gnu_test
      30  {
      31    // Compile-time typedef testing.
      32    template<typename _Tp, bool _Bt = traits<_Tp>::is_container::value>
      33      struct basic_types
      34      {
      35        // Base container requirements (table 80)
      36        typedef _Tp 					test_type;
      37        typedef typename test_type::value_type 		value_type;
      38        typedef typename test_type::pointer 		pointer;
      39        typedef typename test_type::const_pointer 	const_pointer;
      40        typedef typename test_type::reference 		reference;
      41        typedef typename test_type::const_reference 	const_reference;
      42        typedef typename test_type::iterator 		iterator;
      43        typedef typename test_type::const_iterator 	const_iterator;
      44        typedef typename test_type::size_type 		size_type;
      45        typedef typename test_type::difference_type 	difference_type;
      46      };
      47  
      48    // Conditional typedef testing, positive.
      49    template<typename _Tp, bool _Bt = traits<_Tp>::is_reversible::value>
      50      struct reversible_types
      51      {
      52        // Reversible container requirements (table 81)
      53        typedef _Tp 					 test_type;
      54        typedef typename test_type::reverse_iterator 	 reverse_iterator;
      55        typedef typename test_type::const_reverse_iterator const_reverse_iterator;
      56      };
      57  
      58    template<typename _Tp, bool _Bt = traits<_Tp>::is_allocator_aware::value>
      59      struct allocator_aware_types
      60      {
      61        // _Alloc-aware requirements (table 82)
      62        typedef _Tp 					 test_type;
      63        typedef typename test_type::allocator_type      	 allocator_type;
      64      };
      65  
      66    template<typename _Tp, bool _Bt = traits<_Tp>::is_associative::value>
      67      struct associative_types
      68      {
      69        // Associative container requirements (table 85)
      70        typedef _Tp 					 test_type;
      71        typedef typename test_type::key_type		 key_type;
      72        typedef typename test_type::key_compare		 key_compare;
      73        typedef typename test_type::value_compare		 value_compare;
      74      };
      75  
      76    template<typename _Tp, bool = traits<_Tp>::is_unordered::value>
      77      struct unordered_types
      78      {
      79        // Unordered associative container requirements (table 87)
      80        typedef _Tp 					 test_type;
      81        typedef typename test_type::key_type		 key_type;
      82        typedef typename test_type::hasher		 hasher;
      83        typedef typename test_type::key_equal		 key_equal;
      84        typedef typename test_type::local_iterator	 local_iterator;
      85        typedef typename test_type::const_local_iterator	 const_local_iterator;
      86      };
      87  
      88    template<typename _Tp, bool _Bt = traits<_Tp>::is_mapped::value>
      89      struct mapped_types
      90      {
      91        typedef _Tp 					 test_type;
      92        typedef typename test_type::mapped_type	   	 mapped_type;
      93      };
      94  
      95    template<typename _Tp, bool = traits<_Tp>::is_adaptor::value>
      96      struct adaptor_types
      97      {
      98        // Container adaptor requirements.
      99        typedef _Tp 					test_type;
     100        typedef typename test_type::value_type 		value_type;
     101        typedef typename test_type::reference 		reference;
     102        typedef typename test_type::const_reference 	const_reference;
     103        typedef typename test_type::size_type 		size_type;
     104        typedef typename test_type::container_type 	container_type;
     105      };
     106  
     107    // Conditional typedef testing, negative.
     108    template<typename _Tp>
     109      struct basic_types<_Tp, false> { };
     110  
     111    template<typename _Tp>
     112      struct adaptor_types<_Tp, false> { };
     113  
     114    template<typename _Tp>
     115      struct reversible_types<_Tp, false> { };
     116  
     117    template<typename _Tp>
     118      struct allocator_aware_types<_Tp, false> { };
     119  
     120    template<typename _Tp>
     121      struct associative_types<_Tp, false> { };
     122  
     123    template<typename _Tp>
     124      struct unordered_types<_Tp, false> { };
     125  
     126    template<typename _Tp>
     127      struct mapped_types<_Tp, false> { };
     128  
     129    // Primary template.
     130    template<typename _Tp>
     131      struct types
     132      : basic_types<_Tp>, adaptor_types<_Tp>, reversible_types<_Tp>,
     133        allocator_aware_types<_Tp>, associative_types<_Tp>,
     134        unordered_types<_Tp>, mapped_types<_Tp>
     135      { };
     136  
     137  
     138    // Run-time test for constant_iterator requirements.
     139    template<typename _Tp, bool = traits<_Tp>::is_allocator_aware::value>
     140      struct populate
     141      {
     142        populate(_Tp& container)
     143        {
     144  	// Avoid uninitialized warnings, requires DefaultContructible.
     145  	typedef typename _Tp::value_type value_type;
     146  	container.insert(container.begin(), value_type());
     147  	container.insert(container.begin(), value_type());
     148        }
     149    };
     150  
     151    template<typename _Tp>
     152      struct populate<_Tp, false>
     153      {
     154        populate(_Tp& container) { }
     155      };
     156  
     157    template<typename _Tp, bool = traits<_Tp>::is_reversible::value>
     158      struct reverse_members
     159      {
     160        reverse_members(_Tp& container)
     161        {
     162  	assert( container.crbegin() == container.rbegin() );
     163  	assert( container.crend() == container.rend() );
     164  	assert( container.crbegin() != container.crend() );
     165        }
     166      };
     167  
     168    template<typename _Tp>
     169      struct reverse_members<_Tp, false>
     170      {
     171        reverse_members(_Tp&) { }
     172      };
     173  
     174    template<typename _Iterator,
     175  	   bool _Mutable,
     176  	   typename = typename std::iterator_traits<_Iterator>::iterator_category>
     177      struct iterator_concept_checks;
     178  
     179  #if __cplusplus >= 201103L
     180    // DR 691.
     181    template<typename _Tp>
     182      struct forward_members_unordered
     183      {
     184        forward_members_unordered(const typename _Tp::value_type& v)
     185        {
     186  	// Make sure that even if rel_ops is injected there is no ambiguity
     187  	// when comparing iterators.
     188  	using namespace std::rel_ops;
     189  
     190  	typedef _Tp					test_type;
     191  	test_type container;
     192  	container.insert(v);
     193  
     194  	iterator_concept_checks<typename _Tp::local_iterator, false> cc;
     195  	iterator_concept_checks<typename _Tp::const_local_iterator,
     196  				false> ccc;
     197  
     198  	assert( container.cbegin(0) == container.begin(0) );
     199  	assert( container.cend(0) == container.end(0) );
     200  	const auto bn = container.bucket(1);
     201  	auto clit = container.cbegin(bn);
     202  	assert( clit != container.cend(bn) );
     203  	assert( clit != container.end(bn) );
     204  	assert( clit++ == container.cbegin(bn) );
     205  	assert( clit == container.end(bn) );
     206  
     207  	clit = container.cbegin(bn);
     208  	assert( ++clit == container.cend(bn) );
     209  
     210  	assert( container.begin(bn) != container.cend(bn) );
     211        }
     212      };
     213  #endif
     214  
     215    template<typename _Iterator>
     216      struct iterator_concept_checks<_Iterator, false,
     217  				   std::forward_iterator_tag>
     218      {
     219        iterator_concept_checks()
     220        {
     221  	using namespace __gnu_cxx;
     222  	__function_requires<_ForwardIteratorConcept<_Iterator>>();
     223        }
     224      };
     225  
     226    template<typename _Iterator>
     227      struct iterator_concept_checks<_Iterator, true,
     228  				   std::forward_iterator_tag>
     229      {
     230        iterator_concept_checks()
     231        {
     232  	using namespace __gnu_cxx;
     233  	__function_requires<_Mutable_ForwardIteratorConcept<_Iterator>>();
     234        }
     235      };
     236  
     237    template<typename _Iterator>
     238      struct iterator_concept_checks<_Iterator, false,
     239  				   std::bidirectional_iterator_tag>
     240      {
     241        iterator_concept_checks()
     242        {
     243  	using namespace __gnu_cxx;
     244  	__function_requires<_BidirectionalIteratorConcept<_Iterator>>();
     245        }
     246      };
     247  
     248    template<typename _Iterator>
     249      struct iterator_concept_checks<_Iterator, true,
     250  				   std::bidirectional_iterator_tag>
     251      {
     252        iterator_concept_checks()
     253        {
     254  	using namespace __gnu_cxx;
     255  	__function_requires<_Mutable_BidirectionalIteratorConcept<_Iterator>>();
     256        }
     257      };
     258  
     259    template<typename _Iterator>
     260      struct iterator_concept_checks<_Iterator, false,
     261  				   std::random_access_iterator_tag>
     262      {
     263        iterator_concept_checks()
     264        {
     265  	using namespace __gnu_cxx;
     266  	__function_requires<_RandomAccessIteratorConcept<_Iterator>>();
     267        }
     268      };
     269  
     270    template<typename _Iterator>
     271      struct iterator_concept_checks<_Iterator, true,
     272  				   std::random_access_iterator_tag>
     273      {
     274        iterator_concept_checks()
     275        {
     276  	using namespace __gnu_cxx;
     277  	__function_requires<_Mutable_RandomAccessIteratorConcept<_Iterator>>();
     278        }
     279      };
     280  
     281    template<typename _Tp>
     282      struct forward_members
     283      {
     284        forward_members(_Tp& container)
     285        {
     286  	// Make sure that even if rel_ops is injected there is no ambiguity
     287  	// when comparing iterators.
     288  	using namespace std::rel_ops;
     289  
     290  	typedef traits<_Tp> traits_type;
     291  	iterator_concept_checks<typename _Tp::iterator,
     292  				!(traits_type::is_associative::value
     293  				  || traits_type::is_unordered::value)> cc;
     294  	iterator_concept_checks<typename _Tp::const_iterator, false> ccc;
     295  
     296  	assert( container.cbegin() == container.begin() );
     297  	assert( container.end() == container.cend() );
     298  	assert( container.cbegin() != container.cend() );
     299  	assert( container.cbegin() != container.end() );
     300  	assert( container.begin() != container.cend() );
     301        }
     302    };
     303  
     304    template<typename _Tp,
     305  	   typename
     306      = typename std::iterator_traits<typename _Tp::iterator>::iterator_category>
     307      struct category_members : forward_members<_Tp>
     308      {
     309        category_members(_Tp& container)
     310  	: forward_members<_Tp>(container)
     311        { };
     312      };
     313  
     314    template<typename _Tp>
     315      struct category_members<_Tp, std::random_access_iterator_tag>
     316      : forward_members<_Tp>
     317      {
     318        category_members(_Tp& container)
     319  	: forward_members<_Tp>(container)
     320        {
     321  	// Make sure that even if rel_ops is injected there is no ambiguity
     322  	// when comparing iterators.
     323  	using namespace std::rel_ops;
     324  
     325  	assert( !(container.begin() < container.begin()) );
     326  	assert( !(container.cbegin() < container.cbegin()) );
     327  	assert( !(container.cbegin() < container.begin()) );
     328  	assert( !(container.begin() < container.cbegin()) );
     329  	assert( container.begin() <= container.begin() );
     330  	assert( container.cbegin() <= container.cbegin() );
     331  	assert( container.cbegin() <= container.begin() );
     332  	assert( container.begin() <= container.cbegin() );
     333  
     334  	assert( !(container.begin() > container.begin()) );
     335  	assert( !(container.cbegin() > container.cbegin()) );
     336  	assert( !(container.cbegin() > container.begin()) );
     337  	assert( !(container.begin() > container.cbegin()) );
     338  	assert( container.begin() >= container.begin() );
     339  	assert( container.cbegin() >= container.cbegin() );
     340  	assert( container.cbegin() >= container.begin() );
     341  	assert( container.begin() >= container.cbegin() );
     342  
     343  	assert( container.begin() - container.begin() == 0 );
     344  	assert( container.cbegin() - container.cbegin() == 0 );
     345  	assert( container.cbegin() - container.begin() == 0 );
     346  	assert( container.begin() - container.cbegin() == 0 );
     347  
     348  	assert( container.begin() + 0 == container.begin() );
     349  	assert( container.cbegin() + 0 == container.cbegin() );
     350  	assert( 0 + container.begin() == container.begin() );
     351  	assert( 0 + container.cbegin() == container.cbegin() );
     352  	assert( container.begin() - 0 == container.begin() );
     353  	assert( container.cbegin() - 0 == container.cbegin() );
     354        }
     355    };
     356  
     357    template<typename _Tp>
     358      struct citerator
     359      {
     360        typedef _Tp 					test_type;
     361        typedef traits<test_type>				traits_type;
     362        typedef typename test_type::value_type 		value_type;
     363  
     364        static test_type _S_container;
     365  
     366        // Unconditional.
     367        struct members : category_members<_Tp>
     368        {
     369  	members() : category_members<_Tp>(_S_container)
     370  	{ }
     371        };
     372  
     373        // Run test.
     374        citerator()
     375        {
     376  	populate<test_type> p(_S_container);
     377  	members m1;
     378  	reverse_members<test_type> m2(_S_container);
     379        }
     380    };
     381  
     382    template<typename _Tp>
     383    _Tp citerator<_Tp>::_S_container;
     384  
     385    // DR 130 vs. C++98 vs. C++11.
     386    // Defined in testsuite_shared.cc.
     387    void
     388    erase_external(std::set<int>& s);
     389  
     390    void
     391    erase_external(std::multiset<int>& s);
     392  
     393    void
     394    erase_external(std::map<int, int>& s);
     395  
     396    void
     397    erase_external(std::multimap<int, int>& s);
     398  
     399    void
     400    erase_external_iterators(std::set<int>& s);
     401  
     402    void
     403    erase_external_iterators(std::multiset<int>& s);
     404  
     405    void
     406    erase_external_iterators(std::map<int, int>& s);
     407  
     408    void
     409    erase_external_iterators(std::multimap<int, int>& s);
     410  
     411  #if __cplusplus < 201103L
     412  # error "must be compiled with C++11 (or later)"
     413  #else
     414  template<typename _Tp>
     415    void
     416    linkage_check_cxx98_cxx11_erase(_Tp& container)
     417    {
     418      // Crashing when external reference and internal reference symbols are
     419      // equivalently mangled but have different size return types in C++98
     420      // and C++11 signatures.
     421      erase_external(container); 		// C++98
     422      container.erase(container.begin());	// C++11
     423    }
     424  
     425  template<typename _Tp>
     426    void
     427    linkage_check_cxx98_cxx11_erase_iterators(_Tp& container)
     428    {
     429      // Crashing when external reference and internal reference symbols are
     430      // equivalently mangled but have different size return types in C++98
     431      // and C++11 signatures.
     432      erase_external_iterators(container);// C++98
     433  
     434      auto iter = container.begin();
     435      container.erase(iter, ++iter);	// C++11
     436    }
     437  #endif
     438  
     439  } // namespace __gnu_test
     440  
     441  #endif