[Props] Implement load properties
authorJihoon Lee <jhoon.it.lee@samsung.com>
Fri, 9 Apr 2021 13:46:58 +0000 (22:46 +0900)
committerJijoong Moon <jijoong.moon@samsung.com>
Mon, 3 May 2021 02:45:00 +0000 (11:45 +0900)
This patch implement `load_properties` which helps loading properties
for a tuple of properties.

Please note that `getKeyVal` is taken from `parse_util` because there is
a build option issue with android build

**Self evaluation:**
1. Build test: [X]Passed [ ]Failed [ ]Skipped
2. Run test: [X]Passed [ ]Failed [ ]Skipped

Signed-off-by: Jihoon Lee <jhoon.it.lee@samsung.com>
nntrainer/utils/base_properties.h
nntrainer/utils/node_exporter.cpp
nntrainer/utils/node_exporter.h
nntrainer/utils/parse_util.cpp
nntrainer/utils/parse_util.h
test/unittest/unittest_properties.cpp

index 8c025c1..814e6aa 100644 (file)
@@ -277,8 +277,8 @@ template <typename T> std::string to_string(const T &property) {
  * @brief convert dispatcher (from string)
  *
  * @tparam T type to convert
- * @param str string to vert
- * @param property property, converted type
+ * @param str string to convert
+ * @param[out] property property, converted type
  */
 template <typename T> void from_string(const std::string &str, T &property) {
   using tag_type =
index eefba97..9236c9f 100644 (file)
@@ -1,4 +1,3 @@
-#include <node_exporter.h>
 // SPDX-License-Identifier: Apache-2.0
 /**
  * Copyright (C) 2021 Jihoon Lee <jhoon.it.lee@samsung.com>
@@ -10,6 +9,9 @@
  * @author Jihoon Lee <jhoon.it.lee@samsung.com>
  * @bug No known bugs except for NYI items
  */
+
+#include <node_exporter.h>
+
 namespace nntrainer {
 
 template <>
index 072e7a3..0411be5 100644 (file)
@@ -15,6 +15,7 @@
 #include <vector>
 
 #include <nntrainer_error.h>
+#include <parse_util.h>
 
 #ifndef __NODE_EXPORTER_H__
 #define __NODE_EXPORTER_H__
@@ -114,40 +115,6 @@ public:
   const T &get_result();
 
 private:
-  /**
-   * @brief base case of iterate_prop, iterate_prop iterates the given tuple
-   *
-   * @tparam I size of tuple(automated)
-   * @tparam Callable generic lambda to be called during iteration
-   * @tparam Ts types from tuple
-   * @param c callable gerneric labmda
-   * @param tup tuple to be iterated
-   * @return void
-   */
-  template <size_t I = 0, typename Callable, typename... Ts>
-  typename std::enable_if<I == sizeof...(Ts), void>::type
-  iterate_prop(Callable &&c, const std::tuple<Ts...> &tup) {
-    // end of recursion;
-  }
-
-  /**
-   * @brief base case of iterate_prop, iterate_prop iterates the given tuple
-   *
-   * @tparam I size of tuple(automated)
-   * @tparam Callable generic lambda to be called during iteration
-   * @tparam Ts types from tuple
-   * @param c callable gerneric labmda
-   * @param tup tuple to be iterated
-   * @return not used
-   */
-  template <size_t I = 0, typename Callable, typename... Ts>
-  typename std::enable_if<(I < sizeof...(Ts)), void>::type
-  iterate_prop(Callable &&c, const std::tuple<Ts...> &tup) {
-    c(std::get<I>(tup), I);
-
-    iterate_prop<I + 1>(c, tup);
-  }
-
   std::vector<std::pair<std::string, std::string>>
     stored_result; /**< stored result */
 
@@ -156,5 +123,90 @@ private:
   bool is_exported; /**< boolean to check if exported */
 };
 
+/**
+ * @brief base case of iterate_prop, iterate_prop iterates the given tuple
+ *
+ * @tparam I size of tuple(automated)
+ * @tparam Callable generic lambda to be called during iteration
+ * @tparam Ts types from tuple
+ * @param c callable gerneric labmda
+ * @param tup tuple to be iterated
+ * @return void
+ */
+template <size_t I = 0, typename Callable, typename... Ts>
+typename std::enable_if<I == sizeof...(Ts), void>::type
+iterate_prop(Callable &&c, const std::tuple<Ts...> &tup) {
+  // end of recursion;
+}
+
+/**
+ * @brief base case of iterate_prop, iterate_prop iterates the given tuple
+ *
+ * @tparam I size of tuple(automated)
+ * @tparam Callable generic lambda to be called during iteration
+ * @tparam Ts types from tuple
+ * @param c callable gerneric labmda
+ * @param tup tuple to be iterated
+ * @return not used
+ */
+template <size_t I = 0, typename Callable, typename... Ts>
+typename std::enable_if<(I < sizeof...(Ts)), void>::type
+iterate_prop(Callable &&c, const std::tuple<Ts...> &tup) {
+  c(std::get<I>(tup), I);
+
+  iterate_prop<I + 1>(c, tup);
+}
+
+/**
+ * @copydoc  template <size_t I = 0, typename Callable, typename... Ts>
+typename std::enable_if<(I < sizeof...(Ts)), void>::type iterate_prop(Callable
+&&c, const std::tuple<Ts...> &tup)
+ */
+template <size_t I = 0, typename Callable, typename... Ts>
+typename std::enable_if<(I < sizeof...(Ts)), void>::type
+iterate_prop(Callable &&c, std::tuple<Ts...> &tup) {
+  c(std::get<I>(tup), I);
+
+  iterate_prop<I + 1>(c, tup);
+}
+
+/**
+ * @brief load property from the api formatted string ({"key=value",
+ * "key1=value1"})
+ *
+ * @tparam Ts prop type
+ * @param string_vector api formatted string;
+ * @param[out] props props to be iterated
+ * @return std::vector<std::string> vector of string that is not used while
+ * setting the property
+ */
+template <typename... Ts>
+std::vector<std::string>
+load_properties(const std::vector<std::string> &string_vector,
+                std::tuple<Ts...> &props) {
+
+  std::vector<std::string> left = string_vector;
+
+  auto callable = [&left](auto &&prop, size_t index) {
+    std::string prop_key = std::remove_reference_t<decltype(prop)>::key;
+
+    for (auto iter = left.begin(); iter < left.end(); ++iter) {
+      std::string key, value;
+      int status = getKeyValue(*iter, key, value);
+      NNTR_THROW_IF(status != ML_ERROR_NONE, std::invalid_argument)
+        << "parsing property failed, original format: " << *iter;
+
+      if (istrequal(prop_key, key) == true) {
+        from_string(value, prop);
+        iter = left.erase(iter);
+      }
+    }
+  };
+
+  iterate_prop(callable, props);
+
+  return left;
+}
+
 } // namespace nntrainer
 #endif // __NODE_EXPORTER_H__
index 34c6246..cf12d15 100644 (file)
 
 namespace nntrainer {
 
-int getKeyValue(std::string &input_str, std::string &key, std::string &value) {
+int getKeyValue(const std::string &input_str, std::string &key,
+                std::string &value) {
   int status = ML_ERROR_NONE;
+  auto input_trimmed = input_str;
+
   std::vector<std::string> list;
   static const std::regex words_regex("[^\\s=]+");
-  input_str.erase(std::remove(input_str.begin(), input_str.end(), ' '),
-                  input_str.end());
-  auto words_begin =
-    std::sregex_iterator(input_str.begin(), input_str.end(), words_regex);
+  input_trimmed.erase(
+    std::remove(input_trimmed.begin(), input_trimmed.end(), ' '),
+    input_trimmed.end());
+  auto words_begin = std::sregex_iterator(input_trimmed.begin(),
+                                          input_trimmed.end(), words_regex);
   auto words_end = std::sregex_iterator();
   int nwords = std::distance(words_begin, words_end);
   if (nwords != 2) {
     ml_loge("Error: input string must be 'key = value' format, %s given",
-            input_str.c_str());
+            input_trimmed.c_str());
     return ML_ERROR_INVALID_PARAMETER;
   }
 
@@ -60,6 +64,7 @@ int getKeyValue(std::string &input_str, std::string &key, std::string &value) {
 
   key = list[0];
   value = list[1];
+
   return status;
 }
 
index fb7dea9..ecdccbb 100644 (file)
@@ -166,7 +166,8 @@ int setBoolean(bool &val, std::string str);
  * @retval #ML_ERROR_NONE Successful.
  * @retval #ML_ERROR_INVALID_PARAMETER invalid parameter.
  */
-int getKeyValue(std::string &input_str, std::string &key, std::string &value);
+int getKeyValue(const std::string &input_str, std::string &key,
+                std::string &value);
 
 /**
  * @brief     join vector of int to string with delimiter ","
index cc32e36..b1ffd3b 100644 (file)
@@ -121,6 +121,29 @@ TEST(BasicProperty, valid_p) {
     auto pair2 = std::pair<std::string, std::string>("quality_banana", "");
     EXPECT_EQ(result[1], pair2);
   }
+
+  { /**< export from layer */
+    auto layer = nntrainer::FullyConnectedLayer(1);
+    nntrainer::Exporter e;
+    layer.export_to(e);
+
+    auto result = e.get_result<nntrainer::ExportMethods::METHOD_STRINGVECTOR>();
+    auto pair = std::pair<std::string, std::string>("unit", "1");
+    EXPECT_EQ(result[0], pair);
+  }
+
+  { /**< load from layer */
+    auto props = std::make_tuple(NumBanana(), QualityOfBanana());
+
+    auto v =
+      nntrainer::load_properties({"num_banana=2", "quality_banana=thisisgood",
+                                  "num_banana=42", "not_used=key"},
+                                 props);
+
+    EXPECT_EQ(v, std::vector<std::string>{"not_used=key"});
+    EXPECT_EQ(std::get<0>(props).get(), 42);
+    EXPECT_EQ(std::get<1>(props).get(), "thisisgood");
+  }
 }
 
 TEST(BasicProperty, setNotValid_01_n) {
@@ -167,16 +190,6 @@ TEST(Exporter, notExported_n) {
                std::invalid_argument);
 }
 
-TEST(Exporter, exportFromLayer_p) {
-  auto layer = nntrainer::FullyConnectedLayer(1);
-  nntrainer::Exporter e;
-  layer.export_to(e);
-
-  auto result = e.get_result<nntrainer::ExportMethods::METHOD_STRINGVECTOR>();
-  auto pair = std::pair<std::string, std::string>("unit", "1");
-  EXPECT_EQ(result[0], pair);
-}
-
 /**
  * @brief Main gtest
  */