1383 lines
49 KiB
C#
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
|
|
}
|
|
} |