mirror of
https://github.com/SubtitleEdit/subtitleedit.git
synced 2024-11-25 20:52:44 +01:00
Use native HashSet
This commit is contained in:
parent
1736453b2f
commit
3d87dc4bef
@ -1,786 +0,0 @@
|
|||||||
//
|
|
||||||
// HashSet.cs
|
|
||||||
//
|
|
||||||
// Authors:
|
|
||||||
// Jb Evain <jbevain@novell.com>
|
|
||||||
//
|
|
||||||
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
// a copy of this software and associated documentation files (the
|
|
||||||
// "Software"), to deal in the Software without restriction, including
|
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
// permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
// the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be
|
|
||||||
// included in all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.Serialization;
|
|
||||||
using System.Security;
|
|
||||||
using System.Security.Permissions;
|
|
||||||
|
|
||||||
// HashSet is basically implemented as a reduction of Dictionary<K, V>
|
|
||||||
|
|
||||||
namespace Nikse.SubtitleEdit.Logic
|
|
||||||
{
|
|
||||||
|
|
||||||
[Serializable, HostProtection (SecurityAction.LinkDemand, MayLeakOnAbort = true)]
|
|
||||||
[DebuggerDisplay ("Count={Count}")]
|
|
||||||
public sealed class HashSet<T> : ICollection<T>, ISerializable, IDeserializationCallback
|
|
||||||
#if NET_4_0 || MOONLIGHT || MOBILE
|
|
||||||
, ISet<T>
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
const int INITIAL_SIZE = 10;
|
|
||||||
const float DEFAULT_LOAD_FACTOR = (90f / 100);
|
|
||||||
const int NO_SLOT = -1;
|
|
||||||
const int HASH_FLAG = -2147483648;
|
|
||||||
|
|
||||||
struct Link {
|
|
||||||
public int HashCode;
|
|
||||||
public int Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The hash table contains indices into the "links" array
|
|
||||||
int [] table;
|
|
||||||
|
|
||||||
Link [] links;
|
|
||||||
T [] slots;
|
|
||||||
|
|
||||||
// The number of slots in "links" and "slots" that
|
|
||||||
// are in use (i.e. filled with data) or have been used and marked as
|
|
||||||
// "empty" later on.
|
|
||||||
int touched;
|
|
||||||
|
|
||||||
// The index of the first slot in the "empty slots chain".
|
|
||||||
// "Remove ()" prepends the cleared slots to the empty chain.
|
|
||||||
// "Add ()" fills the first slot in the empty slots chain with the
|
|
||||||
// added item (or increases "touched" if the chain itself is empty).
|
|
||||||
int empty_slot;
|
|
||||||
|
|
||||||
// The number of items in this set.
|
|
||||||
int count;
|
|
||||||
|
|
||||||
// The number of items the set can hold without
|
|
||||||
// resizing the hash table and the slots arrays.
|
|
||||||
int threshold;
|
|
||||||
|
|
||||||
IEqualityComparer<T> comparer;
|
|
||||||
SerializationInfo si;
|
|
||||||
|
|
||||||
// The number of changes made to this set. Used by enumerators
|
|
||||||
// to detect changes and invalidate themselves.
|
|
||||||
int generation;
|
|
||||||
|
|
||||||
public int Count {
|
|
||||||
get { return count; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashSet ()
|
|
||||||
{
|
|
||||||
Init (INITIAL_SIZE, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashSet (IEqualityComparer<T> comparer)
|
|
||||||
{
|
|
||||||
Init (INITIAL_SIZE, comparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashSet (IEnumerable<T> collection) : this (collection, null)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashSet (IEnumerable<T> collection, IEqualityComparer<T> comparer)
|
|
||||||
{
|
|
||||||
if (collection == null)
|
|
||||||
throw new ArgumentNullException ("collection");
|
|
||||||
|
|
||||||
int capacity = 0;
|
|
||||||
var col = collection as ICollection<T>;
|
|
||||||
if (col != null)
|
|
||||||
capacity = col.Count;
|
|
||||||
|
|
||||||
Init (capacity, comparer);
|
|
||||||
foreach (var item in collection)
|
|
||||||
Add (item);
|
|
||||||
}
|
|
||||||
|
|
||||||
private HashSet (SerializationInfo info, StreamingContext context)
|
|
||||||
{
|
|
||||||
si = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Init (int capacity, IEqualityComparer<T> comparer)
|
|
||||||
{
|
|
||||||
if (capacity < 0)
|
|
||||||
throw new ArgumentOutOfRangeException ("capacity");
|
|
||||||
|
|
||||||
this.comparer = comparer ?? EqualityComparer<T>.Default;
|
|
||||||
if (capacity == 0)
|
|
||||||
capacity = INITIAL_SIZE;
|
|
||||||
|
|
||||||
/* Modify capacity so 'capacity' elements can be added without resizing */
|
|
||||||
capacity = (int) (capacity / DEFAULT_LOAD_FACTOR) + 1;
|
|
||||||
|
|
||||||
InitArrays (capacity);
|
|
||||||
generation = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitArrays (int size)
|
|
||||||
{
|
|
||||||
table = new int [size];
|
|
||||||
|
|
||||||
links = new Link [size];
|
|
||||||
empty_slot = NO_SLOT;
|
|
||||||
|
|
||||||
slots = new T [size];
|
|
||||||
touched = 0;
|
|
||||||
|
|
||||||
threshold = (int) (table.Length * DEFAULT_LOAD_FACTOR);
|
|
||||||
if (threshold == 0 && table.Length > 0)
|
|
||||||
threshold = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SlotsContainsAt (int index, int hash, T item)
|
|
||||||
{
|
|
||||||
int current = table [index] - 1;
|
|
||||||
while (current != NO_SLOT) {
|
|
||||||
Link link = links [current];
|
|
||||||
if (link.HashCode == hash && ((hash == HASH_FLAG && (item == null || null == slots [current])) ? (item == null && null == slots [current]) : comparer.Equals (item, slots [current])))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
current = link.Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo (T [] array)
|
|
||||||
{
|
|
||||||
CopyTo (array, 0, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo (T [] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
CopyTo (array, arrayIndex, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo (T [] array, int arrayIndex, int count)
|
|
||||||
{
|
|
||||||
if (array == null)
|
|
||||||
throw new ArgumentNullException ("array");
|
|
||||||
if (arrayIndex < 0)
|
|
||||||
throw new ArgumentOutOfRangeException ("arrayIndex");
|
|
||||||
if (arrayIndex > array.Length)
|
|
||||||
throw new ArgumentException ("index larger than largest valid index of array");
|
|
||||||
if (array.Length - arrayIndex < count)
|
|
||||||
throw new ArgumentException ("Destination array cannot hold the requested elements!");
|
|
||||||
|
|
||||||
for (int i = 0, items = 0; i < touched && items < count; i++) {
|
|
||||||
if (GetLinkHashCode (i) != 0)
|
|
||||||
array [arrayIndex++] = slots [i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resize ()
|
|
||||||
{
|
|
||||||
int newSize = PrimeHelper.ToPrime ((table.Length << 1) | 1);
|
|
||||||
|
|
||||||
// allocate new hash table and link slots array
|
|
||||||
var newTable = new int [newSize];
|
|
||||||
var newLinks = new Link [newSize];
|
|
||||||
|
|
||||||
for (int i = 0; i < table.Length; i++) {
|
|
||||||
int current = table [i] - 1;
|
|
||||||
while (current != NO_SLOT) {
|
|
||||||
int hashCode = newLinks [current].HashCode = GetItemHashCode (slots [current]);
|
|
||||||
int index = (hashCode & int.MaxValue) % newSize;
|
|
||||||
newLinks [current].Next = newTable [index] - 1;
|
|
||||||
newTable [index] = current + 1;
|
|
||||||
current = links [current].Next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
table = newTable;
|
|
||||||
links = newLinks;
|
|
||||||
|
|
||||||
// allocate new data slots, copy data
|
|
||||||
var newSlots = new T [newSize];
|
|
||||||
Array.Copy (slots, 0, newSlots, 0, touched);
|
|
||||||
slots = newSlots;
|
|
||||||
|
|
||||||
threshold = (int) (newSize * DEFAULT_LOAD_FACTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetLinkHashCode (int index)
|
|
||||||
{
|
|
||||||
return links [index].HashCode & HASH_FLAG;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetItemHashCode (T item)
|
|
||||||
{
|
|
||||||
if (item == null)
|
|
||||||
return HASH_FLAG;
|
|
||||||
return comparer.GetHashCode (item) | HASH_FLAG;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Add (T item)
|
|
||||||
{
|
|
||||||
int hashCode = GetItemHashCode (item);
|
|
||||||
int index = (hashCode & int.MaxValue) % table.Length;
|
|
||||||
|
|
||||||
if (SlotsContainsAt (index, hashCode, item))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (++count > threshold) {
|
|
||||||
Resize ();
|
|
||||||
index = (hashCode & int.MaxValue) % table.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find an empty slot
|
|
||||||
int current = empty_slot;
|
|
||||||
if (current == NO_SLOT)
|
|
||||||
current = touched++;
|
|
||||||
else
|
|
||||||
empty_slot = links [current].Next;
|
|
||||||
|
|
||||||
// store the hash code of the added item,
|
|
||||||
// prepend the added item to its linked list,
|
|
||||||
// update the hash table
|
|
||||||
links [current].HashCode = hashCode;
|
|
||||||
links [current].Next = table [index] - 1;
|
|
||||||
table [index] = current + 1;
|
|
||||||
|
|
||||||
// store item
|
|
||||||
slots [current] = item;
|
|
||||||
|
|
||||||
generation++;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEqualityComparer<T> Comparer {
|
|
||||||
get { return comparer; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear ()
|
|
||||||
{
|
|
||||||
count = 0;
|
|
||||||
|
|
||||||
Array.Clear (table, 0, table.Length);
|
|
||||||
Array.Clear (slots, 0, slots.Length);
|
|
||||||
Array.Clear (links, 0, links.Length);
|
|
||||||
|
|
||||||
// empty the "empty slots chain"
|
|
||||||
empty_slot = NO_SLOT;
|
|
||||||
|
|
||||||
touched = 0;
|
|
||||||
generation++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains (T item)
|
|
||||||
{
|
|
||||||
int hashCode = GetItemHashCode (item);
|
|
||||||
int index = (hashCode & int.MaxValue) % table.Length;
|
|
||||||
|
|
||||||
return SlotsContainsAt (index, hashCode, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove (T item)
|
|
||||||
{
|
|
||||||
// get first item of linked list corresponding to given key
|
|
||||||
int hashCode = GetItemHashCode (item);
|
|
||||||
int index = (hashCode & int.MaxValue) % table.Length;
|
|
||||||
int current = table [index] - 1;
|
|
||||||
|
|
||||||
// if there is no linked list, return false
|
|
||||||
if (current == NO_SLOT)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// walk linked list until right slot (and its predecessor) is
|
|
||||||
// found or end is reached
|
|
||||||
int prev = NO_SLOT;
|
|
||||||
do {
|
|
||||||
Link link = links [current];
|
|
||||||
if (link.HashCode == hashCode && ((hashCode == HASH_FLAG && (item == null || null == slots [current])) ? (item == null && null == slots [current]) : comparer.Equals (slots [current], item)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
prev = current;
|
|
||||||
current = link.Next;
|
|
||||||
} while (current != NO_SLOT);
|
|
||||||
|
|
||||||
// if we reached the end of the chain, return false
|
|
||||||
if (current == NO_SLOT)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
count--;
|
|
||||||
|
|
||||||
// remove slot from linked list
|
|
||||||
// is slot at beginning of linked list?
|
|
||||||
if (prev == NO_SLOT)
|
|
||||||
table [index] = links [current].Next + 1;
|
|
||||||
else
|
|
||||||
links [prev].Next = links [current].Next;
|
|
||||||
|
|
||||||
// mark slot as empty and prepend it to "empty slots chain"
|
|
||||||
links [current].Next = empty_slot;
|
|
||||||
empty_slot = current;
|
|
||||||
|
|
||||||
// clear slot
|
|
||||||
links [current].HashCode = 0;
|
|
||||||
slots [current] = default (T);
|
|
||||||
|
|
||||||
generation++;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int RemoveWhere (Predicate<T> match)
|
|
||||||
{
|
|
||||||
if (match == null)
|
|
||||||
throw new ArgumentNullException ("match");
|
|
||||||
|
|
||||||
var candidates = new List<T> ();
|
|
||||||
|
|
||||||
foreach (var item in this)
|
|
||||||
if (match (item))
|
|
||||||
candidates.Add (item);
|
|
||||||
|
|
||||||
foreach (var item in candidates)
|
|
||||||
Remove (item);
|
|
||||||
|
|
||||||
return candidates.Count;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void TrimExcess ()
|
|
||||||
{
|
|
||||||
Resize ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// set operations
|
|
||||||
|
|
||||||
public void IntersectWith (IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
throw new ArgumentNullException ("other");
|
|
||||||
|
|
||||||
var other_set = ToSet (other);
|
|
||||||
|
|
||||||
RemoveWhere (item => !other_set.Contains (item));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ExceptWith (IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
throw new ArgumentNullException ("other");
|
|
||||||
|
|
||||||
foreach (var item in other)
|
|
||||||
Remove (item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Overlaps (IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
throw new ArgumentNullException ("other");
|
|
||||||
|
|
||||||
foreach (var item in other)
|
|
||||||
if (Contains (item))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetEquals (IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
throw new ArgumentNullException ("other");
|
|
||||||
|
|
||||||
var other_set = ToSet (other);
|
|
||||||
|
|
||||||
if (count != other_set.Count)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
foreach (var item in this)
|
|
||||||
if (!other_set.Contains (item))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SymmetricExceptWith (IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
throw new ArgumentNullException ("other");
|
|
||||||
|
|
||||||
foreach (var item in ToSet (other))
|
|
||||||
if (!Add (item))
|
|
||||||
Remove (item);
|
|
||||||
}
|
|
||||||
|
|
||||||
HashSet<T> ToSet (IEnumerable<T> enumerable)
|
|
||||||
{
|
|
||||||
var set = enumerable as HashSet<T>;
|
|
||||||
if (set == null || !Comparer.Equals (set.Comparer))
|
|
||||||
set = new HashSet<T> (enumerable);
|
|
||||||
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnionWith (IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
throw new ArgumentNullException ("other");
|
|
||||||
|
|
||||||
foreach (var item in other)
|
|
||||||
Add (item);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CheckIsSubsetOf (HashSet<T> other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
throw new ArgumentNullException ("other");
|
|
||||||
|
|
||||||
foreach (var item in this)
|
|
||||||
if (!other.Contains (item))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSubsetOf (IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
throw new ArgumentNullException ("other");
|
|
||||||
|
|
||||||
if (count == 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
var other_set = ToSet (other);
|
|
||||||
|
|
||||||
if (count > other_set.Count)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return CheckIsSubsetOf (other_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsProperSubsetOf (IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
throw new ArgumentNullException ("other");
|
|
||||||
|
|
||||||
if (count == 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
var other_set = ToSet (other);
|
|
||||||
|
|
||||||
if (count >= other_set.Count)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return CheckIsSubsetOf (other_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CheckIsSupersetOf (HashSet<T> other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
throw new ArgumentNullException ("other");
|
|
||||||
|
|
||||||
foreach (var item in other)
|
|
||||||
if (!Contains (item))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSupersetOf (IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
throw new ArgumentNullException ("other");
|
|
||||||
|
|
||||||
var other_set = ToSet (other);
|
|
||||||
|
|
||||||
if (count < other_set.Count)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return CheckIsSupersetOf (other_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsProperSupersetOf (IEnumerable<T> other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
throw new ArgumentNullException ("other");
|
|
||||||
|
|
||||||
var other_set = ToSet (other);
|
|
||||||
|
|
||||||
if (count <= other_set.Count)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return CheckIsSupersetOf (other_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
class HashSetEqualityComparer : IEqualityComparer<HashSet<T>>
|
|
||||||
{
|
|
||||||
public bool Equals (HashSet<T> lhs, HashSet<T> rhs)
|
|
||||||
{
|
|
||||||
if (lhs == rhs)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (lhs == null || rhs == null || lhs.Count != rhs.Count)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
foreach (var item in lhs)
|
|
||||||
if (!rhs.Contains (item))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetHashCode (HashSet<T> hashset)
|
|
||||||
{
|
|
||||||
if (hashset == null)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
IEqualityComparer<T> comparer = EqualityComparer<T>.Default;
|
|
||||||
int hash = 0;
|
|
||||||
foreach (var item in hashset)
|
|
||||||
hash ^= comparer.GetHashCode (item);
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly HashSetEqualityComparer setComparer = new HashSetEqualityComparer ();
|
|
||||||
|
|
||||||
public static IEqualityComparer<HashSet<T>> CreateSetComparer ()
|
|
||||||
{
|
|
||||||
return setComparer;
|
|
||||||
}
|
|
||||||
|
|
||||||
[SecurityCritical]
|
|
||||||
public void GetObjectData (SerializationInfo info, StreamingContext context)
|
|
||||||
{
|
|
||||||
if (info == null) {
|
|
||||||
throw new ArgumentNullException("info");
|
|
||||||
}
|
|
||||||
info.AddValue("Version", generation);
|
|
||||||
info.AddValue("Comparer", comparer, typeof(IEqualityComparer<T>));
|
|
||||||
info.AddValue("Capacity", (table == null) ? 0 : table.Length);
|
|
||||||
if (table != null) {
|
|
||||||
T[] tableArray = new T[table.Length];
|
|
||||||
CopyTo(tableArray);
|
|
||||||
info.AddValue("Elements", tableArray, typeof(T[]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnDeserialization (object sender)
|
|
||||||
{
|
|
||||||
if (si != null)
|
|
||||||
{
|
|
||||||
generation = (int) si.GetValue("Version", typeof(int));
|
|
||||||
comparer = (IEqualityComparer<T>) si.GetValue("Comparer",
|
|
||||||
typeof(IEqualityComparer<T>));
|
|
||||||
int capacity = (int) si.GetValue("Capacity", typeof(int));
|
|
||||||
|
|
||||||
empty_slot = NO_SLOT;
|
|
||||||
if (capacity > 0) {
|
|
||||||
table = new int[capacity];
|
|
||||||
slots = new T[capacity];
|
|
||||||
|
|
||||||
T[] tableArray = (T[]) si.GetValue("Elements", typeof(T[]));
|
|
||||||
if (tableArray == null)
|
|
||||||
throw new SerializationException("Missing Elements");
|
|
||||||
|
|
||||||
for (int iElement = 0; iElement < tableArray.Length; iElement++) {
|
|
||||||
Add(tableArray[iElement]);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
table = null;
|
|
||||||
|
|
||||||
si = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
IEnumerator<T> IEnumerable<T>.GetEnumerator ()
|
|
||||||
{
|
|
||||||
return new Enumerator (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ICollection<T>.IsReadOnly {
|
|
||||||
get { return false; }
|
|
||||||
}
|
|
||||||
|
|
||||||
void ICollection<T>.Add (T item)
|
|
||||||
{
|
|
||||||
Add (item);
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator ()
|
|
||||||
{
|
|
||||||
return new Enumerator (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Enumerator GetEnumerator ()
|
|
||||||
{
|
|
||||||
return new Enumerator (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public struct Enumerator : IEnumerator<T> {
|
|
||||||
|
|
||||||
HashSet<T> hashset;
|
|
||||||
int next;
|
|
||||||
int stamp;
|
|
||||||
|
|
||||||
T current;
|
|
||||||
|
|
||||||
internal Enumerator (HashSet<T> hashset)
|
|
||||||
: this ()
|
|
||||||
{
|
|
||||||
this.hashset = hashset;
|
|
||||||
this.stamp = hashset.generation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool MoveNext ()
|
|
||||||
{
|
|
||||||
CheckState ();
|
|
||||||
|
|
||||||
if (next < 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
while (next < hashset.touched) {
|
|
||||||
int cur = next++;
|
|
||||||
if (hashset.GetLinkHashCode (cur) != 0) {
|
|
||||||
current = hashset.slots [cur];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
next = NO_SLOT;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Current {
|
|
||||||
get { return current; }
|
|
||||||
}
|
|
||||||
|
|
||||||
object IEnumerator.Current {
|
|
||||||
get {
|
|
||||||
CheckState ();
|
|
||||||
if (next <= 0)
|
|
||||||
throw new InvalidOperationException ("Current is not valid");
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IEnumerator.Reset ()
|
|
||||||
{
|
|
||||||
CheckState ();
|
|
||||||
next = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose ()
|
|
||||||
{
|
|
||||||
hashset = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckState ()
|
|
||||||
{
|
|
||||||
if (hashset == null)
|
|
||||||
throw new ObjectDisposedException (null);
|
|
||||||
if (hashset.generation != stamp)
|
|
||||||
throw new InvalidOperationException ("HashSet have been modified while it was iterated over");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// borrowed from System.Collections.HashTable
|
|
||||||
static class PrimeHelper {
|
|
||||||
|
|
||||||
static readonly int [] primes_table = {
|
|
||||||
11,
|
|
||||||
19,
|
|
||||||
37,
|
|
||||||
73,
|
|
||||||
109,
|
|
||||||
163,
|
|
||||||
251,
|
|
||||||
367,
|
|
||||||
557,
|
|
||||||
823,
|
|
||||||
1237,
|
|
||||||
1861,
|
|
||||||
2777,
|
|
||||||
4177,
|
|
||||||
6247,
|
|
||||||
9371,
|
|
||||||
14057,
|
|
||||||
21089,
|
|
||||||
31627,
|
|
||||||
47431,
|
|
||||||
71143,
|
|
||||||
106721,
|
|
||||||
160073,
|
|
||||||
240101,
|
|
||||||
360163,
|
|
||||||
540217,
|
|
||||||
810343,
|
|
||||||
1215497,
|
|
||||||
1823231,
|
|
||||||
2734867,
|
|
||||||
4102283,
|
|
||||||
6153409,
|
|
||||||
9230113,
|
|
||||||
13845163
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool TestPrime (int x)
|
|
||||||
{
|
|
||||||
if ((x & 1) != 0) {
|
|
||||||
int top = (int) Math.Sqrt (x);
|
|
||||||
|
|
||||||
for (int n = 3; n < top; n += 2) {
|
|
||||||
if ((x % n) == 0)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There is only one even prime - 2.
|
|
||||||
return x == 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int CalcPrime (int x)
|
|
||||||
{
|
|
||||||
for (int i = (x & (~1)) - 1; i < Int32.MaxValue; i += 2)
|
|
||||||
if (TestPrime (i))
|
|
||||||
return i;
|
|
||||||
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int ToPrime (int x)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < primes_table.Length; i++)
|
|
||||||
if (x <= primes_table [i])
|
|
||||||
return primes_table [i];
|
|
||||||
|
|
||||||
return CalcPrime (x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -837,7 +837,6 @@
|
|||||||
<Compile Include="Logic\Enums\SelectionChoice.cs" />
|
<Compile Include="Logic\Enums\SelectionChoice.cs" />
|
||||||
<Compile Include="Logic\FastBitmap.cs" />
|
<Compile Include="Logic\FastBitmap.cs" />
|
||||||
<Compile Include="Logic\Fourier.cs" />
|
<Compile Include="Logic\Fourier.cs" />
|
||||||
<Compile Include="Logic\HashSet.cs" />
|
|
||||||
<Compile Include="Logic\IfoParser.cs" />
|
<Compile Include="Logic\IfoParser.cs" />
|
||||||
<Compile Include="Logic\Language.cs" />
|
<Compile Include="Logic\Language.cs" />
|
||||||
<Compile Include="Logic\ManagedBitmap.cs" />
|
<Compile Include="Logic\ManagedBitmap.cs" />
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
using Nikse.SubtitleEdit.Forms;
|
using Nikse.SubtitleEdit.Forms;
|
||||||
|
Loading…
Reference in New Issue
Block a user