//  Integer types, largely based on boost integer.hpp header file
//
// Copyright Beman Dawes and Daryle Walker 1999.  Distributed under
// the Boost Software License, Version 1.0.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
//  -------------------------------------------//
//
//  Changes compared to original boost version:
//   - Assume long long exists
//   - Remove BORLANDC workaround
//   - Don't rely on std::numerical_limits<>::digits, but just use
//     sizeof
//   - Remove static asserts (since they relied on boost::uintmax_t and
//     boost::intmax_t)
//   - Remove #pragma GCC system_header
//   - Remove the int_max_value_t, int_min_value_t and uint_value_t
//     types, since they rely on boost::integer_traits (which again uses
//     <limits.h>, which avr doesn't have
//   - Remove exact_*_base_helper specializations for short, since that
//     is the same as int on avr (and values from limits.h are not
//     available to automatically do this).
//   - Replace CHAR_BIT by 8

#ifndef BOOST_INTEGER_HPP
#define BOOST_INTEGER_HPP

namespace boost
{

  //  Helper templates  ------------------------------------------------------//

  namespace detail
  {

  // convert category to type
  template< int Category > struct int_least_helper {}; // default is empty
  template< int Category > struct uint_least_helper {}; // default is empty

  template<> struct int_least_helper<1> { typedef long long least; };
  template<> struct int_least_helper<2> { typedef long least; };
  template<> struct int_least_helper<3> { typedef int least; };
  template<> struct int_least_helper<4> { typedef short least; };
  template<> struct int_least_helper<5> { typedef signed char least; };
  template<> struct uint_least_helper<1> { typedef unsigned long long least; };
  template<> struct uint_least_helper<2> { typedef unsigned long least; };
  template<> struct uint_least_helper<3> { typedef unsigned int least; };
  template<> struct uint_least_helper<4> { typedef unsigned short least; };
  template<> struct uint_least_helper<5> { typedef unsigned char least; };

  template <int Bits>
  struct exact_signed_base_helper{};
  template <int Bits>
  struct exact_unsigned_base_helper{};

  template <> struct exact_signed_base_helper<sizeof(signed char)* 8> { typedef signed char exact; };
  template <> struct exact_unsigned_base_helper<sizeof(unsigned char)* 8> { typedef unsigned char exact; };
  template <> struct exact_signed_base_helper<sizeof(int)* 8> { typedef int exact; };
  template <> struct exact_unsigned_base_helper<sizeof(unsigned int)* 8> { typedef unsigned int exact; };
  template <> struct exact_signed_base_helper<sizeof(long)* 8> { typedef long exact; };
  template <> struct exact_unsigned_base_helper<sizeof(unsigned long)* 8> { typedef unsigned long exact; };
  template <> struct exact_signed_base_helper<sizeof(long long)* 8> { typedef long long exact; };
  template <> struct exact_unsigned_base_helper<sizeof(unsigned long long)* 8> { typedef unsigned long long exact; };


  } // namespace detail

  //  integer templates specifying number of bits  ---------------------------//

  //  signed
  template< int Bits >   // bits (including sign) required
  struct int_t : public detail::exact_signed_base_helper<Bits>
  {
      typedef typename detail::int_least_helper
        <
          (Bits <= sizeof(long long) * 8) +
          (Bits <= sizeof(long) * 8) +
          (Bits <= sizeof(int) * 8) +
          (Bits <= sizeof(short) * 8) +
          (Bits <= sizeof(signed char) * 8)
        >::least  least;
  };

  //  unsigned
  template< int Bits >   // bits required
  struct uint_t : public detail::exact_unsigned_base_helper<Bits>
  {
      typedef typename detail::uint_least_helper
        <
          (Bits <= sizeof(unsigned long long) * 8) +
          (Bits <= sizeof(unsigned long) * 8) +
          (Bits <= sizeof(unsigned int) * 8) +
          (Bits <= sizeof(unsigned short) * 8) +
          (Bits <= sizeof(unsigned char) * 8)
        >::least  least;
  };

} // namespace boost

#endif // BOOST_INTEGER_HPP
