json: use templated iterator for parsing from views

This commit is contained in:
Danny Robson 2016-06-28 14:16:28 +10:00
parent 194cd6c574
commit 642317f6a4
6 changed files with 109 additions and 78 deletions

View File

@ -20,9 +20,9 @@
#include "json/flat.hpp" #include "json/flat.hpp"
#include "json/except.hpp" #include "json/except.hpp"
#include "io.hpp"
#include "debug.hpp" #include "debug.hpp"
#include "io.hpp"
#include "preprocessor.hpp"
#include <deque> #include <deque>
@ -143,15 +143,16 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
std::vector<json::flat::item> template <typename T>
json::flat::parse (const char *first, const char *last) std::vector<json::flat::item<T>>
json::flat::parse (const util::view<T> src)
{ {
const char *p = first; auto p = src.cbegin ();
const char *pe = last; auto pe = src.cend ();
const char *eof = pe; auto eof = pe;
std::deque<int> ragelstack; std::deque<int> ragelstack;
std::vector<item> parsed; std::vector<item<T>> parsed;
size_t line = 0; size_t line = 0;
int cs, top; int cs, top;
@ -166,17 +167,20 @@ json::flat::parse (const char *first, const char *last)
return parsed; return parsed;
} }
#define INSTANTIATE(KLASS) \
template \
std::vector<json::flat::item<KLASS>> \
json::flat::parse (util::view<KLASS>);
//----------------------------------------------------------------------------- MAP(
std::vector<json::flat::item> INSTANTIATE,
json::flat::parse (const boost::filesystem::path &path)
{
util::mapped_file f (path.string ().c_str ());
if (f.empty ())
throw parse_error ("empty file");
return parse ((const char *)f.cbegin (), (const char*)f.cend ()); std::string::iterator,
} std::string::const_iterator,
const char*restrict
)
#undef INSTANTIATE
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -20,6 +20,8 @@
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <iostream> #include <iostream>
#include "../view.hpp"
namespace json { namespace flat { namespace json { namespace flat {
enum class type { enum class type {
UNKNOWN, UNKNOWN,
@ -37,18 +39,18 @@ namespace json { namespace flat {
ARRAY_END ARRAY_END
}; };
template <typename T>
struct item { struct item {
type tag; type tag;
const char *first; T first;
const char *last; T last;
template <typename T> template <typename U>
T as (void) const; U as (void) const;
}; };
std::vector<item> parse (const char *first, const char *last); template <typename T>
std::vector<item> parse (const char *first); std::vector<item<T>> parse (util::view<T> data);
std::vector<item> parse (const boost::filesystem::path&);
std::ostream& operator<< (std::ostream&, type); std::ostream& operator<< (std::ostream&, type);
} } } }

View File

@ -76,16 +76,20 @@ namespace util {
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
static std::vector<json::flat::item>::const_iterator template <typename T>
parse (std::vector<json::flat::item>::const_iterator first, static
std::vector<json::flat::item>::const_iterator last, typename std::vector<json::flat::item<T>>::const_iterator
parse (typename std::vector<json::flat::item<T>>::const_iterator first,
typename std::vector<json::flat::item<T>>::const_iterator last,
std::unique_ptr<json::tree::node> &output); std::unique_ptr<json::tree::node> &output);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static std::vector<json::flat::item>::const_iterator template <typename T>
parse (std::vector<json::flat::item>::const_iterator first, static
std::vector<json::flat::item>::const_iterator last, typename std::vector<json::flat::item<T>>::const_iterator
parse (typename std::vector<json::flat::item<T>>::const_iterator first,
typename std::vector<json::flat::item<T>>::const_iterator last,
json::tree::array &parent) json::tree::array &parent)
{ {
for (auto cursor = first; cursor != last; ) { for (auto cursor = first; cursor != last; ) {
@ -93,7 +97,7 @@ parse (std::vector<json::flat::item>::const_iterator first,
return cursor + 1; return cursor + 1;
std::unique_ptr<json::tree::node> value; std::unique_ptr<json::tree::node> value;
cursor = ::parse (cursor, last, value); cursor = ::parse<T> (cursor, last, value);
parent.insert (std::move (value)); parent.insert (std::move (value));
} }
@ -102,9 +106,11 @@ parse (std::vector<json::flat::item>::const_iterator first,
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static std::vector<json::flat::item>::const_iterator template <typename T>
parse (std::vector<json::flat::item>::const_iterator first, static
std::vector<json::flat::item>::const_iterator last, typename std::vector<json::flat::item<T>>::const_iterator
parse (typename std::vector<json::flat::item<T>>::const_iterator first,
typename std::vector<json::flat::item<T>>::const_iterator last,
json::tree::object &parent) json::tree::object &parent)
{ {
for (auto cursor = first; cursor != last; ) { for (auto cursor = first; cursor != last; ) {
@ -117,7 +123,7 @@ parse (std::vector<json::flat::item>::const_iterator first,
++cursor; ++cursor;
std::unique_ptr<json::tree::node> val; std::unique_ptr<json::tree::node> val;
cursor = ::parse (cursor, last, val); cursor = ::parse<T> (cursor, last, val);
parent.insert (key, std::move (val)); parent.insert (key, std::move (val));
} }
@ -127,71 +133,78 @@ parse (std::vector<json::flat::item>::const_iterator first,
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static std::vector<json::flat::item>::const_iterator template <typename T>
parse (std::vector<json::flat::item>::const_iterator first, static
std::vector<json::flat::item>::const_iterator last, typename std::vector<json::flat::item<T>>::const_iterator
parse (typename std::vector<json::flat::item<T>>::const_iterator first,
typename std::vector<json::flat::item<T>>::const_iterator last,
std::unique_ptr<json::tree::node> &output) std::unique_ptr<json::tree::node> &output)
{ {
CHECK (first != last); CHECK (first != last);
CHECK (output.get () == nullptr); CHECK (output.get () == nullptr);
using T = json::flat::type; using F = json::flat::type;
switch (first->tag) { switch (first->tag) {
case T::NUL: case F::NUL:
output.reset (new json::tree::null ()); output.reset (new json::tree::null ());
return first + 1; return first + 1;
case T::BOOLEAN: case F::BOOLEAN:
CHECK (*first->first == 't' || *first->first == 'f'); CHECK (*first->first == 't' || *first->first == 'f');
output.reset (new json::tree::boolean (*first->first == 't')); output.reset (new json::tree::boolean (*first->first == 't'));
return first + 1; return first + 1;
case T::STRING: case F::STRING:
CHECK_NEQ (first->first, first->last); CHECK_NEQ (&*first->first, &*first->last);
output.reset (new json::tree::string (first->first + 1, first->last - 1)); output.reset (new json::tree::string (first->first + 1, first->last - 1));
return first + 1; return first + 1;
case T::INTEGER: case F::INTEGER: {
if (first->first[0] == '-') { T start = first->first;
char *end; bool negative = *start == '-';
intmax_t v = strtoll (first->first, &end, 10); if (negative)
++start;
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);
if (end == first->first || end > first->last) T finish = start;
throw json::parse_error ("invalid unsigned integer"); 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)); output.reset (new json::tree::number (v));
}
return first + 1; return first + 1;
}
case T::REAL: case F::REAL: {
output.reset (new json::tree::number (std::atof (first->first))); std::string str (first->first, first->last);
output.reset (new json::tree::number (std::atof (str.c_str())));
return first + 1; return first + 1;
}
case T::ARRAY_BEGIN: { case F::ARRAY_BEGIN: {
auto value = std::make_unique<json::tree::array> (); auto value = std::make_unique<json::tree::array> ();
auto cursor = ::parse (first + 1, last, *value); auto cursor = ::parse<T> (first + 1, last, *value);
output = std::move (value); output = std::move (value);
return cursor; return cursor;
} }
case T::OBJECT_BEGIN: { case F::OBJECT_BEGIN: {
auto value = std::make_unique<json::tree::object> (); auto value = std::make_unique<json::tree::object> ();
auto cursor = ::parse (first + 1, last, *value); auto cursor = ::parse<T> (first + 1, last, *value);
output = std::move (value); output = std::move (value);
return cursor; return cursor;
} }
case T::UNKNOWN: case F::UNKNOWN:
case T::OBJECT_END: case F::OBJECT_END:
case T::ARRAY_END: case F::ARRAY_END:
unreachable (); unreachable ();
} }
@ -203,15 +216,17 @@ parse (std::vector<json::flat::item>::const_iterator first,
std::unique_ptr<json::tree::node> std::unique_ptr<json::tree::node>
json::tree::parse (const boost::filesystem::path &path) json::tree::parse (const boost::filesystem::path &path)
{ {
util::mapped_file f (path.string ().c_str ()); const util::mapped_file f (path.string ().c_str ());
return parse ((const char*)f.cbegin (), (const char*)f.cend ()); return parse<const char*restrict> (f.operator util::view<const char*restrict> ());
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
std::unique_ptr<json::tree::node> std::unique_ptr<json::tree::node>
json::tree::parse (const std::string &path) json::tree::parse (const std::string &data)
{ return parse (path.c_str (), path.c_str () + path.size ()); } {
return parse<std::string::const_iterator> (::util::make_view (data));
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -221,12 +236,13 @@ json::tree::write (const json::tree::node &node, std::ostream &os)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T>
std::unique_ptr<json::tree::node> std::unique_ptr<json::tree::node>
json::tree::parse (const char *first, const char *last) json::tree::parse (const util::view<T> src)
{ {
std::unique_ptr<json::tree::node> output; std::unique_ptr<json::tree::node> output;
auto data = json::flat::parse (first, last); auto data = json::flat::parse (src);
auto end = ::parse (data.cbegin (), data.cend (), output); auto end = ::parse<T> (data.cbegin (), data.cend (), output);
CHECK (end == data.cend ()); CHECK (end == data.cend ());
(void)end; (void)end;

View File

@ -26,6 +26,7 @@
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include "../iterator.hpp" #include "../iterator.hpp"
#include "../view.hpp"
#include "./flat.hpp" #include "./flat.hpp"
#include "./fwd.hpp" #include "./fwd.hpp"
@ -41,8 +42,11 @@ namespace json { namespace tree {
/// Parse an encoded form of JSON into a tree structure /// Parse an encoded form of JSON into a tree structure
extern std::unique_ptr<node> parse (const boost::filesystem::path &path); extern std::unique_ptr<node> parse (const boost::filesystem::path &path);
extern std::unique_ptr<node> parse (const char *start, const char *stop); extern std::unique_ptr<node> parse (const std::string &data);
extern std::unique_ptr<node> parse (const std::string&);
template <typename T>
std::unique_ptr<node>
parse (util::view<T> data);
extern std::unique_ptr<node> from_path (const char *path); extern std::unique_ptr<node> from_path (const char *path);
extern std::unique_ptr<node> from_path (const std::string&); extern std::unique_ptr<node> from_path (const std::string&);
@ -211,6 +215,9 @@ namespace json { namespace tree {
std::string m_value; std::string m_value;
public: public:
template <typename T>
string (T first, T last): m_value (first, last) { ; }
explicit string (const std::string &_value): m_value (_value) { ; } explicit string (const std::string &_value): m_value (_value) { ; }
explicit string (const char *_value): m_value (_value) { ; } explicit string (const char *_value): m_value (_value) { ; }
string (const char *_first, const char *_last): m_value (_first, _last) { ; } string (const char *_first, const char *_last): m_value (_first, _last) { ; }

View File

@ -28,7 +28,7 @@ main (void)
] ]
})_"; })_";
std::unique_ptr<json::tree::node> ptr = json::tree::parse (TEST_STRING); std::unique_ptr<json::tree::node> ptr = json::tree::parse (util::make_view (TEST_STRING));
tap.expect (ptr->is_object (), "is_object"); tap.expect (ptr->is_object (), "is_object");
CHECK (ptr->is_object ()); CHECK (ptr->is_object ());

View File

@ -12,11 +12,12 @@
* limitations under the License. * limitations under the License.
* *
* Copyright: * Copyright:
* 2014-2015, Danny Robson <danny@nerdcruft.net> * 2014-2016, Danny Robson <danny@nerdcruft.net>
*/ */
#include "json/flat.hpp" #include "json/flat.hpp"
#include "json/except.hpp" #include "json/except.hpp"
#include "io.hpp"
#include <iostream> #include <iostream>
#include <cstdlib> #include <cstdlib>
@ -41,7 +42,8 @@ main (int argc, char ** argv) {
} }
try { try {
json::flat::parse (boost::filesystem::path (argv[ARG_PATH])); util::mapped_file data (argv[ARG_PATH]);
json::flat::parse (data.operator util::view<const char*restrict> ());
} catch (const json::error &x) { } catch (const json::error &x) {
std::cerr << "error: " << x.what () << '\n'; std::cerr << "error: " << x.what () << '\n';
return EXIT_FAILURE; return EXIT_FAILURE;