using System.Diagnostics;
using System.Text;
namespace B24SiemensPlugin.TCP
{
///
/// Dynamic byte buffer
///
public class Buffer
{
private byte[] _data;
private long _size;
private long _offset;
///
/// Is the buffer empty?
///
public bool IsEmpty => (_data == null) || (_size == 0);
///
/// Bytes memory buffer
///
public byte[] Data => _data;
///
/// Bytes memory buffer capacity
///
public long Capacity => _data.Length;
///
/// Bytes memory buffer size
///
public long Size => _size;
///
/// Bytes memory buffer offset
///
public long Offset => _offset;
///
/// Buffer indexer operator
///
public byte this[int index] => _data[index];
///
/// Initialize a new expandable buffer with zero capacity
///
public Buffer() { _data = new byte[0]; _size = 0; _offset = 0; }
///
/// Initialize a new expandable buffer with the given capacity
///
public Buffer(long capacity) { _data = new byte[capacity]; _size = 0; _offset = 0; }
///
/// Initialize a new expandable buffer with the given data
///
public Buffer(byte[] data) { _data = data; _size = data.Length; _offset = 0; }
#region Memory buffer methods
///
/// Get string from the current buffer
///
public override string ToString()
{
return ExtractString(0, _size);
}
// Clear the current buffer and its offset
public void Clear()
{
_size = 0;
_offset = 0;
}
///
/// Extract the string from buffer of the given offset and size
///
public string ExtractString(long offset, long size)
{
Debug.Assert(((offset + size) <= Size), "Invalid offset & size!");
if ((offset + size) > Size)
throw new ArgumentException("Invalid offset & size!", nameof(offset));
return Encoding.UTF8.GetString(_data, (int)offset, (int)size);
}
///
/// Remove the buffer of the given offset and size
///
public void Remove(long offset, long size)
{
Debug.Assert(((offset + size) <= Size), "Invalid offset & size!");
if ((offset + size) > Size)
throw new ArgumentException("Invalid offset & size!", nameof(offset));
Array.Copy(_data, offset + size, _data, offset, _size - size - offset);
_size -= size;
if (_offset >= (offset + size))
_offset -= size;
else if (_offset >= offset)
{
_offset -= _offset - offset;
if (_offset > Size)
_offset = Size;
}
}
///
/// Reserve the buffer of the given capacity
///
public void Reserve(long capacity)
{
Debug.Assert((capacity >= 0), "Invalid reserve capacity!");
if (capacity < 0)
throw new ArgumentException("Invalid reserve capacity!", nameof(capacity));
if (capacity > Capacity)
{
byte[] data = new byte[Math.Max(capacity, 2 * Capacity)];
Array.Copy(_data, 0, data, 0, _size);
_data = data;
}
}
// Resize the current buffer
public void Resize(long size)
{
Reserve(size);
_size = size;
if (_offset > _size)
_offset = _size;
}
// Shift the current buffer offset
public void Shift(long offset) { _offset += offset; }
// Unshift the current buffer offset
public void Unshift(long offset) { _offset -= offset; }
#endregion
#region Buffer I/O methods
///
/// Append the given buffer
///
/// Buffer to append
/// Count of append bytes
public long Append(byte[] buffer)
{
Reserve(_size + buffer.Length);
Array.Copy(buffer, 0, _data, _size, buffer.Length);
_size += buffer.Length;
return buffer.Length;
}
///
/// Append the given buffer fragment
///
/// Buffer to append
/// Buffer offset
/// Buffer size
/// Count of append bytes
public long Append(byte[] buffer, long offset, long size)
{
Reserve(_size + size);
Array.Copy(buffer, offset, _data, _size, size);
_size += size;
return size;
}
///
/// Append the given text in UTF-8 encoding
///
/// Text to append
/// Count of append bytes
public long Append(string text)
{
Reserve(_size + Encoding.UTF8.GetMaxByteCount(text.Length));
long result = Encoding.UTF8.GetBytes(text, 0, text.Length, _data, (int)_size);
_size += result;
return result;
}
#endregion
}
}