/* * 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. */ package org.apache.cassandra.io.util; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; public class SafeMemoryWriter extends AbstractDataOutput implements DataOutputPlus { private ByteOrder order = ByteOrder.BIG_ENDIAN; private SafeMemory buffer; private long length; public SafeMemoryWriter(long initialCapacity) { buffer = new SafeMemory(initialCapacity); } public void write(byte[] buffer, int offset, int count) { long newLength = ensureCapacity(count); this.buffer.setBytes(this.length, buffer, offset, count); this.length = newLength; } public void write(int oneByte) { long newLength = ensureCapacity(1); buffer.setByte(length++, (byte) oneByte); length = newLength; } public void writeShort(int val) throws IOException { if (order != ByteOrder.nativeOrder()) val = Short.reverseBytes((short) val); long newLength = ensureCapacity(2); buffer.setShort(length, (short) val); length = newLength; } public void writeInt(int val) { if (order != ByteOrder.nativeOrder()) val = Integer.reverseBytes(val); long newLength = ensureCapacity(4); buffer.setInt(length, val); length = newLength; } public void writeLong(long val) { if (order != ByteOrder.nativeOrder()) val = Long.reverseBytes(val); long newLength = ensureCapacity(8); buffer.setLong(length, val); length = newLength; } public void write(ByteBuffer buffer) { long newLength = ensureCapacity(buffer.remaining()); this.buffer.setBytes(length, buffer); length = newLength; } public void write(Memory memory) { long newLength = ensureCapacity(memory.size()); buffer.put(length, memory, 0, memory.size()); length = newLength; } private long ensureCapacity(long size) { long newLength = this.length + size; if (newLength > buffer.size()) setCapacity(Math.max(newLength, buffer.size() + (buffer.size() / 2))); return newLength; } public SafeMemory currentBuffer() { return buffer; } public void setCapacity(long newCapacity) { if (newCapacity != capacity()) { SafeMemory oldBuffer = buffer; buffer = this.buffer.copy(newCapacity); oldBuffer.free(); } } public void close() { buffer.close(); } public long length() { return length; } public long capacity() { return buffer.size(); } // TODO: consider hoisting this into DataOutputPlus, since most implementations can copy with this gracefully // this would simplify IndexSummary.IndexSummarySerializer.serialize() public SafeMemoryWriter withByteOrder(ByteOrder order) { this.order = order; return this; } }