From 0c2c7c8f82d19342551048aaa271b25822b3937a Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Thu, 23 Apr 2020 17:47:16 +0200 Subject: [PATCH] Add fastpath implementation for Unpooled.copiedBuffer(CharSequence, Charset) when UTF-8 or US-ASCII is used (#10206) Motivation: We can make use of our optimized implementations for UTF-8 and US-ASCII if the user request a copy of a sequence for these charsets Modifications: - Add fastpath implementation - Add unit tests Result: Fixes https://github.com/netty/netty/issues/10205 --- .../main/java/io/netty/buffer/Unpooled.java | 37 +++++++++++++++++++ .../java/io/netty/buffer/UnpooledTest.java | 26 +++++++++++++ 2 files changed, 63 insertions(+) diff --git a/buffer/src/main/java/io/netty/buffer/Unpooled.java b/buffer/src/main/java/io/netty/buffer/Unpooled.java index 491991d189..0bee1dd01b 100644 --- a/buffer/src/main/java/io/netty/buffer/Unpooled.java +++ b/buffer/src/main/java/io/netty/buffer/Unpooled.java @@ -18,6 +18,7 @@ package io.netty.buffer; import static java.util.Objects.requireNonNull; import io.netty.buffer.CompositeByteBuf.ByteWrapper; +import io.netty.util.CharsetUtil; import io.netty.util.internal.PlatformDependent; import java.nio.ByteBuffer; @@ -579,6 +580,12 @@ public final class Unpooled { public static ByteBuf copiedBuffer(CharSequence string, Charset charset) { requireNonNull(string, "string"); + if (CharsetUtil.UTF_8.equals(charset)) { + return copiedBufferUtf8(string); + } + if (CharsetUtil.US_ASCII.equals(charset)) { + return copiedBufferAscii(string); + } if (string instanceof CharBuffer) { return copiedBuffer((CharBuffer) string, charset); } @@ -586,6 +593,36 @@ public final class Unpooled { return copiedBuffer(CharBuffer.wrap(string), charset); } + private static ByteBuf copiedBufferUtf8(CharSequence string) { + boolean release = true; + // Mimic the same behavior as other copiedBuffer implementations. + ByteBuf buffer = ALLOC.heapBuffer(ByteBufUtil.utf8Bytes(string)); + try { + ByteBufUtil.writeUtf8(buffer, string); + release = false; + return buffer; + } finally { + if (release) { + buffer.release(); + } + } + } + + private static ByteBuf copiedBufferAscii(CharSequence string) { + boolean release = true; + // Mimic the same behavior as other copiedBuffer implementations. + ByteBuf buffer = ALLOC.heapBuffer(string.length()); + try { + ByteBufUtil.writeAscii(buffer, string); + release = false; + return buffer; + } finally { + if (release) { + buffer.release(); + } + } + } + /** * Creates a new big-endian buffer whose content is a subregion of * the specified {@code string} encoded in the specified {@code charset}. diff --git a/buffer/src/test/java/io/netty/buffer/UnpooledTest.java b/buffer/src/test/java/io/netty/buffer/UnpooledTest.java index 458f51eb5b..49db811313 100644 --- a/buffer/src/test/java/io/netty/buffer/UnpooledTest.java +++ b/buffer/src/test/java/io/netty/buffer/UnpooledTest.java @@ -15,12 +15,14 @@ */ package io.netty.buffer; +import io.netty.util.CharsetUtil; import org.junit.Test; import org.mockito.Mockito; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.channels.ScatteringByteChannel; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -308,6 +310,30 @@ public class UnpooledTest { assertEquals(0, buf2.refCnt()); } + @Test + public void testCopiedBufferUtf8() { + testCopiedBufferCharSequence("Some UTF_8 like äÄ∏ŒŒ", CharsetUtil.UTF_8); + } + + @Test + public void testCopiedBufferAscii() { + testCopiedBufferCharSequence("Some US_ASCII", CharsetUtil.US_ASCII); + } + + @Test + public void testCopiedBufferSomeOtherCharset() { + testCopiedBufferCharSequence("Some ISO_8859_1", CharsetUtil.ISO_8859_1); + } + + private static void testCopiedBufferCharSequence(CharSequence sequence, Charset charset) { + ByteBuf copied = copiedBuffer(sequence, charset); + try { + assertEquals(sequence, copied.toString(charset)); + } finally { + copied.release(); + } + } + @Test public void testCopiedBuffer() { ByteBuf copied = copiedBuffer(ByteBuffer.allocateDirect(16));