2
0
mirror of https://github.com/boostorg/convert.git synced 2026-01-19 04:02:18 +00:00

14APR-09:44 issue #54: added support for notation::hex

This commit is contained in:
Vladimir Batov
2022-04-14 09:44:24 +10:00
parent b5aa9a720c
commit 1345c1925e
11 changed files with 138 additions and 54 deletions

View File

@@ -89,7 +89,8 @@ struct boost::cnv::cnvbase
BOOST_CNV_STRING_TO (string_type const& s, optional< ldbl_type>& r) const { str_to_(s, r); }
template<typename argument_pack>
derived_type& operator()(argument_pack const& arg)
typename std::enable_if<boost::parameter::is_argument_pack<argument_pack>::value, derived_type&>::type
operator()(argument_pack const& arg)
{
BOOST_CNV_PARAM_TRY(base);
BOOST_CNV_PARAM_TRY(adjust);
@@ -98,6 +99,7 @@ struct boost::cnv::cnvbase
BOOST_CNV_PARAM_TRY(skipws);
BOOST_CNV_PARAM_TRY(width);
BOOST_CNV_PARAM_TRY(fill);
BOOST_CNV_PARAM_TRY(notation);
// BOOST_CNV_PARAM_TRY(locale);
return this->dncast();
@@ -105,16 +107,7 @@ struct boost::cnv::cnvbase
protected:
cnvbase()
:
skipws_ (false),
precision_ (0),
uppercase_ (false),
width_ (0),
fill_ (' '),
base_ (boost::cnv::base::dec),
adjust_ (boost::cnv::adjust::right)
{}
cnvbase() = default;
template<typename string_type, typename out_type>
void
@@ -185,20 +178,22 @@ struct boost::cnv::cnvbase
BOOST_CNV_PARAM_SET(skipws) { skipws_ = arg[cnv::parameter:: skipws]; }
BOOST_CNV_PARAM_SET(width) { width_ = arg[cnv::parameter:: width]; }
BOOST_CNV_PARAM_SET(fill) { fill_ = arg[cnv::parameter:: fill]; }
BOOST_CNV_PARAM_SET(notation) { notation_ = arg[cnv::parameter:: notation]; }
// BOOST_CNV_PARAM_SET(locale) { locale_ = arg[cnv::parameter:: locale]; }
// ULONG_MAX(8 bytes) = 18446744073709551615 (20(10) or 32(2) characters)
// double (8 bytes) max is 316 chars
static int BOOST_CONSTEXPR_OR_CONST bufsize_ = 512;
static int inline BOOST_CONSTEXPR_OR_CONST bufsize_ = 512;
bool skipws_;
int precision_;
bool uppercase_;
int width_;
int fill_;
cnv::base base_;
cnv::adjust adjust_;
// std::locale locale_;
bool skipws_ = false;
int precision_ = 0;
bool uppercase_ = false;
int width_ = 0;
int fill_ = ' ';
cnv::base base_ = boost::cnv::base::dec;
cnv::adjust adjust_ = boost::cnv::adjust::right;
cnv::notation notation_ = boost::cnv::notation::fixed;
// std::locale locale_;
};
#undef BOOST_CNV_TO_STRING

View File

@@ -14,6 +14,7 @@ namespace boost { namespace cnv
using char_type = char;
using uchar_type = unsigned char;
using wchar_type = wchar_t;
using char_cptr = char const*;
namespace detail
{

View File

@@ -13,7 +13,7 @@ namespace boost { namespace cnv
{
enum class adjust { left, right, center };
enum class base { bin =2, oct =8, dec =10, hex =16 };
enum class notation { fixed, scientific };
enum class notation { fixed, scientific, hex };
namespace parameter
{

View File

@@ -21,6 +21,7 @@ struct boost::cnv::printf : boost::cnv::cnvbase<boost::cnv::printf>
{
using this_type = boost::cnv::printf;
using base_type = boost::cnv::cnvbase<this_type>;
using fmt_type = char_cptr const*;
using base_type::operator();
@@ -58,27 +59,65 @@ struct boost::cnv::printf : boost::cnv::cnvbase<boost::cnv::printf>
return type_pos::value;
}
char const* printf_format(int pos) const
char_cptr fmt(
int pos,
fmt_type fxd_d_fmt, fmt_type fxd_x_fmt, fmt_type fxd_o_fmt,
fmt_type sci_d_fmt, fmt_type sci_x_fmt, fmt_type sci_o_fmt,
fmt_type hex_d_fmt, fmt_type hex_x_fmt, fmt_type hex_o_fmt) const
{
static char const* d_fmt[] = { "%.*f", "%.*f", "%.*d", "%.*u", "%.*hd", "%.*hu", "%.*ld", "%.*lu" }; // Must match managed_types
static char const* x_fmt[] = { "%.*f", "%.*f", "%.*x", "%.*x", "%.*hx", "%.*hx", "%.*lx", "%.*lx" }; // Must match managed_types
static char const* o_fmt[] = { "%.*f", "%.*f", "%.*o", "%.*o", "%.*ho", "%.*ho", "%.*lo", "%.*lo" }; // Must match managed_types
char const* fmt = base_ == boost::cnv::base::dec ? d_fmt[pos]
: base_ == boost::cnv::base::hex ? x_fmt[pos]
: base_ == boost::cnv::base::oct ? o_fmt[pos]
: (BOOST_ASSERT(0), nullptr);
return fmt;
if (notation_ == notation::fixed)
return base_ == base::dec ? fxd_d_fmt[pos]
: base_ == base::hex ? fxd_x_fmt[pos]
: base_ == base::oct ? fxd_o_fmt[pos]
: (BOOST_ASSERT(0), nullptr);
if (notation_ == notation::scientific)
return base_ == base::dec ? sci_d_fmt[pos]
: base_ == base::hex ? sci_x_fmt[pos]
: base_ == base::oct ? sci_o_fmt[pos]
: (BOOST_ASSERT(0), nullptr);
if (notation_ == notation::hex)
return base_ == base::dec ? hex_d_fmt[pos]
: base_ == base::hex ? hex_x_fmt[pos]
: base_ == base::oct ? hex_o_fmt[pos]
: (BOOST_ASSERT(0), nullptr);
return (BOOST_ASSERT(0), nullptr);
}
char const* sscanf_format(int pos) const
char_cptr printf_format(int pos) const
{
static char const* d_fmt[] = { "%lf", "%f", "%d", "%u", "%hd", "%hu", "%ld", "%lu" }; // Must match managed_types
static char const* x_fmt[] = { "%lf", "%f", "%x", "%x", "%hx", "%hx", "%lx", "%lx" }; // Must match managed_types
static char const* o_fmt[] = { "%lf", "%f", "%o", "%o", "%ho", "%ho", "%lo", "%lo" }; // Must match managed_types
char const* fmt = base_ == boost::cnv::base::dec ? d_fmt[pos]
: base_ == boost::cnv::base::hex ? x_fmt[pos]
: base_ == boost::cnv::base::oct ? o_fmt[pos]
: (BOOST_ASSERT(0), nullptr);
return fmt;
char_cptr constexpr fxd_d_fmt[] = { "%.*f", "%.*f", "%.*d", "%.*u", "%.*hd", "%.*hu", "%.*ld", "%.*lu" }; // Must match managed_types
char_cptr constexpr fxd_x_fmt[] = { "%.*f", "%.*f", "%.*x", "%.*x", "%.*hx", "%.*hx", "%.*lx", "%.*lx" }; // Must match managed_types
char_cptr constexpr fxd_o_fmt[] = { "%.*f", "%.*f", "%.*o", "%.*o", "%.*ho", "%.*ho", "%.*lo", "%.*lo" }; // Must match managed_types
char_cptr constexpr sci_d_fmt[] = { "%.*e", "%.*e", "%.*d", "%.*u", "%.*hd", "%.*hu", "%.*ld", "%.*lu" }; // Must match managed_types
char_cptr constexpr sci_x_fmt[] = { "%.*e", "%.*e", "%.*x", "%.*x", "%.*hx", "%.*hx", "%.*lx", "%.*lx" }; // Must match managed_types
char_cptr constexpr sci_o_fmt[] = { "%.*e", "%.*e", "%.*o", "%.*o", "%.*ho", "%.*ho", "%.*lo", "%.*lo" }; // Must match managed_types
char_cptr constexpr hex_d_fmt[] = { "%.*a", "%.*a", "%.*d", "%.*u", "%.*hd", "%.*hu", "%.*ld", "%.*lu" }; // Must match managed_types
char_cptr constexpr hex_x_fmt[] = { "%.*a", "%.*a", "%.*x", "%.*x", "%.*hx", "%.*hx", "%.*lx", "%.*lx" }; // Must match managed_types
char_cptr constexpr hex_o_fmt[] = { "%.*a", "%.*a", "%.*o", "%.*o", "%.*ho", "%.*ho", "%.*lo", "%.*lo" }; // Must match managed_types
return fmt(pos,
fxd_d_fmt, fxd_x_fmt, fxd_o_fmt,
sci_d_fmt, sci_x_fmt, sci_o_fmt,
hex_d_fmt, hex_x_fmt, hex_o_fmt);
}
char_cptr sscanf_format(int pos) const
{
char_cptr constexpr fxd_d_fmt[] = { "%lf", "%f", "%d", "%u", "%hd", "%hu", "%ld", "%lu" }; // Must match managed_types
char_cptr constexpr fxd_x_fmt[] = { "%lf", "%f", "%x", "%x", "%hx", "%hx", "%lx", "%lx" }; // Must match managed_types
char_cptr constexpr fxd_o_fmt[] = { "%lf", "%f", "%o", "%o", "%ho", "%ho", "%lo", "%lo" }; // Must match managed_types
char_cptr constexpr sci_d_fmt[] = { "%le", "%e", "%d", "%u", "%hd", "%hu", "%ld", "%lu" }; // Must match managed_types
char_cptr constexpr sci_x_fmt[] = { "%le", "%e", "%x", "%x", "%hx", "%hx", "%lx", "%lx" }; // Must match managed_types
char_cptr constexpr sci_o_fmt[] = { "%le", "%e", "%o", "%o", "%ho", "%ho", "%lo", "%lo" }; // Must match managed_types
char_cptr constexpr hex_d_fmt[] = { "%la", "%a", "%d", "%u", "%hd", "%hu", "%ld", "%lu" }; // Must match managed_types
char_cptr constexpr hex_x_fmt[] = { "%la", "%a", "%x", "%x", "%hx", "%hx", "%lx", "%lx" }; // Must match managed_types
char_cptr constexpr hex_o_fmt[] = { "%la", "%a", "%o", "%o", "%ho", "%ho", "%lo", "%lo" }; // Must match managed_types
return fmt(pos,
fxd_d_fmt, fxd_x_fmt, fxd_o_fmt,
sci_d_fmt, sci_x_fmt, sci_o_fmt,
hex_d_fmt, hex_x_fmt, hex_o_fmt);
}
};

View File

@@ -45,7 +45,7 @@ struct boost::cnv::spirit : public boost::cnv::cnvbase<boost::cnv::spirit>
char_type* end = beg;
bool good = boost::spirit::karma::generate(end, generator(), value_in);
return cnv::range<char_type*>(beg, good ? end : beg);
}
};

View File

@@ -156,8 +156,9 @@ struct boost::cnv::basic_stream
{
cnv::notation notation = arg[cnv::parameter::notation];
/**/ if (notation == cnv::notation:: fixed) std::fixed(stream_);
/**/ if (notation == cnv::notation:: fixed) std::fixed(stream_);
else if (notation == cnv::notation::scientific) std::scientific(stream_);
else if (notation == cnv::notation:: hex) std::hexfloat(stream_);
else BOOST_ASSERT(!"Not implemented");
}

View File

@@ -153,21 +153,21 @@ boost::cnv::strtol::str_to_i(cnv::range<string_type> range, boost::optional<out_
using range_type = cnv::range<string_type>;
using iterator = typename range_type::iterator;
iterator s = range.begin();
uint_type ch = *s;
bool const is_negative = ch == '-' ? (ch = *++s, true) : ch == '+' ? (ch = *++s, false) : false;
bool const is_unsigned = std::is_same<out_type, unsigned_type>::value;
uint_type base = uint_type(base_);
iterator s = range.begin();
uint_type ch = *s;
bool is_negative = ch == '-' ? (ch = *++s, true) : ch == '+' ? (ch = *++s, false) : false;
bool is_unsigned = std::is_same<out_type, unsigned_type>::value;
uint_type base = uint_type(base_);
/**/ if (is_negative && is_unsigned) return;
else if ((base == 0 || base == 16) && ch == '0' && (*++s == 'x' || *s == 'X')) ++s, base = 16;
else if (base == 0) base = ch == '0' ? (++s, 8) : 10;
unsigned_type const max = (std::numeric_limits<out_type>::max)();
unsigned_type const umax = max + (is_negative ? 1 : 0);
unsigned_type const cutoff = umax / base;
uint_type const cutlim = umax % base;
unsigned_type result = 0;
unsigned_type max = (std::numeric_limits<out_type>::max)();
unsigned_type umax = max + (is_negative ? 1 : 0);
unsigned_type cutoff = umax / base;
uint_type cutlim = umax % base;
unsigned_type result = 0;
for (; s != range.sentry(); ++s)
{

View File

@@ -29,8 +29,6 @@ exe convert_test_performance_spirit : performance_spirit.cpp ;
run callable.cpp : : : : convert_test_callable ;
run fallbacks.cpp : : : : convert_test_fallbacks ;
run spirit_converter.cpp : : : : convert_test_spirit_converter ;
run stream_converter.cpp : : : : convert_test_stream_converter ;
run printf_converter.cpp : : : : convert_test_printf_converter ;
run strtol_converter.cpp : : : : convert_test_strtol_converter ;
run lcast_converter.cpp : : : : convert_test_lcast_converter ;
run encryption.cpp : : : : convert_test_encryption ;
@@ -38,4 +36,8 @@ run user_type.cpp : : : : convert_test_user_type ;
run str_to_int.cpp : : : : convert_test_str_to_int ;
run sfinae.cpp : : : : convert_test_sfinae ;
run has_member.cpp : : : : convert_test_has_member ;
run printf_converter.cpp :
/boost/test/included_unit_test_framework : : : convert_test_printf_converter ;
run stream_converter.cpp :
/boost/test/included_unit_test_framework : : : convert_test_stream_converter ;

View File

@@ -20,7 +20,6 @@ int main(int, char const* []) { return 0; }
#include <boost/convert/lexical_cast.hpp>
#include <libs/spirit/workbench/measure.hpp>
#include <boost/spirit/include/qi.hpp>
#include <vector>
namespace

View File

@@ -11,12 +11,33 @@ int main(int, char const* []) { return 0; }
#include <boost/convert.hpp>
#include <boost/convert/printf.hpp>
#include <boost/test/tools/floating_point_comparison.hpp>
using std::string;
using boost::convert;
namespace cnv = boost::cnv;
namespace arg = boost::cnv::parameter;
static
void
test_notation()
{
//[charconv_notation
boost::cnv::printf cnv;
BOOST_TEST( "-3.14159" == convert<string>(-3.14159, cnv(arg::notation = cnv::notation::fixed)(arg::precision = 5)).value());
BOOST_TEST( "-3.142e+00" == convert<string>(-3.14159, cnv(arg::notation = cnv::notation::scientific)(arg::precision = 3)).value());
BOOST_TEST("-0x1.9220p+1" == convert<string>(-3.14159, cnv(arg::notation = cnv::notation::hex)(arg::precision = 4)).value());
const auto close = boost::math::fpc::close_at_tolerance<double>(1);
BOOST_TEST_WITH(-3.14159, convert<double>("-3.14159", cnv(arg::notation = cnv::notation::fixed)).value(), close);
BOOST_TEST_WITH(-3.14159, convert<double>("-3.142e+00", cnv(arg::notation = cnv::notation::scientific)).value(), close);
BOOST_TEST_WITH(-3.14159, convert<double>("-0x1.9220p+1", cnv(arg::notation = cnv::notation::hex)).value(), close);
//]
}
int
main(int, char const* [])
{
@@ -43,6 +64,8 @@ main(int, char const* [])
BOOST_TEST(s01 == "12.345600");
BOOST_TEST(s02 == "12.346");
test_notation();
return boost::report_errors();
}

View File

@@ -11,6 +11,7 @@ int main(int, char const* []) { return 0; }
#include <boost/convert.hpp>
#include <boost/convert/stream.hpp>
#include <boost/test/tools/floating_point_comparison.hpp>
#include <cstdio>
#include <cstdlib>
#include <stdlib.h>
@@ -348,6 +349,28 @@ test_user_str()
//]
}
static
void
test_notation()
{
//[charconv_notation
boost::cnv::cstream cnv;
BOOST_TEST( "-3.14159" == convert<string>(-3.14159, cnv(arg::notation = cnv::notation::fixed)(arg::precision = 5)).value());
BOOST_TEST("-3.142e+00" == convert<string>(-3.14159, cnv(arg::notation = cnv::notation::scientific)(arg::precision = 3)).value());
// precision doesn't affect hexfloat
BOOST_TEST("-0x1.921f9f01b866ep+1" == convert<string>(-3.14159, cnv(arg::notation = cnv::notation::hex)).value());
const auto close = boost::math::fpc::close_at_tolerance<double>(1);
BOOST_TEST_WITH(-3.14159, convert<double>("-3.14159", cnv(arg::notation = cnv::notation::fixed)).value(), close);
BOOST_TEST_WITH(-3.14159, convert<double>("-3.142e+00", cnv(arg::notation = cnv::notation::scientific)).value(), close);
// not supported due to https://gcc.gnu.org/bugzilla//show_bug.cgi?id=81122
// BOOST_TEST_WITH(-3.14159, convert<double>("-0x1.921f9f01b866ep+1", cnv(arg::notation = cnv::notation::hex)).value(), close);
//]
}
int
main(int, char const* [])
{
@@ -365,6 +388,7 @@ main(int, char const* [])
test_locale();
test_dbl_to_str();
test_user_str();
test_notation();
}
catch(boost::bad_optional_access const&)
{