You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pn...@apache.org on 2021/11/28 16:22:51 UTC

[celix] 01/01: Updates C++ properties to support string_view if C++17 is used.

This is an automated email from the ASF dual-hosted git repository.

pnoltes pushed a commit to branch feature/stringview_support_for_properties
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 63f13c5491fe37f79002d7a6b65a1ae2ae070af4
Author: Pepijn Noltes <pn...@apache.org>
AuthorDate: Sun Nov 28 17:01:07 2021 +0100

    Updates C++ properties to support string_view if C++17 is used.
---
 libs/utils/gtest/CMakeLists.txt                |  13 ++-
 libs/utils/gtest/src/CxxPropertiesTestSuite.cc |  59 +++++++++++-
 libs/utils/include/celix/Properties.h          | 123 ++++++++++++++++++++++++-
 3 files changed, 189 insertions(+), 6 deletions(-)

diff --git a/libs/utils/gtest/CMakeLists.txt b/libs/utils/gtest/CMakeLists.txt
index 6cb860d..0802214 100644
--- a/libs/utils/gtest/CMakeLists.txt
+++ b/libs/utils/gtest/CMakeLists.txt
@@ -54,7 +54,7 @@ target_compile_definitions(test_utils PRIVATE -DTEST_ZIP_LOCATION=\"${TEST_ZIP_F
 target_compile_definitions(test_utils PRIVATE -DTEST_A_FILE_LOCATION=\"${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt\")
 target_compile_definitions(test_utils PRIVATE -DTEST_A_DIR_LOCATION=\"${CMAKE_CURRENT_SOURCE_DIR}\")
 
-####### linkig zip against test executable to text extract zip from data ###############################################
+####### linking zip against test executable to text extract zip from data ###############################################
 if (UNIX AND NOT APPLE)
     target_link_libraries(test_utils PRIVATE -Wl,--format=binary -Wl,"test.zip" -Wl,--format=default)
 else ()
@@ -64,3 +64,14 @@ endif ()
 add_test(NAME test_utils COMMAND test_utils)
 setup_target_for_coverage(test_utils SCAN_DIR ..)
 
+
+#Setting standard to C++11 and testing C++ Properties to ensure that this still support C++11.
+#Note that celix Properties are used in the C++11 dependency manager and this be backwards compatible with Celix 2.2.1
+set(CMAKE_CXX_STANDARD 11)
+add_executable(test_properties_with_cxx11
+        src/CxxPropertiesTestSuite.cc
+)
+target_link_libraries(test_properties_with_cxx11 PRIVATE Celix::utils GTest::gtest GTest::gtest_main)
+add_test(NAME test_properties_with_cxx11 COMMAND test_properties_with_cxx11)
+setup_target_for_coverage(test_properties_with_cxx11 SCAN_DIR ..)
+
diff --git a/libs/utils/gtest/src/CxxPropertiesTestSuite.cc b/libs/utils/gtest/src/CxxPropertiesTestSuite.cc
index 8f151e4..060562b 100644
--- a/libs/utils/gtest/src/CxxPropertiesTestSuite.cc
+++ b/libs/utils/gtest/src/CxxPropertiesTestSuite.cc
@@ -87,4 +87,61 @@ TEST_F(CxxPropertiesTestSuite, testWrap) {
     EXPECT_EQ(1, celix_properties_size(props));
 
     celix_properties_destroy(props);
-}
\ No newline at end of file
+}
+
+#if __cplusplus >= 201703L //C++17 or higher
+TEST_F(CxxPropertiesTestSuite, testStringView) {
+    constexpr std::string_view stringViewKey = "KEY1";
+    constexpr std::string_view stringViewValue = "VALUE1";
+    std::string stringKey{"KEY2"};
+    std::string stringValue{"VALUE2"};
+    const char* charKey = "KEY3";
+    const char* charValue = "VALUE3";
+
+    {
+        //rule: I can create properties with initializer_list using std::string, const char* and string_view
+        celix::Properties props {
+                {charKey, charValue},
+                {stringKey, stringValue},
+                {stringViewKey, stringViewValue}
+        };
+        EXPECT_EQ(props.size(), 3);
+
+        //rule: I can use the subscript operator using string_view objects
+        constexpr std::string_view k = "KEY2";
+        constexpr std::string_view v = "VALUE_NEW";
+        std::string check = props[k];
+        EXPECT_EQ(check, "VALUE2");
+        props[k] = v;
+        check = props[k];
+        EXPECT_EQ(check, v);
+    }
+
+    {
+        //rule: I can use set/get with string_view
+        constexpr std::string_view key = "TEST_KEY";
+        constexpr std::string_view value = "TEST_VALUE";
+
+        celix::Properties props{};
+
+        props.set(key, value);
+        EXPECT_EQ(value, props.get(key));
+        props[key] = value;
+        EXPECT_EQ(value, props.get(key));
+        EXPECT_EQ(1, props.size());
+
+        props.set(key,  std::string{"string value"});
+        EXPECT_EQ("string value", props.get(key));
+        props.set(key,  "string value");
+        EXPECT_EQ("string value", props.get(key));
+        EXPECT_EQ(1, props.size());
+
+        props.set(key, 1L); //long
+        EXPECT_EQ(1L, props.getAsLong(key, -1));
+        props.set(key, 1.0); //double
+        EXPECT_EQ(1.0, props.getAsDouble(key, -1));
+        props.set(key, true); //bool
+        EXPECT_EQ(true, props.getAsBool(key, false));
+    }
+}
+#endif
diff --git a/libs/utils/include/celix/Properties.h b/libs/utils/include/celix/Properties.h
index 7698e77..0d00cd2 100644
--- a/libs/utils/include/celix/Properties.h
+++ b/libs/utils/include/celix/Properties.h
@@ -103,14 +103,36 @@ namespace celix {
 
         class ValueRef {
         public:
-            ValueRef(std::shared_ptr<celix_properties_t> _props, std::string _key) : props{std::move(_props)}, key{std::move(_key)} {}
+            ValueRef(std::shared_ptr<celix_properties_t> _props, std::string _key) : props{std::move(_props)}, stringKey{std::move(_key)}, charKey{nullptr} {}
+
+            ValueRef(std::shared_ptr<celix_properties_t> _props, const char* _key) : props{std::move(_props)}, stringKey{}, charKey{_key} {}
+
+#if __cplusplus >= 201703L //C++17 or higher
+            ValueRef& operator=(std::string_view value) {
+                if (charKey == nullptr) {
+                    celix_properties_set(props.get(), stringKey.c_str(), value.data());
+                } else {
+                    celix_properties_set(props.get(), charKey, value.data());
+                }
+                return *this;
+            }
+#else
             ValueRef& operator=(const std::string& value) {
-                celix_properties_set(props.get(), key.c_str(), value.c_str());
+                if (charKey == nullptr) {
+                    celix_properties_set(props.get(), stringKey.c_str(), value.c_str());
+                } else {
+                    celix_properties_set(props.get(), charKey, value.c_str());
+                }
                 return *this;
             }
+#endif
 
             [[nodiscard]] const char* getValue() const {
-                return celix_properties_get(props.get(), key.c_str(), nullptr);
+                if (charKey == nullptr) {
+                    return celix_properties_get(props.get(), stringKey.c_str(), nullptr);
+                } else {
+                    return celix_properties_get(props.get(), charKey, nullptr);
+                }
             }
 
             operator std::string() const {
@@ -119,7 +141,8 @@ namespace celix {
             }
         private:
             std::shared_ptr<celix_properties_t> props;
-            std::string key;
+            std::string stringKey;
+            const char* charKey;
         };
 
 
@@ -138,11 +161,19 @@ namespace celix {
         Properties(const Properties& rhs) :
             cProps{celix_properties_copy(rhs.cProps.get()), [](celix_properties_t* p) { celix_properties_destroy(p); }} {}
 
+#if __cplusplus >= 201703L //C++17 or higher
+        Properties(std::initializer_list<std::pair<std::string_view, std::string_view>> list) : cProps{celix_properties_create(), [](celix_properties_t* p) { celix_properties_destroy(p); }} {
+            for(auto &entry : list) {
+                celix_properties_set(cProps.get(), entry.first.data(), entry.second.data());
+            }
+        }
+#else
         Properties(std::initializer_list<std::pair<std::string, std::string>> list) : cProps{celix_properties_create(), [](celix_properties_t* p) { celix_properties_destroy(p); }} {
             for(auto &entry : list) {
                 celix_properties_set(cProps.get(), entry.first.c_str(), entry.second.c_str());
             }
         }
+#endif
 
         /**
          * @brief Wraps C properties, but does not take ownership -> dtor will not destroy properties
@@ -162,6 +193,21 @@ namespace celix {
             return cProps.get();
         }
 
+#if __cplusplus >= 201703L //C++17 or higher
+        /**
+         * @brief Get the value for a property key
+         */
+        ValueRef operator[](std::string_view key) {
+            return ValueRef{cProps, key.data()};
+        }
+
+        /**
+         * @brief Get the value for a property key
+         */
+        ValueRef operator[](std::string_view key) const {
+            return ValueRef{cProps, key.data()};
+        }
+#else
         /**
          * @brief Get the value for a property key
          */
@@ -175,6 +221,7 @@ namespace celix {
         ValueRef operator[](std::string key) const {
             return ValueRef{cProps, std::move(key)};
         }
+#endif
 
         /**
          * @brief begin iterator
@@ -208,6 +255,73 @@ namespace celix {
             return iter;
         }
 
+#if __cplusplus >= 201703L //C++17 or higher
+        /**
+         * @brief Get the value for a property key or return the defaultValue if the key does not exists.
+         */
+        [[nodiscard]] std::string get(std::string_view key, std::string_view defaultValue = {}) const {
+            const char* found = celix_properties_get(cProps.get(), key.data(), nullptr);
+            return found == nullptr ? std::string{defaultValue} : std::string{found};
+        }
+
+        /**
+         * @brief Get the value as long for a property key or return the defaultValue if the key does not exists.
+         */
+        [[nodiscard]] long getAsLong(std::string_view key, long defaultValue) const {
+            return celix_properties_getAsLong(cProps.get(), key.data(), defaultValue);
+        }
+
+        /**
+         * @brief Get the value as double for a property key or return the defaultValue if the key does not exists.
+         */
+        [[nodiscard]] double getAsDouble(std::string_view key, double defaultValue) const {
+            return celix_properties_getAsDouble(cProps.get(), key.data(), defaultValue);
+        }
+
+        /**
+         * @brief Get the value as bool for a property key or return the defaultValue if the key does not exists.
+         */
+        [[nodiscard]] bool getAsBool(std::string_view key, bool defaultValue) const {
+            return celix_properties_getAsBool(cProps.get(), key.data(), defaultValue);
+        }
+
+        /**
+         * @brief Sets a property
+         */
+        void set(std::string_view key, std::string_view value) {
+            celix_properties_set(cProps.get(), key.data(), value.data());
+        }
+
+        /**
+         * @brief Sets a property
+         */
+        void set(std::string_view key, std::string value) {
+            celix_properties_set(cProps.get(), key.data(), value.data());
+        }
+
+        /**
+         * @brief Sets a property
+         */
+        void set(std::string_view key, const char* value) {
+            celix_properties_set(cProps.get(), key.data(), value);
+        }
+
+        /**
+         * @brief Sets a bool property
+         */
+        void set(std::string_view key, bool value) {
+            celix_properties_setBool(cProps.get(), key.data(), value);
+        }
+
+        /**
+         * @brief Sets a T property. Will use std::to_string to convert the value to string.
+         */
+        template<typename T>
+        void set(std::string_view key, T value) {
+            using namespace std;
+            celix_properties_set(cProps.get(), key.data(), to_string(value).c_str());
+        }
+#else
         /**
          * @brief Get the value for a property key or return the defaultValue if the key does not exists.
          */
@@ -266,6 +380,7 @@ namespace celix {
             using namespace std;
             celix_properties_set(cProps.get(), key.c_str(), to_string(value).c_str());
         }
+#endif
 
         /**
          * @brief Returns the nr of properties.