Skip to content
This repository has been archived by the owner on Mar 26, 2020. It is now read-only.

allow to parse const char * without mem allocation #60

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions json11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ struct JsonParser final {

/* State
*/
const string &str;
const string_view &str;
size_t i;
string &err;
bool failed;
Expand All @@ -362,7 +362,7 @@ struct JsonParser final {
* Advance until the current character is non-whitespace.
*/
void consume_whitespace() {
while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t')
while (i < str.length() && (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t'))
i++;
}

Expand All @@ -372,7 +372,7 @@ struct JsonParser final {
*/
bool consume_comment() {
bool comment_found = false;
if (str[i] == '/') {
if (i < str.size() && str[i] == '/') {
i++;
if (i == str.size())
return fail("unexpected end of input inside comment", 0);
Expand Down Expand Up @@ -502,7 +502,7 @@ struct JsonParser final {

if (ch == 'u') {
// Extract 4-byte escape sequence
string esc = str.substr(i, 4);
string esc = static_cast<std::string>(str.substr(i, 4));
// Explicitly check length of the substring. The following loop
// relies on std::string returning the terminating NUL when
// accessing str[length]. Checking here reduces brittleness.
Expand Down Expand Up @@ -583,7 +583,7 @@ struct JsonParser final {

if (str[i] != '.' && str[i] != 'e' && str[i] != 'E'
&& (i - start_pos) <= static_cast<size_t>(std::numeric_limits<int>::digits10)) {
return std::atoi(str.c_str() + start_pos);
return std::atoi(static_cast<std::string>(str.substr(start_pos)).c_str());
}

// Decimal part
Expand All @@ -610,22 +610,22 @@ struct JsonParser final {
i++;
}

return std::strtod(str.c_str() + start_pos, nullptr);
return std::strtod(static_cast<std::string>(str.substr(start_pos)).c_str(), nullptr);
}

/* expect(str, res)
*
* Expect that 'str' starts at the character that was just read. If it does, advance
* the input and return res. If not, flag an error.
*/
Json expect(const string &expected, Json res) {
Json expect(const string_view &expected, Json res) {
assert(i != 0);
i--;
if (str.compare(i, expected.length(), expected) == 0) {
i += expected.length();
return res;
} else {
return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length()));
return fail("parse error: expected " + static_cast<std::string>(expected) + ", got " + static_cast<std::string>(str.substr(i, expected.length())));
}
}

Expand Down Expand Up @@ -721,7 +721,7 @@ struct JsonParser final {
};
}//namespace {

Json Json::parse(const string &in, string &err, JsonParse strategy) {
Json Json::parse(const string_view &in, string &err, JsonParse strategy) {
JsonParser parser { in, 0, err, false, strategy };
Json result = parser.parse_json(0);

Expand All @@ -734,7 +734,7 @@ Json Json::parse(const string &in, string &err, JsonParse strategy) {
}

// Documented in json11.hpp
vector<Json> Json::parse_multi(const string &in,
vector<Json> Json::parse_multi(const string_view &in,
std::string::size_type &parser_stop_pos,
string &err,
JsonParse strategy) {
Expand Down
53 changes: 49 additions & 4 deletions json11.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@

#pragma once

#include <cassert>
#include <string>
#include <vector>
#include <map>
Expand All @@ -58,6 +59,50 @@

namespace json11 {

//the interface similar to std::basic_string_view from c++17
//when c++17 become common feature for gcc/clang/icc/msvc
//code below can be replace with include <string_view>
class string_view final {
public:
using size_type = size_t;
using traits_type = std::char_traits<char>;
using const_reference = const char &;

constexpr string_view() noexcept: m_len{0}, m_data{nullptr} {}
constexpr string_view(const string_view &other) = default;
string_view(const std::string &str): m_len{str.length()}, m_data{str.data()} {}
constexpr string_view(const char *str, size_type n): m_len{n}, m_data{str} {}
constexpr string_view(const char *str): m_len{str == nullptr ? 0 : traits_type::length(str)}, m_data{str} {}
string_view &operator=(const string_view &) noexcept = default;
/*constexpr*/ const_reference operator[](size_type pos) const {
assert(pos < m_len);
return *(m_data + pos);
}
constexpr const char *data() const noexcept { return m_data; }
constexpr size_type size() const noexcept { return m_len; }
constexpr size_type length() const noexcept { return m_len; }
//should throw, but because of -fno-exception just assert
string_view substr(size_type pos, size_type n = std::string::npos) const {
assert(pos <= m_len);
return string_view{m_data + pos, std::min(n, size_type{m_len - pos})};
}

int compare(string_view str) const noexcept {
int ret = traits_type::compare(m_data, str.m_data, std::min(m_len, str.m_len));
if (ret == 0)
ret = (m_len == str.m_len) ? 0 : m_len < str.m_len ? -1 : 1;
return ret;
}
int compare(size_type pos1, size_type count1, string_view str) const {
return substr(pos1, count1).compare(str);
}

explicit operator std::string() const { return {m_data, m_len}; }
private:
size_type m_len;
const char *m_data;

};
enum JsonParse {
STANDARD, COMMENTS
};
Expand Down Expand Up @@ -149,28 +194,28 @@ class Json final {
}

// Parse. If parse fails, return Json() and assign an error message to err.
static Json parse(const std::string & in,
static Json parse(const string_view & in,
std::string & err,
JsonParse strategy = JsonParse::STANDARD);
static Json parse(const char * in,
std::string & err,
JsonParse strategy = JsonParse::STANDARD) {
if (in) {
return parse(std::string(in), err, strategy);
return parse(string_view(in), err, strategy);
} else {
err = "null input";
return nullptr;
}
}
// Parse multiple objects, concatenated or separated by whitespace
static std::vector<Json> parse_multi(
const std::string & in,
const string_view & in,
std::string::size_type & parser_stop_pos,
std::string & err,
JsonParse strategy = JsonParse::STANDARD);

static inline std::vector<Json> parse_multi(
const std::string & in,
const string_view & in,
std::string & err,
JsonParse strategy = JsonParse::STANDARD) {
std::string::size_type parser_stop_pos;
Expand Down