2 Commits

Author SHA1 Message Date
2273bdd966 Mutable v4 2022-03-20 16:58:17 +03:00
52a3af664f Fix compilation under clang 2022-01-15 23:38:58 +03:00
2 changed files with 80 additions and 19 deletions

View File

@@ -41,10 +41,6 @@ using std::move;
* Serialization * Serialization
*/ */
static void dump(std::nullptr_t, string &out) {
out += "null";
}
static void dump(double value, string &out) { static void dump(double value, string &out) {
if (std::isfinite(value)) { if (std::isfinite(value)) {
char buf[32]; char buf[32];
@@ -55,10 +51,6 @@ static void dump(double value, string &out) {
} }
} }
static void dump(int value, string &out) {
out += std::to_string(value);
}
static void dump(int64_ value, string &out) { static void dump(int64_ value, string &out) {
out += std::to_string(value); out += std::to_string(value);
} }
@@ -146,6 +138,7 @@ void Json::dump(string &out) const {
template <Json::Type tag, typename T> template <Json::Type tag, typename T>
class Value : public JsonValue { class Value : public JsonValue {
protected: protected:
friend class JsonIndex;
// Constructors // Constructors
explicit Value(const T &value) : m_value(value) {} explicit Value(const T &value) : m_value(value) {}
@@ -164,12 +157,12 @@ protected:
return m_value < static_cast<const Value<tag, T> *>(other)->m_value; return m_value < static_cast<const Value<tag, T> *>(other)->m_value;
} }
const T m_value; T m_value;
void dump(string &out) const override { json11::dump(m_value, out); } void dump(string &out) const override { json11::dump(m_value, out); }
}; };
class JsonDouble final : public Value<Json::NUMBER, double> { class JsonDouble final : public Value<Json::NUMBER, double> {
string as_string() const { return std::to_string(m_value); } string as_string() const override { return std::to_string(m_value); }
bool bool_value() const override { return m_value != 0; } bool bool_value() const override { return m_value != 0; }
double number_value() const override { return static_cast<double>(m_value); } double number_value() const override { return static_cast<double>(m_value); }
int64_ int64_value() const override { return static_cast<int64_>(m_value); } int64_ int64_value() const override { return static_cast<int64_>(m_value); }
@@ -181,7 +174,7 @@ public:
}; };
class JsonInt64 final : public Value<Json::NUMBER, int64_> { class JsonInt64 final : public Value<Json::NUMBER, int64_> {
string as_string() const { return std::to_string(m_value); } string as_string() const override { return std::to_string(m_value); }
bool bool_value() const override { return m_value != 0; } bool bool_value() const override { return m_value != 0; }
double number_value() const override { return static_cast<double>(m_value); } double number_value() const override { return static_cast<double>(m_value); }
int64_ int64_value() const override { return static_cast<int64_>(m_value); } int64_ int64_value() const override { return static_cast<int64_>(m_value); }
@@ -193,7 +186,7 @@ public:
}; };
class JsonUInt64 final : public Value<Json::NUMBER, uint64_> { class JsonUInt64 final : public Value<Json::NUMBER, uint64_> {
string as_string() const { return std::to_string(m_value); } string as_string() const override { return std::to_string(m_value); }
bool bool_value() const override { return m_value != 0; } bool bool_value() const override { return m_value != 0; }
double number_value() const override { return static_cast<double>(m_value); } double number_value() const override { return static_cast<double>(m_value); }
int64_ int64_value() const override { return static_cast<int64_>(m_value); } int64_ int64_value() const override { return static_cast<int64_>(m_value); }
@@ -211,7 +204,7 @@ public:
}; };
class JsonString final : public Value<Json::STRING, string> { class JsonString final : public Value<Json::STRING, string> {
string as_string() const { return m_value; } string as_string() const override { return m_value; }
const string &string_value() const override { return m_value; } const string &string_value() const override { return m_value; }
bool bool_value() const override { return m_value != "" && m_value != "0"; } bool bool_value() const override { return m_value != "" && m_value != "0"; }
double number_value() const override double number_value() const override
@@ -259,9 +252,23 @@ public:
explicit JsonObject(Json::object &&value) : Value(move(value)) {} explicit JsonObject(Json::object &&value) : Value(move(value)) {}
}; };
class JsonNull final : public Value<Json::NUL, std::nullptr_t> { class JsonNull final : public JsonValue {
public: public:
JsonNull() : Value(nullptr) {} JsonNull() {}
// Get type tag
Json::Type type() const override {
return Json::NUL;
}
// Comparisons - only within type
bool equals(const JsonValue * other) const override {
return true;
}
bool less(const JsonValue * other) const override {
return false;
}
void dump(string &out) const override {
out += "null";
}
}; };
/* * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * *
@@ -321,7 +328,7 @@ const string & Json::string_value() const { return m_ptr->string_v
const vector<Json> & Json::array_items() const { return m_ptr->array_items(); } const vector<Json> & Json::array_items() const { return m_ptr->array_items(); }
const map<string, Json> & Json::object_items() const { return m_ptr->object_items(); } const map<string, Json> & Json::object_items() const { return m_ptr->object_items(); }
const Json & Json::operator[] (size_t i) const { return (*m_ptr)[i]; } const Json & Json::operator[] (size_t i) const { return (*m_ptr)[i]; }
const Json & Json::operator[] (const string &key) const { return (*m_ptr)[key]; } JsonIndex Json::operator[] (const string &key) { return (JsonIndex){ .m_object = *this, .m_key = key }; }
double JsonValue::number_value() const { return 0; } double JsonValue::number_value() const { return 0; }
int64_ JsonValue::int64_value() const { return 0; } int64_ JsonValue::int64_value() const { return 0; }
@@ -836,8 +843,13 @@ bool Json::has_shape(const shape & types, string & err) const {
return false; return false;
} }
const auto & obj = object_items();
for (auto & item : types) { for (auto & item : types) {
if ((*this)[item.first].type() != item.second) { auto it = obj.find(item.first);
if (it == obj.end()) {
return false;
}
if (it->second.type() != item.second) {
err = "bad type for " + item.first + " in " + dump(); err = "bad type for " + item.first + " in " + dump();
return false; return false;
} }
@@ -846,4 +858,22 @@ bool Json::has_shape(const shape & types, string & err) const {
return true; return true;
} }
/* * * * * * * * * * * * * * * * * * * *
* Indexed wrapper to prevent autovivification
*/
const Json & JsonIndex::self() const {
if (m_object.is_object()) {
return ((JsonObject*)m_object.m_ptr.get())->m_value[m_key];
}
return static_null();
}
Json JsonIndex::operator =(Json value) {
if (m_object.is_object()) {
return ((JsonObject*)m_object.m_ptr.get())->m_value[m_key] = value;
}
return value;
}
} // namespace json11 } // namespace json11

View File

@@ -77,6 +77,8 @@ enum JsonParse {
class JsonValue; class JsonValue;
class JsonIndex;
#if __cplusplus < 201103L #if __cplusplus < 201103L
#error This project can only be compiled with a compiler that supports C++11 #error This project can only be compiled with a compiler that supports C++11
#else #else
@@ -165,7 +167,7 @@ public:
// Return a reference to arr[i] if this is an array, Json() otherwise. // Return a reference to arr[i] if this is an array, Json() otherwise.
const Json & operator[](size_t i) const; const Json & operator[](size_t i) const;
// Return a reference to obj[key] if this is an object, Json() otherwise. // Return a reference to obj[key] if this is an object, Json() otherwise.
const Json & operator[](const std::string &key) const; JsonIndex operator[](const std::string &key);
// Serialize. // Serialize.
void dump(std::string &out) const; void dump(std::string &out) const;
@@ -220,9 +222,38 @@ public:
bool has_shape(const shape & types, std::string & err) const; bool has_shape(const shape & types, std::string & err) const;
private: private:
friend class JsonIndex;
std::shared_ptr<JsonValue> m_ptr; std::shared_ptr<JsonValue> m_ptr;
}; };
class JsonIndex {
public:
Json m_object;
const std::string & m_key;
Json operator =(Json value);
operator const Json &() { return m_object[m_key]; }
const Json & self() const;
bool is_null() const { return self().is_null(); }
bool is_number() const { return self().is_number(); }
bool is_bool() const { return self().is_bool(); }
bool is_string() const { return self().is_string(); }
bool is_array() const { return self().is_array(); }
bool is_object() const { return self().is_object(); }
double number_value() const { return self().number_value(); }
int64_ int64_value() const { return self().int64_value(); }
uint64_ uint64_value() const { return self().uint64_value(); }
std::string as_string() const { return self().as_string(); }
bool bool_value() const { return self().bool_value(); }
const std::string &string_value() const { return self().string_value(); }
const Json::array &array_items() const { return self().array_items(); }
const Json::object &object_items() const { return self().object_items(); }
std::string dump() const { return self().dump(); }
};
// Internal class hierarchy - JsonValue objects are not exposed to users of this API. // Internal class hierarchy - JsonValue objects are not exposed to users of this API.
class JsonValue { class JsonValue {
protected: protected: