parse: change parsing functions to modify the data view

This commit is contained in:
Danny Robson 2018-12-16 13:26:48 +11:00
parent 44760c6869
commit 5fedbdbdfe
5 changed files with 74 additions and 80 deletions

View File

@ -14,7 +14,7 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
static cruft::srgba4f static cruft::srgba4f
parse_hex (cruft::view<const char*> str) parse_hex (cruft::view<const char*> &str)
{ {
if (str.size () != strlen ("#012345")) if (str.size () != strlen ("#012345"))
throw std::invalid_argument ("expected length of 7"); throw std::invalid_argument ("expected length of 7");
@ -36,6 +36,7 @@ parse_hex (cruft::view<const char*> str)
uint8_t g = cruft::ascii::from_hex (str[3]) << 4u | cruft::ascii::from_hex (str[4]); uint8_t g = cruft::ascii::from_hex (str[3]) << 4u | cruft::ascii::from_hex (str[4]);
uint8_t b = cruft::ascii::from_hex (str[5]) << 4u | cruft::ascii::from_hex (str[6]); uint8_t b = cruft::ascii::from_hex (str[5]) << 4u | cruft::ascii::from_hex (str[6]);
str = str.consume (7);
return cruft::srgba<4,uint8_t> { r, g, b, 255 }.template cast<float> (); return cruft::srgba<4,uint8_t> { r, g, b, 255 }.template cast<float> ();
} }
@ -44,7 +45,7 @@ parse_hex (cruft::view<const char*> str)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
template <> template <>
cruft::srgba4f cruft::srgba4f
cruft::parse<cruft::srgba4f> (cruft::view<const char*> str) cruft::parse<cruft::srgba4f> (cruft::view<const char*> &str)
{ {
return parse_hex (str); return parse_hex (str);
} }

View File

@ -19,7 +19,7 @@ static unsigned
default_parallelism (void) default_parallelism (void)
{ {
if (auto var = getenv ("JOB_THREADS")) { if (auto var = getenv ("JOB_THREADS")) {
return cruft::parse<unsigned> (var); return cruft::from_string<unsigned> (var);
} }
return std::thread::hardware_concurrency (); return std::thread::hardware_concurrency ();
@ -31,7 +31,7 @@ static unsigned
default_depth (void) default_depth (void)
{ {
if (auto var = getenv ("JOB_DEPTH")) { if (auto var = getenv ("JOB_DEPTH")) {
return cruft::parse<unsigned> (var); return cruft::from_string<unsigned> (var);
} }
return 1024; return 1024;

View File

@ -3,7 +3,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
* *
* Copyright 2017 Danny Robson <danny@nerdcruft.net> * Copyright 2017-2018 Danny Robson <danny@nerdcruft.net>
*/ */
#include "parse.hpp" #include "parse.hpp"
@ -30,14 +30,16 @@ template <> struct c_traits<long double> { static constexpr auto func = strtold;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T> template <typename T>
T T
c_iparse (const char *first, const char *last) c_iparse (cruft::view<char const*> &data)
{ {
auto tail = const_cast<char *> (last); auto head = const_cast<char *> (data.begin ());
auto val = c_traits<T>::func (first, &tail, 0); auto tail = head;
auto val = c_traits<T>::func (head, &tail, 0);
if (tail != last) if (tail == head)
throw std::invalid_argument ("unable to parse"); throw std::invalid_argument ("unable to parse integer");
data = data.consume (tail);
return val; return val;
} }
@ -45,14 +47,16 @@ c_iparse (const char *first, const char *last)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T> template <typename T>
T T
c_fparse (const char *first, const char *last) c_fparse (cruft::view<char const*> &data)
{ {
auto tail = const_cast<char *> (last); auto head = const_cast<char *> (data.begin ());
auto val = c_traits<T>::func (first, &tail); auto tail = head;
auto val = c_traits<T>::func (head, &tail);
if (tail != last) if (tail == head)
throw std::invalid_argument ("unable to parse"); throw std::invalid_argument ("unable to parse float");
data = data.consume (tail);
return val; return val;
} }
@ -63,9 +67,10 @@ c_fparse (const char *first, const char *last)
#define C_PARSE(T, KLASS) \ #define C_PARSE(T, KLASS) \
template <> \ template <> \
T \ T \
cruft::parse<T> (cruft::view<const char *> str) \ cruft::parse<T> ( \
{ \ cruft::view<const char *> &str \
return c_ ## KLASS ## parse<T> (std::cbegin (str), std::cend (str)); \ ) { \
return c_ ## KLASS ## parse<T> (str); \
} }
@ -80,26 +85,17 @@ C_PARSE(double, f)
C_PARSE(long double, f) C_PARSE(long double, f)
template <> #define C_PARSE_WITH_CAST(FINAL, USED) \
int template<> \
cruft::parse<int> (cruft::view<const char*> str) FINAL \
{ cruft::parse<FINAL> (cruft::view<char const*> &str) { \
auto intermediate = cruft::parse<long> (str); auto remain = str; \
return cruft::cast::lossless<int> (intermediate); auto res = parse<USED> (remain); \
if (res > std::numeric_limits<FINAL>::max ()) \
throw std::invalid_argument ("overflow during parse"); \
\
str = remain; \
return cruft::cast::narrow<FINAL> (res); \
} }
C_PARSE_WITH_CAST(unsigned int, unsigned long)
template <>
unsigned
cruft::parse<unsigned> (cruft::view<const char*> str)
{
return cruft::cast::narrow<unsigned> (parse<unsigned long> (str));
}
template <>
unsigned short
cruft::parse<unsigned short> (cruft::view<const char*> str)
{
return cruft::cast::narrow<unsigned short> (parse<unsigned long> (str));
}

View File

@ -3,43 +3,40 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
* *
* Copyright 2017 Danny Robson <danny@nerdcruft.net> * Copyright 2017-2018 Danny Robson <danny@nerdcruft.net>
*/ */
#ifndef CRUFT_UTIL_PARSE_HPP #pragma once
#define CRUFT_UTIL_PARSE_HPP
#include "view.hpp" #include "view.hpp"
#include <cstring>
#include <string>
#include <iterator>
namespace cruft { namespace cruft {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
/// extracts an instance of a native type T from the string [first, last). /// Extracts an instance of a native type T from the string [first, last).
/// ///
/// throws std::invalid_argument when the type cannot be parsed. /// Throws std::invalid_argument when the type cannot be parsed.
template <typename T> ///
T parse (cruft::view<const char *>); /// The view is modified in place to reflect the unused data.
//-------------------------------------------------------------------------
template <typename T>
T parse (const char *str)
{
return parse<T> (make_view (str));
}
//-------------------------------------------------------------------------
template <typename T> template <typename T>
T T
parse (const std::string &str) parse (cruft::view<const char *> &);
{
return parse<T> (make_view (str));
}
}
#endif
/// Parses a prefix string to obtain an instance of T.
///
/// This only differs from `parse` in that it throws if the entire string
/// isn't consumed during the parse, rather than reporting the remaining
/// data.
template <typename T>
T
from_string (cruft::view<const char*> data)
{
T res = parse<T> (data);
if (!data.empty ())
throw std::invalid_argument ("unable to parse");
return std::move (res);
}
template <typename T> T from_string (const char *data) { return from_string<T> (cruft::view (data)); }
template <typename T> T from_string (std::string const &data) { return from_string<T> (cruft::view (data)); }
}

View File

@ -8,11 +8,11 @@ main (void)
{ {
cruft::TAP::logger tap; cruft::TAP::logger tap;
tap.expect_eq (cruft::parse<long> ("1"), 1L, "parsing long '1'"); tap.expect_eq (cruft::from_string<long> ("1"), 1L, "parsing long '1'");
tap.expect_throw<std::invalid_argument> ([] () { cruft::parse<long> ("a"); }, "parsing long 'a'"); tap.expect_throw<std::invalid_argument> ([] () { cruft::from_string<long> ("a"); }, "parsing long 'a'");
tap.expect_eq (cruft::parse<float> ("1"), 1.f, "parsing float '1'"); tap.expect_eq (cruft::from_string<float> ("1"), 1.f, "parsing float '1'");
tap.expect_throw<std::invalid_argument> ([] () { cruft::parse<float> ("a"); }, "parsing float 'a'"); tap.expect_throw<std::invalid_argument> ([] () { cruft::from_string<float> ("a"); }, "parsing float 'a'");
return tap.status (); return tap.status ();
} }