Felipe97/llama-cpp-compiled
01.1k
1#pragma once2 3#include <cstddef>4#include <cstdint>5#include <initializer_list>6#include <iterator>7#include <map>8#include <memory>9#include <set>10#include <stdexcept>11#include <string>12#include <string_view>13#include <type_traits>14#include <unordered_map>15#include <utility>16#include <vector>17 18// common_json, a thin wrapper around vendor json library19// the underlay library is pimpl, we are using nlohmann::json for now20//21// many features of the library are deliberately left out, to keep this interface small and generic and to keep compile time down22//23// some main differences compared to nlohmann::json :24// - object keys keep the order in which they are added25// - errors are always throw as common_json_error26// - obj.push_back({key, val}) is intentionally unsupported to avoid confusion with push_back on a vector; write it as obj[key] = val for clarity27// - a braced pair in value position does not build, e.g. {"key", {"a", "b"}}; write array({"a", "b"}) where nlohmann made an array28//29// in doubt, search the code base for an existing usage example; do not add anything to this header unless absolutely necessary30 31class common_json;32 33// common_json_value holds a list of these, and each of them holds a value, so one must come first34struct common_json_item;35 36struct common_json_error : std::runtime_error {37 using std::runtime_error::runtime_error;38};39 40// one value, tagged so that this header stays free of the backing library41// note: a value that holds a tree is single use, the second use gives null42struct common_json_value {43 enum value_type {44 VAL_NULL,45 VAL_BOOL,46 VAL_INT,47 VAL_UINT,48 VAL_DOUBLE,49 VAL_STRING,50 VAL_JSON,51 };52 53 value_type type = VAL_NULL;54 55 union {56 bool val_bool;57 int64_t val_int;58 uint64_t val_uint = 0;59 double val_double;60 };61 62 std::string val_string;63 std::shared_ptr<common_json> val_json;64 65 common_json_value(std::nullptr_t = nullptr) : type(VAL_NULL) {}66 common_json_value(bool val) : type(VAL_BOOL), val_bool(val) {}67 common_json_value(std::string val) : type(VAL_STRING), val_string(std::move(val)) {}68 // without this a string_view lands on the common_json ctor below and recurses69 common_json_value(std::string_view val) : type(VAL_STRING), val_string(val) {}70 common_json_value(const char * val);71 common_json_value(const common_json & val);72 common_json_value(common_json && val);73 // only for the types instantiated in json.cpp, the rest fails at link time74 template <typename T> common_json_value(const std::vector<T> & vals);75 // a set becomes an array, in the set's own order76 template <typename T> common_json_value(const std::set<T> & vals);77 // a map becomes an object, keyed in the map's own order78 template <typename T> common_json_value(const std::map<std::string, T> & vals);79 template <typename T> common_json_value(const std::unordered_map<std::string, T> & vals);80 81 // nested object, e.g. {"fn", {{"name", "x"}}}82 // note: a nested pair {"a", "b"} does not build, use common_json::array({"a", "b"}) for an array83 common_json_value(std::initializer_list<common_json_item> items);84 85 template <typename T, typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value, int>::type = 0>86 common_json_value(T val) : type(std::is_signed<T>::value ? VAL_INT : VAL_UINT) {87 if (std::is_signed<T>::value) {88 val_int = (int64_t) val;89 } else {90 val_uint = (uint64_t) val;91 }92 }93 94 template <typename T, typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>95 common_json_value(T val) : type(VAL_DOUBLE), val_double((double) val) {}96};97 98struct common_json_item {99 std::string key;100 common_json_value val;101 102 template <typename T>103 common_json_item(std::string key, T && val) :104 key(std::move(key)), val(std::forward<T>(val)) {}105 106 // a braced list cannot deduce T, so it needs its own overload107 common_json_item(std::string key, std::initializer_list<common_json_item> items) :108 key(std::move(key)), val(items) {}109};110 111// the types common_json_value holds on its own112// anything else reaches its common_json ctor and recurses forever113template <typename T> struct common_json_is_value : std::integral_constant<bool,114 std::is_arithmetic<T>::value ||115 std::is_same<T, std::nullptr_t>::value ||116 std::is_same<T, std::string>::value ||117 std::is_same<T, std::string_view>::value ||118 std::is_same<T, char *>::value ||119 std::is_same<T, const char *>::value ||120 std::is_same<T, common_json>::value> {};121 122template <typename T, typename A>123struct common_json_is_value<std::vector<T, A>> : std::true_type {};124 125template <typename T, typename C, typename A>126struct common_json_is_value<std::set<T, C, A>> : std::true_type {};127 128template <typename V, typename C, typename A>129struct common_json_is_value<std::map<std::string, V, C, A>> : std::true_type {};130 131template <typename V, typename H, typename E, typename A>132struct common_json_is_value<std::unordered_map<std::string, V, H, E, A>> : std::true_type {};133 134class common_json {135 public:136 common_json();137 common_json(const common_json & other);138 common_json(common_json && other) noexcept;139 common_json(std::initializer_list<common_json_item> items);140 common_json(const common_json_value & val);141 142 // direct, a value would need two conversions in a row143 common_json(std::nullptr_t);144 145 // one step, so that "abc" or a vector can go straight into a common_json146 template <typename T, typename std::enable_if<!std::is_same<typename std::decay<T>::type, common_json>::value &&147 !std::is_same<typename std::decay<T>::type, common_json_value>::value, int>::type = 0>148 common_json(T && val) : common_json(common_json_value(std::forward<T>(val))) {149 static_assert(common_json_is_value<typename std::decay<T>::type>::value,150 "no common_json_value ctor holds this type, add one instead of letting it recurse");151 }152 153 // by value, same as the backing library154 // the right side is copied before the left side can invalidate it, e.g. msg["a"] = msg.at("b")155 common_json & operator=(common_json other) noexcept;156 157 ~common_json();158 159 // throws common_json_error if the text is not valid JSON160 static common_json parse(const std::string & text);161 162 // gives a discarded value instead of throwing, check it with is_discarded()163 static common_json parse_no_throw(const std::string & text);164 165 bool is_discarded() const;166 167 static common_json array();168 static common_json array(std::initializer_list<common_json_value> vals);169 static common_json object();170 static common_json object(std::initializer_list<common_json_item> items);171 172 // holds a single value, e.g. make("abc").dump() gives "\"abc\""173 static common_json make(const common_json_value & val);174 175 bool is_null() const;176 bool is_object() const;177 bool is_array() const;178 bool is_string() const;179 bool is_boolean() const;180 bool is_number() const;181 bool is_number_integer() const;182 bool is_number_float() const;183 184 bool empty() const;185 size_t size() const;186 187 bool contains(const std::string & key) const;188 189 bool operator==(const common_json_value & val) const;190 bool operator!=(const common_json_value & val) const;191 192 // at() throws common_json_error if the key is missing, operator[] adds a null value instead193 // note: a const operator[] cannot add, it throws like at()194 common_json & at(const std::string & key);195 const common_json & at(const std::string & key) const;196 common_json & at(size_t idx);197 const common_json & at(size_t idx) const;198 199 common_json & operator[](const std::string & key);200 const common_json & operator[](const std::string & key) const;201 common_json & operator[](const char * key) { return (*this)[std::string(key)]; }202 const common_json & operator[](const char * key) const { return (*this)[std::string(key)]; }203 common_json & operator[](int idx) { return (*this)[to_idx(idx)]; }204 const common_json & operator[](int idx) const { return (*this)[to_idx(idx)]; }205 common_json & operator[](size_t idx);206 const common_json & operator[](size_t idx) const;207 208 common_json & front();209 const common_json & front() const;210 common_json & back();211 const common_json & back() const;212 213 void clear();214 215 void erase(const std::string & key);216 void erase(size_t idx);217 218 // only for the types instantiated in json.cpp, the rest fails at link time219 template <typename T> T get() const;220 221 // implicit get<T>() for plain values, so they can be assigned to their C++ type directly222 // note: kept to this short list on purpose, a wider one makes j["key"] ambiguous223 // note: a numeric one would make "str = json;" ambiguous, a number converts to char too224 operator std::string() const;225 226 template <typename T>227 T value(const std::string & key, T def) const {228 return contains(key) ? at(key).get<T>() : def;229 }230 231 std::string value(const std::string & key, const char * def) const;232 233 // a JSON default needs no get<T>(), it is already the right type234 common_json value(const std::string & key, const common_json & def) const {235 return contains(key) ? at(key) : def;236 }237 238 void assign(const common_json_value & val);239 void set(const common_json_item & item);240 void push_back(const common_json_value & val);241 242 // appends one object, e.g. push_back({{"a", 1}})243 void push_back(std::initializer_list<common_json_item> items);244 245 // 1 if the key is there, 0 if not246 size_t count(const std::string & key) const;247 248 // appends every value of another array; inserting an array into itself throws249 void insert(const common_json & vals);250 251 // a common_json goes through the copy assignment above, everything else becomes a value252 template <typename T, typename std::enable_if<!std::is_same<typename std::decay<T>::type, common_json>::value, int>::type = 0>253 common_json & operator=(T && val) {254 assign(common_json_value(std::forward<T>(val)));255 return *this;256 }257 258 std::string dump(int indent = -1) const;259 260 // same as dump(), but bad UTF-8 gets replaced instead of throwing261 std::string dump_safe(int indent = -1) const;262 263 // walks an array by index, or an object in insertion order264 // a plain value gives itself once, same as the backing library265 class iterator {266 public:267 using iterator_category = std::forward_iterator_tag;268 using value_type = common_json;269 using difference_type = std::ptrdiff_t;270 using pointer = common_json *;271 using reference = common_json &;272 273 iterator(common_json * node, size_t idx) : node(node), idx(idx) {}274 275 common_json & operator*() const;276 common_json & value() const { return **this; }277 std::string key() const;278 279 iterator & operator++() {280 idx++;281 return *this;282 }283 284 bool operator!=(const iterator & other) const { return idx != other.idx; }285 bool operator==(const iterator & other) const { return idx == other.idx; }286 287 private:288 common_json * node;289 size_t idx;290 };291 292 iterator begin() const;293 iterator end() const;294 295 // allows: for (const auto & [key, val] : obj.items())296 class items_view {297 public:298 // the members are public, so an entry also works with structured bindings299 struct entry {300 std::string k;301 common_json & v;302 303 const std::string & key() const { return k; }304 common_json & value() const { return v; }305 };306 307 items_view(common_json * node, size_t n) : node(node), n(n) {}308 309 class iterator {310 public:311 iterator(common_json * node, size_t idx) : node(node), idx(idx) {}312 313 entry operator*() const;314 315 iterator & operator++() {316 idx++;317 return *this;318 }319 320 bool operator!=(const iterator & other) const { return idx != other.idx; }321 322 private:323 common_json * node;324 size_t idx;325 };326 327 iterator begin() const { return iterator(node, 0); }328 iterator end() const { return iterator(node, n); }329 330 private:331 common_json * node;332 size_t n;333 };334 335 items_view items() const;336 337 private:338 // a negative index must not turn into a huge size_t339 static size_t to_idx(int idx) {340 if (idx < 0) {341 throw common_json_error("negative array index");342 }343 return (size_t) idx;344 }345 346 // the backing value is built here, json.cpp checks that it fits347 // it cannot be a pointer: a value inside a tree would then not be a common_json348 // at() could then only give back a copy instead of a real reference349 alignas(8) unsigned char storage[32];350};351 352using common_json_entry = common_json::items_view::entry;353 