diff options
Diffstat (limited to 'dotnet/Qpid.Buffer')
-rw-r--r-- | dotnet/Qpid.Buffer/BaseByteBuffer.cs | 461 | ||||
-rw-r--r-- | dotnet/Qpid.Buffer/BufferDataException.cs | 47 | ||||
-rw-r--r-- | dotnet/Qpid.Buffer/ByteBuffer.cs | 2543 | ||||
-rw-r--r-- | dotnet/Qpid.Buffer/ByteBufferAllocator.cs | 50 | ||||
-rw-r--r-- | dotnet/Qpid.Buffer/ByteBufferHexDumper.cs | 4 | ||||
-rw-r--r-- | dotnet/Qpid.Buffer/ByteBufferProxy.cs | 298 | ||||
-rw-r--r-- | dotnet/Qpid.Buffer/FixedByteBuffer.cs | 367 | ||||
-rw-r--r-- | dotnet/Qpid.Buffer/HeapByteBuffer.cs | 113 | ||||
-rw-r--r-- | dotnet/Qpid.Buffer/Qpid.Buffer.csproj | 6 | ||||
-rw-r--r-- | dotnet/Qpid.Buffer/RefCountingByteBuffer.cs | 336 | ||||
-rw-r--r-- | dotnet/Qpid.Buffer/SimpleByteBufferAllocator.cs | 190 |
11 files changed, 3573 insertions, 842 deletions
diff --git a/dotnet/Qpid.Buffer/BaseByteBuffer.cs b/dotnet/Qpid.Buffer/BaseByteBuffer.cs new file mode 100644 index 0000000000..099c84d6fa --- /dev/null +++ b/dotnet/Qpid.Buffer/BaseByteBuffer.cs @@ -0,0 +1,461 @@ +/* + * + * 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.mina.common.support; +// +//import java.nio.ByteOrder; +//import java.nio.CharBuffer; +//import java.nio.DoubleBuffer; +//import java.nio.FloatBuffer; +//import java.nio.IntBuffer; +//import java.nio.LongBuffer; +//import java.nio.ShortBuffer; +// +//import org.apache.mina.common.ByteBuffer; +//import org.apache.mina.common.ByteBufferAllocator; + +namespace Qpid.Buffer +{ + /** + * A base implementation of {@link ByteBuffer}. This implementation + * assumes that {@link ByteBuffer#buf()} always returns a correct NIO + * {@link FixedByteBuffer} instance. Most implementations could + * extend this class and implement their own buffer management mechanism. + * + * @noinspection StaticNonFinalField + * @see ByteBufferAllocator + */ + public abstract class BaseByteBuffer : ByteBuffer + { + private bool _autoExpand; + + /** + * We don't have any access to Buffer.markValue(), so we need to track it down, + * which will cause small extra overhead. + */ + private int _mark = -1; + + protected BaseByteBuffer() + { + } + + public override bool isDirect() + { + return buf().isDirect(); + } + + public override bool isReadOnly() + { + return buf().isReadOnly(); + } + + public override int capacity() + { + return buf().capacity(); + } + + public override ByteBuffer capacity(int newCapacity) + { + if( newCapacity > capacity() ) + { + // Allocate a new buffer and transfer all settings to it. + int pos = position(); + int lim = limit(); + ByteOrder bo = order(); + + capacity0( newCapacity ); + buf().limit( lim ); + if( _mark >= 0 ) + { + buf().position( _mark ); + buf().mark(); + } + buf().position( pos ); + buf().order( bo ); + } + + return this; + } + + /** + * Implement this method to increase the capacity of this buffer. + * <tt>newCapacity</tt> is always greater than the current capacity. + */ + protected abstract void capacity0( int newCapacity ); + + public override bool isAutoExpand() + { + return _autoExpand; + } + + public override ByteBuffer setAutoExpand(bool autoExpand) + { + _autoExpand = autoExpand; + return this; + } + + public override ByteBuffer expand(int pos, int expectedRemaining) + { + int end = pos + expectedRemaining; + if( end > capacity() ) + { + // The buffer needs expansion. + capacity( end ); + } + + if( end > limit() ) + { + // We call limit() directly to prevent StackOverflowError + buf().limit( end ); + } + return this; + } + + public override int position() + { + return buf().position(); + } + + public override ByteBuffer position(int newPosition) + { + autoExpand( newPosition, 0 ); + buf().position( newPosition ); + if( _mark > newPosition ) + { + _mark = -1; + } + return this; + } + + public override int limit() + { + return buf().limit(); + } + + public override ByteBuffer limit(int newLimit) + { + autoExpand( newLimit, 0 ); + buf().limit( newLimit ); + if( _mark > newLimit ) + { + _mark = -1; + } + return this; + } + + public override ByteBuffer mark() + { + buf().mark(); + _mark = position(); + return this; + } + + public override int markValue() + { + return _mark; + } + + public override ByteBuffer reset() + { + buf().reset(); + return this; + } + + public override ByteBuffer clear() + { + buf().clear(); + _mark = -1; + return this; + } + + public override ByteBuffer flip() + { + buf().flip(); + _mark = -1; + return this; + } + + public override ByteBuffer rewind() + { + buf().rewind(); + _mark = -1; + return this; + } + + public override byte get() + { + return buf().get(); + } + + public override ByteBuffer put(byte b) + { + autoExpand( 1 ); + buf().put( b ); + return this; + } + + public override byte get(int index) + { + return buf().get( index ); + } + + public override ByteBuffer put(int index, byte b) + { + autoExpand( index, 1 ); + buf().put( index, b ); + return this; + } + + public override ByteBuffer get(byte[] dst, int offset, int length) + { + buf().get( dst, offset, length ); + return this; + } + + public override ByteBuffer get(byte[] dst) + { + buf().get(dst); + return this; + } + + public override ByteBuffer put(FixedByteBuffer src) + { + autoExpand( src.remaining() ); + buf().put( src ); + return this; + } + + public override ByteBuffer put(byte[] src, int offset, int length) + { + autoExpand( length ); + buf().put( src, offset, length ); + return this; + } + + public override ByteBuffer compact() + { + buf().compact(); + _mark = -1; + return this; + } + + public override ByteOrder order() + { + return buf().order(); + } + + public override ByteBuffer order(ByteOrder bo) + { + buf().order( bo ); + return this; + } + + public override char getChar() + { + return buf().getChar(); + } + + public override ByteBuffer putChar(char value) + { + autoExpand( 2 ); + buf().putChar( value ); + return this; + } + + public override char getChar(int index) + { + return buf().getChar( index ); + } + + public override ByteBuffer putChar(int index, char value) + { + autoExpand( index, 2 ); + buf().putChar( index, value ); + return this; + } + +// public CharBuffer asCharBuffer() +// { +// return buf().asCharBuffer(); +// } + + public override short getShort() + { + return buf().getShort(); + } + + public override ByteBuffer putShort(short value) + { + autoExpand( 2 ); + buf().putShort( value ); + return this; + } + + public override short getShort(int index) + { + return buf().getShort( index ); + } + + public override ByteBuffer putShort(int index, short value) + { + autoExpand( index, 2 ); + buf().putShort( index, value ); + return this; + } + + public override ushort GetUnsignedShort() + { + return buf().getUnsignedShort(); + } + + +// public ShortBuffer asShortBuffer() +// { +// return buf().asShortBuffer(); +// } + + public override int getInt() + { + return buf().getInt(); + } + + public override uint GetUnsignedInt() + { + return buf().getUnsignedInt(); + } + + public override ByteBuffer putInt(int value) + { + autoExpand( 4 ); + buf().putInt( value ); + return this; + } + + public override int getInt(int index) + { + return buf().getInt( index ); + } + + public override ByteBuffer putInt(int index, int value) + { + autoExpand( index, 4 ); + buf().putInt( index, value ); + return this; + } + +// public IntBuffer asIntBuffer() +// { +// return buf().asIntBuffer(); +// } + + public override long getLong() + { + return buf().getLong(); + } + + public override ByteBuffer putLong(long value) + { + autoExpand( 8 ); + buf().putLong( value ); + return this; + } + + public override long getLong(int index) + { + return buf().getLong( index ); + } + + public override ByteBuffer putLong(int index, long value) + { + autoExpand( index, 8 ); + buf().putLong( index, value ); + return this; + } + +// public LongBuffer asLongBuffer() +// { +// return buf().asLongBuffer(); +// } + + public override float getFloat() + { + return buf().getFloat(); + } + + public override ByteBuffer putFloat(float value) + { + autoExpand( 4 ); + buf().putFloat( value ); + return this; + } + + public override float getFloat(int index) + { + return buf().getFloat( index ); + } + + public override ByteBuffer putFloat(int index, float value) + { + autoExpand( index, 4 ); + buf().putFloat( index, value ); + return this; + } + +// public FloatBuffer asFloatBuffer() +// { +// return buf().asFloatBuffer(); +// } + + public override double getDouble() + { + return buf().getDouble(); + } + + public override ByteBuffer putDouble(double value) + { + autoExpand( 8 ); + buf().putDouble( value ); + return this; + } + + public override double getDouble(int index) + { + return buf().getDouble( index ); + } + + public override ByteBuffer putDouble(int index, double value) + { + autoExpand( index, 8 ); + buf().putDouble( index, value ); + return this; + } + + public override ByteBuffer put(byte[] src) + { + buf().put(src); + return this; + } + +// public DoubleBuffer asDoubleBuffer() +// { +// return buf().asDoubleBuffer(); +// } + } +}
\ No newline at end of file diff --git a/dotnet/Qpid.Buffer/BufferDataException.cs b/dotnet/Qpid.Buffer/BufferDataException.cs new file mode 100644 index 0000000000..1c6c37e84f --- /dev/null +++ b/dotnet/Qpid.Buffer/BufferDataException.cs @@ -0,0 +1,47 @@ +/* + * + * 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. + * + */ +using System; + +namespace Qpid.Buffer +{ + /** + * A {@link RuntimeException} which is thrown when the data the {@link ByteBuffer} + * contains is corrupt. + */ + public class BufferDataException : Exception + { + public BufferDataException() + { + } + + public BufferDataException( String message ) : base(message) + { + } + + public BufferDataException( String message, Exception cause ) : base(message, cause) + { + } + + public BufferDataException( Exception cause ) : base("", cause) + { + } + } +} diff --git a/dotnet/Qpid.Buffer/ByteBuffer.cs b/dotnet/Qpid.Buffer/ByteBuffer.cs index 70022407a5..1a43c0b9f3 100644 --- a/dotnet/Qpid.Buffer/ByteBuffer.cs +++ b/dotnet/Qpid.Buffer/ByteBuffer.cs @@ -19,432 +19,2375 @@ * */ using System; -using System.Collections; using System.Text; namespace Qpid.Buffer { - /// <summary> - /// A buffer that manages an underlying byte oriented stream, and writes and reads to and from it in - /// BIG ENDIAN order. - /// </summary> - public abstract class ByteBuffer + public enum ByteOrder { BigEndian, LittleEndian } +// /// <summary> +// /// A buffer that manages an underlying byte oriented stream, and writes and reads to and from it in +// /// BIG ENDIAN order. +// /// </summary> +// public abstract class ByteBuffer +// { +// protected const int MINIMUM_CAPACITY = 1; +// +// protected static Stack _containerStack = new Stack(); +// +// protected static Stack[] _heapBufferStacks = new Stack[] +// { +// new Stack(), new Stack(), new Stack(), new Stack(), +// new Stack(), new Stack(), new Stack(), new Stack(), +// new Stack(), new Stack(), new Stack(), new Stack(), +// new Stack(), new Stack(), new Stack(), new Stack(), +// new Stack(), new Stack(), new Stack(), new Stack(), +// new Stack(), new Stack(), new Stack(), new Stack(), +// new Stack(), new Stack(), new Stack(), new Stack(), +// new Stack(), new Stack(), new Stack(), new Stack() +// }; +// +// /// <summary> +// /// Returns the direct or heap buffer which is capable of the specified size. +// /// Currently does not support direct buffers but this will be an option in future. +// /// </summary> +// /// <param name="capacity">The capacity.</param> +// /// <returns></returns> +// public static ByteBuffer Allocate(int capacity) +// { +// // for now, just allocate a heap buffer but in future could do an optimised "direct" buffer +// // that is implemented natively +// return Allocate(capacity, false); +// } +// +// public static ByteBuffer Allocate(int capacity, bool direct) +// { +// ByteBuffer buffer = Allocate0(capacity, direct); +// RefCountingByteBuffer buf = AllocateContainer(); +// buf.Init(buffer); +// return buf; +// } +// +// private static RefCountingByteBuffer AllocateContainer() +// { +// RefCountingByteBuffer buf = null; +// lock (_containerStack) +// { +// if (_containerStack.Count > 0) +// { +// buf = (RefCountingByteBuffer) _containerStack.Pop(); +// } +// } +// +// if (buf == null) +// { +// buf = new RefCountingByteBuffer(); +// } +// return buf; +// } +// +// protected static ByteBuffer Allocate0(int capacity, bool direct) +// { +// if (direct) +// { +// throw new NotSupportedException("Direct buffers not currently implemented"); +// } +// int idx = GetBufferStackIndex(_heapBufferStacks, capacity); +// Stack stack = _heapBufferStacks[idx]; +// ByteBuffer buf = null; +// lock (stack) +// { +// if (stack.Count > 0) +// { +// buf = (ByteBuffer) stack.Pop(); +// } +// } +// +// if (buf == null) +// { +// buf = new HeapByteBuffer(MINIMUM_CAPACITY << idx); +// } +// +// return buf; +// } +// +// protected static void Release0(ByteBuffer buf) +// { +// Stack stack = _heapBufferStacks[GetBufferStackIndex(_heapBufferStacks, buf.Capacity)]; +// lock (stack) +// { +// stack.Push(buf); +// } +// } +// +// private static int GetBufferStackIndex(Stack[] bufferStacks, int size) +// { +// int targetSize = MINIMUM_CAPACITY; +// int stackIdx = 0; +// // each bucket contains buffers that are double the size of the previous bucket +// while (size > targetSize) +// { +// targetSize <<= 1; +// stackIdx++; +// if (stackIdx >= bufferStacks.Length) +// { +// throw new ArgumentOutOfRangeException("size", "Buffer size is too big: " + size); +// } +// } +// return stackIdx; +// } +// +// /// <summary> +// /// Increases the internal reference count of this buffer to defer automatic release. You have +// /// to invoke release() as many times as you invoked this method to release this buffer. +// /// </summary> +// public abstract void Acquire(); +// +// /// <summary> +// /// Releases the specified buffer to the buffer pool. +// /// </summary> +// public abstract void Release(); +// +// public abstract int Capacity +// { +// get; +// } +// +// public abstract bool IsAutoExpand +// { +// get; +// set; +// } +// +// /// <summary> +// /// Changes the capacity and limit of this buffer sot his buffer gets the specified +// /// expectedRemaining room from the current position. This method works even if you didn't set +// /// autoExpand to true. +// /// </summary> +// /// <param name="expectedRemaining">Room you want from the current position</param> +// public abstract void Expand(int expectedRemaining); +// +// /// <summary> +// /// Changes the capacity and limit of this buffer sot his buffer gets the specified +// /// expectedRemaining room from the specified position. +// /// </summary> +// /// <param name="pos">The pos you want the room to be available from.</param> +// /// <param name="expectedRemaining">The expected room you want available.</param> +// public abstract void Expand(int pos, int expectedRemaining); +// +// /// <summary> +// /// Returns true if and only if this buffer is returned back to the buffer pool when released. +// /// </summary> +// /// <value><c>true</c> if pooled; otherwise, <c>false</c>.</value> +// public abstract bool Pooled +// { +// get; +// set; +// } +// +// public abstract int Position +// { +// get; +// set; +// } +// +// public abstract int Limit +// { +// get; +// set; +// } +// +// //public abstract void Mark(); +// +// //public abstract void Reset(); +// +// public abstract void Clear(); +// +// /// <summary> +// /// Clears this buffer and fills its content with NULL. The position is set to zero, the limit is set to +// /// capacity and the mark is discarded. +// /// </summary> +// public void Sweep() +// { +// Clear(); +// FillAndReset(Remaining); +// } +// +// public void Sweep(byte value) +// { +// Clear(); +// FillAndReset(value, Remaining); +// } +// +// public abstract void Flip(); +// +// public abstract void Rewind(); +// +// public abstract int Remaining +// { +// get; +// } +// +// public bool HasRemaining() +// { +// return Remaining > 0; +// } +// +// public abstract byte Get(); +// +// public abstract byte Get(int index); +// +// public abstract void Get(byte[] destination); +// +// public abstract ushort GetUnsignedShort(); +// +// public abstract uint GetUnsignedInt(); +// +// public abstract ulong GetUnsignedLong(); +// +// public abstract string GetString(uint length, Encoding encoder); +// +// public abstract void Put(byte data); +// +// public abstract void Put(byte[] data); +// public abstract void Put(byte[] data, int offset, int size); +// +// public abstract void Put(ushort data); +// +// public abstract void Put(uint data); +// +// public abstract void Put(ulong data); +// +// public abstract void Put(ByteBuffer buf); +// +// public abstract void Compact(); +// +// public abstract byte[] ToByteArray(); +// +// public override string ToString() +// { +// StringBuilder buf = new StringBuilder(); +// buf.Append("HeapBuffer"); +// buf.AppendFormat("[pos={0} lim={1} cap={2} : {3}]", Position, Limit, Capacity, HexDump); +// return buf.ToString(); +// } +// +// public override int GetHashCode() +// { +// int h = 1; +// int p = Position; +// for (int i = Limit - 1; i >= p; i--) +// { +// h = 31 * h + Get(i); +// } +// +// return h; +// } +// +// public override bool Equals(object obj) +// { +// if (!(obj is ByteBuffer)) +// { +// return false; +// } +// ByteBuffer that = (ByteBuffer) obj; +// +// if (Remaining != that.Remaining) +// { +// return false; +// } +// int p = Position; +// for (int i = Limit - 1, j = that.Limit - 1; i >= p; i--, j--) +// { +// byte v1 = this.Get(i); +// byte v2 = that.Get(j); +// if (v1 != v2) +// { +// return false; +// } +// } +// return true; +// } +// +// public string HexDump +// { +// get +// { +// return ByteBufferHexDumper.GetHexDump(this); +// } +// } +// +// /// <summary> +// /// Fills the buffer with the specified specified value. This method moves the buffer position forward. +// /// </summary> +// /// <param name="value">The value.</param> +// /// <param name="size">The size.</param> +// public void Fill(byte value, int size) +// { +// AutoExpand(size); +// int q = size >> 3; +// int r = size & 7; +// +// if (q > 0) +// { +// int intValue = value | (value << 8) | (value << 16) | (value << 24); +// long longValue = intValue; +// longValue <<= 32; +// longValue |= (ushort)intValue; +// +// for (int i = q; i > 0; i--) +// { +// Put((ulong)longValue); +// } +// } +// +// q = r >> 2; +// r = r & 3; +// +// if (q > 0) +// { +// int intValue = value | (value << 8) | (value << 16) | (value << 24); +// Put((uint)intValue); +// } +// +// q = r >> 1; +// r = r & 1; +// +// if (q > 0) +// { +// short shortValue = (short) (value | (value << 8)); +// Put((ushort) shortValue); +// } +// if (r > 0) +// { +// Put(value); +// } +// } +// +// public void FillAndReset(byte value, int size) +// { +// AutoExpand(size); +// int pos = Position; +// try +// { +// Fill(value, size); +// } +// finally +// { +// Position = pos; +// } +// } +// +// public void Fill(int size) +// { +// AutoExpand(size); +// int q = size >> 3; +// int r = size & 7; +// +// for (int i = q; i > 0; i--) +// { +// Put(0L); +// } +// +// q = r >> 2; +// r = r & 3; +// +// if (q > 0) +// { +// Put(0); +// } +// +// q = r >> 1; +// r = r & 1; +// +// if(q > 0) +// { +// Put((ushort) 0); +// } +// +// if (r > 0) +// { +// Put((byte) 0); +// } +// } +// +// public void FillAndReset(int size) +// { +// AutoExpand(size); +// int pos = Position; +// try +// { +// Fill(size); +// } +// finally +// { +// Position = pos; +// } +// } +// +// public void Skip(int size) +// { +// AutoExpand(size); +// Position = Position + size; +// } +// +// protected void AutoExpand(int expectedRemaining) +// { +// if (IsAutoExpand) +// { +// Expand(expectedRemaining); +// } +// } +// +// protected void AutoExpand(int pos, int expectedRemaining) +// { +// if (IsAutoExpand) +// { +// Expand(pos, expectedRemaining); +// } +// } +// } + + /* + * 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.mina.common; +// +//import java.io.IOException; +//import java.io.InputStream; +//import java.io.ObjectInputStream; +//import java.io.ObjectOutputStream; +//import java.io.ObjectStreamClass; +//import java.io.OutputStream; +//import java.nio.BufferOverflowException; +//import java.nio.BufferUnderflowException; +//import java.nio.ByteOrder; +//import java.nio.CharBuffer; +//import java.nio.DoubleBuffer; +//import java.nio.FloatBuffer; +//import java.nio.IntBuffer; +//import java.nio.LongBuffer; +//import java.nio.ShortBuffer; +//import java.nio.charset.CharacterCodingException; +//import java.nio.charset.CharsetDecoder; +//import java.nio.charset.CharsetEncoder; +//import java.nio.charset.CoderResult; +// +//import org.apache.mina.common.support.ByteBufferHexDumper; +//import org.apache.mina.filter.codec.ProtocolEncoderOutput; + + /** + * A byte buffer used by MINA applications. + * <p> + * This is a replacement for {@link FixedByteBuffer}. Please refer to + * {@link FixedByteBuffer} and {@link java.nio.Buffer} documentation for + * usage. MINA does not use NIO {@link FixedByteBuffer} directly for two + * reasons: + * <ul> + * <li>It doesn't provide useful getters and putters such as + * <code>fill</code>, <code>get/putString</code>, and + * <code>get/putAsciiInt()</code> enough.</li> + * <li>It is hard to distinguish if the buffer is created from MINA buffer + * pool or not. MINA have to return used buffers back to pool.</li> + * <li>It is difficult to write variable-length data due to its fixed + * capacity</li> + * </ul> + * </p> + * + * <h2>Allocation</h2> + * <p> + * You can get a heap buffer from buffer pool: + * <pre> + * ByteBuffer buf = ByteBuffer.allocate(1024, false); + * </pre> + * you can also get a direct buffer from buffer pool: + * <pre> + * ByteBuffer buf = ByteBuffer.allocate(1024, true); + * </pre> + * or you can let MINA choose: + * <pre> + * ByteBuffer buf = ByteBuffer.allocate(1024); + * </pre> + * </p> + * + * <h2>Acquire/Release</h2> + * <p> + * <b>Please note that you never need to release the allocated buffer</b> + * because MINA will release it automatically when: + * <ul> + * <li>You pass the buffer by calling {@link IoSession#write(Object)}.</li> + * <li>You pass the buffer by calling {@link IoFilter.NextFilter#filterWrite(IoSession,IoFilter.WriteRequest)}.</li> + * <li>You pass the buffer by calling {@link ProtocolEncoderOutput#write(ByteBuffer)}.</li> + * </ul> + * And, you don't need to release any {@link ByteBuffer} which is passed as a parameter + * of {@link IoHandler#messageReceived(IoSession, Object)} method. They are released + * automatically when the method returns. + * <p> + * You have to release buffers manually by calling {@link #release()} when: + * <ul> + * <li>You allocated a buffer, but didn't pass the buffer to any of two methods above.</li> + * <li>You called {@link #acquire()} to prevent the buffer from being released.</li> + * </ul> + * </p> + * + * <h2>Wrapping existing NIO buffers and arrays</h2> + * <p> + * This class provides a few <tt>wrap(...)</tt> methods that wraps + * any NIO buffers and byte arrays. Wrapped MINA buffers are not returned + * to the buffer pool by default to prevent unexpected memory leakage by default. + * In case you want to make it pooled, you can call {@link #setPooled(bool)} + * with <tt>true</tt> flag to enable pooling. + * + * <h2>AutoExpand</h2> + * <p> + * Writing variable-length data using NIO <tt>ByteBuffers</tt> is not really + * easy, and it is because its size is fixed. MINA <tt>ByteBuffer</tt> + * introduces <tt>autoExpand</tt> property. If <tt>autoExpand</tt> property + * is true, you never get {@link BufferOverflowException} or + * {@link IndexOutOfBoundsException} (except when index is negative). + * It automatically expands its capacity and limit value. For example: + * <pre> + * String greeting = messageBundle.getMessage( "hello" ); + * ByteBuffer buf = ByteBuffer.allocate( 16 ); + * // Turn on autoExpand (it is off by default) + * buf.setAutoExpand( true ); + * buf.putString( greeting, utf8encoder ); + * </pre> + * NIO <tt>ByteBuffer</tt> is reallocated by MINA <tt>ByteBuffer</tt> behind + * the scene if the encoded data is larger than 16 bytes. Its capacity will + * increase by two times, and its limit will increase to the last position + * the string is written. + * </p> + * + * <h2>Derived Buffers</h2> + * <p> + * Derived buffers are the buffers which were created by + * {@link #duplicate()}, {@link #slice()}, or {@link #asReadOnlyBuffer()}. + * They are useful especially when you broadcast the same messages to + * multiple {@link IoSession}s. Please note that the derived buffers are + * neither pooled nor auto-expandable. Trying to expand a derived buffer will + * raise {@link IllegalStateException}. + * </p> + * + * <h2>Changing Buffer Allocation and Management Policy</h2> + * <p> + * MINA provides a {@link ByteBufferAllocator} interface to let you override + * the default buffer management behavior. There are two allocators provided + * out-of-the-box: + * <ul> + * <li>{@link PooledByteBufferAllocator} (Default)</li> + * <li>{@link SimpleByteBufferAllocator}</li> + * </ul> + * You can change the allocator by calling {@link #setAllocator(ByteBufferAllocator)}. + * </p> + * + * @author The Apache Directory Project (mina-dev@directory.apache.org) + * @version $Rev: 451854 $, $Date: 2006-10-02 11:30:11 +0900 (ì›”, 02 10ì›” 2006) $ + * @noinspection StaticNonFinalField + * @see ByteBufferAllocator + */ + public abstract class ByteBuffer : IComparable { - protected const int MINIMUM_CAPACITY = 1; - - protected static Stack _containerStack = new Stack(); - - protected static Stack[] _heapBufferStacks = new Stack[] - { - new Stack(), new Stack(), new Stack(), new Stack(), - new Stack(), new Stack(), new Stack(), new Stack(), - new Stack(), new Stack(), new Stack(), new Stack(), - new Stack(), new Stack(), new Stack(), new Stack(), - new Stack(), new Stack(), new Stack(), new Stack(), - new Stack(), new Stack(), new Stack(), new Stack(), - new Stack(), new Stack(), new Stack(), new Stack(), - new Stack(), new Stack(), new Stack(), new Stack() - }; - - /// <summary> - /// Returns the direct or heap buffer which is capable of the specified size. - /// Currently does not support direct buffers but this will be an option in future. - /// </summary> - /// <param name="capacity">The capacity.</param> - /// <returns></returns> - public static ByteBuffer Allocate(int capacity) - { - // for now, just allocate a heap buffer but in future could do an optimised "direct" buffer - // that is implemented natively - return Allocate(capacity, false); - } - - public static ByteBuffer Allocate(int capacity, bool direct) - { - ByteBuffer buffer = Allocate0(capacity, direct); - RefCountingByteBuffer buf = AllocateContainer(); - buf.Init(buffer); - return buf; - } - - private static RefCountingByteBuffer AllocateContainer() + //private static ByteBufferAllocator allocator = new PooledByteBufferAllocator(); + private static ByteBufferAllocator allocator = new SimpleByteBufferAllocator(); + + private static bool _useDirectBuffers = false; + + public string HexDump { - RefCountingByteBuffer buf = null; - lock (_containerStack) - { - if (_containerStack.Count > 0) - { - buf = (RefCountingByteBuffer) _containerStack.Pop(); - } - } - - if (buf == null) + get { - buf = new RefCountingByteBuffer(); + return ByteBufferHexDumper.GetHexDump(this); } - return buf; } - - protected static ByteBuffer Allocate0(int capacity, bool direct) + + /** + * Returns the current allocator which manages the allocated buffers. + */ + public static ByteBufferAllocator getAllocator() { - if (direct) - { - throw new NotSupportedException("Direct buffers not currently implemented"); - } - int idx = GetBufferStackIndex(_heapBufferStacks, capacity); - Stack stack = _heapBufferStacks[idx]; - ByteBuffer buf = null; - lock (stack) + return allocator; + } + + /** + * Changes the current allocator with the specified one to manage + * the allocated buffers from now. + */ + public static void setAllocator( ByteBufferAllocator newAllocator ) + { + if( newAllocator == null ) { - if (stack.Count > 0) - { - buf = (ByteBuffer) stack.Pop(); - } + throw new NullReferenceException("allocator cannot be null"); } - if (buf == null) + ByteBufferAllocator oldAllocator = allocator; + + allocator = newAllocator; + + if( null != oldAllocator ) { - buf = new HeapByteBuffer(MINIMUM_CAPACITY << idx); + oldAllocator.dispose(); } + } - return buf; + public static bool isUseDirectBuffers() + { + return _useDirectBuffers; } - - protected static void Release0(ByteBuffer buf) + + public static void setUseDirectBuffers( bool useDirectBuffers ) { - Stack stack = _heapBufferStacks[GetBufferStackIndex(_heapBufferStacks, buf.Capacity)]; - lock (stack) - { - stack.Push(buf); - } + _useDirectBuffers = useDirectBuffers; } - - private static int GetBufferStackIndex(Stack[] bufferStacks, int size) + + /** + * Returns the direct or heap buffer which is capable of the specified + * size. This method tries to allocate direct buffer first, and then + * tries heap buffer if direct buffer memory is exhausted. Please use + * {@link #allocate(int, bool)} to allocate buffers of specific type. + * + * @param capacity the capacity of the buffer + */ + public static ByteBuffer allocate( int capacity ) { - int targetSize = MINIMUM_CAPACITY; - int stackIdx = 0; - // each bucket contains buffers that are double the size of the previous bucket - while (size > targetSize) + if( _useDirectBuffers ) { - targetSize <<= 1; - stackIdx++; - if (stackIdx >= bufferStacks.Length) + try + { + // first try to allocate direct buffer + return allocate( capacity, true ); + } + catch (OutOfMemoryException) { - throw new ArgumentOutOfRangeException("size", "Buffer size is too big: " + size); + // fall through to heap buffer } } - return stackIdx; - } - - /// <summary> - /// Increases the internal reference count of this buffer to defer automatic release. You have - /// to invoke release() as many times as you invoked this method to release this buffer. - /// </summary> - public abstract void Acquire(); - /// <summary> - /// Releases the specified buffer to the buffer pool. - /// </summary> - public abstract void Release(); + return allocate( capacity, false ); + } - public abstract int Capacity + /** + * Returns the buffer which is capable of the specified size. + * + * @param capacity the capacity of the buffer + * @param direct <tt>true</tt> to get a direct buffer, + * <tt>false</tt> to get a heap buffer. + */ + public static ByteBuffer allocate( int capacity, bool direct ) { - get; + return allocator.allocate( capacity, direct ); } - public abstract bool IsAutoExpand + /** + * Wraps the specified NIO {@link FixedByteBuffer} into MINA buffer. + */ + public static ByteBuffer wrap( FixedByteBuffer nioBuffer ) { - get; - set; + return allocator.wrap( nioBuffer ); } - /// <summary> - /// Changes the capacity and limit of this buffer sot his buffer gets the specified - /// expectedRemaining room from the current position. This method works even if you didn't set - /// autoExpand to true. - /// </summary> - /// <param name="expectedRemaining">Room you want from the current position</param> - public abstract void Expand(int expectedRemaining); - - /// <summary> - /// Changes the capacity and limit of this buffer sot his buffer gets the specified - /// expectedRemaining room from the specified position. - /// </summary> - /// <param name="pos">The pos you want the room to be available from.</param> - /// <param name="expectedRemaining">The expected room you want available.</param> - public abstract void Expand(int pos, int expectedRemaining); - - /// <summary> - /// Returns true if and only if this buffer is returned back to the buffer pool when released. - /// </summary> - /// <value><c>true</c> if pooled; otherwise, <c>false</c>.</value> - public abstract bool Pooled + /** + * Wraps the specified byte array into MINA heap buffer. + */ + public static ByteBuffer wrap( byte[] byteArray ) { - get; - set; + return wrap( FixedByteBuffer.wrap( byteArray ) ); } - - public abstract int Position + + /** + * Wraps the specified byte array into MINA heap buffer. + * Please note that MINA buffers are going to be pooled, and + * therefore there can be waste of memory if you wrap + * your byte array specifying <tt>offset</tt> and <tt>length</tt>. + */ + public static ByteBuffer wrap( byte[] byteArray, int offset, int length ) { - get; - set; + return wrap( FixedByteBuffer.wrap( byteArray, offset, length ) ); } - public abstract int Limit + protected ByteBuffer() { - get; - set; } - //public abstract void Mark(); + /** + * Increases the internal reference count of this buffer to defer + * automatic release. You have to invoke {@link #release()} as many + * as you invoked this method to release this buffer. + * + * @throws IllegalStateException if you attempt to acquire already + * released buffer. + */ + public abstract void acquire(); - //public abstract void Reset(); + /** + * Releases the specified buffer to buffer pool. + * + * @throws IllegalStateException if you attempt to release already + * released buffer. + */ + public abstract void release(); - public abstract void Clear(); + /** + * Returns the underlying NIO buffer instance. + */ + public abstract FixedByteBuffer buf(); - /// <summary> - /// Clears this buffer and fills its content with NULL. The position is set to zero, the limit is set to - /// capacity and the mark is discarded. - /// </summary> - public void Sweep() - { - Clear(); - FillAndReset(Remaining); - } + /** + * @see FixedByteBuffer#isDirect() + */ + public abstract bool isDirect(); + + /** + * @see FixedByteBuffer#isReadOnly() + */ + public abstract bool isReadOnly(); + + /** + * @see FixedByteBuffer#capacity() + */ + public abstract int capacity(); + + /** + * Changes the capacity of this buffer. + */ + public abstract ByteBuffer capacity( int newCapacity ); - public void Sweep(byte value) + /** + * Returns <tt>true</tt> if and only if <tt>autoExpand</tt> is turned on. + */ + public abstract bool isAutoExpand(); + + /** + * Turns on or off <tt>autoExpand</tt>. + */ + public abstract ByteBuffer setAutoExpand( bool autoExpand ); + + /** + * Changes the capacity and limit of this buffer so this buffer get + * the specified <tt>expectedRemaining</tt> room from the current position. + * This method works even if you didn't set <tt>autoExpand</tt> to + * <tt>true</tt>. + */ + public ByteBuffer expand( int expectedRemaining ) { - Clear(); - FillAndReset(value, Remaining); + return expand( position(), expectedRemaining ); } + + /** + * Changes the capacity and limit of this buffer so this buffer get + * the specified <tt>expectedRemaining</tt> room from the specified + * <tt>pos</tt>. + * This method works even if you didn't set <tt>autoExpand</tt> to + * <tt>true</tt>. + */ + public abstract ByteBuffer expand( int pos, int expectedRemaining ); + + /** + * Returns <tt>true</tt> if and only if this buffer is returned back + * to the buffer pool when released. + * <p> + * The default value of this property is <tt>true</tt> if and only if you + * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, bool)}, + * or <tt>false</tt> otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)}, + * and {@link #wrap(FixedByteBuffer)}) + */ + public abstract bool isPooled(); + + /** + * Sets whether this buffer is returned back to the buffer pool when released. + * <p> + * The default value of this property is <tt>true</tt> if and only if you + * allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, bool)}, + * or <tt>false</tt> otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)}, + * and {@link #wrap(FixedByteBuffer)}) + */ + public abstract void setPooled( bool pooled ); + + /** + * @see java.nio.Buffer#position() + */ + public abstract int position(); + + /** + * @see java.nio.Buffer#position(int) + */ + public abstract ByteBuffer position( int newPosition ); + + /** + * @see java.nio.Buffer#limit() + */ + public abstract int limit(); + + /** + * @see java.nio.Buffer#limit(int) + */ + public abstract ByteBuffer limit( int newLimit ); + + /** + * @see java.nio.Buffer#mark() + */ + public abstract ByteBuffer mark(); + + /** + * Returns the position of the current mark. This method returns <tt>-1</tt> if no + * mark is set. + */ + public abstract int markValue(); + + /** + * @see java.nio.Buffer#reset() + */ + public abstract ByteBuffer reset(); + + /** + * @see java.nio.Buffer#clear() + */ + public abstract ByteBuffer clear(); + + /** + * Clears this buffer and fills its content with <tt>NUL</tt>. + * The position is set to zero, the limit is set to the capacity, + * and the mark is discarded. + */ +// public ByteBuffer sweep() +// { +// clear(); +// return fillAndReset( remaining() ); +// } - public abstract void Flip(); + /** + * Clears this buffer and fills its content with <tt>value</tt>. + * The position is set to zero, the limit is set to the capacity, + * and the mark is discarded. + */ +// public ByteBuffer sweep( byte value ) +// { +// clear(); +// return fillAndReset( value, remaining() ); +// } - public abstract void Rewind(); + /** + * @see java.nio.Buffer#flip() + */ + public abstract ByteBuffer flip(); - public abstract int Remaining + /** + * @see java.nio.Buffer#rewind() + */ + public abstract ByteBuffer rewind(); + + /** + * @see java.nio.Buffer#remaining() + */ + public int remaining() { - get; + return limit() - position(); } - - public bool HasRemaining() + + /** + * @see java.nio.Buffer#hasRemaining() + */ + public bool hasRemaining() { - return Remaining > 0; + return remaining() > 0; } - public abstract byte Get(); + /** + * @see FixedByteBuffer#duplicate() + */ + public abstract ByteBuffer duplicate(); - public abstract byte Get(int index); - - public abstract void Get(byte[] destination); + /** + * @see FixedByteBuffer#slice() + */ + public abstract ByteBuffer slice(); - public abstract ushort GetUnsignedShort(); + /** + * @see FixedByteBuffer#asReadOnlyBuffer() + */ + public abstract ByteBuffer asReadOnlyBuffer(); - public abstract uint GetUnsignedInt(); + /** + * @see FixedByteBuffer#array() + */ + public abstract byte[] array(); - public abstract ulong GetUnsignedLong(); + /** + * @see FixedByteBuffer#arrayOffset() + */ + public abstract int arrayOffset(); - public abstract string GetString(uint length, Encoding encoder); + /** + * @see FixedByteBuffer#get() + */ + public abstract byte get(); - public abstract void Put(byte data); + /** + * Reads one unsigned byte as a short integer. + */ + public short getUnsigned() + { + return (short)( get() & 0xff ); + } - public abstract void Put(byte[] data); - public abstract void Put(byte[] data, int offset, int size); + /** + * @see FixedByteBuffer#put(byte) + */ + public abstract ByteBuffer put( byte b ); - public abstract void Put(ushort data); + /** + * @see FixedByteBuffer#get(int) + */ + public abstract byte get( int index ); - public abstract void Put(uint data); + /** + * Reads one byte as an unsigned short integer. + */ + public short getUnsigned( int index ) + { + return (short)( get( index ) & 0xff ); + } - public abstract void Put(ulong data); + /** + * @see FixedByteBuffer#put(int, byte) + */ + public abstract ByteBuffer put( int index, byte b ); - public abstract void Put(ByteBuffer buf); - - public abstract void Compact(); + /** + * @see FixedByteBuffer#get(byte[], int, int) + */ + public abstract ByteBuffer get( byte[] dst, int offset, int length ); - public abstract byte[] ToByteArray(); - - public override string ToString() + /** + * @see FixedByteBuffer#get(byte[]) + */ + public abstract ByteBuffer get(byte[] dst); +// { +// return get( dst, 0, dst.Length ); +// } + + /** + * Writes the content of the specified <tt>src</tt> into this buffer. + */ + public abstract ByteBuffer put( FixedByteBuffer src ); + + /** + * Writes the content of the specified <tt>src</tt> into this buffer. + */ + public ByteBuffer put( ByteBuffer src ) + { + return put( src.buf() ); + } + + /** + * @see FixedByteBuffer#put(byte[], int, int) + */ + public abstract ByteBuffer put( byte[] src, int offset, int length ); + + /** + * @see FixedByteBuffer#put(byte[]) + */ + public abstract ByteBuffer put(byte[] src); +// { +// return put(src); +//// return put( src, 0, src.Length ); +// } + + /** + * @see FixedByteBuffer#compact() + */ + public abstract ByteBuffer compact(); + + public String toString() { StringBuilder buf = new StringBuilder(); - buf.Append("HeapBuffer"); - buf.AppendFormat("[pos={0} lim={1} cap={2} : {3}]", Position, Limit, Capacity, HexDump); + if( isDirect() ) + { + buf.Append( "DirectBuffer" ); + } + else + { + buf.Append( "HeapBuffer" ); + } + buf.Append( "[pos=" ); + buf.Append( position() ); + buf.Append( " lim=" ); + buf.Append( limit() ); + buf.Append( " cap=" ); + buf.Append( capacity() ); + buf.Append( ": " ); + buf.Append( getHexDump() ); + buf.Append( ']' ); return buf.ToString(); } - public override int GetHashCode() + public int hashCode() { int h = 1; - int p = Position; - for (int i = Limit - 1; i >= p; i--) + int p = position(); + for( int i = limit() - 1; i >= p; i -- ) { - h = 31 * h + Get(i); + h = 31 * h + get( i ); } - return h; } - public override bool Equals(object obj) + public bool equals( Object o ) { - if (!(obj is ByteBuffer)) + if( !( o is ByteBuffer ) ) { return false; } - ByteBuffer that = (ByteBuffer) obj; - - if (Remaining != that.Remaining) + + ByteBuffer that = (ByteBuffer)o; + if( this.remaining() != that.remaining() ) { return false; } - int p = Position; - for (int i = Limit - 1, j = that.Limit - 1; i >= p; i--, j--) + + int p = this.position(); + for( int i = this.limit() - 1, j = that.limit() - 1; i >= p; i --, j -- ) { - byte v1 = this.Get(i); - byte v2 = that.Get(j); - if (v1 != v2) + byte v1 = this.get( i ); + byte v2 = that.get( j ); + if( v1 != v2 ) { return false; } } return true; } - - public string HexDump - { - get - { - return ByteBufferHexDumper.GetHexDump(this); - } - } - /// <summary> - /// Fills the buffer with the specified specified value. This method moves the buffer position forward. - /// </summary> - /// <param name="value">The value.</param> - /// <param name="size">The size.</param> - public void Fill(byte value, int size) + public int CompareTo( Object o ) { - AutoExpand(size); - int q = size >> 3; - int r = size & 7; - - if (q > 0) + ByteBuffer that = (ByteBuffer)o; + int n = this.position() + Math.Min( this.remaining(), that.remaining() ); + for( int i = this.position(), j = that.position(); i < n; i ++, j ++ ) { - int intValue = value | (value << 8) | (value << 16) | (value << 24); - long longValue = intValue; - longValue <<= 32; - longValue |= (ushort)intValue; - - for (int i = q; i > 0; i--) + byte v1 = this.get( i ); + byte v2 = that.get( j ); + if( v1 == v2 ) { - Put((ulong)longValue); + continue; + } + if( v1 < v2 ) + { + return -1; } - } - q = r >> 2; - r = r & 3; - - if (q > 0) - { - int intValue = value | (value << 8) | (value << 16) | (value << 24); - Put((uint)intValue); + return +1; } + return this.remaining() - that.remaining(); + } - q = r >> 1; - r = r & 1; - - if (q > 0) - { - short shortValue = (short) (value | (value << 8)); - Put((ushort) shortValue); - } - if (r > 0) - { - Put(value); - } + /** + * @see FixedByteBuffer#order() + */ + public abstract ByteOrder order(); + + /** + * @see FixedByteBuffer#order(ByteOrder) + */ + public abstract ByteBuffer order( ByteOrder bo ); + + /** + * @see FixedByteBuffer#getChar() + */ + public abstract char getChar(); + + /** + * @see FixedByteBuffer#putChar(char) + */ + public abstract ByteBuffer putChar( char value ); + + /** + * @see FixedByteBuffer#getChar(int) + */ + public abstract char getChar( int index ); + + /** + * @see FixedByteBuffer#putChar(int, char) + */ + public abstract ByteBuffer putChar( int index, char value ); + + /** + * @see FixedByteBuffer#asCharBuffer() + */ +// public abstract CharBuffer asCharBuffer(); + + /** + * @see FixedByteBuffer#getShort() + */ + public abstract short getShort(); + + /** + * Reads two bytes unsigned integer. + */ + public int getUnsignedShort() + { + return getShort() & 0xffff; } - - public void FillAndReset(byte value, int size) + + /** + * @see FixedByteBuffer#putShort(short) + */ + public abstract ByteBuffer putShort( short value ); + + /** + * @see FixedByteBuffer#getShort() + */ + public abstract short getShort( int index ); + + /** + * Reads two bytes unsigned integer. + */ + public int getUnsignedShort( int index ) { - AutoExpand(size); - int pos = Position; - try - { - Fill(value, size); - } - finally - { - Position = pos; - } + return getShort( index ) & 0xffff; } - - public void Fill(int size) + + /** + * @see FixedByteBuffer#putShort(int, short) + */ + public abstract ByteBuffer putShort( int index, short value ); + + /** + * @see FixedByteBuffer#asShortBuffer() + */ +// public abstract ShortBuffer asShortBuffer(); + + /** + * @see FixedByteBuffer#getInt() + */ + public abstract int getInt(); + + /** + * Reads four bytes unsigned integer. + */ + public uint getUnsignedInt() { - AutoExpand(size); - int q = size >> 3; - int r = size & 7; +// return getInt() & 0xffffffffL; - for (int i = q; i > 0; i--) - { - Put(0L); - } + //CheckSpaceForReading(4); + byte b1 = get(); + byte b2 = get(); + byte b3 = get(); + byte b4 = get(); + return (uint)((b1 << 24) + (b2 << 16) + (b3 << 8) + b4); + } + + /** + * @see FixedByteBuffer#putInt(int) + */ + public abstract ByteBuffer putInt( int value ); + + /** + * @see FixedByteBuffer#getInt(int) + */ + public abstract int getInt( int index ); + + /** + * Reads four bytes unsigned integer. + */ + public long getUnsignedInt( int index ) + { + return getInt( index ) & 0xffffffffL; + } + + /** + * @see FixedByteBuffer#putInt(int, int) + */ + public abstract ByteBuffer putInt( int index, int value ); + + /** + * @see FixedByteBuffer#asIntBuffer() + */ +// public abstract IntBuffer asIntBuffer(); + + /** + * @see FixedByteBuffer#getLong() + */ + public abstract long getLong(); + + /** + * @see FixedByteBuffer#putLong(int, long) + */ + public abstract ByteBuffer putLong( long value ); + + /** + * @see FixedByteBuffer#getLong(int) + */ + public abstract long getLong( int index ); + + /** + * @see FixedByteBuffer#putLong(int, long) + */ + public abstract ByteBuffer putLong( int index, long value ); + + /** + * @see FixedByteBuffer#asLongBuffer() + */ +// public abstract LongBuffer asLongBuffer(); + + /** + * @see FixedByteBuffer#getFloat() + */ + public abstract float getFloat(); + + /** + * @see FixedByteBuffer#putFloat(float) + */ + public abstract ByteBuffer putFloat( float value ); + + /** + * @see FixedByteBuffer#getFloat(int) + */ + public abstract float getFloat( int index ); + + /** + * @see FixedByteBuffer#putFloat(int, float) + */ + public abstract ByteBuffer putFloat( int index, float value ); + + /** + * @see FixedByteBuffer#asFloatBuffer() + */ +// public abstract FloatBuffer asFloatBuffer(); + + /** + * @see FixedByteBuffer#getDouble() + */ + public abstract double getDouble(); + + /** + * @see FixedByteBuffer#putDouble(double) + */ + public abstract ByteBuffer putDouble( double value ); + + /** + * @see FixedByteBuffer#getDouble(int) + */ + public abstract double getDouble( int index ); + + /** + * @see FixedByteBuffer#putDouble(int, double) + */ + public abstract ByteBuffer putDouble( int index, double value ); - q = r >> 2; - r = r & 3; + /** + * @see FixedByteBuffer#asDoubleBuffer() + */ +// public abstract DoubleBuffer asDoubleBuffer(); - if (q > 0) + /** + * Returns an {@link InputStream} that reads the data from this buffer. + * {@link InputStream#read()} returns <tt>-1</tt> if the buffer position + * reaches to the limit. + */ +// public InputStream asInputStream() +// { +// // XXX: Use System.IO.Stream here? +// return new InputStream() +// { +// public int available() +// { +// return ByteBuffer.this.remaining(); +// } +// +// public synchronized void mark( int readlimit ) +// { +// ByteBuffer.this.mark(); +// } +// +// public bool markSupported() +// { +// return true; +// } +// +// public int read() +// { +// if( ByteBuffer.this.hasRemaining() ) +// { +// return ByteBuffer.this.get() & 0xff; +// } +// else +// { +// return -1; +// } +// } +// +// public int read( byte[] b, int off, int len ) +// { +// int remaining = ByteBuffer.this.remaining(); +// if( remaining > 0 ) +// { +// int readBytes = Math.min( remaining, len ); +// ByteBuffer.this.get( b, off, readBytes ); +// return readBytes; +// } +// else +// { +// return -1; +// } +// } +// +// public synchronized void reset() +// { +// ByteBuffer.this.reset(); +// } +// +// public long skip( long n ) +// { +// int bytes; +// if( n > Integer.MAX_VALUE ) +// { +// bytes = ByteBuffer.this.remaining(); +// } +// else +// { +// bytes = Math.min( ByteBuffer.this.remaining(), (int)n ); +// } +// ByteBuffer.this.skip( bytes ); +// return bytes; +// } +// }; +// } + + /** + * Returns an {@link OutputStream} that Appends the data into this buffer. + * Please note that the {@link OutputStream#write(int)} will throw a + * {@link BufferOverflowException} instead of an {@link IOException} + * in case of buffer overflow. Please set <tt>autoExpand</tt> property by + * calling {@link #setAutoExpand(bool)} to prevent the unexpected runtime + * exception. + */ +// public OutputStream asOutputStream() +// { +// return new OutputStream() +// { +// public void write( byte[] b, int off, int len ) +// { +// ByteBuffer.this.put( b, off, len ); +// } +// +// public void write( int b ) +// { +// ByteBuffer.this.put( (byte)b ); +// } +// }; +// } + + /** + * Returns hexdump of this buffer. + */ + public String getHexDump() + { + return ByteBufferHexDumper.GetHexDump(this); + } + + //////////////////////////////// + // String getters and putters // + //////////////////////////////// + + /** + * Reads a <code>NUL</code>-terminated string from this buffer using the + * specified <code>decoder</code> and returns it. This method reads + * until the limit of this buffer if no <tt>NUL</tt> is found. + */ +// public String getString( Encoding decoder ) +// { +// if( !hasRemaining() ) +// { +// return ""; +// } +// +// decoder. +// bool utf16 = decoder.charset().name().startsWith( "UTF-16" ); +// +// int oldPos = position(); +// int oldLimit = limit(); +// int end; +// +// if( !utf16 ) +// { +// while( hasRemaining() ) +// { +// if( get() == 0 ) +// { +// break; +// } +// } +// +// end = position(); +// if( end == oldLimit && get( end - 1 ) != 0 ) +// { +// limit( end ); +// } +// else +// { +// limit( end - 1 ); +// } +// } +// else +// { +// while( remaining() >= 2 ) +// { +// if( ( get() == 0 ) && ( get() == 0 ) ) +// { +// break; +// } +// } +// +// end = position(); +// if( end == oldLimit || end == oldLimit - 1 ) +// { +// limit( end ); +// } +// else +// { +// limit( end - 2 ); +// } +// } +// +// position( oldPos ); +// if( !hasRemaining() ) +// { +// limit( oldLimit ); +// position( end ); +// return ""; +// } +// decoder.reset(); +// +// int expectedLength = (int)( remaining() * decoder.averageCharsPerByte() ) + 1; +// CharBuffer out = CharBuffer.allocate( expectedLength ); +// for( ; ; ) +// { +// CoderResult cr; +// if( hasRemaining() ) +// { +// cr = decoder.decode( buf(), out, true ); +// } +// else +// { +// cr = decoder.flush( out ); +// } +// +// if( cr.isUnderflow() ) +// { +// break; +// } +// +// if( cr.isOverflow() ) +// { +// CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength ); +// out.flip(); +// o.put( out ); +// out = o; +// continue; +// } +// +// cr.throwException(); +// } +// +// limit( oldLimit ); +// position( end ); +// return out.flip().toString(); +// } + + /** + * Reads a <code>NUL</code>-terminated string from this buffer using the + * specified <code>decoder</code> and returns it. + * + * @param fieldSize the maximum number of bytes to read + */ +// public String getString( int fieldSize, CharsetDecoder decoder ) throws CharacterCodingException +// { +// checkFieldSize( fieldSize ); +// +// if( fieldSize == 0 ) +// { +// return ""; +// } +// +// if( !hasRemaining() ) +// { +// return ""; +// } +// +// bool utf16 = decoder.charset().name().startsWith( "UTF-16" ); +// +// if( utf16 && ( ( fieldSize & 1 ) != 0 ) ) +// { +// throw new IllegalArgumentException( "fieldSize is not even." ); +// } +// +// int oldPos = position(); +// int oldLimit = limit(); +// int end = position() + fieldSize; +// +// if( oldLimit < end ) +// { +// throw new BufferUnderflowException(); +// } +// +// int i; +// +// if( !utf16 ) +// { +// for( i = 0; i < fieldSize; i ++ ) +// { +// if( get() == 0 ) +// { +// break; +// } +// } +// +// if( i == fieldSize ) +// { +// limit( end ); +// } +// else +// { +// limit( position() - 1 ); +// } +// } +// else +// { +// for( i = 0; i < fieldSize; i += 2 ) +// { +// if( ( get() == 0 ) && ( get() == 0 ) ) +// { +// break; +// } +// } +// +// if( i == fieldSize ) +// { +// limit( end ); +// } +// else +// { +// limit( position() - 2 ); +// } +// } +// +// position( oldPos ); +// if( !hasRemaining() ) +// { +// limit( oldLimit ); +// position( end ); +// return ""; +// } +// decoder.reset(); +// +// int expectedLength = (int)( remaining() * decoder.averageCharsPerByte() ) + 1; +// CharBuffer out = CharBuffer.allocate( expectedLength ); +// for( ; ; ) +// { +// CoderResult cr; +// if( hasRemaining() ) +// { +// cr = decoder.decode( buf(), out, true ); +// } +// else +// { +// cr = decoder.flush( out ); +// } +// +// if( cr.isUnderflow() ) +// { +// break; +// } +// +// if( cr.isOverflow() ) +// { +// CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength ); +// out.flip(); +// o.put( out ); +// out = o; +// continue; +// } +// +// cr.throwException(); +// } +// +// limit( oldLimit ); +// position( end ); +// return out.flip().toString(); +// } + + /** + * Writes the content of <code>in</code> into this buffer using the + * specified <code>encoder</code>. This method doesn't terminate + * string with <tt>NUL</tt>. You have to do it by yourself. + * + * @throws BufferOverflowException if the specified string doesn't fit + */ +// public ByteBuffer putString( +// CharSequence val, CharsetEncoder encoder ) throws CharacterCodingException +// { +// if( val.length() == 0 ) +// { +// return this; +// } +// +// CharBuffer in = CharBuffer.wrap( val ); +// encoder.reset(); +// +// int expandedState = 0; +// +// for( ; ; ) +// { +// CoderResult cr; +// if( in.hasRemaining() ) +// { +// cr = encoder.encode( in, buf(), true ); +// } +// else +// { +// cr = encoder.flush( buf() ); +// } +// +// if( cr.isUnderflow() ) +// { +// break; +// } +// if( cr.isOverflow() ) +// { +// if( isAutoExpand() ) +// { +// switch( expandedState ) +// { +// case 0: +// autoExpand( (int)Math.ceil( in.remaining() * encoder.averageBytesPerChar() ) ); +// expandedState ++; +// break; +// case 1: +// autoExpand( (int)Math.ceil( in.remaining() * encoder.maxBytesPerChar() ) ); +// expandedState ++; +// break; +// default: +// throw new RuntimeException( "Expanded by " + +// (int)Math.ceil( in.remaining() * encoder.maxBytesPerChar() ) + +// " but that wasn't enough for '" + val + "'" ); +// } +// continue; +// } +// } +// else +// { +// expandedState = 0; +// } +// cr.throwException(); +// } +// return this; +// } + + /** + * Writes the content of <code>in</code> into this buffer as a + * <code>NUL</code>-terminated string using the specified + * <code>encoder</code>. + * <p> + * If the charset name of the encoder is UTF-16, you cannot specify + * odd <code>fieldSize</code>, and this method will Append two + * <code>NUL</code>s as a terminator. + * <p> + * Please note that this method doesn't terminate with <code>NUL</code> + * if the input string is longer than <tt>fieldSize</tt>. + * + * @param fieldSize the maximum number of bytes to write + */ +// public ByteBuffer putString( +// CharSequence val, int fieldSize, CharsetEncoder encoder ) throws CharacterCodingException +// { +// checkFieldSize( fieldSize ); +// +// if( fieldSize == 0 ) +// return this; +// +// autoExpand( fieldSize ); +// +// bool utf16 = encoder.charset().name().startsWith( "UTF-16" ); +// +// if( utf16 && ( ( fieldSize & 1 ) != 0 ) ) +// { +// throw new IllegalArgumentException( "fieldSize is not even." ); +// } +// +// int oldLimit = limit(); +// int end = position() + fieldSize; +// +// if( oldLimit < end ) +// { +// throw new BufferOverflowException(); +// } +// +// if( val.length() == 0 ) +// { +// if( !utf16 ) +// { +// put( (byte)0x00 ); +// } +// else +// { +// put( (byte)0x00 ); +// put( (byte)0x00 ); +// } +// position( end ); +// return this; +// } +// +// CharBuffer in = CharBuffer.wrap( val ); +// limit( end ); +// encoder.reset(); +// +// for( ; ; ) +// { +// CoderResult cr; +// if( in.hasRemaining() ) +// { +// cr = encoder.encode( in, buf(), true ); +// } +// else +// { +// cr = encoder.flush( buf() ); +// } +// +// if( cr.isUnderflow() || cr.isOverflow() ) +// { +// break; +// } +// cr.throwException(); +// } +// +// limit( oldLimit ); +// +// if( position() < end ) +// { +// if( !utf16 ) +// { +// put( (byte)0x00 ); +// } +// else +// { +// put( (byte)0x00 ); +// put( (byte)0x00 ); +// } +// } +// +// position( end ); +// return this; +// } + + /** + * Reads a string which has a 16-bit length field before the actual + * encoded string, using the specified <code>decoder</code> and returns it. + * This method is a shortcut for <tt>getPrefixedString(2, decoder)</tt>. + */ +// public String getPrefixedString( CharsetDecoder decoder ) throws CharacterCodingException +// { +// return getPrefixedString( 2, decoder ); +// } + + /** + * Reads a string which has a length field before the actual + * encoded string, using the specified <code>decoder</code> and returns it. + * + * @param prefixLength the length of the length field (1, 2, or 4) + */ +// public String getPrefixedString( int prefixLength, CharsetDecoder decoder ) throws CharacterCodingException +// { +// if( !prefixedDataAvailable( prefixLength ) ) +// { +// throw new BufferUnderflowException(); +// } +// +// int fieldSize = 0; +// +// switch( prefixLength ) +// { +// case 1: +// fieldSize = getUnsigned(); +// break; +// case 2: +// fieldSize = getUnsignedShort(); +// break; +// case 4: +// fieldSize = getInt(); +// break; +// } +// +// if( fieldSize == 0 ) +// { +// return ""; +// } +// +// bool utf16 = decoder.charset().name().startsWith( "UTF-16" ); +// +// if( utf16 && ( ( fieldSize & 1 ) != 0 ) ) +// { +// throw new BufferDataException( "fieldSize is not even for a UTF-16 string." ); +// } +// +// int oldLimit = limit(); +// int end = position() + fieldSize; +// +// if( oldLimit < end ) +// { +// throw new BufferUnderflowException(); +// } +// +// limit( end ); +// decoder.reset(); +// +// int expectedLength = (int)( remaining() * decoder.averageCharsPerByte() ) + 1; +// CharBuffer out = CharBuffer.allocate( expectedLength ); +// for( ; ; ) +// { +// CoderResult cr; +// if( hasRemaining() ) +// { +// cr = decoder.decode( buf(), out, true ); +// } +// else +// { +// cr = decoder.flush( out ); +// } +// +// if( cr.isUnderflow() ) +// { +// break; +// } +// +// if( cr.isOverflow() ) +// { +// CharBuffer o = CharBuffer.allocate( out.capacity() + expectedLength ); +// out.flip(); +// o.put( out ); +// out = o; +// continue; +// } +// +// cr.throwException(); +// } +// +// limit( oldLimit ); +// position( end ); +// return out.flip().toString(); +// } + + /** + * Writes the content of <code>in</code> into this buffer as a + * string which has a 16-bit length field before the actual + * encoded string, using the specified <code>encoder</code>. + * This method is a shortcut for <tt>putPrefixedString(in, 2, 0, encoder)</tt>. + * + * @throws BufferOverflowException if the specified string doesn't fit + */ +// public ByteBuffer putPrefixedString( CharSequence in, CharsetEncoder encoder ) throws CharacterCodingException +// { +// return putPrefixedString( in, 2, 0, encoder ); +// } + + /** + * Writes the content of <code>in</code> into this buffer as a + * string which has a 16-bit length field before the actual + * encoded string, using the specified <code>encoder</code>. + * This method is a shortcut for <tt>putPrefixedString(in, prefixLength, 0, encoder)</tt>. + * + * @param prefixLength the length of the length field (1, 2, or 4) + * + * @throws BufferOverflowException if the specified string doesn't fit + */ +// public ByteBuffer putPrefixedString( CharSequence in, int prefixLength, CharsetEncoder encoder ) +// throws CharacterCodingException +// { +// return putPrefixedString( in, prefixLength, 0, encoder ); +// } + + /** + * Writes the content of <code>in</code> into this buffer as a + * string which has a 16-bit length field before the actual + * encoded string, using the specified <code>encoder</code>. + * This method is a shortcut for <tt>putPrefixedString(in, prefixLength, padding, ( byte ) 0, encoder)</tt>. + * + * @param prefixLength the length of the length field (1, 2, or 4) + * @param padding the number of padded <tt>NUL</tt>s (1 (or 0), 2, or 4) + * + * @throws BufferOverflowException if the specified string doesn't fit + */ +// public ByteBuffer putPrefixedString( CharSequence in, int prefixLength, int padding, CharsetEncoder encoder ) +// throws CharacterCodingException +// { +// return putPrefixedString( in, prefixLength, padding, (byte)0, encoder ); +// } + + /** + * Writes the content of <code>in</code> into this buffer as a + * string which has a 16-bit length field before the actual + * encoded string, using the specified <code>encoder</code>. + * + * @param prefixLength the length of the length field (1, 2, or 4) + * @param padding the number of padded bytes (1 (or 0), 2, or 4) + * @param padValue the value of padded bytes + * + * @throws BufferOverflowException if the specified string doesn't fit + */ +// public ByteBuffer putPrefixedString( CharSequence val, +// int prefixLength, +// int padding, +// byte padValue, +// CharsetEncoder encoder ) throws CharacterCodingException +// { +// int maxLength; +// switch( prefixLength ) +// { +// case 1: +// maxLength = 255; +// break; +// case 2: +// maxLength = 65535; +// break; +// case 4: +// maxLength = Integer.MAX_VALUE; +// break; +// default: +// throw new IllegalArgumentException( "prefixLength: " + prefixLength ); +// } +// +// if( val.length() > maxLength ) +// { +// throw new IllegalArgumentException( "The specified string is too long." ); +// } +// if( val.length() == 0 ) +// { +// switch( prefixLength ) +// { +// case 1: +// put( (byte)0 ); +// break; +// case 2: +// putShort( (short)0 ); +// break; +// case 4: +// putInt( 0 ); +// break; +// } +// return this; +// } +// +// int padMask; +// switch( padding ) +// { +// case 0: +// case 1: +// padMask = 0; +// break; +// case 2: +// padMask = 1; +// break; +// case 4: +// padMask = 3; +// break; +// default: +// throw new IllegalArgumentException( "padding: " + padding ); +// } +// +// CharBuffer in = CharBuffer.wrap( val ); +// int expectedLength = (int)( in.remaining() * encoder.averageBytesPerChar() ) + 1; +// +// skip( prefixLength ); // make a room for the length field +// int oldPos = position(); +// encoder.reset(); +// +// for( ; ; ) +// { +// CoderResult cr; +// if( in.hasRemaining() ) +// { +// cr = encoder.encode( in, buf(), true ); +// } +// else +// { +// cr = encoder.flush( buf() ); +// } +// +// if( position() - oldPos > maxLength ) +// { +// throw new IllegalArgumentException( "The specified string is too long." ); +// } +// +// if( cr.isUnderflow() ) +// { +// break; +// } +// if( cr.isOverflow() && isAutoExpand() ) +// { +// autoExpand( expectedLength ); +// continue; +// } +// cr.throwException(); +// } +// +// // Write the length field +// fill( padValue, padding - ( ( position() - oldPos ) & padMask ) ); +// int length = position() - oldPos; +// switch( prefixLength ) +// { +// case 1: +// put( oldPos - 1, (byte)length ); +// break; +// case 2: +// putShort( oldPos - 2, (short)length ); +// break; +// case 4: +// putInt( oldPos - 4, length ); +// break; +// } +// return this; +// } + + /** + * Reads a Java object from the buffer using the context {@link ClassLoader} + * of the current thread. + */ +// public Object getObject() throws ClassNotFoundException +// { +// return getObject( Thread.currentThread().getContextClassLoader() ); +// } + + /** + * Reads a Java object from the buffer using the specified <tt>classLoader</tt>. + */ +// public Object getObject( final ClassLoader classLoader ) throws ClassNotFoundException +// { +// if( !prefixedDataAvailable( 4 ) ) +// { +// throw new BufferUnderflowException(); +// } +// +// int length = getInt(); +// if( length <= 4 ) +// { +// throw new BufferDataException( "Object length should be greater than 4: " + length ); +// } +// +// int oldLimit = limit(); +// limit( position() + length ); +// try +// { +// ObjectInputStream in = new ObjectInputStream( asInputStream() ) +// { +// protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException +// { +// String className = readUTF(); +// Class clazz = Class.forName( className, true, classLoader ); +// return ObjectStreamClass.lookup( clazz ); +// } +// }; +// return in.readObject(); +// } +// catch( IOException e ) +// { +// throw new BufferDataException( e ); +// } +// finally +// { +// limit( oldLimit ); +// } +// } + + /** + * Writes the specified Java object to the buffer. + */ +// public ByteBuffer putObject( Object o ) +// { +// int oldPos = position(); +// skip( 4 ); // Make a room for the length field. +// try +// { +// ObjectOutputStream out = new ObjectOutputStream( asOutputStream() ) +// { +// protected void writeClassDescriptor( ObjectStreamClass desc ) throws IOException +// { +// writeUTF( desc.getName() ); +// } +// }; +// out.writeObject( o ); +// out.flush(); +// } +// catch( IOException e ) +// { +// throw new BufferDataException( e ); +// } +// +// // Fill the length field +// int newPos = position(); +// position( oldPos ); +// putInt( newPos - oldPos - 4 ); +// position( newPos ); +// return this; +// } + + /** + * Returns <tt>true</tt> if this buffer contains a data which has a data + * length as a prefix and the buffer has remaining data as enough as + * specified in the data length field. This method is identical with + * <tt>prefixedDataAvailable( prefixLength, Integer.MAX_VALUE )</tt>. + * Please not that using this method can allow DoS (Denial of Service) + * attack in case the remote peer sends too big data length value. + * It is recommended to use {@link #prefixedDataAvailable(int, int)} + * instead. + * + * @param prefixLength the length of the prefix field (1, 2, or 4) + * + * @throws IllegalArgumentException if prefixLength is wrong + * @throws BufferDataException if data length is negative + */ + public bool prefixedDataAvailable( int prefixLength ) + { + return prefixedDataAvailable( prefixLength, int.MaxValue); + } + + /** + * Returns <tt>true</tt> if this buffer contains a data which has a data + * length as a prefix and the buffer has remaining data as enough as + * specified in the data length field. + * + * @param prefixLength the length of the prefix field (1, 2, or 4) + * @param maxDataLength the allowed maximum of the read data length + * + * @throws IllegalArgumentException if prefixLength is wrong + * @throws BufferDataException if data length is negative or greater then <tt>maxDataLength</tt> + */ + public bool prefixedDataAvailable( int prefixLength, int maxDataLength ) + { + if( remaining() < prefixLength ) { - Put(0); + return false; } - q = r >> 1; - r = r & 1; - - if(q > 0) + int dataLength; + switch( prefixLength ) { - Put((ushort) 0); + case 1: + dataLength = getUnsigned( position() ); + break; + case 2: + dataLength = getUnsignedShort( position() ); + break; + case 4: + dataLength = getInt( position() ); + break; + default: + throw new ArgumentException("prefixLength: " + prefixLength); } - if (r > 0) + if( dataLength < 0 || dataLength > maxDataLength ) { - Put((byte) 0); + throw new BufferDataException( "dataLength: " + dataLength ); } + + return remaining() - prefixLength >= dataLength; } - - public void FillAndReset(int size) + + ////////////////////////// + // Skip or fill methods // + ////////////////////////// + + /** + * Forwards the position of this buffer as the specified <code>size</code> + * bytes. + */ + public ByteBuffer skip( int size ) { - AutoExpand(size); - int pos = Position; - try - { - Fill(size); - } - finally - { - Position = pos; - } + autoExpand( size ); + return position( position() + size ); } - - public void Skip(int size) + + /** + * Fills this buffer with the specified value. + * This method moves buffer position forward. + */ +// public ByteBuffer fill( byte value, int size ) +// { +// autoExpand( size ); +// int q = size >>> 3; +// int r = size & 7; +// +// if( q > 0 ) +// { +// int intValue = value | ( value << 8 ) | ( value << 16 ) +// | ( value << 24 ); +// long longValue = intValue; +// longValue <<= 32; +// longValue |= intValue; +// +// for( int i = q; i > 0; i -- ) +// { +// putLong( longValue ); +// } +// } +// +// q = r >>> 2; +// r = r & 3; +// +// if( q > 0 ) +// { +// int intValue = value | ( value << 8 ) | ( value << 16 ) +// | ( value << 24 ); +// putInt( intValue ); +// } +// +// q = r >> 1; +// r = r & 1; +// +// if( q > 0 ) +// { +// short shortValue = (short)( value | ( value << 8 ) ); +// putShort( shortValue ); +// } +// +// if( r > 0 ) +// { +// put( value ); +// } +// +// return this; +// } + + /** + * Fills this buffer with the specified value. + * This method does not change buffer position. + */ +// public ByteBuffer fillAndReset( byte value, int size ) +// { +// autoExpand( size ); +// int pos = position(); +// try +// { +// fill( value, size ); +// } +// finally +// { +// position( pos ); +// } +// return this; +// } + + /** + * Fills this buffer with <code>NUL (0x00)</code>. + * This method moves buffer position forward. + */ +// public ByteBuffer fill( int size ) +// { +// autoExpand( size ); +// int q = size >>> 3; +// int r = size & 7; +// +// for( int i = q; i > 0; i -- ) +// { +// putLong( 0L ); +// } +// +// q = r >>> 2; +// r = r & 3; +// +// if( q > 0 ) +// { +// putInt( 0 ); +// } +// +// q = r >> 1; +// r = r & 1; +// +// if( q > 0 ) +// { +// putShort( (short)0 ); +// } +// +// if( r > 0 ) +// { +// put( (byte)0 ); +// } +// +// return this; +// } + + /** + * Fills this buffer with <code>NUL (0x00)</code>. + * This method does not change buffer position. + */ +// public ByteBuffer fillAndReset( int size ) +// { +// autoExpand( size ); +// int pos = position(); +// try +// { +// fill( size ); +// } +// finally +// { +// position( pos ); +// } +// +// return this; +// } + + /** + * This method forwards the call to {@link #expand(int)} only when + * <tt>autoExpand</tt> property is <tt>true</tt>. + */ + protected ByteBuffer autoExpand( int expectedRemaining ) { - AutoExpand(size); - Position = Position + size; + if( isAutoExpand() ) + { + expand( expectedRemaining ); + } + return this; } - - protected void AutoExpand(int expectedRemaining) + + /** + * This method forwards the call to {@link #expand(int)} only when + * <tt>autoExpand</tt> property is <tt>true</tt>. + */ + protected ByteBuffer autoExpand( int pos, int expectedRemaining ) { - if (IsAutoExpand) + if( isAutoExpand() ) { - Expand(expectedRemaining); + expand( pos, expectedRemaining ); } + return this; } - - protected void AutoExpand(int pos, int expectedRemaining) + + private static void checkFieldSize( int fieldSize ) { - if (IsAutoExpand) + if( fieldSize < 0 ) { - Expand(pos, expectedRemaining); + throw new ArgumentOutOfRangeException("fieldSize"); } - } + } + + public abstract void put(ushort value); + public abstract ushort GetUnsignedShort(); + public abstract uint GetUnsignedInt(); + public abstract void put(uint max); + public abstract void put(ulong tag); + public abstract ulong GetUnsignedLong(); } } - diff --git a/dotnet/Qpid.Buffer/ByteBufferAllocator.cs b/dotnet/Qpid.Buffer/ByteBufferAllocator.cs new file mode 100644 index 0000000000..2dabd0ef50 --- /dev/null +++ b/dotnet/Qpid.Buffer/ByteBufferAllocator.cs @@ -0,0 +1,50 @@ +/* + * + * 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. + * + */ +using Qpid.Buffer; + +namespace Qpid.Buffer +{ + /** + * Allocates {@link ByteBuffer}s and manages them. Please implement this + * interface if you need more advanced memory management scheme. + */ + public interface ByteBufferAllocator + { + /** + * Returns the buffer which is capable of the specified size. + * + * @param capacity the capacity of the buffer + * @param direct <tt>true</tt> to get a direct buffer, + * <tt>false</tt> to get a heap buffer. + */ + ByteBuffer allocate(int capacity, bool direct); + + /** + * Wraps the specified NIO {@link FixedByteBuffer} into MINA buffer. + */ + ByteBuffer wrap(FixedByteBuffer nioBuffer); + + /** + * Dispose of this allocator. + */ + void dispose(); + } +}
\ No newline at end of file diff --git a/dotnet/Qpid.Buffer/ByteBufferHexDumper.cs b/dotnet/Qpid.Buffer/ByteBufferHexDumper.cs index a43331ff1a..459abc56ef 100644 --- a/dotnet/Qpid.Buffer/ByteBufferHexDumper.cs +++ b/dotnet/Qpid.Buffer/ByteBufferHexDumper.cs @@ -49,7 +49,7 @@ namespace Qpid.Buffer public static string GetHexDump(ByteBuffer input) { - int size = input.Limit - input.Position; + int size = input.limit() - input.position(); if (size == 0) { return "empty"; @@ -57,7 +57,7 @@ namespace Qpid.Buffer StringBuilder output = new StringBuilder(size * 3 - 1); - byte[] data = input.ToByteArray(); + byte[] data = input.array(); int byteValue = data[0] & 0xFF; output.Append((char) highDigits[byteValue]); output.Append((char) lowDigits[byteValue]); diff --git a/dotnet/Qpid.Buffer/ByteBufferProxy.cs b/dotnet/Qpid.Buffer/ByteBufferProxy.cs index 2dd4e73aa6..6fc46ab156 100644 --- a/dotnet/Qpid.Buffer/ByteBufferProxy.cs +++ b/dotnet/Qpid.Buffer/ByteBufferProxy.cs @@ -23,7 +23,7 @@ using System.Text; namespace Qpid.Buffer { - public class ByteBufferProxy : ByteBuffer + public class ByteBufferProxy //: ByteBuffer { protected ByteBuffer _buf; @@ -37,154 +37,154 @@ namespace Qpid.Buffer } - public override void Acquire() - { - _buf.Acquire(); - } - - public override void Release() - { - _buf.Release(); - } - - public override int Capacity - { - get { return _buf.Capacity; } - } - - public override bool IsAutoExpand - { - get { return _buf.IsAutoExpand; } - set { _buf.IsAutoExpand = value; } - } - - public override void Expand(int expectedRemaining) - { - _buf.Expand(expectedRemaining); - } - - public override void Expand(int pos, int expectedRemaining) - { - _buf.Expand(pos, expectedRemaining); - } - - public override bool Pooled - { - get { return _buf.Pooled; } - set { _buf.Pooled = value; } - } - - public override int Position - { - get { return _buf.Position; } - set { _buf.Position = value; } - } - - public override int Limit - { - get { return _buf.Limit; } - set { _buf.Limit = value; } - } - - public override void Clear() - { - _buf.Clear(); - } - - public override void Flip() - { - _buf.Flip(); - } - - public override void Rewind() - { - _buf.Rewind(); - } - - public override int Remaining - { - get { return _buf.Remaining; } - } - - public override byte Get() - { - return _buf.Get(); - } - - public override byte Get(int index) - { - return _buf.Get(index); - } - - public override void Get(byte[] destination) - { - _buf.Get(destination); - } - - public override ushort GetUnsignedShort() - { - return _buf.GetUnsignedShort(); - } - - public override uint GetUnsignedInt() - { - return _buf.GetUnsignedInt(); - } - - public override ulong GetUnsignedLong() - { - return _buf.GetUnsignedLong(); - } - - public override string GetString(uint length, Encoding encoder) - { - return _buf.GetString(length, encoder); - } - - public override void Put(byte data) - { - _buf.Put(data); - } - - public override void Put(byte[] data, int offset, int size) - { - _buf.Put(data, offset, size); - } - - public override void Put(byte[] data) - { - _buf.Put(data); - } - - public override void Put(ushort data) - { - _buf.Put(data); - } - - public override void Put(uint data) - { - _buf.Put(data); - } - - public override void Put(ulong data) - { - _buf.Put(data); - } - - public override void Put(ByteBuffer buf) - { - _buf.Put(buf); - } - - public override void Compact() - { - _buf.Compact(); - } - - public override byte[] ToByteArray() - { - return _buf.ToByteArray(); - } +// public /*override*/ void Acquire() +// { +// _buf.Acquire(); +// } +// +// public /*override*/ void Release() +// { +// _buf.Release(); +// } +// +// public /*override*/ int Capacity +// { +// get { return _buf.Capacity; } +// } +// +// public /*override*/ bool IsAutoExpand +// { +// get { return _buf.IsAutoExpand; } +// set { _buf.IsAutoExpand = value; } +// } +// +// public /*override*/ void Expand(int expectedRemaining) +// { +// _buf.Expand(expectedRemaining); +// } +// +// public /*override*/ void Expand(int pos, int expectedRemaining) +// { +// _buf.Expand(pos, expectedRemaining); +// } +// +// public /*override*/ bool Pooled +// { +// get { return _buf.Pooled; } +// set { _buf.Pooled = value; } +// } +// +// public /*override*/ int Position +// { +// get { return _buf.Position; } +// set { _buf.Position = value; } +// } +// +// public /*override*/ int Limit +// { +// get { return _buf.Limit; } +// set { _buf.Limit = value; } +// } +// +// public /*override*/ void Clear() +// { +// _buf.Clear(); +// } +// +// public /*override*/ void Flip() +// { +// _buf.Flip(); +// } +// +// public /*override*/ void Rewind() +// { +// _buf.Rewind(); +// } +// +// public /*override*/ int Remaining +// { +// get { return _buf.Remaining; } +// } +// +// public /*override*/ byte Get() +// { +// return _buf.Get(); +// } +// +// public /*override*/ byte Get(int index) +// { +// return _buf.Get(index); +// } +// +// public /*override*/ void Get(byte[] destination) +// { +// _buf.Get(destination); +// } +// +// public /*override*/ ushort GetUnsignedShort() +// { +// return _buf.GetUnsignedShort(); +// } +// +// public /*override*/ uint GetUnsignedInt() +// { +// return _buf.GetUnsignedInt(); +// } +// +// public /*override*/ ulong GetUnsignedLong() +// { +// return _buf.GetUnsignedLong(); +// } +// +// public /*override*/ string GetString(uint length, Encoding encoder) +// { +// return _buf.GetString(length, encoder); +// } +// +// public /*override*/ void Put(byte data) +// { +// _buf.Put(data); +// } +// +// public /*override*/ void Put(byte[] data, int offset, int size) +// { +// _buf.Put(data, offset, size); +// } +// +// public /*override*/ void Put(byte[] data) +// { +// _buf.Put(data); +// } +// +// public /*override*/ void Put(ushort data) +// { +// _buf.Put(data); +// } +// +// public /*override*/ void Put(uint data) +// { +// _buf.Put(data); +// } +// +// public /*override*/ void Put(ulong data) +// { +// _buf.Put(data); +// } +// +// public /*override*/ void Put(ByteBuffer buf) +// { +// _buf.Put(buf); +// } +// +// public /*override*/ void Compact() +// { +// _buf.Compact(); +// } +// +// public /*override*/ byte[] ToByteArray() +// { +// return _buf.ToByteArray(); +// } } } diff --git a/dotnet/Qpid.Buffer/FixedByteBuffer.cs b/dotnet/Qpid.Buffer/FixedByteBuffer.cs new file mode 100644 index 0000000000..39a17a6fa7 --- /dev/null +++ b/dotnet/Qpid.Buffer/FixedByteBuffer.cs @@ -0,0 +1,367 @@ +/* + * + * 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. + * + */ +using System; + +namespace Qpid.Buffer +{ + public class FixedByteBuffer + { + private HeapByteBuffer _buf; + + public FixedByteBuffer(int capacity) + { + _buf = new HeapByteBuffer(capacity); + } + + public FixedByteBuffer(byte[] bytes) + { + _buf = HeapByteBuffer.wrap(bytes); + } + + public static FixedByteBuffer wrap(byte[] array) + { + return new FixedByteBuffer(array); + } + + public static FixedByteBuffer wrap(byte[] array, int offset, int length) + { + throw new NotImplementedException(); + } + + public ByteOrder order() + { + return ByteOrder.LittleEndian; + } + + public void order(ByteOrder bo) + { + // Ignore endianess. + } + + public void compact() + { + _buf.Compact(); + } + + public char getChar() + { + throw new NotImplementedException(); + } + + public char getChar(int index) + { + throw new NotImplementedException(); + } + + public void putChar(char value) + { + throw new NotImplementedException(); + } + + public void putChar(int index, char value) + { + throw new NotImplementedException(); + } + + public bool isDirect() + { + return false; + } + + public bool isReadOnly() + { + throw new NotImplementedException(); + } + + public int capacity() + { + return _buf.Capacity; + } + + public int limit() + { + return _buf.Limit; + } + + public int limit(int limit) + { + int previousLimit = _buf.Limit; + _buf.Limit = limit; + return previousLimit; + } + + public int position() + { + return _buf.Position; + } + + public int position(int newPosition) + { + int prev = _buf.Position; + _buf.Position = newPosition; + return prev; + } + + public void mark() + { + throw new NotImplementedException(); + } + + public static FixedByteBuffer allocateDirect(int capacity) + { + throw new NotImplementedException(); + } + + public static FixedByteBuffer allocate(int capacity) + { + return new FixedByteBuffer(capacity); + } + + public void clear() + { + _buf.Clear(); + } + + public void put(byte b) + { + _buf.Put(b); + } + + public void put(int index, byte b) + { + throw new NotImplementedException(); + } + + public void put(FixedByteBuffer buf) + { + _buf.Put(buf.array(), buf.position(), buf.limit() - buf.position()); + } + + public FixedByteBuffer duplicate() + { + throw new NotImplementedException(); + } + + public FixedByteBuffer slice() + { + throw new NotImplementedException(); + } + + public FixedByteBuffer asReadOnlyBuffer() + { + throw new NotImplementedException(); + } + + /// <summary> + /// Returns backing array. + /// </summary> + /// <returns></returns> + public byte[] array() + { + return _buf.array(); + } + + public int arrayOffset() + { + throw new NotImplementedException(); + } + + public void reset() + { + throw new NotImplementedException(); + } + + public void flip() + { + _buf.Flip(); + } + + public void rewind() + { + _buf.Rewind(); + } + + public byte get() + { + return _buf.Get(); + } + + public byte get(int index) + { + throw new NotImplementedException(); + } + + public short getShort() + { + throw new NotImplementedException(); + } + + public short getShort(int index) + { + throw new NotImplementedException(); + } + + public void putShort(short value) + { + throw new NotImplementedException(); + } + + public void putShort(int index, short value) + { + throw new NotImplementedException(); + } + + public int getInt() + { + throw new NotImplementedException(); + } + + public int getInt(int index) + { + throw new NotImplementedException(); + } + + public void putInt(int value) + { + throw new NotImplementedException(); + } + + public void putInt(int index, int value) + { + throw new NotImplementedException(); + } + + public ByteBuffer get(byte[] dst, int offset, int length) + { + throw new NotImplementedException(); + } + + public ByteBuffer put(byte[] src, int offset, int length) + { + throw new NotImplementedException(); + } + + public long getLong() + { + throw new NotImplementedException(); + } + + public long getLong(int index) + { + throw new NotImplementedException(); + } + + public void putLong(long value) + { + throw new NotImplementedException(); + } + + public void putLong(int index, long value) + { + throw new NotImplementedException(); + } + + public int remaining() + { + return _buf.Remaining; + } + + public float getFloat() + { + throw new NotImplementedException(); + } + + public float getFloat(int index) + { + throw new NotImplementedException(); + } + + public void putFloat(float value) + { + throw new NotImplementedException(); + } + + public void putFloat(int index, float value) + { + throw new NotImplementedException(); + } + + public double getDouble() + { + throw new NotImplementedException(); + } + + public double getDouble(int index) + { + throw new NotImplementedException(); + } + + public void putDouble(double value) + { + throw new NotImplementedException(); + } + + public void putDouble(int index, double value) + { + throw new NotImplementedException(); + } + + public ushort getUnsignedShort() + { + return _buf.GetUnsignedShort(); + } + + public uint getUnsignedInt() + { + return _buf.GetUnsignedInt(); + } + + public void get(byte[] dst) + { + _buf.Get(dst); + } + + public void put(ushort value) + { + _buf.Put(value); + } + + public void put(uint max) + { + _buf.Put(max); + } + + public void put(ulong tag) + { + _buf.Put(tag); + } + + public void put(byte[] src) + { + _buf.Put(src); + } + + public ulong getUnsignedLong() + { + return _buf.GetUnsignedLong(); + } + } +} diff --git a/dotnet/Qpid.Buffer/HeapByteBuffer.cs b/dotnet/Qpid.Buffer/HeapByteBuffer.cs index ea3b11b60d..3ac99021d7 100644 --- a/dotnet/Qpid.Buffer/HeapByteBuffer.cs +++ b/dotnet/Qpid.Buffer/HeapByteBuffer.cs @@ -23,7 +23,7 @@ using System.Text; namespace Qpid.Buffer { - public class HeapByteBuffer : ByteBuffer + public class HeapByteBuffer //: ByteBuffer { private byte[] _underlyingData; @@ -48,7 +48,7 @@ namespace Qpid.Buffer _position = length; } - public override int Capacity + public /*override*/ int Capacity { get { @@ -56,7 +56,7 @@ namespace Qpid.Buffer } } - public override int Position + public /*override*/ int Position { get { @@ -72,7 +72,7 @@ namespace Qpid.Buffer /// Sets this buffer's limit. If the position is larger than the new limit then it is set to the new limit. /// </summary> /// <value>The new limit value; must be non-negative and no larger than this buffer's capacity</value> - public override int Limit + public /*override*/ int Limit { get { @@ -100,7 +100,7 @@ namespace Qpid.Buffer /// Returns the number of elements between the current position and the limit /// </summary> /// <value>The number of elements remaining in this buffer</value> - public override int Remaining + public /*override*/ int Remaining { get { @@ -108,24 +108,29 @@ namespace Qpid.Buffer } } - public override void Clear() + public /*override*/ void Clear() { _position = 0; _limit = Capacity; } - public override void Flip() + public /*override*/ void Flip() { _limit = _position; _position = 0; } - public override void Rewind() + public /*override*/ void Rewind() { _position = 0; } - public override byte[] ToByteArray() + public byte[] array() + { + return _underlyingData; + } + + public /*override*/ byte[] ToByteArray() { // Return copy of bytes remaining. byte[] result = new byte[Remaining]; @@ -156,7 +161,7 @@ namespace Qpid.Buffer /// </summary> /// <param name="data">The byte to be written</param> /// <exception cref="BufferOverflowException">If this buffer's current position is not smaller than its limit</exception> - public override void Put(byte data) + public /*override*/ void Put(byte data) { CheckSpace(1); _underlyingData[_position++] = data; @@ -168,12 +173,12 @@ namespace Qpid.Buffer /// </summary> /// <param name="data">The data to copy.</param> /// <exception cref="BufferOverflowException">If this buffer's current position plus the array length is not smaller than its limit</exception> - public override void Put(byte[] data) + public /*override*/ void Put(byte[] data) { Put(data, 0, data.Length); } - public override void Put(byte[] data, int offset, int size) + public /*override*/ void Put(byte[] data, int offset, int size) { if (data == null) { @@ -188,14 +193,14 @@ namespace Qpid.Buffer /// Writes the given ushort into this buffer at the current position, and then increments the position. /// </summary> /// <param name="data">The ushort to be written</param> - public override void Put(ushort data) + public /*override*/ void Put(ushort data) { CheckSpace(2); _underlyingData[_position++] = (byte) (data >> 8); _underlyingData[_position++] = (byte) data; } - public override void Put(uint data) + public /*override*/ void Put(uint data) { CheckSpace(4); _underlyingData[_position++] = (byte) (data >> 24); @@ -204,7 +209,7 @@ namespace Qpid.Buffer _underlyingData[_position++] = (byte) data; } - public override void Put(ulong data) + public /*override*/ void Put(ulong data) { CheckSpace(8); _underlyingData[_position++] = (byte) (data >> 56); @@ -222,7 +227,7 @@ namespace Qpid.Buffer /// </summary> /// <returns>a byte</returns> /// <exception cref="BufferUnderflowException">if there are no bytes left to read</exception> - public override byte Get() + public /*override*/ byte Get() { CheckSpaceForReading(1); return _underlyingData[_position++]; @@ -233,7 +238,7 @@ namespace Qpid.Buffer /// </summary> /// <param name="destination">The destination array. The array must not /// be bigger than the remaining space in the buffer, nor can it be null.</param> - public override void Get(byte[] destination) + public /*override*/ void Get(byte[] destination) { if (destination == null) { @@ -250,7 +255,7 @@ namespace Qpid.Buffer /// </summary> /// <returns>an unsigned short</returns> /// <exception cref="BufferUnderflowException">If there are fewer than two bytes remaining in this buffer</exception> - public override ushort GetUnsignedShort() + public /*override*/ ushort GetUnsignedShort() { CheckSpaceForReading(2); byte upper = _underlyingData[_position++]; @@ -263,7 +268,7 @@ namespace Qpid.Buffer /// </summary> /// <returns>an unsigned integer</returns> /// <exception cref="BufferUnderflowException">If there are fewer than four bytes remaining in this buffer</exception> - public override uint GetUnsignedInt() + public /*override*/ uint GetUnsignedInt() { CheckSpaceForReading(4); byte b1 = _underlyingData[_position++]; @@ -273,7 +278,7 @@ namespace Qpid.Buffer return (uint) ((b1 << 24) + (b2 << 16) + (b3 << 8) + b4); } - public override ulong GetUnsignedLong() + public /*override*/ ulong GetUnsignedLong() { CheckSpaceForReading(8); byte b1 = _underlyingData[_position++]; @@ -288,7 +293,7 @@ namespace Qpid.Buffer (b6 << 16) + (b7 << 8) + b8); } - public override string GetString(uint length, Encoding encoder) + public /*override*/ string GetString(uint length, Encoding encoder) { CheckSpaceForReading((int)length); string result = encoder.GetString(_underlyingData, _position, (int)length); @@ -296,31 +301,31 @@ namespace Qpid.Buffer return result; } - public override void Acquire() + public /*override*/ void Acquire() { } - public override void Release() + public /*override*/ void Release() { } - public override bool IsAutoExpand + public /*override*/ bool IsAutoExpand { get { return false; } set { } } - public override void Expand(int expectedRemaining) + public /*override*/ void Expand(int expectedRemaining) { throw new NotImplementedException(); } - public override void Expand(int pos, int expectedRemaining) + public /*override*/ void Expand(int pos, int expectedRemaining) { throw new NotImplementedException(); } - public override bool Pooled + public /*override*/ bool Pooled { get { return false; } set { } @@ -336,38 +341,38 @@ namespace Qpid.Buffer throw new NotImplementedException(); } - public override byte Get(int index) + public /*override*/ byte Get(int index) { throw new NotImplementedException(); } - public override void Put(ByteBuffer src) - { - if (src == this) - { - throw new ArgumentException("Cannot copy self into self!"); - } - - HeapByteBuffer sb; - if (src is HeapByteBuffer) - { - sb = (HeapByteBuffer) src; - } - else - { - sb = (HeapByteBuffer)((RefCountingByteBuffer) src).Buf; - } - int n = sb.Remaining; - if (n > Remaining) - { - throw new BufferOverflowException("Not enought capacity in this buffer for " + n + " elements - only " + Remaining + " remaining"); - } - Array.Copy(sb._underlyingData, sb._position, _underlyingData, _position, n); - sb._position += n; - _position += n; - } +// public /*override*/ void Put(ByteBuffer src) +// { +// if (src == this) +// { +// throw new ArgumentException("Cannot copy self into self!"); +// } +// +// HeapByteBuffer sb; +// if (src is HeapByteBuffer) +// { +// sb = (HeapByteBuffer) src; +// } +// else +// { +// sb = (HeapByteBuffer)((RefCountingByteBuffer) src).Buf; +// } +// int n = sb.Remaining; +// if (n > Remaining) +// { +// throw new BufferOverflowException("Not enought capacity in this buffer for " + n + " elements - only " + Remaining + " remaining"); +// } +// Array.Copy(sb._underlyingData, sb._position, _underlyingData, _position, n); +// sb._position += n; +// _position += n; +// } - public override void Compact() + public /*override*/ void Compact() { if (Remaining > 0) { diff --git a/dotnet/Qpid.Buffer/Qpid.Buffer.csproj b/dotnet/Qpid.Buffer/Qpid.Buffer.csproj index dbc12856bf..7bca166fbc 100644 --- a/dotnet/Qpid.Buffer/Qpid.Buffer.csproj +++ b/dotnet/Qpid.Buffer/Qpid.Buffer.csproj @@ -36,14 +36,18 @@ <Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="BaseByteBuffer.cs" />
+ <Compile Include="BufferDataException.cs" />
<Compile Include="BufferOverflowException.cs" />
<Compile Include="BufferUnderflowException.cs" />
<Compile Include="ByteBuffer.cs" />
+ <Compile Include="ByteBufferAllocator.cs" />
<Compile Include="ByteBufferHexDumper.cs" />
<Compile Include="ByteBufferProxy.cs" />
+ <Compile Include="FixedByteBuffer.cs" />
<Compile Include="HeapByteBuffer.cs" />
- <Compile Include="RefCountingByteBuffer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="SimpleByteBufferAllocator.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
diff --git a/dotnet/Qpid.Buffer/RefCountingByteBuffer.cs b/dotnet/Qpid.Buffer/RefCountingByteBuffer.cs deleted file mode 100644 index 0d3fc4b77b..0000000000 --- a/dotnet/Qpid.Buffer/RefCountingByteBuffer.cs +++ /dev/null @@ -1,336 +0,0 @@ -/* - * - * 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. - * - */ -using System; -using System.Text; - -namespace Qpid.Buffer -{ - public class RefCountingByteBuffer : ByteBuffer - { - private ByteBuffer _buf; - - private int _refCount = 1; - private bool _autoExpand; - private bool _pooled; - - public void Init(ByteBuffer buf) - { - lock (this) - { - _buf = buf; - buf.Clear(); - _autoExpand = false; - _pooled = true; - _refCount = 1; - } - } - - public override void Acquire() - { - lock (this) - { - if (_refCount <= 0) - { - throw new Exception("Already released buffer"); - } - _refCount++; - } - } - - public override void Release() - { - lock (this) - { - if (_refCount <= 0) - { - _refCount = 0; - throw new Exception("Already released buffer. Release called too many times"); - } - - _refCount--; - if (_refCount > 0) - { - return; - } - } - - if (_pooled) - { - Release0(_buf); - } - - lock (_containerStack) - { - _containerStack.Push(this); - } - } - - public ByteBuffer Buf - { - get - { - return _buf; - } - } - - public override bool IsAutoExpand - { - get - { - return _autoExpand; - } - - set - { - _autoExpand = value; - } - } - - public override bool Pooled - { - get - { - return _pooled; - } - - set - { - _pooled = value; - } - } - - public override int Capacity - { - get - { - return _buf.Capacity; - } - } - - public override int Position - { - get - { - return _buf.Position; - } - set - { - AutoExpand(value, 0); - _buf.Position = value; - } - } - - public override int Limit - { - get - { - return _buf.Limit; - } - set - { - AutoExpand(value, 0); - _buf.Limit = value; - } - } - - /*public override void Mark() - { - _buf.Mark(); - } - - public override void Reset() - { - _buf.Reset(); - }*/ - - public override void Clear() - { - _buf.Clear(); - } - - public override void Flip() - { - _buf.Flip(); - } - - public override void Rewind() - { - _buf.Rewind(); - } - - public override int Remaining - { - get - { - return _buf.Remaining; - } - } - - public override byte Get() - { - return _buf.Get(); - } - - public override void Put(byte data) - { - AutoExpand(1); - _buf.Put(data); - } - - public override byte Get(int index) - { - return _buf.Get(index); - } - - public override void Compact() - { - _buf.Compact(); - } - - - public override void Get(byte[] destination) - { - _buf.Get(destination); - } - - public override ushort GetUnsignedShort() - { - return _buf.GetUnsignedShort(); - } - - public override uint GetUnsignedInt() - { - return _buf.GetUnsignedInt(); - } - - public override ulong GetUnsignedLong() - { - return _buf.GetUnsignedLong(); - } - - public override string GetString(uint length, Encoding encoder) - { - return _buf.GetString(length, encoder); - } - - public override void Put(byte[] data) - { - AutoExpand(data.Length); - _buf.Put(data); - } - - public override void Put(byte[] data, int offset, int size) - { - AutoExpand(size); - _buf.Put(data, offset, size); - } - - public override void Put(ushort data) - { - AutoExpand(2); - _buf.Put(data); - } - - public override void Put(uint data) - { - AutoExpand(4); - _buf.Put(data); - } - - public override void Put(ulong data) - { - AutoExpand(8); - _buf.Put(data); - } - - public override void Put(ByteBuffer buf) - { - AutoExpand(buf.Remaining); - _buf.Put(buf); - } - - public override void Expand(int expectedRemaining) - { - if (_autoExpand) - { - int pos = _buf.Position; - int limit = _buf.Limit; - int end = pos + expectedRemaining; - if (end > limit) - { - EnsureCapacity(end); - _buf.Limit = end; - } - } - } - - public override void Expand(int pos, int expectedRemaining) - { - if (_autoExpand) - { - int limit = _buf.Limit; - int end = pos + expectedRemaining; - if (end > limit) - { - EnsureCapacity(end); - _buf.Limit = end; - } - } - } - - private void EnsureCapacity(int requestedCapacity) - { - if (requestedCapacity <= _buf.Capacity) - { - return; - } - - int newCapacity = MINIMUM_CAPACITY; - while (newCapacity < requestedCapacity) - { - newCapacity <<= 1; - } - - ByteBuffer oldBuf = _buf; - ByteBuffer newBuf = Allocate0(newCapacity, false); - newBuf.Clear(); - int pos = oldBuf.Position; - int limit = oldBuf.Limit; - oldBuf.Clear(); - newBuf.Put(oldBuf); - newBuf.Position = pos; - newBuf.Limit = limit; - _buf = newBuf; - Release0(oldBuf); - } - - public override byte[] ToByteArray() - { - return _buf.ToByteArray(); - } - - public override string ToString() - { - return "RefCountingByteBuffer: refs= " + _refCount + "buf=" + base.ToString(); - } - } -} - diff --git a/dotnet/Qpid.Buffer/SimpleByteBufferAllocator.cs b/dotnet/Qpid.Buffer/SimpleByteBufferAllocator.cs new file mode 100644 index 0000000000..852c7f3aa8 --- /dev/null +++ b/dotnet/Qpid.Buffer/SimpleByteBufferAllocator.cs @@ -0,0 +1,190 @@ +/* + * + * 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. + * + */ +using System; +using System.Runtime.CompilerServices; + +namespace Qpid.Buffer +{ + /** + * A simplistic {@link ByteBufferAllocator} which simply allocates a new + * buffer every time. + */ + public class SimpleByteBufferAllocator : ByteBufferAllocator + { + private const int MINIMUM_CAPACITY = 1; + + public SimpleByteBufferAllocator() + { + } + + public ByteBuffer allocate( int capacity, bool direct ) + { + FixedByteBuffer nioBuffer; + if( direct ) + { + nioBuffer = FixedByteBuffer.allocateDirect( capacity ); + } + else + { + nioBuffer = FixedByteBuffer.allocate( capacity ); + } + return new SimpleByteBuffer( nioBuffer ); + } + + public ByteBuffer wrap( FixedByteBuffer nioBuffer ) + { + return new SimpleByteBuffer( nioBuffer ); + } + + public void dispose() + { + } + + private class SimpleByteBuffer : BaseByteBuffer + { + private FixedByteBuffer _buf; + private int refCount = 1; + + internal SimpleByteBuffer( FixedByteBuffer buf ) + { + this._buf = buf; + buf.order( ByteOrder.BigEndian ); + refCount = 1; + } + + [MethodImpl(MethodImplOptions.Synchronized)] + public override void acquire() + { + if( refCount <= 0 ) + { + throw new InvalidOperationException("Already released buffer."); + } + + refCount ++; + } + + public override void release() + { + lock( this ) + { + if( refCount <= 0 ) + { + refCount = 0; + throw new InvalidOperationException( + "Already released buffer. You released the buffer too many times." ); + } + + refCount --; + if( refCount > 0) + { + return; + } + } + } + + public override FixedByteBuffer buf() + { + return _buf; + } + + public override bool isPooled() + { + return false; + } + + public override void setPooled(bool pooled) + { + } + + protected override void capacity0(int requestedCapacity) + { + Console.WriteLine("XXX capacity0 called with requestedCapacity=" + requestedCapacity); // FIXME: remove this. + + int newCapacity = MINIMUM_CAPACITY; + while( newCapacity < requestedCapacity ) + { + newCapacity <<= 1; + } + + FixedByteBuffer oldBuf = this._buf; + FixedByteBuffer newBuf; + if( isDirect() ) + { + newBuf = FixedByteBuffer.allocateDirect( newCapacity ); + } + else + { + newBuf = FixedByteBuffer.allocate( newCapacity ); + } + + newBuf.clear(); + oldBuf.clear(); + newBuf.put( oldBuf ); + this._buf = newBuf; + } + + public override ByteBuffer duplicate() { + return new SimpleByteBuffer( this._buf.duplicate() ); + } + + public override ByteBuffer slice() + { + return new SimpleByteBuffer( this._buf.slice() ); + } + + public override ByteBuffer asReadOnlyBuffer() + { + return new SimpleByteBuffer( this._buf.asReadOnlyBuffer() ); + } + + public override byte[] array() + { + return _buf.array(); + } + + public override int arrayOffset() + { + return _buf.arrayOffset(); + } + + public override void put(ushort value) + { + _buf.put(value); + } + + public override void put(uint max) + { + _buf.put(max); + } + + public override void put(ulong tag) + { + _buf.put(tag); + } + + public override ulong GetUnsignedLong() + { + return _buf.getUnsignedLong(); + } + + } + } +} |