json: use templated iterator for parsing from views
This commit is contained in:
parent
194cd6c574
commit
642317f6a4
@ -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
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -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);
|
||||||
} }
|
} }
|
||||||
|
114
json/tree.cpp
114
json/tree.cpp
@ -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;
|
||||||
|
@ -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) { ; }
|
||||||
|
@ -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 ());
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user