Simple-Log  alpha-v0.7
FlushPolicies.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_FLUSH_POLICIES_HPP
7 #define SL_LOG_FLUSH_POLICIES_HPP
8 
9 #pragma once
10 
11 #include "Record.hpp"
12 #include "TupleAlgorithms.hpp"
13 
14 #include <chrono>
15 #include <concepts>
16 #include <cstddef>
17 #include <functional>
18 #include <type_traits>
19 #include <utility>
20 
21 namespace sl::log
22 {
26  template <class T, class TRecord>
27  concept FlushPolicyFor =
28  Record<TRecord> &&
29  std::predicate<T, const TRecord&, std::size_t> &&
30  requires(T policy)
31  {
32  { policy.flushed() };
33  };
34 }
35 
36 namespace sl::log::detail
37 {
38  template <Record TRecord>
39  class AbstractFlushPolicyWrapper
40  {
41  public:
42  using Record_t = std::remove_cvref_t<TRecord>;
43 
44  virtual ~AbstractFlushPolicyWrapper() noexcept = default;
45 
46  AbstractFlushPolicyWrapper(const AbstractFlushPolicyWrapper&) = delete;
47  AbstractFlushPolicyWrapper& operator =(const AbstractFlushPolicyWrapper&) = delete;
48  AbstractFlushPolicyWrapper(AbstractFlushPolicyWrapper&&) = delete;
49  AbstractFlushPolicyWrapper& operator =(AbstractFlushPolicyWrapper&&) = delete;
50 
51  virtual bool operator ()(const Record_t& record, std::size_t messageByteSize) = 0;
52  virtual void flushed() = 0;
53 
54  protected:
55  AbstractFlushPolicyWrapper() noexcept = default;
56  };
57 
58  template <Record TRecord, FlushPolicyFor<TRecord> TFlushPolicy>
59  class FlushPolicyWrapper final :
60  public AbstractFlushPolicyWrapper<TRecord>
61  {
62  using Super = AbstractFlushPolicyWrapper<TRecord>;
63  public:
64  using typename Super::Record_t;
65  using FlushPolicy_t = std::remove_reference_t<TFlushPolicy>;
66 
67  explicit FlushPolicyWrapper() noexcept(std::is_nothrow_constructible_v<FlushPolicy_t>) :
68  m_FlushPolicy{}
69  {
70  }
71 
72  explicit FlushPolicyWrapper(TFlushPolicy flushPolicy) noexcept(std::is_nothrow_move_constructible_v<FlushPolicy_t>) :
73  m_FlushPolicy{ std::move(flushPolicy) }
74  {
75  }
76 
77  bool operator ()(const Record_t& record, std::size_t messageByteSize) override
78  {
79  return std::invoke(m_FlushPolicy, record, messageByteSize);
80  }
81 
82  void flushed() override
83  {
84  m_FlushPolicy.flushed();
85  }
86 
87  private:
88  FlushPolicy_t m_FlushPolicy;
89  };
90 
91  template <auto VConstant>
92  struct ConstantInvokable
93  {
94  template <class... TArgs>
95  constexpr auto operator()(TArgs&&...) const noexcept
96  {
97  return VConstant;
98  }
99  };
100 
101  struct PredProjInvocation
102  {
103  template <class TPredicate, class TProjection, class TProjected, class... TArgs>
104  constexpr auto operator ()(TPredicate& pred, TProjection& proj, const TProjected& projected, TArgs&&... args) const
105  {
106  return std::invoke(pred, std::invoke(proj, projected), std::forward<TArgs>(args)...);
107  }
108  };
109 
110  struct PredProjInvocationIgnoreArgs
111  {
112  template <class TPredicate, class TProjection, class TProjected, class... TArgs>
113  constexpr auto operator ()(TPredicate& pred, TProjection& proj, const TProjected& projected, TArgs&&...) const
114  {
115  return std::invoke(pred, std::invoke(proj, projected));
116  }
117  };
118 }
119 
120 namespace sl::log
121 {
142  template <class TPredicate, class TProjection = std::identity, class TInvocationRule = detail::PredProjInvocation>
144  {
145  public:
146  using Predicate_t = std::remove_cvref_t<TPredicate>;
147  using Projection_t = std::remove_cvref_t<TProjection>;
148  using InvocationRule_t = std::remove_cvref_t<TInvocationRule>;
149 
156  explicit FlushPolicy(
157  TPredicate predicate = Predicate_t{},
158  TProjection projection = Projection_t{},
159  TInvocationRule invocation = InvocationRule_t{}
160  )
161  noexcept(std::is_nothrow_move_constructible_v<TPredicate> && std::is_nothrow_move_constructible_v<TProjection> &&
162  std::is_nothrow_move_constructible_v<TInvocationRule>) :
163  m_Predicate{ std::move(predicate) },
164  m_Projection{ std::move(projection) },
165  m_Invocation{ std::move(invocation) }
166  {
167  }
168 
176  template <class... TArgs>
177  requires std::constructible_from<Predicate_t, TArgs...>
178  explicit FlushPolicy(
179  std::in_place_t _,
180  TArgs&&... args
181  )
182  noexcept(std::is_nothrow_constructible_v<TPredicate, TArgs...> && std::is_nothrow_constructible_v<TProjection> &&
183  std::is_nothrow_constructible_v<TInvocationRule>) :
184  m_Predicate{ std::forward<TArgs>(args)... }
185  {
186  }
187 
196  template <Record TRecord>
197  bool operator ()(const TRecord& record, std::size_t messageByteSize)
198  {
199  return m_Invocation(m_Predicate, m_Projection, record, messageByteSize);
200  }
201 
205  constexpr void flushed() const noexcept
206  {
207  }
208 
209  private:
210  Predicate_t m_Predicate;
211  Projection_t m_Projection;
212  //[[no_unique_address]]
213  InvocationRule_t m_Invocation;
214  };
215 
222  template <class TAlgorithm, class... TFlushPolicies>
224  {
225  public:
226  using Algorithm_t = TAlgorithm;
227 
232  constexpr explicit FlushPolicyChain(
233  TFlushPolicies ... policies
234  )
235  noexcept(std::is_nothrow_constructible_v<Algorithm_t> && (std::is_nothrow_move_constructible_v<TFlushPolicies> && ...)) :
236  m_Algorithm{},
237  m_Policies{ std::move(policies)... }
238  {
239  }
240 
246  constexpr explicit FlushPolicyChain(
247  TAlgorithm algorithm,
248  TFlushPolicies ... policies
249  )
250  noexcept(std::is_nothrow_move_constructible_v<Algorithm_t> && (std::is_nothrow_move_constructible_v<TFlushPolicies> && ...
251  )
252  ) :
253  m_Algorithm{ std::move(algorithm) },
254  m_Policies{ std::forward<TFlushPolicies>(policies)... }
255  {
256  }
257 
266  template <Record TRecord>
267  bool operator ()(const TRecord& record, std::size_t messageByteSize)
268  {
269  return std::invoke(m_Algorithm, m_Policies, record, messageByteSize);
270  }
271 
275  constexpr void flushed()
276  {
277  detail::TupleForEach{}(
278  m_Policies,
279  [](auto&& policy)
280  {
281  policy.flushed();
282  }
283  );
284  }
285 
290  [[nodiscard]]
291  constexpr bool empty() const noexcept
292  {
293  return std::tuple_size_v<decltype(m_Policies)> == 0;
294  }
295 
300  [[nodiscard]]
301  constexpr std::size_t size() const noexcept
302  {
303  return std::tuple_size_v<decltype(m_Policies)>;
304  }
305 
306  private:
307  Algorithm_t m_Algorithm;
308  std::tuple<TFlushPolicies...> m_Policies;
309  };
310 
315  template <class... TFlushPolicies>
317  public FlushPolicyChain<detail::TupleAllOf, TFlushPolicies...>
318  {
319  using Algorithm_t = detail::TupleAllOf;
320 
321  public:
326  constexpr explicit FlushPolicyAllOf(
327  TFlushPolicies ... policies
328  )
329  noexcept((std::is_nothrow_move_constructible_v<TFlushPolicies> && ...)) :
330  FlushPolicyChain<Algorithm_t, TFlushPolicies...>{ std::move(policies)... }
331  {
332  }
333  };
334 
339  template <class... TFlushPolicies>
341  public FlushPolicyChain<detail::TupleAnyOf, TFlushPolicies...>
342  {
343  using Algorithm_t = detail::TupleAnyOf;
344 
345  public:
350  constexpr explicit FlushPolicyAnyOf(
351  TFlushPolicies ... policies
352  )
353  noexcept((std::is_nothrow_move_constructible_v<TFlushPolicies> && ...)) :
354  FlushPolicyChain<Algorithm_t, TFlushPolicies...>{ std::move(policies)... }
355  {
356  }
357  };
358 
363  template <class... TFlushPolicies>
365  public FlushPolicyChain<detail::TupleNoneOf, TFlushPolicies...>
366  {
367  using Algorithm_t = detail::TupleNoneOf;
368 
369  public:
374  constexpr explicit FlushPolicyNoneOf(
375  TFlushPolicies ... policies
376  )
377  noexcept((std::is_nothrow_move_constructible_v<TFlushPolicies> && ...)) :
378  FlushPolicyChain<Algorithm_t, TFlushPolicies...>{ std::move(policies)... }
379  {
380  }
381  };
382 
387 
398  template <Record TRecord, std::predicate<const RecordMessage_t<TRecord>&> TUnaryPredicate>
399  constexpr auto makeMessageFlushPolicyFor(TUnaryPredicate&& predicate)
400  {
401  return FlushPolicy{
402  std::forward<TUnaryPredicate>(predicate),
404  detail::PredProjInvocationIgnoreArgs{}
405  };
406  }
407 
418  template <Record TRecord, std::predicate<const RecordSeverity_t<TRecord>&> TUnaryPredicate>
419  constexpr auto makeSeverityFlushPolicyFor(TUnaryPredicate&& predicate)
420  {
421  return FlushPolicy{
422  std::forward<TUnaryPredicate>(predicate),
424  detail::PredProjInvocationIgnoreArgs{}
425  };
426  }
427 
438  template <Record TRecord, std::predicate<const RecordChannel_t<TRecord>&> TUnaryPredicate>
439  constexpr auto makeChannelFlushPolicyFor(TUnaryPredicate&& predicate)
440  {
441  return FlushPolicy{
442  std::forward<TUnaryPredicate>(predicate),
444  detail::PredProjInvocationIgnoreArgs{}
445  };
446  }
447 
458  template <Record TRecord, std::predicate<const RecordTimePoint_t<TRecord>&> TUnaryPredicate>
459  constexpr auto makeTimePointFlushPolicyFor(TUnaryPredicate&& predicate)
460  {
461  return FlushPolicy{
462  std::forward<TUnaryPredicate>(predicate),
464  detail::PredProjInvocationIgnoreArgs{}
465  };
466  }
467 
475  {
476  public:
477  using Duration_t = std::chrono::milliseconds;
478  using Clock_t = std::chrono::steady_clock;
479  using TimePoint_t = Clock_t::time_point;
480 
488  template <class TRep, class TPeriod>
489  explicit TimedFlushPolicy(std::chrono::duration<TRep, TPeriod> duration) :
490  m_Duration{ std::chrono::duration_cast<Duration_t>(duration) }
491  {
492  }
493 
501  template <Record TRecord>
502  bool operator ()(const TRecord& record, std::size_t messageByteSize) noexcept
503  {
504  const auto now = Clock_t::now();
505  return m_Duration <= now - m_StartPoint;
506  }
507 
511  void flushed() noexcept
512  {
513  m_StartPoint = Clock_t::now();
514  }
515 
516  private:
517  TimePoint_t m_StartPoint = Clock_t::now();
518  Duration_t m_Duration;
519  };
520 
526  {
527  public:
532  explicit ByteCountFlushPolicy(std::size_t byteThreshold) noexcept :
533  m_ByteThreshold{ byteThreshold }
534  {
535  }
536 
544  template <Record TRecord>
545  bool operator ()(const TRecord& record, std::size_t messageByteSize) noexcept
546  {
547  m_ByteCount += messageByteSize;
548  return m_ByteThreshold <= m_ByteCount;
549  }
550 
554  void flushed() noexcept
555  {
556  m_ByteCount = 0;
557  }
558 
559  private:
560  std::size_t m_ByteThreshold;
561  std::size_t m_ByteCount = 0;
562  };
563 
565 }
566 
567 #endif
A Flush-Policy which acts on accumulated byte count.
Definition: FlushPolicies.hpp:526
void flushed() noexcept
Resets the internal byte counter.
Definition: FlushPolicies.hpp:554
ByteCountFlushPolicy(std::size_t byteThreshold) noexcept
Constructor.
Definition: FlushPolicies.hpp:532
Convenience type for chaining multiple FlushPolicies with AND.
Definition: FlushPolicies.hpp:318
constexpr FlushPolicyAllOf(TFlushPolicies ... policies) noexcept((std::is_nothrow_move_constructible_v< TFlushPolicies > &&...))
Constructor.
Definition: FlushPolicies.hpp:326
Convenience type for chaining multiple FlushPolicies with OR.
Definition: FlushPolicies.hpp:342
constexpr FlushPolicyAnyOf(TFlushPolicies ... policies) noexcept((std::is_nothrow_move_constructible_v< TFlushPolicies > &&...))
Constructor.
Definition: FlushPolicies.hpp:350
Chains multiple FlushPolicy objects together.
Definition: FlushPolicies.hpp:224
constexpr void flushed()
Calls flushed on all FlushPolicy objects.
Definition: FlushPolicies.hpp:275
constexpr FlushPolicyChain(TAlgorithm algorithm, TFlushPolicies ... policies) noexcept(std::is_nothrow_move_constructible_v< Algorithm_t > &&(std::is_nothrow_move_constructible_v< TFlushPolicies > &&...))
Constructor overload.
Definition: FlushPolicies.hpp:246
constexpr std::size_t size() const noexcept
Obtains the amount of attached FlushPolicy objects.
Definition: FlushPolicies.hpp:301
constexpr bool empty() const noexcept
Returns whether the are no FlushPolicy objects attached.
Definition: FlushPolicies.hpp:291
constexpr FlushPolicyChain(TFlushPolicies ... policies) noexcept(std::is_nothrow_constructible_v< Algorithm_t > &&(std::is_nothrow_move_constructible_v< TFlushPolicies > &&...))
Constructor.
Definition: FlushPolicies.hpp:232
TAlgorithm Algorithm_t
Definition: FlushPolicies.hpp:226
A customizable FlushPolicy class.
Definition: FlushPolicies.hpp:144
std::remove_cvref_t< TPredicate > Predicate_t
Definition: FlushPolicies.hpp:146
requires std::constructible_from< Predicate_t, TArgs... > FlushPolicy(std::in_place_t _, TArgs &&... args) noexcept(std::is_nothrow_constructible_v< TPredicate, TArgs... > &&std::is_nothrow_constructible_v< TProjection > &&std::is_nothrow_constructible_v< TInvocationRule >)
Constructor overload for in_place predicate initializing.
Definition: FlushPolicies.hpp:178
constexpr void flushed() const noexcept
NoOp.
Definition: FlushPolicies.hpp:205
std::remove_cvref_t< TInvocationRule > InvocationRule_t
Definition: FlushPolicies.hpp:148
FlushPolicy(TPredicate predicate=Predicate_t{}, TProjection projection=Projection_t{}, TInvocationRule invocation=InvocationRule_t{}) noexcept(std::is_nothrow_move_constructible_v< TPredicate > &&std::is_nothrow_move_constructible_v< TProjection > &&std::is_nothrow_move_constructible_v< TInvocationRule >)
Constructor.
Definition: FlushPolicies.hpp:156
std::remove_cvref_t< TProjection > Projection_t
Definition: FlushPolicies.hpp:147
Convenience type for chaining multiple FlushPolicies with NOR.
Definition: FlushPolicies.hpp:366
constexpr FlushPolicyNoneOf(TFlushPolicies ... policies) noexcept((std::is_nothrow_move_constructible_v< TFlushPolicies > &&...))
Constructor.
Definition: FlushPolicies.hpp:374
A Flush-Policy which acts on a durations.
Definition: FlushPolicies.hpp:475
void flushed() noexcept
Restarts the internal duration clock.
Definition: FlushPolicies.hpp:511
TimedFlushPolicy(std::chrono::duration< TRep, TPeriod > duration)
Constructs the object with the specified duration threshold.
Definition: FlushPolicies.hpp:489
std::chrono::steady_clock Clock_t
Definition: FlushPolicies.hpp:478
Clock_t::time_point TimePoint_t
Definition: FlushPolicies.hpp:479
std::chrono::milliseconds Duration_t
Definition: FlushPolicies.hpp:477
constexpr auto makeChannelFlushPolicyFor(TUnaryPredicate &&predicate)
Factory function for creating Flush-Policies based on Record::channel member.
Definition: FlushPolicies.hpp:439
constexpr auto makeSeverityFlushPolicyFor(TUnaryPredicate &&predicate)
Factory function for creating Flush-Policies based on Record::severity member.
Definition: FlushPolicies.hpp:419
constexpr auto makeTimePointFlushPolicyFor(TUnaryPredicate &&predicate)
Factory function for creating Flush-Policies based on Record::timePoint member.
Definition: FlushPolicies.hpp:459
constexpr auto makeMessageFlushPolicyFor(TUnaryPredicate &&predicate)
Factory function for creating Flush-Policies based on Record::message member.
Definition: FlushPolicies.hpp:399
BaseRecord< SevLvl, std::string > Record_t
Prepared Record type.
Definition: PresetTypes.hpp:52
concept Record
Concept which all the necessary concepts for Record types.
Definition: Record.hpp:204
Definition: BasicSink.hpp:22
concept FlushPolicyFor
Concept for invokable flush policies.
Definition: FlushPolicies.hpp:27
Provides a layer of abstraction to Record member setter.
Definition: Record.hpp:118