// Debugging support implementation -*- C++ -*-

// Copyright (C) 2003-2018 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file debug/helper_functions.h
 *  This file is a GNU debug extension to the Standard C++ Library.
 */

#ifndef _GLIBCXX_DEBUG_HELPER_FUNCTIONS_H
#define _GLIBCXX_DEBUG_HELPER_FUNCTIONS_H 1

#include <bits/stl_iterator_base_types.h>	// for iterator_traits,
						// categories and _Iter_base
#include <bits/cpp_type_traits.h>		// for __is_integer

#include <bits/stl_pair.h>			// for pair

namespace __gnu_debug
{
  /** The precision to which we can calculate the distance between
   *  two iterators.
   */
  enum _Distance_precision
    {
      __dp_none,	// Not even an iterator type
      __dp_equality,	//< Can compare iterator equality, only
      __dp_sign,	//< Can determine equality and ordering
      __dp_exact	//< Can determine distance precisely
    };

  template<typename _Iterator,
	   typename = typename std::__is_integer<_Iterator>::__type>
    struct _Distance_traits
    {
    private:
      typedef
      typename std::iterator_traits<_Iterator>::difference_type _ItDiffType;

      template<typename _DiffType,
	       typename = typename std::__is_void<_DiffType>::__type>
	struct _DiffTraits
	{ typedef _DiffType __type; };

      template<typename _DiffType>
	struct _DiffTraits<_DiffType, std::__true_type>
	{ typedef std::ptrdiff_t __type; };

      typedef typename _DiffTraits<_ItDiffType>::__type _DiffType;

    public:
      typedef std::pair<_DiffType, _Distance_precision> __type;
    };

  template<typename _Integral>
    struct _Distance_traits<_Integral, std::__true_type>
    { typedef std::pair<std::ptrdiff_t, _Distance_precision> __type; };

  /** Determine the distance between two iterators with some known
   *	precision.
  */
  template<typename _Iterator>
    inline typename _Distance_traits<_Iterator>::__type
    __get_distance(const _Iterator& __lhs, const _Iterator& __rhs,
		   std::random_access_iterator_tag)
    { return std::make_pair(__rhs - __lhs, __dp_exact); }

  template<typename _Iterator>
    inline typename _Distance_traits<_Iterator>::__type
    __get_distance(const _Iterator& __lhs, const _Iterator& __rhs,
		   std::input_iterator_tag)
    {
      if (__lhs == __rhs)
	return std::make_pair(0, __dp_exact);

      return std::make_pair(1, __dp_equality);
    }

  template<typename _Iterator>
    inline typename _Distance_traits<_Iterator>::__type
    __get_distance(const _Iterator& __lhs, const _Iterator& __rhs)
    { return __get_distance(__lhs, __rhs, std::__iterator_category(__lhs)); }

  /** We say that integral types for a valid range, and defer to other
   *  routines to realize what to do with integral types instead of
   *  iterators.
  */
  template<typename _Integral>
    inline bool
    __valid_range_aux(const _Integral&, const _Integral&,
		      typename _Distance_traits<_Integral>::__type& __dist,
		      std::__true_type)
    {
      __dist = std::make_pair(0, __dp_none);
      return true;
    }

  /** We have iterators, so figure out what kind of iterators that are
   *  to see if we can check the range ahead of time.
  */
  template<typename _InputIterator>
    inline bool
    __valid_range_aux(const _InputIterator& __first,
		      const _InputIterator& __last,
		      typename _Distance_traits<_InputIterator>::__type& __dist,
		      std::__false_type)
    {
      __dist = __get_distance(__first, __last);
      switch (__dist.second)
	{
	case __dp_none:
	  break;
	case __dp_equality:
	  if (__dist.first == 0)
	    return true;
	  break;
	case __dp_sign:
	case __dp_exact:
	  return __dist.first >= 0;
	}

      // Can't tell so assume it is fine.
      return true;
    }

  /** Don't know what these iterators are, or if they are even
   *  iterators (we may get an integral type for InputIterator), so
   *  see if they are integral and pass them on to the next phase
   *  otherwise.
  */
  template<typename _InputIterator>
    inline bool
    __valid_range(const _InputIterator& __first, const _InputIterator& __last,
		  typename _Distance_traits<_InputIterator>::__type& __dist)
    {
      typedef typename std::__is_integer<_InputIterator>::__type _Integral;
      return __valid_range_aux(__first, __last, __dist, _Integral());
    }

  template<typename _InputIterator>
    inline bool
    __valid_range(const _InputIterator& __first, const _InputIterator& __last)
    {
      typename _Distance_traits<_InputIterator>::__type __dist;
      return __valid_range(__first, __last, __dist);
    }

#if __cplusplus < 201103L
  // Helper struct to detect random access safe iterators.
  template<typename _Iterator>
    struct __is_safe_random_iterator
    {
      enum { __value = 0 };
      typedef std::__false_type __type;
    };

  template<typename _Iterator>
    struct _Siter_base
    : std::_Iter_base<_Iterator, __is_safe_random_iterator<_Iterator>::__value>
    { };

  /** Helper function to extract base iterator of random access safe iterator
      in order to reduce performance impact of debug mode.  Limited to random
      access iterator because it is the only category for which it is possible
      to check for correct iterators order in the __valid_range function
      thanks to the < operator.
  */
  template<typename _Iterator>
    inline typename _Siter_base<_Iterator>::iterator_type
    __base(_Iterator __it)
    { return _Siter_base<_Iterator>::_S_base(__it); }
#else
  template<typename _Iterator>
    inline _Iterator
    __base(_Iterator __it)
    { return __it; }
#endif

#if __cplusplus < 201103L
  template<typename _Iterator>
    struct _Unsafe_type
    { typedef _Iterator _Type; };
#endif

  /* Remove debug mode safe iterator layer, if any. */
  template<typename _Iterator>
    inline _Iterator
    __unsafe(_Iterator __it)
    { return __it; }
}

#endif
