diff --git a/json11.cpp b/json11.cpp index 5f3b7ef..dbcaa83 100644 --- a/json11.cpp +++ b/json11.cpp @@ -335,7 +335,7 @@ struct JsonParser final { /* State */ - const string &str; + const string_view &str; size_t i; string &err; bool failed; @@ -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++; } @@ -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); @@ -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(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. @@ -583,7 +583,7 @@ struct JsonParser final { if (str[i] != '.' && str[i] != 'e' && str[i] != 'E' && (i - start_pos) <= static_cast(std::numeric_limits::digits10)) { - return std::atoi(str.c_str() + start_pos); + return std::atoi(static_cast(str.substr(start_pos)).c_str()); } // Decimal part @@ -610,7 +610,7 @@ struct JsonParser final { i++; } - return std::strtod(str.c_str() + start_pos, nullptr); + return std::strtod(static_cast(str.substr(start_pos)).c_str(), nullptr); } /* expect(str, res) @@ -618,14 +618,14 @@ struct JsonParser final { * 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(expected) + ", got " + static_cast(str.substr(i, expected.length()))); } } @@ -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); @@ -734,7 +734,7 @@ Json Json::parse(const string &in, string &err, JsonParse strategy) { } // Documented in json11.hpp -vector Json::parse_multi(const string &in, +vector Json::parse_multi(const string_view &in, std::string::size_type &parser_stop_pos, string &err, JsonParse strategy) { diff --git a/json11.hpp b/json11.hpp index e9fe251..f603329 100644 --- a/json11.hpp +++ b/json11.hpp @@ -50,6 +50,7 @@ #pragma once +#include #include #include #include @@ -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 +class string_view final { +public: + using size_type = size_t; + using traits_type = std::char_traits; + 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 }; @@ -149,14 +194,14 @@ 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; @@ -164,13 +209,13 @@ class Json final { } // Parse multiple objects, concatenated or separated by whitespace static std::vector 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 parse_multi( - const std::string & in, + const string_view & in, std::string & err, JsonParse strategy = JsonParse::STANDARD) { std::string::size_type parser_stop_pos;