From 5fedbdbdfe50bde1a331a78828c25c349ac8fde5 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Sun, 16 Dec 2018 13:26:48 +1100 Subject: [PATCH] parse: change parsing functions to modify the data view --- colour.cpp | 5 +-- job/queue.cpp | 4 +-- parse.cpp | 82 ++++++++++++++++++++++++-------------------------- parse.hpp | 55 ++++++++++++++++----------------- test/parse.cpp | 8 ++--- 5 files changed, 74 insertions(+), 80 deletions(-) diff --git a/colour.cpp b/colour.cpp index 7b22f637..10586b9f 100644 --- a/colour.cpp +++ b/colour.cpp @@ -14,7 +14,7 @@ /////////////////////////////////////////////////////////////////////////////// static cruft::srgba4f -parse_hex (cruft::view str) +parse_hex (cruft::view &str) { if (str.size () != strlen ("#012345")) throw std::invalid_argument ("expected length of 7"); @@ -36,6 +36,7 @@ parse_hex (cruft::view str) 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]); + str = str.consume (7); return cruft::srgba<4,uint8_t> { r, g, b, 255 }.template cast (); } @@ -44,7 +45,7 @@ parse_hex (cruft::view str) /////////////////////////////////////////////////////////////////////////////// template <> cruft::srgba4f -cruft::parse (cruft::view str) +cruft::parse (cruft::view &str) { return parse_hex (str); } \ No newline at end of file diff --git a/job/queue.cpp b/job/queue.cpp index df3c64f0..272e93dc 100644 --- a/job/queue.cpp +++ b/job/queue.cpp @@ -19,7 +19,7 @@ static unsigned default_parallelism (void) { if (auto var = getenv ("JOB_THREADS")) { - return cruft::parse (var); + return cruft::from_string (var); } return std::thread::hardware_concurrency (); @@ -31,7 +31,7 @@ static unsigned default_depth (void) { if (auto var = getenv ("JOB_DEPTH")) { - return cruft::parse (var); + return cruft::from_string (var); } return 1024; diff --git a/parse.cpp b/parse.cpp index 31a148a8..fd1e8d7a 100644 --- a/parse.cpp +++ b/parse.cpp @@ -3,7 +3,7 @@ * 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/. * - * Copyright 2017 Danny Robson + * Copyright 2017-2018 Danny Robson */ #include "parse.hpp" @@ -30,14 +30,16 @@ template <> struct c_traits { static constexpr auto func = strtold; //----------------------------------------------------------------------------- template T -c_iparse (const char *first, const char *last) +c_iparse (cruft::view &data) { - auto tail = const_cast (last); - auto val = c_traits::func (first, &tail, 0); + auto head = const_cast (data.begin ()); + auto tail = head; + auto val = c_traits::func (head, &tail, 0); - if (tail != last) - throw std::invalid_argument ("unable to parse"); + if (tail == head) + throw std::invalid_argument ("unable to parse integer"); + data = data.consume (tail); return val; } @@ -45,14 +47,16 @@ c_iparse (const char *first, const char *last) //----------------------------------------------------------------------------- template T -c_fparse (const char *first, const char *last) +c_fparse (cruft::view &data) { - auto tail = const_cast (last); - auto val = c_traits::func (first, &tail); + auto head = const_cast (data.begin ()); + auto tail = head; + auto val = c_traits::func (head, &tail); - if (tail != last) - throw std::invalid_argument ("unable to parse"); + if (tail == head) + throw std::invalid_argument ("unable to parse float"); + data = data.consume (tail); return val; } @@ -60,46 +64,38 @@ c_fparse (const char *first, const char *last) /////////////////////////////////////////////////////////////////////////////// -#define C_PARSE(T, KLASS) \ -template <> \ -T \ -cruft::parse (cruft::view str) \ -{ \ - return c_ ## KLASS ## parse (std::cbegin (str), std::cend (str)); \ +#define C_PARSE(T, KLASS) \ +template <> \ +T \ +cruft::parse ( \ + cruft::view &str \ +) { \ + return c_ ## KLASS ## parse (str); \ } //----------------------------------------------------------------------------- -C_PARSE(long, i) -C_PARSE(long long, i) -C_PARSE(unsigned long, i) +C_PARSE(long, i) +C_PARSE(long long, i) +C_PARSE(unsigned long, i) C_PARSE(unsigned long long, i) -C_PARSE(float, f) -C_PARSE(double, f) +C_PARSE(float, f) +C_PARSE(double, f) C_PARSE(long double, f) -template <> -int -cruft::parse (cruft::view str) -{ - auto intermediate = cruft::parse (str); - return cruft::cast::lossless (intermediate); +#define C_PARSE_WITH_CAST(FINAL, USED) \ +template<> \ +FINAL \ +cruft::parse (cruft::view &str) { \ + auto remain = str; \ + auto res = parse (remain); \ + if (res > std::numeric_limits::max ()) \ + throw std::invalid_argument ("overflow during parse"); \ + \ + str = remain; \ + return cruft::cast::narrow (res); \ } - -template <> -unsigned -cruft::parse (cruft::view str) -{ - return cruft::cast::narrow (parse (str)); -} - - -template <> -unsigned short -cruft::parse (cruft::view str) -{ - return cruft::cast::narrow (parse (str)); -} +C_PARSE_WITH_CAST(unsigned int, unsigned long) diff --git a/parse.hpp b/parse.hpp index 46b779b0..2c74922d 100644 --- a/parse.hpp +++ b/parse.hpp @@ -3,43 +3,40 @@ * 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/. * - * Copyright 2017 Danny Robson + * Copyright 2017-2018 Danny Robson */ -#ifndef CRUFT_UTIL_PARSE_HPP -#define CRUFT_UTIL_PARSE_HPP +#pragma once #include "view.hpp" -#include -#include -#include - - 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. - template - T parse (cruft::view); - - - //------------------------------------------------------------------------- - template - T parse (const char *str) - { - return parse (make_view (str)); - } - - - //------------------------------------------------------------------------- + /// Throws std::invalid_argument when the type cannot be parsed. + /// + /// The view is modified in place to reflect the unused data. template T - parse (const std::string &str) - { - return parse (make_view (str)); - } -} + parse (cruft::view &); -#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 + T + from_string (cruft::view data) + { + T res = parse (data); + if (!data.empty ()) + throw std::invalid_argument ("unable to parse"); + return std::move (res); + } + + template T from_string (const char *data) { return from_string (cruft::view (data)); } + template T from_string (std::string const &data) { return from_string (cruft::view (data)); } +} diff --git a/test/parse.cpp b/test/parse.cpp index b32d9ede..4f9475d5 100644 --- a/test/parse.cpp +++ b/test/parse.cpp @@ -8,11 +8,11 @@ main (void) { cruft::TAP::logger tap; - tap.expect_eq (cruft::parse ("1"), 1L, "parsing long '1'"); - tap.expect_throw ([] () { cruft::parse ("a"); }, "parsing long 'a'"); + tap.expect_eq (cruft::from_string ("1"), 1L, "parsing long '1'"); + tap.expect_throw ([] () { cruft::from_string ("a"); }, "parsing long 'a'"); - tap.expect_eq (cruft::parse ("1"), 1.f, "parsing float '1'"); - tap.expect_throw ([] () { cruft::parse ("a"); }, "parsing float 'a'"); + tap.expect_eq (cruft::from_string ("1"), 1.f, "parsing float '1'"); + tap.expect_throw ([] () { cruft::from_string ("a"); }, "parsing float 'a'"); return tap.status (); } \ No newline at end of file