Skip to content

Commit c36f514

Browse files
authored
Allow use of wide strings in LOG4CXX_XXXXX_ASYNC macros (#556)
1 parent 9ce5cdd commit c36f514

File tree

3 files changed

+200
-22
lines changed

3 files changed

+200
-22
lines changed

src/main/cpp/asyncbuffer.cpp

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717

1818
#include <log4cxx/helpers/asyncbuffer.h>
1919
#include <log4cxx/helpers/transcoder.h>
20+
#if defined(__cpp_concepts) && 202002 <= __cpp_concepts
21+
#include <variant>
22+
#endif // defined(__cpp_concepts) && 202002 <= __cpp_concepts
2023

2124
namespace LOG4CXX_NS
2225
{
@@ -26,9 +29,14 @@ namespace helpers
2629

2730
struct AsyncBuffer::Private
2831
{
29-
std::vector<MessageBufferAppender> data;
30-
31-
Private(const MessageBufferAppender& f)
32+
#if defined(__cpp_concepts) && 202002 <= __cpp_concepts && LOG4CXX_WCHAR_T_API
33+
using value_t = std::variant<MessageBufferAppender, WideMessageBufferAppender>;
34+
#else // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts && LOG4CXX_WCHAR_T_API)
35+
using value_t = MessageBufferAppender;
36+
#endif // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts && LOG4CXX_WCHAR_T_API)
37+
std::vector<value_t> data;
38+
39+
Private(const value_t& f)
3240
: data{ f }
3341
{}
3442

@@ -127,7 +135,34 @@ void AsyncBuffer::renderMessage(LogCharMessageBuffer& msg) const
127135
if (m_priv)
128136
{
129137
for (auto& renderer : m_priv->data)
138+
#if defined(__cpp_concepts) && 202002 <= __cpp_concepts && LOG4CXX_WCHAR_T_API
139+
{
140+
#if LOG4CXX_LOGCHAR_IS_UTF8
141+
if (auto pRenderer = std::get_if<MessageBufferAppender>(&renderer))
142+
(*pRenderer)(msg);
143+
else
144+
{
145+
WideMessageBuffer wideBuf;
146+
std::get<WideMessageBufferAppender>(renderer)(wideBuf);
147+
LOG4CXX_DECODE_WCHAR(lsMsg, wideBuf.extract_str(wideBuf));
148+
msg << lsMsg;
149+
}
150+
#else // !LOG4CXX_LOGCHAR_IS_UTF8
151+
if (auto pRenderer = std::get_if<WideMessageBufferAppender>(&renderer))
152+
(*pRenderer)(msg);
153+
else
154+
{
155+
CharMessageBuffer narrowBuf;
156+
std::get<MessageBufferAppender>(renderer)(narrowBuf);
157+
LOG4CXX_DECODE_CHAR(lsMsg, narrowBuf.extract_str(narrowBuf));
158+
msg << lsMsg;
159+
}
160+
#endif // !LOG4CXX_LOGCHAR_IS_UTF8
161+
}
162+
#else // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts && LOG4CXX_WCHAR_T_API)
130163
renderer(msg);
164+
#endif // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts && LOG4CXX_WCHAR_T_API)
165+
131166
#if LOG4CXX_ASYNC_BUFFER_SUPPORTS_FMT
132167
#if LOG4CXX_LOGCHAR_IS_UTF8
133168
if (0 < m_priv->fmt_string.size())
@@ -171,6 +206,31 @@ void AsyncBuffer::clear()
171206
}
172207
}
173208

209+
#if defined(__cpp_concepts) && 202002 <= __cpp_concepts
210+
/**
211+
* Append \c function to this buffer.
212+
*/
213+
void AsyncBuffer::append(const MessageBufferAppender& f)
214+
{
215+
if (!m_priv)
216+
m_priv = std::make_unique<Private>(f);
217+
else
218+
m_priv->data.push_back(f);
219+
}
220+
221+
#if LOG4CXX_WCHAR_T_API
222+
/**
223+
* Append \c function to this buffer.
224+
*/
225+
void AsyncBuffer::append(const WideMessageBufferAppender& f)
226+
{
227+
if (!m_priv)
228+
m_priv = std::make_unique<Private>(f);
229+
else
230+
m_priv->data.push_back(f);
231+
}
232+
#endif // LOG4CXX_WCHAR_T_API
233+
#else // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts
174234
/**
175235
* Append \c function to this buffer.
176236
*/
@@ -181,6 +241,7 @@ void AsyncBuffer::append(const MessageBufferAppender& f)
181241
else
182242
m_priv->data.push_back(f);
183243
}
244+
#endif // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts
184245

185246
} // namespace helpers
186247
} // namespace LOG4CXX_NS

src/main/include/log4cxx/helpers/asyncbuffer.h

Lines changed: 106 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
#include <fmt/xchar.h>
2828
#endif // LOG4CXX_WCHAR_T_API || LOG4CXX_LOGCHAR_IS_WCHAR
2929
#endif // LOG4CXX_ASYNC_BUFFER_SUPPORTS_FMT
30+
#if defined(__cpp_concepts) && 202002 <= __cpp_concepts
31+
#include <concepts>
32+
#endif
3033

3134
namespace LOG4CXX_NS
3235
{
@@ -59,13 +62,53 @@ class LOG4CXX_EXPORT AsyncBuffer
5962
* @param value type must be copy-constructable
6063
* @return this buffer.
6164
*/
62-
template<typename T>
65+
template <typename T>
6366
AsyncBuffer& operator<<(const T& value)
6467
{
68+
#if defined(__cpp_concepts) && 202002 <= __cpp_concepts
69+
#if LOG4CXX_LOGCHAR_IS_UTF8
70+
if constexpr (requires(std::ostream& buf, T v) { buf << v; })
71+
{
72+
append([value](CharMessageBuffer& msgBuf)
73+
{
74+
msgBuf << value;
75+
});
76+
}
77+
#if LOG4CXX_WCHAR_T_API
78+
else if constexpr (requires(std::wostream& buf, T v) { buf << v; })
79+
{
80+
append([value](WideMessageBuffer& msgBuf)
81+
{
82+
msgBuf << value;
83+
});
84+
}
85+
#endif // LOG4CXX_WCHAR_T_API
86+
else
87+
static_assert(false, "operator<<(std::ostream&) overload must be provided");
88+
#else // !LOG4CXX_LOGCHAR_IS_UTF8
89+
if constexpr (requires(std::wostream& buf, T v) { buf << v; })
90+
{
91+
append([value](WideMessageBuffer& msgBuf)
92+
{
93+
msgBuf << value;
94+
});
95+
}
96+
else if constexpr (requires(std::ostream& buf, T v) { buf << v; })
97+
{
98+
append([value](CharMessageBuffer& msgBuf)
99+
{
100+
msgBuf << value;
101+
});
102+
}
103+
else
104+
static_assert(false, "operator<<(std::wostream&) overload must be provided");
105+
#endif // !LOG4CXX_LOGCHAR_IS_UTF8
106+
#else // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts)
65107
append([value](LogCharMessageBuffer& msgBuf)
66108
{
67109
msgBuf << value;
68110
});
111+
#endif // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts)
69112
return *this;
70113
}
71114

@@ -74,16 +117,57 @@ class LOG4CXX_EXPORT AsyncBuffer
74117
* @param value type must be move-constructable
75118
* @return this buffer.
76119
*/
77-
template<typename T>
120+
template <typename T>
78121
AsyncBuffer& operator<<(const T&& rvalue)
79122
{
123+
#if defined(__cpp_concepts) && 202002 <= __cpp_concepts
124+
#if LOG4CXX_LOGCHAR_IS_UTF8
125+
if constexpr (requires(std::ostream& buf, T v) { buf << v; })
126+
{
127+
append([value = std::move(rvalue)](CharMessageBuffer& msgBuf)
128+
{
129+
msgBuf << value;
130+
});
131+
}
132+
#if LOG4CXX_WCHAR_T_API
133+
else if constexpr (requires(std::wostream& buf, T v) { buf << v; })
134+
{
135+
append([value = std::move(rvalue)](WideMessageBuffer& msgBuf)
136+
{
137+
msgBuf << value;
138+
});
139+
}
140+
#endif // LOG4CXX_WCHAR_T_API
141+
else
142+
static_assert(false, "operator<<(std::ostream&) overload must be provided");
143+
#else // !LOG4CXX_LOGCHAR_IS_UTF8
144+
if constexpr (requires(std::wostream& buf, T v) { buf << v; })
145+
{
146+
append([value = std::move(rvalue)](WideMessageBuffer& msgBuf)
147+
{
148+
msgBuf << value;
149+
});
150+
}
151+
else if constexpr (requires(std::ostream& buf, T v) { buf << v; })
152+
{
153+
append([value = std::move(rvalue)](CharMessageBuffer& msgBuf)
154+
{
155+
msgBuf << value;
156+
});
157+
}
158+
else
159+
static_assert(false, "operator<<(std::wostream&) overload must be provided");
160+
#endif // !LOG4CXX_LOGCHAR_IS_UTF8
161+
#else // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts)
80162
append([value = std::move(rvalue)](LogCharMessageBuffer& msgBuf)
81163
{
82164
msgBuf << value;
83165
});
166+
#endif // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts)
84167
return *this;
85168
}
86-
#endif
169+
170+
#endif // __cpp_init_captures
87171

88172
public: // Accessors
89173
/**
@@ -131,12 +215,30 @@ class LOG4CXX_EXPORT AsyncBuffer
131215
AsyncBuffer& operator=(const AsyncBuffer&) = delete;
132216

133217
LOG4CXX_DECLARE_PRIVATE_MEMBER_PTR(Private, m_priv)
218+
#if defined(__cpp_concepts) && 202002 <= __cpp_concepts
219+
using MessageBufferAppender = std::function<void(CharMessageBuffer&)>;
220+
221+
/**
222+
* Append \c f to this buffer.
223+
*/
224+
void append(const MessageBufferAppender& f);
225+
226+
#if LOG4CXX_WCHAR_T_API
227+
using WideMessageBufferAppender = std::function<void(WideMessageBuffer&)>;
228+
229+
/**
230+
* Append \c f to this buffer.
231+
*/
232+
void append(const WideMessageBufferAppender& f);
233+
#endif // LOG4CXX_WCHAR_T_API
234+
#else // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts)
134235
using MessageBufferAppender = std::function<void(LogCharMessageBuffer&)>;
135236

136237
/**
137-
* Append \c function to this buffer.
238+
* Append \c f to this buffer.
138239
*/
139240
void append(const MessageBufferAppender& f);
241+
#endif // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts)
140242

141243
#if LOG4CXX_ASYNC_BUFFER_SUPPORTS_FMT
142244
void initializeForFmt(StringViewType&& format_string, FmtArgStore&& args);

src/test/cpp/asyncappendertestcase.cpp

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -238,27 +238,42 @@ class AsyncAppenderTestCase : public AppenderSkeletonTestCase
238238
r->getRootLogger()->addAppender(vectorAppender);
239239
r->setConfigured(true);
240240
});
241+
LogString logStr = LOG4CXX_STR("Some logchar string ");
242+
#if LOG4CXX_LOGCHAR_IS_UTF8
243+
std::wstring otherStr(L"Some non-logchar string ");
244+
#else // !LOG4CXX_LOGCHAR_IS_UTF8
245+
std::string otherStr("Some non-logchar string ");
246+
#endif // !LOG4CXX_LOGCHAR_IS_UTF8
241247

242248
// Log some messages
243249
auto root = r->getRootLogger();
244-
#if LOG4CXX_LOGCHAR_IS_UTF8
245-
LOG4CXX_INFO(root, L"Some wide string " << 42);
246-
#else
247-
LOG4CXX_INFO(root, "Some narrow string " << 42);
248-
#endif
249-
int expectedMessageCount = 1;
250-
#ifdef LOG4CXX_XXXX_ASYNC_MACROS_WORK_WITH_ANY_CHAR_TYPE
251-
++expectedMessageCount
252-
#if LOG4CXX_LOGCHAR_IS_UTF8
253-
LOG4CXX_INFO_ASYNC(root, L"Some wide string " << 42);
254-
#else
255-
LOG4CXX_INFO_ASYNC(root, "Some narrow string " << 42);
256-
#endif
257-
#endif // LOG4CXX_XXXX_ASYNC_MACROS_WORK_WITH_ANY_CHAR_TYPE
250+
LOG4CXX_INFO(root, logStr << 42);
251+
LOG4CXX_INFO_ASYNC(root, logStr << 42);
252+
int expectedEventCount = 2;
253+
#if !LOG4CXX_LOGCHAR_IS_UTF8 || LOG4CXX_WCHAR_T_API
254+
LOG4CXX_INFO(root, otherStr << 42);
255+
++expectedEventCount;
256+
#if defined(__cpp_concepts) && 202002 <= __cpp_concepts
257+
LOG4CXX_INFO_ASYNC(root, otherStr << 42);
258+
++expectedEventCount;
259+
#endif // defined(__cpp_concepts) && 202002 <= __cpp_concepts
260+
#endif // !LOG4CXX_LOGCHAR_IS_UTF8 || LOG4CXX_WCHAR_T_API
258261

259262
// Check all messages were received
260263
auto& v = vectorAppender->getVector();
261-
LOGUNIT_ASSERT_EQUAL(expectedMessageCount, int(v.size()));
264+
for (auto& pEvent : v)
265+
LogLog::debug(pEvent->getRenderedMessage());
266+
LOGUNIT_ASSERT_EQUAL(expectedEventCount, int(v.size()));
267+
LOGUNIT_ASSERT_EQUAL(v[0]->getRenderedMessage(), v[1]->getRenderedMessage());
268+
if (4 <= expectedEventCount)
269+
LOGUNIT_ASSERT_EQUAL(v[2]->getRenderedMessage(), v[3]->getRenderedMessage());
270+
#ifdef GENERATE_THE_STATIC_ASSERT_COMPILATION_ERROR
271+
struct AStruct
272+
{
273+
int value;
274+
} data{ 43 };
275+
LOG4CXX_INFO_ASYNC(root, "data.value=" << data);
276+
#endif
262277
}
263278

264279
// this test checks all messages are delivered when an AsyncAppender is closed

0 commit comments

Comments
 (0)