From a2e4a6b26724f917354a5f8ba75cbcc7fa6bfab3 Mon Sep 17 00:00:00 2001 From: Lawrence Ibarria Date: Sun, 17 Dec 2023 03:57:43 +0000 Subject: [PATCH 1/4] Add override flag to MapProxy destructor, helps with warnings on new compilers --- include/hjson/hjson.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hjson/hjson.h b/include/hjson/hjson.h index 3f794a9..8fc6127 100644 --- a/include/hjson/hjson.h +++ b/include/hjson/hjson.h @@ -367,7 +367,7 @@ class MapProxy : public Value { MapProxy(Value&&); public: - ~MapProxy(); + ~MapProxy() override; MapProxy& operator =(const MapProxy&); MapProxy& operator =(const Value&); MapProxy& operator =(Value&&); From 919bdebb4eb81c9be4d3e58778e0c7693c206a5a Mon Sep 17 00:00:00 2001 From: Lawrence Ibarria Date: Sun, 17 Dec 2023 05:34:15 +0000 Subject: [PATCH 2/4] Add functions that use rvalue references Adding functions for Vector and Map that use r-value references for insertion, useful when builing a hjson value recursively --- include/hjson/hjson.h | 5 +++++ src/hjson_value.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/include/hjson/hjson.h b/include/hjson/hjson.h index 8fc6127..26d53af 100644 --- a/include/hjson/hjson.h +++ b/include/hjson/hjson.h @@ -278,6 +278,7 @@ class Value { // Hjson::type_mismatch if this Value is of any other type than Vector or // Undefined. void push_back(const Value&); + void push_back(Value&&); // -- Map specific functions // Get key by its zero-based insertion index. Throws @@ -293,6 +294,10 @@ class Value { Value& at(const std::string& key); const Value& at(const char *key) const; Value& at(const char *key); + + // This function can insert a value into the map without an allocation + void insert(const std::string&key, Value&&); + // Iterations are always done in alphabetical key order. Returns a default // constructed iterator if this Value is of any other type than Map. std::map::iterator begin(); diff --git a/src/hjson_value.cpp b/src/hjson_value.cpp index 38e2616..94b38ef 100644 --- a/src/hjson_value.cpp +++ b/src/hjson_value.cpp @@ -347,6 +347,21 @@ Value& Value::at(const char *name) { return at(std::string(name)); } +void Value::insert(const std::string&key, Value&& other) +{ + switch (prv->type) + { + case Type::Undefined: + throw index_out_of_bounds("Key not found."); + case Type::Map: + try { + prv->m->m.insert_or_assign(key, std::move(other)); + } catch(const std::out_of_range&) {} + default: + throw type_mismatch("Must be of type Map for that operation."); + } +} + const Value Value::operator[](const std::string& name) const { if (prv->type == Type::Undefined) { @@ -1326,6 +1341,18 @@ void Value::push_back(const Value& other) { prv->v->push_back(other); } +void Value::push_back(Value&& other) { + if (prv->type == Type::Undefined) { + prv->~ValueImpl(); + // Recreate the private object using the same memory block. + new(&(*prv)) ValueImpl(Type::Vector); + } else if (prv->type != Type::Vector) { + throw type_mismatch("Must be of type Undefined or Vector for that operation."); + } + + prv->v->push_back(std::move(other)); +} + void Value::move(int from, int to) { switch (prv->type) From 64710c8f73746e92eec643d5236d88828d7692d4 Mon Sep 17 00:00:00 2001 From: Lawrence Ibarria Date: Sun, 17 Dec 2023 17:58:30 +0000 Subject: [PATCH 3/4] Protect new functions behind a define for C++17 --- include/hjson/hjson.h | 8 ++++++-- src/hjson_value.cpp | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/hjson/hjson.h b/include/hjson/hjson.h index 26d53af..92e45bd 100644 --- a/include/hjson/hjson.h +++ b/include/hjson/hjson.h @@ -278,7 +278,6 @@ class Value { // Hjson::type_mismatch if this Value is of any other type than Vector or // Undefined. void push_back(const Value&); - void push_back(Value&&); // -- Map specific functions // Get key by its zero-based insertion index. Throws @@ -295,9 +294,14 @@ class Value { const Value& at(const char *key) const; Value& at(const char *key); +#if __cplusplus >= 201703L + // These are functions available in C++17 and greater only + // This function will add a value to a vector without a copy + void push_back(Value&&); // This function can insert a value into the map without an allocation void insert(const std::string&key, Value&&); - +#endif // __cplusplus >= 201703L + // Iterations are always done in alphabetical key order. Returns a default // constructed iterator if this Value is of any other type than Map. std::map::iterator begin(); diff --git a/src/hjson_value.cpp b/src/hjson_value.cpp index 94b38ef..5a197ac 100644 --- a/src/hjson_value.cpp +++ b/src/hjson_value.cpp @@ -347,6 +347,7 @@ Value& Value::at(const char *name) { return at(std::string(name)); } +#if __cplusplus >= 201703L void Value::insert(const std::string&key, Value&& other) { switch (prv->type) @@ -361,6 +362,7 @@ void Value::insert(const std::string&key, Value&& other) throw type_mismatch("Must be of type Map for that operation."); } } +#endif // __cplusplus >= 201703L const Value Value::operator[](const std::string& name) const { @@ -1341,6 +1343,7 @@ void Value::push_back(const Value& other) { prv->v->push_back(other); } +#if __cplusplus >= 201703L void Value::push_back(Value&& other) { if (prv->type == Type::Undefined) { prv->~ValueImpl(); @@ -1352,6 +1355,7 @@ void Value::push_back(Value&& other) { prv->v->push_back(std::move(other)); } +#endif // __cplusplus >= 201703L void Value::move(int from, int to) { From 2c148e1e4f340229ca8253093a2c2d13fb439055 Mon Sep 17 00:00:00 2001 From: Lawrence Ibarria Date: Sun, 17 Dec 2023 18:26:27 +0000 Subject: [PATCH 4/4] Ensure we can call insert on an empty value and it becomes a Map --- src/hjson_value.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hjson_value.cpp b/src/hjson_value.cpp index 5a197ac..248ed02 100644 --- a/src/hjson_value.cpp +++ b/src/hjson_value.cpp @@ -353,11 +353,15 @@ void Value::insert(const std::string&key, Value&& other) switch (prv->type) { case Type::Undefined: - throw index_out_of_bounds("Key not found."); + prv->~ValueImpl(); + // Recreate the private object using the same memory block. + new(&(*prv)) ValueImpl(Type::Map); + // Fall through case Type::Map: try { prv->m->m.insert_or_assign(key, std::move(other)); } catch(const std::out_of_range&) {} + return; default: throw type_mismatch("Must be of type Map for that operation."); }