Skip to content

Instantly share code, notes, and snippets.

@Virtlink
Created March 17, 2014 02:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Virtlink/9592717 to your computer and use it in GitHub Desktop.
Save Virtlink/9592717 to your computer and use it in GitHub Desktop.
Helper methods for copying data between linear and circular arrays.
using System;
using System.Diagnostics.Contracts;
namespace Virtlink
{
/// <summary>
/// Helper methods for working with circular arrays.
/// </summary>
/// <example>
/// Usage example:
/// <code>
/// byte[] source = new byte[] { 0xAA, 0xBB, 0xCC, 0xDD };
/// byte[] destination = new byte[6];
/// CircularArray.CopyToCircular(source, 0, destination, 4, source.Length);
/// // Result:
/// // { 0xCC, 0xDD, 0x00, 0x00, 0xAA, 0xBB }
/// </code>
/// </example>
/// <remarks>
/// Created by Virtlink. Original source code on GitHub:
/// <see href="https://gist.github.com/Virtlink/9592717"/>.
/// </remarks>
public static class CircularArray
{
/// <summary>
/// Copies data from a linear array to a circular array.
/// </summary>
/// <param name="sourceArray">The linear source array.</param>
/// <param name="sourceIndex">The zero-based offset
/// in <paramref name="sourceArray"/> at which to start reading.</param>
/// <param name="destinationArray">The circular destination array.</param>
/// <param name="destinationIndex">The zero-based offset
/// in <paramref name="destinationArray"/> at which to start writing.</param>
/// <param name="length">The number of elements to copy.</param>
public static void CopyToCircular<T>(
T[] sourceArray,
int sourceIndex,
T[] destinationArray,
int destinationIndex,
int length)
{
#region Contract
Contract.Requires<ArgumentNullException>(sourceArray != null);
Contract.Requires<ArgumentOutOfRangeException>(sourceIndex >= 0);
Contract.Requires<ArgumentOutOfRangeException>(destinationIndex >= 0);
Contract.Requires<ArgumentOutOfRangeException>(sourceIndex + length <= sourceArray.Length);
Contract.Requires<ArgumentOutOfRangeException>(length <= destinationArray.Length);
#endregion
if (length == 0)
return;
// The source is a continuous range.
if (destinationIndex + length <= destinationArray.Length)
{
// The destination is a continuous range.
// |---11111--------| => |-------11111----|
int toCopy = length;
Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, toCopy);
}
else
{
// The destination is split into two ranges.
// |---11122--------| => |22-----------111|
int toCopy = destinationArray.Length - destinationIndex;
Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, toCopy);
Array.Copy(sourceArray, sourceIndex + toCopy, destinationArray, 0, length - toCopy);
}
}
/// <summary>
/// Copies data from a circular array to a linear array.
/// </summary>
/// <param name="sourceArray">The circular source array.</param>
/// <param name="sourceIndex">The zero-based offset
/// in <paramref name="sourceArray"/> at which to start reading.</param>
/// <param name="destinationArray">The linear destination array.</param>
/// <param name="destinationIndex">The zero-based offset
/// in <paramref name="destinationArray"/> at which to start writing.</param>
/// <param name="length">The number of elements to copy.</param>
public static void CopyFromCircular<T>(
T[] sourceArray,
int sourceIndex,
T[] destinationArray,
int destinationIndex,
int length)
{
#region Contract
Contract.Requires<ArgumentNullException>(sourceArray != null);
Contract.Requires<ArgumentOutOfRangeException>(sourceIndex >= 0);
Contract.Requires<ArgumentOutOfRangeException>(destinationIndex >= 0);
Contract.Requires<ArgumentOutOfRangeException>(length < sourceArray.Length);
Contract.Requires<ArgumentOutOfRangeException>(destinationIndex + length <= destinationArray.Length);
#endregion
if (length == 0)
return;
// The destination is a continuous range.
if (sourceIndex + length <= sourceArray.Length)
{
// The source is a continuous range.
// |---11111--------| => |-------11111----|
int toCopy = length;
Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, toCopy);
}
else
{
// The source is split into two ranges.
// |222-----------11| => |-------11222----|
int toCopy = sourceArray.Length - sourceIndex;
Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, toCopy);
Array.Copy(sourceArray, 0, destinationArray, destinationIndex + toCopy, length - toCopy);
}
}
/// <summary>
/// Copies data from one circular array to another circular array.
/// </summary>
/// <param name="sourceArray">The circular source array.</param>
/// <param name="sourceIndex">The zero-based offset
/// in <paramref name="sourceArray"/> at which to start reading.</param>
/// <param name="destinationArray">The circular destination array.</param>
/// <param name="destinationIndex">The zero-based offset
/// in <paramref name="destinationArray"/> at which to start writing.</param>
/// <param name="length">The number of elements to copy.</param>
public static void CopyCircular<T>(
T[] sourceArray,
int sourceIndex,
T[] destinationArray,
int destinationIndex,
int length)
{
#region Contract
Contract.Requires<ArgumentNullException>(sourceArray != null);
Contract.Requires<ArgumentOutOfRangeException>(sourceIndex >= 0);
Contract.Requires<ArgumentOutOfRangeException>(destinationIndex >= 0);
Contract.Requires<ArgumentOutOfRangeException>(length < sourceArray.Length);
Contract.Requires<ArgumentOutOfRangeException>(length < destinationArray.Length);
#endregion
if (length == 0)
return;
if (sourceIndex + length <= sourceArray.Length)
{
// The source is a continuous range.
if (destinationIndex + length <= destinationArray.Length)
{
// The destination is a continuous range.
// |---11111--------| => |-------11111----|
int toCopy = length;
Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, toCopy);
}
else
{
// The destination is split into two ranges.
// |---11122--------| => |22-----------111|
int toCopy = destinationArray.Length - destinationIndex;
Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, toCopy);
Array.Copy(sourceArray, sourceIndex + toCopy, destinationArray, 0, length - toCopy);
}
}
else
{
// The source is split into two ranges.
if (destinationIndex + length <= destinationArray.Length)
{
// The destination is a continuous range.
// |222-----------11| => |-------11222----|
int toCopy = sourceArray.Length - sourceIndex;
Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, toCopy);
Array.Copy(sourceArray, 0, destinationArray, destinationIndex + toCopy, length - toCopy);
}
else
{
// The destination is split into two ranges.
if (sourceArray.Length - sourceIndex < destinationArray.Length - destinationIndex)
{
// |22233---------11| => |33---------11222|
int toCopy1 = sourceArray.Length - sourceIndex;
int toCopy2 = destinationArray.Length - (destinationIndex + toCopy1);
Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, toCopy1);
Array.Copy(sourceArray, 0, destinationArray, destinationIndex + toCopy1, toCopy2);
Array.Copy(sourceArray, 0 + toCopy2, destinationArray, 0, length - toCopy1 - toCopy2);
}
else if (sourceArray.Length - sourceIndex > destinationArray.Length - destinationIndex)
{
// |33---------11222| => |22233---------11|
int toCopy1 = destinationArray.Length - destinationIndex;
int toCopy2 = sourceArray.Length - (sourceIndex + toCopy1);
Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, toCopy1);
Array.Copy(sourceArray, sourceIndex + toCopy1, destinationArray, 0, toCopy2);
Array.Copy(sourceArray, 0, destinationArray, 0 + toCopy2, length - toCopy1 - toCopy2);
}
else
{
// |222---------1111| => |222---------1111|
int toCopy = destinationArray.Length - destinationIndex;
Array.Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, toCopy);
Array.Copy(sourceArray, 0, destinationArray, 0, length - toCopy);
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment