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