Files
DP44/Common/DTS.Common.Utilities/LargeArray.cs
2026-04-17 14:55:32 -04:00

1383 lines
49 KiB
C#

/*
* LargeArray.cs
*
* Copyright © 2009
* Diversified Technical Systems, Inc.
* All Rights Reserved
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
using DTS.Common.Utilities;
using DTS.Common.Utilities.DotNetProgrammingConstructs;
using DTS.Common.Utilities.Logging;
namespace DTS.Common.Utilities.IO.MemoryMap
{
/// <summary>
/// A generic memory-mapped array.
/// </summary>
///
/// <typeparam name="T">
/// The type of object to be contained in this collection.
/// </typeparam>
///
public abstract partial class LargeArray<T>
: Exceptional,
IDisposable,
ICollection,
IEnumerable,
ICloneable,
IList
where T : struct
{
/// <summary>
/// Initialize an instance of a <see cref="T:LargeArray"/>.
/// </summary>
///
/// <param name="size">
/// The <see cref="ulong"/> size of the collection.
/// </param>
///
public LargeArray(ulong size)
: this(size, null, null)
{
}
/// <summary>
/// Initialize an instance of a <see cref="T:LargeArray"/>.
/// </summary>
///
/// <param name="size">
/// The <see cref="ulong"/> size of the collection.
/// </param>
///
/// <param name="scratchFileDirectory">
/// The <see cref="string"/> name of the directory where this LargeArray will store the temporary
/// serializations of its items. If null, then the default location will be used.
/// </param>
///
/// <param name="scratchFilePrefix">
/// The <see cref="string"/> file name prefix under which this LargeArray will store temporary
/// serializations of its items. Initialized to DefaultFilePrefix's value at object
/// creation, unless an alternate is specified by the user. If null, then the default prefix
/// will be used.
/// </param>
///
public LargeArray(ulong size, string scratchFileDirectory, string scratchFilePrefix)
{
try
{
IsMemoryMapped = false;
Size = size;
ViewSize = 0xFFFF; //50 * 1024; //50 * 1024; // 50 * 1024 * 1024;
ScratchDirectory = scratchFileDirectory ?? DefaultScratchDirectory;
FilePrefix = scratchFilePrefix ?? DefaultFilePrefix;
IsMemoryMapped = CreateScratchFile(size, ScratchDirectory, FilePrefix);
}
catch (System.Exception ex)
{
throw new Exception("encountered problem constructing " + GetType().FullName, ex);
}
}
/// <summary>
/// Finalizer. Can't find anyplace else to put this file removal and have it
/// work, since something in the mapping code is tenaciously holding onto it.
/// </summary>
~LargeArray()
{
//
// Delete our scratch file.
//
File.Delete(FullScratchFilename);
}
/// <summary>
/// A shared <see cref="T:LargeArray.NameGeneratorLock"/> object to be shared by all instances
/// of <see cref="T:LargeArray"/> to ensure that no two try to use the same scratch filename.
/// </summary>
protected static NameGeneratorLock NameLock
{
get
{
try { return _NameLock; }
catch (System.Exception ex)
{
throw new Exception("encountered problem getting name generator lock", ex);
}
}
}
private static readonly NameGeneratorLock _NameLock = new NameGeneratorLock();
/// <summary>
/// Get the next unique <see cref="ulong"/> scratch file number designation.
/// </summary>
protected static ulong NextScratchFileNumberDesignation
{
get
{
try
{
lock (NameLock)
{
return _NextScratchFileNumberDesignation++;
}
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting next scratch file number designation", ex);
}
}
}
private static ulong _NextScratchFileNumberDesignation = 0;
/// <summary>
/// The default <see cref="string"/> name of the directory where MegArrays will store the temporary
/// serializations of their items.
/// </summary>
public static string DefaultScratchDirectory
{
get => _DefaultScratchDirectory.Value;
set => _DefaultScratchDirectory.Value = value;
}
private static readonly Property<string> _DefaultScratchDirectory
= new Property<string>(
typeof(LargeArray<T>).FullName + ".DefaultScratchDirectory",
"C:\\\\Temp\\",
true
);
/// <summary>
/// The <see cref="string"/> name of the directory where this LargeArray will store its temporary
/// serializations of its items. Initialized to DefaultScratchDirectory's value at object
/// creation, unless an alternate is specified by the user.
/// </summary>
public string ScratchDirectory
{
get => _ScratchDirectory.Value;
set => _ScratchDirectory.Value = value;
}
private readonly Property<string> _ScratchDirectory
= new Property<string>(
typeof(LargeArray<T>).FullName + ".ScratchDirectory",
null,
false
);
/// <summary>
/// The default <see cref="string"/> prefix name for MegArrays temporary serializations.
/// </summary>
public static string DefaultFilePrefix
{
get => _DefaultFilePrefix.Value;
set => _DefaultFilePrefix.Value = value;
}
private static readonly Property<string> _DefaultFilePrefix
= new Property<string>(
typeof(LargeArray<T>).FullName + ".DefaultFilePrefix",
"largearray.tmp.",
true
);
/// <summary>
/// The <see cref="string"/> file name prefix under which this LargeArray will store temporary
/// serializations of its items. Initialized to DefaultFilePrefix's value at object
/// creation, unless an alternate is specified by the user.
/// </summary>
public string FilePrefix
{
get => _FilePrefix.Value;
set => _FilePrefix.Value = value;
}
private readonly Property<string> _FilePrefix
= new Property<string>(
typeof(LargeArray<T>).FullName + ".FilePrefix",
null,
false
);
/// <summary>
/// Get the <see cref="string"/> filename that this <see cref="T:LargeArray"/> will be
/// using for its memory-mapped serialization file.
/// </summary>
public string ScratchFilename
{
get
{
try
{
if (null == _ScratchFilename)
_ScratchFilename = GenerateNewScratchFilename();
return _ScratchFilename;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting scratch filename property for " + GetType().FullName, ex);
}
}
}
private string _ScratchFilename = null;
/// <summary>
/// Get the fully qualified <see cref="string"/> filename that this <see cref="T:LargeArray"/>
/// will be using for its memory-mapped serialization file.
/// </summary>
public string FullScratchFilename
{
get
{
try
{
if (null == _FullScratchFilename)
_FullScratchFilename = ScratchDirectory + ScratchFilename;
return _FullScratchFilename;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting fully qualified scratch filename property for " + GetType().FullName, ex);
}
}
}
private string _FullScratchFilename = null;
/// <summary>
/// Generate a new unique <see cref="string"/> filename.
/// </summary>
///
/// <returns>
/// A unique <see cref="string"/> filename.
/// </returns>
///
private string GenerateNewScratchFilename()
{
try
{
return FilePrefix + NextScratchFileNumberDesignation.ToString();
}
catch (System.Exception ex)
{
throw new Exception("encounterd problem generating new scratch filename", ex);
}
}
/// <summary>
/// Get the maximum <see cref="ulong"/> size of this <see cref="T:LargeArray"/>.
/// </summary>
public ulong Size
{
get;
}
/// <summary>
/// Get flag indicating whether or not this <see cref="T:LargeArray"/> is
/// currently associated with a disk file.
/// </summary>
private bool IsMemoryMapped
{
get;
set;
}
/// <summary>
/// Get the <see cref="uint"/> view size used by our memory mapping mechanism.
/// </summary>
protected uint ViewSize
{
get;
}
/// <summary>
/// The <see cref="uint"/> size of the basic datum type stored by this object.
/// </summary>
public abstract uint DatumSize
{
get;
}
/// <summary>
/// The value to be substituted for all array values when "clear" is invoked.
/// </summary>
protected abstract T DatumClearValue
{
get;
}
/// <summary>
/// Create the scratch file that will store this object's items.
/// </summary>
///
/// <param name="size">
/// The <see cref="uint"/> size of the scratch file to be created.
/// </param>
///
/// <param name="directory">
/// The <see cref="string"/> path of the directory to contain the newly-created scratch
/// file. It will be created if it does not already exist.
/// </param>
///
/// <param name="filename">
/// The <see cref="string"/> name of the file to be created.
/// </param>
///
/// <returns>
/// <see cref="bool"/> true if the file has been successfully created, false otherwise.
/// </returns>
///
private bool CreateScratchFile(ulong size, string directory, string filename)
{
try
{
// Make sure we have someplace to put this file.
if (!Directory.Exists(directory))
Directory.CreateDirectory(directory);
// Other files of this name should not exist.
if (File.Exists(filename))
throw new ScratchFileAlreadyExistsException("the scratch file \"" + FullScratchFilename + "\" already exists");
APILogger.Log("writing 35 ", FullScratchFilename);
lock (this)
{
using (var fileWriter = new BinaryWriter(new FileStream(FullScratchFilename, FileMode.Create)))
{
var byteSize = Size * DatumSize;
for (ulong i = 0; i < byteSize; i++)
fileWriter.Write((Byte)0x0);
}
}
return true;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem setting up scratch file for " + GetType().FullName, ex);
}
}
/// <summary>
/// Create a file map view array to associate this object with a file representation.
/// </summary>
///
/// <returns>
/// A <see cref="FileMapViewArray"/> association with with object's data file.
/// </returns>
///
protected FileMapViewArray ViewArray
{
get
{
try
{
if (!IsMemoryMapped)
throw new Exception();
else
{
if (!_ViewArray.IsInitialized)
{
var fileInfo = new FileInfo(FullScratchFilename);
// Make a new mapViewArray for the file with proper offset and
// readonly privilages to protect sample integrity.
_ViewArray.Value = new FileMapViewArray(Path.GetFullPath(FullScratchFilename),
MapAccess.FileMapAllAccess,
MapProtection.PageReadWrite,
0,
(fileInfo.Length),
(int)ViewSize);
}
return _ViewArray.Value;
}
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting view array", ex);
}
}
}
private readonly Property<FileMapViewArray> _ViewArray
= new Property<FileMapViewArray>(
typeof(LargeArray<T>).FullName + ".FileMap",
null,
false
);
/// <summary>
/// Get the datum at the specified index.
/// </summary>
///
/// <param name="index">
/// The <see cref="uint"/> index of the datum sought.
/// </param>
///
/// <returns>
/// The datum of type T at the specified index of the memory mapped file.
/// </returns>
///
protected abstract T GetDatumAtIndex(ulong index);
/// <summary>
/// Set the specified index to the specified datum.
/// </summary>
///
/// <param name="datum">
/// The datum to be inserted at the specified index.
/// </param>
///
/// <param name="index">
/// The <see cref="ulong"/> index of the specified datum's destination.
/// </param>
///
protected abstract void SetDatumAtIndex(T datum, ulong index);
#region IDisposable Interface
// *********************************************************************
// ******************** BEGIN IDisposable Interface ********************
// *********************************************************************
/// <summary>
/// Let go our our resources.
/// </summary>
public void Dispose()
{
try
{
if (IsMemoryMapped)
{
ViewArray.Dispose();
IsMemoryMapped = false;
}
}
catch (System.Exception ex)
{
throw new Exception("encountered problem disposing of resources for " + GetType().FullName, ex);
}
}
// *******************************************************************
// ******************** END IDisposable Interface ********************
// *******************************************************************
#endregion
#region ICollection Interface
// *********************************************************************
// ******************** BEGIN ICollection Interface ********************
// *********************************************************************
/// <summary>
/// Gets the <see cref="int"/> number of elements contained in the <see cref="T:LargeArray"/>.
/// </summary>
///
public int Count
{
get
{
try
{
if (LargeCount > int.MaxValue)
throw new LargeOverflowException("\"large\" ulong-sized count is too big to cast to int-sized version");
else return (int)LargeCount;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting item count for " + GetType().FullName, ex);
}
}
}
/// <summary>
/// Gets a <see cref="bool"/> value indicating whether access to the <see cref="T:LargeArray"/>
/// is synchronized (thread safe). Returns true if access to the <see cref="T:LargeArray"/>
/// is synchronized (thread safe); otherwise, false.
/// </summary>
///
public bool IsSynchronized
{
get
{
try
{
return true;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting synchronization capability for " + GetType().FullName, ex);
}
}
}
/// <summary>
/// Get an object that can be used to synchronize access to the System.Collections.ICollection.
/// </summary>
public object SyncRoot
{
get
{
try
{
return this;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting synchronization object for " + GetType().FullName, ex);
}
}
}
/// <summary>
/// Copies the elements of the <see cref="T:LargeArray"/> to a <see cref="System.Array"/>,
/// starting at a particular <see cref="System.Array"/> index. If the array is too small
/// (we're storing more than max int items) then an exception will be thrown.
/// </summary>
///
/// <param name="array">
/// The one-dimensional <see cref="System.Array"/> that is the destination of the elements
/// copied from System.Collections.ICollection. The <see cref="System.Array"/> must have zero-based
/// indexing.
/// </param>
///
/// <param name="index">
/// The zero-based <see cref="int"/> index inn the array at which copying begins.
/// </param>
///
/// <exception cref="System.ArgumentNullException">
/// The array is null.
/// </exception>
///
/// <exception cref="System.ArgumentOutOfRangeException">
/// The index is less than zero.
/// </exception>
///
/// <exception cref="System.ArgumentException">
/// The array is multidimensional OR...
/// the index is equal to or greater than the length of the array OR...
/// the number of elements in the source System.Collections.ICollection is greater than the available
/// space from index to the end of the destination array.
/// </exception>
///
/// <exception cref="System.ArgumentException">
/// The type of the source System.Collections.ICollection cannot be cast automatically
/// to the type of the destination array.
/// </exception>
///
public void CopyTo(Array array, int index)
{
try
{
if (null == array)
throw new ArgumentNullException("cannot copy to null array reference");
else if (index < 0)
throw new ArgumentOutOfRangeException("cannot copy from negative index (" + index.ToString() + ")");
else if (array.Rank > 1)
throw new ArgumentException("cannot copy to multidimensional array (parameter array rank is " + array.Rank.ToString() + ")");
else if ((ulong)(array.Length - index) < LargeCount)
throw new ArgumentException("target array is too small (" + (array.Length - index).ToString() + " < " + LargeCount.ToString() + ")");
else
{
ulong source_index;
int target_index;
for (source_index = 0, target_index = index;
source_index < LargeCount;
target_index++, source_index++)
{
((object[])array)[target_index] = this[source_index];
}
}
}
catch (ArgumentNullException)
{
throw;
}
catch (ArgumentOutOfRangeException)
{
throw;
}
catch (ArgumentException)
{
throw;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem copying to " + GetType().FullName, ex);
}
}
// *******************************************************************
// ******************** END ICollection Interface ********************
// *******************************************************************
#endregion
#region IEnumerable Interface
// *********************************************************************
// ******************** BEGIN IEnumerable Interface ********************
// *********************************************************************
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
///
/// <returns>
/// An System.Collections.IEnumerator object that can be used to iterate through
/// the collection.
/// </returns>
///
public IEnumerator GetEnumerator()
{
try
{
return new Enumerator(this);
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting iterator for " + GetType().FullName, ex);
}
}
// *******************************************************************
// ******************** END IEnumerable Interface ********************
// *******************************************************************
#endregion
#region IList Interface
// ***************************************************************
// ******************** BEGIN IList Interface ********************
// ***************************************************************
/// <summary>
/// Gets a <see cref="bool"/> value indicating whether the <see cref="T:LargeArray"/> has a fixed size.
/// Returns true if it has a fixed size; otherwise, false.
/// </summary>
public bool IsFixedSize
{
get
{
try
{
return true;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem determining whether " + GetType().FullName + " has fixed size", ex);
}
}
}
/// <summary>
/// Get a <see cref="bool"/> value indicating whether or not this <see cref="T:LargeArray"/>
/// object is read-only. Returns true if it is read-only; false otherwise.
/// </summary>
public bool IsReadOnly
{
get
{
try
{
return false;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem determining read-only-ness of " + GetType().FullName, ex);
}
}
}
/// <summary>
/// Get/set the element at the specified <see cref="int"/> index.
/// </summary>
///
/// <param name="index">
/// The <see cref="int"/> zero-based index of the element to gat or sat.
/// </param>
///
/// <returns>
/// The element at the specified index.
/// </returns>
///
/// <exception cref="System.ArgumentOutOfRangeException">
/// The index is not a valid index in the <see cref="T:LargeArray"/>.
/// </exception>
///
/// <exception cref="System.NotSupportedException">
/// The property is not set and the <see cref="T:LargeArray"/> is read-only.
/// </exception>
///
public virtual object this[int index]
{
get
{
try
{
if (index < 0)
throw new ArgumentOutOfRangeException("cannot access element at negative index (" + index.ToString() + ")");
else return this[(ulong)index];
}
catch (ArgumentOutOfRangeException)
{
throw;
}
catch (NotSupportedException)
{
throw;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting item at index " + index.ToString() + " in " + GetType().FullName, ex);
}
}
set
{
try
{
if (index < 0)
throw new ArgumentOutOfRangeException("cannot access element at negative index (" + index.ToString() + ")");
else if (IsReadOnly)
throw new NotSupportedException("cannot assign value to read-only collection");
else this[(ulong)index] = (T)value;
}
catch (ArgumentOutOfRangeException)
{
throw;
}
catch (NotSupportedException)
{
throw;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem setting item at index " + index.ToString() + " in " + GetType().FullName, ex);
}
}
}
/// <summary>
/// Add an item to the <see cref="T:LargeArray"/>.
/// </summary>
///
/// <param name="value">
/// The <see cref="System.Object"/> to add to the <see cref="T:LargeArray"/>.
/// </param>
///
/// <returns>
/// The <see cref="int"/> position into which the new element was inserted.
/// </returns>
///
/// <exception cref="System.NotSupportedException">
/// The <see cref="T:LargeArray"/> is read-only OR...
/// The <see cref="T:LargeArray"/> has a fixed size.
/// </exception>
///
public int Add(object value)
{
try
{
throw new NotSupportedException("operation is not supported for read-only objects");
}
catch (NotSupportedException ex)
{
throw ex;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem adding item to " + GetType().FullName, ex);
}
}
/// <summary>
/// Remove all items from the <see cref="T:LargeArray"/>.
/// </summary>
///
/// <exception cref="System.NotSupportedException">
/// The <see cref="T:LargeArray"/> is read-only.
/// </exception>
///
public void Clear()
{
try
{
// TODO: Add some status notification to this thing.
for (ulong i = 0; i < LargeCount; i++)
this[i] = DatumClearValue;
}
catch (NotSupportedException)
{
throw;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem clearing " + GetType().FullName, ex);
}
}
/// <summary>
/// Determines whether the <see cref="T:LargeArray"/> contains a specific value.
/// </summary>
///
/// <param name="value">
/// The <see cref="System.Object"/> to locate in the <see cref="T:LargeArray"/>.
/// </param>
///
/// <returns>
/// <see cref="bool"/> true if the <see cref="System.Object"/> is found in the <see cref="T:LargeArray"/>;
/// false otherwise.
/// </returns>
///
public bool Contains(object value)
{
try
{
var itemFound = false;
for (ulong i = 0; i < LargeCount && !itemFound; i++)
if (this[i].Equals(value))
itemFound = true;
return itemFound;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem determining whether " + GetType().FullName + " contains the value: " + value.ToString(), ex);
}
}
/// <summary>
/// Determine the index of a specific item in the <see cref="T:LargeArray"/>.
/// </summary>
///
/// <param name="value">
/// The <see cref="System.Object"/> to be located in the <see cref="T:LargeArray"/>.
/// </param>
///
/// <returns>
/// the <see cref="int"/> index value if found in the list; -1 otherwise.
/// </returns>
///
public int IndexOf(object value)
{
try
{
var index = -1;
var largeIndex = LargeIndexOf(value);
if (null == largeIndex)
index = -1;
else if (largeIndex > int.MaxValue)
throw new LargeOverflowException("index of object is to large to be represented by an int (" + largeIndex.ToString() + ")");
else index = (int)largeIndex;
return index;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem determining the index of object \"" + value.ToString() + "\" in " + GetType().FullName, ex);
}
}
/// <summary>
/// Insert an item into the <see cref="T:LargeArray"/> at the specified index.
/// </summary>
///
/// <param name="index">
/// The zero-based <see cref="int"/> index at which the value should be inserted.
/// </param>
///
/// <param name="value">
/// The <see cref="System.Object"/> to insert into the <see cref="T:LargeArray"/>.
/// </param>
///
/// <exception cref="System.ArgumentOutOfRangeException">
/// The index is not a valid index in the <see cref="T:LargeArray"/>
/// </exception>
///
/// <exception cref="System.NotSupportedException">
/// The <see cref="T:LargeArray"/> is read-only OR...
/// The <see cref="T:LargeArray"/> has a fixed size.
/// </exception>
///
public void Insert(int index, object value)
{
try
{
throw new NotSupportedException("operation is not supported for read-only objects");
}
catch (ArgumentOutOfRangeException)
{
throw;
}
catch (NotSupportedException)
{
throw;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem inserting item \"" + value.ToString() + "\" into " + GetType().FullName + " at index " + index.ToString(), ex);
}
}
/// <summary>
/// Remove the first occurance of a specific object from the <see cref="T:LargeArray"/>.
/// </summary>
///
/// <param name="value">
/// The <see cref="System.Object"/> to be removed from the <see cref="T:LargeArray"/>
/// </param>
///
/// <exception cref="System.NotSupportedException">
/// The <see cref="T:LargeArray"/> is read-only OR...
/// the <see cref="T:LargeArray"/> has a fixed size.
/// </exception>
///
public void Remove(object value)
{
try
{
throw new NotSupportedException("operation is not supported for read-only objects");
}
catch (NotSupportedException ex)
{
throw new Exception("encountered problme removing first occurance of object " + value.ToString() + " from " + GetType().FullName, ex);
}
}
/// <summary>
/// Remove the <see cref="T:LargeArray"/> item at the specified index.
/// </summary>
///
/// <param name="index">
/// The zero-based <see cref="int"/> index of the item to remove.
/// </param>
///
/// <exception cref="System.ArgumentOutOfRangeException">
/// The index is not a valid index in the <see cref="T:LargeArray"/>.
/// </exception>
///
/// <exception cref="System.NotSupportedException">
/// The <see cref="T:LargeArray"/> is read-only OR...
/// the <see cref="T:LargeArray"/> has a fixed size.
/// </exception>
///
public void RemoveAt(int index)
{
try
{
throw new NotSupportedException("operation is not supported for read-only objects");
}
catch (NotSupportedException)
{
throw;
}
catch (ArgumentOutOfRangeException)
{
throw;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem removing the " + GetType().FullName + " item at index " + index.ToString(), ex);
}
}
// *************************************************************
// ******************** END IList Interface ********************
// *************************************************************
#endregion
#region "Large" ICollection Interface
// *****************************************************************************
// ******************** BEGIN "Large" ICollection Interface ********************
// *****************************************************************************
/// <summary>
/// Gets the <see cref="ulong"/> number of elements contained in the <see cref="T:LargeArray"/>.
/// </summary>
///
public ulong LargeCount
{
get
{
try
{
return Size;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting item count for " + GetType().FullName, ex);
}
}
}
/// <summary>
/// Copies the elements of the <see cref="T:LargeArray"/> to a <see cref="System.Array"/>,
/// starting at a particular <see cref="System.Array"/> index. If the array is too small
/// (we're storing more than max int items) then an exception will be thrown.
/// </summary>
///
/// <param name="array">
/// The one-dimensional <see cref="System.Array"/> that is the destination of the elements
/// copied from System.Collections.ICollection. The <see cref="System.Array"/> must have zero-based
/// indexing.
/// </param>
///
/// <param name="index">
/// The zero-based <see cref="ulong"/> index inn the array at which copying begins.
/// </param>
///
/// <exception cref="System.ArgumentNullException">
/// The array is null.
/// </exception>
///
/// <exception cref="System.ArgumentException">
/// The array is multidimensional OR...
/// the index is equal to or greater than the length of the array OR...
/// the number of elements i nthe source System.Collections.ICollection is greater than the available
/// space from index to the end of the destination array.
/// </exception>
///
/// <exception cref="System.ArgumentException">
/// The type of the source System.Collections.ICollection cannot be cast automatically
/// to the type of the destination array.
/// </exception>
///
public void LargeCopyTo(Array array, ulong index)
{
try
{
if (null == array)
throw new ArgumentNullException("cannot copy to null array reference");
else if (index < 0)
throw new ArgumentOutOfRangeException("cannot copy from negative index (" + index.ToString() + ")");
else if (array.Rank > 1)
throw new ArgumentException("cannot copy to multidimensional array (parameter array rank is " + array.Rank.ToString() + ")");
else if (((ulong)(array.Length) - index) < LargeCount)
throw new ArgumentException("target array is too small (" + ((ulong)(array.Length) - index).ToString() + " < " + LargeCount.ToString() + ")");
else
{
ulong source_index;
ulong target_index;
for (source_index = 0, target_index = index;
source_index < LargeCount;
target_index++, source_index++)
{
((object[])array)[target_index] = this[source_index];
}
}
}
catch (ArgumentNullException)
{
throw;
}
catch (ArgumentOutOfRangeException)
{
throw;
}
catch (ArgumentException)
{
throw;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem copying to " + GetType().FullName, ex);
}
}
// ***************************************************************************
// ******************** END "Large" ICollection Interface ********************
// ***************************************************************************
#endregion
#region "Large" IList Interface
// ***********************************************************************
// ******************** BEGIN "Large" IList Interface ********************
// ***********************************************************************
/// <summary>
/// Get/set the element at the specified <see cref="int"/> index.
/// </summary>
///
/// <param name="index">
/// The <see cref="ulong"/> zero-based index of the element to gat or sat.
/// </param>
///
/// <returns>
/// The element at the specified index.
/// </returns>
///
/// <exception cref="System.ArgumentOutOfRangeException">
/// The index is not a valid index in the <see cref="T:LargeArray"/>.
/// </exception>
///
/// <exception cref="System.NotSupportedException">
/// The property is not set and the <see cref="T:LargeArray"/> is read-only.
/// </exception>
///
public T this[ulong index]
{
get
{
try
{
return GetDatumAtIndex(index);
}
catch (ArgumentOutOfRangeException)
{
throw;
}
catch (NotSupportedException)
{
throw;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem getting item at index " + index.ToString() + " in " + GetType().FullName, ex);
}
}
set
{
try
{
SetDatumAtIndex(value, index);
}
catch (ArgumentOutOfRangeException)
{
throw;
}
catch (NotSupportedException)
{
throw;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem setting item at index " + index.ToString() + " in " + GetType().FullName, ex);
}
}
}
/// <summary>
/// Add an item to the <see cref="T:LargeArray"/>.
/// </summary>
///
/// <param name="value">
/// The <see cref="System.Object"/> to add to the <see cref="T:LargeArray"/>.
/// </param>
///
/// <returns>
/// The <see cref="ulong"/> position into which the new element was inserted.
/// </returns>
///
/// <exception cref="System.NotSupportedException">
/// The <see cref="T:LargeArray"/> is read-only OR...
/// The <see cref="T:LargeArray"/> has a fixed size.
/// </exception>
///
public ulong LargeAdd(object value)
{
try
{
throw new NotSupportedException("operation is not supported for read-only objects");
}
catch (NotSupportedException ex)
{
throw ex;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem adding item to " + GetType().FullName, ex);
}
}
/// <summary>
/// Determine the index of a specific item in the <see cref="T:LargeArray"/>.
/// </summary>
///
/// <param name="value">
/// The <see cref="System.Object"/> to be located in the <see cref="T:LargeArray"/>.
/// </param>
///
/// <returns>
/// the <see cref="ulong"/> index value if found in the list; null otherwise.
/// </returns>
///
public ulong? LargeIndexOf(object value)
{
try
{
ulong? objectIndex = null;
for (ulong i = 0; i < LargeCount && null == objectIndex; i++)
if (this[i].Equals(value))
objectIndex = i;
return objectIndex;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem determining the index of object \"" + value.ToString() + "\" in " + GetType().FullName, ex);
}
}
/// <summary>
/// Insert an item into the <see cref="T:LargeArray"/> at the specified index.
/// </summary>
///
/// <param name="index">
/// The zero-based <see cref="ulong"/> index at which the value should be inserted.
/// </param>
///
/// <param name="value">
/// The <see cref="System.Object"/> to insert into the <see cref="T:LargeArray"/>.
/// </param>
///
/// <exception cref="System.ArgumentOutOfRangeException">
/// The index is not a valid index in the <see cref="T:LargeArray"/>
/// </exception>
///
/// <exception cref="System.NotSupportedException">
/// The <see cref="T:LargeArray"/> is read-only OR...
/// The <see cref="T:LargeArray"/> has a fixed size.
/// </exception>
///
public void LargeInsert(ulong index, object value)
{
try
{
throw new NotSupportedException("operation is not supported for read-only objects");
}
catch (ArgumentOutOfRangeException ex)
{
throw ex;
}
catch (NotSupportedException ex)
{
throw ex;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem inserting item \"" + value.ToString() + "\" into " + GetType().FullName + " at index " + index.ToString(), ex);
}
}
/// <summary>
/// Remove the <see cref="T:LargeArray"/> item at the specified index.
/// </summary>
///
/// <param name="index">
/// The zero-based <see cref="ulong"/> index of the item to remove.
/// </param>
///
/// <exception cref="System.ArgumentOutOfRangeException">
/// The index is not a valid index in the <see cref="T:LargeArray"/>.
/// </exception>
///
/// <exception cref="System.NotSupportedException">
/// The <see cref="T:LargeArray"/> is read-only OR...
/// the <see cref="T:LargeArray"/> has a fixed size.
/// </exception>
///
public void LargeRemoveAt(ulong index)
{
try
{
throw new NotSupportedException("operation is not supported for read-only objects");
}
catch (NotSupportedException)
{
throw;
}
catch (ArgumentOutOfRangeException)
{
throw;
}
catch (System.Exception ex)
{
throw new Exception("encountered problem removing the " + GetType().FullName + " item at index " + index.ToString(), ex);
}
}
// *********************************************************************
// ******************** END "Large" IList Interface ********************
// *********************************************************************
#endregion
#region ICloneable Interface
// ********************************************************************
// ******************** BEGIN ICloneable Interface ********************
// ********************************************************************
/// <summary>
/// create a new object that is a copy of the current instance
/// </summary>
/// <returns>a new object of the same type with all objects duplicated or referenced</returns>
public abstract object Clone();
// ******************************************************************
// ******************** END ICloneable Interface ********************
// ******************************************************************
#endregion
}
}