From 642317f6a4789dc4d4d93ba6cae64c1d31740647 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 28 Jun 2016 14:16:28 +1000 Subject: [PATCH] json: use templated iterator for parsing from views --- json/flat.cpp.rl | 38 ++++++++------ json/flat.hpp | 16 +++--- json/tree.cpp | 114 +++++++++++++++++++++++----------------- json/tree.hpp | 11 +++- test/json_types.cpp | 2 +- tools/json-validate.cpp | 6 ++- 6 files changed, 109 insertions(+), 78 deletions(-) diff --git a/json/flat.cpp.rl b/json/flat.cpp.rl index 8504ec11..71d82257 100644 --- a/json/flat.cpp.rl +++ b/json/flat.cpp.rl @@ -20,9 +20,9 @@ #include "json/flat.hpp" #include "json/except.hpp" - -#include "io.hpp" #include "debug.hpp" +#include "io.hpp" +#include "preprocessor.hpp" #include @@ -143,15 +143,16 @@ //----------------------------------------------------------------------------- -std::vector -json::flat::parse (const char *first, const char *last) +template +std::vector> +json::flat::parse (const util::view src) { - const char *p = first; - const char *pe = last; - const char *eof = pe; + auto p = src.cbegin (); + auto pe = src.cend (); + auto eof = pe; std::deque ragelstack; - std::vector parsed; + std::vector> parsed; size_t line = 0; int cs, top; @@ -166,17 +167,20 @@ json::flat::parse (const char *first, const char *last) return parsed; } +#define INSTANTIATE(KLASS) \ +template \ +std::vector> \ +json::flat::parse (util::view); -//----------------------------------------------------------------------------- -std::vector -json::flat::parse (const boost::filesystem::path &path) -{ - util::mapped_file f (path.string ().c_str ()); - if (f.empty ()) - throw parse_error ("empty file"); +MAP( + INSTANTIATE, - return parse ((const char *)f.cbegin (), (const char*)f.cend ()); -} + std::string::iterator, + std::string::const_iterator, + const char*restrict +) + +#undef INSTANTIATE //----------------------------------------------------------------------------- diff --git a/json/flat.hpp b/json/flat.hpp index d86e553b..b8a58224 100644 --- a/json/flat.hpp +++ b/json/flat.hpp @@ -20,6 +20,8 @@ #include #include +#include "../view.hpp" + namespace json { namespace flat { enum class type { UNKNOWN, @@ -37,18 +39,18 @@ namespace json { namespace flat { ARRAY_END }; + template struct item { type tag; - const char *first; - const char *last; + T first; + T last; - template - T as (void) const; + template + U as (void) const; }; - std::vector parse (const char *first, const char *last); - std::vector parse (const char *first); - std::vector parse (const boost::filesystem::path&); + template + std::vector> parse (util::view data); std::ostream& operator<< (std::ostream&, type); } } diff --git a/json/tree.cpp b/json/tree.cpp index 4afb7ef9..a65d09fe 100644 --- a/json/tree.cpp +++ b/json/tree.cpp @@ -76,16 +76,20 @@ namespace util { } /////////////////////////////////////////////////////////////////////////////// -static std::vector::const_iterator -parse (std::vector::const_iterator first, - std::vector::const_iterator last, +template +static +typename std::vector>::const_iterator +parse (typename std::vector>::const_iterator first, + typename std::vector>::const_iterator last, std::unique_ptr &output); //----------------------------------------------------------------------------- -static std::vector::const_iterator -parse (std::vector::const_iterator first, - std::vector::const_iterator last, +template +static +typename std::vector>::const_iterator +parse (typename std::vector>::const_iterator first, + typename std::vector>::const_iterator last, json::tree::array &parent) { for (auto cursor = first; cursor != last; ) { @@ -93,7 +97,7 @@ parse (std::vector::const_iterator first, return cursor + 1; std::unique_ptr value; - cursor = ::parse (cursor, last, value); + cursor = ::parse (cursor, last, value); parent.insert (std::move (value)); } @@ -102,9 +106,11 @@ parse (std::vector::const_iterator first, //----------------------------------------------------------------------------- -static std::vector::const_iterator -parse (std::vector::const_iterator first, - std::vector::const_iterator last, +template +static +typename std::vector>::const_iterator +parse (typename std::vector>::const_iterator first, + typename std::vector>::const_iterator last, json::tree::object &parent) { for (auto cursor = first; cursor != last; ) { @@ -117,7 +123,7 @@ parse (std::vector::const_iterator first, ++cursor; std::unique_ptr val; - cursor = ::parse (cursor, last, val); + cursor = ::parse (cursor, last, val); parent.insert (key, std::move (val)); } @@ -127,71 +133,78 @@ parse (std::vector::const_iterator first, //----------------------------------------------------------------------------- -static std::vector::const_iterator -parse (std::vector::const_iterator first, - std::vector::const_iterator last, +template +static +typename std::vector>::const_iterator +parse (typename std::vector>::const_iterator first, + typename std::vector>::const_iterator last, std::unique_ptr &output) { CHECK (first != last); CHECK (output.get () == nullptr); - using T = json::flat::type; + using F = json::flat::type; switch (first->tag) { - case T::NUL: + case F::NUL: output.reset (new json::tree::null ()); return first + 1; - case T::BOOLEAN: + case F::BOOLEAN: CHECK (*first->first == 't' || *first->first == 'f'); output.reset (new json::tree::boolean (*first->first == 't')); return first + 1; - case T::STRING: - CHECK_NEQ (first->first, first->last); + case F::STRING: + CHECK_NEQ (&*first->first, &*first->last); output.reset (new json::tree::string (first->first + 1, first->last - 1)); return first + 1; - case T::INTEGER: - if (first->first[0] == '-') { - char *end; - intmax_t v = strtoll (first->first, &end, 10); - - if (end == first->first || end > first->last) - throw json::parse_error ("invalid signed integer"); - output.reset (new json::tree::number (v)); - } else { - char *end; - uintmax_t v = strtoull (first->first, &end, 10); + case F::INTEGER: { + T start = first->first; + bool negative = *start == '-'; + if (negative) + ++start; - if (end == first->first || end > first->last) - throw json::parse_error ("invalid unsigned integer"); + T finish = start; + uintmax_t v = 0; + while (isdigit (*finish)) + v *= 10, v += *finish - '0', ++finish; + + if (finish == start || finish > first->last) + throw json::parse_error ("invalid integer"); + + if (negative) + output.reset (new json::tree::number (-intmax_t(v))); + else output.reset (new json::tree::number (v)); - } return first + 1; + } - case T::REAL: - output.reset (new json::tree::number (std::atof (first->first))); + case F::REAL: { + std::string str (first->first, first->last); + output.reset (new json::tree::number (std::atof (str.c_str()))); return first + 1; + } - case T::ARRAY_BEGIN: { + case F::ARRAY_BEGIN: { auto value = std::make_unique (); - auto cursor = ::parse (first + 1, last, *value); + auto cursor = ::parse (first + 1, last, *value); output = std::move (value); return cursor; } - case T::OBJECT_BEGIN: { + case F::OBJECT_BEGIN: { auto value = std::make_unique (); - auto cursor = ::parse (first + 1, last, *value); + auto cursor = ::parse (first + 1, last, *value); output = std::move (value); return cursor; } - case T::UNKNOWN: - case T::OBJECT_END: - case T::ARRAY_END: + case F::UNKNOWN: + case F::OBJECT_END: + case F::ARRAY_END: unreachable (); } @@ -203,15 +216,17 @@ parse (std::vector::const_iterator first, std::unique_ptr json::tree::parse (const boost::filesystem::path &path) { - util::mapped_file f (path.string ().c_str ()); - return parse ((const char*)f.cbegin (), (const char*)f.cend ()); + const util::mapped_file f (path.string ().c_str ()); + return parse (f.operator util::view ()); } //----------------------------------------------------------------------------- std::unique_ptr -json::tree::parse (const std::string &path) - { return parse (path.c_str (), path.c_str () + path.size ()); } +json::tree::parse (const std::string &data) +{ + return parse (::util::make_view (data)); +} //----------------------------------------------------------------------------- @@ -221,12 +236,13 @@ json::tree::write (const json::tree::node &node, std::ostream &os) //----------------------------------------------------------------------------- +template std::unique_ptr -json::tree::parse (const char *first, const char *last) +json::tree::parse (const util::view src) { std::unique_ptr output; - auto data = json::flat::parse (first, last); - auto end = ::parse (data.cbegin (), data.cend (), output); + auto data = json::flat::parse (src); + auto end = ::parse (data.cbegin (), data.cend (), output); CHECK (end == data.cend ()); (void)end; diff --git a/json/tree.hpp b/json/tree.hpp index 0aa2b19f..65270464 100644 --- a/json/tree.hpp +++ b/json/tree.hpp @@ -26,6 +26,7 @@ #include #include "../iterator.hpp" +#include "../view.hpp" #include "./flat.hpp" #include "./fwd.hpp" @@ -41,8 +42,11 @@ namespace json { namespace tree { /// Parse an encoded form of JSON into a tree structure extern std::unique_ptr parse (const boost::filesystem::path &path); - extern std::unique_ptr parse (const char *start, const char *stop); - extern std::unique_ptr parse (const std::string&); + extern std::unique_ptr parse (const std::string &data); + + template + std::unique_ptr + parse (util::view data); extern std::unique_ptr from_path (const char *path); extern std::unique_ptr from_path (const std::string&); @@ -211,6 +215,9 @@ namespace json { namespace tree { std::string m_value; public: + template + string (T first, T last): m_value (first, last) { ; } + explicit string (const std::string &_value): m_value (_value) { ; } explicit string (const char *_value): m_value (_value) { ; } string (const char *_first, const char *_last): m_value (_first, _last) { ; } diff --git a/test/json_types.cpp b/test/json_types.cpp index 02dd6bd5..bc9173e5 100644 --- a/test/json_types.cpp +++ b/test/json_types.cpp @@ -28,7 +28,7 @@ main (void) ] })_"; - std::unique_ptr ptr = json::tree::parse (TEST_STRING); + std::unique_ptr ptr = json::tree::parse (util::make_view (TEST_STRING)); tap.expect (ptr->is_object (), "is_object"); CHECK (ptr->is_object ()); diff --git a/tools/json-validate.cpp b/tools/json-validate.cpp index 90009d8c..ec173037 100644 --- a/tools/json-validate.cpp +++ b/tools/json-validate.cpp @@ -12,11 +12,12 @@ * limitations under the License. * * Copyright: - * 2014-2015, Danny Robson + * 2014-2016, Danny Robson */ #include "json/flat.hpp" #include "json/except.hpp" +#include "io.hpp" #include #include @@ -41,7 +42,8 @@ main (int argc, char ** argv) { } try { - json::flat::parse (boost::filesystem::path (argv[ARG_PATH])); + util::mapped_file data (argv[ARG_PATH]); + json::flat::parse (data.operator util::view ()); } catch (const json::error &x) { std::cerr << "error: " << x.what () << '\n'; return EXIT_FAILURE;