implement generic method checker and is-union 05/33905/8
authorKrzysztof Dynowski <k.dynowski@samsung.com>
Tue, 13 Jan 2015 12:45:30 +0000 (13:45 +0100)
committerKrzysztof Dynowski <k.dynowski@samsung.com>
Wed, 21 Jan 2015 14:52:39 +0000 (15:52 +0100)
[Bug/Feature]       N/A
[Cause]             N/A
[Solution]          N/A
[Verification]      Build, install

Change-Id: Iaf8eb549729e095ed1d446bc6fd2cd71399e1019

src/config/from-kvjson-visitor.hpp
src/config/is-union.hpp [new file with mode: 0644]
src/config/manager.hpp

index d2c1060..e01774e 100644 (file)
@@ -1,6 +1,3 @@
-#ifndef CONFIG_FROM_KVJSON_VISITOR_HPP
-#define CONFIG_FROM_KVJSON_VISITOR_HPP
-
 /*
  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
  *
  * @brief   KVStore visitor with defaults values from json
  */
 
-#include "config/manager.hpp"
+#ifndef CONFIG_FROM_KVJSON_VISITOR_HPP
+#define CONFIG_FROM_KVJSON_VISITOR_HPP
 
+#include "config/from-kvstore-visitor.hpp"
+#include "config/is-union.hpp"
+#include <json/json.h>
 
 namespace config {
 
@@ -36,6 +37,7 @@ public:
     FromKVJsonVisitor(const std::string& db, const std::string& json, const std::string& prefix)
         : mStorePtr(new KVStore(db))
         , mKeyPrefix(prefix)
+        , mIsUnion(false)
     {
         mObject = json_tokener_parse(json.c_str());
         if (mObject == nullptr) {
@@ -43,14 +45,16 @@ public:
         }
     }
 
+
     ~FromKVJsonVisitor() {
         json_object_put(mObject);
     }
 
     FromKVJsonVisitor(const FromKVJsonVisitor& v) :
-        mObject(json_object_get(v.mObject)),
+        mObject(v.mObject ? json_object_get(v.mObject) : nullptr),
         mStorePtr(v.mStorePtr),
-        mKeyPrefix(v.mKeyPrefix)
+        mKeyPrefix(v.mKeyPrefix),
+        mIsUnion(v.mIsUnion)
     {
     }
     FromKVJsonVisitor& operator=(const FromKVJsonVisitor&) = delete;
@@ -64,49 +68,64 @@ private:
     std::shared_ptr<KVStore> mStorePtr;
     std::string mKeyPrefix;
     json_object* mObject;
+    bool mIsUnion;
 
     // create visitor for field object (visitable object)
-    FromKVJsonVisitor(const FromKVJsonVisitor& v, const std::string& name) :
-        mStorePtr(v.mStorePtr)
+    FromKVJsonVisitor(const FromKVJsonVisitor& v, const std::string& name, const bool isUnion) :
+        mStorePtr(v.mStorePtr), mIsUnion(isUnion || v.mIsUnion)
     {
-        json_object* object;
-        if (!json_object_object_get_ex(v.mObject, name.c_str(), &object)) {
-            throw ConfigException("Missing json field " + key(mKeyPrefix, name));
-        }
-        mObject = json_object_get(object);
         mKeyPrefix = key(v.mKeyPrefix, name);
+        json_object* object = nullptr;
+        if (v.mObject && !json_object_object_get_ex(v.mObject, name.c_str(), &object)) {
+            if (!mIsUnion)
+                throw ConfigException("Missing json field " + mKeyPrefix);
+        }
+        mObject = object ? json_object_get(object) : nullptr;
     }
 
     // create visitor for vector i-th element (visitable object)
-    FromKVJsonVisitor(const FromKVJsonVisitor& v, int i) :
-        mStorePtr(v.mStorePtr)
+    FromKVJsonVisitor(const FromKVJsonVisitor& v, int i, const bool isUnion) :
+        mStorePtr(v.mStorePtr), mIsUnion(isUnion || v.mIsUnion)
     {
-        json_object* object = json_object_array_get_idx(v.mObject, i);
-        checkType(object, json_type_object);
-        mObject = json_object_get(object);
         mKeyPrefix = key(v.mKeyPrefix, std::to_string(i));
+        json_object* object = nullptr;
+        if (v.mObject) {
+            object = json_object_array_get_idx(v.mObject, i);
+            checkType(object, json_type_object);
+        }
+        mObject = object ? json_object_get(object) : nullptr;
     }
 
     template<typename T, typename std::enable_if<!isVisitable<T>::value, int>::type = 0>
     void getValue(const std::string& name, T& t)
     {
-        json_object* object;
-        if (!json_object_object_get_ex(mObject, name.c_str(), &object)) {
-            throw ConfigException("Missing json field " + key(mKeyPrefix, name));
-        }
         std::string k = key(mKeyPrefix, name);
         if (mStorePtr->exists(k)) {
             t = mStorePtr->get<T>(k);
         }
         else {
+            json_object* object = nullptr;
+            if (mObject) {
+                json_object_object_get_ex(mObject, name.c_str(), &object);
+            }
+            if (!object) {
+                throw ConfigException("Missing json field " + key(mKeyPrefix, name));
+            }
             fromJsonObject(object, t);
         }
     }
 
-    template<typename T, typename std::enable_if<isVisitable<T>::value, int>::type = 0>
+    template<typename T, typename std::enable_if<isUnion<T>::value, int>::type = 0>
+    void getValue(const std::string& name, T& t)
+    {
+        FromKVJsonVisitor visitor(*this, name, true);
+        t.accept(visitor);
+    }
+
+    template<typename T, typename std::enable_if<isVisitable<T>::value && !isUnion<T>::value, int>::type = 0>
     void getValue(const std::string& name, T& t)
     {
-        FromKVJsonVisitor visitor(*this, name);
+        FromKVJsonVisitor visitor(*this, name, false);
         t.accept(visitor);
     }
 
@@ -115,22 +134,27 @@ private:
         if (mStorePtr->exists(name)) {
             return mStorePtr->get<int>(name);
         }
-        return json_object_array_length(object);
+        if (object) {
+            return json_object_array_length(object);
+        }
+        return -1;
     }
 
     template<typename T>
     void getValue(const std::string& name, std::vector<T>& value)
     {
-        json_object* object;
-        if (!json_object_object_get_ex(mObject, name.c_str(), &object)) {
-            throw ConfigException("Missing json field " + key(mKeyPrefix, name));
+        json_object* object = nullptr;
+        if (mObject && json_object_object_get_ex(mObject, name.c_str(), &object)) {
+            checkType(object, json_type_array);
         }
-        checkType(object, json_type_array);
 
         std::string k = key(mKeyPrefix, name);
         int length = getArraySize(k, object);
+        if (length < 0) {
+            throw ConfigException("Missing json field " + key(mKeyPrefix, name));
+        }
         value.resize(static_cast<size_t>(length));
-        FromKVJsonVisitor visitor(*this, name);
+        FromKVJsonVisitor visitor(*this, name, false);
         for (int i = 0; i < length; ++i) {
             visitor.getValue(i, value[i]);
         }
@@ -139,20 +163,30 @@ private:
     template<typename T, typename std::enable_if<!isVisitable<T>::value, int>::type = 0>
     void getValue(int i, T& t)
     {
-        json_object* object = json_object_array_get_idx(mObject, i);
         std::string k = key(mKeyPrefix, std::to_string(i));
         if (mStorePtr->exists(k)) {
             t = mStorePtr->get<T>(k);
         }
         else {
+            json_object* object = mObject ? json_object_array_get_idx(mObject, i) : nullptr;
+            if (!object) {
+                throw ConfigException("Missing json array elem " + k);
+            }
             fromJsonObject(object, t);
         }
     }
 
-    template<typename T, typename std::enable_if<isVisitable<T>::value, int>::type = 0>
+    template<typename T, typename std::enable_if<isUnion<T>::value, int>::type = 0>
+    void getValue(int i, T& t)
+    {
+        FromKVJsonVisitor visitor(*this, i, true);
+        t.accept(visitor);
+    }
+
+    template<typename T, typename std::enable_if<isVisitable<T>::value && !isUnion<T>::value, int>::type = 0>
     void getValue(int i, T& t)
     {
-        FromKVJsonVisitor visitor(*this, i);
+        FromKVJsonVisitor visitor(*this, i, false);
         t.accept(visitor);
     }
 
@@ -162,7 +196,7 @@ private:
         std::string k = key(mKeyPrefix, std::to_string(i));
         int length = getArraySize(k, mObject);
         value.resize(static_cast<size_t>(length));
-        FromKVJsonVisitor visitor(*this, i);
+        FromKVJsonVisitor visitor(*this, i, false);
         for (int i = 0; i < length; ++i) {
             visitor.getValue(i, value[i]);
         }
diff --git a/src/config/is-union.hpp b/src/config/is-union.hpp
new file mode 100644 (file)
index 0000000..f696b72
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Krzysztof Dynowski (k.dynowski@samsumg.com)
+ * @brief   Internal configuration helper
+ */
+
+#ifndef CONFIG_IS_UNION_HPP
+#define CONFIG_IS_UNION_HPP
+
+#include "config/is-visitable.hpp"
+
+namespace config {
+
+// generic member checker, start
+template <typename T, typename F>
+struct has_member_impl {
+    template <typename C>
+    static std::true_type check(typename F::template checker__<C>* =0);
+
+    template <typename C>
+    static std::false_type check(...);
+
+    static const bool value = std::is_same<decltype(check<T>(0)), std::true_type>::value;
+};
+
+template <typename T, typename F>
+struct has_member : public std::integral_constant<bool, has_member_impl<T, F>::value> {};
+// generic member checker, end
+
+
+template <typename X>
+struct check_union : isVisitable<X> {
+    template <typename T,
+         //list of function union must implement
+         const X& (T::*)() const = &T::as,
+         X& (T::*)(const X& src) = &T::set,
+         bool (T::*)() = &T::isSet
+    >
+    struct checker__ {};
+};
+template<typename T>
+struct isUnion : has_member<T, check_union<T>> {};
+
+//Note:
+// unfortunately, above generic has_member can't be used for isVisitable
+// because Vistable need 'accept' OR 'accept const', while has_member make exect match
+// e.g accept AND accept const
+
+} // namespace config
+
+#endif // CONFIG_FROM_KVJSON_VISITOR_HPP
+
index 0785094..7c50087 100644 (file)
@@ -32,7 +32,6 @@
 #include "config/from-kvstore-visitor.hpp"
 #include "config/from-fdstore-visitor.hpp"
 #include "config/from-kvjson-visitor.hpp"
-#include "config/is-visitable.hpp"
 #include "config/fs-utils.hpp"