/* Copyright 2015, 2016, Michele Santullo
* This file is part of "dindexer".
*
* "dindexer" is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* "dindexer" is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with "dindexer". If not, see .
*/
#ifndef id942A6B5AB2AF443C82D4321775BFC9E8
#define id942A6B5AB2AF443C82D4321775BFC9E8
#include "compatibility.h"
#include "helpers/sequence_bt.hpp"
#include "helpers/MaxSizedArray.hpp"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace dinhelp {
namespace customize {
template
struct index_array_to_string;
template
struct char_to_int;
} //namespace customize
namespace implem {
template
typename std::make_unsigned::type abs ( T parValue ) a_pure;
template int count_leading_zeroes ( typename std::enable_if::is_signed, T>::type parValue ) a_always_inline;
template int count_leading_zeroes ( typename std::enable_if::is_signed, T>::type parValue ) a_always_inline;
int count_leading_zeroes_overload ( unsigned char parValue ) a_always_inline;
int count_leading_zeroes_overload ( unsigned short int parValue ) a_always_inline;
int count_leading_zeroes_overload ( unsigned int parValue ) a_always_inline;
int count_leading_zeroes_overload ( unsigned long parValue ) a_always_inline;
int count_leading_zeroes_overload ( unsigned long long parValue ) a_always_inline;
template
struct power {
enum { value = Base * power::value };
};
template
struct power {
enum { value = 1 };
};
template ::is_signed>
struct is_negative;
template
struct is_negative {
static int check (T parValue) { return (parValue < 0 ? 1 : 0); }
};
template
struct is_negative {
static constexpr int check (T) { return 0; }
};
template class Tag, typename T, typename F>
inline auto int_to_string (const F parFrom) -> MaxSizedArray::count_digits_bt(std::numeric_limits::type>::max())> {
using ArrayRetType = MaxSizedArray::count_digits_bt(std::numeric_limits::type>::max())>;
ArrayRetType retval;
F div = 1;
constexpr const std::size_t charset_offs = (Tag::lower_case ? Tag::base : 0);
const auto sign_length = (is_negative::check(parFrom) and Tag::sign_allowed ? 1 : 0);
for (std::size_t z = 0; z < Tag::count_digits(parFrom) - sign_length; ++z) {
retval.push_back(static_cast(((Tag::make_unsigned(parFrom) / div) % Tag::base) + charset_offs));
div *= Tag::base;
}
std::reverse(retval.begin(), retval.end());
return retval;
};
template class Tag, typename T, typename F>
inline T string_to_int (const F& parFrom) {
T retval(0);
T mul(1);
for (auto chara : boost::adaptors::reverse(parFrom)) {
retval += dinhelp::customize::char_to_int::make(chara) * mul;
mul *= Tag::base;
}
return retval * dinhelp::customize::char_to_int::sgn(parFrom);
};
template
struct hex {
enum {
base = 16,
sign_allowed = 0,
lower_case = (LowerCase ? 1 : 0)
};
static std::size_t count_digits ( T parValue ) a_pure;
static typename std::make_unsigned::type make_unsigned ( T parValue ) a_pure;
static constexpr std::size_t count_digits_bt (std::size_t parNum) {
return (parNum == 0 ? 0 : static_cast(std::log10(static_cast(parNum)) / std::log10(static_cast(base)))) + 1;
}
};
} //namespace implem
namespace tags {
template
struct dec {
enum {
base = 10,
sign_allowed = 1,
lower_case = 0
};
template
static std::size_t count_digits_implem (T parValue, dinhelp::bt::index_seq, dinhelp::bt::index_seq) a_pure;
static std::size_t count_digits (T parValue) a_pure;
static typename std::make_unsigned::type make_unsigned ( T parValue ) a_pure;
static constexpr std::size_t count_digits_bt (std::size_t parNum) {
return (parNum == 0 ? 0 : static_cast(std::log10(static_cast(parNum)))) + 1 + (std::numeric_limits::is_signed ? 1 : 0);
}
};
template
using hex = dinhelp::implem::hex;
template
using hexl = dinhelp::implem::hex;
template
struct bin {
enum {
base = 2,
sign_allowed = 0,
lower_case = 0
};
static std::size_t count_digits ( T parValue ) a_pure;
static typename std::make_unsigned::type make_unsigned ( T parValue ) a_pure;
static constexpr std::size_t count_digits_bt (std::size_t parNum) {
return (parNum == 0 ? 0 : static_cast(std::log2(static_cast(parNum)))) + 1;
}
};
//See: http://stackoverflow.com/questions/9721042/count-number-of-digits-which-method-is-most-efficient#9721113
template
template
std::size_t dec::count_digits_implem (T parValue, dinhelp::bt::index_seq, dinhelp::bt::index_seq) {
typedef typename std::make_unsigned::type UT;
static constexpr UT powers[] = { 0, static_cast(dinhelp::implem::power<10, Powers + 1>::value)... };
static constexpr std::size_t maxdigits[] = { count_digits_bt(static_cast(::pow(2.0, Digits))) - (std::numeric_limits::is_signed ? 1 : 0)... };
const auto bits = sizeof(parValue) * CHAR_BIT - dinhelp::implem::count_leading_zeroes(dinhelp::implem::abs(parValue));
static_assert(std::is_same::value, "Unexpected type");
return (dinhelp::implem::abs(parValue) < powers[maxdigits[bits] - 1] ? maxdigits[bits] - 1 : maxdigits[bits]) + dinhelp::implem::is_negative::check(parValue);
}
template
std::size_t dec::count_digits (T parValue) {
return count_digits_implem(
parValue,
dinhelp::bt::index_range<0, count_digits_bt(std::numeric_limits::max()) - (std::numeric_limits::is_signed ? 1 : 0) - 1>(),
dinhelp::bt::index_range<0, CHAR_BIT * sizeof(T) + 1>()
);
}
template
typename std::make_unsigned::type dec::make_unsigned (T parValue) {
return dinhelp::implem::abs(parValue);
}
template
std::size_t bin::count_digits (T parValue) {
return std::max((sizeof(parValue) * CHAR_BIT - dinhelp::implem::count_leading_zeroes::type>(make_unsigned(parValue))), 1);
}
template
typename std::make_unsigned::type bin::make_unsigned (T parValue) {
return static_cast::type>(parValue);
}
} //namespace tags
namespace implem {
template class Tag>
struct lexical_cast {
template
static T convert ( const typename std::enable_if::value, F>::type& parFrom ) {
const auto indices = int_to_string(parFrom);
return dinhelp::customize::index_array_to_string::make(indices, is_negative::check(parFrom) bitand Tag::sign_allowed);
}
template
static typename std::enable_if::value, T>::type convert ( const F& parFrom ) {
return string_to_int(parFrom);
}
};
template
inline int count_leading_zeroes (typename std::enable_if::is_signed, T>::type parValue) {
return count_leading_zeroes(dinhelp::implem::abs(parValue));
}
template
inline int count_leading_zeroes (typename std::enable_if::is_signed, T>::type parValue) {
return count_leading_zeroes_overload(parValue) + sizeof(T) * CHAR_BIT;
}
inline int count_leading_zeroes_overload (unsigned char parValue) {
return __builtin_clz(parValue) - sizeof(unsigned int) * CHAR_BIT;
}
inline int count_leading_zeroes_overload (unsigned short int parValue) {
return __builtin_clz(parValue) - sizeof(unsigned int) * CHAR_BIT;
}
inline int count_leading_zeroes_overload (unsigned int parValue) {
return __builtin_clz(parValue) - sizeof(unsigned int) * CHAR_BIT;
}
inline int count_leading_zeroes_overload (unsigned long parValue) {
return __builtin_clzl(parValue) - sizeof(unsigned long) * CHAR_BIT;
}
inline int count_leading_zeroes_overload (unsigned long long parValue) {
return __builtin_clzll(parValue) - sizeof(unsigned long long) * CHAR_BIT;
}
//See: http://stackoverflow.com/questions/16101062/why-does-stdabs-return-signed-types
template
typename std::make_unsigned::type abs (T parValue) {
//We need to cast before negating x to avoid the overflow.
return (parValue < 0 ? -static_cast::type>(parValue) : parValue);
}
template
std::size_t hex::count_digits (T parValue) {
return std::max(((sizeof(parValue) * CHAR_BIT - dinhelp::implem::count_leading_zeroes::type>(make_unsigned(parValue))) + (CHAR_BIT / 2 - 1)) / (CHAR_BIT / 2), 1);
}
template
typename std::make_unsigned::type hex::make_unsigned (T parValue) {
return static_cast::type>(parValue);
}
} //namespace implem
template class Tag=tags::dec, typename F=void>
inline T lexical_cast (const F& parFrom) {
return dinhelp::implem::lexical_cast::template convert(parFrom);
}
namespace customize {
template<>
struct index_array_to_string {
template
static std::string make (const MaxSizedArray &parIndices, int parNegative) {
static const char symbols[] = {'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'A', 'B',
'C', 'D', 'E', 'F',
'0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b',
'c', 'd', 'e', 'f'
};
std::string retval(parIndices.size() + parNegative, '-');
for (auto z = parNegative; z < static_cast(parIndices.size()) + parNegative; ++z) {
retval[z] = symbols[parIndices[z - parNegative]];
}
return retval;
}
};
template
struct char_to_int {
static T make (char parChar) {
if (parChar >= '0' and parChar <= '9')
return parChar - '0';
else if (parChar >= 'a' and parChar <= 'f')
return 10 + parChar - 'a';
else if (parChar >= 'A' and parChar <= 'F')
return 10 + parChar - 'A';
else if (parChar == '-')
return 0;
return 0;
}
template
static T sgn (const Container& parString) {
return static_cast(std::numeric_limits::is_signed and parString.begin() != parString.end() and *parString.begin() == '-' ? -1 : 1);
}
};
} //namespace customize
} //namespace dinhelp
#endif