mirror of
https://github.com/KingDuckZ/dindexer.git
synced 2024-11-29 01:33:46 +00:00
Add dedicated tests for lexical_cast and fix failures I found.
This commit is contained in:
parent
7ae8b95599
commit
2c5030f929
3 changed files with 147 additions and 33 deletions
|
@ -20,11 +20,11 @@
|
|||
|
||||
#include "compatibility.h"
|
||||
#include "helpers/sequence_bt.hpp"
|
||||
#include "helpers/MaxSizedArray.hpp"
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <limits>
|
||||
#include <math.h>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
@ -42,10 +42,10 @@ namespace dinhelp {
|
|||
} //namespace customize
|
||||
|
||||
namespace implem {
|
||||
template <typename T>
|
||||
inline constexpr std::size_t max_digits() {
|
||||
return static_cast<std::size_t>(::log(std::numeric_limits<T>::max()));
|
||||
}
|
||||
int count_leading_zeroes ( uint8_t parValue ) a_always_inline;
|
||||
int count_leading_zeroes ( uint16_t parValue ) a_always_inline;
|
||||
int count_leading_zeroes ( uint32_t parValue ) a_always_inline;
|
||||
int count_leading_zeroes ( uint64_t parValue ) a_always_inline;
|
||||
|
||||
template <std::size_t Base, std::size_t Val>
|
||||
struct power {
|
||||
|
@ -56,26 +56,17 @@ namespace dinhelp {
|
|||
enum { value = 1 };
|
||||
};
|
||||
|
||||
constexpr std::size_t count_digits_10_compiletime (std::size_t parNum) {
|
||||
return (parNum == 0 ? 0 : static_cast<std::size_t>(::log10(parNum))) + 1;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
struct maxdigits {
|
||||
enum { value = count_digits_10_compiletime(static_cast<std::size_t>(::pow(2.0, static_cast<double>(N)))) };
|
||||
};
|
||||
|
||||
template <template <typename> class Tag, typename T, typename F>
|
||||
inline std::array<uint8_t, max_digits<T>()> int_to_string (const F& parFrom) {
|
||||
using ArrayRetType = std::array<uint8_t, max_digits<T>()>;
|
||||
inline auto int_to_string (const F& parFrom) -> MaxSizedArray<uint8_t, Tag<F>::count_digits_bt(std::numeric_limits<F>::max())> {
|
||||
using ArrayRetType = MaxSizedArray<uint8_t, Tag<F>::count_digits_bt(std::numeric_limits<F>::max())>;
|
||||
|
||||
ArrayRetType retval;
|
||||
F div = 1;
|
||||
for (std::size_t z = 0; z < Tag<F>::count_digits(parFrom); ++z) {
|
||||
retval[Tag<F>::count_digits(parFrom) - z - 1] = static_cast<uint8_t>((parFrom / div) % Tag<F>::base);
|
||||
retval.push_back(static_cast<uint8_t>((parFrom / div) % Tag<F>::base));
|
||||
div *= Tag<F>::base;
|
||||
}
|
||||
std::fill(retval.begin() + Tag<F>::count_digits(parFrom), retval.end(), 0xff);
|
||||
std::reverse(retval.begin(), retval.end());
|
||||
return retval;
|
||||
};
|
||||
|
||||
|
@ -96,12 +87,14 @@ namespace dinhelp {
|
|||
struct dec {
|
||||
enum { base = 10 };
|
||||
|
||||
template <T... Powers, std::size_t... Digits>
|
||||
static std::size_t count_digits (
|
||||
T parValue,
|
||||
dinhelp::bt::index_seq<Powers...> = dinhelp::bt::index_range<0, dinhelp::implem::max_digits<T>()>(),
|
||||
dinhelp::bt::index_seq<Digits...> = dinhelp::bt::index_range<0, CHAR_BIT * sizeof(T)>()
|
||||
) a_pure;
|
||||
template <std::size_t... Powers, std::size_t... Digits>
|
||||
static std::size_t count_digits_implem (T parValue, dinhelp::bt::index_seq<Powers...>, dinhelp::bt::index_seq<Digits...>) a_pure;
|
||||
|
||||
static std::size_t count_digits (T parValue) a_pure;
|
||||
|
||||
static constexpr std::size_t count_digits_bt (std::size_t parNum) {
|
||||
return (parNum == 0 ? 0 : static_cast<std::size_t>(::log10(parNum))) + 1;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -109,21 +102,33 @@ namespace dinhelp {
|
|||
enum { base = 16 };
|
||||
|
||||
static std::size_t count_digits ( T parValue ) a_pure;
|
||||
static constexpr std::size_t count_digits_bt (std::size_t parNum) {
|
||||
return (parNum == 0 ? 0 : static_cast<std::size_t>(::log10(parNum) / ::log10(base))) + 1;
|
||||
}
|
||||
};
|
||||
|
||||
//See: http://stackoverflow.com/questions/9721042/count-number-of-digits-which-method-is-most-efficient#9721113
|
||||
template <typename T>
|
||||
template <T... Powers, std::size_t... Digits>
|
||||
std::size_t dec<T>::count_digits (T parValue, dinhelp::bt::index_seq<Powers...>, dinhelp::bt::index_seq<Digits...>) {
|
||||
static T powers[] = { 0, dinhelp::implem::power<10, Powers + 1>::value... };
|
||||
static std::size_t maxdigits[] = { dinhelp::implem::maxdigits<Digits>::value... };
|
||||
const auto bits = sizeof(parValue) * CHAR_BIT - __builtin_clz(parValue);
|
||||
template <std::size_t... Powers, std::size_t... Digits>
|
||||
std::size_t dec<T>::count_digits_implem (T parValue, dinhelp::bt::index_seq<Powers...>, dinhelp::bt::index_seq<Digits...>) {
|
||||
static T powers[] = { 0, static_cast<T>(dinhelp::implem::power<10, Powers + 1>::value)... };
|
||||
static std::size_t maxdigits[] = { count_digits_bt(static_cast<std::size_t>(::pow(2.0, Digits)))... };
|
||||
const auto bits = sizeof(parValue) * CHAR_BIT - dinhelp::implem::count_leading_zeroes(parValue);
|
||||
return (parValue < powers[maxdigits[bits] - 1] ? maxdigits[bits] - 1 : maxdigits[bits]);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t dec<T>::count_digits (T parValue) {
|
||||
return count_digits_implem(
|
||||
parValue,
|
||||
dinhelp::bt::index_range<0, count_digits_bt(std::numeric_limits<T>::max()) + 1>(),
|
||||
dinhelp::bt::index_range<0, CHAR_BIT * sizeof(T) + 1>()
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t hex<T>::count_digits (T parValue) {
|
||||
return std::max(((sizeof(parValue) * CHAR_BIT - __builtin_clz(parValue)) + (CHAR_BIT / 2 - 1)) / (CHAR_BIT / 2), 1);
|
||||
return std::max<std::size_t>(((sizeof(parValue) * CHAR_BIT - dinhelp::implem::count_leading_zeroes(parValue)) + (CHAR_BIT / 2 - 1)) / (CHAR_BIT / 2), 1);
|
||||
}
|
||||
} //namespace tags
|
||||
|
||||
|
@ -141,6 +146,22 @@ namespace dinhelp {
|
|||
return string_to_int<Tag, T, F>(parFrom);
|
||||
}
|
||||
};
|
||||
|
||||
inline int count_leading_zeroes (uint8_t parValue) {
|
||||
return __builtin_clz(parValue) - (sizeof(unsigned int) * CHAR_BIT - sizeof(uint8_t) * CHAR_BIT);
|
||||
}
|
||||
|
||||
inline int count_leading_zeroes (uint16_t parValue) {
|
||||
return __builtin_clz(parValue) - (sizeof(unsigned int) * CHAR_BIT - sizeof(uint16_t) * CHAR_BIT);
|
||||
}
|
||||
|
||||
inline int count_leading_zeroes (uint32_t parValue) {
|
||||
return __builtin_clzl(parValue) - (sizeof(unsigned long) * CHAR_BIT - sizeof(uint32_t) * CHAR_BIT);
|
||||
}
|
||||
|
||||
inline int count_leading_zeroes (uint64_t parValue) {
|
||||
return __builtin_clzll(parValue) - (sizeof(unsigned long long) * CHAR_BIT - sizeof(uint64_t) * CHAR_BIT);
|
||||
}
|
||||
} //namespace implem
|
||||
|
||||
template <typename T, template <typename> class Tag=tags::dec, typename F=void>
|
||||
|
@ -152,12 +173,12 @@ namespace dinhelp {
|
|||
template<>
|
||||
struct index_array_to_string<std::string> {
|
||||
template<std::size_t N>
|
||||
static std::string make (const std::array<uint8_t, N> &parIndices) {
|
||||
static std::string make (const MaxSizedArray<uint8_t, N> &parIndices) {
|
||||
static const char symbols[] = {'0', '1', '2', '3', '4', '5',
|
||||
'6', '7', '8', '9', 'A', 'B',
|
||||
'C', 'D', 'E', 'F'};
|
||||
std::string retval(N, ' ');
|
||||
for (std::size_t z = 0; z < N; ++z) {
|
||||
std::string retval(parIndices.size(), ' ');
|
||||
for (std::size_t z = 0; z < parIndices.size(); ++z) {
|
||||
retval[z] = symbols[parIndices[z]];
|
||||
}
|
||||
return retval;
|
||||
|
|
|
@ -5,6 +5,7 @@ add_executable(${PROJECT_NAME}
|
|||
test_guess_content_type.cpp
|
||||
test_glob2regex.cpp
|
||||
test_tiger_string_conv.cpp
|
||||
test_lexical_cast.cpp
|
||||
)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} SYSTEM
|
||||
|
|
92
test/unit/test_lexical_cast.cpp
Normal file
92
test/unit/test_lexical_cast.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "helpers/lexical_cast.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
|
||||
TEST(helpers, lexical_cast) {
|
||||
using dinhelp::lexical_cast;
|
||||
using dinhelp::tags::hex;
|
||||
using dinhelp::tags::dec;
|
||||
|
||||
{
|
||||
const uint8_t value = 0x34;
|
||||
const auto hex_str = lexical_cast<std::string, hex>(value);
|
||||
EXPECT_EQ("34", hex_str);
|
||||
const auto dec_str = lexical_cast<std::string, dec>(value);
|
||||
EXPECT_EQ("52", dec_str);
|
||||
}
|
||||
{
|
||||
const uint16_t value = 0xFFFF;
|
||||
const auto hex_str = lexical_cast<std::string, hex>(value);
|
||||
EXPECT_EQ("FFFF", hex_str);
|
||||
const auto dec_str = lexical_cast<std::string, dec>(value);
|
||||
EXPECT_EQ("65535", dec_str);
|
||||
}
|
||||
{
|
||||
const uint16_t value = 0xFF;
|
||||
const auto hex_str = lexical_cast<std::string, hex>(value);
|
||||
EXPECT_EQ("FF", hex_str);
|
||||
const auto dec_str = lexical_cast<std::string, dec>(value);
|
||||
EXPECT_EQ("255", dec_str);
|
||||
}
|
||||
{
|
||||
const uint16_t value = 0x100;
|
||||
const auto hex_str = lexical_cast<std::string, hex>(value);
|
||||
EXPECT_EQ("100", hex_str);
|
||||
const auto dec_str = lexical_cast<std::string, dec>(value);
|
||||
EXPECT_EQ("256", dec_str);
|
||||
}
|
||||
{
|
||||
const uint32_t value = 0x1ABC;
|
||||
const auto hex_str = lexical_cast<std::string, hex>(value);
|
||||
EXPECT_EQ("1ABC", hex_str);
|
||||
const auto dec_str = lexical_cast<std::string, dec>(value);
|
||||
EXPECT_EQ("6844", dec_str);
|
||||
}
|
||||
{
|
||||
const uint32_t value = 0xffffffff;
|
||||
const auto hex_str = lexical_cast<std::string, hex>(value);
|
||||
EXPECT_EQ("FFFFFFFF", hex_str);
|
||||
const auto dec_str = lexical_cast<std::string, dec>(value);
|
||||
EXPECT_EQ("4294967295", dec_str);
|
||||
}
|
||||
{
|
||||
const uint32_t value = 1;
|
||||
const auto hex_str = lexical_cast<std::string, hex>(value);
|
||||
EXPECT_EQ("1", hex_str);
|
||||
const auto dec_str = lexical_cast<std::string, dec>(value);
|
||||
EXPECT_EQ("1", dec_str);
|
||||
}
|
||||
{
|
||||
const uint32_t value = 0;
|
||||
const auto hex_str = lexical_cast<std::string, hex>(value);
|
||||
EXPECT_EQ("0", hex_str);
|
||||
const auto dec_str = lexical_cast<std::string, dec>(value);
|
||||
EXPECT_EQ("0", dec_str);
|
||||
}
|
||||
{
|
||||
const uint64_t value = 0x12abcd34;
|
||||
const auto hex_str = lexical_cast<std::string, hex>(value);
|
||||
EXPECT_EQ("12ABCD34", hex_str);
|
||||
const auto dec_str = lexical_cast<std::string, dec>(value);
|
||||
EXPECT_EQ("313249076", dec_str);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue