mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-09-29 09:27:33 -05:00
harden a bit
This commit is contained in:
+44
-12
@@ -54,6 +54,7 @@ static ordered_json to_json(const common_json_value & val) {
|
||||
case common_json_value::VAL_STRING: return val.val_string;
|
||||
case common_json_value::VAL_JSON:
|
||||
// one owner means no one else can see this tree, so it is safe to move it out
|
||||
// note: this makes a value single use, same as the json_ref of the backing library
|
||||
if (val.val_json.use_count() == 1) {
|
||||
return std::move(as_json(val.val_json.get()));
|
||||
}
|
||||
@@ -213,14 +214,19 @@ common_json::~common_json() {
|
||||
|
||||
common_json common_json::parse(const std::string & text) {
|
||||
try {
|
||||
return common_json_from_raw(ordered_json::parse(text));
|
||||
// the assignment moves the parsed tree in, it does not copy
|
||||
common_json out;
|
||||
as_json(&out) = ordered_json::parse(text);
|
||||
return out;
|
||||
} catch (const std::exception & e) {
|
||||
throw common_json_error(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
common_json common_json::parse_no_throw(const std::string & text) {
|
||||
return common_json_from_raw(ordered_json::parse(text, nullptr, false));
|
||||
common_json out;
|
||||
as_json(&out) = ordered_json::parse(text, nullptr, false);
|
||||
return out;
|
||||
}
|
||||
|
||||
bool common_json::is_discarded() const {
|
||||
@@ -228,21 +234,27 @@ bool common_json::is_discarded() const {
|
||||
}
|
||||
|
||||
common_json common_json::array() {
|
||||
return common_json_from_raw(ordered_json::array());
|
||||
common_json out;
|
||||
as_json(&out) = ordered_json::array();
|
||||
return out;
|
||||
}
|
||||
|
||||
common_json common_json::array(std::initializer_list<common_json_value> vals) {
|
||||
ordered_json out = ordered_json::array();
|
||||
common_json out;
|
||||
ordered_json & arr = as_json(&out);
|
||||
arr = ordered_json::array();
|
||||
|
||||
for (const auto & val : vals) {
|
||||
out.push_back(to_json(val));
|
||||
arr.push_back(to_json(val));
|
||||
}
|
||||
|
||||
return common_json_from_raw(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
common_json common_json::object() {
|
||||
return common_json_from_raw(ordered_json::object());
|
||||
common_json out;
|
||||
as_json(&out) = ordered_json::object();
|
||||
return out;
|
||||
}
|
||||
|
||||
common_json common_json::object(std::initializer_list<common_json_item> items) {
|
||||
@@ -270,6 +282,10 @@ bool common_json::contains(const std::string & key) const {
|
||||
}
|
||||
|
||||
bool common_json::operator==(const common_json_value & val) const {
|
||||
// compare a tree in place, to_json() would copy it
|
||||
if (val.type == common_json_value::VAL_JSON) {
|
||||
return as_json(this) == as_json(val.val_json.get());
|
||||
}
|
||||
return as_json(this) == to_json(val);
|
||||
}
|
||||
|
||||
@@ -345,11 +361,17 @@ std::string common_json::dump_safe(int indent) const {
|
||||
// an array is indexed directly, an object needs a walk from the start
|
||||
common_json & common_json::iterator::operator*() const {
|
||||
return guard([&]() -> common_json & {
|
||||
if (as_json(node).is_object()) {
|
||||
return as_common(std::next(as_json(node).begin(), idx).value());
|
||||
ordered_json & j = as_json(node);
|
||||
|
||||
if (j.is_object()) {
|
||||
return as_common(std::next(j.begin(), idx).value());
|
||||
}
|
||||
if (j.is_array()) {
|
||||
return as_common(j[idx]);
|
||||
}
|
||||
|
||||
return as_common(as_json(node)[idx]);
|
||||
// a plain value gives itself once, same as the backing library
|
||||
return *node;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -365,11 +387,21 @@ common_json::iterator common_json::end() const {
|
||||
return iterator(const_cast<common_json *>(this), size());
|
||||
}
|
||||
|
||||
// the keys follow the backing library: the index for an array, "" for a plain value
|
||||
common_json::items_view::entry common_json::items_view::iterator::operator*() const {
|
||||
return guard([&]() -> entry {
|
||||
auto it = std::next(as_json(node).begin(), idx);
|
||||
ordered_json & j = as_json(node);
|
||||
|
||||
return { it.key(), as_common(it.value()) };
|
||||
if (j.is_object()) {
|
||||
auto it = std::next(j.begin(), idx);
|
||||
|
||||
return { it.key(), as_common(it.value()) };
|
||||
}
|
||||
if (j.is_array()) {
|
||||
return { std::to_string(idx), as_common(j[idx]) };
|
||||
}
|
||||
|
||||
return { std::string(), *node };
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+14
-3
@@ -30,6 +30,8 @@ struct common_json_error : std::runtime_error {
|
||||
};
|
||||
|
||||
// one value, tagged so that this header stays free of the backing library
|
||||
// note: a value that holds a tree is single use, consuming the same value twice
|
||||
// (e.g. through a named initializer list) gives null on the second use
|
||||
struct common_json_value {
|
||||
enum value_type {
|
||||
VAL_NULL,
|
||||
@@ -188,8 +190,8 @@ class common_json {
|
||||
const common_json & operator[](const std::string & key) const;
|
||||
common_json & operator[](const char * key) { return (*this)[std::string(key)]; }
|
||||
const common_json & operator[](const char * key) const { return (*this)[std::string(key)]; }
|
||||
common_json & operator[](int idx) { return (*this)[(size_t) idx]; }
|
||||
const common_json & operator[](int idx) const { return (*this)[(size_t) idx]; }
|
||||
common_json & operator[](int idx) { return (*this)[to_idx(idx)]; }
|
||||
const common_json & operator[](int idx) const { return (*this)[to_idx(idx)]; }
|
||||
common_json & operator[](size_t idx);
|
||||
const common_json & operator[](size_t idx) const;
|
||||
|
||||
@@ -236,7 +238,7 @@ class common_json {
|
||||
// 1 if the key is there, 0 if not
|
||||
size_t count(const std::string & key) const;
|
||||
|
||||
// appends every value of another array
|
||||
// appends every value of another array; inserting an array into itself throws
|
||||
void insert(const common_json & vals);
|
||||
|
||||
// a common_json goes through the copy assignment above, everything else becomes a value
|
||||
@@ -252,6 +254,7 @@ class common_json {
|
||||
std::string dump_safe(int indent = -1) const;
|
||||
|
||||
// walks an array by index, or an object in insertion order
|
||||
// a plain value gives itself once, same as the backing library
|
||||
class iterator {
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
@@ -325,6 +328,14 @@ class common_json {
|
||||
items_view items() const;
|
||||
|
||||
private:
|
||||
// a negative index must not turn into a huge size_t
|
||||
static size_t to_idx(int idx) {
|
||||
if (idx < 0) {
|
||||
throw common_json_error("negative array index");
|
||||
}
|
||||
return (size_t) idx;
|
||||
}
|
||||
|
||||
// the backing value is built here, json.cpp checks that it fits
|
||||
// it cannot be a pointer: a value inside a tree would then not be a common_json,
|
||||
// so at() could only give back a copy instead of a real reference
|
||||
|
||||
@@ -1895,11 +1895,14 @@ common_json common_peg_arena::to_json() const {
|
||||
for (const auto & parser : parsers_) {
|
||||
parsers.push_back(serialize_parser_variant(parser));
|
||||
}
|
||||
return common_json_from_raw(nlohmann::ordered_json{
|
||||
// the assignment moves the tree in, it does not copy
|
||||
common_json out;
|
||||
common_json_raw<nlohmann::ordered_json>(out) = nlohmann::ordered_json{
|
||||
{"parsers", parsers},
|
||||
{"rules", rules_},
|
||||
{"root", root_}
|
||||
});
|
||||
};
|
||||
return out;
|
||||
}
|
||||
|
||||
static common_peg_parser_variant deserialize_parser_variant(const nlohmann::ordered_json & j) {
|
||||
|
||||
@@ -42,7 +42,7 @@ static T json_value(const json & body, const std::string & key, const T & defaul
|
||||
if (body.contains(key) && !body.at(key).is_null()) {
|
||||
try {
|
||||
return body.at(key).get<T>();
|
||||
} catch (const std::exception & err) {
|
||||
} catch (const common_json_error & err) {
|
||||
LOG_WRN("Wrong type supplied for parameter '%s', using default value: %s\n", key.c_str(), err.what());
|
||||
return default_value;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user