diff options
author | Steven Shaw <steshaw@apache.org> | 2006-12-12 17:36:17 +0000 |
---|---|---|
committer | Steven Shaw <steshaw@apache.org> | 2006-12-12 17:36:17 +0000 |
commit | ad8fa512e788075a4573678738b6f11f1c8cbd59 (patch) | |
tree | 69eef3dfec5848f489a9f129237e38ae35b3079c /qpid/dotnet/Qpid.Buffer | |
parent | 4e1735463fdb63f87d03541c33a816a5c7af563f (diff) | |
download | qpid-python-ad8fa512e788075a4573678738b6f11f1c8cbd59.tar.gz |
QPID-139. Initial (re)port of MINA's bytebuffer abstraction. Now includes the autoexpand feature. References to java.nio.Buffer were replaced with FixedByteBuffer and necessary methods added and implemented. FixedByteBuffer delegates to our existing HeapByteBuffer.
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@486248 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/dotnet/Qpid.Buffer')
-rw-r--r-- | qpid/dotnet/Qpid.Buffer/BaseByteBuffer.cs | 461 | ||||
-rw-r--r-- | qpid/dotnet/Qpid.Buffer/BufferDataException.cs | 47 | ||||
-rw-r--r-- | qpid/dotnet/Qpid.Buffer/ByteBuffer.cs | 2543 | ||||
-rw-r--r-- | qpid/dotnet/Qpid.Buffer/ByteBufferAllocator.cs | 50 | ||||
-rw-r--r-- | qpid/dotnet/Qpid.Buffer/ByteBufferHexDumper.cs | 4 | ||||
-rw-r--r-- | qpid/dotnet/Qpid.Buffer/ByteBufferProxy.cs | 298 | ||||
-rw-r--r-- | qpid/dotnet/Qpid.Buffer/FixedByteBuffer.cs | 367 | ||||
-rw-r--r-- | qpid/dotnet/Qpid.Buffer/HeapByteBuffer.cs | 113 | ||||
-rw-r--r-- | qpid/dotnet/Qpid.Buffer/Qpid.Buffer.csproj | 6 | ||||
-rw-r--r-- | qpid/dotnet/Qpid.Buffer/RefCountingByteBuffer.cs | 336 | ||||
-rw-r--r-- | qpid/dotnet/Qpid.Buffer/SimpleByteBufferAllocator.cs | 190 |
11 files changed, 3573 insertions, 842 deletions
diff --git a/qpid/dotnet/Qpid.Buffer/BaseByteBuffer.cs b/qpid/dotnet/Qpid.Buffer/BaseByteBuffer.cs new file mode 100644 index 0000000000..099c84d6fa --- /dev/null +++ b/qpid/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/qpid/dotnet/Qpid.Buffer/BufferDataException.cs b/qpid/dotnet/Qpid.Buffer/BufferDataException.cs new file mode 100644 index 0000000000..1c6c37e84f --- /dev/null +++ b/qpid/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/qpid/dotnet/Qpid.Buffer/ByteBuffer.cs b/qpid/dotnet/Qpid.Buffer/ByteBuffer.cs index 70022407a5..1a43c0b9f3 100644 --- a/qpid/dotnet/Qpid.Buffer/ByteBuffer.cs +++ b/qpid/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/qpid/dotnet/Qpid.Buffer/ByteBufferAllocator.cs b/qpid/dotnet/Qpid.Buffer/ByteBufferAllocator.cs new file mode 100644 index 0000000000..2dabd0ef50 --- /dev/null +++ b/qpid/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/qpid/dotnet/Qpid.Buffer/ByteBufferHexDumper.cs b/qpid/dotnet/Qpid.Buffer/ByteBufferHexDumper.cs index a43331ff1a..459abc56ef 100644 --- a/qpid/dotnet/Qpid.Buffer/ByteBufferHexDumper.cs +++ b/qpid/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/qpid/dotnet/Qpid.Buffer/ByteBufferProxy.cs b/qpid/dotnet/Qpid.Buffer/ByteBufferProxy.cs index 2dd4e73aa6..6fc46ab156 100644 --- a/qpid/dotnet/Qpid.Buffer/ByteBufferProxy.cs +++ b/qpid/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/qpid/dotnet/Qpid.Buffer/FixedByteBuffer.cs b/qpid/dotnet/Qpid.Buffer/FixedByteBuffer.cs new file mode 100644 index 0000000000..39a17a6fa7 --- /dev/null +++ b/qpid/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/qpid/dotnet/Qpid.Buffer/HeapByteBuffer.cs b/qpid/dotnet/Qpid.Buffer/HeapByteBuffer.cs index ea3b11b60d..3ac99021d7 100644 --- a/qpid/dotnet/Qpid.Buffer/HeapByteBuffer.cs +++ b/qpid/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/qpid/dotnet/Qpid.Buffer/Qpid.Buffer.csproj b/qpid/dotnet/Qpid.Buffer/Qpid.Buffer.csproj index dbc12856bf..7bca166fbc 100644 --- a/qpid/dotnet/Qpid.Buffer/Qpid.Buffer.csproj +++ b/qpid/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/qpid/dotnet/Qpid.Buffer/RefCountingByteBuffer.cs b/qpid/dotnet/Qpid.Buffer/RefCountingByteBuffer.cs deleted file mode 100644 index 0d3fc4b77b..0000000000 --- a/qpid/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/qpid/dotnet/Qpid.Buffer/SimpleByteBufferAllocator.cs b/qpid/dotnet/Qpid.Buffer/SimpleByteBufferAllocator.cs new file mode 100644 index 0000000000..852c7f3aa8 --- /dev/null +++ b/qpid/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(); + } + + } + } +} |