Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. // Debugging vector implementation -*- C++ -*-
  2.  
  3. // Copyright (C) 2003-2013 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/vector
  26.  *  This file is a GNU debug extension to the Standard C++ Library.
  27.  */
  28.  
  29. #ifndef _GLIBCXX_DEBUG_VECTOR
  30. #define _GLIBCXX_DEBUG_VECTOR 1
  31.  
  32. #include <vector>
  33. #include <utility>
  34. #include <debug/safe_sequence.h>
  35. #include <debug/safe_iterator.h>
  36.  
  37. namespace std _GLIBCXX_VISIBILITY(default)
  38. {
  39. namespace __debug
  40. {
  41.   /// Class std::vector with safety/checking/debug instrumentation.
  42.   template<typename _Tp,
  43.            typename _Allocator = std::allocator<_Tp> >
  44.     class vector
  45.     : public _GLIBCXX_STD_C::vector<_Tp, _Allocator>,
  46.       public __gnu_debug::_Safe_sequence<vector<_Tp, _Allocator> >
  47.     {
  48.       typedef _GLIBCXX_STD_C::vector<_Tp, _Allocator> _Base;
  49.  
  50.       typedef typename _Base::iterator _Base_iterator;
  51.       typedef typename _Base::const_iterator _Base_const_iterator;
  52.       typedef __gnu_debug::_Equal_to<_Base_const_iterator> _Equal;
  53.  
  54. #if __cplusplus >= 201103L
  55.       typedef __gnu_cxx::__alloc_traits<_Allocator>  _Alloc_traits;
  56. #endif
  57.  
  58.     public:
  59.       typedef typename _Base::reference             reference;
  60.       typedef typename _Base::const_reference       const_reference;
  61.  
  62.       typedef __gnu_debug::_Safe_iterator<_Base_iterator,vector>
  63.       iterator;
  64.       typedef __gnu_debug::_Safe_iterator<_Base_const_iterator,vector>
  65.       const_iterator;
  66.  
  67.       typedef typename _Base::size_type             size_type;
  68.       typedef typename _Base::difference_type       difference_type;
  69.  
  70.       typedef _Tp                                   value_type;
  71.       typedef _Allocator                            allocator_type;
  72.       typedef typename _Base::pointer               pointer;
  73.       typedef typename _Base::const_pointer         const_pointer;
  74.       typedef std::reverse_iterator<iterator>       reverse_iterator;
  75.       typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  76.  
  77.       // 23.2.4.1 construct/copy/destroy:
  78.       explicit
  79.       vector(const _Allocator& __a = _Allocator())
  80.       : _Base(__a), _M_guaranteed_capacity(0) { }
  81.  
  82. #if __cplusplus >= 201103L
  83.       explicit
  84.       vector(size_type __n, const _Allocator& __a = _Allocator())
  85.       : _Base(__n, __a), _M_guaranteed_capacity(__n) { }
  86.  
  87.       vector(size_type __n, const _Tp& __value,
  88.              const _Allocator& __a = _Allocator())
  89.       : _Base(__n, __value, __a), _M_guaranteed_capacity(__n) { }
  90. #else
  91.       explicit
  92.       vector(size_type __n, const _Tp& __value = _Tp(),
  93.              const _Allocator& __a = _Allocator())
  94.       : _Base(__n, __value, __a), _M_guaranteed_capacity(__n) { }
  95. #endif
  96.  
  97. #if __cplusplus >= 201103L
  98.       template<class _InputIterator,
  99.                typename = std::_RequireInputIter<_InputIterator>>
  100. #else
  101.       template<class _InputIterator>
  102. #endif
  103.         vector(_InputIterator __first, _InputIterator __last,
  104.                const _Allocator& __a = _Allocator())
  105.         : _Base(__gnu_debug::__base(__gnu_debug::__check_valid_range(__first,
  106.                                                                      __last)),
  107.                 __gnu_debug::__base(__last), __a),
  108.           _M_guaranteed_capacity(0)
  109.         { _M_update_guaranteed_capacity(); }
  110.  
  111.       vector(const vector& __x)
  112.       : _Base(__x), _M_guaranteed_capacity(__x.size()) { }
  113.  
  114.       /// Construction from a release-mode vector
  115.       vector(const _Base& __x)
  116.       : _Base(__x), _M_guaranteed_capacity(__x.size()) { }
  117.  
  118. #if __cplusplus >= 201103L
  119.       vector(vector&& __x) noexcept
  120.       : _Base(std::move(__x)),
  121.         _M_guaranteed_capacity(this->size())
  122.       {
  123.         this->_M_swap(__x);
  124.         __x._M_guaranteed_capacity = 0;
  125.       }
  126.  
  127.       vector(const vector& __x, const allocator_type& __a)
  128.       : _Base(__x, __a), _M_guaranteed_capacity(__x.size()) { }
  129.  
  130.       vector(vector&& __x, const allocator_type& __a)
  131.       : _Base(std::move(__x), __a),
  132.         _M_guaranteed_capacity(this->size())
  133.       {
  134.         __x._M_invalidate_all();
  135.         __x._M_guaranteed_capacity = 0;
  136.       }
  137.  
  138.       vector(initializer_list<value_type> __l,
  139.              const allocator_type& __a = allocator_type())
  140.       : _Base(__l, __a),
  141.         _M_guaranteed_capacity(__l.size()) { }
  142. #endif
  143.  
  144.       ~vector() _GLIBCXX_NOEXCEPT { }
  145.  
  146.       vector&
  147.       operator=(const vector& __x)
  148.       {
  149.         static_cast<_Base&>(*this) = __x;
  150.         this->_M_invalidate_all();
  151.         _M_update_guaranteed_capacity();
  152.         return *this;
  153.       }
  154.  
  155. #if __cplusplus >= 201103L
  156.       vector&
  157.       operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
  158.       {
  159.         __glibcxx_check_self_move_assign(__x);
  160.         _Base::operator=(std::move(__x));
  161.         this->_M_invalidate_all();
  162.         _M_update_guaranteed_capacity();
  163.         __x._M_invalidate_all();
  164.         __x._M_guaranteed_capacity = 0;
  165.         return *this;
  166.       }
  167.  
  168.       vector&
  169.       operator=(initializer_list<value_type> __l)
  170.       {
  171.         static_cast<_Base&>(*this) = __l;
  172.         this->_M_invalidate_all();
  173.         _M_update_guaranteed_capacity();
  174.         return *this;
  175.       }
  176. #endif
  177.  
  178. #if __cplusplus >= 201103L
  179.       template<typename _InputIterator,
  180.                typename = std::_RequireInputIter<_InputIterator>>
  181. #else
  182.       template<typename _InputIterator>
  183. #endif
  184.         void
  185.         assign(_InputIterator __first, _InputIterator __last)
  186.         {
  187.           __glibcxx_check_valid_range(__first, __last);
  188.           _Base::assign(__gnu_debug::__base(__first),
  189.                         __gnu_debug::__base(__last));
  190.           this->_M_invalidate_all();
  191.           _M_update_guaranteed_capacity();
  192.         }
  193.  
  194.       void
  195.       assign(size_type __n, const _Tp& __u)
  196.       {
  197.         _Base::assign(__n, __u);
  198.         this->_M_invalidate_all();
  199.         _M_update_guaranteed_capacity();
  200.       }
  201.  
  202. #if __cplusplus >= 201103L
  203.       void
  204.       assign(initializer_list<value_type> __l)
  205.       {
  206.         _Base::assign(__l);
  207.         this->_M_invalidate_all();
  208.         _M_update_guaranteed_capacity();
  209.       }
  210. #endif
  211.  
  212.       using _Base::get_allocator;
  213.  
  214.       // iterators:
  215.       iterator
  216.       begin() _GLIBCXX_NOEXCEPT
  217.       { return iterator(_Base::begin(), this); }
  218.  
  219.       const_iterator
  220.       begin() const _GLIBCXX_NOEXCEPT
  221.       { return const_iterator(_Base::begin(), this); }
  222.  
  223.       iterator
  224.       end() _GLIBCXX_NOEXCEPT
  225.       { return iterator(_Base::end(), this); }
  226.  
  227.       const_iterator
  228.       end() const _GLIBCXX_NOEXCEPT
  229.       { return const_iterator(_Base::end(), this); }
  230.  
  231.       reverse_iterator
  232.       rbegin() _GLIBCXX_NOEXCEPT
  233.       { return reverse_iterator(end()); }
  234.  
  235.       const_reverse_iterator
  236.       rbegin() const _GLIBCXX_NOEXCEPT
  237.       { return const_reverse_iterator(end()); }
  238.  
  239.       reverse_iterator
  240.       rend() _GLIBCXX_NOEXCEPT
  241.       { return reverse_iterator(begin()); }
  242.  
  243.       const_reverse_iterator
  244.       rend() const _GLIBCXX_NOEXCEPT
  245.       { return const_reverse_iterator(begin()); }
  246.  
  247. #if __cplusplus >= 201103L
  248.       const_iterator
  249.       cbegin() const noexcept
  250.       { return const_iterator(_Base::begin(), this); }
  251.  
  252.       const_iterator
  253.       cend() const noexcept
  254.       { return const_iterator(_Base::end(), this); }
  255.  
  256.       const_reverse_iterator
  257.       crbegin() const noexcept
  258.       { return const_reverse_iterator(end()); }
  259.  
  260.       const_reverse_iterator
  261.       crend() const noexcept
  262.       { return const_reverse_iterator(begin()); }
  263. #endif
  264.  
  265.       // 23.2.4.2 capacity:
  266.       using _Base::size;
  267.       using _Base::max_size;
  268.  
  269. #if __cplusplus >= 201103L
  270.       void
  271.       resize(size_type __sz)
  272.       {
  273.         bool __realloc = _M_requires_reallocation(__sz);
  274.         if (__sz < this->size())
  275.           this->_M_invalidate_after_nth(__sz);
  276.         _Base::resize(__sz);
  277.         if (__realloc)
  278.           this->_M_invalidate_all();
  279.         _M_update_guaranteed_capacity();
  280.       }
  281.  
  282.       void
  283.       resize(size_type __sz, const _Tp& __c)
  284.       {
  285.         bool __realloc = _M_requires_reallocation(__sz);
  286.         if (__sz < this->size())
  287.           this->_M_invalidate_after_nth(__sz);
  288.         _Base::resize(__sz, __c);
  289.         if (__realloc)
  290.           this->_M_invalidate_all();
  291.         _M_update_guaranteed_capacity();
  292.       }
  293. #else
  294.       void
  295.       resize(size_type __sz, _Tp __c = _Tp())
  296.       {
  297.         bool __realloc = _M_requires_reallocation(__sz);
  298.         if (__sz < this->size())
  299.           this->_M_invalidate_after_nth(__sz);
  300.         _Base::resize(__sz, __c);
  301.         if (__realloc)
  302.           this->_M_invalidate_all();
  303.         _M_update_guaranteed_capacity();
  304.       }
  305. #endif
  306.  
  307. #if __cplusplus >= 201103L
  308.       void
  309.       shrink_to_fit()
  310.       {
  311.         if (_Base::_M_shrink_to_fit())
  312.           {
  313.             _M_guaranteed_capacity = _Base::capacity();
  314.             this->_M_invalidate_all();
  315.           }
  316.       }
  317. #endif
  318.  
  319.       size_type
  320.       capacity() const _GLIBCXX_NOEXCEPT
  321.       {
  322. #ifdef _GLIBCXX_DEBUG_PEDANTIC
  323.         return _M_guaranteed_capacity;
  324. #else
  325.         return _Base::capacity();
  326. #endif
  327.       }
  328.  
  329.       using _Base::empty;
  330.  
  331.       void
  332.       reserve(size_type __n)
  333.       {
  334.         bool __realloc = _M_requires_reallocation(__n);
  335.         _Base::reserve(__n);
  336.         if (__n > _M_guaranteed_capacity)
  337.           _M_guaranteed_capacity = __n;
  338.         if (__realloc)
  339.           this->_M_invalidate_all();
  340.       }
  341.  
  342.       // element access:
  343.       reference
  344.       operator[](size_type __n)
  345.       {
  346.         __glibcxx_check_subscript(__n);
  347.         return _M_base()[__n];
  348.       }
  349.  
  350.       const_reference
  351.       operator[](size_type __n) const
  352.       {
  353.         __glibcxx_check_subscript(__n);
  354.         return _M_base()[__n];
  355.       }
  356.  
  357.       using _Base::at;
  358.  
  359.       reference
  360.       front()
  361.       {
  362.         __glibcxx_check_nonempty();
  363.         return _Base::front();
  364.       }
  365.  
  366.       const_reference
  367.       front() const
  368.       {
  369.         __glibcxx_check_nonempty();
  370.         return _Base::front();
  371.       }
  372.  
  373.       reference
  374.       back()
  375.       {
  376.         __glibcxx_check_nonempty();
  377.         return _Base::back();
  378.       }
  379.  
  380.       const_reference
  381.       back() const
  382.       {
  383.         __glibcxx_check_nonempty();
  384.         return _Base::back();
  385.       }
  386.  
  387.       // _GLIBCXX_RESOLVE_LIB_DEFECTS
  388.       // DR 464. Suggestion for new member functions in standard containers.
  389.       using _Base::data;
  390.  
  391.       // 23.2.4.3 modifiers:
  392.       void
  393.       push_back(const _Tp& __x)
  394.       {
  395.         bool __realloc = _M_requires_reallocation(this->size() + 1);
  396.         _Base::push_back(__x);
  397.         if (__realloc)
  398.           this->_M_invalidate_all();
  399.         _M_update_guaranteed_capacity();
  400.       }
  401.  
  402. #if __cplusplus >= 201103L
  403.       template<typename _Up = _Tp>
  404.         typename __gnu_cxx::__enable_if<!std::__are_same<_Up, bool>::__value,
  405.                                         void>::__type
  406.         push_back(_Tp&& __x)
  407.         { emplace_back(std::move(__x)); }
  408.  
  409.       template<typename... _Args>
  410.         void
  411.         emplace_back(_Args&&... __args)
  412.         {
  413.           bool __realloc = _M_requires_reallocation(this->size() + 1);
  414.           _Base::emplace_back(std::forward<_Args>(__args)...);
  415.           if (__realloc)
  416.             this->_M_invalidate_all();
  417.           _M_update_guaranteed_capacity();
  418.         }
  419. #endif
  420.  
  421.       void
  422.       pop_back()
  423.       {
  424.         __glibcxx_check_nonempty();
  425.         this->_M_invalidate_if(_Equal(--_Base::end()));
  426.         _Base::pop_back();
  427.       }
  428.  
  429. #if __cplusplus >= 201103L
  430.       template<typename... _Args>
  431.         iterator
  432.         emplace(iterator __position, _Args&&... __args)
  433.         {
  434.           __glibcxx_check_insert(__position);
  435.           bool __realloc = _M_requires_reallocation(this->size() + 1);
  436.           difference_type __offset = __position.base() - _Base::begin();
  437.           _Base_iterator __res = _Base::emplace(__position.base(),
  438.                                                 std::forward<_Args>(__args)...);
  439.           if (__realloc)
  440.             this->_M_invalidate_all();
  441.           else
  442.             this->_M_invalidate_after_nth(__offset);
  443.           _M_update_guaranteed_capacity();
  444.           return iterator(__res, this);
  445.         }
  446. #endif
  447.  
  448.       iterator
  449.       insert(iterator __position, const _Tp& __x)
  450.       {
  451.         __glibcxx_check_insert(__position);
  452.         bool __realloc = _M_requires_reallocation(this->size() + 1);
  453.         difference_type __offset = __position.base() - _Base::begin();
  454.         _Base_iterator __res = _Base::insert(__position.base(), __x);
  455.         if (__realloc)
  456.           this->_M_invalidate_all();
  457.         else
  458.           this->_M_invalidate_after_nth(__offset);
  459.         _M_update_guaranteed_capacity();
  460.         return iterator(__res, this);
  461.       }
  462.  
  463. #if __cplusplus >= 201103L
  464.       template<typename _Up = _Tp>
  465.         typename __gnu_cxx::__enable_if<!std::__are_same<_Up, bool>::__value,
  466.                                         iterator>::__type
  467.         insert(iterator __position, _Tp&& __x)
  468.         { return emplace(__position, std::move(__x)); }
  469.  
  470.       void
  471.       insert(iterator __position, initializer_list<value_type> __l)
  472.       { this->insert(__position, __l.begin(), __l.end()); }
  473. #endif
  474.  
  475.       void
  476.       insert(iterator __position, size_type __n, const _Tp& __x)
  477.       {
  478.         __glibcxx_check_insert(__position);
  479.         bool __realloc = _M_requires_reallocation(this->size() + __n);
  480.         difference_type __offset = __position.base() - _Base::begin();
  481.         _Base::insert(__position.base(), __n, __x);
  482.         if (__realloc)
  483.           this->_M_invalidate_all();
  484.         else
  485.           this->_M_invalidate_after_nth(__offset);
  486.         _M_update_guaranteed_capacity();
  487.       }
  488.  
  489. #if __cplusplus >= 201103L
  490.       template<class _InputIterator,
  491.                typename = std::_RequireInputIter<_InputIterator>>
  492. #else
  493.       template<class _InputIterator>
  494. #endif
  495.         void
  496.         insert(iterator __position,
  497.                _InputIterator __first, _InputIterator __last)
  498.         {
  499.           __glibcxx_check_insert_range(__position, __first, __last);
  500.  
  501.           /* Hard to guess if invalidation will occur, because __last
  502.              - __first can't be calculated in all cases, so we just
  503.              punt here by checking if it did occur. */
  504.           _Base_iterator __old_begin = _M_base().begin();
  505.           difference_type __offset = __position.base() - _Base::begin();
  506.           _Base::insert(__position.base(), __gnu_debug::__base(__first),
  507.                                            __gnu_debug::__base(__last));
  508.  
  509.           if (_M_base().begin() != __old_begin)
  510.             this->_M_invalidate_all();
  511.           else
  512.             this->_M_invalidate_after_nth(__offset);
  513.           _M_update_guaranteed_capacity();
  514.         }
  515.  
  516.       iterator
  517.       erase(iterator __position)
  518.       {
  519.         __glibcxx_check_erase(__position);
  520.         difference_type __offset = __position.base() - _Base::begin();
  521.         _Base_iterator __res = _Base::erase(__position.base());
  522.         this->_M_invalidate_after_nth(__offset);
  523.         return iterator(__res, this);
  524.       }
  525.  
  526.       iterator
  527.       erase(iterator __first, iterator __last)
  528.       {
  529.         // _GLIBCXX_RESOLVE_LIB_DEFECTS
  530.         // 151. can't currently clear() empty container
  531.         __glibcxx_check_erase_range(__first, __last);
  532.  
  533.         if (__first.base() != __last.base())
  534.           {
  535.             difference_type __offset = __first.base() - _Base::begin();
  536.             _Base_iterator __res = _Base::erase(__first.base(),
  537.                                                 __last.base());
  538.             this->_M_invalidate_after_nth(__offset);
  539.             return iterator(__res, this);
  540.           }
  541.         else
  542.           return __first;
  543.       }
  544.  
  545.       void
  546.       swap(vector& __x)
  547. #if __cplusplus >= 201103L
  548.                         noexcept(_Alloc_traits::_S_nothrow_swap())
  549. #endif
  550.       {
  551. #if __cplusplus >= 201103L
  552.         if (!_Alloc_traits::_S_propagate_on_swap())
  553.           __glibcxx_check_equal_allocs(__x);
  554. #endif
  555.         _Base::swap(__x);
  556.         this->_M_swap(__x);
  557.         std::swap(_M_guaranteed_capacity, __x._M_guaranteed_capacity);
  558.       }
  559.  
  560.       void
  561.       clear() _GLIBCXX_NOEXCEPT
  562.       {
  563.         _Base::clear();
  564.         this->_M_invalidate_all();
  565.         _M_guaranteed_capacity = 0;
  566.       }
  567.  
  568.       _Base&
  569.       _M_base() _GLIBCXX_NOEXCEPT { return *this; }
  570.  
  571.       const _Base&
  572.       _M_base() const _GLIBCXX_NOEXCEPT { return *this; }
  573.  
  574.     private:
  575.       size_type _M_guaranteed_capacity;
  576.  
  577.       bool
  578.       _M_requires_reallocation(size_type __elements)
  579.       { return __elements > this->capacity(); }
  580.  
  581.       void
  582.       _M_update_guaranteed_capacity()
  583.       {
  584.         if (this->size() > _M_guaranteed_capacity)
  585.           _M_guaranteed_capacity = this->size();
  586.       }
  587.  
  588.       void
  589.       _M_invalidate_after_nth(difference_type __n)
  590.       {
  591.         typedef __gnu_debug::_After_nth_from<_Base_const_iterator> _After_nth;
  592.         this->_M_invalidate_if(_After_nth(__n, _Base::begin()));
  593.       }
  594.     };
  595.  
  596.   template<typename _Tp, typename _Alloc>
  597.     inline bool
  598.     operator==(const vector<_Tp, _Alloc>& __lhs,
  599.                const vector<_Tp, _Alloc>& __rhs)
  600.     { return __lhs._M_base() == __rhs._M_base(); }
  601.  
  602.   template<typename _Tp, typename _Alloc>
  603.     inline bool
  604.     operator!=(const vector<_Tp, _Alloc>& __lhs,
  605.                const vector<_Tp, _Alloc>& __rhs)
  606.     { return __lhs._M_base() != __rhs._M_base(); }
  607.  
  608.   template<typename _Tp, typename _Alloc>
  609.     inline bool
  610.     operator<(const vector<_Tp, _Alloc>& __lhs,
  611.               const vector<_Tp, _Alloc>& __rhs)
  612.     { return __lhs._M_base() < __rhs._M_base(); }
  613.  
  614.   template<typename _Tp, typename _Alloc>
  615.     inline bool
  616.     operator<=(const vector<_Tp, _Alloc>& __lhs,
  617.                const vector<_Tp, _Alloc>& __rhs)
  618.     { return __lhs._M_base() <= __rhs._M_base(); }
  619.  
  620.   template<typename _Tp, typename _Alloc>
  621.     inline bool
  622.     operator>=(const vector<_Tp, _Alloc>& __lhs,
  623.                const vector<_Tp, _Alloc>& __rhs)
  624.     { return __lhs._M_base() >= __rhs._M_base(); }
  625.  
  626.   template<typename _Tp, typename _Alloc>
  627.     inline bool
  628.     operator>(const vector<_Tp, _Alloc>& __lhs,
  629.               const vector<_Tp, _Alloc>& __rhs)
  630.     { return __lhs._M_base() > __rhs._M_base(); }
  631.  
  632.   template<typename _Tp, typename _Alloc>
  633.     inline void
  634.     swap(vector<_Tp, _Alloc>& __lhs, vector<_Tp, _Alloc>& __rhs)
  635.     { __lhs.swap(__rhs); }
  636.  
  637. } // namespace __debug
  638.  
  639. #if __cplusplus >= 201103L
  640.   // DR 1182.
  641.   /// std::hash specialization for vector<bool>.
  642.   template<typename _Alloc>
  643.     struct hash<__debug::vector<bool, _Alloc>>
  644.     : public __hash_base<size_t, __debug::vector<bool, _Alloc>>
  645.     {
  646.       size_t
  647.       operator()(const __debug::vector<bool, _Alloc>& __b) const noexcept
  648.       { return std::hash<_GLIBCXX_STD_C::vector<bool, _Alloc>>()
  649.           (__b._M_base()); }
  650.     };
  651. #endif
  652.  
  653. } // namespace std
  654.  
  655. #endif
  656.