From 1c099147471cbb80861a68f4bcb36655b4161a0c Mon Sep 17 00:00:00 2001 From: akobrin1 Date: Wed, 30 Jun 2021 23:55:26 -0400 Subject: [PATCH] univalue support for move semantics --- src/univalue/include/univalue.h | 28 +++++-- src/univalue/lib/univalue.cpp | 116 +++++++++++++++++++++++++--- src/univalue/lib/univalue_read.cpp | 18 ++--- src/univalue/lib/univalue_write.cpp | 52 +++++++------ 4 files changed, 165 insertions(+), 49 deletions(-) diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h index bba1f048d..afe81c603 100644 --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -18,11 +18,9 @@ class UniValue { public: enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, }; - UniValue() { typ = VNULL; } - UniValue(UniValue::VType initialType, const std::string& initialStr = "") { - typ = initialType; - val = initialStr; - } + UniValue() : typ(VNULL) {} + UniValue(UniValue::VType type, const std::string& value = std::string()) : typ(type), val(value) {} + UniValue(UniValue::VType type, std::string&& value) : typ(type), val(std::move(value)) {} UniValue(uint64_t val_) { setInt(val_); } @@ -41,9 +39,11 @@ class UniValue { UniValue(const std::string& val_) { setStr(val_); } + UniValue(std::string&& val_) { + setStr(std::move(val_)); + } UniValue(const char *val_) { - std::string s(val_); - setStr(s); + setStr(std::string(val_)); } void clear(); @@ -60,11 +60,13 @@ class UniValue { bool setNull(); bool setBool(bool val); bool setNumStr(const std::string& val); + bool setNumStr(std::string&& val); bool setInt(uint64_t val); bool setInt(int64_t val); bool setInt(int val_) { return setInt((int64_t)val_); } bool setFloat(double val); bool setStr(const std::string& val); + bool setStr(std::string&& val); bool setArray(); bool setObject(); @@ -91,11 +93,22 @@ class UniValue { bool isObject() const { return (typ == VOBJ); } bool push_back(const UniValue& val); + bool push_back(UniValue&& val); bool push_backV(const std::vector& vec); + bool push_backV(std::vector&& vec); void __pushKV(const std::string& key, const UniValue& val); + void __pushKV(const std::string& key, UniValue&& val); + void __pushKV(std::string&& key, const UniValue& val); + void __pushKV(std::string&& key, UniValue&& val); + bool pushKV(const std::string& key, const UniValue& val); + bool pushKV(const std::string& key, UniValue&& val); + bool pushKV(std::string&& key, const UniValue& val); + bool pushKV(std::string&& key, UniValue&& val); + bool pushKVs(const UniValue& obj); + bool pushKVs(UniValue&& obj); std::string write(unsigned int prettyIndent = 0, unsigned int indentLevel = 0) const; @@ -113,6 +126,7 @@ class UniValue { std::vector values; bool findKey(const std::string& key, size_t& retIdx) const; + void write(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const; diff --git a/src/univalue/lib/univalue.cpp b/src/univalue/lib/univalue.cpp index 2b966ad85..feb6ed7d6 100644 --- a/src/univalue/lib/univalue.cpp +++ b/src/univalue/lib/univalue.cpp @@ -54,22 +54,25 @@ bool UniValue::setNumStr(const std::string& val_) return true; } -bool UniValue::setInt(uint64_t val_) +bool UniValue::setNumStr(std::string&& val_) { - std::ostringstream oss; + if (!validNumStr(val_)) + return false; - oss << val_; + clear(); + typ = VNUM; + val = std::move(val_); + return true; +} - return setNumStr(oss.str()); +bool UniValue::setInt(uint64_t val_) +{ + return setNumStr(std::to_string(val_)); } bool UniValue::setInt(int64_t val_) { - std::ostringstream oss; - - oss << val_; - - return setNumStr(oss.str()); + return setNumStr(std::to_string(val_)); } bool UniValue::setFloat(double val_) @@ -91,6 +94,14 @@ bool UniValue::setStr(const std::string& val_) return true; } +bool UniValue::setStr(std::string&& val_) +{ + clear(); + typ = VSTR; + val = std::move(val_); + return true; +} + bool UniValue::setArray() { clear(); @@ -114,6 +125,15 @@ bool UniValue::push_back(const UniValue& val_) return true; } +bool UniValue::push_back(UniValue&& val_) +{ + if (typ != VARR) + return false; + + values.push_back(std::move(val_)); + return true; +} + bool UniValue::push_backV(const std::vector& vec) { if (typ != VARR) @@ -124,12 +144,40 @@ bool UniValue::push_backV(const std::vector& vec) return true; } +bool UniValue::push_backV(std::vector&& vec) +{ + if (typ != VARR) + return false; + + values.insert(values.end(), std::make_move_iterator(vec.begin()), std::make_move_iterator(vec.end())); + + return true; +} + void UniValue::__pushKV(const std::string& key, const UniValue& val_) { keys.push_back(key); values.push_back(val_); } +void UniValue::__pushKV(const std::string& key, UniValue&& val_) +{ + keys.push_back(key); + values.push_back(std::move(val_)); +} + +void UniValue::__pushKV(std::string&& key, const UniValue& val_) +{ + keys.push_back(std::move(key)); + values.push_back(val_); +} + +void UniValue::__pushKV(std::string&& key, UniValue&& val_) +{ + keys.push_back(std::move(key)); + values.push_back(std::move(val_)); +} + bool UniValue::pushKV(const std::string& key, const UniValue& val_) { if (typ != VOBJ) @@ -143,6 +191,45 @@ bool UniValue::pushKV(const std::string& key, const UniValue& val_) return true; } +bool UniValue::pushKV(const std::string& key, UniValue&& val_) +{ + if (typ != VOBJ) + return false; + + size_t idx; + if (findKey(key, idx)) + values[idx] = std::move(val_); + else + __pushKV(key, std::move(val_)); + return true; +} + +bool UniValue::pushKV(std::string&& key, const UniValue& val_) +{ + if (typ != VOBJ) + return false; + + size_t idx; + if (findKey(key, idx)) + values[idx] = val_; + else + __pushKV(std::move(key), val_); + return true; +} + +bool UniValue::pushKV(std::string&& key, UniValue&& val_) +{ + if (typ != VOBJ) + return false; + + size_t idx; + if (findKey(key, idx)) + values[idx] = std::move(val_); + else + __pushKV(std::move(key), std::move(val_)); + return true; +} + bool UniValue::pushKVs(const UniValue& obj) { if (typ != VOBJ || obj.typ != VOBJ) @@ -154,6 +241,17 @@ bool UniValue::pushKVs(const UniValue& obj) return true; } +bool UniValue::pushKVs(UniValue&& obj) +{ + if (typ != VOBJ || obj.typ != VOBJ) + return false; + + for (size_t i = 0; i < obj.keys.size(); i++) + __pushKV(std::move(obj.keys[i]), std::move(obj.values.at(i))); + + return true; +} + void UniValue::getObjMap(std::map& kv) const { if (typ != VOBJ) diff --git a/src/univalue/lib/univalue_read.cpp b/src/univalue/lib/univalue_read.cpp index fe8749a67..3a023a977 100644 --- a/src/univalue/lib/univalue_read.cpp +++ b/src/univalue/lib/univalue_read.cpp @@ -172,7 +172,7 @@ enum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed, } } - tokenVal = numStr; + tokenVal = std::move(numStr); consumed = static_cast(raw - rawStart); return JTOK_NUMBER; } @@ -234,7 +234,7 @@ enum jtokentype getJsonToken(std::string& tokenVal, unsigned int& consumed, if (!writer.finalize()) return JTOK_ERR; - tokenVal = valStr; + tokenVal = std::move(valStr); consumed = static_cast(raw - rawStart); return JTOK_STRING; } @@ -325,7 +325,7 @@ bool UniValue::read(const char *raw, size_t size) } else { UniValue tmpVal(utyp); UniValue *top = stack.back(); - top->values.push_back(tmpVal); + top->values.push_back(std::move(tmpVal)); UniValue *newTop = &(top->values.back()); stack.push_back(newTop); @@ -400,12 +400,12 @@ bool UniValue::read(const char *raw, size_t size) } if (!stack.size()) { - *this = tmpVal; + *this = std::move(tmpVal); break; } UniValue *top = stack.back(); - top->values.push_back(tmpVal); + top->values.push_back(std::move(tmpVal)); setExpect(NOT_VALUE); break; @@ -414,12 +414,12 @@ bool UniValue::read(const char *raw, size_t size) case JTOK_NUMBER: { UniValue tmpVal(VNUM, tokenVal); if (!stack.size()) { - *this = tmpVal; + *this = std::move(tmpVal); break; } UniValue *top = stack.back(); - top->values.push_back(tmpVal); + top->values.push_back(std::move(tmpVal)); setExpect(NOT_VALUE); break; @@ -434,11 +434,11 @@ bool UniValue::read(const char *raw, size_t size) } else { UniValue tmpVal(VSTR, tokenVal); if (!stack.size()) { - *this = tmpVal; + *this = std::move(tmpVal); break; } UniValue *top = stack.back(); - top->values.push_back(tmpVal); + top->values.push_back(std::move(tmpVal)); } setExpect(NOT_VALUE); diff --git a/src/univalue/lib/univalue_write.cpp b/src/univalue/lib/univalue_write.cpp index db039fcb0..c2c453e72 100644 --- a/src/univalue/lib/univalue_write.cpp +++ b/src/univalue/lib/univalue_write.cpp @@ -7,11 +7,8 @@ #include "univalue.h" #include "univalue_escapes.h" -static std::string json_escape(const std::string& inS) +static void json_escape(const std::string& inS, std::string& outS) { - std::string outS; - outS.reserve(inS.size() * 2); - for (unsigned int i = 0; i < inS.size(); i++) { unsigned char ch = inS[i]; const char *escStr = escapes[ch]; @@ -21,16 +18,21 @@ static std::string json_escape(const std::string& inS) else outS += ch; } - - return outS; } std::string UniValue::write(unsigned int prettyIndent, unsigned int indentLevel) const { std::string s; - s.reserve(1024); + s.reserve(2048); + write(prettyIndent, indentLevel, s); + return s; +} +void UniValue::write(unsigned int prettyIndent, + unsigned int indentLevel, + std::string& s) const +{ unsigned int modIndent = indentLevel; if (modIndent == 0) modIndent = 1; @@ -46,7 +48,9 @@ std::string UniValue::write(unsigned int prettyIndent, writeArray(prettyIndent, modIndent, s); break; case VSTR: - s += "\"" + json_escape(val) + "\""; + s += '"'; + json_escape(val, s); + s += '"'; break; case VNUM: s += val; @@ -55,8 +59,6 @@ std::string UniValue::write(unsigned int prettyIndent, s += (val == "1" ? "true" : "false"); break; } - - return s; } static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) @@ -66,47 +68,49 @@ static void indentStr(unsigned int prettyIndent, unsigned int indentLevel, std:: void UniValue::writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const { - s += "["; + s += '['; if (prettyIndent) - s += "\n"; + s += '\n'; for (unsigned int i = 0; i < values.size(); i++) { if (prettyIndent) indentStr(prettyIndent, indentLevel, s); - s += values[i].write(prettyIndent, indentLevel + 1); + values[i].write(prettyIndent, indentLevel + 1, s); if (i != (values.size() - 1)) { - s += ","; + s += ','; } if (prettyIndent) - s += "\n"; + s += '\n'; } if (prettyIndent) indentStr(prettyIndent, indentLevel - 1, s); - s += "]"; + s += ']'; } void UniValue::writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const { - s += "{"; + s += '{'; if (prettyIndent) - s += "\n"; + s += '\n'; for (unsigned int i = 0; i < keys.size(); i++) { if (prettyIndent) indentStr(prettyIndent, indentLevel, s); - s += "\"" + json_escape(keys[i]) + "\":"; + s += '\"'; + json_escape(keys[i], s); + s += "\":"; if (prettyIndent) - s += " "; - s += values.at(i).write(prettyIndent, indentLevel + 1); + s += ' '; + values.at(i).write(prettyIndent, indentLevel + 1, s); if (i != (values.size() - 1)) - s += ","; + s += ','; if (prettyIndent) - s += "\n"; + s += '\n'; } if (prettyIndent) indentStr(prettyIndent, indentLevel - 1, s); - s += "}"; + s += '}'; }