parse: add more documentation for parsing templates

This commit is contained in:
Danny Robson 2019-02-02 13:44:04 +11:00
parent 4c29123d4d
commit 4b37f59e22

View File

@ -9,6 +9,7 @@
#include "parse.hpp" #include "parse.hpp"
#include "cast.hpp" #include "cast.hpp"
#include "preprocessor.hpp"
#include <cstdlib> #include <cstdlib>
#include <stdexcept> #include <stdexcept>
@ -16,15 +17,22 @@
using cruft::parse; using cruft::parse;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
template <typename T> struct c_traits; /// A trait class that records the C string parsing function for a given type.
template <> struct c_traits<long> { static constexpr auto func = strtol; }; ///
template <> struct c_traits<long long> { static constexpr auto func = strtoll; }; /// Not all types will necessarily have a corresponding parsing function. eg,
template <> struct c_traits<unsigned long> { static constexpr auto func = strtoul; }; template <typename ValueT> struct parse_traits { };
template <> struct c_traits<unsigned long long> { static constexpr auto func = strtoull; };
template <> struct c_traits<float> { static constexpr auto func = strtof; }; //-----------------------------------------------------------------------------
template <> struct c_traits<double> { static constexpr auto func = strtod; }; template <> struct parse_traits<long> { static constexpr auto value = strtol; };
template <> struct c_traits<long double> { static constexpr auto func = strtold; }; template <> struct parse_traits<long long> { static constexpr auto value = strtoll; };
template <> struct parse_traits<unsigned long> { static constexpr auto value = strtoul; };
template <> struct parse_traits<unsigned long long> { static constexpr auto value = strtoull; };
//-----------------------------------------------------------------------------
template <> struct parse_traits<float> { static constexpr auto value = strtof; };
template <> struct parse_traits<double> { static constexpr auto value = strtod; };
template <> struct parse_traits<long double> { static constexpr auto value = strtold; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -34,7 +42,7 @@ c_iparse (cruft::view<char const*> &data)
{ {
auto head = const_cast<char *> (data.begin ()); auto head = const_cast<char *> (data.begin ());
auto tail = head; auto tail = head;
auto val = c_traits<T>::func (head, &tail, 0); auto val = parse_traits<T>::value (head, &tail, 0);
if (tail == head) if (tail == head)
throw std::invalid_argument ("unable to parse integer"); throw std::invalid_argument ("unable to parse integer");
@ -51,7 +59,7 @@ c_fparse (cruft::view<char const*> &data)
{ {
auto head = const_cast<char *> (data.begin ()); auto head = const_cast<char *> (data.begin ());
auto tail = head; auto tail = head;
auto val = c_traits<T>::func (head, &tail); auto val = parse_traits<T>::value (head, &tail);
if (tail == head) if (tail == head)
throw std::invalid_argument ("unable to parse float"); throw std::invalid_argument ("unable to parse float");
@ -64,27 +72,45 @@ c_fparse (cruft::view<char const*> &data)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#define C_PARSE(T, KLASS) \ /// Specialise cruft::parse for the type KLASS and dispatch the actual parsing
template <> \ /// to safe template wrappers around the C parsing functions.
T \ #define C_PARSE(PREFIX, KLASS) \
cruft::parse<T> ( \ template <> \
cruft::view<const char *> &str \ KLASS \
) { \ cruft::parse<KLASS> ( \
return c_ ## KLASS ## parse<T> (str); \ cruft::view<const char *> &str \
) { \
return c_ ## PREFIX ## parse<KLASS> (str); \
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
C_PARSE(long, i) MAP1(C_PARSE, i,
C_PARSE(long long, i) unsigned long,
C_PARSE(unsigned long, i) unsigned long long,
C_PARSE(unsigned long long, i) long,
long long
C_PARSE(float, f) )
C_PARSE(double, f)
C_PARSE(long double, f)
//-----------------------------------------------------------------------------
MAP1(C_PARSE, f,
float,
double,
long double
)
///////////////////////////////////////////////////////////////////////////////
/// Specialise cruft::parse for the type FINAL and dispatch the actual parsing
/// to the safe template wrappers defined above, but use the type USED as an
/// intermediary type.
///
/// We need to parse using the type `USED` because there aren't C parsing
/// routines for all the fundamental types.
///
/// We check that the final result can safely fit within `FINAL` before
/// returning the value, else we raise an exception.
#define C_PARSE_WITH_CAST(FINAL, USED) \ #define C_PARSE_WITH_CAST(FINAL, USED) \
template<> \ template<> \
FINAL \ FINAL \