/* Copyright 2010-2015 MongoDB Inc.
*
* Licensed 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.IO;
namespace MongoDB.Bson.IO
{
///
/// Represents a slice of a byte buffer.
///
public class ByteBufferSlice : IByteBuffer
{
private readonly IByteBuffer _buffer;
private bool _disposed;
private readonly int _length;
private readonly int _offset;
///
/// Initializes a new instance of the class.
///
/// The byte buffer.
/// The offset of the slice.
/// The length of the slice.
public ByteBufferSlice(IByteBuffer buffer, int offset, int length)
{
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
if (!buffer.IsReadOnly)
{
throw new ArgumentException("The buffer is not read only.", "buffer");
}
if (offset < 0 || offset > buffer.Length)
{
throw new ArgumentOutOfRangeException("offset");
}
if (length < 0 || offset + length > buffer.Length)
{
throw new ArgumentOutOfRangeException("length");
}
_buffer = buffer;
_offset = offset;
_length = length;
}
///
/// Gets the buffer.
///
///
/// The buffer.
///
public IByteBuffer Buffer
{
get
{
ThrowIfDisposed();
return _buffer;
}
}
///
public int Capacity
{
get
{
ThrowIfDisposed();
return _length;
}
}
///
public bool IsReadOnly
{
get
{
ThrowIfDisposed();
return true;
}
}
///
public int Length
{
get
{
ThrowIfDisposed();
return _length;
}
set
{
throw new NotSupportedException();
}
}
///
public ArraySegment AccessBackingBytes(int position)
{
EnsureValidPosition(position);
ThrowIfDisposed();
var segment = _buffer.AccessBackingBytes(position + _offset);
var count = Math.Min(segment.Count, _length - position);
return new ArraySegment(segment.Array, segment.Offset, count);
}
///
public void Clear(int position, int count)
{
EnsureValidPositionAndCount(position, count);
ThrowIfDisposed();
_buffer.Clear(position + _offset, count);
}
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
public void EnsureCapacity(int minimumCapacity)
{
throw new NotSupportedException();
}
///
public byte GetByte(int position)
{
EnsureValidPosition(position);
ThrowIfDisposed();
return _buffer.GetByte(position + _offset);
}
///
public void GetBytes(int position, byte[] destination, int offset, int count)
{
EnsureValidPositionAndCount(position, count);
ThrowIfDisposed();
_buffer.GetBytes(position + _offset, destination, offset, count);
}
///
public IByteBuffer GetSlice(int position, int length)
{
EnsureValidPositionAndLength(position, length);
ThrowIfDisposed();
return _buffer.GetSlice(position + _offset, length);
}
///
public void MakeReadOnly()
{
ThrowIfDisposed();
}
///
public void SetByte(int position, byte value)
{
throw new NotSupportedException();
}
///
public void SetBytes(int position, byte[] source, int offset, int count)
{
throw new NotSupportedException();
}
///
/// Releases unmanaged and - optionally - managed resources.
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected virtual void Dispose(bool disposing)
{
if (disposing && !_disposed)
{
_buffer.Dispose();
}
_disposed = true;
}
private void EnsureValidPosition(int position)
{
if (position < 0 || position > _length)
{
throw new ArgumentOutOfRangeException("position");
}
}
private void EnsureValidPositionAndCount(int position, int count)
{
EnsureValidPosition(position);
if (count < 0 || position + count > _length)
{
throw new ArgumentOutOfRangeException("count");
}
}
private void EnsureValidPositionAndLength(int position, int length)
{
EnsureValidPosition(position);
if (length < 0 || position + length > _length)
{
throw new ArgumentOutOfRangeException("length");
}
}
private void ThrowIfDisposed()
{
if (_disposed)
{
throw new ObjectDisposedException(GetType().Name);
}
}
}
}