//******************************************************************************************************
// FileBackedHashSet.cs - Gbtc
//
// Copyright © 2014, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), 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.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 12/02/2014 - Stephen C. Wills
// Generated original version of source code.
//
//******************************************************************************************************
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace GSF.Collections
{
///
/// Represents a lookup table backed by a file, with very little memory overhead.
///
/// The type of the items in the lookup table.
public class FileBackedHashSet : ISet, IDisposable
{
#region [ Members ]
// Fields
private FileBackedLookupTable m_lookupTable;
#endregion
#region [ Constructors ]
///
/// Creates a new instance of the class.
///
/// cannot be serialized.
public FileBackedHashSet()
: this(Path.GetTempFileName(), EqualityComparer.Default)
{
}
///
/// Creates a new instance of the class.
///
/// The path to the file used to store the lookup table.
/// is a zero-length string, contains only white space, or contains one or more invalid characters as defined by .
/// is null.
/// cannot be serialized.
public FileBackedHashSet(string filePath)
: this(filePath, EqualityComparer.Default)
{
}
///
/// Creates a new instance of the class.
///
/// The equality comparer used to compare items in the hash set.
/// cannot be serialized.
public FileBackedHashSet(IEqualityComparer comparer)
: this(Path.GetTempFileName(), comparer)
{
}
///
/// Creates a new instance of the class.
///
/// The enumerable whose elements are copied to this hash set.
/// is null.
/// cannot be serialized.
public FileBackedHashSet(IEnumerable enumerable)
: this(Path.GetTempFileName(), enumerable, EqualityComparer.Default)
{
}
///
/// Creates a new instance of the class.
///
/// The path to the file used to store the lookup table.
/// The equality comparer used to compare items in the hash set.
/// is a zero-length string, contains only white space, or contains one or more invalid characters as defined by .
/// is null.
/// cannot be serialized.
public FileBackedHashSet(string filePath, IEqualityComparer comparer)
{
m_lookupTable = new FileBackedLookupTable(LookupTableType.HashSet, filePath, comparer);
}
///
/// Creates a new instance of the class.
///
/// The path to the file used to store the lookup table.
/// The enumerable whose elements are copied to this hash set.
/// is a zero-length string, contains only white space, or contains one or more invalid characters as defined by .
/// is null or is null.
/// cannot be serialized.
public FileBackedHashSet(string filePath, IEnumerable enumerable)
: this(filePath, enumerable, EqualityComparer.Default)
{
}
///
/// Creates a new instance of the class.
///
/// The enumerable whose elements are copied to this hash set.
/// The equality comparer used to compare items in the hash set.
/// is null.
/// cannot be serialized.
public FileBackedHashSet(IEnumerable enumerable, IEqualityComparer comparer)
: this(Path.GetTempFileName(), enumerable, comparer)
{
}
///
/// Creates a new instance of the class.
///
/// The path to the file used to store the lookup table.
/// The enumerable whose elements are copied to this hash set.
/// The equality comparer used to compare items in the hash set.
/// is a zero-length string, contains only white space, or contains one or more invalid characters as defined by .
/// is null or is null.
/// cannot be serialized.
public FileBackedHashSet(string filePath, IEnumerable enumerable, IEqualityComparer comparer)
{
m_lookupTable = new FileBackedLookupTable(LookupTableType.HashSet, filePath, comparer);
foreach (T item in enumerable)
Add(item);
}
#endregion
#region [ Properties ]
///
/// Gets or sets the path to the file backing this hash set.
///
/// FilePath is set and is a zero-length string, contains only white space, or contains one or more invalid characters as defined by .
///
/// Changes to this property will cause the file to close if the file is already opened.
/// Data will not be automatically written from the old file to the new file.
///
public string FilePath
{
get
{
return m_lookupTable.FilePath;
}
set
{
m_lookupTable.FilePath = value;
}
}
///
/// Gets the number of elements contained in the .
///
///
/// The number of elements contained in the .
///
public int Count
{
get
{
return m_lookupTable.Count;
}
}
///
/// Gets a value indicating whether the is read-only.
///
///
/// true if the is read-only; otherwise, false.
///
public bool IsReadOnly
{
get
{
return m_lookupTable.IsReadOnly;
}
}
///
/// Gets the default signature used by the
/// if no user-defined signature is supplied.
///
public byte[] DefaultSignature
{
get
{
return new Guid(FileBackedLookupTable.HashSetSignature).ToRfcBytes();
}
}
///
/// Gets or sets the signature of the file backing the lookup table.
///
/// Attempt is made to set Signature to a null value.
/// Attempt is made to set Signature to a value larger than the maximum allowed size.
/// Attempt is made to modify Signature of a read-only lookup table.
public byte[] Signature
{
get
{
return m_lookupTable.Signature;
}
set
{
m_lookupTable.Signature = value;
}
}
///
/// Gets or sets the size of the cache used
/// to store data from the file in memory.
///
public long CacheSize
{
get
{
return m_lookupTable.CacheSize;
}
set
{
m_lookupTable.CacheSize = value;
}
}
///
/// Gets the number of operations that fragment the
/// lookup table that have occurred since the last
/// time the lookup table was compacted.
///
///
/// This value is not stored in the file and may therefore
/// be inaccurate if the lookup table has not been compacted
/// since the last time it was opened.
///
public int FragmentationCount
{
get
{
return m_lookupTable.FragmentationCount;
}
}
#endregion
#region [ Methods ]
///
/// Opens the file backing this hash set.
///
/// File is already open.
public void Open()
{
m_lookupTable.Open();
}
///
/// Adds an element to the current set and returns a value to indicate if the element was successfully added.
///
/// The element to add to the set.
///
/// true if the element is added to the set; false if the element is already in the set.
///
public bool Add(T item)
{
return m_lookupTable.TryAdd(item, null);
}
///
/// Removes the first occurrence of a specific object from the .
///
/// The object to remove from the .
///
/// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original .
///
/// The is read-only.
public bool Remove(T item)
{
return m_lookupTable.Remove(item);
}
///
/// Removes all elements that match the conditions defined by the specified predicate from a collection.
///
/// The delegate that defines the conditions of the elements to remove.
/// The number of elements that were removed from the collection.
/// match is null
/// The is read-only.
public int RemoveWhere(Predicate match)
{
int removedCount;
if ((object)match == null)
throw new ArgumentNullException("match");
removedCount = 0;
m_lookupTable.UnmarkAll();
foreach (T item in this)
{
if (match(item))
{
m_lookupTable.TryMark(item);
removedCount++;
}
}
m_lookupTable.RemoveMarked();
return removedCount;
}
///
/// Determines whether the contains a specific value.
///
/// The object to locate in the .
///
/// true if is found in the ; otherwise, false.
///
public bool Contains(T item)
{
return m_lookupTable.ContainsKey(item);
}
///
/// Modifies the current set so that it contains all elements that are present in either the current set or the specified collection.
///
/// The collection to compare to the current set.
/// is null.
/// The is read-only.
public void UnionWith(IEnumerable other)
{
if ((object)other == null)
throw new ArgumentNullException("other");
foreach (T item in other)
Add(item);
}
///
/// Modifies the current set so that it contains only elements that are also in a specified collection.
///
/// The collection to compare to the current set.
/// is null.
/// The is read-only.
public void IntersectWith(IEnumerable other)
{
if ((object)other == null)
throw new ArgumentNullException("other");
m_lookupTable.UnmarkAll();
foreach (T item in other)
m_lookupTable.TryMark(item);
m_lookupTable.RemoveUnmarked();
}
///
/// Removes all elements in the specified collection from the current set.
///
/// The collection of items to remove from the set.
/// is null.
/// The is read-only.
public void ExceptWith(IEnumerable other)
{
if ((object)other == null)
throw new ArgumentNullException("other");
foreach (T item in other)
m_lookupTable.Remove(item);
}
///
/// Modifies the current set so that it contains only elements that are present
/// either in the current set or in the specified collection, but not both.
///
/// The collection to compare to the current set.
/// is null.
/// The is read-only.
public void SymmetricExceptWith(IEnumerable other)
{
List list;
if ((object)other == null)
throw new ArgumentNullException("other");
list = new List();
m_lookupTable.UnmarkAll();
foreach (T item in other)
{
if (!m_lookupTable.TryMark(item))
list.Add(item);
}
m_lookupTable.RemoveMarked();
foreach (T item in list)
Add(item);
}
///
/// Determines whether a set is a subset of a specified collection.
///
/// The collection to compare to the current set.
///
/// true if the current set is a subset of ; otherwise, false.
///
/// is null.
/// The is read-only.
public bool IsSubsetOf(IEnumerable other)
{
if ((object)other == null)
throw new ArgumentNullException("other");
m_lookupTable.UnmarkAll();
foreach (T item in other)
m_lookupTable.TryMark(item);
return m_lookupTable.AllMarked();
}
///
/// Determines whether the current set is a superset of a specified collection.
///
/// The collection to compare to the current set.
///
/// true if the current set is a superset of ; otherwise, false.
///
/// is null.
public bool IsSupersetOf(IEnumerable other)
{
if ((object)other == null)
throw new ArgumentNullException("other");
foreach (T item in other)
{
if (!Contains(item))
return false;
}
return true;
}
///
/// Determines whether the current set is a proper (strict) superset of a specified collection.
///
/// The collection to compare to the current set.
///
/// true if the current set is a proper superset of ; otherwise, false.
///
/// is null.
/// The is read-only.
public bool IsProperSupersetOf(IEnumerable other)
{
if ((object)other == null)
throw new ArgumentNullException("other");
m_lookupTable.UnmarkAll();
foreach (T item in other)
{
if (!m_lookupTable.TryMark(item))
return false;
}
return !m_lookupTable.AllMarked();
}
///
/// Determines whether the current set is a proper (strict) subset of a specified collection.
///
/// The collection to compare to the current set.
///
/// true if the current set is a proper subset of ; otherwise, false.
///
/// is null.
/// The is read-only.
public bool IsProperSubsetOf(IEnumerable other)
{
bool canBeProperSubset;
if ((object)other == null)
throw new ArgumentNullException("other");
canBeProperSubset = false;
m_lookupTable.UnmarkAll();
foreach (T item in other)
{
if (!m_lookupTable.TryMark(item))
canBeProperSubset = true;
}
return canBeProperSubset && m_lookupTable.AllMarked();
}
///
/// Determines whether the current set overlaps with the specified collection.
///
/// The collection to compare to the current set.
///
/// true if the current set and share at least one common element; otherwise, false.
///
/// is null.
public bool Overlaps(IEnumerable other)
{
if ((object)other == null)
throw new ArgumentNullException("other");
foreach (T item in other)
{
if (Contains(item))
return true;
}
return false;
}
///
/// Determines whether the current set and the specified collection contain the same elements.
///
/// The collection to compare to the current set.
///
/// true if the current set is equal to ; otherwise, false.
///
/// is null.
/// The is read-only.
public bool SetEquals(IEnumerable other)
{
if ((object)other == null)
throw new ArgumentNullException("other");
m_lookupTable.UnmarkAll();
foreach (T item in other)
{
if (!m_lookupTable.TryMark(item))
return false;
}
return m_lookupTable.AllMarked();
}
///
/// Removes all items from the .
///
/// The is read-only.
public void Clear()
{
m_lookupTable.Clear();
}
///
/// Copies the elements of the to an , starting at a particular index.
///
/// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing.
/// The zero-based index in at which copying begins.
/// is null.
/// is less than 0.
/// The number of elements in the source is greater than the available space from to the end of the destination .
public void CopyTo(T[] array, int arrayIndex)
{
if ((object)array == null)
throw new ArgumentNullException("array");
if (arrayIndex < 0)
throw new ArgumentOutOfRangeException("arrayIndex");
if (m_lookupTable.Count > array.Length - arrayIndex)
throw new ArgumentException("Not enough available space in array to copy elements from hash set");
foreach (T item in this)
array[arrayIndex++] = item;
}
///
/// Returns an enumerator that iterates through the collection.
///
///
/// A that can be used to iterate through the collection.
///
/// 1
public IEnumerator GetEnumerator()
{
return m_lookupTable.GetKeys().GetEnumerator();
}
///
/// Defragments the item section of the hash set,
/// which gets fragmented after removing items.
///
public void Compact()
{
m_lookupTable.Compact();
}
///
/// Closes the file backing this hash set.
///
public void Close()
{
m_lookupTable.Close();
}
///
/// Releases all the resources used by the object.
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected virtual void Dispose(bool disposing)
{
if (disposing)
Close();
}
///
/// Adds an item to the .
///
/// The object to add to the .
/// The is read-only.
void ICollection.Add(T item)
{
Add(item);
}
///
/// Returns an enumerator that iterates through a collection.
///
///
/// An object that can be used to iterate through the collection.
///
/// 2
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
}