31 package com.google.protobuf;
36 import java.io.IOException;
37 import java.io.OutputStream;
40 import java.nio.ByteBuffer;
41 import java.nio.channels.WritableByteChannel;
44 final class ByteBufferWriter {
45 private ByteBufferWriter() {}
52 private static final int MIN_CACHED_BUFFER_SIZE = 1024;
59 private static final int MAX_CACHED_BUFFER_SIZE = 16 * 1024;
63 private static final float BUFFER_REALLOCATION_THRESHOLD = 0.5f;
71 private static final ThreadLocal<SoftReference<byte[]>> BUFFER =
72 new ThreadLocal<SoftReference<byte[]>>();
75 private static final Class<?> FILE_OUTPUT_STREAM_CLASS = safeGetClass(
"java.io.FileOutputStream");
77 private static final long CHANNEL_FIELD_OFFSET = getChannelFieldOffset(FILE_OUTPUT_STREAM_CLASS);
83 static void clearCachedBuffer() {
91 static void write(ByteBuffer
buffer, OutputStream
output)
throws IOException {
92 final int initialPos =
buffer.position();
101 final byte[]
array = getOrCreateBuffer(
buffer.remaining());
102 while (
buffer.hasRemaining()) {
110 buffer.position(initialPos);
114 private static byte[] getOrCreateBuffer(
int requestedSize) {
115 requestedSize = max(requestedSize, MIN_CACHED_BUFFER_SIZE);
117 byte[]
buffer = getBuffer();
120 buffer =
new byte[requestedSize];
123 if (requestedSize <= MAX_CACHED_BUFFER_SIZE) {
130 private static boolean needToReallocate(
int requestedSize,
int bufferLength) {
132 return bufferLength < requestedSize
133 && bufferLength < requestedSize * BUFFER_REALLOCATION_THRESHOLD;
136 private static byte[] getBuffer() {
137 SoftReference<byte[]> sr = BUFFER.get();
138 return sr ==
null ? null : sr.get();
141 private static void setBuffer(
byte[]
value) {
142 BUFFER.set(
new SoftReference<
byte[]>(
value));
145 private static boolean writeToChannel(ByteBuffer
buffer, OutputStream
output)
throws IOException {
146 if (CHANNEL_FIELD_OFFSET >= 0 && FILE_OUTPUT_STREAM_CLASS.isInstance(
output)) {
148 WritableByteChannel channel =
null;
150 channel = (WritableByteChannel) UnsafeUtil.getObject(
output, CHANNEL_FIELD_OFFSET);
151 }
catch (ClassCastException e) {
154 if (channel !=
null) {
162 private static Class<?> safeGetClass(String className) {
164 return Class.forName(className);
165 }
catch (ClassNotFoundException e) {
170 private static long getChannelFieldOffset(Class<?> clazz) {
172 if (clazz !=
null && UnsafeUtil.hasUnsafeArrayOperations()) {
173 Field field = clazz.getDeclaredField(
"channel");
174 return UnsafeUtil.objectFieldOffset(
field);
176 }
catch (Throwable e) {