1 /* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef JSON_NODE_H 17 #define JSON_NODE_H 18 19 #include <filesystem> 20 #include <list> 21 #include <memory> 22 #include <optional> 23 #include <string> 24 #include <type_traits> 25 #include <unordered_map> 26 #include <variant> 27 #include <vector> 28 29 #include "cJSON.h" 30 #include "log/log.h" 31 #include "macros.h" 32 #include "traits_util.h" 33 34 namespace Updater { 35 class JsonNode; 36 37 enum class NodeType { OBJECT, INT, STRING, ARRAY, BOOL, NUL, UNKNOWN }; 38 39 using NodeMap = std::unordered_map<std::string, std::unique_ptr<JsonNode>>; 40 using NodeVec = std::vector<std::unique_ptr<JsonNode>>; 41 using cJSONPtr = std::unique_ptr<cJSON, decltype(&cJSON_Delete)>; 42 template<typename...T> 43 using optionalVariant = std::variant<std::optional<T> ...>; 44 45 namespace Fs = std::filesystem; 46 class JsonNode { 47 DISALLOW_COPY_MOVE(JsonNode); 48 public: 49 JsonNode(); 50 explicit JsonNode(const Fs::path &path); 51 explicit JsonNode(const std::string &str, bool needDelete = true); 52 explicit JsonNode(const cJSON *root, bool needDelete = true); 53 ~JsonNode(); 54 55 const JsonNode &operator[](int idx) const; 56 const JsonNode &operator[](const std::string &key) const; 57 JsonNode &operator[](int idx); 58 JsonNode &operator[](const std::string &key); 59 60 template<typename T> As()61 std::optional<T> As() const 62 { 63 if (auto optPtr = std::get_if<std::optional<Detail::StandardType<T>>>(&innerObj_); optPtr) { 64 return *optPtr; 65 } 66 return std::nullopt; 67 } 68 69 template<typename T> 70 bool operator==(T rhs) const 71 { 72 if (auto optPtr = std::get_if<std::optional<Detail::StandardType<T>>>(&innerObj_); optPtr) { 73 return *optPtr == rhs; 74 } 75 return false; 76 } 77 Size()78 int Size() const 79 { 80 return size_; 81 } Type()82 NodeType Type() const 83 { 84 return type_; 85 } Key()86 std::optional<std::string> Key() const 87 { 88 return key_; 89 } 90 std::list<std::reference_wrapper<JsonNode>>::const_iterator begin() const; 91 std::list<std::reference_wrapper<JsonNode>>::const_iterator end() const; 92 template<typename T> 93 void operator=(T &&rhs) 94 { 95 static_assert(Detail::G_IS_BASE_TYPE<Detail::RemoveCvRef<T>>, "only allow change int, string, bool value"); 96 if (innerObj_.valueless_by_exception()) { 97 innerObj_ = Detail::OptStandardType<T>(rhs); 98 } 99 if (auto optPtr = std::get_if<Detail::OptStandardType<T>>(&innerObj_); optPtr) { 100 *optPtr = Detail::OptStandardType<T>(rhs); 101 } else { 102 LOG(ERROR) << "assign json node failed, key is " << key_.value_or("null") << ", type is " 103 << static_cast<int>(type_) << ", rhs is " << rhs; 104 } 105 } 106 private: 107 void Parse(const cJSON *root); 108 void Init(const cJSON *root, bool needDelete); 109 int size_ {1}; 110 NodeType type_ {NodeType::UNKNOWN}; /* json node type */ 111 std::optional<std::string> key_ {std::nullopt}; /* key for object items */ 112 optionalVariant<bool, int, std::string, NodeVec, NodeMap> innerObj_ {}; 113 std::list<std::reference_wrapper<JsonNode>> innerNodesList_ {}; 114 }; 115 GetInvalidNode()116 inline JsonNode &GetInvalidNode() 117 { 118 static JsonNode emptyNode; // used for invalid json node 119 return emptyNode; 120 } 121 122 template<typename T> GetNodeByIdx(T & innerObj,int size,int idx)123 inline JsonNode &GetNodeByIdx(T &innerObj, int size, int idx) 124 { 125 auto optVec = std::get_if<std::optional<NodeVec>>(&innerObj); 126 if (optVec == nullptr || *optVec == std::nullopt) { 127 return GetInvalidNode(); // type not matched 128 } 129 auto &nodeVec = **optVec; 130 if (idx < 0 || idx >= size) { 131 return GetInvalidNode(); 132 } 133 return *nodeVec[idx]; 134 } 135 136 template<typename T> GetNodeByKey(T & innerObj,const std::string & key)137 inline JsonNode &GetNodeByKey(T &innerObj, const std::string &key) 138 { 139 auto optMap = std::get_if<std::optional<NodeMap>>(&innerObj); 140 if (optMap == nullptr || *optMap == std::nullopt) { 141 return GetInvalidNode(); // type not matched 142 } 143 auto &nodeMap = **optMap; 144 if (auto it = nodeMap.find(key); it != nodeMap.end()) { 145 return *(it->second); 146 } 147 return GetInvalidNode(); 148 } 149 } 150 #endif // NODE_H 151