Browse Source

Switch to using a format_factory class to contain state better.

Sam Jaffe 5 years ago
parent
commit
32f4116f46
3 changed files with 100 additions and 77 deletions
  1. 37 11
      src/loggers/pattern_layout.h
  2. 20 18
      src/loggers/pattern_layout_date.cxx
  3. 43 48
      src/loggers/pattern_layout_format.cxx

+ 37 - 11
src/loggers/pattern_layout.h

@@ -15,22 +15,48 @@ namespace logging {
   struct logpacket;
   class format {
   public:
-    struct generator_t {
-      virtual ~generator_t() = default;
-      std::string str(logpacket const & lp) const;
-      virtual void write(logpacket const & lp, std::ostream & os) const = 0;
-    };
-  public:
-    enum class token_id {
-      DATE, PRIORITY, CATEGORY, MESSAGE, STRING, NEWLINE
-    };
-    
+    struct generator_t;
     using generator = std::shared_ptr<generator_t>;
+
+  private:
+    friend class format_factory;
+    std::vector<generator> gen;
     
+  public:
     static format parse_format_string(std::string const &);
     void process(logpacket const & pkt, std::ostream & os) const;
     std::string process(logpacket const & pkt) const;
+  };
+  
+  class format_factory {
   private:
-    std::vector<generator> gen;
+    std::string data_string_;
+    char const * curr_;
+    char const * const end_;
+    char const * next_ = nullptr;
+    std::vector<format::generator> generators_{};
+    
+  public:
+    format_factory(std::string const & str);
+    format create();
+    
+  private:
+    bool is(char c) const { return next_ && *next_ == c; }
+    bool is(char const * str) const {
+      return next_ && !strncmp(next_, str, strlen(str));
+    }
+    template <typename T, typename... Args> void append(Args &&... args) {
+      generators_.push_back(std::make_shared<T>(std::forward<Args>(args)...));
+    }
+    
+    void create_date();
+    void create_size_bounded();
+    format::generator create_impl();
+  };
+  
+  struct format::generator_t {
+    virtual ~generator_t() = default;
+    std::string str(logpacket const & lp) const;
+    virtual void write(logpacket const & lp, std::ostream & os) const = 0;
   };
 }

+ 20 - 18
src/loggers/pattern_layout_date.cxx

@@ -35,9 +35,15 @@ static std::string fmt_time_with_milis(struct timeval round,
 }
 
 namespace logging {
-  struct time_gen : public format::generator_t {
+  class time_gen : public format::generator_t {
+  public:
     enum resolution { seconds, milis };
-    
+
+  private:
+    std::string predef_format;
+    resolution res;
+
+  public:
     time_gen(std::string const & pre, resolution res)
     : predef_format(pre), res(res) {}
     
@@ -48,18 +54,16 @@ namespace logging {
           break;
         case milis:
           os << fmt_time_with_milis(lp.time, predef_format);
-        break;
+          break;
       }
     }
-    std::string predef_format;
-    resolution res;
   };
 
-  format::generator parse_date_format_string(char const * str) {
+  time_gen parse_date_format_string(char const * str) {
     char const * const end = strchr(str, '}');
     if (end == nullptr) {
-      std::string error_msg{"expected date-format specifier to terminate"};
-      throw format_parsing_exception{error_msg};
+      throw format_parsing_exception{
+        "expected date-format specifier to terminate"};
     }
     std::string fmt(str, end);
     if (fmt.find("%_ms") != std::string::npos) {
@@ -69,25 +73,23 @@ namespace logging {
         pos += 2;
       }
       fmt.replace(fmt.find("%%_ms"), 5, "%.03d");
-      return std::make_shared<time_gen>(fmt, time_gen::milis);
+      return time_gen(fmt, time_gen::milis);
     } else {
-      return std::make_shared<time_gen>(fmt, time_gen::seconds);
+      return time_gen(fmt, time_gen::seconds);
     }
   }
   
-#define is( chr ) *next == chr
-#define is_string( str ) ! strncmp(next, str, strlen(str))
-  format::generator date_token(char const * next) {
+  void format_factory::create_date() {
     std::string predef_format = "%%Y-%%m-%%d %%H:%%M:%%S,%.03d";
-    if (is_string("{ISO8601}")) {
+    if (is("{ISO8601}")) {
       predef_format = "%%Y-%%m-%%dT%%H:%%M:%%S.%.03dZ";
-    } else if (is_string("{ABSOLUTE}")) {
+    } else if (is("{ABSOLUTE}")) {
       predef_format = "%%H:%%M:%%S,%.03d";
-    } else if (is_string("{DATE}")) {
+    } else if (is("{DATE}")) {
       predef_format = "%%d %%b %%Y %%H:%%M:%%S,%.03d";
     } else if (is('{')) {
-      return parse_date_format_string(next+1);
+      return append<time_gen>(parse_date_format_string(next_+1));
     }
-    return std::make_shared<time_gen>(predef_format, time_gen::milis);
+    append<time_gen>(predef_format, time_gen::milis);
   }
 }

+ 43 - 48
src/loggers/pattern_layout_format.cxx

@@ -153,8 +153,7 @@ namespace logging {
   
   format::generator date_token(char const * next);
 
-  format::generator handle( char const * & next ) {
-    auto is = [&next](char c) { return *next == c; };
+  format::generator format_factory::create_impl() {
     if (is('c')) {
       return std::make_shared<log_handle_gen>();
     } else if (is('p')) {
@@ -164,8 +163,8 @@ namespace logging {
     } else if (is('t')) {
       return std::make_shared<thread_name_gen>();
     } else {
-      std::string error_msg{"unknown format character: '"};
-      throw unknown_format_specifier{error_msg + *next + "'"};
+      throw unknown_format_specifier{std::string("unknown format character: '")
+        + *next_ + "'"};
     }
   }
   
@@ -176,71 +175,67 @@ namespace logging {
     return rval;
   }
   
-  std::pair<int, size_t> get_bounds(char const * & next) {
-    int min = *next == '.' ? 0 : eat(next);
-    size_t max = *next == '.' ? eat(++next) : std::string::npos;
-    return std::make_pair(min, max);
-  }
-  
-  format::generator parse_with_bounds(char const * & next) {
-    bool const is_left = *next == '-';
-    if (is_left) ++next;
+  void format_factory::create_size_bounded() {
+    bool const is_left = is('-');
+    if (is_left) ++next_;
     
-    auto bounds = get_bounds(next);
+    int const min = is('.') ? 0 : eat(next_);
+    size_t const max = is('.') ? eat(++next_) : std::string::npos;
     
-    bounds_gen gen{handle(next), is_left, bounds.first, bounds.second};
-    return std::make_shared<bounds_gen>(gen);
+    append<bounds_gen>(create_impl(), is_left, min, max);
   }
   
-  format format::parse_format_string( std::string const & fmt ) {
-    format out;
-    char const * curr = fmt.c_str();
-    char const * next = nullptr;
-    char const * const end = curr + fmt.size();
-    auto is = [&next](char c) { return *next == c; };
-    
-    while ((next = std::strchr(curr, '%')) != nullptr) {
-      ++next;
-      if (end == next) {
-        std::string error_msg{"expected format specifier, got end of string"};
-        throw format_parsing_exception{error_msg}; // TODO
+  format format_factory::create() {
+    while ((next_ = std::strchr(curr_, '%')) != nullptr) {
+      ++next_;
+      if (end_ == next_) {
+        throw format_parsing_exception{
+          "expected format specifier, got end of string"};
       }
       
-      if (curr < next-1) {
-        std::string lit{curr, next - 1};
-        out.gen.push_back(std::make_shared<literal_gen>(lit));
+      if (curr_ < next_ - 1) {
+        append<literal_gen>(std::string(curr_, next_ - 1));
       }
 
       if (is('d')) {
-        ++next;
-        out.gen.push_back(date_token(next));
-        if (is('{')) next = std::strchr(next, '}');
+        ++next_;
+        create_date();
+        if (is('{')) next_ = std::strchr(next_, '}');
       } else if (is('n')) {
-        out.gen.push_back(std::make_shared<literal_gen>(NEWLINE_TOKEN));
+        append<literal_gen>(NEWLINE_TOKEN);
       } else if (is('%')) {
-        out.gen.push_back(std::make_shared<literal_gen>("%"));
-      } else if (is('.') || is('-') || isdigit( *next )) {
-        out.gen.push_back(parse_with_bounds(next));
+        append<literal_gen>("%");
+      } else if (is('.') || is('-') || isdigit(*next_)) {
+        create_size_bounded();
       } else if (is('C')) {
-        out.gen.push_back(std::make_shared<class_info_gen>(++next));
-        if (is('{')) next = std::strchr(next, '}');
+        append<class_info_gen>(++next_);
+        if (is('{')) next_ = std::strchr(next_, '}');
       } else if (is('F') || is('M') || is('L') || is('l')) {
-        out.gen.push_back(std::make_shared<location_info_gen>(*next));
+        append<location_info_gen>(*next_);
       } else if (is('r')) {
-        out.gen.push_back(std::make_shared<time_elapsed_gen>());
+        append<time_elapsed_gen>();
       } else {
-        out.gen.push_back(handle(next));
+        generators_.push_back(create_impl());
       }
-      curr = ++next;
+      curr_ = ++next_;
     }
-    if (curr < end) {
-      std::string lit{curr, end};
-      out.gen.push_back(std::make_shared<literal_gen>(lit));
+    if (curr_ < end_) {
+      append<literal_gen>(std::string(curr_, end_));
     }
+    
+    format out;
+    out.gen = generators_;
     return out;
   }
-#undef is
   
+  format_factory::format_factory(std::string const & fmt)
+    : data_string_(fmt), curr_(data_string_.c_str()),
+      end_(curr_ + data_string_.size()){}
+
+  format format::parse_format_string(std::string const & fmt) {
+    return format_factory(fmt).create();
+  }
+
   void format::process(logpacket const & pkt, std::ostream & os) const {
     for (auto func : gen) { func->write(pkt, os); }
   }