diff --git a/.gitmodules b/.gitmodules index c0f6db171e..dbb4ce5802 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,9 +4,6 @@ [submodule "cc-wrapper"] path = submodules/cc-wrapper url = https://github.com/eranif/cc-wrapper -[submodule "submodules/cJSON"] - path = submodules/cJSON - url = https://github.com/DaveGamble/cJSON [submodule "submodules/doctest"] path = submodules/doctest url = https://github.com/doctest/doctest diff --git a/CMakeLists.txt b/CMakeLists.txt index 34ff83a25b..fe2f0dd8e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -988,7 +988,6 @@ endif() add_subdirectory(submodules/lexilla) add_subdirectory(submodules) -include_directories(submodules/cJSON) add_subdirectory(sdk/wxsqlite3) add_subdirectory(sdk/databaselayer) diff --git a/CodeLite/CMakeLists.txt b/CodeLite/CMakeLists.txt index ba55d1a4b2..800432c45a 100644 --- a/CodeLite/CMakeLists.txt +++ b/CodeLite/CMakeLists.txt @@ -97,8 +97,7 @@ target_link_libraries( ${GTK_LIBS} ${ADDITIONAL_LIBRARIES} ${LIBUCHARDET_LIB} - assistantlib - cJSON) + assistantlib) if(MINGW) set_target_properties( diff --git a/CodeLite/JSON.cpp b/CodeLite/JSON.cpp index f6f68ca073..c8a1afe562 100644 --- a/CodeLite/JSON.cpp +++ b/CodeLite/JSON.cpp @@ -29,16 +29,20 @@ #include -JSON::JSON(const wxString& text) { m_json = cJSON_Parse(text.mb_str(wxConvUTF8).data()); } +JSON::JSON(const wxString& text) +{ + m_json = std::make_shared(nlohmann::ordered_json::parse(text.mb_str(wxConvUTF8).data())); +} JSON::JSON(JsonType type) { - if (type == JsonType::Array) - m_json = cJSON_CreateArray(); - else if (type == JsonType::Null) - m_json = cJSON_CreateNull(); - else - m_json = cJSON_CreateObject(); + if (type == JsonType::Array) { + m_json = std::make_shared(nlohmann::ordered_json::array()); + } else if (type == JsonType::Null) { + m_json = std::make_shared(nlohmann::ordered_json(nullptr)); + } else { + m_json = std::make_shared(nlohmann::ordered_json::object()); + } } JSON::JSON(const wxFileName& filename) @@ -47,17 +51,7 @@ JSON::JSON(const wxFileName& filename) if (!FileUtils::ReadFileContent(filename, content)) { return; } - - const std::string cstr = content.ToStdString(wxConvUTF8); - m_json = cJSON_Parse(cstr.c_str()); -} - -JSON::~JSON() -{ - if (m_json) { - cJSON_Delete(m_json); - m_json = nullptr; - } + m_json = std::make_shared(nlohmann::ordered_json::parse(content.ToStdString(wxConvUTF8))); } void JSON::save(const wxFileName& fn) const @@ -74,277 +68,300 @@ JSONItem JSON::toElement() const if (!m_json) { return JSONItem(nullptr); } - return JSONItem(m_json); + return JSONItem(m_json, m_json.get()); } -JSONItem JSONItem::namedObject(const wxString& name) const +JSONItem JSONItem::createArray() { - if (!m_json) { - return JSONItem(nullptr); - } - - cJSON* obj = cJSON_GetObjectItem(m_json, name.mb_str(wxConvUTF8).data()); - if (!obj) { - return JSONItem(nullptr); - } - return JSONItem(obj); + auto root = std::make_shared(nlohmann::ordered_json::array()); + return JSONItem(root, root.get()); } -cJSON* JSON::release() +JSONItem JSONItem::createObject() { - cJSON* p = m_json; - m_json = nullptr; - return p; + auto root = std::make_shared(nlohmann::ordered_json::object()); + return JSONItem(root, root.get()); } -/////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////// -JSONItem::JSONItem(cJSON* json) - : m_json(json) +/////////////////////////////////////////////////////////////////////////////// +JSONItem::JSONItem(std::shared_ptr root, nlohmann::ordered_json* json) + : m_root(std::move(root)) + , m_json(json) { } -JSONItem JSONItem::operator[](int index) const +char* JSONItem::FormatRawString(bool formatted) const { - if (isArray()) { - return arrayItem(index); + if (!m_json) { + return nullptr; } - return JSONItem(nullptr); + const auto s = m_json->dump(formatted ? 2 : -1); + return strdup(s.data()); } -std::unordered_map JSONItem::GetAsMap() const +wxString JSONItem::format(bool formatted) const { - if (!m_json || !isObject()) { - return {}; - } - - std::unordered_map res; - cJSON* c = m_json->child; - while (c) { - res.erase(c->string); - res.insert({c->string, JSONItem{c}}); - c = c->next; + if (!m_json) { + return wxT(""); } - return res; + return wxString::FromUTF8(m_json->dump(formatted ? 2 : -1)); } -std::vector JSONItem::GetAsVector() const -{ - if (!m_json || !isArray()) { - return {}; - } +bool JSONItem::isNull() const { return m_json && m_json->is_null(); } +bool JSONItem::isBool() const { return m_json && m_json->is_boolean(); } +bool JSONItem::isString() const { return m_json && m_json->is_string(); } +bool JSONItem::isNumber() const { return m_json && m_json->is_number(); } +bool JSONItem::isArray() const { return m_json && m_json->is_array(); } +bool JSONItem::isObject() const { return m_json && m_json->is_object(); } - std::vector res; - res.reserve(arraySize()); - cJSON* c = m_json->child; - while (c) { - res.emplace_back(JSONItem{c}); - c = c->next; +bool JSONItem::toBool(bool defaultValue) const +{ + if (!m_json || !isBool()) { + return defaultValue; } - return res; + return m_json->get(); } -JSONItem JSONItem::operator[](const wxString& name) const { return namedObject(name); } - -JSONItem JSONItem::arrayItem(int pos) const +wxString JSONItem::toString(const wxString& defaultValue) const { - if (!m_json) { - return JSONItem(nullptr); + if (!m_json || !isString()) { + return defaultValue; } - - if (m_json->type != cJSON_Array) - return JSONItem(nullptr); - - int size = cJSON_GetArraySize(m_json); - if (pos >= size) - return JSONItem(nullptr); - - return JSONItem(cJSON_GetArrayItem(m_json, pos)); + return wxString::FromUTF8(m_json->get()); } -bool JSONItem::isNull() const +int JSONItem::toInt(int defaultValue) const { - if (!m_json) { - return false; + if (!m_json || !isNumber()) { + return defaultValue; } - return m_json->type == cJSON_NULL; + return m_json->get(); } -bool JSONItem::toBool(bool defaultValue) const +size_t JSONItem::toSize_t(size_t defaultValue) const { - if (!m_json) { + if (!m_json || !isNumber()) { return defaultValue; } + return m_json->get(); +} - if (!isBool()) { +double JSONItem::toDouble(double defaultValue) const +{ + if (!m_json || !isNumber()) { return defaultValue; } - - return m_json->type == cJSON_True; + return m_json->get(); } -wxString JSONItem::toString(const wxString& defaultValue) const +int JSONItem::arraySize() const { - if (!m_json) { - return defaultValue; + if (!m_json || !isArray()) { + return 0; } + return static_cast(m_json->size()); +} - if (m_json->type != cJSON_String) { - return defaultValue; +JSONItem JSONItem::arrayItem(int pos) const +{ + if (!m_json || !isArray() || pos < 0 || arraySize() <= pos) { + return JSONItem(nullptr); } - - return wxString(m_json->valuestring, wxConvUTF8); + return JSONItem(m_root, &m_json->at(pos)); } -bool JSONItem::isBool() const +JSONItem JSONItem::operator[](int index) const { return arrayItem(index); } + +std::vector JSONItem::GetAsVector() const { - if (!m_json) { - return false; + if (!m_json || !isArray()) { + return {}; } - return m_json->type == cJSON_True || m_json->type == cJSON_False; + std::vector res; + res.reserve(arraySize()); + for (auto& child : *m_json) { + res.emplace_back(JSONItem{m_root, &child}); + } + return res; } -bool JSONItem::isString() const +wxArrayString JSONItem::toArrayString(const wxArrayString& defaultValue) const { - if (!m_json) { - return false; + if (!m_json || !isArray()) { + return defaultValue; } - return m_json->type == cJSON_String; -} + const int arr_size = arraySize(); + if (arr_size == 0) { + return defaultValue; + } -void JSONItem::arrayAppend(const char* value) -{ - if (!m_json) { - return; + wxArrayString arr; + arr.reserve(arr_size); + for (const auto& child : *m_json) { + if (!child.is_string()) { + return defaultValue; + } + arr.push_back(wxString::FromUTF8(child.get())); } - cJSON* p = cJSON_CreateString(value); - cJSON_AddItemToArray(m_json, p); + return arr; } -void JSONItem::arrayAppend(const std::string& value) { arrayAppend(value.c_str()); } - -void JSONItem::arrayAppend(double number) +std::vector JSONItem::toDoubleArray(const std::vector& defaultValue) const { - if (!m_json) { - return; + if (!m_json || !isArray()) { + return defaultValue; } - cJSON* p = cJSON_CreateNumber(number); - cJSON_AddItemToArray(m_json, p); -} -void JSONItem::arrayAppend(int number) { arrayAppend((double)number); } + const int arr_size = arraySize(); + if (arr_size == 0) { + return defaultValue; + } -void JSONItem::arrayAppend(const wxString& value) { arrayAppend(value.mb_str(wxConvUTF8).data()); } + std::vector arr; + arr.reserve(arr_size); + for (const auto& child : *m_json) { + if (!child.is_number()) { + return defaultValue; + } + arr.push_back(child.get()); + } + return arr; +} -void JSONItem::arrayAppend(JSONItem&& element) +std::vector JSONItem::toIntArray(const std::vector& defaultValue) const { - if (!m_json) { - return; + if (!m_json || !isArray()) { + return defaultValue; } - if (element.m_json) { - cJSON_AddItemToArray(m_json, element.m_json); + + const int arr_size = arraySize(); + if (arr_size == 0) { + return defaultValue; } -} -JSONItem JSONItem::createArray() -{ - JSONItem arr(cJSON_CreateArray()); + std::vector arr; + arr.reserve(arr_size); + for (const auto& child : *m_json) { + if (!child.is_number()) { + return defaultValue; + } + arr.push_back(child.get()); + } return arr; } -JSONItem JSONItem::createObject() +bool JSONItem::contains(const wxString& name) const { - JSONItem obj(cJSON_CreateObject()); - return obj; + if (!m_json || !isObject()) { + return false; + } + const auto keyBuffer = name.mb_str(wxConvUTF8); + return m_json->contains(keyBuffer.data()); } -char* JSONItem::FormatRawString(bool formatted) const +JSONItem JSONItem::namedObject(const wxString& name) const { - if (!m_json) { - return nullptr; + if (!m_json || !isObject()) { + return JSONItem(nullptr); } - - if (formatted) { - return cJSON_Print(m_json); - + const auto keyBuffer = name.mb_str(wxConvUTF8); + if (m_json->contains(keyBuffer.data())) { + return {m_root, &m_json->at(keyBuffer.data())}; } else { - return cJSON_PrintUnformatted(m_json); + return JSONItem(nullptr); } } -wxString JSONItem::format(bool formatted) const +JSONItem JSONItem::operator[](const wxString& name) const { return namedObject(name); } + +std::unordered_map JSONItem::GetAsMap() const { - if (!m_json) { - return wxT(""); + if (!m_json || !isObject()) { + return {}; } - auto p = formatted ? cJSON_Print(m_json) : cJSON_PrintUnformatted(m_json); - auto utf8_str = wxString::FromUTF8(p); - free(p); - return utf8_str; + std::unordered_map res; + for (auto& [key, child] : m_json->items()) { + res.emplace(key, JSONItem{m_root, &child}); + } + return res; } -int JSONItem::toInt(int defaultVal) const +wxStringMap_t JSONItem::toStringMap(const wxStringMap_t& default_map) const { - if (!m_json) { - return defaultVal; + if (!m_json || !isArray()) { + return default_map; } + wxStringMap_t res; - if (m_json->type != cJSON_Number) { - return defaultVal; + for (int i = 0; i < arraySize(); ++i) { + wxString key = arrayItem(i).namedObject("key").toString(); + wxString val = arrayItem(i).namedObject("value").toString(); + res.emplace(key, val); } - - return m_json->valueint; + return res; } -size_t JSONItem::toSize_t(size_t defaultVal) const +void JSONItem::arrayAppend(const char* value) { - if (!m_json) { - return defaultVal; + if (!m_json || !isArray()) { + return; } + m_json->push_back(value); +} - if (m_json->type != cJSON_Number) { - return defaultVal; - } +void JSONItem::arrayAppend(const std::string& value) { arrayAppend(value.c_str()); } +void JSONItem::arrayAppend(const wxString& value) { arrayAppend(value.mb_str(wxConvUTF8).data()); } - return (size_t)m_json->valueint; +void JSONItem::arrayAppend(double number) +{ + if (!m_json || !isArray()) { + return; + } + m_json->push_back(number); } -double JSONItem::toDouble(double defaultVal) const +void JSONItem::arrayAppend(int number) { arrayAppend(static_cast(number)); } + +void JSONItem::arrayAppend(JSONItem&& element) { - if (!m_json) { - return defaultVal; + if (!m_json || !isArray()) { + return; } - - if (m_json->type != cJSON_Number) { - return defaultVal; + if (element.m_json) { + m_json->push_back(*element.m_json); + element.m_root = nullptr; + element.m_json = nullptr; } - - return m_json->valuedouble; } -int JSONItem::arraySize() const +JSONItem& JSONItem::addNull(const wxString& name) { - if (!m_json) { - return 0; + if (m_json && isObject()) { + m_json->emplace(name.ToStdString(wxConvUTF8).data(), nullptr); } + return *this; +} +JSONItem JSONItem::AddArray(const wxString& name) +{ + JSONItem json = createArray(); + addProperty(name, json); + return namedObject(name); +} - if (m_json->type != cJSON_Array) - return 0; - - return cJSON_GetArraySize(m_json); +JSONItem JSONItem::AddObject(const wxString& name) +{ + JSONItem json = createObject(); + addProperty(name, json); + return namedObject(name); } JSONItem& JSONItem::addProperty(const wxString& name, bool value) { - if (m_json) { - if (value) { - cJSON_AddTrueToObject(m_json, name.mb_str(wxConvUTF8).data()); - } else { - cJSON_AddFalseToObject(m_json, name.mb_str(wxConvUTF8).data()); - } + if (m_json && isObject()) { + m_json->emplace(name.mb_str(wxConvUTF8).data(), value); } return *this; } @@ -356,8 +373,8 @@ JSONItem& JSONItem::addProperty(const wxString& name, const wxString& value) JSONItem& JSONItem::addProperty(const wxString& name, const std::string& value) { - if (m_json) { - cJSON_AddStringToObject(m_json, name.mb_str(wxConvUTF8).data(), value.data()); + if (m_json && isObject()) { + m_json->emplace(name.mb_str(wxConvUTF8).data(), value); } return *this; } @@ -369,8 +386,8 @@ JSONItem& JSONItem::addProperty(const wxString& name, const wxChar* value) JSONItem& JSONItem::addProperty(const wxString& name, long value) { - if (m_json) { - cJSON_AddNumberToObject(m_json, name.mb_str(wxConvUTF8).data(), value); + if (m_json && isObject()) { + m_json->emplace(name.mb_str(wxConvUTF8).data(), value); } return *this; } @@ -385,94 +402,19 @@ JSONItem& JSONItem::addProperty(const wxString& name, const wxArrayString& arr) return *this; } -wxArrayString JSONItem::toArrayString(const wxArrayString& defaultValue) const -{ - if (!m_json) { - return defaultValue; - } - - if (m_json->type != cJSON_Array) { - return defaultValue; - } - - int arr_size = arraySize(); - if (arr_size == 0) { - return defaultValue; - } - - wxArrayString arr; - arr.reserve(arr_size); - auto child = m_json->child; - while (child) { - arr.push_back(wxString(child->valuestring, wxConvUTF8)); - child = child->next; - } - return arr; -} - -bool JSONItem::contains(const wxString& name) const -{ - if (!m_json) { - return false; - } - - std::string name_cstr = name.ToStdString(wxConvUTF8); - return cJSON_GetObjectItem(m_json, name_cstr.c_str()) != nullptr; -} - -#if wxUSE_GUI - -JSONItem& JSONItem::addProperty(const wxString& name, const wxSize& sz) -{ - wxString szStr; - szStr << sz.x << "," << sz.y; - return addProperty(name, szStr); -} - -wxSize JSONItem::toSize() const -{ - if (!m_json) { - return wxDefaultSize; - } - - if (m_json->type != cJSON_String) { - return wxDefaultSize; - } - - wxString str = m_json->valuestring; - wxString x = str.BeforeFirst(','); - wxString y = str.AfterFirst(','); - - long nX(-1), nY(-1); - if (!x.ToLong(&nX) || !y.ToLong(&nY)) - return wxDefaultSize; - - return wxSize(nX, nY); -} - -#endif - JSONItem& JSONItem::addProperty(const wxString& name, const JSONItem& element) { - if (!m_json) { + if (!m_json || !isObject() || !element.m_json) { return *this; } - cJSON_AddItemToObject(m_json, name.mb_str(wxConvUTF8).data(), element.m_json); + (*m_json)[name.mb_str(wxConvUTF8).data()] = *element.m_json; return *this; } -void JSONItem::removeProperty(const wxString& name) -{ - // delete child property - if (!m_json) { - return; - } - cJSON_DeleteItemFromObject(m_json, name.mb_str(wxConvUTF8).data()); -} #if wxUSE_GUI JSONItem& JSONItem::addProperty(const wxString& name, const wxStringMap_t& stringMap) { - if (!m_json) + if (!m_json || !isObject()) return *this; JSONItem arr = JSONItem::createArray(); @@ -486,148 +428,72 @@ JSONItem& JSONItem::addProperty(const wxString& name, const wxStringMap_t& strin return *this; } #endif -wxStringMap_t JSONItem::toStringMap(const wxStringMap_t& default_map) const -{ - wxStringMap_t res; - if (!m_json || m_json->type != cJSON_Array) { - return default_map; - } - - for (int i = 0; i < arraySize(); ++i) { - wxString key = arrayItem(i).namedObject("key").toString(); - wxString val = arrayItem(i).namedObject("value").toString(); - res.insert(std::make_pair(key, val)); - } - return res; -} JSONItem& JSONItem::addProperty(const wxString& name, size_t value) { return addProperty(name, (int)value); } -JSONItem& JSONItem::addNull(const wxString& name) -{ - if (m_json) { - cJSON_AddNullToObject(m_json, name.ToStdString(wxConvUTF8).data()); - } - return *this; -} - JSONItem& JSONItem::addProperty(const wxString& name, const char* value, const wxMBConv& conv) { return addProperty(name, wxString(value, conv)); } -bool JSONItem::isArray() const -{ - if (!m_json) { - return false; - } - return m_json->type == cJSON_Array; -} - -bool JSONItem::isObject() const -{ - if (!m_json) { - return false; - } - return m_json->type == cJSON_Object; -} - -bool JSONItem::isNumber() const -{ - if (!m_json) { - return false; - } - return m_json->type == cJSON_Number; -} - JSONItem& JSONItem::addProperty(const wxString& name, const wxFileName& filename) { return addProperty(name, filename.GetFullPath()); } -JSONItem JSONItem::AddArray(const wxString& name) -{ - JSONItem json = createArray(); - addProperty(name, json); - return json; -} - -JSONItem JSONItem::AddObject(const wxString& name) -{ - JSONItem json = createObject(); - addProperty(name, json); - return json; -} - JSONItem& JSONItem::addProperty(const wxString& name, JSON&& json) { - if (!m_json) { + if (!m_json || !json.m_json) { return *this; } - cJSON_AddItemToObject(m_json, name.mb_str(wxConvUTF8).data(), json.release()); + (*m_json)[name.mb_str(wxConvUTF8).data()] = std::move(*json.m_json); + json.m_json = nullptr; return *this; } -std::vector JSONItem::toDoubleArray(const std::vector& defaultValue) const +JSONItem& JSONItem::addProperty(const wxString& name, const std::vector& arr_int) { - if (!m_json) { - return defaultValue; - } - - if (m_json->type != cJSON_Array) { - return defaultValue; - } - - int arr_size = arraySize(); - if (arr_size == 0) { - return defaultValue; + if (!m_json || !isObject()) { + return *this; } - std::vector arr; - arr.reserve(arr_size); - auto child = m_json->child; - while (child) { - arr.push_back(child->valuedouble); - child = child->next; + // create array + JSONItem arr = AddArray(name); + for (size_t n : arr_int) { + arr.m_json->push_back(n); } - return arr; + return *this; } -std::vector JSONItem::toIntArray(const std::vector& defaultValue) const +void JSONItem::removeProperty(const wxString& name) { + // delete child property if (!m_json) { - return defaultValue; - } - - if (m_json->type != cJSON_Array) { - return defaultValue; - } - - int arr_size = arraySize(); - if (arr_size == 0) { - return defaultValue; + return; } + m_json->erase(name.mb_str(wxConvUTF8).data()); +} - std::vector arr; - arr.reserve(arr_size); - auto child = m_json->child; - while (child) { - arr.push_back(child->valueint); - child = child->next; - } - return arr; +JSONItem& JSONItem::addProperty(const wxString& name, const wxSize& sz) +{ + wxString szStr; + szStr << sz.x << "," << sz.y; + return addProperty(name, szStr); } -JSONItem& JSONItem::addProperty(const wxString& name, const std::vector& arr_int) +wxSize JSONItem::toSize() const { - if (!m_json || !isObject()) { - return *this; + if (!m_json || !isString()) { + return wxDefaultSize; } + wxString str = toString(); + wxString x = str.BeforeFirst(','); + wxString y = str.AfterFirst(','); - // create array - JSONItem arr = AddArray(name); - for (size_t n : arr_int) { - cJSON_AddItemToArray(arr.m_json, cJSON_CreateNumber(n)); + long nX(-1), nY(-1); + if (!x.ToLong(&nX) || !y.ToLong(&nY)) { + return wxDefaultSize; } - return *this; + + return wxSize(nX, nY); } diff --git a/CodeLite/JSON.h b/CodeLite/JSON.h index 6d838c4c33..9de4b1b904 100644 --- a/CodeLite/JSON.h +++ b/CodeLite/JSON.h @@ -29,20 +29,18 @@ #include "codelite_exports.h" #include "macros.h" -#include +#include +#include #include #include #include #include +#include #include #include #include #include -#if wxUSE_GUI -#include -#endif - ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// @@ -73,19 +71,10 @@ class WXDLLIMPEXP_CL JSONItem */ bool hasNamedObject(const wxString& name) const { return contains(name); } - /// If your array is big (hundred of entries) use - /// `GetAsVector` and iterate it instead JSONItem operator[](int index) const; JSONItem operator[](const wxString& name) const; - /// the C implementation for accessing large arrays, is the sum of an arithmetic progression. - /// Use this method to get an array with `O(1)` access - /// This call is `O(n)` std::vector GetAsVector() const; - - /// the C implementation for accessing by name is by `O(n)` - /// Use this method when you have large number of items and - /// `O(1)` is required std::unordered_map GetAsMap() const; bool toBool(bool defaultValue = false) const; @@ -110,14 +99,14 @@ class WXDLLIMPEXP_CL JSONItem */ char* FormatRawString(bool formatted = true) const; int arraySize() const; - int toInt(int defaultVal = -1) const; + int toInt(int defaultValue = -1) const; /// Convert the value into `E` from template requires(std::is_enum_v) - E fromNumber(E default_value) const + E fromNumber(E defaultValue) const { - return static_cast(toInt(static_cast(default_value))); + return static_cast(toInt(static_cast(defaultValue))); } template @@ -141,8 +130,8 @@ class WXDLLIMPEXP_CL JSONItem static_assert(!std::is_same_v, "GetValue called with unsupported type."); } } - size_t toSize_t(size_t defaultVal = 0) const; - double toDouble(double defaultVal = -1.0) const; + size_t toSize_t(size_t defaultValue = 0) const; + double toDouble(double defaultValue = -1.0) const; wxSize toSize() const; @@ -220,20 +209,11 @@ class WXDLLIMPEXP_CL JSONItem bool isOk() const { return m_json != nullptr; } private: - explicit JSONItem(cJSON* json); - - /** - * @brief release the internal pointer - */ - cJSON* release() - { - cJSON* temp = m_json; - m_json = nullptr; - return temp; - } + JSONItem(std::shared_ptr root, nlohmann::ordered_json* current); private: - cJSON* m_json = nullptr; + std::shared_ptr m_root; + nlohmann::ordered_json* m_json = nullptr; }; ////////////////////////////////////////////////////////////////////////// @@ -256,7 +236,7 @@ class WXDLLIMPEXP_CL JSON // Make this class not copyable JSON(const JSON&) = delete; JSON& operator=(const JSON&) = delete; - ~JSON(); + ~JSON() = default; void save(const wxFileName& fn) const; bool isOk() const { return m_json != nullptr; } @@ -264,10 +244,7 @@ class WXDLLIMPEXP_CL JSON JSONItem toElement() const; private: - cJSON* release(); - -private: - cJSON* m_json = nullptr; + std::shared_ptr m_json; }; #endif // ZJSONNODE_H diff --git a/TODO.md b/TODO.md index c97468e061..a76fd057b4 100644 --- a/TODO.md +++ b/TODO.md @@ -15,7 +15,6 @@ others: - SFTP plugin: re-use the remote find in files dialog - SFTP plugin: use clTerminalViewCtrl for the log view - Spell Checker: enable it for the commit dialog -- use json instead of cJSON everywhere Medium: ----- diff --git a/Tests/CodeliteTest/JsonTests.cpp b/Tests/CodeliteTest/JsonTests.cpp index 7ea58bcf59..44d256de6f 100644 --- a/Tests/CodeliteTest/JsonTests.cpp +++ b/Tests/CodeliteTest/JsonTests.cpp @@ -167,7 +167,7 @@ TEST_CASE("number json") CHECK(item.isNumber()); CHECK(!item.isArray()); CHECK(!item.isObject()); - CHECK(item.format() == "12.340000"); + CHECK(item.format() == "12.34"); CHECK(item.toBool(false) == false); CHECK(item.toBool(true) == true); @@ -245,6 +245,9 @@ TEST_CASE("object json") CHECK(item.arraySize() == 0); CHECK(!item[0].isOk()); + CHECK(item.contains("key1")); + CHECK(item.contains("key2")); + CHECK(!item.contains("key")); CHECK(item.hasNamedObject("key1")); CHECK(item.hasNamedObject("key2")); CHECK(!item.hasNamedObject("key")); @@ -267,7 +270,7 @@ TEST_CASE("array append") item.arrayAppend("world"); item.arrayAppend(wxString(L"...")); item.arrayAppend(JSONItem::createObject()); - CHECK(item.format(false) == R"([4.200000,51,"Hello","world","...",{}])"); + CHECK(item.format(false) == R"([4.2,51.0,"Hello","world","...",{}])"); CHECK(item.format(false) == json.toElement().format(false)); } @@ -292,3 +295,79 @@ TEST_CASE("object append/remove") R"({"key1":true,"key2":51,"key3":"Hello","key4":"world","key6":[],"key7":[4,8,15,16,23,42]})"); CHECK(item.format(false) == json.toElement().format(false)); } + +TEST_CASE("object addXxx") +{ + JSON json(JsonType::Object); + auto item = json.toElement(); + auto array = item.AddArray("array"); + array.arrayAppend(42); + auto& self = item.addNull("Null"); + CHECK(&self == &item); + auto object = item.AddObject("object"); + auto object2 = JSONItem::createObject(); + auto& object3 = object.addProperty("inner", object2); + CHECK(&object == &object3); + JSON moved(JsonType::Object); + moved.toElement().addProperty("a", 1); + item.addProperty("moved", std::move(moved)); + CHECK(item.format(false) == R"({"array":[42.0],"Null":null,"object":{"inner":{}},"moved":{"a":1}})"); +} + +TEST_CASE("toArrayString") +{ + wxArrayString strings{"hello", "world"}; + + JSON root(JsonType::Object); + root.toElement().addProperty("strings", strings); + + CHECK(strings == root.toElement()["strings"].toArrayString()); +} + +TEST_CASE("toIntArray") +{ + const std::vector v{4, 8, 15, 16, 23, 42}; + + JSON root(JsonType::Object); + root.toElement().addProperty("v", v); + + CHECK(v == root.toElement()["v"].toIntArray()); +} + +TEST_CASE("toDoubleArray") +{ + const std::vector v{1.1, 2.2, 3.3}; + + JSON root(JsonType::Array); + for (auto d : v) { + root.toElement().arrayAppend(d); + } + + CHECK(v == root.toElement().toDoubleArray()); +} + +TEST_CASE("toStringMap") { + const wxStringMap_t map{{"1", "one"}, {"2", "two"}}; + + JSON root(JsonType::Object); + root.toElement().addProperty("map", map); + + CHECK(map == root.toElement()["map"].toStringMap()); +} + +TEST_CASE("GetAsVector") { + JSON root("[1,2,3]"); + const auto v = root.toElement().GetAsVector(); + REQUIRE(v.size() == 3); + CHECK(1 == v[0].toInt()); + CHECK(2 == v[1].toInt()); + CHECK(3 == v[2].toInt()); +} + +TEST_CASE("GetAsMap") { + JSON root(R"({"age":42,"name":"Doe"})"); + const auto m = root.toElement().GetAsMap(); + REQUIRE(m.size() == 2); + CHECK(42 == m.at("age").toInt()); + CHECK("Doe" == m.at("name").toString()); +} diff --git a/submodules/CMakeLists.txt b/submodules/CMakeLists.txt index 365b9749fd..71cf1cfd93 100644 --- a/submodules/CMakeLists.txt +++ b/submodules/CMakeLists.txt @@ -8,12 +8,6 @@ add_subdirectory(cc-wrapper) install(TARGETS cc-wrapper DESTINATION ${CL_INSTALL_BIN}) -# ###################################################################################################################### -# cJSON -# ###################################################################################################################### -add_library(cJSON STATIC ${CMAKE_CURRENT_SOURCE_DIR}/cJSON/cJSON.c ${CMAKE_CURRENT_SOURCE_DIR}/cJSON/cJSON.h) -target_include_directories(cJSON PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/cJSON) - # ###################################################################################################################### # doctest # a library header for test framework diff --git a/submodules/cJSON b/submodules/cJSON deleted file mode 160000 index fd1ac4f179..0000000000 --- a/submodules/cJSON +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fd1ac4f1791b403af1f7350b1195ac114f9b792b