Simple-Log  alpha-v0.7
StringPattern.hpp
Go to the documentation of this file.
1 // Copyright Dominic Koepke 2021 - 2021.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE_1_0.txt or copy at
4 // https://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef SL_LOG_STRING_PATTERN_HPP
7 #define SL_LOG_STRING_PATTERN_HPP
8 
9 #pragma once
10 
11 #include <algorithm>
12 #include <charconv>
13 #include <chrono>
14 #include <iomanip>
15 #include <regex>
16 #include <sstream>
17 #include <variant>
18 
19 namespace sl::log::detail
20 {
21  struct IncNumberGenerator
22  {
23  unsigned minWidth = 0;
24  unsigned current = 1;
25 
26  void operator()(std::ostream& stream)
27  {
28  stream << std::setfill('0') << std::setw(minWidth) << current++;
29  }
30  };
31 
32  // ToDo: modernize with c++20 chrono features
33  struct DateTimeGenerator
34  {
35  std::string token;
36 
37  void operator()(std::ostream& stream) const
38  {
39  const auto now = std::chrono::system_clock::now();
40  auto t_c = std::chrono::system_clock::to_time_t(now);
41  stream << std::put_time(std::localtime(&t_c), token.c_str());
42  }
43  };
44 
45  struct StringGenerator
46  {
47  std::string_view str;
48 
49  void operator()(std::ostream& stream) const
50  {
51  stream << str;
52  }
53  };
54 
55  using Generator = std::variant<StringGenerator, IncNumberGenerator, DateTimeGenerator>;
56 
57  [[nodiscard]] inline Generator makeGeneratorFromMatch(std::string_view token)
58  {
59  if (token.starts_with('%'))
60  {
61  // ReSharper disable once CppDefaultCaseNotHandledInSwitchStatement
62  switch (token.back())
63  {
64  case 'H': // hour (2 digits)
65  case 'M': // minute (2 digits)
66  case 'S': // second (2 digits)
67 
68  case 'Y': // year (4 digits)
69  case 'm': // month (2 digits)
70  case 'd': // day of month (2 digits)
71  case 'j': // day of year (3 digits)
72  return DateTimeGenerator{ { std::cbegin(token), std::cbegin(token) + 2 } };
73 
74  case 'N':
75  token.remove_prefix(1);
76  unsigned width = 0;
77  std::from_chars(token.data(), &token.back(), width);
78  return IncNumberGenerator{ .minWidth = width };
79  }
80  }
81 
82  // treat everything else as const substring, even if it contains a %
83  return StringGenerator{ token };
84  }
85 
86  [[nodiscard]] inline std::vector<Generator> makeTokenGeneratorsFromPatternString(std::string_view patternString)
87  {
88  std::vector<Generator> generators;
89 
90  // ToDo: use ranges
91  const std::regex regEx{ "%(Y|m|d|H|M|S|j|\\d*N)" };
92  std::for_each(
93  std::cregex_token_iterator
94  {
95  patternString.data(),
96  patternString.data() + std::size(patternString),
97  regEx,
98  { -1, 0 }
99  },
100  std::cregex_token_iterator{},
101  [&generators](const auto& match)
102  {
103  if (match.length() != 0)
104  {
105  generators.emplace_back(makeGeneratorFromMatch({ match.first, match.second }));
106  }
107  }
108  );
109  return generators;
110  }
111 }
112 
113 namespace sl::log
114 {
120  {
121  public:
125  StringPattern() noexcept = default;
126 
131  explicit StringPattern(std::string patternString) :
132  m_PatternString{ std::move(patternString) },
133  m_TokenGenerators{ detail::makeTokenGeneratorsFromPatternString(m_PatternString) }
134  {
135  }
136 
142  std::string next()
143  {
144  std::ostringstream ss;
145  for (auto& token : m_TokenGenerators)
146  {
147  std::visit(
148  [&ss](auto& generator)
149  {
150  generator(ss);
151  },
152  token
153  );
154  }
155  return std::move(ss).str();
156  }
157 
162  [[nodiscard]]
163  std::string_view patternString() const noexcept
164  {
165  return m_PatternString;
166  }
167 
172  void setPatternString(std::string patternString)
173  {
174  m_PatternString = std::move(patternString);
175  m_TokenGenerators = detail::makeTokenGeneratorsFromPatternString(m_PatternString);
176  }
177 
178  private:
179  std::string m_PatternString;
180  std::vector<detail::Generator> m_TokenGenerators;
181  };
182 }
183 
184 #endif
Helper class for generating patterned strings.
Definition: StringPattern.hpp:120
void setPatternString(std::string patternString)
Sets the pattern string.
Definition: StringPattern.hpp:172
std::string_view patternString() const noexcept
Getter of the used pattern string.
Definition: StringPattern.hpp:163
StringPattern() noexcept=default
Default Constructor.
std::string next()
Creates a new string.
Definition: StringPattern.hpp:142
Definition: BasicSink.hpp:22