From 5a08dc0d9aeafe3b4e242e3b7722bfbd38acbbb2 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 | 38 ++++++++++++++++++- .../java/io/netty/buffer/UnpooledTest.java | 26 +++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/buffer/src/main/java/io/netty/buffer/Unpooled.java b/buffer/src/main/java/io/netty/buffer/Unpooled.java index 3976f4f896..1a64e0fd3c 100644 --- a/buffer/src/main/java/io/netty/buffer/Unpooled.java +++ b/buffer/src/main/java/io/netty/buffer/Unpooled.java @@ -17,6 +17,7 @@ package io.netty.buffer; import io.netty.buffer.CompositeByteBuf.ByteWrapper; import io.netty.util.internal.ObjectUtil; +import io.netty.util.CharsetUtil; import io.netty.util.internal.PlatformDependent; import java.nio.ByteBuffer; @@ -577,7 +578,12 @@ public final class Unpooled { */ public static ByteBuf copiedBuffer(CharSequence string, Charset charset) { ObjectUtil.checkNotNull(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); } @@ -585,6 +591,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 f7fd30ba91..25af662622 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));