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

Reply via email to