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 2c6c4f40 Fix performance regression with JSON & XML output (#757)
2c6c4f40 is described below

commit 2c6c4f40f71f7681233c40c43df4faa143bc48b5
Author: Stephen Webb <[email protected]>
AuthorDate: Sat Sep 5 14:01:59 2026 +1000

    Fix performance regression with JSON & XML output (#757)
    
    * Avoid dynamic memory allocation in Transcoder::decode
    
    * Use inlined ByteBuffer methods when encoding
    
    * Check for ASCII before using Transcoder::getCodePoint
---
 src/main/cpp/bytebuffer.cpp                        |  55 +++-----
 src/main/cpp/charsetdecoder.cpp                    |  25 ++--
 src/main/cpp/charsetencoder.cpp                    | 141 +++++++++++++++++----
 src/main/cpp/jsonlayout.cpp                        |   6 +-
 src/main/cpp/transcoder.cpp                        | 106 +---------------
 src/main/cpp/transform.cpp                         |   6 +-
 src/main/include/log4cxx/helpers/bytebuffer.h      |   6 +-
 src/main/include/log4cxx/helpers/charsetdecoder.h  |   4 +-
 src/main/include/log4cxx/helpers/charsetencoder.h  |  22 ++++
 src/main/include/log4cxx/helpers/transcoder.h      |  10 +-
 src/main/include/log4cxx/private/bytebuffer_priv.h | 131 +++++++++++++++++++
 11 files changed, 331 insertions(+), 181 deletions(-)

diff --git a/src/main/cpp/bytebuffer.cpp b/src/main/cpp/bytebuffer.cpp
index 62a3e770..8890dd45 100644
--- a/src/main/cpp/bytebuffer.cpp
+++ b/src/main/cpp/bytebuffer.cpp
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 #include <log4cxx/logstring.h>
-#include <log4cxx/helpers/bytebuffer.h>
+#include <log4cxx/private/bytebuffer_priv.h>
 #if LOG4CXX_ABI_VERSION <= 15
 #include <log4cxx/helpers/exception.h>
 #endif
@@ -24,17 +24,6 @@
 using namespace LOG4CXX_NS;
 using namespace LOG4CXX_NS::helpers;
 
-struct ByteBuffer::ByteBufferPriv
-{
-       ByteBufferPriv(char* data1, size_t capacity) :
-               base(data1), pos(0), lim(capacity), cap(capacity) {}
-
-       char* base;
-       size_t pos;
-       size_t lim;
-       size_t cap;
-};
-
 ByteBuffer::ByteBuffer(char* data1, size_t capacity)
        : m_priv(std::make_unique<ByteBufferPriv>(data1, capacity))
 {
@@ -44,24 +33,24 @@ ByteBuffer::~ByteBuffer()
 {
 }
 
+ByteBufferPriv& ByteBuffer::impl()
+{
+    return *m_priv;
+}
+
 void ByteBuffer::clear()
 {
-       m_priv->lim = m_priv->cap;
-       m_priv->pos = 0;
+       m_priv->clear();
 }
 
 void ByteBuffer::carry()
 {
-       auto available = remaining();
-       memmove(m_priv->base, current(), available);
-       m_priv->lim = m_priv->cap;
-       m_priv->pos = available;
+       m_priv->carry();
 }
 
 void ByteBuffer::flip()
 {
-       m_priv->lim = m_priv->pos;
-       m_priv->pos = 0;
+       m_priv->flip();
 }
 
 #if LOG4CXX_ABI_VERSION <= 15
@@ -95,53 +84,45 @@ void ByteBuffer::limit(size_t newLimit)
 
 bool ByteBuffer::put(char byte)
 {
-       if (m_priv->pos < m_priv->lim)
-       {
-               m_priv->base[m_priv->pos++] = byte;
-               return true;
-       }
-
-       return false;
+       return m_priv->put(byte);
 }
 
 char* ByteBuffer::data()
 {
-       return m_priv->base;
+       return m_priv->data();
 }
 
 const char* ByteBuffer::data() const
 {
-       return m_priv->base;
+       return m_priv->data();
 }
 
 char* ByteBuffer::current()
 {
-       return m_priv->base + m_priv->pos;
+       return m_priv->current();
 }
 
 const char* ByteBuffer::current() const
 {
-       return m_priv->base + m_priv->pos;
+       return m_priv->current();
 }
 
 size_t ByteBuffer::limit() const
 {
-       return m_priv->lim;
+       return m_priv->limit();
 }
 
 size_t ByteBuffer::position() const
 {
-       return m_priv->pos;
+       return m_priv->position();
 }
 
 size_t ByteBuffer::remaining() const
 {
-       return m_priv->lim - m_priv->pos;
+       return m_priv->remaining();
 }
 
 size_t ByteBuffer::increment_position(size_t byteCount)
 {
-    auto available = remaining();
-    m_priv->pos += byteCount < available ? byteCount : available;
-    return remaining();
+    return m_priv->increment_position(byteCount);
 }
diff --git a/src/main/cpp/charsetdecoder.cpp b/src/main/cpp/charsetdecoder.cpp
index fc9ce181..3c2541e5 100644
--- a/src/main/cpp/charsetdecoder.cpp
+++ b/src/main/cpp/charsetdecoder.cpp
@@ -18,7 +18,7 @@
 #include <log4cxx/private/string_c11.h>
 #include <log4cxx/logstring.h>
 #include <log4cxx/helpers/charsetdecoder.h>
-#include <log4cxx/helpers/bytebuffer.h>
+#include <log4cxx/private/bytebuffer_priv.h>
 #include <log4cxx/helpers/exception.h>
 #include <log4cxx/helpers/pool.h>
 #include <log4cxx/helpers/loglog.h>
@@ -87,9 +87,10 @@ class APRCharsetDecoder : public CharsetDecoder
                {
                }
 
-               virtual log4cxx_status_t decode(ByteBuffer& in,
+               virtual log4cxx_status_t decode(ByteBuffer& in_param,
                        LogString& out)
                {
+                       auto& in = in_param.impl();
                        enum { BUFSIZE = 256 };
                        logchar buf[BUFSIZE];
                        const apr_size_t initial_outbytes_left = BUFSIZE * 
sizeof(logchar);
@@ -167,9 +168,10 @@ class MbstowcsCharsetDecoder : public CharsetDecoder
                        return APR_SUCCESS;
                }
 
-               virtual log4cxx_status_t decode(ByteBuffer& in,
+               virtual log4cxx_status_t decode(ByteBuffer& in_param,
                        LogString& out)
                {
+                       auto& in = in_param.impl();
                        log4cxx_status_t stat = APR_SUCCESS;
                        enum { BUFSIZE = 256 };
                        wchar_t wbuf[BUFSIZE];
@@ -276,9 +278,10 @@ class TrivialCharsetDecoder : public CharsetDecoder
                {
                }
 
-               virtual log4cxx_status_t decode(ByteBuffer& in,
+               virtual log4cxx_status_t decode(ByteBuffer& in_param,
                        LogString& out)
                {
+                       auto& in = in_param.impl();
                        size_t remaining = in.remaining();
 
                        if ( remaining > 0)
@@ -315,9 +318,10 @@ class UTF8CharsetDecoder : public CharsetDecoder
                }
 
        private:
-               virtual log4cxx_status_t decode(ByteBuffer& in,
+               virtual log4cxx_status_t decode(ByteBuffer& in_param,
                        LogString& out)
                {
+                       auto& in = in_param.impl();
                        auto availableByteCount = in.remaining();
                        while (0 < availableByteCount)
                        {
@@ -352,9 +356,10 @@ class ISOLatinCharsetDecoder : public CharsetDecoder
                }
 
        private:
-               virtual log4cxx_status_t decode(ByteBuffer& in,
+               virtual log4cxx_status_t decode(ByteBuffer& in_param,
                        LogString& out)
                {
+                       auto& in = in_param.impl();
                        auto availableByteCount = in.remaining();
                        auto src = in.current();
                        auto srcEnd = src + availableByteCount;
@@ -394,9 +399,10 @@ class USASCIICharsetDecoder : public CharsetDecoder
 
        private:
 
-               virtual log4cxx_status_t decode(ByteBuffer& in,
+               virtual log4cxx_status_t decode(ByteBuffer& in_param,
                        LogString& out)
                {
+                       auto& in = in_param.impl();
                        log4cxx_status_t stat = APR_SUCCESS;
 
                        auto availableByteCount = in.remaining();
@@ -439,8 +445,9 @@ class LocaleCharsetDecoder : public CharsetDecoder
                LocaleCharsetDecoder() : state()
                {
                }
-               log4cxx_status_t decode(ByteBuffer& in, LogString& out) override
+               log4cxx_status_t decode(ByteBuffer& in_param, LogString& out) 
override
                {
+                       auto& in = in_param.impl();
                        log4cxx_status_t result = APR_SUCCESS;
                        auto p = in.current();
                        auto availableByteCount = in.remaining();
@@ -594,7 +601,7 @@ log4cxx_status_t CharsetDecoder::decode(const char* in, 
size_t maxByteCount, Log
        return decode(buf, out);
 }
 
-unsigned int CharsetDecoder::getUTF8CodePoint(ByteBuffer& in)
+unsigned int CharsetDecoder::getUTF8CodePoint(ByteBufferPriv& in)
 {
        auto availableByteCount = in.remaining();
        if (0 == availableByteCount)
diff --git a/src/main/cpp/charsetencoder.cpp b/src/main/cpp/charsetencoder.cpp
index eb789a2d..ea09b86c 100644
--- a/src/main/cpp/charsetencoder.cpp
+++ b/src/main/cpp/charsetencoder.cpp
@@ -16,7 +16,7 @@
  */
 #include <log4cxx/logstring.h>
 #include <log4cxx/helpers/charsetencoder.h>
-#include <log4cxx/helpers/bytebuffer.h>
+#include <log4cxx/private/bytebuffer_priv.h>
 #include <log4cxx/helpers/exception.h>
 #include <apr_xlate.h>
 #include <log4cxx/helpers/stringhelper.h>
@@ -88,8 +88,9 @@ class APRCharsetEncoder : public CharsetEncoder
 
                virtual log4cxx_status_t encode(const LogString& in,
                        LogString::const_iterator& iter,
-                       ByteBuffer& out) override
+                       ByteBuffer& out_param) override
                {
+                       auto& out = out_param.impl();
                        apr_status_t stat;
                        size_t outbytes_left = out.remaining();
                        size_t initial_outbytes_left = outbytes_left;
@@ -128,8 +129,8 @@ class APRCharsetEncoder : public CharsetEncoder
                log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& 
out) LOG4CXX_16_VIRTUAL_SPECIFIER
                {
                        apr_status_t result = APR_SUCCESS;
-                       if (codePoint <= 0x10FFFF)
-                               Transcoder::encodeUTF8(codePoint, out);
+                       if (codePoint <= 0x10FFFF && 4 <= out.remaining())
+                               
out.increment_position(putUTF8CodePoint(codePoint, out.current()));
                        else
                                result = APR_BADARG;
                        return result;
@@ -160,8 +161,9 @@ class WcstombsCharsetEncoder : public CharsetEncoder
                 */
                log4cxx_status_t encode(const LogString& in,
                        LogString::const_iterator& iter,
-                       ByteBuffer& out) override
+                       ByteBuffer& out_param) override
                {
+                       auto& out = out_param.impl();
                        log4cxx_status_t stat = APR_SUCCESS;
 
                        if (iter != in.end())
@@ -261,8 +263,9 @@ class USASCIICharsetEncoder : public CharsetEncoder
 
                virtual log4cxx_status_t encode(const LogString& in,
                        LogString::const_iterator& iter,
-                       ByteBuffer& out) override
+                       ByteBuffer& out_param) override
                {
+                       auto& out = out_param.impl();
                        log4cxx_status_t stat = APR_SUCCESS;
 
                        if (iter != in.end())
@@ -322,8 +325,9 @@ class ISOLatinCharsetEncoder : public CharsetEncoder
 
                virtual log4cxx_status_t encode(const LogString& in,
                        LogString::const_iterator& iter,
-                       ByteBuffer& out) override
+                       ByteBuffer& out_param) override
                {
+                       auto& out = out_param.impl();
                        log4cxx_status_t stat = APR_SUCCESS;
 
                        while (out.remaining() > 0 && iter != in.end())
@@ -377,8 +381,9 @@ class TrivialCharsetEncoder : public CharsetEncoder
 
                virtual log4cxx_status_t encode(const LogString& in,
                        LogString::const_iterator& iter,
-                       ByteBuffer& out) override
+                       ByteBuffer& out_param) override
                {
+                       auto& out = out_param.impl();
                        if (iter != in.end())
                        {
                                size_t requested = in.length() - (iter - 
in.begin());
@@ -432,12 +437,13 @@ class UTF8CharsetEncoder : public CharsetEncoder
 
                virtual log4cxx_status_t encode(const LogString& in,
                        LogString::const_iterator& iter,
-                       ByteBuffer& out) override
+                       ByteBuffer& out_param) override
                {
-                       while (iter != in.end() && out.remaining() >= 8)
+                       auto& out = out_param.impl();
+                       while (iter != in.end() && 4 <= out.remaining())
                        {
                                auto sv = Transcoder::getCodePoint(in, iter);
-                               Transcoder::encodeUTF8(sv, out);
+                               out.increment_position(putUTF8CodePoint(sv, 
out.current()));
                        }
 
                        return APR_SUCCESS;
@@ -449,8 +455,8 @@ class UTF8CharsetEncoder : public CharsetEncoder
                log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& 
out) LOG4CXX_16_VIRTUAL_SPECIFIER
                {
                        apr_status_t result = APR_SUCCESS;
-                       if (codePoint <= 0x10FFFF)
-                               Transcoder::encodeUTF8(codePoint, out);
+                       if (codePoint <= 0x10FFFF && 4 <= out.remaining())
+                               
out.increment_position(putUTF8CodePoint(codePoint, out.current()));
                        else
                                result = APR_BADARG;
                        return result;
@@ -473,12 +479,13 @@ class UTF16BECharsetEncoder : public CharsetEncoder
 
                virtual log4cxx_status_t encode(const LogString& in,
                        LogString::const_iterator& iter,
-                       ByteBuffer& out) override
+                       ByteBuffer& out_param) override
                {
-                       while (iter != in.end() && out.remaining() >= 4)
+                       auto& out = out_param.impl();
+                       while (iter != in.end() && 4 <= out.remaining())
                        {
                                auto sv = Transcoder::getCodePoint(in, iter);
-                               Transcoder::encodeUTF16BE(sv, out);
+                               out.increment_position(putUTF16BECodePoint(sv, 
out.current()));
                        }
 
                        return APR_SUCCESS;
@@ -490,7 +497,7 @@ class UTF16BECharsetEncoder : public CharsetEncoder
                log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& 
out) LOG4CXX_16_VIRTUAL_SPECIFIER
                {
                        apr_status_t result = APR_SUCCESS;
-                       if (codePoint <= 0x10FFFF)
+                       if (codePoint <= 0x10FFFF && 4 <= out.remaining())
                                Transcoder::encodeUTF16BE(codePoint, out);
                        else
                                result = APR_BADARG;
@@ -515,12 +522,13 @@ class UTF16LECharsetEncoder : public CharsetEncoder
 
                virtual log4cxx_status_t encode(const LogString& in,
                        LogString::const_iterator& iter,
-                       ByteBuffer& out) override
+                       ByteBuffer& out_param) override
                {
-                       while (iter != in.end() && out.remaining() >= 4)
+                       auto& out = out_param.impl();
+                       while (iter != in.end() && 4 <= out.remaining())
                        {
                                auto sv = Transcoder::getCodePoint(in, iter);
-                               Transcoder::encodeUTF16LE(sv, out);
+                               out.increment_position(putUTF16LECodePoint(sv, 
out.current()));
                        }
 
                        return APR_SUCCESS;
@@ -532,8 +540,8 @@ class UTF16LECharsetEncoder : public CharsetEncoder
                log4cxx_status_t encode(unsigned int codePoint, ByteBuffer& 
out) LOG4CXX_16_VIRTUAL_SPECIFIER
                {
                        apr_status_t result = APR_SUCCESS;
-                       if (codePoint <= 0x10FFFF)
-                               Transcoder::encodeUTF16LE(codePoint, out);
+                       if (codePoint <= 0x10FFFF && 4 <= out.remaining())
+                               
out.increment_position(putUTF16LECodePoint(codePoint, out.current()));
                        else
                                result = APR_BADARG;
                        return result;
@@ -555,9 +563,10 @@ class LocaleCharsetEncoder : public CharsetEncoder
                log4cxx_status_t encode
                        ( const LogString&           in
                        , LogString::const_iterator& nextCodePoint
-                       , ByteBuffer&                out
+                       , ByteBuffer&                out_param
                        ) override
                {
+                       auto& out = out_param.impl();
                        log4cxx_status_t result = APR_SUCCESS;
 #if !LOG4CXX_CHARSET_EBCDIC
                        char* current = out.current();
@@ -795,3 +804,89 @@ bool CharsetEncoder::isTriviallyCopyable(const LogString& 
src, const CharsetEnco
                result = !!dynamic_cast<TrivialCharsetEncoder*>(enc.get());
        return result;
 }
+
+size_t CharsetEncoder::putUTF8CodePoint(unsigned int ch, char* dst)
+{
+       if (ch < 0x80)
+       {
+               dst[0] = (char) ch;
+               return 1;
+       }
+       else if (ch < 0x800)
+       {
+               dst[0] = (char) (0xC0 + (ch >> 6));
+               dst[1] = (char) (0x80 + (ch & 0x3F));
+               return 2;
+       }
+       else if (ch < 0x10000)
+       {
+               dst[0] = (char) (0xE0 + (ch >> 12));
+               dst[1] = (char) (0x80 + ((ch >> 6) & 0x3F));
+               dst[2] = (char) (0x80 + (ch & 0x3F));
+               return 3;
+       }
+       else if (ch <= 0x10FFFF)
+       {
+               dst[0] = (char) (0xF0 + (ch >> 18));
+               dst[1] = (char) (0x80 + ((ch >> 12) & 0x3F));
+               dst[2] = (char) (0x80 + ((ch >> 6) & 0x3F));
+               dst[3] = (char) (0x80 + (ch & 0x3F));
+               return 4;
+       }
+       else
+       {
+               //
+               //  output UTF-8 encoding of 0xFFFF
+               //
+               dst[0] = (char) 0xEF;
+               dst[1] = (char) 0xBF;
+               dst[2] = (char) 0xBF;
+               return 3;
+       }
+}
+
+size_t CharsetEncoder::putUTF16BECodePoint(unsigned int ch, char* dst)
+{
+       if (ch <= 0xFFFF)
+       {
+               dst[0] = (char) (ch >> 8);
+               dst[1] = (char) (ch & 0xFF);
+               return 2;
+       }
+
+       if (ch <= 0x10FFFF)
+       {
+               unsigned char w = (unsigned char) ((ch >> 16) - 1);
+               dst[0] = (char) (0xD8 + (w >> 2));
+               dst[1] = (char) (((w & 0x03) << 6) + ((ch >> 10) & 0x3F));
+               dst[2] = (char) (0xDC + ((ch >> 8) & 0x03));
+               dst[3] = (char) (ch & 0xFF);
+               return 4;
+       }
+
+       dst[0] = dst[1] = (char) 0xFF;
+       return 2;
+}
+
+size_t CharsetEncoder::putUTF16LECodePoint(unsigned int ch, char* dst)
+{
+       if (ch <= 0xFFFF)
+       {
+               dst[1] = (char) (ch >> 8);
+               dst[0] = (char) (ch & 0xFF);
+               return 2;
+       }
+
+       if (ch <= 0x10FFFF)
+       {
+               unsigned char w = (unsigned char) ((ch >> 16) - 1);
+               dst[1] = (char) (0xD8 + (w >> 2));
+               dst[0] = (char) (((w & 0x03) << 6) + ((ch >> 10) & 0x3F));
+               dst[3] = (char) (0xDC + ((ch >> 8) & 0x03));
+               dst[2] = (char) (ch & 0xFF);
+               return 4;
+       }
+
+       dst[0] = dst[1] = (char) 0xFF;
+       return 2;
+}
\ No newline at end of file
diff --git a/src/main/cpp/jsonlayout.cpp b/src/main/cpp/jsonlayout.cpp
index a66c8a77..9de7705e 100644
--- a/src/main/cpp/jsonlayout.cpp
+++ b/src/main/cpp/jsonlayout.cpp
@@ -223,7 +223,11 @@ void JSONLayout::appendItem(const LogString& input, 
LogString& buf)
        for (auto nextCodePoint = start; input.end() != nextCodePoint; )
        {
                auto lastCodePoint = nextCodePoint;
-               auto ch = Transcoder::getCodePoint(input, nextCodePoint);
+               auto ch = static_cast<unsigned int>(*nextCodePoint);
+               if (ch <= 0x7f)
+                       ++nextCodePoint;
+               else
+                       ch = Transcoder::getCodePoint(input, nextCodePoint);
                if (0x22 == ch || 0x5c == ch) // double quote or backslash?
                        ;
                else if (0x20 <= ch && 0xFFFD != ch) // not a control character 
or the replacement character?
diff --git a/src/main/cpp/transcoder.cpp b/src/main/cpp/transcoder.cpp
index bf71a302..4efd9da6 100644
--- a/src/main/cpp/transcoder.cpp
+++ b/src/main/cpp/transcoder.cpp
@@ -20,7 +20,7 @@
 #include <log4cxx/helpers/pool.h>
 #include <stdlib.h>
 #include <log4cxx/helpers/exception.h>
-#include <log4cxx/helpers/bytebuffer.h>
+#include <log4cxx/private/bytebuffer_priv.h>
 #include <log4cxx/helpers/charsetdecoder.h>
 #include <log4cxx/helpers/charsetencoder.h>
 #include <log4cxx/helpers/stringhelper.h>
@@ -81,117 +81,25 @@ char* Transcoder::encodeUTF8(const LogString& src, Pool& p)
 
 void Transcoder::encodeUTF8(unsigned int sv, ByteBuffer& dst)
 {
-       size_t bytes = encodeUTF8(sv, dst.current());
-       dst.increment_position(bytes);
-}
-
-
-size_t Transcoder::encodeUTF8(unsigned int ch, char* dst)
-{
-       if (ch < 0x80)
-       {
-               dst[0] = (char) ch;
-               return 1;
-       }
-       else if (ch < 0x800)
-       {
-               dst[0] = (char) (0xC0 + (ch >> 6));
-               dst[1] = (char) (0x80 + (ch & 0x3F));
-               return 2;
-       }
-       else if (ch < 0x10000)
-       {
-               dst[0] = (char) (0xE0 + (ch >> 12));
-               dst[1] = (char) (0x80 + ((ch >> 6) & 0x3F));
-               dst[2] = (char) (0x80 + (ch & 0x3F));
-               return 3;
-       }
-       else if (ch <= 0x10FFFF)
-       {
-               dst[0] = (char) (0xF0 + (ch >> 18));
-               dst[1] = (char) (0x80 + ((ch >> 12) & 0x3F));
-               dst[2] = (char) (0x80 + ((ch >> 6) & 0x3F));
-               dst[3] = (char) (0x80 + (ch & 0x3F));
-               return 4;
-       }
-       else
-       {
-               //
-               //  output UTF-8 encoding of 0xFFFF
-               //
-               dst[0] = (char) 0xEF;
-               dst[1] = (char) 0xBF;
-               dst[2] = (char) 0xBF;
-               return 3;
-       }
+       dst.increment_position(CharsetEncoder::putUTF8CodePoint(sv, 
dst.current()));
 }
 
 void Transcoder::encodeUTF16BE(unsigned int sv, ByteBuffer& dst)
 {
-       size_t bytes = encodeUTF16BE(sv, dst.current());
-       dst.increment_position(bytes);
-}
-
-
-size_t Transcoder::encodeUTF16BE(unsigned int ch, char* dst)
-{
-       if (ch <= 0xFFFF)
-       {
-               dst[0] = (char) (ch >> 8);
-               dst[1] = (char) (ch & 0xFF);
-               return 2;
-       }
-
-       if (ch <= 0x10FFFF)
-       {
-               unsigned char w = (unsigned char) ((ch >> 16) - 1);
-               dst[0] = (char) (0xD8 + (w >> 2));
-               dst[1] = (char) (((w & 0x03) << 6) + ((ch >> 10) & 0x3F));
-               dst[2] = (char) (0xDC + ((ch >> 8) & 0x03));
-               dst[3] = (char) (ch & 0xFF);
-               return 4;
-       }
-
-       dst[0] = dst[1] = (char) 0xFF;
-       return 2;
+       dst.increment_position(CharsetEncoder::putUTF16BECodePoint(sv, 
dst.current()));
 }
 
 void Transcoder::encodeUTF16LE(unsigned int sv, ByteBuffer& dst)
 {
-       size_t bytes = encodeUTF16LE(sv, dst.current());
-       dst.increment_position(bytes);
+       dst.increment_position(CharsetEncoder::putUTF16LECodePoint(sv, 
dst.current()));
 }
 
-size_t Transcoder::encodeUTF16LE(unsigned int ch, char* dst)
-{
-       if (ch <= 0xFFFF)
-       {
-               dst[1] = (char) (ch >> 8);
-               dst[0] = (char) (ch & 0xFF);
-               return 2;
-       }
-
-       if (ch <= 0x10FFFF)
-       {
-               unsigned char w = (unsigned char) ((ch >> 16) - 1);
-               dst[1] = (char) (0xD8 + (w >> 2));
-               dst[0] = (char) (((w & 0x03) << 6) + ((ch >> 10) & 0x3F));
-               dst[3] = (char) (0xDC + ((ch >> 8) & 0x03));
-               dst[2] = (char) (ch & 0xFF);
-               return 4;
-       }
-
-       dst[0] = dst[1] = (char) 0xFF;
-       return 2;
-}
-
-
 unsigned int Transcoder::decode(const std::string& src,
        std::string::const_iterator& iter)
 {
        auto offset = iter - src.begin();
        auto remaining = src.size() - offset;
-       ByteBuffer buf(const_cast<char*>(src.data() + offset), remaining);
+       ByteBufferPriv buf(const_cast<char*>(src.data() + offset), remaining);
        auto result = CharsetDecoder::getUTF8CodePoint(buf);
        iter += remaining - buf.remaining();
        return result;
@@ -231,7 +139,7 @@ unsigned int Transcoder::getCodePoint(const std::string& 
str, std::string::const
 void Transcoder::encode(unsigned int sv, std::string& dst)
 {
        char tmp[8];
-       size_t bytes = encodeUTF8(sv, tmp);
+       size_t bytes = CharsetEncoder::putUTF8CodePoint(sv, tmp);
        dst.append(tmp, bytes);
 }
 
@@ -314,9 +222,9 @@ void Transcoder::encode(const LogString& src, std::string& 
dst)
        }
 
 #endif
-
        if (iter != src.end())
        {
+               static const int BUFSIZE = 256;
                char buf[BUFSIZE];
                ByteBuffer out(buf, BUFSIZE);
 
diff --git a/src/main/cpp/transform.cpp b/src/main/cpp/transform.cpp
index 7ede9a6f..ee1ee457 100644
--- a/src/main/cpp/transform.cpp
+++ b/src/main/cpp/transform.cpp
@@ -43,7 +43,11 @@ void appendValidCharacters(LogString& buf, const LogString& 
input, CharProcessor
        for (auto nextCodePoint = start; input.end() != nextCodePoint; )
        {
                auto lastCodePoint = nextCodePoint;
-               auto ch = Transcoder::getCodePoint(input, nextCodePoint);
+               auto ch = static_cast<unsigned int>(*nextCodePoint);
+               if (ch <= 0x7f)
+                       ++nextCodePoint;
+               else
+                       ch = Transcoder::getCodePoint(input, nextCodePoint);
                if (((0x20 <= ch && ch <= 0xD7FF) &&
                                specials[0] != ch &&
                                specials[1] != ch &&
diff --git a/src/main/include/log4cxx/helpers/bytebuffer.h 
b/src/main/include/log4cxx/helpers/bytebuffer.h
index f2fe0c3e..670c47c2 100644
--- a/src/main/include/log4cxx/helpers/bytebuffer.h
+++ b/src/main/include/log4cxx/helpers/bytebuffer.h
@@ -26,6 +26,7 @@ namespace LOG4CXX_NS
 
 namespace helpers
 {
+struct ByteBufferPriv;
 
 /**
 * An area of memory and a cursor into that memory.
@@ -40,7 +41,7 @@ namespace helpers
 class LOG4CXX_EXPORT ByteBuffer
 {
        private:
-               LOG4CXX_DECLARE_PRIVATE_MEMBER_PTR(ByteBufferPriv, m_priv)
+               LOG4CXX_DECLARE_PRIVATE_MEMBER(std::unique_ptr<ByteBufferPriv>, 
m_priv);
 
        public:
                /// A \c capacity sized area of memory at \c data.
@@ -110,7 +111,8 @@ class LOG4CXX_EXPORT ByteBuffer
                /// @returns true if \c byteValue was stored in the buffer.
                bool put(char byteValue);
 
-
+               /// Internal use only
+               ByteBufferPriv& impl();
        private:
                ByteBuffer(const ByteBuffer&);
                ByteBuffer& operator=(const ByteBuffer&);
diff --git a/src/main/include/log4cxx/helpers/charsetdecoder.h 
b/src/main/include/log4cxx/helpers/charsetdecoder.h
index 71938e84..5a9af190 100644
--- a/src/main/include/log4cxx/helpers/charsetdecoder.h
+++ b/src/main/include/log4cxx/helpers/charsetdecoder.h
@@ -27,7 +27,7 @@ namespace helpers
 class CharsetDecoder;
 LOG4CXX_PTR_DEF(CharsetDecoder);
 class ByteBuffer;
-
+struct ByteBufferPriv;
 
 /**
 *   An abstract engine to transform a sequences of bytes in a specific charset
@@ -109,7 +109,7 @@ class LOG4CXX_EXPORT CharsetDecoder : public Object
                 *  @param buf the bytes to decode.
                 *  @return the code point value, if successful, otherwise 
0xFFFF. The \c buf cursor position is only incremented if successful.
                 */
-               static unsigned int getUTF8CodePoint(ByteBuffer& buf);
+               static unsigned int getUTF8CodePoint(ByteBufferPriv& buf);
 
        private:
                /**
diff --git a/src/main/include/log4cxx/helpers/charsetencoder.h 
b/src/main/include/log4cxx/helpers/charsetencoder.h
index 44b7b5dd..4e971cb2 100644
--- a/src/main/include/log4cxx/helpers/charsetencoder.h
+++ b/src/main/include/log4cxx/helpers/charsetencoder.h
@@ -131,7 +131,29 @@ class LOG4CXX_EXPORT CharsetEncoder : public Object
                */
                static bool isTriviallyCopyable(const LogString& src, const 
CharsetEncoderPtr& enc);
 
+               /**
+                *  Add UTF-8 bytes to \c dst corresponding to \c ch.
+                *  @pre dst is a writable address for 4 consecutive bytes
+                *  @param ch the code point value.
+                *  @param dst storage for upto 4 bytes.
+                */
+               static size_t putUTF8CodePoint(unsigned int ch, char* dst);
 
+               /**
+                *  Add UTF-16 big-endian bytes to \c dst corresponding to \c 
ch.
+                *  @pre dst is a writable address for 4 consecutive bytes
+                *  @param ch the code point value.
+                *  @param dst storage for upto 4 bytes.
+                */
+               static size_t putUTF16BECodePoint(unsigned int ch, char* dst);
+
+               /**
+                *  Add UTF-16 little-endian bytes to \c dst corresponding to 
\c ch.
+                *  @pre dst is a writable address for 4 consecutive bytes
+                *  @param ch the code point value.
+                *  @param dst storage for upto 4 bytes.
+                */
+               static size_t putUTF16LECodePoint(unsigned int ch, char* dst);
        private:
                /**
                *   Private copy constructor.
diff --git a/src/main/include/log4cxx/helpers/transcoder.h 
b/src/main/include/log4cxx/helpers/transcoder.h
index 51ed6b96..28f3255c 100644
--- a/src/main/include/log4cxx/helpers/transcoder.h
+++ b/src/main/include/log4cxx/helpers/transcoder.h
@@ -51,14 +51,17 @@ class LOG4CXX_EXPORT Transcoder
 #endif
                /**
                 *    Append the code point \c sv to \c dst as UTF-8.
+                *    @pre 4 <= dst.remaining()
                 */
                static void encodeUTF8(unsigned int sv, ByteBuffer& dst);
                /**
                 *    Append the code point \c sv to \c dst as UTF-16LE.
+                *    @pre 4 <= dst.remaining()
                 */
                static void encodeUTF16LE(unsigned int sv, ByteBuffer& dst);
                /**
                 *    Append the code point \c sv to \c dst as UTF-16BE.
+                *    @pre 4 <= dst.remaining()
                 */
                static void encodeUTF16BE(unsigned int sv, ByteBuffer& dst);
 
@@ -230,17 +233,10 @@ class LOG4CXX_EXPORT Transcoder
                 */
                static std::string encodeCharsetName(const LogString& 
charsetName);
 
-       private:
-
        private:
                Transcoder();
                Transcoder(const Transcoder&);
                Transcoder& operator=(const Transcoder&);
-               enum { BUFSIZE = 256 };
-               static size_t encodeUTF8(unsigned int ch, char* dst);
-               static size_t encodeUTF16BE(unsigned int ch, char* dst);
-               static size_t encodeUTF16LE(unsigned int ch, char* dst);
-
 };
 }
 }
diff --git a/src/main/include/log4cxx/private/bytebuffer_priv.h 
b/src/main/include/log4cxx/private/bytebuffer_priv.h
new file mode 100644
index 00000000..93ec2a1e
--- /dev/null
+++ b/src/main/include/log4cxx/private/bytebuffer_priv.h
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <log4cxx/helpers/bytebuffer.h>
+#include <cstring> // memmove
+
+using namespace LOG4CXX_NS;
+using namespace LOG4CXX_NS::helpers;
+
+struct LOG4CXX_NS::helpers::ByteBufferPriv
+{
+private: // Attributes
+       char* base;
+       size_t pos;
+       size_t lim;
+       size_t cap;
+
+public: // ...structor
+       ByteBufferPriv(char* data, size_t capacity)
+               : base(data)
+               , pos(0)
+               , lim(capacity)
+               , cap(capacity)
+               {}
+
+public: // Accessors
+       inline char* data();
+       inline const char* data() const;
+       inline char* current();
+       inline const char* current() const;
+       inline size_t limit() const;
+       inline size_t position() const;
+       inline size_t remaining() const;
+
+public: // Modifiers
+       inline void carry();
+       inline void clear();
+       inline void flip();
+       inline size_t increment_position(size_t byteCount);
+       inline bool put(char byteValue);
+
+#if LOG4CXX_ABI_VERSION <= 15
+       friend class ByteBuffer;
+#endif
+};
+
+void ByteBufferPriv::clear()
+{
+       this->lim = this->cap;
+       this->pos = 0;
+}
+
+void ByteBufferPriv::carry()
+{
+       auto available = remaining();
+       memmove(this->base, current(), available);
+       this->lim = this->cap;
+       this->pos = available;
+}
+
+void ByteBufferPriv::flip()
+{
+       this->lim = this->pos;
+       this->pos = 0;
+}
+
+bool ByteBufferPriv::put(char byte)
+{
+       if (this->pos < this->lim)
+       {
+               this->base[this->pos++] = byte;
+               return true;
+       }
+
+       return false;
+}
+
+char* ByteBufferPriv::data()
+{
+       return this->base;
+}
+
+const char* ByteBufferPriv::data() const
+{
+       return this->base;
+}
+
+char* ByteBufferPriv::current()
+{
+       return this->base + this->pos;
+}
+
+const char* ByteBufferPriv::current() const
+{
+       return this->base + this->pos;
+}
+
+size_t ByteBufferPriv::limit() const
+{
+       return this->lim;
+}
+
+size_t ByteBufferPriv::position() const
+{
+       return this->pos;
+}
+
+size_t ByteBufferPriv::remaining() const
+{
+       return this->lim - this->pos;
+}
+
+size_t ByteBufferPriv::increment_position(size_t byteCount)
+{
+    auto available = remaining();
+    this->pos += byteCount < available ? byteCount : available;
+    return remaining();
+}

Reply via email to