瀏覽代碼

Support int, bool.
Use variant instead of tagged psuedo-union

Sam Jaffe 6 年之前
父節點
當前提交
5af5eb2caa

+ 21 - 6
include/logger/properties.h

@@ -12,16 +12,31 @@
 #include <string>
 #include <vector>
 
+#include "../../../types/variant/variant.hpp"
+
 namespace logging {
+  struct properties;
+  using object_t = std::map<std::string, properties>;
+  using array_t = std::vector<properties>;
+
   struct properties {
-    operator std::string const &() const;
-    properties const & operator[](std::size_t idx) const;
+    bool contains(std::string const & key) const;
+    bool contains(std::size_t idx) const;
+    
+    object_t const & object() const;
+    array_t const & array() const;
+
     properties const & operator[](std::string const & key) const;
+    properties const & operator[](char const * key) const {
+      return operator[](std::string(key));
+    }
+    properties const & operator[](std::size_t idx) const;
+    operator std::string const &() const;
+    std::string const & str() const;
+    operator int() const;
+    operator bool() const;
 
-    const enum { STRING, OBJECT, ARRAY } type;
-    const std::map<std::string, properties> obj;
-    const std::vector<properties> array;
-    const std::string value;
+    variant<object_t, array_t, std::string, int, bool> data;
   };
   
   extern properties const DEFAULT_APPENDER_SCHEMA;

+ 7 - 9
src/log_manager.cxx

@@ -51,11 +51,11 @@ manager_impl::manager_impl() {
 std::shared_ptr<logger_impl>
 manager_impl::get_logger(properties const & props) {
   auto out = std::make_shared<logger_impl>();
-  if (props.type == properties::OBJECT) {
+  if (props.data.is<object_t>()) {
     // TODO include settings on the parent
     out->impls.push_back(appenders.at(props["ref"]));
-  } else if (props.type == properties::ARRAY) {
-    for (auto & part : props.array) {
+  } else if (props.data.is<array_t>()) {
+    for (auto & part : props.array()) {
       out->impls.push_back(appenders.at(part["ref"]));
     }
   } else {
@@ -75,7 +75,7 @@ static bool is_layout(std::string const & str) {
 
 static p_layout load_layout(std::string const & source,
                             properties const & props) {
-  for (auto & layout : props.obj) {
+  for (auto & layout : props.object()) {
     if (is_layout(layout.first)) {
       return layouts::instance().get(layout.first, layout.second);
     }
@@ -85,15 +85,14 @@ static p_layout load_layout(std::string const & source,
 
 template <typename T>
 void inject_log_level(properties const & props, T & val) {
-  if (props.obj.count("level")) {
+  if (props.contains("level")) {
     val.min_log_level = level_from_string(props["level"]);
   }
 }
 
 void manager_impl::configure_appenders(properties const & props) {
   // TODO: Support multiple File loggers, etc.
-  expects(props["appenders"].type == properties::OBJECT);
-  for (auto & app : props["appenders"].obj) {
+  for (auto & app : props["appenders"].object()) {
     auto pair = std::make_pair(load_appender(app.first, app.second),
                                load_layout(app.first, app.second));
     inject_log_level(app.second, *pair.first);
@@ -102,8 +101,7 @@ void manager_impl::configure_appenders(properties const & props) {
 }
 
 void manager_impl::configure_loggers(properties const & props) {
-  expects(props["loggers"].type == properties::OBJECT);
-  for (auto & log : props["loggers"].obj) {
+  for (auto & log : props["loggers"].object()) {
     auto plog = get_logger(log.second["appenders"]);
     inject_log_level(log.second, *plog);
     loggers[log.first] = plog;

+ 1 - 10
src/loggers/console_appender.cxx

@@ -16,15 +16,6 @@
 
 using namespace logging;
 
-static std::string validate_or_throw(logging::properties const& props) {
-  expects(props.type == properties::OBJECT, "expected properties to be a map");
-  auto it = props.obj.find("target");
-  expects(it != props.obj.end(), "expected a console target entry");
-  expects(it->second.type == properties::STRING,
-          "expected properties[\"target\"] to be a string");
-  return it->second.value;
-}
-
 class console_appender : public appender {
 public:
   static std::shared_ptr<appender> create(properties const& props);
@@ -39,7 +30,7 @@ private:
 };
 
 std::shared_ptr<appender> console_appender::create(properties const& props) {
-  const std::string target = validate_or_throw(props);
+  const std::string target = props["target"];
   if (target == "SYSTEM_OUT") {
     return std::make_shared<console_appender>(std::cout);
   } else if (target == "SYSTEM_ERR") {

+ 1 - 1
src/loggers/file_appender.cxx

@@ -30,7 +30,7 @@ private:
 };
 
 static bool is_append(properties const & props) {
-  return props.obj.count("append") && props["append"].value == "true";
+  return props.contains("append") && props["append"];
 }
 
 std::shared_ptr<appender> file_appender::create(properties const & props) {

+ 53 - 27
src/loggers/properties.cxx

@@ -20,15 +20,12 @@
  */
 namespace logging {
   namespace {
-    properties _property(std::map<std::string, properties> const& m) {
-      return properties{properties::OBJECT, m, {}, {}};
-    }
-//    properties _list(std::vector<properties> const& l) {
-//      return properties{properties::ARRAY, {}, l, {}};
-//    }
-    properties _value(std::string const& s) {
-      return properties{properties::STRING, {}, {}, s};
+    properties _property(object_t const& m) {
+      properties pr{m};
+      return pr;
     }
+//    properties _list(array_t const& l) { return {l}; }
+    properties _v(std::string const & t) { return {t}; }
   }
   
   /*
@@ -46,45 +43,74 @@ namespace logging {
   extern properties const DEFAULT_APPENDER_SCHEMA;
   extern properties const DEFAULT_LOGGER_SCHEMA;
   
-  static char const * const DEFAULT_PATTERN =
-    "%d{%h:%M:%s.%_ms} [%t] %-5.5p %.36c - %m%n";
-
   properties const DEFAULT_APPENDER_SCHEMA{_property({
     {"appenders", _property({
       {"Console", _property({
-        {"target", _value("SYSTEM_OUT")},
+        {"target", _v("SYSTEM_OUT")},
         {"PatternLayout", _property({
-          {"pattern", _value(DEFAULT_PATTERN)}
+          {"pattern", _v("%d{%h:%M:%s.%_ms} [%t] %-5.5p %.36c - %m%n")}
         })}
       })}
     })}
   })};
-  
+    
   properties const DEFAULT_LOGGER_SCHEMA{_property({
     {"loggers", _property({
       {"root", _property({
-        {"level", _value("Error")},
+        {"level", _v("Error")},
         {"appenders", _property({
-          {"ref", _value("Console")}
+          {"ref", _v("Console")}
         })}
       })}
     })}
   })};
   
-  properties::operator std::string const &() const {
-    expects(type == STRING, invalid_property_type, "expected STRING");
-    return value;
+  bool properties::contains(std::string const & key) const {
+    return data.is<object_t>() && object().count(key);
+  }
+  
+  bool properties::contains(std::size_t idx) const {
+    return data.is<array_t>() && array().size() < idx;
   }
+  
+  object_t const & properties::object() const {
+    expects(data.is<object_t>(), invalid_property_type, "expected OBJECT");
+    return data.get<object_t>();
+  }
+  
+  array_t const & properties::array() const {
+    expects(data.is<array_t>(), invalid_property_type, "expected ARRAY");
+    return data.get<array_t>();
+  }
+
+  properties const & properties::operator[](std::string const & key) const {
+    expects(data.is<object_t>(), invalid_property_type, "expected OBJECT");
+    expects(contains(key), missing_property, "Missing key: " + key);
+    return object().at(key);
+  }
+
   properties const & properties::operator[](std::size_t idx) const {
-    expects(type == ARRAY, invalid_property_type, "expected ARRAY");
-    expects(idx < array.size(), missing_property,
+    expects(data.is<array_t>(), invalid_property_type, "expected ARRAY");
+    expects(contains(idx), missing_property,
             "Out of bounds: " + std::to_string(idx));
-    return array.at(idx);
+    return array().at(idx);
   }
-  properties const & properties::operator[](std::string const & key) const {
-    expects(type == OBJECT, invalid_property_type, "expected OBJECT");
-    expects(obj.find(key) != obj.end(), missing_property,
-            "Missing key: " + key);
-    return obj.at(key);
+  
+  properties::operator std::string const &() const {
+    expects(data.is<std::string>(), invalid_property_type, "expected STRING");
+    return data.get<std::string>();
   }
+  
+  properties::operator int() const {
+    expects(data.is<int>(), invalid_property_type, "expected INT");
+    return data.get<int>();
+  }
+  
+  properties::operator bool() const {
+    expects(data.is<bool>(), invalid_property_type, "expected BOOL");
+    return data.get<bool>();
+  }
+  
+  std::string const & properties::str() const { return *this; }
+
 }

+ 15 - 21
test/test_properties.cxx

@@ -10,15 +10,9 @@
 using logging::properties;
 
 namespace {
-  properties _property(std::map<std::string, properties> const& m) {
-    return properties{properties::OBJECT, m, {}, {}};
-  }
-  properties _list(std::vector<properties> const& l) {
-    return properties{properties::ARRAY, {}, l, {}};
-  }
-  properties _value(std::string const& s) {
-    return properties{properties::STRING, {}, {}, s};
-  }
+  properties _property(logging::object_t const& m) { return {m}; }
+  properties _list(logging::array_t const& l) { return {l}; }
+  properties _v(std::string const & t) { return {t}; }
 }
 
 extern properties const APPENDER_LEVEL_PROPERTY_SCHEMA;
@@ -30,13 +24,13 @@ properties const MIN_PROPERTY_SCHEMA{_property({
   {"configuration", _property({
     {"appenders", _property({
       {"Mock", _property({
-        {"MockLayout", _value("")}
+        {"MockLayout", _v("")}
       })}
     })},
     {"loggers", _property({
       {"root", _property({
         {"appenders", _property({
-          {"ref", _value("Mock")}
+          {"ref", _v("Mock")}
         })}
       })}
     })}
@@ -47,14 +41,14 @@ properties const APPENDER_LEVEL_PROPERTY_SCHEMA{_property({
   {"configuration", _property({
     {"appenders", _property({
       {"Mock", _property({
-        {"level", _value("Warning")},
-        {"MockLayout", _value("")}
+        {"level", _v("Warning")},
+        {"MockLayout", _v("")}
       })}
     })},
     {"loggers", _property({
       {"root", _property({
         {"appenders", _property({
-          {"ref", _value("Mock")}
+          {"ref", _v("Mock")}
         })}
       })}
     })}
@@ -65,15 +59,15 @@ properties const LOGGER_LEVEL_PROPERTY_SCHEMA{_property({
   {"configuration", _property({
     {"appenders", _property({
       {"Mock", _property({
-        {"level", _value("Warning")},
-        {"MockLayout", _value("")}
+        {"level", _v("Warning")},
+        {"MockLayout", _v("")}
       })}
     })},
     {"loggers", _property({
       {"root", _property({
-        {"level", _value("Error")},
+        {"level", _v("Error")},
         {"appenders", _property({
-          {"ref", _value("Mock")}
+          {"ref", _v("Mock")}
         })}
       })}
     })}
@@ -84,14 +78,14 @@ properties const MULTIPLEX_PROPERTY_SCHEMA{_property({
   {"configuration", _property({
     {"appenders", _property({
       {"Mock", _property({
-        {"MockLayout", _value("")}
+        {"MockLayout", _v("")}
       })}
     })},
     {"loggers", _property({
       {"root", _property({
         {"appenders", _list({
-          _property({{"ref", _value("Mock")}}),
-          _property({{"ref", _value("Mock")}})
+          _property({{"ref", _v("Mock")}}),
+          _property({{"ref", _v("Mock")}})
         })}
       })}
     })}