mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-09-14 18:02:52 +02:00
add common/json
This commit is contained in:
+230
@@ -0,0 +1,230 @@
|
||||
#include "json.h"
|
||||
|
||||
#include "ggml.h"
|
||||
|
||||
#define JSON_ASSERT GGML_ASSERT
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
using nlohmann::ordered_json;
|
||||
|
||||
// common_json_node is never defined, it only stands for an ordered_json in this file
|
||||
static ordered_json & as_json(common_json_node * node) {
|
||||
return *reinterpret_cast<ordered_json *>(node);
|
||||
}
|
||||
|
||||
static const ordered_json & as_json(const common_json_node * node) {
|
||||
return *reinterpret_cast<const ordered_json *>(node);
|
||||
}
|
||||
|
||||
static common_json_node * as_node(ordered_json * json) {
|
||||
return reinterpret_cast<common_json_node *>(json);
|
||||
}
|
||||
|
||||
void common_json_node_deleter::operator()(common_json_node * node) const {
|
||||
delete reinterpret_cast<ordered_json *>(node);
|
||||
}
|
||||
|
||||
static common_json make_json(const ordered_json & val) {
|
||||
common_json out;
|
||||
as_json(out.get_node()) = val;
|
||||
return out;
|
||||
}
|
||||
|
||||
static ordered_json to_json(const common_json_value & val) {
|
||||
switch (val.type) {
|
||||
case common_json_value::VAL_NULL: return nullptr;
|
||||
case common_json_value::VAL_BOOL: return val.val_bool;
|
||||
case common_json_value::VAL_INT: return val.val_int;
|
||||
case common_json_value::VAL_UINT: return val.val_uint;
|
||||
case common_json_value::VAL_DOUBLE: return val.val_double;
|
||||
case common_json_value::VAL_STRING: return val.val_string;
|
||||
case common_json_value::VAL_JSON: return as_json(val.val_json->get_node());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T> T & common_json_raw(common_json_ref & json) {
|
||||
return as_json(json.get_node());
|
||||
}
|
||||
|
||||
template <typename T> const T & common_json_raw(const common_json_ref & json) {
|
||||
return as_json(json.get_node());
|
||||
}
|
||||
|
||||
template <typename T> common_json common_json_from_raw(const T & json) {
|
||||
return make_json(json);
|
||||
}
|
||||
|
||||
// the bridge is usable only for the type below
|
||||
template ordered_json & common_json_raw<ordered_json>(common_json_ref &);
|
||||
template const ordered_json & common_json_raw<ordered_json>(const common_json_ref &);
|
||||
template common_json common_json_from_raw<ordered_json>(const ordered_json &);
|
||||
|
||||
common_json_value::common_json_value(const char * val) {
|
||||
if (val) {
|
||||
type = VAL_STRING;
|
||||
val_string = val;
|
||||
} else {
|
||||
type = VAL_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
common_json_value::common_json_value(const common_json & val) :
|
||||
type(VAL_JSON), val_json(std::make_shared<common_json>(val)) {}
|
||||
|
||||
common_json_value::common_json_value(const common_json_ref & val) :
|
||||
type(VAL_JSON), val_json(std::make_shared<common_json>(make_json(as_json(val.get_node())))) {}
|
||||
|
||||
bool common_json_ref::is_null() const { return as_json(node).is_null(); }
|
||||
bool common_json_ref::is_object() const { return as_json(node).is_object(); }
|
||||
bool common_json_ref::is_array() const { return as_json(node).is_array(); }
|
||||
bool common_json_ref::is_string() const { return as_json(node).is_string(); }
|
||||
bool common_json_ref::is_boolean() const { return as_json(node).is_boolean(); }
|
||||
bool common_json_ref::is_number() const { return as_json(node).is_number(); }
|
||||
bool common_json_ref::is_number_integer() const { return as_json(node).is_number_integer(); }
|
||||
|
||||
bool common_json_ref::empty() const { return as_json(node).empty(); }
|
||||
size_t common_json_ref::size() const { return as_json(node).size(); }
|
||||
|
||||
bool common_json_ref::contains(const std::string & key) const {
|
||||
return as_json(node).contains(key);
|
||||
}
|
||||
|
||||
bool common_json_ref::operator==(const common_json_value & val) const {
|
||||
return as_json(node) == to_json(val);
|
||||
}
|
||||
|
||||
bool common_json_ref::operator!=(const common_json_value & val) const {
|
||||
return !(*this == val);
|
||||
}
|
||||
|
||||
common_json_ref common_json_ref::at(const std::string & key) const {
|
||||
return common_json_ref(as_node(&as_json(node).at(key)));
|
||||
}
|
||||
|
||||
common_json_ref common_json_ref::operator[](const std::string & key) const {
|
||||
return common_json_ref(as_node(&as_json(node)[key]));
|
||||
}
|
||||
|
||||
common_json_ref common_json_ref::operator[](size_t idx) const {
|
||||
return common_json_ref(as_node(&as_json(node)[idx]));
|
||||
}
|
||||
|
||||
void common_json_ref::assign(const common_json_value & val) {
|
||||
as_json(node) = to_json(val);
|
||||
}
|
||||
|
||||
void common_json_ref::set(const common_json_item & item) {
|
||||
as_json(node)[item.key] = to_json(item.val);
|
||||
}
|
||||
|
||||
void common_json_ref::push_back(const common_json_value & val) {
|
||||
as_json(node).push_back(to_json(val));
|
||||
}
|
||||
|
||||
std::string common_json_ref::dump(int indent) const {
|
||||
return as_json(node).dump(indent);
|
||||
}
|
||||
|
||||
// an array is indexed directly, an object needs a walk from the start
|
||||
common_json_ref common_json_ref::iterator::operator*() const {
|
||||
if (as_json(node).is_object()) {
|
||||
return common_json_ref(as_node(&std::next(as_json(node).begin(), idx).value()));
|
||||
}
|
||||
|
||||
return common_json_ref(as_node(&as_json(node)[idx]));
|
||||
}
|
||||
|
||||
std::string common_json_ref::iterator::key() const {
|
||||
return std::next(as_json(node).begin(), idx).key();
|
||||
}
|
||||
|
||||
std::pair<std::string, common_json_ref> common_json_ref::items_view::iterator::operator*() const {
|
||||
auto it = std::next(as_json(node).begin(), idx);
|
||||
|
||||
return { it.key(), common_json_ref(as_node(&it.value())) };
|
||||
}
|
||||
|
||||
common_json::common_json() :
|
||||
common_json_ref(nullptr), pimpl(as_node(new ordered_json(ordered_json::object()))) {
|
||||
node = pimpl.get();
|
||||
}
|
||||
|
||||
common_json::common_json(std::initializer_list<common_json_item> items) : common_json() {
|
||||
for (const auto & item : items) {
|
||||
set(item);
|
||||
}
|
||||
}
|
||||
|
||||
common_json::common_json(const common_json & other) :
|
||||
common_json_ref(nullptr), pimpl(as_node(new ordered_json(as_json(other.node)))) {
|
||||
node = pimpl.get();
|
||||
}
|
||||
|
||||
common_json::common_json(common_json && other) noexcept :
|
||||
common_json_ref(other.node), pimpl(std::move(other.pimpl)) {
|
||||
other.node = nullptr;
|
||||
}
|
||||
|
||||
common_json & common_json::operator=(const common_json & other) {
|
||||
as_json(node) = as_json(other.node);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
common_json & common_json::operator=(common_json && other) noexcept {
|
||||
pimpl = std::move(other.pimpl);
|
||||
node = pimpl.get();
|
||||
|
||||
other.node = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
common_json::~common_json() = default;
|
||||
|
||||
common_json common_json::parse(const std::string & text) {
|
||||
try {
|
||||
return make_json(ordered_json::parse(text));
|
||||
} catch (const std::exception & e) {
|
||||
throw common_json_error(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
common_json common_json::array() {
|
||||
return make_json(ordered_json::array());
|
||||
}
|
||||
|
||||
common_json common_json::object() {
|
||||
return common_json();
|
||||
}
|
||||
|
||||
common_json common_json::make(const common_json_value & val) {
|
||||
return make_json(to_json(val));
|
||||
}
|
||||
|
||||
template <typename T> T common_json_ref::get() const {
|
||||
return as_json(node).get<T>();
|
||||
}
|
||||
|
||||
// get<T>() is usable only for the types below
|
||||
|
||||
#define COMMON_JSON_GET(...) template __VA_ARGS__ common_json_ref::get<__VA_ARGS__>() const;
|
||||
|
||||
COMMON_JSON_GET(bool)
|
||||
COMMON_JSON_GET(int)
|
||||
COMMON_JSON_GET(unsigned int)
|
||||
COMMON_JSON_GET(long)
|
||||
COMMON_JSON_GET(unsigned long)
|
||||
COMMON_JSON_GET(long long)
|
||||
COMMON_JSON_GET(unsigned long long)
|
||||
COMMON_JSON_GET(float)
|
||||
COMMON_JSON_GET(double)
|
||||
COMMON_JSON_GET(std::string)
|
||||
COMMON_JSON_GET(std::vector<std::string>)
|
||||
|
||||
#undef COMMON_JSON_GET
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
#pragma once
|
||||
|
||||
// JSON object, it works without the need to include a JSON library header
|
||||
// note: object keys keep the order in which they are added
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
class common_json;
|
||||
class common_json_ref;
|
||||
|
||||
// one value of the backing library, only json.cpp knows what it is
|
||||
struct common_json_node;
|
||||
|
||||
struct common_json_node_deleter {
|
||||
void operator()(common_json_node * node) const;
|
||||
};
|
||||
|
||||
struct common_json_error : std::runtime_error {
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
// one value, tagged so that this header stays free of the backing library
|
||||
struct common_json_value {
|
||||
enum value_type {
|
||||
VAL_NULL,
|
||||
VAL_BOOL,
|
||||
VAL_INT,
|
||||
VAL_UINT,
|
||||
VAL_DOUBLE,
|
||||
VAL_STRING,
|
||||
VAL_JSON,
|
||||
};
|
||||
|
||||
value_type type = VAL_NULL;
|
||||
|
||||
union {
|
||||
bool val_bool;
|
||||
int64_t val_int;
|
||||
uint64_t val_uint = 0;
|
||||
double val_double;
|
||||
};
|
||||
|
||||
std::string val_string;
|
||||
std::shared_ptr<common_json> val_json;
|
||||
|
||||
common_json_value(std::nullptr_t = nullptr) : type(VAL_NULL) {}
|
||||
common_json_value(bool val) : type(VAL_BOOL), val_bool(val) {}
|
||||
common_json_value(std::string val) : type(VAL_STRING), val_string(std::move(val)) {}
|
||||
common_json_value(const char * val);
|
||||
common_json_value(const common_json & val);
|
||||
common_json_value(const common_json_ref & val);
|
||||
|
||||
template <typename T, typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value, int>::type = 0>
|
||||
common_json_value(T val) : type(std::is_signed<T>::value ? VAL_INT : VAL_UINT) {
|
||||
if (std::is_signed<T>::value) {
|
||||
val_int = (int64_t) val;
|
||||
} else {
|
||||
val_uint = (uint64_t) val;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
|
||||
common_json_value(T val) : type(VAL_DOUBLE), val_double((double) val) {}
|
||||
};
|
||||
|
||||
struct common_json_item {
|
||||
std::string key;
|
||||
common_json_value val;
|
||||
|
||||
template <typename T>
|
||||
common_json_item(std::string key, T && val) :
|
||||
key(std::move(key)), val(std::forward<T>(val)) {}
|
||||
};
|
||||
|
||||
// view to a value owned by a common_json, it goes stale if the owner gets a new key
|
||||
class common_json_ref {
|
||||
public:
|
||||
explicit common_json_ref(common_json_node * node) : node(node) {}
|
||||
|
||||
common_json_ref(const common_json_ref &) = default;
|
||||
|
||||
// rebinding a view is almost always a write-through by mistake, use assign() to write
|
||||
common_json_ref & operator=(const common_json_ref &) = delete;
|
||||
|
||||
bool is_null() const;
|
||||
bool is_object() const;
|
||||
bool is_array() const;
|
||||
bool is_string() const;
|
||||
bool is_boolean() const;
|
||||
bool is_number() const;
|
||||
bool is_number_integer() const;
|
||||
|
||||
bool empty() const;
|
||||
size_t size() const;
|
||||
|
||||
bool contains(const std::string & key) const;
|
||||
|
||||
bool operator==(const common_json_value & val) const;
|
||||
bool operator!=(const common_json_value & val) const;
|
||||
|
||||
// at() throws if the key is missing, operator[] adds a null value instead
|
||||
common_json_ref at(const std::string & key) const;
|
||||
common_json_ref operator[](const std::string & key) const;
|
||||
common_json_ref operator[](size_t idx) const;
|
||||
|
||||
// only for the types instantiated in json.cpp, the rest fails at link time
|
||||
template <typename T> T get() const;
|
||||
|
||||
template <typename T>
|
||||
T value(const std::string & key, T def) const {
|
||||
return contains(key) ? at(key).get<T>() : def;
|
||||
}
|
||||
|
||||
std::string value(const std::string & key, const char * def) const {
|
||||
return contains(key) ? at(key).get<std::string>() : std::string(def);
|
||||
}
|
||||
|
||||
void assign(const common_json_value & val);
|
||||
void set(const common_json_item & item);
|
||||
void push_back(const common_json_value & val);
|
||||
|
||||
template <typename T>
|
||||
common_json_ref & operator=(T && val) {
|
||||
assign(common_json_value(std::forward<T>(val)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string dump(int indent = -1) const;
|
||||
|
||||
// walks an array by index, or an object in insertion order
|
||||
class iterator {
|
||||
public:
|
||||
iterator(common_json_node * node, size_t idx) : node(node), idx(idx) {}
|
||||
|
||||
common_json_ref operator*() const;
|
||||
std::string key() const;
|
||||
|
||||
iterator & operator++() {
|
||||
idx++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator & other) const { return idx != other.idx; }
|
||||
bool operator==(const iterator & other) const { return idx == other.idx; }
|
||||
|
||||
private:
|
||||
common_json_node * node;
|
||||
size_t idx;
|
||||
};
|
||||
|
||||
iterator begin() const { return iterator(node, 0); }
|
||||
iterator end() const { return iterator(node, size()); }
|
||||
|
||||
// allows: for (const auto & [key, val] : obj.items())
|
||||
class items_view {
|
||||
public:
|
||||
items_view(common_json_node * node, size_t n) : node(node), n(n) {}
|
||||
|
||||
class iterator {
|
||||
public:
|
||||
iterator(common_json_node * node, size_t idx) : node(node), idx(idx) {}
|
||||
|
||||
std::pair<std::string, common_json_ref> operator*() const;
|
||||
|
||||
iterator & operator++() {
|
||||
idx++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator & other) const { return idx != other.idx; }
|
||||
|
||||
private:
|
||||
common_json_node * node;
|
||||
size_t idx;
|
||||
};
|
||||
|
||||
iterator begin() const { return iterator(node, 0); }
|
||||
iterator end() const { return iterator(node, n); }
|
||||
|
||||
private:
|
||||
common_json_node * node;
|
||||
size_t n;
|
||||
};
|
||||
|
||||
items_view items() const { return items_view(node, size()); }
|
||||
|
||||
common_json_node * get_node() const { return node; }
|
||||
|
||||
protected:
|
||||
common_json_node * node;
|
||||
};
|
||||
|
||||
// owns the value it points to
|
||||
class common_json : public common_json_ref {
|
||||
public:
|
||||
common_json();
|
||||
common_json(std::initializer_list<common_json_item> items);
|
||||
common_json(const common_json & other);
|
||||
common_json(common_json && other) noexcept;
|
||||
|
||||
common_json & operator=(const common_json & other);
|
||||
common_json & operator=(common_json && other) noexcept;
|
||||
|
||||
// out-of-line, the deleter needs to know the real type
|
||||
~common_json();
|
||||
|
||||
// throws common_json_error if the text is not valid JSON
|
||||
static common_json parse(const std::string & text);
|
||||
|
||||
static common_json array();
|
||||
static common_json object();
|
||||
|
||||
// holds a single value, e.g. make("abc").dump() gives "\"abc\""
|
||||
static common_json make(const common_json_value & val);
|
||||
|
||||
private:
|
||||
std::unique_ptr<common_json_node, common_json_node_deleter> pimpl;
|
||||
};
|
||||
|
||||
// bridge for code that still uses internal component from nlohmann::json
|
||||
// usage: common_json_raw<nlohmann::ordered_json>(j)
|
||||
// TODO: maybe completely remove this in the future
|
||||
|
||||
template <typename T> T & common_json_raw(common_json_ref & json);
|
||||
template <typename T> const T & common_json_raw(const common_json_ref & json);
|
||||
|
||||
template <typename T> common_json common_json_from_raw(const T & json);
|
||||
Reference in New Issue
Block a user