#include <strconv_numeric.h>
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN

#include <boost/test/unit_test.hpp>
#include <ctime>

using namespace std::literals::string_view_literals;

namespace strconcept_tests
  {
  constexpr bool test_0()
    {
    using type = std::vector<uint32_t>;
    return std::is_same_v<uint32_t, strconcept::iterator_value_type_t<type::iterator>>;
    }
    static_assert(test_0());

//   namespace test_1
//     {
//     using type = std::back_insert_iterator<std::vector<uint32_t>>;
//     static_assert( std::is_same_v<uint32_t, strconcept::iterator_value_type_t<type::iterator>>);
//     }
//
  }

namespace strconv_value_to_hex
  {
  static_assert( strconv::value_to_hex(uint8_t(0)) == '0' );
  static_assert( strconv::value_to_hex(uint8_t(5)) == '5' );
  static_assert( strconv::value_to_hex(uint8_t(15)) == 'F' );
  }

namespace from_hex_ascii_test
{
   constexpr bool test_1()
    {
    constexpr auto input = "ff1a34b5f30027"sv;
    uint8_t res[7]{};
    strconv::from_hex_ascii( std::begin(input), std::end(input),  std::begin(res) );
    constexpr std::array<uint8_t,7> expected { {0xff,0x1a,0x34,0xb5,0xf3,0x00,0x27} };
    return stralgo::detail::equal( expected.begin(), expected.end(), &res[0] );
    }

  static_assert( test_1() );
}

namespace strconv_to_hex_ascii
{
  constexpr bool test_1()
      {
      uint8_t tst[7]{0u,1u,2u,0xffu,0x34,0x7f,10};
      char res[14]{};
      std::string_view result{ &res[0], 14 };
      strconv::to_hex_ascii( std::begin(tst), std::end(tst), std::begin(res) );
      constexpr auto expected{"000102FF347F0A"sv};
      return result == expected;
      };

    static_assert( test_1() );

    constexpr bool test_2()
      {
      uint8_t tst[7]{0u,1u,2u,0xffu,0x34,0x7f,10};
      char res[14]{};
      std::string_view result{ &res[0], 14 };
      strconv::to_hex_ascii<strconv::char_case_e::lowercase>( std::begin(tst), std::end(tst), std::begin(res) );
      constexpr auto expected{"000102ff347f0a"sv};
      return result == expected;
      };

    static_assert( test_2() );
}

inline constexpr auto integral_to_string_max_size = 128;

namespace calculate_size_div_info_test
  {

    static_assert( strconv::detail::calculate_size_div_info<10>(0u).size_ == 0 );
    static_assert( strconv::detail::calculate_size_div_info<10>(1u).size_ == 1 );
    static_assert( strconv::detail::calculate_size_div_info<10>(10u).size_ == 2 );
    static_assert( strconv::detail::calculate_size_div_info<10>(99u).size_ == 2 );
    static_assert( strconv::detail::calculate_size_div_info<10>(100u).size_ == 3 );

    static_assert( strconv::detail::calculate_size_div_info<10>(0u).divisor_ == 0 );
    static_assert( strconv::detail::calculate_size_div_info<10>(1u).divisor_ == 1 );
    static_assert( strconv::detail::calculate_size_div_info<10>(10u).divisor_ == 10 );
    static_assert( strconv::detail::calculate_size_div_info<10>(99u).divisor_ == 10 );
    static_assert( strconv::detail::calculate_size_div_info<10>(100u).divisor_ == 100 );
    static_assert( strconv::detail::calculate_size_div_info<10>(1000u).divisor_ == 1000 );
    static_assert( strconv::detail::calculate_size_div_info<10>(9999u).divisor_ == 1000 );

    static_assert( strconv::detail::calculate_size_div_info<10>( 18446744073709551610ull).divisor_ == 10000000000000000000ull );
    //18446744073709551615ull
    //10000000000000000000

    static_assert( strconv::detail::calculate_size_div_info<16>(0u).size_ == 0 );
    static_assert( strconv::detail::calculate_size_div_info<16>(1u).size_ == 1 );
    static_assert( strconv::detail::calculate_size_div_info<16>(0xfu).size_ == 1 );
    static_assert( strconv::detail::calculate_size_div_info<16>(0x10u).size_ == 2 );
    static_assert( strconv::detail::calculate_size_div_info<16>(0xffu).size_ == 2 );
    static_assert( strconv::detail::calculate_size_div_info<16>(0xfffu).size_ == 3 );
    static_assert( strconv::detail::calculate_size_div_info<16>(0xffffu).size_ == 4 );

    static_assert( strconv::detail::calculate_size_div_info<16>(0u).divisor_ == 0 );
    static_assert( strconv::detail::calculate_size_div_info<16>(1u).divisor_ == 1 );
    static_assert( strconv::detail::calculate_size_div_info<16>(0xfu).divisor_ == 1 );
    static_assert( strconv::detail::calculate_size_div_info<16>(0x10u).divisor_ == 0x10 );
    static_assert( strconv::detail::calculate_size_div_info<16>(0xffu).divisor_ == 0x10 );
    static_assert( strconv::detail::calculate_size_div_info<16>(0xfffu).divisor_ == 0x100 );
    static_assert( strconv::detail::calculate_size_div_info<16>(0xffffu).divisor_ == 0x1000 );

  }

#pragma clang optimize off

BOOST_AUTO_TEST_CASE( calc_size_div_info )
{
//   auto l10 = std::log(10);
//   auto ll10 = std::log(std::max<unsigned>(1, 1000));
//   auto res = static_cast<unsigned>(1 + std::log(std::max<unsigned>(1, 1000))/std::log(10) );

    BOOST_TEST( strconv::detail::calculate_size_div_info<10>(0u).size_ == 0 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<10>(1u).size_ == 1 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<10>(10u).size_ == 2 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<10>(99u).size_ == 2 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<10>(100u).size_ == 3 );

    BOOST_TEST( strconv::detail::calculate_size_div_info<10>(0u).divisor_ == 0 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<10>(1u).divisor_ == 1 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<10>(10u).divisor_ == 10 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<10>(99u).divisor_ == 10 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<10>(100u).divisor_ == 100 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<10>(1000u).divisor_ == 1000 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<10>(9999u).divisor_ == 1000 );

    BOOST_TEST( strconv::detail::calculate_size_div_info<10>( 18446744073709551610ull).divisor_ == 10000000000000000000ull );
    //18446744073709551615ull
    //10000000000000000000

    BOOST_TEST( strconv::detail::calculate_size_div_info<16>(0u).size_ == 0 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<16>(1u).size_ == 1 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<16>(0xfu).size_ == 1 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<16>(0x10u).size_ == 2 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<16>(0xffu).size_ == 2 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<16>(0xfffu).size_ == 3 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<16>(0xffffu).size_ == 4 );

    BOOST_TEST( strconv::detail::calculate_size_div_info<16>(0u).divisor_ == 0 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<16>(1u).divisor_ == 1 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<16>(0xfu).divisor_ == 1 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<16>(0x10u).divisor_ == 0x10 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<16>(0xffu).divisor_ == 0x10 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<16>(0xfffu).divisor_ == 0x100 );
    BOOST_TEST( strconv::detail::calculate_size_div_info<16>(0xffffu).divisor_ == 0x1000 );
}
#pragma clang optimize on

using traits = strconv::integral_format_traits;
using strconv::format_e;
using strconv::char_case_e;
using strconv::prepend_sign_e;
using strconv::padd_with_e;
using strconv::include_prefix_e;
using strconv::alignment_e;

namespace integral_to_string_test
{

  inline constexpr auto hex_lower = traits{ .format = format_e::hexadecimal,
                                            .char_case = char_case_e::lowercase };

  inline constexpr auto hex_upper = traits{ .format = format_e::hexadecimal,
                                            .char_case = char_case_e::uppercase };

  //--------------------------------------------------------------------------------------------------------
    constexpr bool test_unsigned_1()
      {
      constexpr unsigned value{ 0 };
      constexpr std::string_view expected{ "0" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_1() );

    constexpr bool test_unsigned_1a()
      {
      constexpr unsigned value{ 0 };
      constexpr std::string_view expected{ "" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .precision = 0}>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_1a() );

    constexpr bool test_unsigned_1b()
      {
      constexpr unsigned value{ 0 };
      constexpr std::string_view expected{ "    0" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .precision = 5}>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_1b() );

    constexpr bool test_unsigned_1c()
      {
      constexpr unsigned value{ 0 };
      constexpr std::string_view expected{ "00000" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .precision = 5,
                                                     .padd_with = padd_with_e::zeros
                                                   }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_1c() );
  //--------------------------------------------------------------------------------------------------------
    constexpr bool test_unsigned_2()
      {
      constexpr unsigned value{ 0 };
      constexpr std::string_view expected{ "0x0" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<hex_lower>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_2() );

    constexpr bool test_unsigned_2a()
      {
      constexpr unsigned value{ 0 };
      constexpr std::string_view expected{ "" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .precision = 0,
                                                     .format = format_e::hexadecimal
                                                      }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_2a() );

    constexpr bool test_unsigned_2b()
      {
      constexpr unsigned value{ 0 };
      constexpr std::string_view expected{ "   0x0" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .precision = 6,
                                                     .format = format_e::hexadecimal
                                                      }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_2b() );

    constexpr bool test_unsigned_2c()
      {
      constexpr unsigned value{ 0 };
      constexpr std::string_view expected{ "0x0000" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .precision = 6,
                                                     .format = format_e::hexadecimal,
                                                     .padd_with = padd_with_e::zeros
                                                      }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_2c() );

    constexpr bool test_unsigned_2d()
      {
      constexpr unsigned value{ 0 };
      constexpr std::string_view expected{ "000000" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .precision = 6,
                                                     .format = format_e::hexadecimal,
                                                     .padd_with = padd_with_e::zeros,
                                                     .include_prefix = include_prefix_e::no_prefix
                                                      }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_2d() );
  //--------------------------------------------------------------------------------------------------------
    constexpr bool test_unsigned_7()
      {
      constexpr unsigned value{ 0 };
      constexpr std::string_view expected{ "0b0" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .format = format_e::binary }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_7() );

    constexpr bool test_unsigned_7a()
      {
      constexpr unsigned value{ 0 };
      constexpr std::string_view expected{ "" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .precision = 0,
                                                     .format = format_e::binary
                                                      }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_7a() );

    constexpr bool test_unsigned_7b()
      {
      constexpr unsigned value{ 0 };
      constexpr std::string_view expected{ "   0b0" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .precision = 6,
                                                     .format = format_e::binary
                                                      }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_7b() );

    constexpr bool test_unsigned_7c()
      {
      constexpr unsigned value{ 0 };
      constexpr std::string_view expected{ "0b0000" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .precision = 6,
                                                     .format = format_e::binary,
                                                     .padd_with = padd_with_e::zeros
                                                      }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    constexpr bool test_unsigned_7d()
      {
      constexpr unsigned value{ 0 };
      constexpr std::string_view expected{ "000000" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .precision = 6,
                                                     .format = format_e::binary,
                                                     .padd_with = padd_with_e::zeros,
                                                     .include_prefix = include_prefix_e::no_prefix
                                                      }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_7d() );
  //--------------------------------------------------------------------------------------------------------
    constexpr bool test_unsigned_3()
      {
      constexpr unsigned value{ 1501900 };
      constexpr std::string_view expected{ "1501900" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_3() );
  //--------------------------------------------------------------------------------------------------------
    constexpr bool test_unsigned_8()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr unsigned value{ 0b1010011 };
      constexpr std::string_view expected{ "0b1010011" };
      auto oit = strconv::integral_to_string<traits{ .format = format_e::binary}>( value, itbeg );

      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_8() );

    constexpr bool test_unsigned_8a()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr unsigned value{ 0b1010011 };
      constexpr std::string_view expected{ "0B1010011" };
      auto oit = strconv::integral_to_string<traits{ .format = format_e::binary,
                                                     .char_case = char_case_e::uppercase
                                                   }>( value, itbeg );

      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_8a() );

    constexpr bool test_unsigned_8b()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr unsigned value{ 0b1010011 };
      constexpr std::string_view expected{ "1010011" };
      auto oit = strconv::integral_to_string<traits{ .format = format_e::binary,
                                                     .include_prefix = include_prefix_e::no_prefix}
                                            >( value, itbeg );

      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_8b() );

    constexpr bool test_unsigned_8c()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr unsigned value{ 0b1010011 };
      constexpr std::string_view expected{ "   1010011" };
      auto oit = strconv::integral_to_string<traits{ .precision = 10,
                                                     .format = format_e::binary,
                                                     .include_prefix = include_prefix_e::no_prefix}
                                            >( value, itbeg );

      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_8c() );
    constexpr bool test_unsigned_8d()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr unsigned value{ 0b1010011 };
      constexpr std::string_view expected{ " 0b1010011" };
      auto oit = strconv::integral_to_string<traits{ .precision = 10,
                                                     .format = format_e::binary,
                                                     .include_prefix = include_prefix_e::with_prefix}
                                            >( value, itbeg );

      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_8d() );

    constexpr bool test_unsigned_8e()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr unsigned value{ 0b1010011 };
      constexpr std::string_view expected{ "0B000001010011" };
      auto oit = strconv::integral_to_string<traits{ .precision = 14,
                                                     .format = format_e::binary,
                                                     .char_case = char_case_e::uppercase,
                                                     .padd_with = padd_with_e::zeros,
                                                     .include_prefix = include_prefix_e::with_prefix}
                                            >( value, itbeg );

      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_8e() );

    constexpr bool test_unsigned_8f()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr unsigned value{ 0b1010011 };
      constexpr std::string_view expected{ "+0b00001010011" };
      auto oit = strconv::integral_to_string<traits{ .precision = 14,
                                                     .format = format_e::binary,
                                                     .char_case = char_case_e::lowercase,
                                                     .padd_with = padd_with_e::zeros,
                                                     .sign = prepend_sign_e::always,
                                                     .include_prefix = include_prefix_e::with_prefix
                                                      }
                                            >( value, itbeg );

      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_8f() );
  //--------------------------------------------------------------------------------------------------------
    constexpr bool test_unsigned_4()
      {
      constexpr unsigned value{ 0x1ffeb3e };
      constexpr std::string_view expected{ "0X1FFEB3E" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<hex_upper>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_4() );

    constexpr bool test_unsigned_4a()
      {
      constexpr unsigned value{ 0x1ffeb3e };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr std::string_view expected{ "+0X0001FFEB3E" };
      auto oit = strconv::integral_to_string<traits{ .precision = 13,
                                                     .format = format_e::hexadecimal,
                                                     .char_case = char_case_e::uppercase,
                                                     .padd_with = padd_with_e::zeros,
                                                     .sign = prepend_sign_e::always
                                                      }>( value, itbeg );

      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_4a() );

    constexpr bool test_unsigned_4b()
      {
      constexpr unsigned value{ 0x1ffeb3e };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr std::string_view expected{ "  +0X1FFEB3E" };
      auto oit = strconv::integral_to_string<traits{ .precision = 12,
                                                     .format = format_e::hexadecimal,
                                                     .char_case = char_case_e::uppercase,
                                                     .padd_with = padd_with_e::space,
                                                     .sign = prepend_sign_e::always
                                                      }>( value, itbeg );

      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_4b() );

    constexpr bool test_unsigned_4c()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr unsigned value{ 0x1ffeb3e };
      constexpr std::string_view expected{ "+0X1FFEB3E  " };
      auto oit = strconv::integral_to_string<traits{ .precision = 12,
                                                     .format = format_e::hexadecimal,
                                                     .char_case = char_case_e::uppercase,
                                                     .padd_with = padd_with_e::space,
                                                     .sign = prepend_sign_e::always,
                                                     .alignment = alignment_e::left
                                                      }>( value, itbeg );

      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_4c() );

    constexpr bool test_unsigned_4d()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr unsigned value{ 0x1ffeb3e };
      constexpr std::string_view expected{ " +0X1FFEB3E " };
      auto oit = strconv::integral_to_string<traits{ .precision = 12,
                                                     .format = format_e::hexadecimal,
                                                     .char_case = char_case_e::uppercase,
                                                     .padd_with = padd_with_e::space,
                                                     .sign = prepend_sign_e::always,
                                                     .alignment = alignment_e::middle
                                                      }>( value, itbeg );

      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_4d() );
  //--------------------------------------------------------------------------------------------------------
    constexpr bool test_unsigned_5()
      {
      constexpr uint64_t value{ 1844674407370955161ull };
      constexpr std::string_view expected{ "1844674407370955161" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_5() );

    constexpr bool test_unsigned_5a()
      {
      constexpr uint64_t value{ 1844674407370955161ull };
      constexpr std::string_view expected{ "+1844674407370955161" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .sign = prepend_sign_e::always }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_5a() );

    constexpr bool test_unsigned_5b()
      {
      constexpr int64_t value{ -1844674407370955161ll };
      constexpr std::string_view expected{ "  -1844674407370955161" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .precision = 22 }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_5b() );

    constexpr bool test_unsigned_5c()
      {
      constexpr int64_t value{ -1844674407370955161ll };
      constexpr std::string_view expected{ "-001844674407370955161" };
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .precision = 22,
                                                     .padd_with = padd_with_e::zeros
                                                   }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_5c() );
  //--------------------------------------------------------------------------------------------------------
    constexpr bool test_unsigned_6()
      {
      constexpr uint64_t value{ 0x1ffeb3ef1ffeb3ull };
      constexpr auto expected{ L"0x1ffeb3ef1ffeb3"sv };
      wchar_t buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<hex_lower>( value, itbeg );
      std::wstring_view result{ itbeg, static_cast<std::wstring_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_6() );

    constexpr bool test_unsigned_6a()
      {
      constexpr uint64_t value{ 0x1ffeb3ef1ffeb3ull };
      constexpr auto expected{ L"+0x1ffeb3ef1ffeb3"sv };
      wchar_t buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .format = format_e::hexadecimal,
                                                     .char_case = char_case_e::lowercase,
                                                     .sign = prepend_sign_e::always
                                                    }>( value, itbeg );
      std::wstring_view result{ itbeg, static_cast<std::wstring_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_6a() );

    constexpr bool test_unsigned_6b()
      {
      constexpr int64_t value{ -0x1ffeb3ef1ffeb3ll };
      constexpr auto expected{ L"-0x1ffeb3ef1ffeb3"sv };
      wchar_t buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .format = format_e::hexadecimal,
                                                     .char_case = char_case_e::lowercase,
                                                     .sign = prepend_sign_e::only_negative
                                                    }>( value, itbeg );
      std::wstring_view result{ itbeg, static_cast<std::wstring_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_6b() );

    constexpr bool test_unsigned_6c()
      {
      constexpr int64_t value{ -0x1ffeb3ef1ffeb3ll };
      constexpr auto expected{ L"  -0x1ffeb3ef1ffeb3   "sv };
      wchar_t buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };
      auto oit = strconv::integral_to_string<traits{ .precision = 22,
                                                     .format = format_e::hexadecimal,
                                                     .char_case = char_case_e::lowercase,
                                                     .sign = prepend_sign_e::only_negative,
                                                     .alignment = alignment_e::middle
                                                    }>( value, itbeg );
      std::wstring_view result{ itbeg, static_cast<std::wstring_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_6c() );
  //--------------------------------------------------------------------------------------------------------
    constexpr bool test_unsigned_9()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr uint64_t value{ 0b1100110011001100110011001100110011001100110011001100110011001ull };
      constexpr std::string_view expected{ "0b1100110011001100110011001100110011001100110011001100110011001" };
      auto oit = strconv::integral_to_string<traits{.format = format_e::binary}>( value, itbeg );

      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_9() );
    constexpr bool test_unsigned_9a()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr int64_t value{ -0b1100110011001100110011001100110011001100110011001100110011001ll };
      constexpr std::string_view expected{ "-0b1100110011001100110011001100110011001100110011001100110011001" };
      auto oit = strconv::integral_to_string<traits{.format = format_e::binary}>( value, itbeg );

      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_9a() );

    constexpr bool test_unsigned_9b()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr int64_t value{ -0b1100110011001100110011001100110011001100110011001100110011001ll };
      constexpr std::string_view expected{ "-0b00001100110011001100110011001100110011001100110011001100110011001" };
      auto oit = strconv::integral_to_string<traits{.precision = 68,
                                                    .format = format_e::binary,
                                                    .padd_with = padd_with_e::zeros
                                                    }>( value, itbeg );

      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_9b() );

    constexpr bool test_unsigned_9c()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr int64_t value{ -0b1100110011001100110011001100110011001100110011001100110011001ll };
      constexpr std::string_view expected{ "    -0b1100110011001100110011001100110011001100110011001100110011001" };
      auto oit = strconv::integral_to_string<traits{.precision = 68,
                                                    .format = format_e::binary,
                                                    .padd_with = padd_with_e::space
                                                    }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_9c() );

    constexpr bool test_unsigned_9d()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr int64_t value{ -0b1100110011001100110011001100110011001100110011001100110011001ll };
      constexpr std::string_view expected{ "      -1100110011001100110011001100110011001100110011001100110011001" };
      auto oit = strconv::integral_to_string<traits{.precision = 68,
                                                    .format = format_e::binary,
                                                    .padd_with = padd_with_e::space,
                                                    .include_prefix = include_prefix_e::no_prefix
                                                    }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_unsigned_9d() );
  //--------------------------------------------------------------------------------------------------------
}
struct strconv_fixture_t {};

BOOST_FIXTURE_TEST_SUITE(strconv_fixture, strconv_fixture_t )
//----------------------------------------------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(strconv_integral_to_string)
{
  using traits = strconv::integral_format_traits;
    {
    constexpr int64_t value{ -0x1ffeb3ef1ffeb3ll };
    constexpr auto expected{ "  -0x1ffeb3ef1ffeb3   "sv };
    auto result = strconv::integral_to_string<traits{ .precision = 22,
                                                   .format = format_e::hexadecimal,
                                                   .char_case = char_case_e::lowercase,
                                                   .sign = prepend_sign_e::only_negative,
                                                   .alignment = alignment_e::middle
                                                  }>( value );

    BOOST_TEST( expected == result );
    }
    {
    constexpr unsigned value{ 0 };
    constexpr std::string_view expected{ "0" };
    auto result = strconv::integral_to_string( value );
    BOOST_TEST( expected == result );
    }
    {
      constexpr unsigned value{ 0b1010011 };
      constexpr std::string_view expected{ " 0b1010011" };
      auto result = strconv::integral_to_string<traits{ .precision = 10,
                                                     .format = format_e::binary,
                                                     .include_prefix = include_prefix_e::with_prefix}
                                            >( value );
    BOOST_TEST( expected == result );
    }
}
//----------------------------------------------------------------------------------------------------------------------
using strconv::trailing_zeros_e;
namespace estimate_float_to_string_test
  {
  using traits = strconv::float_format_traits;
  //----------------------------------------------------------------------------------------------------------------------
    constexpr bool test_estimate_float_0()
      {
      constexpr double value{ 0.0 };

      auto est_info = strconv::detail::estimate_float_to_string_<traits{
                                                .decimal_places = 4,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value);
      return est_info.size() == 1;
      }
    static_assert( test_estimate_float_0() );

    constexpr bool test_estimate_float_0a()
      {
      constexpr double value{ 0.0 };

      auto est_info = strconv::detail::estimate_float_to_string_<traits{
                                                .precision = 0,
                                                .decimal_places = 4,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value);
      return est_info.size() == 0;
      }
    static_assert( test_estimate_float_0a() );

  //----------------------------------------------------------------------------------------------------------------------
    constexpr bool test_estimate_float_1()
      {
      constexpr double value{ 202.5 };
      //constexpr std::string_view expected{ "202.5" };
      auto est_info = strconv::detail::estimate_float_to_string_<traits{
                                                .decimal_places = 4,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value);
      return est_info.size() == 5;
      }
    static_assert( test_estimate_float_1() );
    constexpr bool test_estimate_float_1a()
      {
      constexpr double value{ 202.5 };
      auto est_info = strconv::detail::estimate_float_to_string_<traits{
                                                .decimal_places = 4,
                                                .trailing_zeros = trailing_zeros_e::preserve
                                                }>( value);
      return est_info.size() == 8;
      }
    static_assert( test_estimate_float_1a() );
  //----------------------------------------------------------------------------------------------------------------------
    constexpr bool test_estimate_float_2()
      {
      constexpr double value{ 0.5 };
      //constexpr std::string_view expected{ "202.5" };
      auto est_info = strconv::detail::estimate_float_to_string_<traits{
                                                .decimal_places = 4,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value);
      return est_info.size() == 3;
      }
    static_assert( test_estimate_float_2() );

    constexpr bool test_estimate_float_2a()
      {
      constexpr double value{ 0.5 };
      //constexpr std::string_view expected{ "202.5" };
      auto est_info = strconv::detail::estimate_float_to_string_<traits{
                                                .decimal_places = 4,
                                                .trailing_zeros = trailing_zeros_e::preserve
                                                }>( value);
      return est_info.size() == 6;
      }
    static_assert( test_estimate_float_2a() );
  //----------------------------------------------------------------------------------------------------------------------
  }
namespace float_to_string_test
  {
  using traits = strconv::float_format_traits;
    //----------------------------------------------------------------------------------------------------------------------

    //----------------------------------------------------------------------------------------------------------------------
    constexpr bool test_float_0()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 0.0 };
      constexpr std::string_view expected{ "0" };
      auto oit = strconv::float_to_string<traits{
                                                .decimal_places = 4,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_0() );

    constexpr bool test_float_0a()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 0.0 };
      constexpr std::string_view expected{ "" };
      auto oit = strconv::float_to_string<traits{
                                                .precision = 0,
                                                .decimal_places = 4,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_0a() );

    constexpr bool test_float_0e()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 0.0 };
      constexpr std::string_view expected{ "+0.0000" };
      auto oit = strconv::float_to_string<traits{
                                                .precision = 1,
                                                .decimal_places = 4,
                                                .sign = prepend_sign_e::always,
                                                .trailing_zeros = trailing_zeros_e::preserve
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_0e() );
    //----------------------------------------------------------------------------------------------------------------------

    constexpr bool test_float_1()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 202.5 };
      constexpr std::string_view expected{ "202.5" };
      auto oit = strconv::float_to_string<traits{
                                                .decimal_places = 4,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_1() );

    constexpr bool test_float_1a()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 2.5 };
      constexpr std::string_view expected{ "2.5000" };
      auto oit = strconv::float_to_string<traits{
                                                .decimal_places = 4,
                                                .trailing_zeros = trailing_zeros_e::preserve
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_1a() );
    //----------------------------------------------------------------------------------------------------------------------

    constexpr bool test_float_2()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 0.5 };
      constexpr std::string_view expected{ "0.5" };
      auto oit = strconv::float_to_string<traits{
                                                .decimal_places = 4,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_2() );

    constexpr bool test_float_2a()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 0.5 };
      constexpr std::string_view expected{ "0.500" };
      auto oit = strconv::float_to_string<traits{
                                                .decimal_places = 3,
                                                .trailing_zeros = trailing_zeros_e::preserve
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_2a() );

    //----------------------------------------------------------------------------------------------------------------------

    constexpr bool test_float_3()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 0.5 };
      constexpr std::string_view expected{ "       0.5" };
      auto oit = strconv::float_to_string<traits{
                                                .precision = 10,
                                                .decimal_places = 4,
                                                .alignment = alignment_e::right,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_3() );

    constexpr bool test_float_3a()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 0.5 };
      constexpr std::string_view expected{ "   0.5    " };
      auto oit = strconv::float_to_string<traits{
                                                .precision = 10,
                                                .decimal_places = 4,
                                                .alignment = alignment_e::middle,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_3a() );

    constexpr bool test_float_3b()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 0.5 };
      constexpr std::string_view expected{ "0.5       " };
      auto oit = strconv::float_to_string<traits{
                                                .precision = 10,
                                                .decimal_places = 4,
                                                .alignment = alignment_e::left,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_3b() );

    constexpr bool test_float_3c()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 120.5 };
      constexpr std::string_view expected{ "     120.5" };
      auto oit = strconv::float_to_string<traits{
                                                .precision = 10,
                                                .decimal_places = 4,
                                                .alignment = alignment_e::right,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_3c() );

    constexpr bool test_float_3d()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 120.5 };
      constexpr std::string_view expected{ "  120.5   " };
      auto oit = strconv::float_to_string<traits{
                                                .precision = 10,
                                                .decimal_places = 4,
                                                .alignment = alignment_e::middle,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_3d() );

    constexpr bool test_float_3e()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 120.5 };
      constexpr std::string_view expected{ "120.5     " };
      auto oit = strconv::float_to_string<traits{
                                                .precision = 10,
                                                .decimal_places = 4,
                                                .alignment = alignment_e::left,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_3e() );
    //----------------------------------------------------------------------------------------------------------------------

    constexpr bool test_float_4()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 0.5 };
      constexpr std::string_view expected{ "00000000.5" };
      auto oit = strconv::float_to_string<traits{
                                                .precision = 10,
                                                .decimal_places = 4,
                                                .padd_with = padd_with_e::zeros,
                                                .trailing_zeros = trailing_zeros_e::skip
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_4() );

    constexpr bool test_float_4a()
      {
      char buffer_[integral_to_string_max_size]{};
      auto itbeg{ &buffer_[0] };

      constexpr double value{ 0.5 };
      constexpr std::string_view expected{ "00000.5000" };
      auto oit = strconv::float_to_string<traits{
                                                .precision = 10,
                                                .decimal_places = 4,
                                                .padd_with = padd_with_e::zeros,
                                                .trailing_zeros = trailing_zeros_e::preserve
                                                }>( value, itbeg );
      std::string_view result{ itbeg, static_cast<std::string_view::size_type>(oit-itbeg) };
      return expected == result;
      }
    static_assert( test_float_4a() );
    //----------------------------------------------------------------------------------------------------------------------

  }

namespace string_to_integral_test
  {
  using strconv::string_to_integral;
  using namespace std::string_view_literals;
  using strconv::input_format_e;

  template<typename integral_type,
           input_format_e input_format = input_format_e::undetermined,
           typename expected_type>
  constexpr auto test( std::string_view source, expected_type expected, int end_it_offset )
    {
    auto [result,end_it] = string_to_integral<integral_type,input_format>(source);
    return std::next(std::begin(source),end_it_offset) == end_it
      && static_cast<integral_type>(expected) == result;
    }
  //format undetermined
  static_assert( test<uint8_t>({}, 0u, 0 ) );
  static_assert( test<uint8_t>("-"sv,0u,0) );
  static_assert( test<uint8_t>("+"sv,0u,1) );
  static_assert( test<uint8_t>("0x"sv,0u,2) );
  static_assert( test<uint8_t>("+0x"sv,0u,3) );

  static_assert( test<int8_t>({},0,0) );
  static_assert( test<int8_t>(""sv,0,0) );
  static_assert( test<int8_t>("-"sv,0,1) );
  static_assert( test<int8_t>("+"sv,0,1) );
  static_assert( test<int8_t>("0x"sv,0,2) );
  static_assert( test<int8_t>("+0x"sv,0,3) );

  static_assert( test<uint8_t>("-1"sv,0u,0) );
  static_assert( test<uint8_t>("255"sv,255u,3) );
  static_assert( test<uint8_t>("0xff"sv,255u,4) );

  static_assert( test<uint8_t>(" \t0xff 0xfe"sv,255u,6) );
  static_assert( test<uint8_t,input_format_e::hexadecimal>(" \t0xff 0xfe"sv,255u,6) );
  static_assert( test<uint8_t,input_format_e::hexadecimal>(" \tff 0xfe"sv,255u,4) );

  static_assert( test<int8_t>("-1"sv,-1,2) );
  static_assert( test<int8_t>("0x1f"sv, 0x1f,4) );
  static_assert( test<int8_t>("+0x1f"sv, 0x1f,5) );
  static_assert( test<int8_t>("-0x1f"sv,-0x1f,5) );
  static_assert( test<int8_t>("0x7f"sv, 0x7f,4) );

  static_assert( test<uint16_t>("-1"sv,0u,0) );
  static_assert( test<uint16_t>("255"sv,255u,3) );
  static_assert( test<uint16_t>("0xff"sv,255u,4) );
  static_assert( test<uint16_t>("0xFfFf"sv,0xffffu,6) );

  static_assert( test<int16_t>("-1"sv,-1,2) );
  static_assert( test<int16_t>("32767"sv,0x7fff,5) );
  static_assert( test<int16_t>("0x7fff"sv,0x7fff,6) );
  static_assert( test<int16_t>("-0x7fff"sv,-0x7fff,7) );

  static_assert( test<uint32_t>("0"sv,0u,1) );
  static_assert( test<uint32_t>("+0"sv,0u,2) );
  static_assert( test<uint32_t>("-0"sv,0u,0) );
  static_assert( test<uint32_t>("-1"sv,0u,0) );
  static_assert( test<uint32_t>("\t  \t-124566554 "sv,0u,0) );
  static_assert( test<uint32_t>("\t  \t124566554 "sv,124566554u,13) );
  static_assert( test<uint32_t>("\t  \t+124566554 "sv,124566554u,14) );
  static_assert( test<uint32_t>("\t  \t-124566554XSCD"sv,0u,0) );
  static_assert( test<uint32_t>("\t  \t-124566554 123432"sv,0u,0) );
  static_assert( test<uint32_t>("\t  \t+124566554XSCD"sv,124566554u,14) );
  static_assert( test<uint32_t>("\t  \t+124566554 123432"sv,124566554u,14) );

  static_assert( test<int32_t>("0"sv,0,1) );
  static_assert( test<int32_t>("+0"sv,0,2) );
  static_assert( test<int32_t>("-0"sv,0,2) );
  static_assert( test<int32_t>(" -0"sv,0,3) );
  static_assert( test<int32_t>("    -0"sv,0,6) );
  static_assert( test<int32_t>("   +0"sv,0,5) );
  static_assert( test<int32_t>( {},0,0) );
  static_assert( test<int32_t>("1"sv,1,1) );
  static_assert( test<int32_t>("1000"sv,1000,4) );
  static_assert( test<uint32_t>("1000"sv,1000u,4) );
  static_assert( test<int32_t>("12"sv,12,2) );
  static_assert( test<int32_t>("124566554"sv,124566554,9) );
  static_assert( test<int32_t>("+124566554"sv,124566554,10) );
  static_assert( test<int32_t>("-124566554"sv,-124566554,10) );
  static_assert( test<int32_t>("\t  \t-124566554"sv,-124566554,14) );
  static_assert( test<int32_t>("\t  \t+124566554"sv,124566554,14) );
  static_assert( test<int32_t>("\t  \t-124566554a"sv,-124566554,14) );
  static_assert( test<int32_t>("\t  \t+124566554a"sv,124566554,14) );
  static_assert( test<int32_t>("\t  \t-124566554 "sv,-124566554,14) );
  static_assert( test<int32_t>("\t  \t+124566554 "sv,124566554,14) );
  static_assert( test<int32_t>("\t  \t-124566554XSCD"sv,-124566554,14) );
  static_assert( test<int32_t>("\t  \t+124566554XSCD"sv,124566554,14) );
  static_assert( test<int32_t>("\t  \t-124566554 123432"sv,-124566554,14) );
  static_assert( test<int32_t>("\t  \t+124566554 123432"sv,124566554,14) );

  static_assert( test<int64_t>("+0xFF"sv,0xff,5) );
  static_assert( test<int64_t>("-0xFF3423"sv,-0xff3423,9) );
  static_assert( test<int64_t>("\t \t 0xFF3423 342fsdv"sv,0xff3423,12) );
  static_assert( test<int64_t>("\t \t 0x1aF3423R342fsdv"sv,0x1af3423,13) );

  static_assert( test<int64_t>("0xFF"sv,0xffu,4) );
  static_assert( test<int64_t>("0xFF3423"sv,0xff3423u,8) );
  static_assert( test<int64_t>("\t \t 0xFF3423 342fsdv"sv,0xff3423,12) );
  static_assert( test<int64_t>("\t \t +0xFF3423 342fsdv"sv,0xff3423,13) );
  static_assert( test<int64_t>("\t \t -0x1aF3423R342fsdv"sv,-0x1af3423,14) );
  static_assert( test<int64_t>("\t \t 0XFf3423 342fsdv"sv,0xff3423,12) );
  static_assert( test<int64_t>("\t \t +0XFF3423 342fsdv"sv,0xff3423,13) );
  static_assert( test<int64_t>( "\t \t -0X1aF3423R342fsdv"sv,-0x1af3423,14) );
  static_assert( test<int64_t>("\t \t +0x7fffffffffffffff"sv,  0x7fffffffffffffffll,23) );
  static_assert( test<int64_t>("\t \t -0x7fffffffffffffff"sv,  -0x7fffffffffffffffll,23) );

  static_assert( test<uint64_t>("\t \t 0xffffffffffffffff"sv,  0xffffffffffffffffull,22) );
  static_assert( test<uint64_t>("\t \t +0xffffffffffffffff"sv,  0xffffffffffffffffull,23) );

  //explicitly specified format decimal
  static_assert( test<uint32_t,input_format_e::decimal>("\t  \t124566554 "sv,124566554u,13) );
  static_assert( test<uint32_t,input_format_e::decimal>("\t  \t124566554fa "sv,124566554u,13) );
  static_assert( test<uint32_t,input_format_e::decimal>("\t  \t124566554 54 "sv,124566554u,13) );

  //explicitly specified format hexadecimal
  static_assert( test<int64_t,input_format_e::hexadecimal>("+0xFF"sv,0xff,5) );
  static_assert( test<int64_t,input_format_e::hexadecimal>("-0xFF3423"sv,-0xff3423,9) );
  static_assert( test<int64_t,input_format_e::hexadecimal>("\t \t 0xFF3423 342fsdv"sv,0xff3423,12) );

  static_assert( test<int64_t,input_format_e::hexadecimal>("+FF"sv,0xff,3) );
  static_assert( test<int64_t,input_format_e::hexadecimal>("-FF3423"sv,-0xff3423,7) );
  static_assert( test<int64_t,input_format_e::hexadecimal>("\t \t FF3423 342fsdv"sv,0xff3423,10) );
  }

BOOST_AUTO_TEST_CASE(strconv_string_to_integral_test)
{
  //Test comile string/string_view iterators on return
  using namespace string_to_integral_test;
  std::string source{ "\t \t 0xFF3423 342fsdv"sv };
  auto [result,end_it] = string_to_integral<uint32_t>(source);
  BOOST_TEST(result == 0xFF3423);
  auto [result2,end_it2] = string_to_integral<int32_t>(source);
  BOOST_TEST(result2 == 0xFF3423);
}

namespace string_to_float_test
  {
  using strconv::string_to_float;
  using namespace std::string_view_literals;

  template<typename float_type, typename expected_type>
  constexpr auto test( std::string_view source, expected_type expected, int end_it_offset )
    {
    auto [result,end_it] = string_to_float<float_type>(source);
    return std::next(std::begin(source),end_it_offset) == end_it
      && static_cast<float_type>(expected) == result;
    }

  static_assert( test<float>({}, 0.f, 0 ) );

  static_assert( test<float>(""sv, 0.f, 0 ) );
  static_assert( test<double>(""sv, 0., 0 ) );

  static_assert( test<float>("0"sv, 0.f, 1 ) );
  static_assert( test<double>("0"sv, 0., 1 ) );

  static_assert( test<float>("0."sv, 0.f, 2 ) );
  static_assert( test<double>("0."sv, 0., 2 ) );

  static_assert( test<float>("0.1"sv, 0.1f, 3 ) );
  static_assert( test<double>("0.1"sv, 0.1, 3 ) );

  static_assert( test<float>("0.1333"sv, 0.1333f, 6 ) );
  static_assert( test<double>("0.1333"sv, 0.1333, 6 ) );

  static_assert( test<double>("10.1333"sv, 10.1333, 7 ) );
  static_assert( test<double>("+10.1333"sv, 10.1333, 8 ) );
  static_assert( test<double>("-10.1333"sv, -10.1333, 8 ) );
  static_assert( test<double>("-110.1333"sv, -110.1333, 9 ) );
  static_assert( test<double>("1000.36"sv, 1000.36, 7 ) );
  }
BOOST_AUTO_TEST_CASE(strconv_string_to_float_test)
{
  using strconv::detail::log2p1;
  auto lg = 3.32192809488736;//double(log2p1(10u)-1);
  auto i = 1+unsigned(double(log2p1(1000u)-1)/lg);
  i = 1+unsigned(double(log2p1(999u)-1)/lg);

  using namespace string_to_float_test;
  auto [result,end_it] = strconv::string_to_float<double>("1000.08"sv);
  BOOST_TEST( result == 1000.08);

}
//----------------------------------------------------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(strconv_compose)
{
  {
  using strconv::integral_format_traits;
  using strconv::fmt;

  constexpr integral_format_traits ptrfmt
    {
    .precision = 6,
    .format = format_e::hexadecimal,
    .char_case = char_case_e::uppercase,
    .padd_with = padd_with_e::zeros
    };

  auto strres{
  strconv::compose<char>(
    " some view "sv,
    127.3f, //default formatted floating point
    ',', ///single char
    125, //default formatted integral number
    '[',
    fmt<integral_format_traits{
            .precision = 15,
            .format = format_e::binary,
            .char_case = char_case_e::lowercase,
            .alignment = alignment_e::middle
            }>(456), //custom formatted integral number with traits like in integral_to_string
    "] ["sv,
    fmt<strconv::float_format_traits{
                                              .precision = 10,
                                              .decimal_places = 2,
                                              .padd_with = padd_with_e::space,
                                              .sign = prepend_sign_e::only_negative,
                                              .alignment = alignment_e::left,
                                              .trailing_zeros = trailing_zeros_e::skip
                                              }>(10.46713), //custom formatted floating point number with traits like in float_to_string
    "] "sv,
    fmt<ptrfmt>(0x1ff56ef001), ' ', //reuse custom constexpr formatting
    fmt<ptrfmt>(0x0)
  ) };

  constexpr auto expected{ " some view 127.300003,125[  0b111001000  ] [10.46     ] 0X1FF56EF001 0X0000"sv };

  BOOST_TEST( expected == strres );
  }
  {
  auto strres{strconv::compose( "output_filename"sv,
                   '_', strconv::fmt<strconv::integral_format_traits{
                       .precision = 4,
                       .padd_with = padd_with_e::zeros
                    }>(2),
                   '_', strconv::fmt<strconv::integral_format_traits{
                     .precision = 11,
                     .format = format_e::hexadecimal,
                     .char_case = char_case_e::lowercase,
                     .padd_with = padd_with_e::zeros,
                     .include_prefix = include_prefix_e::with_prefix
                      }>(0x1ffeb3e), ".c"sv )};
  constexpr auto expected{ "output_filename_0002_0x001ffeb3e.c"sv };
  BOOST_TEST( expected == strres );
  }
  {
  std::tm tm_value{
    .tm_sec = 3,
    .tm_min = 1,
    .tm_hour = 5,
    .tm_yday = 125
  };
  using strconv::fmt;
  constexpr strconv::integral_format_traits _22dec
    {
    .precision = 2,
    .padd_with = strconv::padd_with_e::zeros
    };
  auto strres { strconv::compose( tm_value.tm_yday," days "sv , fmt<_22dec>(tm_value.tm_hour), ':', fmt<_22dec>(tm_value.tm_min), ':', fmt<_22dec>(tm_value.tm_sec) ) };
  constexpr auto expected{ "125 days 05:01:03"sv };
  BOOST_TEST( expected == strres );
  }
}
BOOST_AUTO_TEST_SUITE_END()


//==================================================================================================
/*!
  @file

    @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_IS_DENORMAL_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_IS_DENORMAL_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

  /*!

    @ingroup group-predicates
    This function object returns @ref True or @ref False according x is denormal or not.

    @par Header <boost/simd/function/is_denormal.hpp>

    @par Note

    Using `is_denormal(x)` is similar to `(x != 0) && (abs(x) < Smallestposval<T>())`

    @see Smallestposval

    @par Example:

      @snippet is_denormal.cpp is_denormal

    @par Possible output:

      @snippet is_denormal.txt is_denormal

  **/
  as_logical_t<Value> is_denormal(Value const& x);
} }
#endif

#include <boost/simd/function/scalar/is_denormal.hpp>
#include <boost/simd/function/simd/is_denormal.hpp>

#endif


//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_HMSB_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_HMSB_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{
  /*!
    @ingroup group-reduction

    Returns a std::bitset build from the most significant bit of each value its argument.

    @param  v Value to process
    @return A std::bitset of the size of cardinal(v) containing the most signiicant bits of each
    elements of v.
  **/
  std::bitset<cardinal_of<Value>::value> hmsb(Value const & v);
} }
#endif

#include <boost/simd/function/scalar/hmsb.hpp>
#include <boost/simd/function/simd/hmsb.hpp>

#endif


// Copyright 2011-2017 Ryan Curtin (http://www.ratml.org/)
// Copyright 2017 National ICT Australia (NICTA)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ------------------------------------------------------------------------

#include <armadillo>

#include "catch.hpp"

using namespace arma;

TEST_CASE("fn_eigs_test")
  {
  for (size_t trial = 0; trial < 10; ++trial)
    {
    // Test ARPACK decomposition of sparse matrices.
    sp_mat m(1000, 1000);
    sp_vec dd;
    for (size_t i = 0; i < 10; ++i)
      {
      dd.sprandu(1000, 1, 0.15);
      double eig = 10.0 * randu<double>();
      m += eig * dd * dd.t();
      }
    mat d(m);

    // Eigendecompose, getting first 5 eigenvectors.
    vec sp_eigval;
    mat sp_eigvec;
    eigs_sym(sp_eigval, sp_eigvec, m, 5);

    // Do the same for the dense case.
    vec eigval;
    mat eigvec;
    eig_sym(eigval, eigvec, d);

    for (uword i = 0; i < 5; ++i)
      {
      // It may be pointed the wrong direction.
      REQUIRE( sp_eigval(i) == Approx(eigval(i + 995)).epsilon(0.01) );

      for (uword j = 0; j < 1000; ++j)
        {
        REQUIRE( std::abs(sp_eigvec(j, i)) ==
                 Approx(std::abs(eigvec(j, i + 995))).epsilon(0.01) );
        }
      }
    }
  }

TEST_CASE("fn_eigs_float_test")
  {
  for (size_t trial = 0; trial < 10; ++trial)
    {
    // Test ARPACK decomposition of sparse matrices.
    SpMat<float> m(100, 100);
    SpCol<float> dd;
    for (size_t i = 0; i < 10; ++i)
      {
      dd.sprandu(100, 1, 0.15);
      float eig = 10.0 * randu<float>();
      m += eig * dd * dd.t();
      }
    Mat<float> d(m);

    // Eigendecompose, getting first 5 eigenvectors.
    Col<float> sp_eigval;
    Mat<float> sp_eigvec;
    eigs_sym(sp_eigval, sp_eigvec, m, 5);

    // Do the same for the dense case.
    Col<float> eigval;
    Mat<float> eigvec;
    eig_sym(eigval, eigvec, d);

    for (uword i = 0; i < 5; ++i)
      {
      // It may be pointed the wrong direction.
      REQUIRE( sp_eigval(i) == Approx(eigval(i + 95)).epsilon(0.01) );

      for (uword j = 0; j < 100; ++j)
        {
        REQUIRE(std::abs(sp_eigvec(j, i)) ==
                Approx(std::abs(eigvec(j, i + 95))).epsilon(0.01) );
        }
      }
    }
  }

TEST_CASE("fn_eigs_sm_test")
  {
  for (size_t trial = 0; trial < 10; ++trial)
    {
    // Test ARPACK decomposition of sparse matrices.
    sp_mat m(100, 100);
    for (uword i = 0; i < 100; ++i)
      {
      m(i, i) = i + 10;
      }
    mat d(m);

    // Eigendecompose, getting first 5 eigenvectors.
    vec sp_eigval;
    mat sp_eigvec;
    eigs_sym(sp_eigval, sp_eigvec, m, 5, "sm");

    // Do the same for the dense case.
    vec eigval;
    mat eigvec;
    eig_sym(eigval, eigvec, d);

    for (size_t i = 0; i < 5; ++i)
      {
      // It may be pointed the wrong direction.
      REQUIRE( sp_eigval(i) == Approx(eigval(i)).epsilon(0.01) );

      for (size_t j = 0; j < 100; ++j)
        {
        REQUIRE( std::abs(sp_eigvec(j, i)) ==
                 Approx(std::abs(eigvec(j, i))).epsilon(0.01) );
        }
      }
    }
  }

TEST_CASE("fn_eigs_sigma_test")
  {
  const uword n_trials = 10;

  uword count = 0;

  for(uword trial=0; trial < n_trials; ++trial)
    {
    // Test ARPACK decomposition of sparse matrices.
    sp_mat m; m.sprandu(100, 100, 0.1);
    m = m.t() + m;
    for(uword i = 0; i < 100; ++i)  { m(i, i) = i + 10; }
    mat d(m);

    // Eigendecompose, getting first 5 eigenvectors around 12.1.
    vec sp_eigval;
    mat sp_eigvec;
    const bool status_sparse = eigs_sym(sp_eigval, sp_eigvec, m, 5, 12.1);

    // Do the same for the dense case.
    vec eigval;
    mat eigvec;
    const bool status_dense = eig_sym(eigval, eigvec, d);

    if(status_sparse && status_dense)
      {
      ++count;

      for(uword i = 0; i < 5; ++i)
        {
        // It may be pointed the wrong direction.
        REQUIRE( sp_eigval(i) == Approx(eigval(i)).epsilon(0.01) );

        for (size_t j = 0; j < 100; ++j)
          {
          REQUIRE( std::abs(sp_eigvec(j, i)) ==
                   Approx(std::abs(eigvec(j, i))).epsilon(0.01) );
          }
        }
      }
    }

  REQUIRE( count > 0 );
  }


#define NOHASH 1

#include <iostream>
#include <fstream>
#include <map>
#include <algorithm>

#include <CGAL/Surface_mesh.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/IO/Polyhedron_iostream.h>

#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
#include <CGAL/boost/graph/graph_traits_Polyhedron_3.h>
#include <CGAL/boost/graph/properties_Polyhedron_3.h>
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/Timer.h>
#include<boost/range/iterator_range.hpp>
#include <boost/unordered_map.hpp>
#include <unordered_map>

#include <boost/random/random_number_generator.hpp>
#include <boost/random/linear_congruential.hpp>

typedef CGAL::Simple_cartesian<double>  Kernel;
typedef Kernel::Point_3                 Point_3;
typedef Kernel::Vector_3                Vector_3;

typedef CGAL::Timer                     Timer;

template <typename G, typename Map>
void
run(const G& g)
{
  typedef typename boost::graph_traits<G>::vertex_descriptor vertex_descriptor;

  typedef typename boost::property_map<G,CGAL::vertex_point_t>::const_type  VPM;
  VPM vpm = get(CGAL::vertex_point,g);

  std::vector<vertex_descriptor> V, V2;
  std::vector<Point_3> P1, P2;

  for(vertex_descriptor vd : vertices(g)){
    V.push_back(vd);
    V2.push_back(vd);
  }

  boost::rand48 random;
  boost::random_number_generator<boost::rand48> rng(random);
  std::random_shuffle(V.begin(), V.end(), rng);

  Timer t;
#if 0
  t.start();
  Map vm;
  for(vertex_descriptor vd : V){
    vm[vd] = get(vpm,vd);
  }
  t.stop();  std::cerr << "Insertion:  " << t.time() << " sec.     " << std::endl;
#endif

  Vector_3 v(0,0,0);
  std::size_t st=0;

#if 0
  std::cerr << "foreach std::vector<vertex_descriptor)\n";
  t.reset(); t.start();
  for(int i=0; i<100; i++){
  for(vertex_descriptor vd : V2){
#ifdef NOHASH
    st += std::size_t(vd);
#else
    typename Map::iterator it = vm.find(vd);
    v = v + ((*it).second - CGAL::ORIGIN);
#endif
  }
  }

  t.stop();  std::cerr << "  " <<t.time() << " sec.     " << std::endl;
#endif

#if 1
  std::cerr << "foreach boost::iterator_range r = vertices(g))\n";

  t.reset(); t.start();
  for(int i=0; i<100; i++){
  boost::iterator_range<typename boost::graph_traits<G>::vertex_iterator> r = vertices(g);

  for(vertex_descriptor vd : r) {
#ifdef NOHASH
    st += std::size_t(vd);
    // v = v + (get(vpm,vd) - CGAL::ORIGIN);
#else
    typename Map::iterator it = vm.find(vd);
    v = v + ((*it).second - CGAL::ORIGIN);
#endif
  }
  }
  t.stop();  std::cerr << "  " <<t.time() << " sec.     " << std::endl;
#endif

#if 1
   std::cerr << "foreach CGAL::Iterator_range r = vertices(g))\n";
  t.reset(); t.start();
  for(int i=0; i<100; i++){
  CGAL::Iterator_range<typename boost::graph_traits<G>::vertex_iterator> ir = vertices(g);
  for(vertex_descriptor vd : ir) {
#ifdef NOHASH
    st += std::size_t(vd);
    //v = v + (get(vpm,vd) - CGAL::ORIGIN);
#else
    typename Map::iterator it = vm.find(vd);
    v = v + ((*it).second - CGAL::ORIGIN);
#endif
  }
  }
  t.stop();  std::cerr << "  " <<t.time() << " sec.     " << std::endl;

#endif

#if 1
  std::cerr << "foreach vertices(g))\n";
  t.reset(); t.start();
  for(int i=0; i<100; i++){
  for(vertex_descriptor vd : vertices(g)) {
#ifdef NOHASH
    st += std::size_t(vd);
    //v = v + (get(vpm,vd) - CGAL::ORIGIN);
#else
    typename Map::iterator it = vm.find(vd);
    v = v + ((*it).second - CGAL::ORIGIN);
#endif
  }
  }
  t.stop();  std::cerr << "  " <<t.time() << " sec.     " << std::endl;
#endif

#if 1
  std::cerr << "for vertices(g))\n";
  t.reset(); t.start();
  for(int i=0; i<100; i++){
    for(vertex_descriptor vd : vertices(g)) {
#ifdef NOHASH
    st += std::size_t(vd);
    //v = v + (get(vpm,vd) - CGAL::ORIGIN);
#else
    typename Map::iterator it = vm.find(vd);
    v = v + ((*it).second - CGAL::ORIGIN);
#endif
  }
  }
  t.stop();  std::cerr << "  " <<t.time() << " sec.     " << std::endl;

#endif

#if 0
  std::cerr << "boost::tie(vb,ve) = vertices(g);\n";
  t.reset(); t.start();
    for(int i=0; i<100; i++){
  typename boost::graph_traits<G>::vertex_iterator vb, ve;
  boost::tie(vb,ve) = vertices(g);
  for(; vb != ve; ++vb) {
    vertex_descriptor vd = *vb;
#ifdef NOHASH
    st += std::size_t(vd);
    //v = v + (get(vpm,vd) - CGAL::ORIGIN);
#else
    typename Map::iterator it = vm.find(vd);
    v = v + ((*it).second - CGAL::ORIGIN);
#endif
  }
    }
  t.stop();  std::cerr << "  " <<t.time() << " sec.     " << std::endl;
#endif

  std::cerr << "v = " << v << "  " << st << std::endl;

}

struct blob {
  int a, b, c, d, e, f, g;
};

int main(int , char* argv[])
{

  {
    typedef CGAL::Surface_mesh<Point_3>     Mesh;
    typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
    typedef std::map<vertex_descriptor,Point_3> SM;
    typedef std::unordered_map<vertex_descriptor,Point_3> SUM;
    typedef boost::unordered_map<vertex_descriptor,Point_3> BUM;

    Mesh m;
    std::ifstream input(argv[1]);
    input >> m;

    std::cerr << num_vertices(m) << " items\n";
    std::cerr << "\nSurface_mesh  std::map"<< std::endl;
    run<Mesh,SM>(m);
#if 0
    std::cerr << "\nSurface_mesh  std::unordered_map"<< std::endl;
    run<Mesh,SUM>(m);
    std::cerr << "\nSurface_mesh  boost::unordered_map"<< std::endl;
    run<Mesh,BUM>(m);
#endif
  }

#if 0
  {
    typedef CGAL::Polyhedron_3<Kernel>      Mesh;
    typedef boost::graph_traits<Mesh>::vertex_descriptor vertex_descriptor;
    typedef std::map<vertex_descriptor,Point_3> SM;
    typedef std::unordered_map<vertex_descriptor,Point_3> SUM;
    typedef boost::unordered_map<vertex_descriptor,Point_3> BUM;

    Mesh m;
    std::ifstream input(argv[1]);
    input >> m;

    std::cerr << "\nPolyhedron_3  std::map" << std::endl;
    run<Mesh,SM>(m);
    std::cerr << "\nPolyhedron_3 std::unordered_map"<< std::endl;
    run<Mesh,SUM>(m);
    std::cerr << "\nPolyhedron_3 boost::unordered_map"<< std::endl;
    run<Mesh,BUM>(m);
  }

  {
    const int N = 3165798;
    std::cerr << "\nHashing "<< N << " pointers\n";
    std::vector<int> ints(N);

    std::vector<blob> data(N);
    for(int i =0; i <N ; i++){
      ints[i]=i;
    }
    std::random_shuffle(ints.begin(), ints.end());

    {
      boost::unordered_map<blob*,int> um;
      Timer t;
      t.start();
      for(int i= 0; i < N; i++){
        um[& (data[ints[i]])] = i;
      }
      t.stop();
      std::cerr << " boost::unordered_map: " <<  t.time() << " sec.\n";
    }

    {
      std::unordered_map<blob*,int> um;
      Timer t;
      t.start();
      for(int i= 0; i < N; i++){
        um[& (data[ints[i]])] = i;
      }
      t.stop();
      std::cerr  << " std::unordered_map: " << t.time() << " sec.\n";
    }
  }
#endif

  return 0;
}


///////////////////////////////////////////////////////////////////////////////
//  Copyright Paul Bristow 2015.
//  Copyright Christopher Kormanyos 2015.
//  Copyright Nikhar Agrawal 2015.
//  Distributed under the Boost Software License,
//  Version 1.0. (See accompanying file LICENSE_1_0.txt
//  or copy at http://www.boost.org/LICENSE_1_0.txt)
//

//! \file
//!\brief Basic tests for fixed_point.

#define BOOST_TEST_MODULE test_negatable_basic_construct
#define BOOST_LIB_DIAGNOSTIC

#include <boost/test/included/unit_test.hpp>

#include <iostream>
#include <iomanip>
#include <sstream>

#include "boost/fixed_point/fixed_point.hpp"

BOOST_AUTO_TEST_CASE(test_negatable_basic_construct_nearest_even_round)
{
  //! small range and resolution
  {
    typedef boost::fixed_point::negatable<4, -2, boost::fixed_point::round::nearest_even> fixed_point_type_nearest_even_round;
    fixed_point_type_nearest_even_round x = fixed_point_type_nearest_even_round (-1.375);
    fixed_point_type_nearest_even_round y = fixed_point_type_nearest_even_round(-1.5);

    BOOST_CHECK_EQUAL(x, y);

    x = fixed_point_type_nearest_even_round (1.375);
    y = fixed_point_type_nearest_even_round (1.5);

    BOOST_CHECK_EQUAL(x, y);

    BOOST_CHECK_EQUAL(fixed_point_type_nearest_even_round::all_bits, 7);
    BOOST_CHECK_EQUAL(fixed_point_type_nearest_even_round::range, 4);
    BOOST_CHECK_EQUAL(fixed_point_type_nearest_even_round::resolution, -2);
    BOOST_CHECK_EQUAL(x.all_bits, 7);
    BOOST_CHECK_EQUAL(y.range, 4);
    BOOST_CHECK_EQUAL(x.resolution, -2);
  }

  //! larger range and small resolution
  {
    typedef boost::fixed_point::negatable<400, -2, boost::fixed_point::round::nearest_even> fixed_point_type_nearest_even_round;
    fixed_point_type_nearest_even_round x = fixed_point_type_nearest_even_round (-1.375);
    fixed_point_type_nearest_even_round y = fixed_point_type_nearest_even_round(-1.5);

    BOOST_CHECK_EQUAL(x, y);

    x = fixed_point_type_nearest_even_round (1.375);
    y = fixed_point_type_nearest_even_round (1.5);

    BOOST_CHECK_EQUAL(x, y);

    BOOST_CHECK_EQUAL(fixed_point_type_nearest_even_round::all_bits, 403);
    BOOST_CHECK_EQUAL(fixed_point_type_nearest_even_round::range, 400);
    BOOST_CHECK_EQUAL(fixed_point_type_nearest_even_round::resolution, -2);
  }

  //! larger range and larger resolution
  {
    typedef boost::fixed_point::negatable<87, -4, boost::fixed_point::round::nearest_even> fixed_point_type_nearest_even_round;
    fixed_point_type_nearest_even_round x = fixed_point_type_nearest_even_round (-605.28125);
    fixed_point_type_nearest_even_round y = fixed_point_type_nearest_even_round(-605.25);

    BOOST_CHECK_EQUAL(x, y);

    x = fixed_point_type_nearest_even_round (605.28125);
    y = fixed_point_type_nearest_even_round (605.25);

    BOOST_CHECK_EQUAL(x, y);

    BOOST_CHECK_EQUAL(fixed_point_type_nearest_even_round::all_bits, 92);
    BOOST_CHECK_EQUAL(fixed_point_type_nearest_even_round::range, 87);
    BOOST_CHECK_EQUAL(fixed_point_type_nearest_even_round::resolution, -4);
  }
}

BOOST_AUTO_TEST_CASE(test_negatable_basic_construct_fastest_round)
{
  //! small range and resolution
  {
    typedef boost::fixed_point::negatable<4, -2, boost::fixed_point::round::fastest> fixed_point_type_fastest_round;
    fixed_point_type_fastest_round x = fixed_point_type_fastest_round (-1.33);
    fixed_point_type_fastest_round y = fixed_point_type_fastest_round(-1.25);
    fixed_point_type_fastest_round z = fixed_point_type_fastest_round(-1.5);

    BOOST_CHECK_EQUAL(x == y || x == z, true);

    x = fixed_point_type_fastest_round (1.33);
    y = fixed_point_type_fastest_round (1.25);
    z = fixed_point_type_fastest_round (1.5);

    BOOST_CHECK_EQUAL(x == y || x == z, true);
  }

  //! larger range and small resolution
  {
    typedef boost::fixed_point::negatable<400, -2, boost::fixed_point::round::fastest> fixed_point_type_fastest_round;
    fixed_point_type_fastest_round x = fixed_point_type_fastest_round (-1.33);
    fixed_point_type_fastest_round y = fixed_point_type_fastest_round(-1.25);
    fixed_point_type_fastest_round z = fixed_point_type_fastest_round(-1.5);

    BOOST_CHECK_EQUAL(x == y || x == z, true);

    x = fixed_point_type_fastest_round (1.33);
    y = fixed_point_type_fastest_round (1.25);
    z = fixed_point_type_fastest_round (1.5);

    BOOST_CHECK_EQUAL(x == y || x == z, true);
  }

  //! larger range and larger resolution
  {
    typedef boost::fixed_point::negatable<87, -4, boost::fixed_point::round::fastest> fixed_point_type_fastest_round;
    fixed_point_type_fastest_round x = fixed_point_type_fastest_round (-6053.2777);
    fixed_point_type_fastest_round y = fixed_point_type_fastest_round(-6053.3125);
    fixed_point_type_fastest_round z = fixed_point_type_fastest_round(-6053.25);

    BOOST_CHECK_EQUAL(x == y || x == z, true);

    x = fixed_point_type_fastest_round (6053.2777);
    y = fixed_point_type_fastest_round (6053.3125);
    z = fixed_point_type_fastest_round (6053.25);

    BOOST_CHECK_EQUAL(x == y || x == z, true);
  }
}


/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *  Copyright (c) 2012-, Open Perception, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the copyright holder(s) nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */
#ifndef PCL_REGISTRATION_IMPL_CORRESPONDENCE_REJECTION_SAMPLE_CONSENSUS_HPP_
#define PCL_REGISTRATION_IMPL_CORRESPONDENCE_REJECTION_SAMPLE_CONSENSUS_HPP_

#include <boost/unordered_map.hpp>

///////////////////////////////////////////////////////////////////////////////////////////
template <typename PointT> void
pcl::registration::CorrespondenceRejectorSampleConsensus<PointT>::getRemainingCorrespondences (
    const pcl::Correspondences& original_correspondences,
    pcl::Correspondences& remaining_correspondences)
{
  if (!input_)
  {
    PCL_ERROR ("[pcl::registration::%s::getRemainingCorrespondences] No input cloud dataset was given!\n", getClassName ().c_str ());
    return;
  }

  if (!target_)
  {
    PCL_ERROR ("[pcl::registration::%s::getRemainingCorrespondences] No input target dataset was given!\n", getClassName ().c_str ());
    return;
  }

  if (save_inliers_)
     inlier_indices_.clear ();

  int nr_correspondences = static_cast<int> (original_correspondences.size ());
  std::vector<int> source_indices (nr_correspondences);
  std::vector<int> target_indices (nr_correspondences);

  // Copy the query-match indices
  for (size_t i = 0; i < original_correspondences.size (); ++i)
  {
    source_indices[i] = original_correspondences[i].index_query;
    target_indices[i] = original_correspondences[i].index_match;
  }

   // from pcl/registration/icp.hpp:
   std::vector<int> source_indices_good;
   std::vector<int> target_indices_good;
   {
     // From the set of correspondences found, attempt to remove outliers
     // Create the registration model
     typedef typename pcl::SampleConsensusModelRegistration<PointT>::Ptr SampleConsensusModelRegistrationPtr;
     SampleConsensusModelRegistrationPtr model;
     model.reset (new pcl::SampleConsensusModelRegistration<PointT> (input_, source_indices));
     // Pass the target_indices
     model->setInputTarget (target_, target_indices);
     // Create a RANSAC model
     pcl::RandomSampleConsensus<PointT> sac (model, inlier_threshold_);
     sac.setMaxIterations (max_iterations_);

     // Compute the set of inliers
     if (!sac.computeModel ())
     {
       remaining_correspondences = original_correspondences;
       best_transformation_.setIdentity ();
       return;
     }
     else
     {
       if (refine_ && !sac.refineModel ())
       {
         PCL_ERROR ("[pcl::registration::CorrespondenceRejectorSampleConsensus::getRemainingCorrespondences] Could not refine the model! Returning an empty solution.\n");
         return;
       }

       std::vector<int> inliers;
       sac.getInliers (inliers);

       if (inliers.size () < 3)
       {
         remaining_correspondences = original_correspondences;
         best_transformation_.setIdentity ();
         return;
       }
       boost::unordered_map<int, int> index_to_correspondence;
       for (int i = 0; i < nr_correspondences; ++i)
         index_to_correspondence[original_correspondences[i].index_query] = i;

       remaining_correspondences.resize (inliers.size ());
       for (size_t i = 0; i < inliers.size (); ++i)
         remaining_correspondences[i] = original_correspondences[index_to_correspondence[inliers[i]]];

       if (save_inliers_)
       {
         inlier_indices_.reserve (inliers.size ());
         for (size_t i = 0; i < inliers.size (); ++i)
           inlier_indices_.push_back (index_to_correspondence[inliers[i]]);
       }

       // get best transformation
       Eigen::VectorXf model_coefficients;
       sac.getModelCoefficients (model_coefficients);
       best_transformation_.row (0) = model_coefficients.segment<4>(0);
       best_transformation_.row (1) = model_coefficients.segment<4>(4);
       best_transformation_.row (2) = model_coefficients.segment<4>(8);
       best_transformation_.row (3) = model_coefficients.segment<4>(12);
     }
   }
}

#endif    // PCL_REGISTRATION_IMPL_CORRESPONDENCE_REJECTION_SAMPLE_CONSENSUS_HPP_


#ifndef STAN_MATH_PRIM_MAT_FUN_MDIVIDE_LEFT_SPD_HPP
#define STAN_MATH_PRIM_MAT_FUN_MDIVIDE_LEFT_SPD_HPP

#include <boost/math/tools/promotion.hpp>
#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/fun/promote_common.hpp>
#include <stan/math/prim/mat/err/check_multiplicable.hpp>
#include <stan/math/prim/mat/err/check_pos_definite.hpp>

namespace stan {
namespace math {

/**
 * Returns the solution of the system Ax=b where A is symmetric positive
 * definite.
 * @param A Matrix.
 * @param b Right hand side matrix or vector.
 * @return x = A^-1 b, solution of the linear system.
 * @throws std::domain_error if A is not square or the rows of b don't
 * match the size of A.
 */
template <typename T1, typename T2, int R1, int C1, int R2, int C2>
inline Eigen::Matrix<return_type_t<T1, T2>, R1, C2> mdivide_left_spd(
    const Eigen::Matrix<T1, R1, C1> &A, const Eigen::Matrix<T2, R2, C2> &b) {
  check_multiplicable("mdivide_left_spd", "A", A, "b", b);
  check_pos_definite("mdivide_left_spd", "A", A);
  return promote_common<Eigen::Matrix<T1, R1, C1>, Eigen::Matrix<T2, R1, C1> >(
             A)
      .llt()
      .solve(
          promote_common<Eigen::Matrix<T1, R2, C2>, Eigen::Matrix<T2, R2, C2> >(
              b));
}

}  // namespace math
}  // namespace stan
#endif