This is an automated email from the ASF dual-hosted git repository.
swebb2066 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git
The following commit(s) were added to refs/heads/master by this push:
new c36f5147 Allow use of wide strings in LOG4CXX_XXXXX_ASYNC macros (#556)
c36f5147 is described below
commit c36f514742a700744d50188f4620729a3ede1f12
Author: Stephen Webb <[email protected]>
AuthorDate: Thu Oct 30 10:12:11 2025 +1100
Allow use of wide strings in LOG4CXX_XXXXX_ASYNC macros (#556)
---
src/main/cpp/asyncbuffer.cpp | 67 ++++++++++++++-
src/main/include/log4cxx/helpers/asyncbuffer.h | 110 ++++++++++++++++++++++++-
src/test/cpp/asyncappendertestcase.cpp | 45 ++++++----
3 files changed, 200 insertions(+), 22 deletions(-)
diff --git a/src/main/cpp/asyncbuffer.cpp b/src/main/cpp/asyncbuffer.cpp
index 4a146bad..f4233122 100644
--- a/src/main/cpp/asyncbuffer.cpp
+++ b/src/main/cpp/asyncbuffer.cpp
@@ -17,6 +17,9 @@
#include <log4cxx/helpers/asyncbuffer.h>
#include <log4cxx/helpers/transcoder.h>
+#if defined(__cpp_concepts) && 202002 <= __cpp_concepts
+#include <variant>
+#endif // defined(__cpp_concepts) && 202002 <= __cpp_concepts
namespace LOG4CXX_NS
{
@@ -26,9 +29,14 @@ namespace helpers
struct AsyncBuffer::Private
{
- std::vector<MessageBufferAppender> data;
-
- Private(const MessageBufferAppender& f)
+#if defined(__cpp_concepts) && 202002 <= __cpp_concepts && LOG4CXX_WCHAR_T_API
+ using value_t = std::variant<MessageBufferAppender,
WideMessageBufferAppender>;
+#else // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts &&
LOG4CXX_WCHAR_T_API)
+ using value_t = MessageBufferAppender;
+#endif // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts &&
LOG4CXX_WCHAR_T_API)
+ std::vector<value_t> data;
+
+ Private(const value_t& f)
: data{ f }
{}
@@ -127,7 +135,34 @@ void AsyncBuffer::renderMessage(LogCharMessageBuffer& msg)
const
if (m_priv)
{
for (auto& renderer : m_priv->data)
+#if defined(__cpp_concepts) && 202002 <= __cpp_concepts && LOG4CXX_WCHAR_T_API
+ {
+#if LOG4CXX_LOGCHAR_IS_UTF8
+ if (auto pRenderer =
std::get_if<MessageBufferAppender>(&renderer))
+ (*pRenderer)(msg);
+ else
+ {
+ WideMessageBuffer wideBuf;
+
std::get<WideMessageBufferAppender>(renderer)(wideBuf);
+ LOG4CXX_DECODE_WCHAR(lsMsg,
wideBuf.extract_str(wideBuf));
+ msg << lsMsg;
+ }
+#else // !LOG4CXX_LOGCHAR_IS_UTF8
+ if (auto pRenderer =
std::get_if<WideMessageBufferAppender>(&renderer))
+ (*pRenderer)(msg);
+ else
+ {
+ CharMessageBuffer narrowBuf;
+
std::get<MessageBufferAppender>(renderer)(narrowBuf);
+ LOG4CXX_DECODE_CHAR(lsMsg,
narrowBuf.extract_str(narrowBuf));
+ msg << lsMsg;
+ }
+#endif // !LOG4CXX_LOGCHAR_IS_UTF8
+ }
+#else // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts &&
LOG4CXX_WCHAR_T_API)
renderer(msg);
+#endif // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts &&
LOG4CXX_WCHAR_T_API)
+
#if LOG4CXX_ASYNC_BUFFER_SUPPORTS_FMT
#if LOG4CXX_LOGCHAR_IS_UTF8
if (0 < m_priv->fmt_string.size())
@@ -171,6 +206,31 @@ void AsyncBuffer::clear()
}
}
+#if defined(__cpp_concepts) && 202002 <= __cpp_concepts
+/**
+ * Append \c function to this buffer.
+ */
+void AsyncBuffer::append(const MessageBufferAppender& f)
+{
+ if (!m_priv)
+ m_priv = std::make_unique<Private>(f);
+ else
+ m_priv->data.push_back(f);
+}
+
+#if LOG4CXX_WCHAR_T_API
+/**
+ * Append \c function to this buffer.
+ */
+void AsyncBuffer::append(const WideMessageBufferAppender& f)
+{
+ if (!m_priv)
+ m_priv = std::make_unique<Private>(f);
+ else
+ m_priv->data.push_back(f);
+}
+#endif // LOG4CXX_WCHAR_T_API
+#else // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts
/**
* Append \c function to this buffer.
*/
@@ -181,6 +241,7 @@ void AsyncBuffer::append(const MessageBufferAppender& f)
else
m_priv->data.push_back(f);
}
+#endif // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts
} // namespace helpers
} // namespace LOG4CXX_NS
diff --git a/src/main/include/log4cxx/helpers/asyncbuffer.h
b/src/main/include/log4cxx/helpers/asyncbuffer.h
index 44110ebf..1784b358 100644
--- a/src/main/include/log4cxx/helpers/asyncbuffer.h
+++ b/src/main/include/log4cxx/helpers/asyncbuffer.h
@@ -27,6 +27,9 @@
#include <fmt/xchar.h>
#endif // LOG4CXX_WCHAR_T_API || LOG4CXX_LOGCHAR_IS_WCHAR
#endif // LOG4CXX_ASYNC_BUFFER_SUPPORTS_FMT
+#if defined(__cpp_concepts) && 202002 <= __cpp_concepts
+#include <concepts>
+#endif
namespace LOG4CXX_NS
{
@@ -59,13 +62,53 @@ public: // Operators
* @param value type must be copy-constructable
* @return this buffer.
*/
- template<typename T>
+ template <typename T>
AsyncBuffer& operator<<(const T& value)
{
+#if defined(__cpp_concepts) && 202002 <= __cpp_concepts
+#if LOG4CXX_LOGCHAR_IS_UTF8
+ if constexpr (requires(std::ostream& buf, T v) { buf << v; })
+ {
+ append([value](CharMessageBuffer& msgBuf)
+ {
+ msgBuf << value;
+ });
+ }
+#if LOG4CXX_WCHAR_T_API
+ else if constexpr (requires(std::wostream& buf, T v) { buf <<
v; })
+ {
+ append([value](WideMessageBuffer& msgBuf)
+ {
+ msgBuf << value;
+ });
+ }
+#endif // LOG4CXX_WCHAR_T_API
+ else
+ static_assert(false, "operator<<(std::ostream&)
overload must be provided");
+#else // !LOG4CXX_LOGCHAR_IS_UTF8
+ if constexpr (requires(std::wostream& buf, T v) { buf << v; })
+ {
+ append([value](WideMessageBuffer& msgBuf)
+ {
+ msgBuf << value;
+ });
+ }
+ else if constexpr (requires(std::ostream& buf, T v) { buf << v;
})
+ {
+ append([value](CharMessageBuffer& msgBuf)
+ {
+ msgBuf << value;
+ });
+ }
+ else
+ static_assert(false, "operator<<(std::wostream&)
overload must be provided");
+#endif // !LOG4CXX_LOGCHAR_IS_UTF8
+#else // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts)
append([value](LogCharMessageBuffer& msgBuf)
{
msgBuf << value;
});
+#endif // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts)
return *this;
}
@@ -74,16 +117,57 @@ public: // Operators
* @param value type must be move-constructable
* @return this buffer.
*/
- template<typename T>
+ template <typename T>
AsyncBuffer& operator<<(const T&& rvalue)
{
+#if defined(__cpp_concepts) && 202002 <= __cpp_concepts
+#if LOG4CXX_LOGCHAR_IS_UTF8
+ if constexpr (requires(std::ostream& buf, T v) { buf << v; })
+ {
+ append([value = std::move(rvalue)](CharMessageBuffer&
msgBuf)
+ {
+ msgBuf << value;
+ });
+ }
+#if LOG4CXX_WCHAR_T_API
+ else if constexpr (requires(std::wostream& buf, T v) { buf <<
v; })
+ {
+ append([value = std::move(rvalue)](WideMessageBuffer&
msgBuf)
+ {
+ msgBuf << value;
+ });
+ }
+#endif // LOG4CXX_WCHAR_T_API
+ else
+ static_assert(false, "operator<<(std::ostream&)
overload must be provided");
+#else // !LOG4CXX_LOGCHAR_IS_UTF8
+ if constexpr (requires(std::wostream& buf, T v) { buf << v; })
+ {
+ append([value = std::move(rvalue)](WideMessageBuffer&
msgBuf)
+ {
+ msgBuf << value;
+ });
+ }
+ else if constexpr (requires(std::ostream& buf, T v) { buf << v;
})
+ {
+ append([value = std::move(rvalue)](CharMessageBuffer&
msgBuf)
+ {
+ msgBuf << value;
+ });
+ }
+ else
+ static_assert(false, "operator<<(std::wostream&)
overload must be provided");
+#endif // !LOG4CXX_LOGCHAR_IS_UTF8
+#else // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts)
append([value = std::move(rvalue)](LogCharMessageBuffer& msgBuf)
{
msgBuf << value;
});
+#endif // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts)
return *this;
}
-#endif
+
+#endif // __cpp_init_captures
public: // Accessors
/**
@@ -131,12 +215,30 @@ private:
AsyncBuffer& operator=(const AsyncBuffer&) = delete;
LOG4CXX_DECLARE_PRIVATE_MEMBER_PTR(Private, m_priv)
+#if defined(__cpp_concepts) && 202002 <= __cpp_concepts
+ using MessageBufferAppender = std::function<void(CharMessageBuffer&)>;
+
+ /**
+ * Append \c f to this buffer.
+ */
+ void append(const MessageBufferAppender& f);
+
+#if LOG4CXX_WCHAR_T_API
+ using WideMessageBufferAppender =
std::function<void(WideMessageBuffer&)>;
+
+ /**
+ * Append \c f to this buffer.
+ */
+ void append(const WideMessageBufferAppender& f);
+#endif // LOG4CXX_WCHAR_T_API
+#else // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts)
using MessageBufferAppender =
std::function<void(LogCharMessageBuffer&)>;
/**
- * Append \c function to this buffer.
+ * Append \c f to this buffer.
*/
void append(const MessageBufferAppender& f);
+#endif // !(defined(__cpp_concepts) && 202002 <= __cpp_concepts)
#if LOG4CXX_ASYNC_BUFFER_SUPPORTS_FMT
void initializeForFmt(StringViewType&& format_string, FmtArgStore&&
args);
diff --git a/src/test/cpp/asyncappendertestcase.cpp
b/src/test/cpp/asyncappendertestcase.cpp
index b9dd8bcc..36744924 100644
--- a/src/test/cpp/asyncappendertestcase.cpp
+++ b/src/test/cpp/asyncappendertestcase.cpp
@@ -238,27 +238,42 @@ class AsyncAppenderTestCase : public
AppenderSkeletonTestCase
r->getRootLogger()->addAppender(vectorAppender);
r->setConfigured(true);
});
+ LogString logStr = LOG4CXX_STR("Some logchar string ");
+#if LOG4CXX_LOGCHAR_IS_UTF8
+ std::wstring otherStr(L"Some non-logchar string ");
+#else // !LOG4CXX_LOGCHAR_IS_UTF8
+ std::string otherStr("Some non-logchar string ");
+#endif // !LOG4CXX_LOGCHAR_IS_UTF8
// Log some messages
auto root = r->getRootLogger();
-#if LOG4CXX_LOGCHAR_IS_UTF8
- LOG4CXX_INFO(root, L"Some wide string " << 42);
-#else
- LOG4CXX_INFO(root, "Some narrow string " << 42);
-#endif
- int expectedMessageCount = 1;
-#ifdef LOG4CXX_XXXX_ASYNC_MACROS_WORK_WITH_ANY_CHAR_TYPE
- ++expectedMessageCount
-#if LOG4CXX_LOGCHAR_IS_UTF8
- LOG4CXX_INFO_ASYNC(root, L"Some wide string " << 42);
-#else
- LOG4CXX_INFO_ASYNC(root, "Some narrow string " << 42);
-#endif
-#endif // LOG4CXX_XXXX_ASYNC_MACROS_WORK_WITH_ANY_CHAR_TYPE
+ LOG4CXX_INFO(root, logStr << 42);
+ LOG4CXX_INFO_ASYNC(root, logStr << 42);
+ int expectedEventCount = 2;
+#if !LOG4CXX_LOGCHAR_IS_UTF8 || LOG4CXX_WCHAR_T_API
+ LOG4CXX_INFO(root, otherStr << 42);
+ ++expectedEventCount;
+#if defined(__cpp_concepts) && 202002 <= __cpp_concepts
+ LOG4CXX_INFO_ASYNC(root, otherStr << 42);
+ ++expectedEventCount;
+#endif // defined(__cpp_concepts) && 202002 <= __cpp_concepts
+#endif // !LOG4CXX_LOGCHAR_IS_UTF8 || LOG4CXX_WCHAR_T_API
// Check all messages were received
auto& v = vectorAppender->getVector();
- LOGUNIT_ASSERT_EQUAL(expectedMessageCount,
int(v.size()));
+ for (auto& pEvent : v)
+ LogLog::debug(pEvent->getRenderedMessage());
+ LOGUNIT_ASSERT_EQUAL(expectedEventCount, int(v.size()));
+ LOGUNIT_ASSERT_EQUAL(v[0]->getRenderedMessage(),
v[1]->getRenderedMessage());
+ if (4 <= expectedEventCount)
+
LOGUNIT_ASSERT_EQUAL(v[2]->getRenderedMessage(), v[3]->getRenderedMessage());
+#ifdef GENERATE_THE_STATIC_ASSERT_COMPILATION_ERROR
+ struct AStruct
+ {
+ int value;
+ } data{ 43 };
+ LOG4CXX_INFO_ASYNC(root, "data.value=" << data);
+#endif
}
// this test checks all messages are delivered when an
AsyncAppender is closed