/*
*
* 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 HeapByteBuffer : ByteBuffer
{
private byte[] _underlyingData;
///
/// The position of the next value to be read or written
///
private int _position;
///
/// The index of the first element that should not be read or written
///
private int _limit;
public HeapByteBuffer(int size) : this(new byte[size], 0)
{
}
private HeapByteBuffer(byte[] bytes, int length)
{
_underlyingData = bytes;
_limit = bytes.Length;
_position = length;
}
public override int Capacity
{
get
{
return _underlyingData.Length;
}
}
public override int Position
{
get
{
return _position;
}
set
{
_position = value;
}
}
///
/// Sets this buffer's limit. If the position is larger than the new limit then it is set to the new limit.
///
/// The new limit value; must be non-negative and no larger than this buffer's capacity
public override int Limit
{
get
{
return _limit;
}
set
{
if (value < 0)
{
throw new ArgumentException("Limit must not be negative");
}
if (value > Capacity)
{
throw new ArgumentException("Limit must not be greater than Capacity");
}
_limit = value;
if (_position > value)
{
_position = value;
}
}
}
///
/// Returns the number of elements between the current position and the limit
///
/// The number of elements remaining in this buffer
public override int Remaining
{
get
{
return (_limit - _position);
}
}
public override void Clear()
{
_position = 0;
_limit = Capacity;
}
public override void Flip()
{
_limit = _position;
_position = 0;
}
public override void Rewind()
{
_position = 0;
}
public override byte[] ToByteArray()
{
return _underlyingData;
}
private void CheckSpace(int size)
{
if (_position + size > _limit)
{
throw new BufferOverflowException("Attempt to write " + size + " byte(s) to buffer where position is " + _position +
" and limit is " + _limit);
}
}
private void CheckSpaceForReading(int size)
{
if (_position + size > _limit)
{
throw new BufferUnderflowException("Attempt to read " + size + " byte(s) to buffer where position is " + _position +
" and limit is " + _limit);
}
}
///
/// Writes the given byte into this buffer at the current position, and then increments the position.
///
/// The byte to be written
/// If this buffer's current position is not smaller than its limit
public override void Put(byte data)
{
CheckSpace(1);
_underlyingData[_position++] = data;
}
///
/// Writes all the data in the given byte array into this buffer at the current
/// position and then increments the position.
///
/// The data to copy.
/// If this buffer's current position plus the array length is not smaller than its limit
public override void Put(byte[] data)
{
Put(data, 0, data.Length);
}
public override void Put(byte[] data, int offset, int size)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
CheckSpace(size);
Array.Copy(data, offset, _underlyingData, _position, size);
_position += size;
}
///
/// Writes the given ushort into this buffer at the current position, and then increments the position.
///
/// The ushort to be written
public override void Put(ushort data)
{
CheckSpace(2);
_underlyingData[_position++] = (byte) (data >> 8);
_underlyingData[_position++] = (byte) data;
}
public override void Put(uint data)
{
CheckSpace(4);
_underlyingData[_position++] = (byte) (data >> 24);
_underlyingData[_position++] = (byte) (data >> 16);
_underlyingData[_position++] = (byte) (data >> 8);
_underlyingData[_position++] = (byte) data;
}
public override void Put(ulong data)
{
CheckSpace(8);
_underlyingData[_position++] = (byte) (data >> 56);
_underlyingData[_position++] = (byte) (data >> 48);
_underlyingData[_position++] = (byte) (data >> 40);
_underlyingData[_position++] = (byte) (data >> 32);
_underlyingData[_position++] = (byte) (data >> 24);
_underlyingData[_position++] = (byte) (data >> 16);
_underlyingData[_position++] = (byte) (data >> 8);
_underlyingData[_position++] = (byte) data;
}
///
/// Read the byte at the current position and increment the position
///
/// a byte
/// if there are no bytes left to read
public override byte Get()
{
CheckSpaceForReading(1);
return _underlyingData[_position++];
}
///
/// Reads bytes from the buffer into the supplied array
///
/// The destination array. The array must not
/// be bigger than the remaining space in the buffer, nor can it be null.
public override void Get(byte[] destination)
{
if (destination == null)
{
throw new ArgumentNullException("destination");
}
int len = destination.Length;
CheckSpaceForReading(len);
Array.Copy(_underlyingData, _position, destination, 0, len);
_position += len;
}
///
/// Reads and returns an unsigned short (two bytes, big endian) from this buffer
///
/// an unsigned short
/// If there are fewer than two bytes remaining in this buffer
public override ushort GetUnsignedShort()
{
CheckSpaceForReading(2);
byte upper = _underlyingData[_position++];
byte lower = _underlyingData[_position++];
return (ushort) ((upper << 8) + lower);
}
///
/// Reads and returns an unsigned int (four bytes, big endian) from this buffer
///
/// an unsigned integer
/// If there are fewer than four bytes remaining in this buffer
public override uint GetUnsignedInt()
{
CheckSpaceForReading(4);
byte b1 = _underlyingData[_position++];
byte b2 = _underlyingData[_position++];
byte b3 = _underlyingData[_position++];
byte b4 = _underlyingData[_position++];
return (uint) ((b1 << 24) + (b2 << 16) + (b3 << 8) + b4);
}
public override ulong GetUnsignedLong()
{
CheckSpaceForReading(8);
byte b1 = _underlyingData[_position++];
byte b2 = _underlyingData[_position++];
byte b3 = _underlyingData[_position++];
byte b4 = _underlyingData[_position++];
byte b5 = _underlyingData[_position++];
byte b6 = _underlyingData[_position++];
byte b7 = _underlyingData[_position++];
byte b8 = _underlyingData[_position++];
return (ulong)((b1 << 56) + (b2 << 48) + (b3 << 40) + (b4 << 32) + (b5 << 24) +
(b6 << 16) + (b7 << 8) + b8);
}
public override string GetString(uint length, Encoding encoder)
{
CheckSpaceForReading((int)length);
string result = encoder.GetString(_underlyingData, _position, (int)length);
_position += (int)length;
return result;
}
public override void Acquire()
{
}
public override void Release()
{
}
public override bool IsAutoExpand
{
get { return false; }
set { }
}
public override void Expand(int expectedRemaining)
{
throw new NotImplementedException();
}
public override void Expand(int pos, int expectedRemaining)
{
throw new NotImplementedException();
}
public override bool Pooled
{
get { return false; }
set { }
}
public void Mark()
{
throw new NotImplementedException();
}
public void Reset()
{
throw new NotImplementedException();
}
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 Compact()
{
if (Remaining > 0)
{
if (_position > 0)
{
Array.Copy(_underlyingData, _position, _underlyingData, 0, Remaining);
}
_position = Remaining;
}
else
{
_position = 0;
}
_limit = Capacity;
}
public static HeapByteBuffer wrap(byte[] bytes, int length)
{
return new HeapByteBuffer(bytes, length);
}
public static HeapByteBuffer wrap(byte[] bytes)
{
return new HeapByteBuffer(bytes, bytes.Length);
}
}
}