1  // Safe container implementation  -*- C++ -*-
       2  
       3  // Copyright (C) 2014-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
       7  // terms of the GNU General Public License as published by the
       8  // Free Software Foundation; either version 3, or (at your option)
       9  // any later version.
      10  
      11  // This library is distributed in the hope that it will be useful,
      12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14  // GNU General Public License for more details.
      15  
      16  // Under Section 7 of GPL version 3, you are granted additional
      17  // permissions described in the GCC Runtime Library Exception, version
      18  // 3.1, as published by the Free Software Foundation.
      19  
      20  // You should have received a copy of the GNU General Public License and
      21  // a copy of the GCC Runtime Library Exception along with this program;
      22  // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
      23  // <http://www.gnu.org/licenses/>.
      24  
      25  /** @file debug/safe_container.h
      26   *  This file is a GNU debug extension to the Standard C++ Library.
      27   */
      28  
      29  #ifndef _GLIBCXX_DEBUG_SAFE_CONTAINER_H
      30  #define _GLIBCXX_DEBUG_SAFE_CONTAINER_H 1
      31  
      32  #include <ext/alloc_traits.h>
      33  
      34  namespace __gnu_debug
      35  {
      36    /// Safe class dealing with some allocator dependent operations.
      37    template<typename _SafeContainer,
      38  	   typename _Alloc,
      39  	   template<typename> class _SafeBase,
      40  	   bool _IsCxx11AllocatorAware = true>
      41      class _Safe_container
      42      : public _SafeBase<_SafeContainer>
      43      {
      44        typedef _SafeBase<_SafeContainer> _Base;
      45  
      46        _SafeContainer&
      47        _M_cont() _GLIBCXX_NOEXCEPT
      48        { return *static_cast<_SafeContainer*>(this); }
      49  
      50      protected:
      51  #if __cplusplus >= 201103L
      52        _Safe_container() = default;
      53        _Safe_container(const _Safe_container&) = default;
      54        _Safe_container(_Safe_container&&) = default;
      55  
      56      private:
      57        _Safe_container(_Safe_container&& __x, const _Alloc&, std::true_type)
      58        : _Safe_container(std::move(__x))
      59        { }
      60  
      61        _Safe_container(_Safe_container&& __x, const _Alloc& __a, std::false_type)
      62        : _Safe_container()
      63        {
      64  	if (__x._M_cont().get_allocator() == __a)
      65  	  _Base::_M_swap(__x);
      66  	else
      67  	  __x._M_invalidate_all();
      68        }
      69  
      70      protected:
      71        _Safe_container(_Safe_container&& __x, const _Alloc& __a)
      72        : _Safe_container(std::move(__x), __a,
      73  		      typename std::allocator_traits<_Alloc>::is_always_equal{})
      74        { }
      75  #endif
      76  
      77        // Copy assignment invalidate all iterators.
      78        _Safe_container&
      79        operator=(const _Safe_container&) _GLIBCXX_NOEXCEPT
      80        {
      81  	this->_M_invalidate_all();
      82  	return *this;
      83        }
      84  
      85  #if __cplusplus >= 201103L
      86        _Safe_container&
      87        operator=(_Safe_container&& __x) noexcept
      88        {
      89  	if (std::__addressof(__x) == this)
      90  	  {
      91  	    // Standard containers have a valid but unspecified value after
      92  	    // self-move, so we invalidate all debug iterators even if the
      93  	    // underlying container happens to preserve its contents.
      94  	    this->_M_invalidate_all();
      95  	    return *this;
      96  	  }
      97  
      98  	if (_IsCxx11AllocatorAware)
      99  	  {
     100  	    typedef __gnu_cxx::__alloc_traits<_Alloc> _Alloc_traits;
     101  
     102  	    bool __xfer_memory = _Alloc_traits::_S_propagate_on_move_assign()
     103  	      || _M_cont().get_allocator() == __x._M_cont().get_allocator();
     104  	    if (__xfer_memory)
     105  	      _Base::_M_swap(__x);
     106  	    else
     107  	      this->_M_invalidate_all();
     108  	  }
     109  	else
     110  	  _Base::_M_swap(__x);
     111  
     112  	__x._M_invalidate_all();
     113  	return *this;
     114        }
     115  
     116        void
     117        _M_swap(_Safe_container& __x) noexcept
     118        {
     119  	if (_IsCxx11AllocatorAware)
     120  	  {
     121  	    typedef __gnu_cxx::__alloc_traits<_Alloc> _Alloc_traits;
     122  
     123  	    if (!_Alloc_traits::_S_propagate_on_swap())
     124  	      __glibcxx_check_equal_allocs(this->_M_cont()._M_base(),
     125  					   __x._M_cont()._M_base());
     126  	  }
     127  
     128  	_Base::_M_swap(__x);
     129        }
     130  #endif
     131      };
     132  
     133  } // namespace __gnu_debug
     134  
     135  #endif