univalue.h
1 // Copyright 2014 BitPay Inc. 2 // Copyright 2015 Bitcoin Core Developers 3 // Distributed under the MIT software license, see the accompanying 4 // file COPYING or https://opensource.org/licenses/mit-license.php. 5 6 #ifndef BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H 7 #define BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H 8 9 #include <charconv> 10 #include <cstddef> 11 #include <cstdint> 12 #include <map> 13 #include <stdexcept> 14 #include <string> 15 #include <string_view> 16 #include <system_error> 17 #include <type_traits> 18 #include <utility> 19 #include <vector> 20 21 // NOLINTNEXTLINE(misc-no-recursion) 22 class UniValue { 23 public: 24 enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, }; 25 26 class type_error : public std::runtime_error 27 { 28 using std::runtime_error::runtime_error; 29 }; 30 31 UniValue() { typ = VNULL; } 32 UniValue(UniValue::VType type, std::string str = {}) : typ{type}, val{std::move(str)} {} 33 template <typename Ref, typename T = std::remove_cv_t<std::remove_reference_t<Ref>>, 34 std::enable_if_t<std::is_floating_point_v<T> || // setFloat 35 std::is_same_v<bool, T> || // setBool 36 std::is_signed_v<T> || std::is_unsigned_v<T> || // setInt 37 std::is_constructible_v<std::string, T>, // setStr 38 bool> = true> 39 UniValue(Ref&& val) 40 { 41 if constexpr (std::is_floating_point_v<T>) { 42 setFloat(val); 43 } else if constexpr (std::is_same_v<bool, T>) { 44 setBool(val); 45 } else if constexpr (std::is_signed_v<T>) { 46 setInt(int64_t{val}); 47 } else if constexpr (std::is_unsigned_v<T>) { 48 setInt(uint64_t{val}); 49 } else { 50 setStr(std::string{std::forward<Ref>(val)}); 51 } 52 } 53 54 void clear(); 55 56 void setNull(); 57 void setBool(bool val); 58 void setNumStr(std::string str); 59 void setInt(uint64_t val); 60 void setInt(int64_t val); 61 void setInt(int val_) { return setInt(int64_t{val_}); } 62 void setFloat(double val); 63 void setStr(std::string str); 64 void setArray(); 65 void setObject(); 66 67 enum VType getType() const { return typ; } 68 const std::string& getValStr() const { return val; } 69 bool empty() const { return (values.size() == 0); } 70 71 size_t size() const { return values.size(); } 72 73 void reserve(size_t new_cap); 74 75 void getObjMap(std::map<std::string,UniValue>& kv) const; 76 bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes) const; 77 const UniValue& operator[](const std::string& key) const; 78 const UniValue& operator[](size_t index) const; 79 bool exists(const std::string& key) const { size_t i; return findKey(key, i); } 80 81 bool isNull() const { return (typ == VNULL); } 82 bool isTrue() const { return (typ == VBOOL) && (val == "1"); } 83 bool isFalse() const { return (typ == VBOOL) && (val != "1"); } 84 bool isBool() const { return (typ == VBOOL); } 85 bool isStr() const { return (typ == VSTR); } 86 bool isNum() const { return (typ == VNUM); } 87 bool isArray() const { return (typ == VARR); } 88 bool isObject() const { return (typ == VOBJ); } 89 90 void push_back(UniValue val); 91 void push_backV(const std::vector<UniValue>& vec); 92 template <class It> 93 void push_backV(It first, It last); 94 95 void pushKVEnd(std::string key, UniValue val); 96 void pushKV(std::string key, UniValue val); 97 void pushKVs(UniValue obj); 98 99 std::string write(unsigned int prettyIndent = 0, 100 unsigned int indentLevel = 0) const; 101 102 bool read(std::string_view raw); 103 104 private: 105 UniValue::VType typ; 106 std::string val; // numbers are stored as C++ strings 107 std::vector<std::string> keys; 108 std::vector<UniValue> values; 109 110 void checkType(const VType& expected) const; 111 bool findKey(const std::string& key, size_t& retIdx) const; 112 void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; 113 void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; 114 115 public: 116 // Strict type-specific getters, these throw std::runtime_error if the 117 // value is of unexpected type 118 const std::vector<std::string>& getKeys() const; 119 const std::vector<UniValue>& getValues() const; 120 template <typename Int> 121 Int getInt() const; 122 bool get_bool() const; 123 const std::string& get_str() const; 124 double get_real() const; 125 const UniValue& get_obj() const; 126 const UniValue& get_array() const; 127 128 enum VType type() const { return getType(); } 129 const UniValue& find_value(std::string_view key) const; 130 }; 131 132 template <class It> 133 void UniValue::push_backV(It first, It last) 134 { 135 checkType(VARR); 136 values.insert(values.end(), first, last); 137 } 138 139 template <typename Int> 140 Int UniValue::getInt() const 141 { 142 static_assert(std::is_integral_v<Int>); 143 checkType(VNUM); 144 Int result; 145 const auto [first_nonmatching, error_condition] = std::from_chars(val.data(), val.data() + val.size(), result); 146 if (first_nonmatching != val.data() + val.size() || error_condition != std::errc{}) { 147 throw std::runtime_error("JSON integer out of range"); 148 } 149 return result; 150 } 151 152 enum jtokentype { 153 JTOK_ERR = -1, 154 JTOK_NONE = 0, // eof 155 JTOK_OBJ_OPEN, 156 JTOK_OBJ_CLOSE, 157 JTOK_ARR_OPEN, 158 JTOK_ARR_CLOSE, 159 JTOK_COLON, 160 JTOK_COMMA, 161 JTOK_KW_NULL, 162 JTOK_KW_TRUE, 163 JTOK_KW_FALSE, 164 JTOK_NUMBER, 165 JTOK_STRING, 166 }; 167 168 extern enum jtokentype getJsonToken(std::string& tokenVal, 169 unsigned int& consumed, const char *raw, const char *end); 170 extern const char *uvTypeName(UniValue::VType t); 171 172 static inline bool jsonTokenIsValue(enum jtokentype jtt) 173 { 174 switch (jtt) { 175 case JTOK_KW_NULL: 176 case JTOK_KW_TRUE: 177 case JTOK_KW_FALSE: 178 case JTOK_NUMBER: 179 case JTOK_STRING: 180 return true; 181 182 default: 183 return false; 184 } 185 186 // not reached 187 } 188 189 static inline bool json_isspace(int ch) 190 { 191 switch (ch) { 192 case 0x20: 193 case 0x09: 194 case 0x0a: 195 case 0x0d: 196 return true; 197 198 default: 199 return false; 200 } 201 202 // not reached 203 } 204 205 extern const UniValue NullUniValue; 206 207 #endif // BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H