stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork

This commit is contained in:
2026-02-24 18:38:47 +00:00
parent da8c28aaeb
commit 65cb2619a7
13106 changed files with 2484322 additions and 1804 deletions
@@ -0,0 +1,189 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_CONVERTER_BASE_HPP
#define BOOST_CONVERT_CONVERTER_BASE_HPP
#include <boost/convert/parameters.hpp>
#include <boost/convert/detail/is_string.hpp>
#include <cctype>
#include <cstring>
namespace boost { namespace cnv
{
namespace ARG = boost::cnv::parameter;
template<typename> struct cnvbase;
}}
#define BOOST_CNV_TO_STRING \
template<typename string_type> \
typename boost::enable_if<cnv::is_string<string_type>, void>::type \
operator()
#define BOOST_CNV_STRING_TO \
template<typename string_type> \
typename boost::enable_if<cnv::is_string<string_type>, void>::type \
operator()
#define BOOST_CNV_PARAM(param_name, param_type) \
derived_type& operator()(boost::parameter::aux::tag<ARG::type::param_name, param_type>::type const& arg)
template<typename derived_type>
struct boost::cnv::cnvbase
{
using this_type = cnvbase;
using int_type = int;
using uint_type = unsigned int;
using lint_type = long int;
using ulint_type = unsigned long int;
using sint_type = short int;
using usint_type = unsigned short int;
using llint_type = long long int;
using ullint_type = unsigned long long int;
using flt_type = float;
using dbl_type = double;
using ldbl_type = long double;
// Integration of user-types via operator>>()
template<typename type_in, typename type_out>
void
operator()(type_in const& in, boost::optional<type_out>& out) const
{
in >> out;
}
// Basic type to string
BOOST_CNV_TO_STRING ( int_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRING ( uint_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRING ( lint_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRING ( llint_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRING ( ulint_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRING (ullint_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRING ( sint_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRING ( usint_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRING ( flt_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRING ( dbl_type v, optional<string_type>& r) const { to_str_(v, r); }
BOOST_CNV_TO_STRING ( ldbl_type v, optional<string_type>& r) const { to_str_(v, r); }
// String to basic type
BOOST_CNV_STRING_TO (string_type const& s, optional< int_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TO (string_type const& s, optional< uint_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TO (string_type const& s, optional< lint_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TO (string_type const& s, optional< llint_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TO (string_type const& s, optional< ulint_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TO (string_type const& s, optional<ullint_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TO (string_type const& s, optional< sint_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TO (string_type const& s, optional< usint_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TO (string_type const& s, optional< flt_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TO (string_type const& s, optional< dbl_type>& r) const { str_to_(s, r); }
BOOST_CNV_STRING_TO (string_type const& s, optional< ldbl_type>& r) const { str_to_(s, r); }
// Formatters
// BOOST_CNV_PARAM (locale, std::locale const) { locale_ = arg[ARG:: locale]; return dncast(); }
BOOST_CNV_PARAM (base, base::type const) { base_ = arg[ARG:: base]; return dncast(); }
BOOST_CNV_PARAM (adjust, adjust::type const) { adjust_ = arg[ARG:: adjust]; return dncast(); }
BOOST_CNV_PARAM (precision, int const) { precision_ = arg[ARG::precision]; return dncast(); }
BOOST_CNV_PARAM (precision, int) { precision_ = arg[ARG::precision]; return dncast(); }
BOOST_CNV_PARAM (uppercase, bool const) { uppercase_ = arg[ARG::uppercase]; return dncast(); }
BOOST_CNV_PARAM (skipws, bool const) { skipws_ = arg[ARG:: skipws]; return dncast(); }
BOOST_CNV_PARAM (width, int const) { width_ = arg[ARG:: width]; return dncast(); }
BOOST_CNV_PARAM (fill, char const) { fill_ = arg[ARG:: fill]; return dncast(); }
protected:
cnvbase()
:
base_ (10),
skipws_ (false),
precision_ (0),
uppercase_ (false),
width_ (0),
fill_ (' '),
adjust_ (boost::cnv::adjust::right)
{}
template<typename string_type, typename out_type>
void
str_to_(string_type const& str, optional<out_type>& result_out) const
{
using range_type = cnv::range<string_type const>;
using char_type = typename range_type::value_type;
range_type range (str);
auto is_space = [](char_type ch)
{
return std::isspace(static_cast<unsigned char>(ch));
};
if (skipws_)
for (; !range.empty() && is_space(*range.begin()); ++range);
if (range.empty()) return;
if (is_space(*range.begin())) return;
dncast().str_to(range, result_out);
}
template<typename in_type, typename string_type>
void
to_str_(in_type value_in, optional<string_type>& result_out) const
{
using range_type = cnv::range<string_type>;
using char_type = typename range_type::value_type;
char_type buf[bufsize_];
cnv::range<char_type*> range = dncast().to_str(value_in, buf);
char_type* beg = range.begin();
char_type* end = range.end();
if (beg < end)
format_(buf, beg, end), result_out = string_type(beg, end);
}
template<typename char_type>
void
format_(char_type* buf, char_type*& beg, char_type*& end) const
{
if (uppercase_)
for (char_type* p = beg; p < end; ++p) *p = std::toupper(*p);
if (width_)
{
int num_fillers = (std::max)(0, int(width_ - (end - beg)));
int num_left = adjust_ == boost::cnv::adjust::left ? 0
: adjust_ == boost::cnv::adjust::right ? num_fillers
: (num_fillers / 2);
int num_right = num_fillers - num_left;
int str_size = end - beg;
bool move = (beg < buf + num_left) // No room for left fillers
|| (buf + bufsize_ < end + num_right); // No room for right fillers
if (move)
{
std::memmove(buf + num_left, beg, str_size * sizeof(char_type));
beg = buf + num_left;
end = beg + str_size;
}
for (int k = 0; k < num_left; *(--beg) = fill_, ++k);
for (int k = 0; k < num_right; *(end++) = fill_, ++k);
}
}
derived_type const& dncast () const { return *static_cast<derived_type const*>(this); }
derived_type& dncast () { return *static_cast<derived_type*>(this); }
// ULONG_MAX(8 bytes) = 18446744073709551615 (20(10) or 32(2) characters)
// double (8 bytes) max is 316 chars
static int const bufsize_ = 512;
int base_;
bool skipws_;
int precision_;
bool uppercase_;
int width_;
int fill_;
adjust::type adjust_;
// std::locale locale_;
};
#undef BOOST_CNV_TO_STRING
#undef BOOST_CNV_STRING_TO
#undef BOOST_CNV_PARAM
#endif // BOOST_CONVERT_CONVERTER_BASE_HPP
@@ -0,0 +1,62 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_PARAMETER_EXT_PRIVATE_HPP
#define BOOST_PARAMETER_EXT_PRIVATE_HPP
#include <boost/parameter/keyword.hpp>
// A Boost.Parameter extension by Andrey Semashev.
// This should really go to Boost.Parameter in the end.
namespace boost { namespace parameter {
// The metafunction, given the type of the arguments pack and the keyword tag,
// returns the corresponding parameter type
template< typename ArgsT, typename KeywordTagT >
struct parameter_type
{
typedef void type;
};
template< typename ArgT, typename KeywordTagT >
struct parameter_type<aux::tagged_argument<KeywordTagT, ArgT>, KeywordTagT>
{
typedef typename aux::tagged_argument< KeywordTagT, ArgT >::value_type type;
};
template< typename KeywordTagT1, typename ArgT, typename KeywordTagT2 >
struct parameter_type< aux::tagged_argument< KeywordTagT1, ArgT >, KeywordTagT2 >
{
typedef void type;
};
template< typename ArgT, typename TailT, typename KeywordTagT >
struct parameter_type<
aux::arg_list<
aux::tagged_argument< KeywordTagT, ArgT >,
TailT
>,
KeywordTagT
>
{
typedef typename aux::tagged_argument< KeywordTagT, ArgT >::value_type type;
};
template< typename KeywordTagT1, typename ArgT, typename TailT, typename KeywordTagT2 >
struct parameter_type<
aux::arg_list<
aux::tagged_argument< KeywordTagT1, ArgT >,
TailT
>,
KeywordTagT2
> :
public parameter_type< TailT, KeywordTagT2 >
{
};
}} // boost::parameter
#endif // BOOST_PARAMETER_EXT_PRIVATE_HPP
@@ -0,0 +1,23 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_DETAIL_IS_CHAR_HPP
#define BOOST_CONVERT_DETAIL_IS_CHAR_HPP
#include <boost/mpl/bool.hpp>
#include <boost/type_traits/remove_const.hpp>
namespace boost { namespace cnv
{
namespace detail
{
template<typename T> struct is_char : mpl::false_ {};
template<> struct is_char<char> : mpl:: true_ {};
template<> struct is_char<wchar_t> : mpl:: true_ {};
}
template <typename T> struct is_char : detail::is_char<typename remove_const<T>::type> {};
}}
#endif // BOOST_CONVERT_DETAIL_IS_CHAR_HPP
@@ -0,0 +1,51 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_FORWARD_HPP
#define BOOST_CONVERT_FORWARD_HPP
#if defined(_MSC_VER)
//MSVC++ 7.0 _MSC_VER == 1300
//MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio 2003)
//MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005)
//MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008)
//MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
//MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
//MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
//MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
//MSVC++ 15.0 _MSC_VER == 1910 (Visual Studio 2017)
# pragma warning(disable: 4244)
# pragma warning(disable: 4224)
# pragma warning(disable: 4996)
# pragma warning(disable: 4180) // qualifier applied to function type has no meaning
# pragma warning(disable: 4100) // unreferenced formal parameter
# pragma warning(disable: 4146) // unary minus operator applied to unsigned type
#if _MSC_VER < 1900 /* MSVC-14 defines real snprintf()... just about time! */
# define snprintf _snprintf
#endif
#endif
#include <boost/config.hpp>
#include <boost/version.hpp>
#include <boost/optional.hpp>
#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
#undef BOOST_CONVERT_CXX11
#else
#define BOOST_CONVERT_CXX11
#endif
#if defined(BOOST_INTEL) && (BOOST_INTEL <= 1200) /* Intel 12.0 and lower have broken SFINAE */
#error "Boost.Convert is not supported on this platform due to broken SFINAE."
#endif
#if defined(BOOST_MSVC) && (BOOST_MSVC < 1800) /* MSVC-11 and lower have broken SFINAE */
//# error "Boost.Convert is not supported on this platform due to broken SFINAE."
# define BOOST_CONVERT_MSVC_SFINAE_BROKEN
#endif
#endif // BOOST_CONVERT_FORWARD_HPP
@@ -0,0 +1,61 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_HAS_MEMBER_HPP
#define BOOST_CONVERT_HAS_MEMBER_HPP
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/detail/yes_no_type.hpp>
// This macro allows to check if a type has a member named "__member_name__"...
// ... regardless of the signature. If takes advantage of the following behavior related to
// function resolution. Say, both, foo and base, declare a method with the same name "func":
//
// struct foo { int func (int, int) { return 0; } };
// struct base { void func () {} };
// struct mixin : public foo, public base {};
//
// Now, if we inherit from both -- foo and base -- classes, then the following calls will fail
// mixin_ptr(0)->func();
// mixin_ptr(0)->func(5, 5);
// with the error message (gcc): request for member func is ambiguous
// regardless if we provide any arguments or not even though one might expect that
// arg-based signature resolution might kick in. The only way to deploy those methods is:
//
// mixin_ptr(0)->foo::func();
// mixin_ptr(0)->base::func(5, 5);
//
// C2. The actual signature of __member_name__ is not taken into account. If
// __T__::__member_name__(any-signature) exists, then the introduced base::__member_name__
// will cause mixin->__member_name__() call to fail to compile (due to ambiguity).
// C3. &U::__member_name__ (a.k.a. &mixin::__member_name__)
// has the type of func_type only if __T__::__member_name__ does not exist.
// If __T__::member_name does exist, then mixin::__member_name__ is ambiguous
// and "yes_type test (...)" kicks in instead.
// C4. Need to find some unique/ugly name so that it does not clash if this macro is
// used inside some other template class;
#define BOOST_DECLARE_HAS_MEMBER(__trait_name__, __member_name__) \
\
template <typename __boost_has_member_T__> /*C4*/ \
class __trait_name__ \
{ \
typedef typename ::boost::remove_const<__boost_has_member_T__>::type check_type; \
typedef ::boost::type_traits::yes_type yes_type; \
typedef ::boost::type_traits:: no_type no_type; \
\
struct base { void __member_name__(/*C2*/) {}}; \
struct mixin : public base, public check_type {}; \
\
template <void (base::*)()> struct aux {}; \
\
template <typename U> static no_type test(aux<&U::__member_name__>*); /*C3*/ \
template <typename U> static yes_type test(...); \
\
public: \
\
BOOST_STATIC_CONSTANT(bool, value = (sizeof(yes_type) == sizeof(test<mixin>(0)))); \
}
#endif // BOOST_CONVERT_HAS_MEMBER_HPP
@@ -0,0 +1,100 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_IS_CALLABLE_HPP
#define BOOST_CONVERT_IS_CALLABLE_HPP
#include <boost/convert/detail/has_member.hpp>
namespace boost { namespace cnv { namespace detail
{
typedef ::boost::type_traits::yes_type yes_type;
typedef ::boost::type_traits:: no_type no_type;
struct not_found {};
struct void_return_substitute {};
// The overloaded comma operator only kicks in for U != void essentially short-circuiting
// itself ineffective. Otherwise, when U=void, the standard op,() kicks in and returns
// 'void_return_substitute'.
template<typename U> U const& operator, (U const&, void_return_substitute);
template<typename U> U& operator, (U&, void_return_substitute);
template <typename src, typename dst> struct match_const { typedef dst type; };
template <typename src, typename dst> struct match_const<src const, dst> { typedef dst const type; };
template<typename T, typename return_type>
struct redirect
{
static no_type test (...);
static yes_type test (return_type);
};
template<typename T>
struct redirect<T, void>
{
static yes_type test (...);
static no_type test (not_found);
};
}}}
// No-args case needs to be implemented differently and has not been implemented yet.
// template <typename R>
// struct check<true, R ()>
// C1. Need to find some unique/ugly names so that they do not clash if this macro is
// used inside some other template class;
// C2. Body of the function is not actually used anywhere.
// However, Intel C++ compiler treats it as an error. So, we provide the body.
#define BOOST_DECLARE_IS_CALLABLE(__trait_name__, __member_name__) \
\
template <typename __boost_is_callable_T__, typename __boost_is_callable_signature__> \
class __trait_name__ \
{ \
typedef __boost_is_callable_T__ class_type; /*C1*/ \
typedef __boost_is_callable_signature__ signature; /*C1*/ \
typedef boost::cnv::detail::not_found not_found; \
\
BOOST_DECLARE_HAS_MEMBER(has_member, __member_name__); \
\
struct mixin : public class_type \
{ \
using class_type::__member_name__; \
not_found __member_name__(...) const { return not_found(); /*C2*/} \
}; \
\
typedef typename boost::cnv::detail::match_const<class_type, mixin>::type* mixin_ptr; \
\
template <bool has, typename F> struct check { static bool const value = false; }; \
\
template <typename Arg1, typename R> \
struct check<true, R (Arg1)> \
{ \
typedef typename boost::decay<Arg1>::type* a1; \
\
static bool const value = sizeof(boost::type_traits::yes_type) \
== sizeof(boost::cnv::detail::redirect<class_type, R>::test( \
(mixin_ptr(0)->__member_name__(*a1(0)), \
boost::cnv::detail::void_return_substitute()))); \
}; \
template <typename Arg1, typename Arg2, typename R> \
struct check<true, R (Arg1, Arg2)> \
{ \
typedef typename boost::decay<Arg1>::type* a1; \
typedef typename boost::decay<Arg2>::type* a2; \
\
static bool const value = sizeof(boost::type_traits::yes_type) \
== sizeof(boost::cnv::detail::redirect<class_type, R>::test( \
(mixin_ptr(0)->__member_name__(*a1(0), *a2(0)), \
boost::cnv::detail::void_return_substitute()))); \
}; \
\
public: \
\
/* Check the existence of __member_name__ first, then the signature. */ \
static bool const value = check<has_member<class_type>::value, signature>::value; \
}
#endif // BOOST_CONVERT_IS_CALLABLE_HPP
@@ -0,0 +1,47 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_IS_CONVERTER_HPP
#define BOOST_CONVERT_IS_CONVERTER_HPP
#include <boost/convert/detail/forward.hpp>
#include <boost/convert/detail/is_callable.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>
#include <boost/ref.hpp>
namespace boost { namespace cnv
{
template<typename, typename, typename, typename =void>
struct is_cnv { BOOST_STATIC_CONSTANT(bool, value = false); };
template<typename Class, typename TypeIn, typename TypeOut>
struct is_cnv<Class, TypeIn, TypeOut, typename enable_if<is_class<Class>, void>::type>
{
typedef typename ::boost::unwrap_reference<Class>::type class_type;
typedef void signature_type(TypeIn const&, optional<TypeOut>&);
BOOST_DECLARE_IS_CALLABLE(is_callable, operator());
BOOST_STATIC_CONSTANT(bool, value = (is_callable<class_type, signature_type>::value));
};
template<typename Function, typename TypeIn, typename TypeOut>
struct is_cnv<Function, TypeIn, TypeOut,
typename enable_if_c<is_function<Function>::value && function_types::function_arity<Function>::value == 2,
void>::type>
{
typedef TypeIn in_type;
typedef optional<TypeOut>& out_type;
typedef typename function_traits<Function>::arg1_type func_in_type;
typedef typename function_traits<Function>::arg2_type func_out_type;
BOOST_STATIC_CONSTANT(bool, in_good = (is_convertible<in_type, func_in_type>::value));
BOOST_STATIC_CONSTANT(bool, out_good = (is_same<out_type, func_out_type>::value));
BOOST_STATIC_CONSTANT(bool, value = (in_good && out_good));
};
}}
#endif // BOOST_CONVERT_IS_CONVERTER_HPP
@@ -0,0 +1,61 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_IS_FUNCTION_HPP
#define BOOST_CONVERT_IS_FUNCTION_HPP
#include <boost/convert/detail/forward.hpp>
#include <boost/convert/detail/has_member.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits.hpp>
#include <boost/function_types/is_function_pointer.hpp>
#include <boost/function_types/function_arity.hpp>
#include <boost/function_types/result_type.hpp>
namespace boost { namespace cnv
{
typedef ::boost::type_traits::yes_type yes_type;
typedef ::boost::type_traits:: no_type no_type;
template <bool has_operator, typename Functor, typename TypeOut>
struct check_functor { BOOST_STATIC_CONSTANT(bool, value = false); };
template<typename Func, typename TypeOut, class Enable =void>
struct is_fun { BOOST_STATIC_CONSTANT(bool, value = false); };
template <typename Functor, typename TypeOut>
struct check_functor<true, Functor, TypeOut>
{
static yes_type test (TypeOut const&);
static no_type test (...);
static const bool value = sizeof(yes_type) == sizeof(test(((Functor*) 0)->operator()()));
};
template<typename Functor, typename TypeOut>
struct is_fun<Functor, TypeOut,
typename enable_if_c<is_class<Functor>::value && !is_convertible<Functor, TypeOut>::value, void>::type>
{
BOOST_DECLARE_HAS_MEMBER(has_funop, operator());
BOOST_STATIC_CONSTANT(bool, value = (check_functor<has_funop<Functor>::value, Functor, TypeOut>::value));
};
template<typename Function, typename TypeOut>
struct is_fun<Function, TypeOut,
typename enable_if_c<
function_types::is_function_pointer<Function>::value &&
function_types::function_arity<Function>::value == 0 &&
!is_same<Function, TypeOut>::value,
void>::type>
{
typedef TypeOut out_type;
typedef typename function_types::result_type<Function>::type func_out_type;
BOOST_STATIC_CONSTANT(bool, value = (is_convertible<func_out_type, out_type>::value));
};
}}
#endif // BOOST_CONVERT_IS_FUNCTION_HPP
@@ -0,0 +1,34 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_DETAIL_IS_STRING_HPP
#define BOOST_CONVERT_DETAIL_IS_STRING_HPP
#include <boost/convert/detail/range.hpp>
namespace boost { namespace cnv
{
namespace detail
{
template<typename T, bool is_range_class> struct is_string : mpl::false_ {};
template<typename T> struct is_string<T*, false>
{
static bool const value = cnv::is_char<T>::value;
};
template <typename T, std::size_t N> struct is_string<T [N], false>
{
static bool const value = cnv::is_char<T>::value;
};
template<typename T> struct is_string<T, /*is_range_class=*/true>
{
static bool const value = cnv::is_char<typename T::value_type>::value;
};
}
template<typename T> struct is_string : detail::is_string<
typename remove_const<T>::type,
boost::is_class<T>::value && boost::cnv::is_range<T>::value> {};
}}
#endif // BOOST_CONVERT_DETAIL_IS_STRING_HPP
@@ -0,0 +1,117 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_DETAIL_RANGE_HPP
#define BOOST_CONVERT_DETAIL_RANGE_HPP
#include <boost/convert/detail/has_member.hpp>
#include <boost/convert/detail/char.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/range/iterator.hpp>
namespace boost { namespace cnv
{
namespace detail
{
template<typename T, bool is_class> struct is_range : mpl::false_ {};
template<typename T> struct is_range<T, /*is_class=*/true>
{
BOOST_DECLARE_HAS_MEMBER(has_begin, begin);
BOOST_DECLARE_HAS_MEMBER( has_end, end);
static bool const value = has_begin<T>::value && has_end<T>::value;
};
}
template<typename T> struct is_range : detail::is_range<typename remove_const<T>::type, boost::is_class<T>::value> {};
template<typename T, typename enable =void> struct range;
template<typename T, typename enable =void> struct iterator;
template<typename T>
struct iterator<T, typename enable_if<is_range<T> >::type>
{
typedef typename boost::range_iterator<T>::type type;
typedef typename boost::range_iterator<T const>::type const_type;
typedef typename boost::iterator_value<type>::type value_type;
};
template<typename T>
struct iterator<T*, void>
{
typedef typename remove_const<T>::type value_type;
typedef T* type;
typedef value_type const* const_type;
};
template<typename T>
struct range_base
{
typedef typename cnv::iterator<T>::value_type value_type;
typedef typename cnv::iterator<T>::type iterator;
typedef typename cnv::iterator<T>::const_type const_iterator;
typedef const_iterator sentry_type;
iterator begin () { return begin_; }
const_iterator begin () const { return begin_; }
void operator++ () { ++begin_; }
// void operator-- () { --end_; }
protected:
range_base (iterator b, iterator e) : begin_(b), end_(e) {}
iterator begin_;
iterator mutable end_;
};
template<typename T>
struct range<T, typename enable_if<is_range<T> >::type> : public range_base<T>
{
typedef range this_type;
typedef range_base<T> base_type;
typedef typename base_type::iterator iterator;
typedef typename base_type::const_iterator const_iterator;
typedef const_iterator sentry_type;
range (T& r) : base_type(r.begin(), r.end()) {}
iterator end () { return base_type::end_; }
const_iterator end () const { return base_type::end_; }
sentry_type sentry () const { return base_type::end_; }
bool empty () const { return base_type::begin_ == base_type::end_; }
};
template<typename T>
struct range<T*, typename enable_if<cnv::is_char<T> >::type> : public range_base<T*>
{
typedef range this_type;
typedef range_base<T*> base_type;
typedef typename remove_const<T>::type value_type;
typedef T* iterator;
typedef value_type const* const_iterator;
struct sentry_type
{
friend bool operator!=(iterator it, sentry_type) { return !!*it; }
};
range (iterator b, iterator e =0) : base_type(b, e) {}
iterator end () { return base_type::end_ ? base_type::end_ : (base_type::end_ = base_type::begin_ + size()); }
const_iterator end () const { return base_type::end_ ? base_type::end_ : (base_type::end_ = base_type::begin_ + size()); }
sentry_type sentry () const { return sentry_type(); }
std::size_t size () const { return std::char_traits<value_type>::length(base_type::begin_); }
bool empty () const { return !*base_type::begin_; }
};
template<typename T>
struct range<T* const, void> : public range<T*>
{
range (T* b, T* e =0) : range<T*>(b, e) {}
};
template <typename T, std::size_t N>
struct range<T [N], void> : public range<T*>
{
range (T* b, T* e =0) : range<T*>(b, e) {}
};
}}
#endif // BOOST_CONVERT_DETAIL_RANGE_HPP
@@ -0,0 +1,40 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_LEXICAL_CAST_HPP
#define BOOST_CONVERT_LEXICAL_CAST_HPP
#include <boost/lexical_cast.hpp>
namespace boost { namespace cnv
{
struct lexical_cast;
}}
/// @brief boost::lexical_cast-based converter
/// @details The purpose of the converter is to
/// * Make use of the boost::lexical_cast functionality and performance that many people have become
/// accustomed to and comfortable with;
/// * Demonstrate how existing independent conversion/transformation-related facilities might be
// incorporated in to the Boost.Convert framework.
///
/// The converter can easily replace boost::lexical_cast, adding flexibility and convenience.
struct boost::cnv::lexical_cast
{
template<typename TypeOut, typename TypeIn>
void
operator()(TypeIn const& value_in, boost::optional<TypeOut>& result_out) const
{
try
{
result_out = boost::lexical_cast<TypeOut>(value_in);
}
catch (boost::bad_lexical_cast const&)
{
}
}
};
#endif // BOOST_CONVERT_LEXICAL_CAST_HPP
@@ -0,0 +1,33 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_PARAMETERS_HPP
#define BOOST_CONVERT_PARAMETERS_HPP
#include <boost/convert/detail/boost_parameter_ext.hpp>
namespace boost
{
namespace cnv
{
struct adjust { enum type { left, right, center };};
struct base { enum type { bin =2, dec =10, hex =16, oct =8 };};
struct notation { enum type { fixed, scientific };};
namespace parameter
{
BOOST_PARAMETER_KEYWORD(type, adjust)
BOOST_PARAMETER_KEYWORD(type, base)
BOOST_PARAMETER_KEYWORD(type, fill)
BOOST_PARAMETER_KEYWORD(type, locale)
BOOST_PARAMETER_KEYWORD(type, notation)
BOOST_PARAMETER_KEYWORD(type, precision)
BOOST_PARAMETER_KEYWORD(type, skipws)
BOOST_PARAMETER_KEYWORD(type, uppercase)
BOOST_PARAMETER_KEYWORD(type, width)
}
}
}
#endif // BOOST_CONVERT_PARAMETERS_HPP
@@ -0,0 +1,89 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_PRINTF_HPP
#define BOOST_CONVERT_PRINTF_HPP
#include <boost/convert/base.hpp>
#include <boost/make_default.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/find.hpp>
#include <boost/range/as_literal.hpp>
#include <string>
#include <cstdio>
namespace boost { namespace cnv
{
struct printf;
}}
struct boost::cnv::printf : public boost::cnv::cnvbase<boost::cnv::printf>
{
typedef boost::cnv::printf this_type;
typedef boost::cnv::cnvbase<this_type> base_type;
using base_type::operator();
template<typename in_type>
cnv::range<char*>
to_str(in_type value_in, char* buf) const
{
char const* fmt = pformat(pos<in_type>());
int const num_chars = snprintf(buf, bufsize_, fmt, precision_, value_in);
bool const success = num_chars < bufsize_;
return cnv::range<char*>(buf, success ? (buf + num_chars) : buf);
}
template<typename string_type, typename out_type>
void
str_to(cnv::range<string_type> range, optional<out_type>& result_out) const
{
out_type result = boost::make_default<out_type>();
int const num_read = sscanf(&*range.begin(), format(pos<out_type>()), &result);
if (num_read == 1)
result_out = result;
}
private:
template<typename Type> int pos() const
{
typedef boost::mpl::vector<double, float,
int, unsigned int,
short int, unsigned short int,
long int, unsigned long int
> managed_types;
typedef typename boost::mpl::find<managed_types, Type>::type type_iterator;
typedef typename type_iterator::pos type_pos;
return type_pos::value;
}
char const* pformat(int pos) const
{
static char const* d_format[] = { "%.*f", "%.*f", "%.*d", "%.*u", "%.*hd", "%.*hu", "%.*ld", "%.*lu" }; // Must match managed_types
static char const* x_format[] = { "%.*f", "%.*f", "%.*x", "%.*x", "%.*hx", "%.*hx", "%.*lx", "%.*lx" }; // Must match managed_types
static char const* o_format[] = { "%.*f", "%.*f", "%.*o", "%.*o", "%.*ho", "%.*ho", "%.*lo", "%.*lo" }; // Must match managed_types
char const* format = base_ == 10 ? d_format[pos]
: base_ == 16 ? x_format[pos]
: base_ == 8 ? o_format[pos]
: (BOOST_ASSERT(0), (char const*) 0);
return format;
}
char const* format(int pos) const
{
static char const* d_format[] = { "%f", "%f", "%d", "%u", "%hd", "%hu", "%ld", "%lu" }; // Must match managed_types
static char const* x_format[] = { "%f", "%f", "%x", "%x", "%hx", "%hx", "%lx", "%lx" }; // Must match managed_types
static char const* o_format[] = { "%f", "%f", "%o", "%o", "%ho", "%ho", "%lo", "%lo" }; // Must match managed_types
char const* format = base_ == 10 ? d_format[pos]
: base_ == 16 ? x_format[pos]
: base_ == 8 ? o_format[pos]
: (BOOST_ASSERT(0), (char const*) 0);
return format;
}
};
#endif // BOOST_CONVERT_PRINTF_HPP
@@ -0,0 +1,54 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_SPIRIT_BASED_CONVERTER_HPP
#define BOOST_CONVERT_SPIRIT_BASED_CONVERTER_HPP
#include <boost/convert/base.hpp>
#include <boost/convert/detail/forward.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
namespace boost { namespace cnv
{
struct spirit;
}}
struct boost::cnv::spirit : public boost::cnv::cnvbase<boost::cnv::spirit>
{
typedef boost::cnv::spirit this_type;
typedef boost::cnv::cnvbase<this_type> base_type;
using base_type::operator();
template<typename string_type, typename out_type>
void
str_to(cnv::range<string_type> range, optional<out_type>& result_out) const
{
typedef typename cnv::range<string_type>::iterator iterator;
typedef typename boost::spirit::traits::create_parser<out_type>::type parser;
iterator beg = range.begin();
iterator end = range.end();
out_type result;
if (boost::spirit::qi::parse(beg, end, parser(), result))
if (beg == end) // ensure the whole string has been parsed
result_out = result;
}
template<typename in_type, typename char_type>
cnv::range<char_type*>
to_str(in_type value_in, char_type* beg) const
{
typedef typename boost::spirit::traits::create_generator<in_type>::type generator;
char_type* end = beg;
bool good = boost::spirit::karma::generate(end, generator(), value_in);
return cnv::range<char_type*>(beg, good ? end : beg);
}
};
#endif // BOOST_CONVERT_SPIRIT_BASED_CONVERTER_HPP
@@ -0,0 +1,198 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_STRINGSTREAM_BASED_CONVERTER_HPP
#define BOOST_CONVERT_STRINGSTREAM_BASED_CONVERTER_HPP
#include <boost/convert/parameters.hpp>
#include <boost/convert/detail/is_string.hpp>
#include <boost/make_default.hpp>
#include <sstream>
#include <iomanip>
#define BOOST_CNV_STRING_ENABLE \
template<typename string_type, typename type> \
typename boost::enable_if<cnv::is_string<string_type>, void>::type \
operator()
#define BOOST_CNV_PARAM(PARAM_NAME, PARAM_TYPE) \
this_type& \
operator()(boost::parameter::aux::tag<boost::cnv::parameter::type::PARAM_NAME, PARAM_TYPE>::type const& arg)
namespace boost { namespace cnv
{
template<class Char> struct basic_stream;
typedef boost::cnv::basic_stream<char> cstream;
typedef boost::cnv::basic_stream<wchar_t> wstream;
}}
template<class Char>
struct boost::cnv::basic_stream : boost::noncopyable
{
// C01. In string-to-type conversions the "string" must be a CONTIGUOUS ARRAY of
// characters because "ibuffer_type" uses/relies on that (it deals with char_type*).
// C02. Use the provided "string_in" as the input (read-from) buffer and, consequently,
// avoid the overhead associated with stream_.str(string_in) --
// copying of the content into internal buffer.
// C03. The "strbuf.gptr() != strbuf.egptr()" check replaces "istream.eof() != true"
// which for some reason does not work when we try converting the "true" string
// to "bool" with std::boolalpha set. Seems that istream state gets unsynced compared
// to the actual underlying buffer.
typedef Char char_type;
typedef boost::cnv::basic_stream<char_type> this_type;
typedef std::basic_stringstream<char_type> stream_type;
typedef std::basic_istream<char_type> istream_type;
typedef std::basic_streambuf<char_type> buffer_type;
typedef std::basic_string<char_type> stdstr_type;
typedef std::ios_base& (*manipulator_type)(std::ios_base&);
struct ibuffer_type : public buffer_type
{
using buffer_type::eback;
using buffer_type::gptr;
using buffer_type::egptr;
ibuffer_type(char_type const* beg, std::size_t sz) //C01
{
char_type* b = const_cast<char_type*>(beg);
buffer_type::setg(b, b, b + sz);
}
};
struct obuffer_type : public buffer_type
{
using buffer_type::pbase;
using buffer_type::pptr;
using buffer_type::epptr;
};
basic_stream() : stream_(std::ios_base::in | std::ios_base::out) {}
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
basic_stream(this_type&& other) : stream_(std::move(other.stream_)) {}
#endif
BOOST_CNV_STRING_ENABLE(type const& v, optional<string_type>& s) const { to_str(v, s); }
BOOST_CNV_STRING_ENABLE(string_type const& s, optional<type>& r) const { str_to(cnv::range<string_type const>(s), r); }
// Resolve ambiguity of string-to-string
template<typename type> void operator()( char_type const* s, optional<type>& r) const { str_to(cnv::range< char_type const*>(s), r); }
template<typename type> void operator()(stdstr_type const& s, optional<type>& r) const { str_to(cnv::range<stdstr_type const>(s), r); }
// Formatters
template<typename manipulator>
this_type& operator() (manipulator m) { return (stream_ << m, *this); }
this_type& operator() (manipulator_type m) { return (m(stream_), *this); }
this_type& operator() (std::locale const& l) { return (stream_.imbue(l), *this); }
BOOST_CNV_PARAM(locale, std::locale const) { return (stream_.imbue(arg[cnv::parameter::locale]), *this); }
BOOST_CNV_PARAM(precision, int const) { return (stream_.precision(arg[cnv::parameter::precision]), *this); }
BOOST_CNV_PARAM(precision, int) { return (stream_.precision(arg[cnv::parameter::precision]), *this); }
BOOST_CNV_PARAM(width, int const) { return (stream_.width(arg[cnv::parameter::width]), *this); }
BOOST_CNV_PARAM(fill, char const) { return (stream_.fill(arg[cnv::parameter::fill]), *this); }
BOOST_CNV_PARAM(uppercase, bool const)
{
bool uppercase = arg[cnv::parameter::uppercase];
uppercase ? (void) stream_.setf(std::ios::uppercase) : stream_.unsetf(std::ios::uppercase);
return *this;
}
BOOST_CNV_PARAM(skipws, bool const)
{
bool skipws = arg[cnv::parameter::skipws];
skipws ? (void) stream_.setf(std::ios::skipws) : stream_.unsetf(std::ios::skipws);
return *this;
}
BOOST_CNV_PARAM(adjust, boost::cnv::adjust::type const)
{
cnv::adjust::type adjust = arg[cnv::parameter::adjust];
/**/ if (adjust == cnv::adjust:: left) stream_.setf(std::ios::adjustfield, std::ios:: left);
else if (adjust == cnv::adjust::right) stream_.setf(std::ios::adjustfield, std::ios::right);
else BOOST_ASSERT(!"Not implemented");
return *this;
}
BOOST_CNV_PARAM(base, boost::cnv::base::type const)
{
cnv::base::type base = arg[cnv::parameter::base];
/**/ if (base == cnv::base::dec) std::dec(stream_);
else if (base == cnv::base::hex) std::hex(stream_);
else if (base == cnv::base::oct) std::oct(stream_);
else BOOST_ASSERT(!"Not implemented");
return *this;
}
BOOST_CNV_PARAM(notation, boost::cnv::notation::type const)
{
cnv::notation::type notation = arg[cnv::parameter::notation];
/**/ if (notation == cnv::notation:: fixed) std::fixed(stream_);
else if (notation == cnv::notation::scientific) std::scientific(stream_);
else BOOST_ASSERT(!"Not implemented");
return *this;
}
private:
template<typename string_type, typename out_type> void str_to(cnv::range<string_type>, optional<out_type>&) const;
template<typename string_type, typename in_type> void to_str(in_type const&, optional<string_type>&) const;
mutable stream_type stream_;
};
template<typename char_type>
template<typename string_type, typename in_type>
inline
void
boost::cnv::basic_stream<char_type>::to_str(
in_type const& value_in,
boost::optional<string_type>& string_out) const
{
stream_.clear(); // Clear the flags
stream_.str(stdstr_type()); // Clear/empty the content of the stream
if (!(stream_ << value_in).fail())
{
buffer_type* buf = stream_.rdbuf();
obuffer_type* obuf = static_cast<obuffer_type*>(buf);
char_type const* beg = obuf->pbase();
char_type const* end = obuf->pptr();
string_out = string_type(beg, end); // Instead of stream_.str();
}
}
template<typename char_type>
template<typename string_type, typename out_type>
inline
void
boost::cnv::basic_stream<char_type>::str_to(
boost::cnv::range<string_type> string_in,
boost::optional<out_type>& result_out) const
{
if (string_in.empty ()) return;
istream_type& istream = stream_;
buffer_type* oldbuf = istream.rdbuf();
char_type const* beg = &*string_in.begin();
std::size_t sz = string_in.end() - string_in.begin();
ibuffer_type newbuf (beg, sz); //C02
istream.rdbuf(&newbuf);
istream.clear(); // Clear the flags
istream >> *(result_out = boost::make_default<out_type>());
if (istream.fail() || newbuf.gptr() != newbuf.egptr()/*C03*/)
result_out = boost::none;
istream.rdbuf(oldbuf);
}
#undef BOOST_CNV_STRING_ENABLE
#undef BOOST_CNV_PARAM
#endif // BOOST_CONVERT_STRINGSTREAM_BASED_CONVERTER_HPP
@@ -0,0 +1,219 @@
// Copyright (c) 2009-2016 Vladimir Batov.
// Use, modification and distribution are subject to the Boost Software License,
// Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
#ifndef BOOST_CONVERT_STRTOL_CONVERTER_HPP
#define BOOST_CONVERT_STRTOL_CONVERTER_HPP
#include <boost/convert/base.hpp>
#include <boost/type_traits/make_unsigned.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/math/special_functions/round.hpp>
#include <limits>
#include <cmath>
#include <cstdlib>
#include <climits>
#if __GNUC__ == 4 && __GNUC_MINOR__ <= 2
namespace std
{
using ::strtold; // Tests indicated that gcc-4.2.1 does not have 'std::strtold'
}
#endif
namespace boost { namespace cnv
{
struct strtol;
}}
/// @brief std::strtol-based extended converter
/// @details The converter offers a fairly decent overall performance and moderate formatting facilities.
struct boost::cnv::strtol : public boost::cnv::cnvbase<boost::cnv::strtol>
{
typedef boost::cnv::strtol this_type;
typedef boost::cnv::cnvbase<this_type> base_type;
using base_type::operator();
private:
friend struct boost::cnv::cnvbase<this_type>;
template<typename string_type> void str_to(cnv::range<string_type> v, optional< int_type>& r) const { str_to_i (v, r); }
template<typename string_type> void str_to(cnv::range<string_type> v, optional< sint_type>& r) const { str_to_i (v, r); }
template<typename string_type> void str_to(cnv::range<string_type> v, optional< lint_type>& r) const { str_to_i (v, r); }
template<typename string_type> void str_to(cnv::range<string_type> v, optional< llint_type>& r) const { str_to_i (v, r); }
template<typename string_type> void str_to(cnv::range<string_type> v, optional< uint_type>& r) const { str_to_i (v, r); }
template<typename string_type> void str_to(cnv::range<string_type> v, optional< usint_type>& r) const { str_to_i (v, r); }
template<typename string_type> void str_to(cnv::range<string_type> v, optional< ulint_type>& r) const { str_to_i (v, r); }
template<typename string_type> void str_to(cnv::range<string_type> v, optional<ullint_type>& r) const { str_to_i (v, r); }
template<typename string_type> void str_to(cnv::range<string_type> v, optional< flt_type>& r) const { str_to_d (v, r); }
template<typename string_type> void str_to(cnv::range<string_type> v, optional< dbl_type>& r) const { str_to_d (v, r); }
template<typename string_type> void str_to(cnv::range<string_type> v, optional< ldbl_type>& r) const { str_to_d (v, r); }
template <typename char_type> cnv::range<char_type*> to_str ( int_type v, char_type* buf) const { return i_to_str(v, buf); }
template <typename char_type> cnv::range<char_type*> to_str ( uint_type v, char_type* buf) const { return i_to_str(v, buf); }
template <typename char_type> cnv::range<char_type*> to_str ( lint_type v, char_type* buf) const { return i_to_str(v, buf); }
template <typename char_type> cnv::range<char_type*> to_str ( ulint_type v, char_type* buf) const { return i_to_str(v, buf); }
template <typename char_type> cnv::range<char_type*> to_str ( llint_type v, char_type* buf) const { return i_to_str(v, buf); }
template <typename char_type> cnv::range<char_type*> to_str (ullint_type v, char_type* buf) const { return i_to_str(v, buf); }
template <typename char_type> cnv::range<char_type*> to_str ( dbl_type v, char_type* buf) const;
template<typename char_type, typename in_type> cnv::range<char_type*> i_to_str (in_type, char_type*) const;
template<typename string_type, typename out_type> void str_to_i (cnv::range<string_type>, optional<out_type>&) const;
template<typename string_type, typename out_type> void str_to_d (cnv::range<string_type>, optional<out_type>&) const;
static double adjust_fraction (double, int);
static int get_char (int v) { return (v < 10) ? (v += '0') : (v += 'A' - 10); }
};
template<typename char_type, typename Type>
boost::cnv::range<char_type*>
boost::cnv::strtol::i_to_str(Type in_value, char_type* buf) const
{
// C1. Base=10 optimization improves performance 10%
typedef typename boost::make_unsigned<Type>::type unsigned_type;
char_type* beg = buf + bufsize_ / 2;
char_type* end = beg;
bool const is_negative = in_value < 0;
unsigned_type value = static_cast<unsigned_type>(is_negative ? -in_value : in_value);
if (base_ == 10) for (; value; *(--beg) = int(value % 10) + '0', value /= 10); //C1
else for (; value; *(--beg) = get_char(value % base_), value /= base_);
if (beg == end) *(--beg) = '0';
if (is_negative) *(--beg) = '-';
return cnv::range<char_type*>(beg, end);
}
inline
double
boost::cnv::strtol::adjust_fraction(double fraction, int precision)
{
// C1. Bring forward the fraction coming right after precision digits.
// That is, say, fraction=0.234567, precision=2. Then brought forward=23.4567
// C3. INT_MAX(4bytes)=2,147,483,647. So, 10^8 seems appropriate. If not, drop it down to 4.
// C4. ::round() returns the integral value that is nearest to x,
// with halfway cases rounded away from zero. Therefore,
// round( 0.4) = 0
// round( 0.5) = 1
// round( 0.6) = 1
// round(-0.4) = 0
// round(-0.5) = -1
// round(-0.6) = -1
int const tens[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 };
for (int k = precision / 8; k; --k) fraction *= 100000000; //C3.
fraction *= tens[precision % 8]; //C1
// return ::rint(fraction); //C4
return boost::math::round(fraction); //C4
}
template <typename char_type>
inline
boost::cnv::range<char_type*>
boost::cnv::strtol::to_str(double value, char_type* buf) const
{
char_type* beg = buf + bufsize_ / 2;
char_type* end = beg;
char_type* ipos = end - 1;
bool const is_negative = (value < 0) ? (value = -value, true) : false;
double ipart = std::floor(value);
double fpart = adjust_fraction(value - ipart, precision_);
int precision = precision_;
int const base = 10;
for (; 1 <= ipart; ipart /= base)
*(--beg) = get_char(int(ipart - std::floor(ipart / base) * base));
if (beg == end) *(--beg) = '0';
if (precision) *(end++) = '.';
for (char_type* fpos = end += precision; precision; --precision, fpart /= base)
*(--fpos) = get_char(int(fpart - std::floor(fpart / base) * base));
if (1 <= fpart)
{
for (; beg <= ipos; --ipos)
if (*ipos == '9') *ipos = '0';
else { ++*ipos; break; }
if (ipos < beg)
*(beg = ipos) = '1';
}
if (is_negative) *(--beg) = '-';
return cnv::range<char_type*>(beg, end);
}
template<typename string_type, typename out_type>
void
boost::cnv::strtol::str_to_i(cnv::range<string_type> range, boost::optional<out_type>& result_out) const
{
typedef typename boost::make_unsigned<out_type>::type unsigned_type;
typedef cnv::range<string_type> range_type;
typedef typename range_type::iterator iterator;
iterator s = range.begin();
unsigned int ch = *s;
bool const is_negative = ch == '-' ? (ch = *++s, true) : ch == '+' ? (ch = *++s, false) : false;
bool const is_unsigned = boost::is_same<out_type, unsigned_type>::value;
unsigned int base = 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)() + (is_negative ? 1 : 0);
unsigned_type const cutoff = max / base;
unsigned int const cutlim = max % base;
unsigned_type result = 0;
for (; s != range.sentry(); ++s)
{
ch = *s;
/**/ if (std::isdigit(ch)) ch -= '0';
else if (std::isalpha(ch)) ch -= (std::isupper(ch) ? 'A' : 'a') - 10;
else return;
if (base <= ch || cutoff < result || (result == cutoff && cutlim < ch))
return;
result *= base;
result += ch;
}
result_out = is_negative ? -out_type(result) : out_type(result);
}
template<typename string_type, typename out_type>
void
boost::cnv::strtol::str_to_d(cnv::range<string_type> range, optional<out_type>& result_out) const
{
// C2. Simply check if the end-of-string was reached -- *cnv_end == 0
// instead of traversing once with strlen() to find the end iterator
// and then comparing to it as in
// char const* end = str + strlen(str); // Unnecessary traversal!
// bool const good = ... && cnv_end == end;
typedef cnv::range<string_type> range_type;
typedef typename range_type::value_type ch_type;
ch_type const* str = &*range.begin(); // Currently only works with 'char'
char* cnv_end = 0;
ldbl_type result = strtold(str, &cnv_end);
bool good = result != -HUGE_VALL && result != HUGE_VALL && *cnv_end == 0/*C2*/;
out_type max = (std::numeric_limits<out_type>::max)();
if (good && -max <= result && result <= max)
result_out = out_type(result);
}
#endif // BOOST_CONVERT_STRTOL_CONVERTER_HPP