bux API Reference 1.9.0
Static library of whatever are seen required in general purpose but not directly supported from Modern C++. Or whatever reusable originated from my side projects.
Loading...
Searching...
No Matches
ParaLog.h
Go to the documentation of this file.
1#pragma once
2
3#include "SyncLog.h" // bux::I_SyncLog, bux::I_ReenterableLog, bux::C_ReenterableOstream
4#include <concepts> // std::derived_from<>, std::convertible_to<>
5#include <functional> // std::function<>
6#include <list> // std::list<>
7#include <memory> // std::unique_ptr<>
8#include <sstream> // std::ostringstream
9#include <string_view> // std::string_view
10#include <vector> // std::vector<>
11
12namespace bux {
13
14//
15// Types
16//
17class C_ParaLog: public I_SyncLog
22{
23public:
24
25 // Data
26 class C_NodeProxy;
27 class C_NodeArrayProxy;
28
29 // Nonvirtuals
30 explicit C_ParaLog(const std::chrono::time_zone *tz_ = nullptr): I_SyncLog(tz_) {}
31 explicit C_ParaLog(bool use_local_time): C_ParaLog(use_local_time? std::chrono::get_tzdb().current_zone(): nullptr) {}
32 template<class...T_Args>
33 bool addChild(T_Args&&...args);
34 template<class C_LogImpl, class C_Holder = typename C_AutoSinkHolderT<C_LogImpl>::type, class...T_Args>
35 bool addChildT(std::function<void(C_LogImpl&)> post_ctor = {}, E_LogLevel ll = LL_VERBOSE, T_Args&&...args);
36 template<typename F>
37 [[nodiscard]]C_NodeArrayProxy partitionBy(F f);
38
39 // Implement I_SyncLog
40 std::ostream *lockLog() override;
41 std::ostream *lockLog(E_LogLevel ll) override;
42 void unlockLog(bool flush) override;
43
44private:
45
46 // Types
47 struct C_Node;
48
49 using FC_Accept = std::function<bool(std::string_view)>;
50 using C_NodePtr = std::unique_ptr<C_Node>;
51
52 struct C_NodePartition
53 {
54 std::vector<std::pair<FC_Accept,C_NodePtr>> m_filteredNodes;
55 C_NodePtr m_elseNode;
56 };
57
58 struct C_Node
59 {
60 std::vector<std::unique_ptr<I_ReenterableLog>> m_loggers;
61 std::list<C_NodePartition> m_partitions;
62 };
63 friend class C_NodeProxy;
64
65 struct C_LockedNodePartition;
66
67 struct C_LockedNode
68 {
69 std::vector<std::pair<I_ReenterableLog*,std::ostream*>> m_loggers;
70 std::vector<C_LockedNodePartition> m_partitions;
71
72 void create_from(const C_Node &node, const std::function<std::ostream*(I_ReenterableLog&)> &to_log);
73 bool empty() const { return m_loggers.empty() && m_partitions.empty(); }
74 void log(std::string_view s, bool flush) const;
75 };
76
77 struct C_LockedNodePartition
78 {
79 std::vector<std::pair<const FC_Accept&,C_LockedNode>> m_filteredNodes;
80 C_LockedNode m_elseNode;
81
82 bool empty() const { return m_filteredNodes.empty() && m_elseNode.empty(); }
83 };
84
85 // Data
86 std::recursive_mutex m_lock;
87 C_Node m_root;
88 std::list<std::pair<C_LockedNode,std::ostringstream>> m_lockedStack;
89
90 // Nonvirtuals
91 std::ostream *lockLog(const std::function<std::ostream*(I_ReenterableLog&)> &to_log);
92};
93
95{
96public:
97
98 // Nonvirtuals
99 C_NodeArrayProxy(std::recursive_mutex &lock, C_NodePartition &nodePart): m_lock(&lock), m_nodePart(&nodePart) {}
100 [[nodiscard]]C_NodeProxy operator[](size_t i) const;
101 [[nodiscard]]C_NodeProxy matchedNone() const;
102 size_t sizeOfFilters() const { return m_nodePart->m_filteredNodes.size(); }
103
104private:
105
106 // Data
107 std::recursive_mutex *m_lock;
108 C_NodePartition *m_nodePart;
109
110 // Nonvirtuals
111 C_NodeProxy create_proxy(C_NodePtr &holder) const;
112};
113
115{
116public:
117
118 // Nonvirtuals
119 C_NodeProxy(std::recursive_mutex &lock, C_Node &node): m_lock(&lock), m_node(&node) {}
120 template<std::derived_from<I_ReenterableLog> T>
121 bool addChild(std::unique_ptr<T> &&snap) const
122 {
123 std::lock_guard _{*m_lock};
124 if (snap)
125 {
126 m_node->m_loggers.emplace_back(std::move(snap));
127 return true;
128 }
129 return false;
130 }
131 bool addChild(std::ostream &out, E_LogLevel ll = LL_VERBOSE) const
132 {
133 return addChild(std::make_unique<C_ReenterableOstream>(out, ll));
134 }
135 bool addChild(I_SnapT<std::ostream*> &snap, E_LogLevel ll = LL_VERBOSE) const
136 {
137 return addChild(std::make_unique<C_ReenterableOstreamSnap>(snap, ll));
138 }
139 template<class C_LogImpl, class C_Holder = typename C_AutoSinkHolderT<C_LogImpl>::type, class...T_Args>
140 bool addChildT(std::function<void(C_LogImpl&)> post_ctor = {}, E_LogLevel ll = LL_VERBOSE, T_Args&&...args) const
141 {
142 auto child = std::make_unique<C_ReenterableLoggerInside<C_LogImpl,C_Holder>>(ll, std::forward<T_Args>(args)...);
143 if (post_ctor)
144 post_ctor(child->impl());
145
146 return addChild(std::move(child));
147 }
148 [[nodiscard]]C_NodeArrayProxy partitionBy(std::convertible_to<FC_Accept> auto f) const
149 {
150 std::lock_guard _{*m_lock};
151 auto &dst = m_node->m_partitions.emplace_back();
152 dst.m_filteredNodes.emplace_back(std::piecewise_construct, std::forward_as_tuple(f), std::forward_as_tuple());
153 return {*m_lock, dst};
154 }
155 template<typename Filters>
156 [[nodiscard]]C_NodeArrayProxy partitionBy(Filters fs) const requires requires {
157 { *std::begin(fs) }-> std::convertible_to<FC_Accept>;
158 { std::size(fs) }-> std::convertible_to<size_t>;
159 std::end(fs);
160 }
161 {
162 std::lock_guard _{*m_lock};
163 auto &dst = m_node->m_partitions.emplace_back();
164 dst.m_filteredNodes.reserve(std::size(fs));
165 for (auto &&i: fs)
166 dst.m_filteredNodes.emplace_back(std::piecewise_construct, std::forward_as_tuple(i), std::forward_as_tuple());
167
168 return {*m_lock, dst};
169 }
170
171private:
172
173 // Data
174 std::recursive_mutex *m_lock;
175 C_Node *m_node;
176};
177
178//
179// Implement Class Member Templates
180//
181template<class...T_Args>
182bool C_ParaLog::addChild(T_Args&&...args)
183{
184 return C_NodeProxy{m_lock,m_root}.addChild(std::forward<T_Args>(args)...);
185}
186
187template<class C_LogImpl, class C_Holder, class...T_Args>
188bool C_ParaLog::addChildT(std::function<void(C_LogImpl&)> post_ctor, E_LogLevel ll, T_Args&&...args)
189{
190 return C_NodeProxy{m_lock,m_root}.addChildT<C_LogImpl,C_Holder>(post_ctor, ll, std::forward<T_Args>(args)...);
191}
192
193template<typename F>
195{
196 return C_NodeProxy{m_lock,m_root}.partitionBy(f);
197}
198
199} // namespace bux
C_NodeArrayProxy(std::recursive_mutex &lock, C_NodePartition &nodePart)
Definition ParaLog.h:99
C_NodeProxy operator[](size_t i) const
Definition ParaLog.cpp:8
C_NodeProxy matchedNone() const
Definition ParaLog.cpp:24
bool addChild(I_SnapT< std::ostream * > &snap, E_LogLevel ll=LL_VERBOSE) const
Definition ParaLog.h:135
bool addChild(std::unique_ptr< T > &&snap) const
Definition ParaLog.h:121
bool addChildT(std::function< void(C_LogImpl &)> post_ctor={}, E_LogLevel ll=LL_VERBOSE, T_Args &&...args) const
Definition ParaLog.h:140
C_NodeProxy(std::recursive_mutex &lock, C_Node &node)
Definition ParaLog.h:119
C_NodeArrayProxy partitionBy(Filters fs) const
Definition ParaLog.h:156
C_NodeArrayProxy partitionBy(std::convertible_to< FC_Accept > auto f) const
Definition ParaLog.h:148
bool addChild(std::ostream &out, E_LogLevel ll=LL_VERBOSE) const
Definition ParaLog.h:131
bool addChild(T_Args &&...args)
Definition ParaLog.h:182
C_ParaLog(bool use_local_time)
Definition ParaLog.h:31
C_ParaLog(const std::chrono::time_zone *tz_=nullptr)
Definition ParaLog.h:30
C_NodeArrayProxy partitionBy(F f)
void unlockLog(bool flush) override
If the previous call to lockLog() returned null, the behavior is undefined.
Definition ParaLog.cpp:104
bool addChildT(std::function< void(C_LogImpl &)> post_ctor={}, E_LogLevel ll=LL_VERBOSE, T_Args &&...args)
Definition ParaLog.h:188
std::ostream * lockLog() override
Return non-null pointer if possible.
Definition ParaLog.cpp:94
</// Thread safety is expected
Definition SyncLog.h:15
THE common namespace of bux library.
Definition AtomiX.cpp:3
E_LogLevel
Definition LogLevel.h:9
@ LL_VERBOSE
More detailed or advanced information probably considered too much by some.
Definition LogLevel.h:14
Thread-unsafe implementation is preferred for performance.
Definition SyncLog.h:35
< Parasitic Type
Definition SyncLog.h:167