ConfigException(const std::string& error) : std::runtime_error(error) {}
};
+/**
+ * No such key in the config error.
+ */
+struct NoKeyException: public ConfigException {
+
+ NoKeyException(const std::string& error) : ConfigException(error) {}
+};
+
+/**
+ * Container size does not match the config.
+ */
+struct ContainerSizeException: public ConfigException {
+
+ ContainerSizeException(const std::string& error): ConfigException(error) {}
+};
+
} // namespace config
#endif // COMMON_CONFIG_EXCEPTION_HPP
+++ /dev/null
-/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Contact: Krzysztof Dynowski (k.dynowski@samsumg.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 KVStore visitor with defaults values from json
- */
-
-#ifndef COMMON_CONFIG_FROM_KVJSON_VISITOR_HPP
-#define COMMON_CONFIG_FROM_KVJSON_VISITOR_HPP
-
-#include "config/from-kvstore-visitor.hpp"
-#include "config/is-union.hpp"
-#include "config/visit-fields.hpp"
-
-#include <utility>
-#include <json.h>
-
-namespace config {
-
-class FromKVJsonVisitor {
-public:
- FromKVJsonVisitor(KVStore& store, const std::string& json, const std::string& prefix)
- : mStore(store)
- , mKeyPrefix(prefix)
- , mIsUnion(false)
- {
- mObject = json_tokener_parse(json.c_str());
- if (mObject == nullptr) {
- throw ConfigException("Json parsing error");
- }
- }
-
-
- ~FromKVJsonVisitor() {
- json_object_put(mObject);
- }
-
- FromKVJsonVisitor(const FromKVJsonVisitor& v) :
- mStore(v.mStore),
- mKeyPrefix(v.mKeyPrefix),
- mObject(v.mObject ? json_object_get(v.mObject) : nullptr),
- mIsUnion(v.mIsUnion)
- {
- }
- FromKVJsonVisitor& operator=(const FromKVJsonVisitor&) = delete;
-
- template<typename T>
- void visit(const std::string& name, T& value) {
- getValue(name, value);
- }
-
- template<typename T>
- void visit(std::size_t& idx, T& value) {
- getValue(idx, value);
- idx += 1;
- }
-
-private:
- KVStore& mStore;
- std::string mKeyPrefix;
- json_object* mObject;
- bool mIsUnion;
-
- // create visitor for field object (visitable object)
- FromKVJsonVisitor(const FromKVJsonVisitor& v, const std::string& name, const bool isUnion) :
- mStore(v.mStore),
- mKeyPrefix(key(v.mKeyPrefix, name)),
- mIsUnion(isUnion || v.mIsUnion)
- {
- 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, const bool isUnion) :
- mStore(v.mStore),
- mKeyPrefix(key(v.mKeyPrefix, std::to_string(i))),
- mIsUnion(isUnion || v.mIsUnion)
- {
- 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<std::is_enum<T>::value, int>::type = 0>
- void getValue(const std::string& name, T& t)
- {
- getValue(name,
- *reinterpret_cast<typename std::underlying_type<T>::type*>(&t));
- }
-
- template<typename T,
- typename std::enable_if<!isVisitable<T>::value &&
- !std::is_enum<T>::value, int>::type = 0>
- void getValue(const std::string& name, T& t)
- {
- std::string k = key(mKeyPrefix, name);
- if (mStore.exists(k)) {
- t = mStore.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 " + k);
- }
- fromJsonObject(object, t);
- }
- }
-
- 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, false);
- t.accept(visitor);
- }
-
- int getArraySize(std::string& name, json_object* object)
- {
- if (mStore.exists(name)) {
- return mStore.get<int>(name);
- }
- 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 = nullptr;
- if (mObject && json_object_object_get_ex(mObject, name.c_str(), &object)) {
- checkType(object, json_type_array);
- }
-
- std::string k = key(mKeyPrefix, name);
- int length = getArraySize(k, object);
- if (length < 0) {
- throw ConfigException("Missing array length " + k);
- }
- value.resize(static_cast<size_t>(length));
- FromKVJsonVisitor visitor(*this, name, false);
- if (mStore.exists(k)) {
- json_object_put(visitor.mObject);
- visitor.mObject = nullptr;
- }
- for (int i = 0; i < length; ++i) {
- visitor.getValue(i, value[i]);
- }
- }
-
- template<typename T, std::size_t N>
- void getValue(const std::string& name, std::array<T, N>& values)
- {
- json_object* object = nullptr;
- if (mObject && json_object_object_get_ex(mObject, name.c_str(), &object)) {
- checkType(object, json_type_array);
- }
-
- std::string k = key(mKeyPrefix, name);
- FromKVJsonVisitor visitor(*this, name, false);
- if (mStore.exists(k)) {
- json_object_put(visitor.mObject);
- visitor.mObject = nullptr;
- }
- for (std::size_t i = 0; i < N; ++i) {
- visitor.getValue(i, values[i]);
- }
- }
-
- template<typename ... T>
- void getValue(const std::string& name, std::pair<T...>& values)
- {
- json_object* object = nullptr;
- if (mObject && json_object_object_get_ex(mObject, name.c_str(), &object)) {
- checkType(object, json_type_array);
- }
-
- std::string k = key(mKeyPrefix, name);
- FromKVJsonVisitor visitor(*this, name, false);
- if (mStore.exists(k)) {
- json_object_put(visitor.mObject);
- visitor.mObject = nullptr;
- }
-
- std::size_t idx = 0;
- visitFields(values, &visitor, idx);
- }
-
- template<typename T, typename std::enable_if<!isVisitable<T>::value, int>::type = 0>
- void getValue(int i, T& t)
- {
- std::string k = key(mKeyPrefix, std::to_string(i));
- if (mStore.exists(k)) {
- t = mStore.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<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, false);
- t.accept(visitor);
- }
-
- template<typename T>
- void getValue(int i, std::vector<T>& value)
- {
- 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, false);
- if (mStore.exists(k)) {
- json_object_put(visitor.mObject);
- visitor.mObject = nullptr;
- }
- for (int idx = 0; idx < length; ++idx) {
- visitor.getValue(idx, value[idx]);
- }
- }
-
- template<typename T, std::size_t N>
- void getValue(int i, std::array<T, N>& values)
- {
- std::string k = key(mKeyPrefix, std::to_string(i));
-
- FromKVJsonVisitor visitor(*this, i, false);
- if (mStore.exists(k)) {
- json_object_put(visitor.mObject);
- visitor.mObject = nullptr;
- }
- for (std::size_t idx = 0; idx < N; ++idx) {
- visitor.getValue(idx, values[idx]);
- }
- }
-
- static void checkType(json_object* object, json_type type)
- {
- if (type != json_object_get_type(object)) {
- throw ConfigException("Invalid field type " + std::to_string(type));
- }
- }
-
- static void fromJsonObject(json_object* object, int& value)
- {
- checkType(object, json_type_int);
- std::int64_t value64 = json_object_get_int64(object);
- if (value64 > INT32_MAX || value64 < INT32_MIN) {
- throw ConfigException("Value out of range");
- }
- value = static_cast<int>(value64);
- }
-
- static void fromJsonObject(json_object* object, std::int64_t& value)
- {
- checkType(object, json_type_int);
- value = json_object_get_int64(object);
- }
-
- static void fromJsonObject(json_object* object, std::uint32_t& value)
- {
- checkType(object, json_type_int);
- std::int64_t value64 = json_object_get_int64(object);
- if (value64 > UINT32_MAX || value64 < 0) {
- throw ConfigException("Value out of range");
- }
- value = static_cast<std::uint32_t>(value64);
- }
-
- static void fromJsonObject(json_object* object, std::uint64_t& value)
- {
- checkType(object, json_type_int);
- std::int64_t value64 = json_object_get_int64(object);
- if (value64 < 0) {
- throw ConfigException("Value out of range");
- }
- value = static_cast<std::uint64_t>(value64);
- }
-
- static void fromJsonObject(json_object* object, bool& value)
- {
- checkType(object, json_type_boolean);
- value = json_object_get_boolean(object);
- }
-
- static void fromJsonObject(json_object* object, double& value)
- {
- checkType(object, json_type_double);
- value = json_object_get_double(object);
- }
-
- static void fromJsonObject(json_object* object, std::string& value)
- {
- checkType(object, json_type_string);
- value = json_object_get_string(object);
- }
-
- static void fromJsonObject(json_object* object, char* &value)
- {
- checkType(object, json_type_string);
-
- int len = json_object_get_string_len(object);
- value = new char[len + 1];
- std::strncpy(value, json_object_get_string(object), len);
- value[len] = '\0';
- }
-};
-
-} // namespace config
-
-#endif // COMMON_CONFIG_FROM_KVJSON_VISITOR_HPP
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Pawel Kubik (p.kubik@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 Pawel Kubik (p.kubik@samsung.com)
+ * @brief Visitor for loading from KVStore that doesn't fail on missing values
+ */
+
+#ifndef COMMON_CONFIG_FROM_KVSTORE_IGNORING_VISITOR_HPP
+#define COMMON_CONFIG_FROM_KVSTORE_IGNORING_VISITOR_HPP
+
+#include "config/from-kvstore-visitor.hpp"
+
+
+namespace config {
+
+/**
+ * A variant of KVStoreVisitor that ignore non-existing fields.
+ *
+ * Allows to partially update visited structures with fields that exist in the KVStore.
+ */
+class FromKVStoreIgnoringVisitor : public FromKVStoreVisitorBase<FromKVStoreIgnoringVisitor> {
+public:
+ FromKVStoreIgnoringVisitor(KVStore& store, const std::string& prefix)
+ : FromKVStoreVisitorBase<FromKVStoreIgnoringVisitor>(store, prefix)
+ {
+ }
+
+ FromKVStoreIgnoringVisitor(const FromKVStoreVisitorBase<FromKVStoreIgnoringVisitor>& visitor,
+ const std::string& prefix)
+ : FromKVStoreVisitorBase<FromKVStoreIgnoringVisitor>(visitor, prefix)
+ {
+ }
+
+ FromKVStoreVisitor& operator=(const FromKVStoreVisitor&) = delete;
+
+protected:
+ template<typename T>
+ void visitImpl(const std::string& name, T& value)
+ {
+ try {
+ getInternal(name, value);
+ } catch (const NoKeyException& e) {
+ } catch (const ContainerSizeException& e) {
+ }
+ }
+
+private:
+ FromKVStoreIgnoringVisitor(const FromKVStoreIgnoringVisitor& visitor,
+ const std::string& prefix)
+ : FromKVStoreVisitorBase<FromKVStoreIgnoringVisitor>(visitor.mStore, prefix)
+ {
+ }
+
+ template<typename T,
+ typename std::enable_if<isUnion<T>::value, int>::type = 0>
+ void getInternal(const std::string& name, T& value)
+ {
+ std::string type;
+ getInternal(key(name, "type"), type);
+ if (type.empty()) {
+ return;
+ }
+
+ FromKVStoreIgnoringVisitor visitor(*this, name);
+ value.accept(visitor);
+ }
+
+ template<typename T,
+ typename std::enable_if<!isUnion<T>::value, int>::type = 0>
+ void getInternal(const std::string& name, T& value)
+ {
+ FromKVStoreVisitorBase<FromKVStoreIgnoringVisitor>::visitImpl(name, value);
+ }
+
+ friend class FromKVStoreVisitorBase;
+};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_FROM_KVSTORE_IGNORING_VISITOR_HPP
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Pawel Kubik (p.kubik@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 Pawel Kubik (p.kubik@samsung.com)
+ * @brief Base of visitors for loading from KVStore
+ */
+
+#ifndef COMMON_CONFIG_FROM_KVSTORE_VISITOR_BASE_HPP
+#define COMMON_CONFIG_FROM_KVSTORE_VISITOR_BASE_HPP
+
+#include "config/is-visitable.hpp"
+#include "config/kvstore.hpp"
+#include "config/kvstore-visitor-utils.hpp"
+#include "config/visit-fields.hpp"
+
+
+namespace config {
+
+/**
+ * Base class for KVStore visitors.
+ *
+ * A curiously recurring template pattern example. This
+ * base-class provides a set of recursively called function templates. A child class can
+ * modify the base class behaviour in certain cases by defining:
+ * - a set of functions that match those cases
+ * - a template function that match any other case and calls the base class function
+ */
+template<typename RecursiveVisitor>
+class FromKVStoreVisitorBase {
+public:
+ FromKVStoreVisitorBase& operator=(const FromKVStoreVisitorBase&) = delete;
+
+ template<typename T>
+ void visit(const std::string& name, T& value)
+ {
+ static_cast<RecursiveVisitor*>(this)->visitImpl(key(mKeyPrefix, name), value);
+ }
+
+protected:
+ KVStore& mStore;
+ std::string mKeyPrefix;
+
+ template<typename T>
+ void visitImpl(const std::string& name, T& value)
+ {
+ getInternal(name, value);
+ }
+
+ FromKVStoreVisitorBase(KVStore& store, const std::string& prefix)
+ : mStore(store),
+ mKeyPrefix(prefix)
+ {
+ }
+
+ FromKVStoreVisitorBase(const FromKVStoreVisitorBase& visitor,
+ const std::string& prefix)
+ : mStore(visitor.mStore),
+ mKeyPrefix(prefix)
+ {
+ }
+
+private:
+ template<typename T,
+ typename std::enable_if<!isVisitable<T>::value
+ && !std::is_enum<T>::value, int>::type = 0>
+ void getInternal(const std::string& name, T& value)
+ {
+ value = fromString<T>(mStore.get(name));
+ }
+
+ template<typename T, typename std::enable_if<isVisitable<T>::value, int>::type = 0>
+ void getInternal(const std::string& name, T& value)
+ {
+ RecursiveVisitor visitor(*this, name);
+ value.accept(visitor);
+ }
+
+ template<typename T,
+ typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
+ void getInternal(const std::string& name, T& value)
+ {
+ auto rawValue = static_cast<typename std::underlying_type<T>::type>(value);
+ static_cast<RecursiveVisitor*>(this)->visitImpl(name, rawValue);
+ value = static_cast<T>(rawValue);
+ }
+
+ template<typename T>
+ void getInternal(const std::string& name, std::vector<T>& values)
+ {
+ size_t storedSize = 0;
+ getInternal(name, storedSize);
+
+ if (storedSize == 0) {
+ return;
+ }
+
+ values.resize(storedSize);
+ for (size_t i = 0; i < storedSize; ++i) {
+ const std::string k = key(name, std::to_string(i));
+ if (!mStore.prefixExists(k)) {
+ throw ConfigException("Corrupted list serialization.");
+ }
+ static_cast<RecursiveVisitor*>(this)->visitImpl(k, values[i]);
+ }
+ }
+
+ template<typename T, size_t N>
+ void getInternal(const std::string& name, std::array<T, N>& values)
+ {
+ size_t storedSize = 0;
+ getInternal(name, storedSize);
+
+ if (storedSize != values.size()) {
+ throw ContainerSizeException("Size of stored array doesn't match provided one.");
+ }
+
+ for (size_t i = 0; i < storedSize; ++i) {
+ const std::string k = key(name, std::to_string(i));
+ if (!mStore.prefixExists(k)) {
+ throw ConfigException("Corrupted list serialization.");
+ }
+ static_cast<RecursiveVisitor*>(this)->visitImpl(k, values[i]);
+ }
+ }
+
+ template<typename ... T>
+ void getInternal(const std::string& key, std::pair<T...>& values)
+ {
+ std::vector<std::string> strValues;
+
+ getInternal(key, strValues);
+ if (strValues.empty()) {
+ return;
+ }
+
+ if (strValues.size() != sizeof...(T)) {
+ throw ContainerSizeException("Size of stored tuple doesn't match provided one.");
+ }
+
+ GetTupleVisitor visitor;
+ visitFields(values, &visitor, strValues.begin());
+ }
+};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_FROM_KVSTORE_VISITOR_BASE_HPP
/*
* Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
*
- * Contact: Jan Olszak (j.olszak@samsung.com)
+ * Contact: Pawel Kubik (p.kubik@samsung.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/**
* @file
- * @author Jan Olszak (j.olszak@samsung.com)
- * @brief Visitor for loading from KVStore
+ * @author Pawel Kubik (p.kubik@samsung.com)
+ * @brief Default visitor for loading from KVStore
*/
#ifndef COMMON_CONFIG_FROM_KVSTORE_VISITOR_HPP
#define COMMON_CONFIG_FROM_KVSTORE_VISITOR_HPP
-#include "config/is-visitable.hpp"
-#include "config/kvstore.hpp"
+#include "config/from-kvstore-visitor-base.hpp"
+
namespace config {
-class FromKVStoreVisitor {
+/**
+ * Default KVStore visitor.
+ */
+class FromKVStoreVisitor : public FromKVStoreVisitorBase<FromKVStoreVisitor> {
public:
FromKVStoreVisitor(KVStore& store, const std::string& prefix)
- : mStore(store),
- mKeyPrefix(prefix)
- {
- }
-
- FromKVStoreVisitor& operator=(const FromKVStoreVisitor&) = delete;
-
- template<typename T>
- void visit(const std::string& name, T& value)
+ : FromKVStoreVisitorBase<FromKVStoreVisitor>(store, prefix)
{
- getInternal(key(mKeyPrefix, name), value);
}
-private:
- KVStore& mStore;
- std::string mKeyPrefix;
-
- FromKVStoreVisitor(const FromKVStoreVisitor& visitor, const std::string& prefix)
- : mStore(visitor.mStore),
- mKeyPrefix(prefix)
+ FromKVStoreVisitor(const FromKVStoreVisitorBase<FromKVStoreVisitor>& visitor,
+ const std::string& prefix)
+ : FromKVStoreVisitorBase<FromKVStoreVisitor>(visitor, prefix)
{
}
-
- template<typename T, typename std::enable_if<!isVisitable<T>::value, int>::type = 0>
- void getInternal(const std::string& name, T& value)
- {
- value = mStore.get<T>(name);
- }
-
- template<typename T, typename std::enable_if<isVisitable<T>::value, int>::type = 0>
- void getInternal(const std::string& name, T& value)
- {
- FromKVStoreVisitor visitor(*this, name);
- value.accept(visitor);
- }
-
- template<typename T, typename std::enable_if<isVisitable<T>::value, int>::type = 0>
- void getInternal(const std::string& name, std::vector<T>& values)
- {
- values.clear();
-
- size_t vectorSize = mStore.get<size_t>(name);
- if (vectorSize == 0) {
- return;
- }
-
- values.resize(vectorSize);
- for (size_t i = 0; i < vectorSize; ++i) {
- const std::string k = key(name, std::to_string(i));
- getInternal(k, values[i]);
- }
- }
};
} // namespace config
--- /dev/null
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact: Pawel Kubik (p.kubik@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 Pawel Kubik (p.kubik@samsung.com)
+ * @brief KVStore visitors utilities
+ */
+
+#ifndef COMMON_CONFIG_KVSTORE_VISITOR_UTILS_HPP
+#define COMMON_CONFIG_KVSTORE_VISITOR_UTILS_HPP
+
+namespace config {
+
+template<typename T>
+T fromString(const std::string& strValue)
+{
+ std::istringstream iss(strValue);
+ T value;
+ iss >> value;
+ return value;
+}
+
+template<typename T>
+std::string toString(const T& value)
+{
+ std::ostringstream oss;
+ oss << value;
+ return oss.str();
+}
+
+/**
+ * Concatenates all parameters into one std::string.
+ * Uses '.' to connect the terms.
+ * @param args components of the string
+ * @tparam delim optional delimiter
+ * @tparam Args any type implementing str
+ * @return string created from he args
+ */
+template<char delim = '.', typename Arg1, typename ... Args>
+std::string key(const Arg1& a1, const Args& ... args)
+{
+ std::string ret = toString(a1);
+ std::initializer_list<std::string> strings {toString(args)...};
+ for (const std::string& s : strings) {
+ ret += delim + s;
+ }
+
+ return ret;
+}
+
+/**
+ * Function added for key function completeness.
+ *
+ * @tparam delim = '.' parameter not used, added for consistency
+ * @return empty string
+ */
+template<char delim = '.'>
+std::string key()
+{
+ return std::string();
+}
+
+struct GetTupleVisitor
+{
+ template<typename T>
+ static void visit(std::vector<std::string>::iterator& it, T& value)
+ {
+ if (!it->empty()) {
+ value = fromString<T>(*it);
+ }
+ ++it;
+ }
+};
+
+struct SetTupleVisitor
+{
+ template<typename T>
+ static void visit(std::vector<std::string>::iterator& it, const T& value)
+ {
+ *it = toString<T>(value);
+ ++it;
+ }
+};
+
+} // namespace config
+
+#endif // COMMON_CONFIG_KVSTORE_VISITOR_UTILS_HPP
assert(mTransactionDepth == 0);
}
+void KVStore::set(const std::string& key, const std::string& value)
+{
+ Transaction transaction(*this);
+ ScopedReset scopedReset(mSetValueStmt);
+
+ ::sqlite3_bind_text(mSetValueStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_STATIC);
+ ::sqlite3_bind_text(mSetValueStmt->get(), 2, value.c_str(), AUTO_DETERM_SIZE, SQLITE_STATIC);
+
+
+ if (::sqlite3_step(mSetValueStmt->get()) != SQLITE_DONE) {
+ throw ConfigException("Error during stepping: " + mConn.getErrorMessage());
+ }
+ transaction.commit();
+}
+
+std::string KVStore::get(const std::string& key)
+{
+ Transaction transaction(*this);
+ ScopedReset scopedReset(mGetValueStmt);
+
+ ::sqlite3_bind_text(mGetValueStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_TRANSIENT);
+
+ int ret = ::sqlite3_step(mGetValueStmt->get());
+ if (ret == SQLITE_DONE) {
+ throw NoKeyException("No value corresponding to the key: " + key + "@" + mPath);
+ }
+ if (ret != SQLITE_ROW) {
+ throw ConfigException("Error during stepping: " + mConn.getErrorMessage());
+ }
+
+ std::string value = reinterpret_cast<const char*>(
+ sqlite3_column_text(mGetValueStmt->get(), FIRST_COLUMN));
+
+ transaction.commit();
+ return value;
+}
+
void KVStore::setupDb()
{
// called only from ctor, transaction is not needed
mGetValueStmt.reset(
new sqlite3::Statement(mConn, "SELECT value FROM data WHERE key = ? LIMIT 1"));
mGetKeyExistsStmt.reset(
- // following line left in comment to have example of any subkey matching
- //new sqlite3::Statement(mConn, "SELECT 1 FROM data WHERE key = ?1 OR key GLOB escapeStr(?1) || '.*' LIMIT 1"));
- new sqlite3::Statement(mConn, "SELECT 1 FROM data WHERE key = ?1 LIMIT 1"));
+ new sqlite3::Statement(mConn, "SELECT 1 FROM data WHERE key = ?1 LIMIT 1"));
+ mGetKeyPrefixExistsStmt.reset(
+ new sqlite3::Statement(mConn, "SELECT 1 FROM data WHERE key = ?1 OR key GLOB escapeStr(?1) || '.*' LIMIT 1"));
mGetIsEmptyStmt.reset(
new sqlite3::Statement(mConn, "SELECT 1 FROM data LIMIT 1"));
mSetValueStmt.reset(
return ret == SQLITE_ROW;
}
-void KVStore::remove(const std::string& key)
-{
- Transaction transaction(*this);
- ScopedReset scopedReset(mRemoveValuesStmt);
-
- ::sqlite3_bind_text(mRemoveValuesStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_STATIC);
-
- if (::sqlite3_step(mRemoveValuesStmt->get()) != SQLITE_DONE) {
- throw ConfigException("Error during stepping: " + mConn.getErrorMessage());
- }
- transaction.commit();
-}
-
-void KVStore::setInternal(const std::string& key, const char* value)
-{
- Transaction transaction(*this);
- ScopedReset scopedReset(mSetValueStmt);
-
- ::sqlite3_bind_text(mSetValueStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_STATIC);
- ::sqlite3_bind_text(mSetValueStmt->get(), 2, value, AUTO_DETERM_SIZE, SQLITE_STATIC);
-
-
- if (::sqlite3_step(mSetValueStmt->get()) != SQLITE_DONE) {
- throw ConfigException("Error during stepping: " + mConn.getErrorMessage());
- }
- transaction.commit();
-}
-
-void KVStore::setInternal(const std::string& key, const std::string& value)
-{
- setInternal(key, value.c_str());
-}
-
-void KVStore::setInternal(const std::string& key, const std::initializer_list<std::string>& values)
-{
- setInternal(key, std::vector<std::string>(values));
-}
-
-void KVStore::setInternal(const std::string& key, const std::vector<std::string>& values)
+bool KVStore::prefixExists(const std::string& key)
{
- if (values.size() > std::numeric_limits<unsigned int>::max()) {
- throw ConfigException("Too many values to insert");
- }
-
Transaction transaction(*this);
+ ScopedReset scopedReset(mGetKeyPrefixExistsStmt);
- remove(key);
-
- // Save vector's capacity
- setInternal(key, values.size());
-
- // Save vector's elements
- for (unsigned int i = 0; i < values.size(); ++i) {
- setInternal(config::key(key, std::to_string(i)),
- values[i]);
- }
- transaction.commit();
-}
+ ::sqlite3_bind_text(mGetKeyPrefixExistsStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_TRANSIENT);
-std::string KVStore::getInternal(const std::string& key, std::string*)
-{
- Transaction transaction(*this);
- ScopedReset scopedReset(mGetValueStmt);
-
- ::sqlite3_bind_text(mGetValueStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_TRANSIENT);
-
- int ret = ::sqlite3_step(mGetValueStmt->get());
- if (ret == SQLITE_DONE) {
- throw ConfigException("No value corresponding to the key: " + key + "@" + mPath);
- }
- if (ret != SQLITE_ROW) {
+ int ret = ::sqlite3_step(mGetKeyPrefixExistsStmt->get());
+ if (ret != SQLITE_DONE && ret != SQLITE_ROW) {
throw ConfigException("Error during stepping: " + mConn.getErrorMessage());
}
- std::string value = reinterpret_cast<const char*>(
- sqlite3_column_text(mGetValueStmt->get(), FIRST_COLUMN));
-
transaction.commit();
- return value;
+ return ret == SQLITE_ROW;
}
-char* KVStore::getInternal(const std::string& key, char**)
+void KVStore::remove(const std::string& key)
{
Transaction transaction(*this);
- ScopedReset scopedReset(mGetValueStmt);
+ ScopedReset scopedReset(mRemoveValuesStmt);
- ::sqlite3_bind_text(mGetValueStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_TRANSIENT);
+ ::sqlite3_bind_text(mRemoveValuesStmt->get(), 1, key.c_str(), AUTO_DETERM_SIZE, SQLITE_STATIC);
- int ret = ::sqlite3_step(mGetValueStmt->get());
- if (ret == SQLITE_DONE) {
- throw ConfigException("No value corresponding to the key: " + key + "@" + mPath);
- }
- if (ret != SQLITE_ROW) {
+ if (::sqlite3_step(mRemoveValuesStmt->get()) != SQLITE_DONE) {
throw ConfigException("Error during stepping: " + mConn.getErrorMessage());
}
-
- const char* source = reinterpret_cast<const char*>(sqlite3_column_text(mGetValueStmt->get(), FIRST_COLUMN));
-
- size_t length = std::strlen(source);
- char* value = new char[length + 1];
-
- std::strncpy(value, source, length);
- value[length] = '\0';
-
- transaction.commit();
- return value;
-}
-
-std::vector<std::string> KVStore::getInternal(const std::string& key, std::vector<std::string>*)
-{
- Transaction transaction(*this);
-
- unsigned int valuesSize = get<unsigned int>(key);
- std::vector<std::string> values(valuesSize);
- if (valuesSize == 0) {
- transaction.commit();
- return values;
- }
-
- for (unsigned int i = 0; i < values.size(); ++i) {
- values[i] = getInternal(config::key(key, std::to_string(i)),
- static_cast<std::string*>(nullptr));
-
- }
-
transaction.commit();
- return values;
}
std::vector<std::string> KVStore::getKeys()
#include "config/sqlite3/connection.hpp"
#include "config/sqlite3/statement.hpp"
-#include "config/visit-fields.hpp"
#include <algorithm>
#include <initializer_list>
bool isEmpty();
/**
- * @param key string regexp of the stored values
+ * @param key string of the stored value
*
* @return Does this key exist in the database
*/
bool exists(const std::string& key);
/**
+ * @param key string of the stored value
+ *
+ * @return Does a key starting with an argument exist in the database
+ */
+ bool prefixExists(const std::string& key);
+
+ /**
* Removes values corresponding to the passed key.
* Many values may correspond to one key, so many values may
* need to be deleted
* @param key string key of the value
* @param value value corresponding to the key
*/
- template<typename T>
- void set(const std::string& key, const T& value)
- {
- return setInternal(key, value);
- }
+ void set(const std::string& key, const std::string& value);
/**
* Gets the value corresponding to the key.
- * Uses stringstreams to parse.
*
* @param key string key of the value
- * @tparam T = std::string desired type of the return value
* @return value corresponding to the key
*/
- template<typename T = std::string>
- T get(const std::string& key)
- {
- return getInternal(key, static_cast<T*>(nullptr));
- }
+ std::string get(const std::string& key);
/**
* Returns all stored keys.
size_t mTransactionDepth;
bool mIsTransactionCommited;
- void setInternal(const std::string& key, const std::string& value);
- void setInternal(const std::string& key, const char* value);
- void setInternal(const std::string& key, const std::initializer_list<std::string>& values);
- void setInternal(const std::string& key, const std::vector<std::string>& values);
- template<typename T, typename std::enable_if<!std::is_enum<T>::value, int>::type = 0>
- void setInternal(const std::string& key, const T& value);
- template<typename T, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
- void setInternal(const std::string& key, const T& value);
- template<typename T>
- void setInternal(const std::string& key, const std::vector<T>& values);
- template<typename T, std::size_t N>
- void setInternal(const std::string& key, const std::array<T, N>& values);
- template<typename ... T>
- void setInternal(const std::string& key, const std::pair<T...>& values);
-
- std::string getInternal(const std::string& key, std::string*);
- char* getInternal(const std::string& key, char**);
- std::vector<std::string> getInternal(const std::string& key, std::vector<std::string>*);
- template<typename T, typename std::enable_if<!std::is_enum<T>::value, int>::type = 0>
- T getInternal(const std::string& key, T*);
- template<typename T, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
- T getInternal(const std::string& key, T*);
- template<typename T>
- std::vector<T> getInternal(const std::string& key, std::vector<T>*);
- template<typename T, std::size_t N>
- std::array<T, N> getInternal(const std::string& key, std::array<T, N>*);
- template<typename ... T>
- std::pair<T...> getInternal(const std::string& key, std::pair<T...>*);
-
std::string mPath;
sqlite3::Connection mConn;
std::unique_ptr<sqlite3::Statement> mGetValueStmt;
std::unique_ptr<sqlite3::Statement> mGetKeyExistsStmt;
+ std::unique_ptr<sqlite3::Statement> mGetKeyPrefixExistsStmt;
std::unique_ptr<sqlite3::Statement> mGetIsEmptyStmt;
std::unique_ptr<sqlite3::Statement> mGetValueListStmt;
std::unique_ptr<sqlite3::Statement> mSetValueStmt;
void createFunctions();
};
-namespace {
-template<typename T>
-std::string toString(const T& value)
-{
- std::ostringstream oss;
- oss << value;
- return oss.str();
-}
-
-template<typename T>
-T fromString(const std::string& strValue)
-{
- std::istringstream iss(strValue);
- T value;
- iss >> value;
- return value;
-}
-
-} // namespace
-
-template<typename T, typename std::enable_if<!std::is_enum<T>::value, int>::type>
-void KVStore::setInternal(const std::string& key, const T& value)
-{
- setInternal(key, toString(value));
-}
-
-template<typename T, typename std::enable_if<std::is_enum<T>::value, int>::type>
-void KVStore::setInternal(const std::string& key, const T& value)
-{
- setInternal(key,
- static_cast<const typename std::underlying_type<T>::type>(value));
-}
-
-template<typename T>
-void KVStore::setInternal(const std::string& key, const std::vector<T>& values)
-{
- std::vector<std::string> strValues(values.size());
-
- std::transform(values.begin(),
- values.end(),
- strValues.begin(),
- toString<T>);
-
- setInternal(key, strValues);
-}
-
-template<typename T, std::size_t N>
-void KVStore::setInternal(const std::string& key, const std::array<T, N>& values)
-{
- std::vector<std::string> strValues(N);
-
- std::transform(values.begin(),
- values.end(),
- strValues.begin(),
- toString<T>);
-
- setInternal(key, strValues);
-}
-
-struct SetTupleVisitor
-{
- template<typename T>
- static void visit(std::vector<std::string>::iterator& it, const T& value)
- {
- *it = toString<T>(value);
- ++it;
- }
-};
-
-template<typename ... T>
-void KVStore::setInternal(const std::string& key, const std::pair<T...>& values)
-{
- std::vector<std::string> strValues(std::tuple_size<std::pair<T...>>::value);
-
- SetTupleVisitor visitor;
- visitFields(values, &visitor, strValues.begin());
- setInternal(key, strValues);
-}
-
-template<typename T, typename std::enable_if<!std::is_enum<T>::value, int>::type>
-T KVStore::getInternal(const std::string& key, T*)
-{
- return fromString<T>(getInternal(key, static_cast<std::string*>(nullptr)));
-}
-
-template<typename T, typename std::enable_if<std::is_enum<T>::value, int>::type>
-T KVStore::getInternal(const std::string& key, T*)
-{
- return static_cast<T>(getInternal(key,
- static_cast<typename std::underlying_type<T>::type*>(nullptr)));
-}
-
-template<typename T, std::size_t N>
-std::array<T, N> KVStore::getInternal(const std::string& key, std::array<T, N>*)
-{
- std::vector<std::string> strValues = getInternal(key, static_cast<std::vector<std::string>*>(nullptr));
- std::array<T, N> values;
-
- std::transform(strValues.begin(),
- strValues.end(),
- values.begin(),
- fromString<T>);
-
- return values;
-}
-
-template<typename T>
-std::vector<T> KVStore::getInternal(const std::string& key, std::vector<T>*)
-{
- std::vector<std::string> strValues = getInternal(key, static_cast<std::vector<std::string>*>(nullptr));
- std::vector<T> values(strValues.size());
-
- std::transform(strValues.begin(),
- strValues.end(),
- values.begin(),
- fromString<T>);
-
- return values;
-}
-
-struct GetTupleVisitor
-{
- template<typename T>
- static void visit(std::vector<std::string>::iterator& it, T& value)
- {
- value = fromString<T>(*it);
- ++it;
- }
-};
-
-template<typename ... T>
-std::pair<T...> KVStore::getInternal(const std::string& key, std::pair<T...>*)
-{
- std::vector<std::string> strValues = getInternal(key, static_cast<std::vector<std::string>*>(nullptr));
- std::pair<T...> values;
-
- GetTupleVisitor visitor;
- visitFields(values, &visitor, strValues.begin());
-
- return values;
-}
-
-/**
- * Concatenates all parameters into one std::string.
- * Uses '.' to connect the terms.
- * @param args components of the string
- * @tparam delim optional delimiter
- * @tparam Args any type implementing str
- * @return string created from he args
- */
-template<char delim = '.', typename Arg1, typename ... Args>
-std::string key(const Arg1& a1, const Args& ... args)
-{
- std::string ret = toString(a1);
- std::initializer_list<std::string> strings {toString(args)...};
- for (const std::string& s : strings) {
- ret += delim + s;
- }
-
- return ret;
-}
-
-/**
- * Function added for key function completeness.
- *
- * @tparam delim = '.' parameter not used, added for consistency
- * @return empty string
- */
-template<char delim = '.'>
-std::string key()
-{
- return std::string();
-}
-
} // namespace config
#endif // COMMON_CONFIG_KVSTORE_HPP
#include "config/from-gvariant-visitor.hpp"
#include "config/from-json-visitor.hpp"
#include "config/from-kvstore-visitor.hpp"
+#include "config/from-kvstore-ignoring-visitor.hpp"
#include "config/from-fdstore-visitor.hpp"
-#include "config/from-kvjson-visitor.hpp"
#include "config/fs-utils.hpp"
#include "config/is-union.hpp"
KVStore store(kvfile);
KVStore::Transaction transaction(store);
- FromKVJsonVisitor visitor(store, json, kvConfigName);
- config.accept(visitor);
+ FromJsonVisitor fromJsonVisitor(json);
+ FromKVStoreIgnoringVisitor fromKVStoreVisitor(store, kvConfigName);
+ config.accept(fromJsonVisitor);
+ config.accept(fromKVStoreVisitor);
transaction.commit();
}
#include "config/is-visitable.hpp"
#include "config/kvstore.hpp"
+#include "config/kvstore-visitor-utils.hpp"
namespace config {
{
}
- template<typename T, typename std::enable_if<!isVisitable<T>::value, int>::type = 0>
+ template<typename T,
+ typename std::enable_if<!isVisitable<T>::value
+ && !std::is_enum<T>::value, int>::type = 0>
void setInternal(const std::string& name, const T& value)
{
- mStore.set(name, value);
+ mStore.set(name, toString(value));
}
template<typename T, typename std::enable_if<isVisitable<T>::value, int>::type = 0>
value.accept(visitor);
}
- template<typename T, typename std::enable_if<isVisitable<T>::value, int>::type = 0>
- void setInternal(const std::string& name, const std::vector<T>& values)
+ template<typename T, typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
+ void setInternal(const std::string& name, const T& value)
{
+ setInternal(name, static_cast<const typename std::underlying_type<T>::type>(value));
+ }
+
+ template <typename I>
+ void setRangeInternal(const std::string& name,
+ const I& begin,
+ const I& end,
+ const size_t size) {
+ if (size > std::numeric_limits<unsigned int>::max()) {
+ throw ConfigException("Too many values to insert");
+ }
+
+ KVStore::Transaction transaction(mStore);
+
mStore.remove(name);
- mStore.set(name, values.size());
- for (size_t i = 0; i < values.size(); ++i) {
- setInternal(key(name, std::to_string(i)), values[i]);
+ setInternal(name, size);
+ size_t i = 0;
+ for (auto it = begin; it != end; ++it) {
+ const std::string k = key(name, std::to_string(i));
+ setInternal(k, *it);
+ ++i;
}
+ transaction.commit();
+ }
+
+ template<typename T>
+ void setInternal(const std::string& name, const std::vector<T>& values)
+ {
+ setRangeInternal(name, values.begin(), values.end(), values.size());
+ }
+
+ template<typename T, std::size_t N>
+ void setInternal(const std::string& name, const std::array<T, N>& values) {
+ setRangeInternal(name, values.begin(), values.end(), N);
+ }
+
+ template<typename T>
+ void setInternal(const std::string& name, const std::initializer_list<T>& values)
+ {
+ setRangeInternal(name, values.begin(), values.end(), values.size());
+ }
+
+ template<typename ... T>
+ void setInternal(const std::string& key, const std::pair<T...>& values)
+ {
+ std::vector<std::string> strValues(std::tuple_size<std::pair<T...>>::value);
+
+ SetTupleVisitor visitor;
+ visitFields(values, &visitor, strValues.begin());
+ setInternal(key, strValues);
}
};
std::uint32_t uint32Val;
std::uint64_t uint64Val;
std::string stringVal;
- char* cstringVal;
double doubleVal;
bool boolVal;
TestEnum enumVal;
uint32Val,
uint64Val,
stringVal,
- cstringVal,
doubleVal,
boolVal,
enumVal,
"\"uint32Val\": 123456, "
"\"uint64Val\": 1234567890123456789, "
"\"stringVal\": \"blah\", "
- "\"cstringVal\": \"blah\", "
"\"doubleVal\": -1.234000, "
"\"boolVal\": true, "
"\"enumVal\": 12, "
"\"uint32Val\": 0, "
"\"uint64Val\": 0, "
"\"stringVal\": \"\", "
- "\"cstringVal\": \"\", "
+ "\"doubleVal\": 0.0, "
"\"boolVal\": false, "
"\"enumVal\": 0, "
"\"emptyIntVector\": [ ], "
"\"intVector\": [ ], "
"\"stringVector\": [ ], "
"\"doubleVector\": [ ], "
- "\"intArray\": [ ], "
- "\"intIntPair\": [ ], "
+ "\"intArray\": [ 0, 0 ], "
+ "\"intIntPair\": [ 0, 0 ], "
"\"subObj\": { \"intVal\": 0, \"intVector\": [ ], \"subSubObj\": { \"intVal\": 0 } }, "
"\"subVector\": [ ], "
"\"union1\": { \"type\": \"int\", \"value\": 0 }, "
BOOST_CHECK_EQUAL(123456, testConfig.uint32Val);
BOOST_CHECK_EQUAL(1234567890123456789ll, testConfig.uint64Val);
BOOST_CHECK_EQUAL("blah", testConfig.stringVal);
- BOOST_CHECK_EQUAL("blah", testConfig.cstringVal);
BOOST_CHECK_CLOSE(-1.234, testConfig.doubleVal, TOLERANCE);
BOOST_CHECK_EQUAL(true, testConfig.boolVal);
BOOST_CHECK(TestEnum::SECOND == testConfig.enumVal);
#include "utils/scoped-dir.hpp"
#include "config/manager.hpp"
-#include "config/from-kvjson-visitor.hpp"
-
namespace {
using namespace utils;
void checkKVConfig(const TestConfig& cfg, const std::string& db)
{
KVStore store(db);
- BOOST_CHECK_EQUAL(store.get<int>("conf.intVal"), cfg.intVal);
- BOOST_CHECK_EQUAL(store.get<int64_t>("conf.int64Val"), cfg.int64Val);
- BOOST_CHECK_EQUAL(store.get<bool>("conf.boolVal"), cfg.boolVal);
- BOOST_CHECK_EQUAL(store.get<std::string>("conf.stringVal"), cfg.stringVal);
- BOOST_CHECK_EQUAL(store.get<int>("conf.intVector"), cfg.intVector.size());
- BOOST_CHECK_EQUAL(store.get<int>("conf.subObj.intVal"), cfg.subObj.intVal);
+ BOOST_CHECK_EQUAL(store.get("conf.intVal"), std::to_string(cfg.intVal));
+ BOOST_CHECK_EQUAL(store.get("conf.int64Val"), std::to_string(cfg.int64Val));
+ BOOST_CHECK_EQUAL(store.get("conf.boolVal"), std::to_string(cfg.boolVal));
+ BOOST_CHECK_EQUAL(store.get("conf.stringVal"), cfg.stringVal);
+ BOOST_CHECK_EQUAL(store.get("conf.intVector"), std::to_string(cfg.intVector.size()));
+ BOOST_CHECK_EQUAL(store.get("conf.subObj.intVal"), std::to_string(cfg.subObj.intVal));
}
BOOST_AUTO_TEST_CASE(ReadConfigDefaults)
}
};
-class TestClass {
-public:
- TestClass(int v): value(v) {}
- TestClass(): value(0) {}
- friend std::ostream& operator<< (std::ostream& out, const TestClass& cPoint);
- friend std::istream& operator>> (std::istream& in, TestClass& cPoint);
- friend bool operator== (const TestClass& lhs, const TestClass& rhs);
- friend bool operator!= (const TestClass& lhs, const TestClass& rhs);
-
-private:
- int value ;
-};
-
-bool operator==(const TestClass& lhs, const TestClass& rhs)
-{
- return lhs.value == rhs.value;
-}
-
-bool operator!=(const TestClass& lhs, const TestClass& rhs)
-{
- return lhs.value != rhs.value;
-}
-
-std::ostream& operator<< (std::ostream& out, const TestClass& tc)
-{
- out << tc.value;;
- return out;
-}
-
-std::istream& operator>> (std::istream& in, TestClass& tc)
-{
- in >> tc.value;
- return in;
-}
-
} // namespace
BOOST_FIXTURE_TEST_SUITE(KVStoreSuite, Fixture)
{
// '*' ?' '[' ']' are escaped
// They shouldn't influence the internal implementation
- std::string HARD_KEY = "[" + KEY;
- BOOST_CHECK_NO_THROW(c.set(HARD_KEY, "A"));
- BOOST_CHECK_NO_THROW(c.set(KEY, "B"));
- BOOST_CHECK(c.exists(HARD_KEY));
- BOOST_CHECK(c.exists(KEY));
- BOOST_CHECK_NO_THROW(c.clear());
+ for (char sc: {'[', ']', '?', '*'}) {
+ std::string HARD_KEY = sc + KEY;
- HARD_KEY = "]" + KEY;
- BOOST_CHECK_NO_THROW(c.set(HARD_KEY, "A"));
- BOOST_CHECK_NO_THROW(c.set(KEY, "B"));
- BOOST_CHECK(c.exists(HARD_KEY));
- BOOST_CHECK(c.exists(KEY));
- BOOST_CHECK_NO_THROW(c.clear());
+ BOOST_CHECK_NO_THROW(c.set(HARD_KEY, "A"));
+ BOOST_CHECK_NO_THROW(c.set(KEY, "B"));
- HARD_KEY = "?" + KEY;
- BOOST_CHECK_NO_THROW(c.set(HARD_KEY, "A"));
- BOOST_CHECK_NO_THROW(c.set(KEY, "B"));
- BOOST_CHECK(c.exists(HARD_KEY));
- BOOST_CHECK(c.exists(KEY));
- BOOST_CHECK_NO_THROW(c.clear());
+ BOOST_CHECK(c.exists(HARD_KEY));
+ BOOST_CHECK(c.exists(KEY));
- HARD_KEY = "*" + KEY;
- BOOST_CHECK_NO_THROW(c.set(HARD_KEY, "A"));
- BOOST_CHECK_NO_THROW(c.set(KEY, "B"));
- BOOST_CHECK(c.exists(HARD_KEY));
- BOOST_CHECK(c.exists(KEY));
+ BOOST_CHECK_NO_THROW(c.clear());
+ }
}
-namespace {
-template<typename A, typename B>
-void testSingleValue(Fixture& f, const A& a, const B& b)
+BOOST_AUTO_TEST_CASE(PrefixExists)
{
- // Set
- BOOST_CHECK_NO_THROW(f.c.set(KEY, a));
- BOOST_CHECK_EQUAL(f.c.get<A>(KEY), a);
+ // '*' ?' '[' ']' are escaped
+ // They shouldn't influence the internal implementation
+ for (char sc: {'[', ']', '?', '*'}) {
+ std::string HARD_KEY = sc + KEY;
+ std::string FIELD_HARD_KEY = HARD_KEY + ".field";
- // Update
- BOOST_CHECK_NO_THROW(f.c.set(KEY, b));
- BOOST_CHECK_EQUAL(f.c.get<B>(KEY), b);
- BOOST_CHECK(f.c.exists(KEY));
+ BOOST_CHECK_NO_THROW(c.set(FIELD_HARD_KEY, "C"));
- // Remove
- BOOST_CHECK_NO_THROW(f.c.remove(KEY));
- BOOST_CHECK(!f.c.exists(KEY));
- BOOST_CHECK_THROW(f.c.get<B>(KEY), ConfigException);
-}
-} // namespace
+ BOOST_CHECK(!c.exists(KEY));
+ BOOST_CHECK(!c.exists(HARD_KEY));
+ BOOST_CHECK(c.exists(FIELD_HARD_KEY));
+ BOOST_CHECK(!c.prefixExists(KEY));
+ BOOST_CHECK(c.prefixExists(HARD_KEY));
+ BOOST_CHECK(c.prefixExists(FIELD_HARD_KEY));
-BOOST_AUTO_TEST_CASE(SingleValue)
-{
- testSingleValue<std::string, std::string>(*this, "A", "B");
- testSingleValue<int, int>(*this, 1, 2);
- testSingleValue<double, double>(*this, 1.1, 2.2);
- testSingleValue<int, std::string>(*this, 2, "A");
- testSingleValue<int64_t, int64_t>(*this, INT64_MAX, INT64_MAX - 2);
- testSingleValue<TestClass, int>(*this, 11, 22);
+ BOOST_CHECK_NO_THROW(c.clear());
+ }
}
namespace {
-template<typename T>
-void setVector(Fixture& f, const std::vector<T>& vec)
-{
- std::vector<T> storedVec;
- BOOST_CHECK_NO_THROW(f.c.set(KEY, vec));
- BOOST_CHECK_NO_THROW(storedVec = f.c.get<std::vector<T>>(KEY))
- BOOST_CHECK_EQUAL_COLLECTIONS(storedVec.begin(), storedVec.end(), vec.begin(), vec.end());
-}
-
-template<typename T>
-void testVectorOfValues(Fixture& f,
- const std::vector<T>& a,
- const std::vector<T>& b,
- const std::vector<T>& c)
+void testSingleValue(Fixture& f, const std::string& a, const std::string& b)
{
// Set
- setVector(f, a);
- setVector(f, b);
- setVector(f, c);
+ BOOST_CHECK_NO_THROW(f.c.set(KEY, a));
+ BOOST_CHECK_EQUAL(f.c.get(KEY), a);
+
+ // Update
+ BOOST_CHECK_NO_THROW(f.c.set(KEY, b));
+ BOOST_CHECK_EQUAL(f.c.get(KEY), b);
+ BOOST_CHECK(f.c.exists(KEY));
// Remove
BOOST_CHECK_NO_THROW(f.c.remove(KEY));
BOOST_CHECK(!f.c.exists(KEY));
- BOOST_CHECK(f.c.isEmpty());
- BOOST_CHECK_THROW(f.c.get<std::vector<T> >(KEY), ConfigException);
BOOST_CHECK_THROW(f.c.get(KEY), ConfigException);
}
} // namespace
-BOOST_AUTO_TEST_CASE(VectorOfValues)
+
+BOOST_AUTO_TEST_CASE(SingleValue)
{
- testVectorOfValues<std::string>(*this, {"A", "B"}, {"A", "C"}, {"A", "B", "C"});
- testVectorOfValues<int>(*this, {1, 2}, {1, 3}, {1, 2, 3});
- testVectorOfValues<int64_t>(*this, {INT64_MAX, 2}, {1, 3}, {INT64_MAX, 2, INT64_MAX});
- testVectorOfValues<double>(*this, {1.1, 2.2}, {1.1, 3.3}, {1.1, 2.2, 3.3});
- testVectorOfValues<TestClass>(*this, {1, 2}, {1, 3}, {1, 2, 3});
+ testSingleValue(*this, "A", "B");
}
BOOST_AUTO_TEST_CASE(Clear)
{
BOOST_CHECK_NO_THROW(c.clear());
- std::vector<std::string> vec = {"A", "B"};
- BOOST_CHECK_NO_THROW(c.set(KEY, vec));
+ BOOST_CHECK_NO_THROW(c.set(KEY, "2"));
+ BOOST_CHECK_NO_THROW(c.set(KEY + ".0", "A"));
+ BOOST_CHECK_NO_THROW(c.set(KEY + ".1", "B"));
BOOST_CHECK_NO_THROW(c.clear());
BOOST_CHECK(c.isEmpty());
BOOST_CHECK_NO_THROW(c.remove(KEY));
- BOOST_CHECK_THROW(c.get<std::vector<std::string>>(KEY), ConfigException);
+ BOOST_CHECK_THROW(c.get(KEY), ConfigException);
BOOST_CHECK_THROW(c.get(KEY), ConfigException);
}
{
{
KVStore::Transaction trans(c);
- c.set<int>(KEY, 1);
+ c.set(KEY, "a");
trans.commit();
}
- BOOST_CHECK_EQUAL(c.get<int>(KEY), 1);
+ BOOST_CHECK_EQUAL(c.get(KEY), "a");
{
KVStore::Transaction trans(c);
- c.set<int>(KEY, 2);
+ c.set(KEY, "b");
// no commit
}
- BOOST_CHECK_EQUAL(c.get<int>(KEY), 1);
+ BOOST_CHECK_EQUAL(c.get(KEY), "a");
{
KVStore::Transaction trans(c);
KVStore::Transaction transOuter(c);
{
KVStore::Transaction transInner(c);
- c.set<int>(KEY, 1);
+ c.set(KEY, "a");
// no inner commit
}
transOuter.commit();
}
- BOOST_CHECK_EQUAL(c.get<int>(KEY), 1);
+ BOOST_CHECK_EQUAL(c.get(KEY), "a");
{
KVStore::Transaction transOuter(c);
{
KVStore::Transaction transInner(c);
- c.set<int>(KEY, 2);
+ c.set(KEY, "b");
transInner.commit();
}
// no outer commit
}
- BOOST_CHECK_EQUAL(c.get<int>(KEY), 1);
+ BOOST_CHECK_EQUAL(c.get(KEY), "a");
{
KVStore::Transaction transOuter(c);
thread2.join();
}
-BOOST_AUTO_TEST_CASE(Key)
-{
- BOOST_CHECK_EQUAL(key(), "");
- BOOST_CHECK_EQUAL(key<>(), "");
- BOOST_CHECK_EQUAL(key(""), "");
- BOOST_CHECK_EQUAL(key("KEY"), "KEY");
- BOOST_CHECK_EQUAL(key<>("KEY"), "KEY");
- BOOST_CHECK_EQUAL(key("KEY", "A"), "KEY.A");
- BOOST_CHECK_EQUAL(key("KEY", 1, 2.2), "KEY.1.2.2");
- BOOST_CHECK_EQUAL(key("KEY", 1, "B"), "KEY.1.B");
- BOOST_CHECK_EQUAL(key<'_'>("KEY", 1, 2.2), "KEY_1_2.2");
-}
-
BOOST_AUTO_TEST_SUITE_END()