Dryad/LinqToDryad/DryadLinqCollection.cs

1471 lines
48 KiB
C#
Raw Blame History

/*
Copyright (c) Microsoft Corporation
All rights reserved.
Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions and
limitations under the License.
*/
//
// <20> Microsoft Corporation. All rights reserved.
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Research.DryadLinq;
namespace Microsoft.Research.DryadLinq.Internal
{
[Serializable]
public struct IndexedValue<T> : IEquatable<IndexedValue<T>>, IComparable<IndexedValue<T>>
{
private int _index;
private T _value;
public int Index
{
get { return _index; }
set { _index = value; }
}
public T Value
{
get { return _value; }
set { _value = value; }
}
public IndexedValue(int index, T value)
{
_index = index;
_value = value;
}
public bool Equals(IndexedValue<T> val)
{
return this.Index == val.Index;
}
public int CompareTo(IndexedValue<T> val)
{
return this.Index - val.Index;
}
public override int GetHashCode()
{
return this.Index;
}
public override bool Equals(object obj)
{
if (!(obj is IndexedValue<T>))
return false;
return this.Equals((IndexedValue<T>)obj);
}
public static bool operator ==(IndexedValue<T> a, IndexedValue<T> b)
{
return a.Equals(b);
}
public static bool operator !=(IndexedValue<T> a, IndexedValue<T> b)
{
return !a.Equals(b);
}
}
public struct HpcLinqGrouping<K, T> : IGrouping<K, T>
{
private K m_key;
private IEnumerable<T> m_elems;
public HpcLinqGrouping(K key, IEnumerable<T> elems)
{
this.m_key = key;
this.m_elems = elems;
}
public K Key
{
get { return this.m_key; }
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return this.m_elems.GetEnumerator();
}
}
public class BigCollection<TElement> : IEnumerable<TElement>
{
protected const int ChunkSize = (1 << 21);
private TElement[][] m_elements;
private Int32 m_pos1;
private Int32 m_pos2;
public BigCollection()
{
this.m_elements = new TElement[4][];
this.m_elements[0] = new TElement[2];
this.m_pos1 = 0;
this.m_pos2 = 0;
}
public long Count()
{
return (ChunkSize * (long)this.m_pos1) + this.m_pos2;
}
public TElement this[long index]
{
get { return this.m_elements[index/ChunkSize][index%ChunkSize]; }
set { this.m_elements[index/ChunkSize][index%ChunkSize] = value; }
}
public void Add(TElement elem)
{
if (this.m_pos2 == this.m_elements[this.m_pos1].Length)
{
if (this.m_pos2 == ChunkSize)
{
this.m_pos1++;
this.m_pos2 = 0;
if (this.m_pos1 == this.m_elements.Length)
{
TElement[][] elems = new TElement[this.m_pos1 * 2][];
Array.Copy(this.m_elements, 0, elems, 0, this.m_pos1);
this.m_elements = elems;
}
this.m_elements[this.m_pos1] = new TElement[ChunkSize];
}
else
{
TElement[] newElems = new TElement[this.m_pos2 * 2];
Array.Copy(this.m_elements[this.m_pos1], 0, newElems, 0, this.m_pos2);
this.m_elements[this.m_pos1] = newElems;
}
}
this.m_elements[this.m_pos1][this.m_pos2] = elem;
this.m_pos2++;
}
public IEnumerable<TElement> Reverse()
{
for (int i = this.m_pos2 - 1; i >= 0; i--)
{
yield return this.m_elements[this.m_pos1][i];
}
for (int i = this.m_pos1 - 1; i >= 0; i--)
{
TElement[] elems = this.m_elements[i];
for (int j = elems.Length - 1; j >= 0; j--)
{
yield return elems[j];
}
}
}
public IEnumerator<TElement> GetEnumerator()
{
for (int i = 0; i < this.m_pos1; i++)
{
TElement[] elems = this.m_elements[i];
for (int j = 0; j < elems.Length; j++)
{
yield return elems[j];
}
}
for (int i = 0; i < this.m_pos2; i++)
{
yield return this.m_elements[this.m_pos1][i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
public class BigDictionary<TKey, TValue> : IEnumerable<Pair<TKey, TValue>>
{
private const int Ratio = 2;
private const int LogChunkSize = 21;
private const int ChunkSize = (1 << LogChunkSize);
private const int ChunkMask = ChunkSize - 1;
private const uint MaxCount = UInt32.MaxValue - ChunkSize;
private IEqualityComparer<TKey> m_comparer;
private UInt32[] m_buckets;
private Entry[][] m_entries;
private UInt32 m_pos1;
private UInt32 m_pos2;
private Int64 m_count;
private UInt32 m_freeList;
public BigDictionary()
: this(null, 1024)
{
}
public BigDictionary(IEqualityComparer<TKey> comparer)
: this(comparer, 1024)
{
}
public BigDictionary(IEqualityComparer<TKey> comparer, int initialCapacity)
{
this.m_comparer = (comparer == null) ? EqualityComparer<TKey>.Default : comparer;
this.m_buckets = new uint[CollectionHelper.GetNextPrime(initialCapacity)];
this.m_entries = new Entry[4][];
this.m_entries[0] = new Entry[ChunkSize];
this.m_pos1 = 0;
this.m_pos2 = 1;
this.m_count = 0;
this.m_freeList = 0;
}
public Int64 Count
{
get { return this.m_count; }
}
public TValue this[TKey key]
{
get {
TValue value;
if (!this.TryGetValue(key, out value))
{
throw new DryadLinqException(HpcLinqErrorCode.KeyNotFound, SR.KeyNotFound);
}
return value;
}
set {
this.Add(key, value);
}
}
public bool TryGetValue(TKey key, out TValue value)
{
int hashCode = this.m_comparer.GetHashCode(key) & 0x7FFFFFFF;
int bucket = hashCode % this.m_buckets.Length;
UInt32 index = this.m_buckets[bucket];
while (index > 0)
{
Entry entry = this.m_entries[index >> LogChunkSize][index & ChunkMask];
if (this.m_comparer.Equals(entry.m_key, key))
{
value = entry.m_value;
return true;
}
index = entry.m_next;
}
value = default(TValue);
return false;
}
public bool ContainsKey(TKey key)
{
TValue value;
return this.TryGetValue(key, out value);
}
public bool Add(TKey key, TValue value)
{
int hashCode = this.m_comparer.GetHashCode(key) & 0x7FFFFFFF;
int bucket = hashCode % this.m_buckets.Length;
UInt32 index = this.m_buckets[bucket];
while (index > 0)
{
Entry entry = this.m_entries[index >> LogChunkSize][index & ChunkMask];
if (this.m_comparer.Equals(entry.m_key, key))
{
return false;
}
index = entry.m_next;
}
// <key, value> is not in the dictionary, so add it
if (this.m_freeList > 0)
{
index = this.m_freeList;
this.m_freeList = this.m_entries[index >> LogChunkSize][index & ChunkMask].m_next;
Entry newEntry = new Entry(key, value, this.m_buckets[bucket]);
this.m_entries[index >> LogChunkSize][index & ChunkMask] = newEntry;
}
else
{
if (this.m_count == (this.m_buckets.Length * Ratio))
{
this.Resize();
bucket = hashCode % this.m_buckets.Length;
}
Entry newEntry = new Entry(key, value, this.m_buckets[bucket]);
if (this.m_pos2 == ChunkSize)
{
if (this.m_count >= MaxCount)
{
throw new DryadLinqException(HpcLinqErrorCode.TooManyItems, SR.TooManyItems);
}
this.m_pos1++;
this.m_pos2 = 0;
if (this.m_pos1 == this.m_entries.Length)
{
Entry[][] newEntries = new Entry[this.m_pos1 * 2][];
Array.Copy(this.m_entries, 0, newEntries, 0, this.m_pos1);
this.m_entries = newEntries;
}
this.m_entries[this.m_pos1] = new Entry[ChunkSize];
}
this.m_entries[this.m_pos1][this.m_pos2] = newEntry;
index = ((this.m_pos1 << LogChunkSize) | this.m_pos2);
this.m_pos2++;
}
this.m_buckets[bucket] = index;
this.m_count++;
return true;
}
// Remove an item from the set. Return true iff the item is in the set and
// is removed successfully from the set.
public bool Remove(TKey key)
{
int hashCode = this.m_comparer.GetHashCode(key) & 0x7FFFFFFF;
int bucket = hashCode % this.m_buckets.Length;
uint pidx = 0;
uint cidx = this.m_buckets[bucket];
while (cidx > 0)
{
Entry entry = this.m_entries[cidx >> LogChunkSize][cidx & ChunkMask];
if (this.m_comparer.Equals(entry.m_key, key))
{
if (pidx == 0)
{
this.m_buckets[bucket] = entry.m_next;
}
else
{
this.m_entries[pidx >> LogChunkSize][pidx & ChunkMask].m_next = entry.m_next;
}
this.m_entries[cidx >> LogChunkSize][cidx & ChunkMask].m_next = this.m_freeList;
this.m_freeList = cidx;
this.m_count--;
return true;
}
pidx = cidx;
cidx = entry.m_next;
}
return false;
}
private void Resize()
{
int oldSize = this.m_buckets.Length;
int newSize = CollectionHelper.GetNextPrime(oldSize);
if (newSize > oldSize)
{
this.m_buckets = new uint[newSize];
for (uint i = 1; i <= this.m_count; i++)
{
Entry entry = this.m_entries[i >> LogChunkSize][i & ChunkMask];
int bucket = (this.m_comparer.GetHashCode(entry.m_key) & 0x7FFFFFFF) % newSize;
this.m_entries[i >> LogChunkSize][i & ChunkMask].m_next = this.m_buckets[bucket];
this.m_buckets[bucket] = i;
}
}
}
public IEnumerable<TKey> GetKeys()
{
for (int i = 0; i < this.m_buckets.Length; i++)
{
uint index = this.m_buckets[i];
while (index > 0)
{
Entry entry = this.m_entries[index >> LogChunkSize][index & ChunkMask];
yield return entry.m_key;
index = entry.m_next;
}
}
}
public IEnumerable<TValue> GetValues()
{
for (int i = 0; i < this.m_buckets.Length; i++)
{
uint index = this.m_buckets[i];
while (index > 0)
{
Entry entry = this.m_entries[index >> LogChunkSize][index & ChunkMask];
yield return entry.m_value;
index = entry.m_next;
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<Pair<TKey, TValue>> GetEnumerator()
{
for (int i = 0; i < this.m_buckets.Length; i++)
{
uint index = this.m_buckets[i];
while (index > 0)
{
Entry entry = this.m_entries[index >> LogChunkSize][index & ChunkMask];
yield return new Pair<TKey, TValue>(entry.m_key, entry.m_value);
index = entry.m_next;
}
}
}
private struct Entry
{
public TKey m_key;
public TValue m_value;
public UInt32 m_next;
public Entry(TKey key, TValue value, UInt32 next)
{
this.m_key = key;
this.m_value = value;
this.m_next = next;
}
}
}
public class AccumulateDictionary<TKey, TSource, TValue> : IEnumerable<Pair<TKey, TValue>>
{
private const int Ratio = 2;
private const int LogChunkSize = 21;
private const int ChunkSize = (1 << LogChunkSize);
private const int ChunkMask = ChunkSize - 1;
private const uint MaxCount = UInt32.MaxValue - ChunkSize;
private IEqualityComparer<TKey> m_comparer;
private Func<TSource, TValue> m_seed;
private Func<TValue, TSource, TValue> m_accumulator;
private UInt32[] m_buckets;
private Entry[][] m_entries;
private UInt32 m_pos1;
private UInt32 m_pos2;
private Int64 m_count;
public AccumulateDictionary(Func<TSource, TValue> seed,
Func<TValue, TSource, TValue> accumulator)
: this(null, 1024, seed, accumulator)
{
}
public AccumulateDictionary(IEqualityComparer<TKey> comparer,
Func<TSource, TValue> seed,
Func<TValue, TSource, TValue> accumulator)
: this(comparer, 1024, seed, accumulator)
{
}
public AccumulateDictionary(IEqualityComparer<TKey> comparer,
int initialCapacity,
Func<TSource, TValue> seed,
Func<TValue, TSource, TValue> accumulator)
{
this.m_comparer = (comparer == null) ? EqualityComparer<TKey>.Default : comparer;
this.m_seed = seed;
this.m_accumulator = accumulator;
this.m_buckets = new uint[CollectionHelper.GetNextPrime(initialCapacity)];
this.m_entries = new Entry[4][];
this.m_entries[0] = new Entry[ChunkSize];
this.m_pos1 = 0;
this.m_pos2 = 1;
this.m_count = 0;
}
public Int64 Count
{
get { return this.m_count; }
}
public bool TryGetValue(TKey key, out TValue value)
{
int hashCode = this.m_comparer.GetHashCode(key) & 0x7FFFFFFF;
int bucket = hashCode % this.m_buckets.Length;
UInt32 index = this.m_buckets[bucket];
while (index > 0)
{
Entry entry = this.m_entries[index >> LogChunkSize][index & ChunkMask];
if (this.m_comparer.Equals(entry.m_key, key))
{
value = entry.m_value;
return true;
}
index = entry.m_next;
}
value = default(TValue);
return false;
}
public bool ContainsKey(TKey key)
{
TValue value;
return this.TryGetValue(key, out value);
}
public void Add(TKey key, TSource elem)
{
int hashCode = this.m_comparer.GetHashCode(key) & 0x7FFFFFFF;
int bucket = hashCode % this.m_buckets.Length;
UInt32 index = this.m_buckets[bucket];
while (index > 0)
{
Entry entry = this.m_entries[index >> LogChunkSize][index & ChunkMask];
if (this.m_comparer.Equals(entry.m_key, key))
{
this.m_entries[index >> LogChunkSize][index & ChunkMask].m_value
= this.m_accumulator(entry.m_value, elem);
return;
}
index = entry.m_next;
}
// <key, elem> is not in the dictionary, so add it
if (this.m_count == (this.m_buckets.Length * Ratio))
{
this.Resize();
bucket = hashCode % this.m_buckets.Length;
}
TValue val = this.m_seed(elem);
Entry newEntry = new Entry(key, val, this.m_buckets[bucket]);
if (this.m_pos2 == ChunkSize)
{
if (this.m_count >= MaxCount)
{
throw new DryadLinqException("Too many items");
}
this.m_pos1++;
this.m_pos2 = 0;
if (this.m_pos1 == this.m_entries.Length)
{
Entry[][] newEntries = new Entry[this.m_pos1 * 2][];
Array.Copy(this.m_entries, 0, newEntries, 0, this.m_pos1);
this.m_entries = newEntries;
}
this.m_entries[this.m_pos1] = new Entry[ChunkSize];
}
this.m_entries[this.m_pos1][this.m_pos2] = newEntry;
index = ((this.m_pos1 << LogChunkSize) | this.m_pos2);
this.m_pos2++;
this.m_buckets[bucket] = index;
this.m_count++;
}
private void Resize()
{
int oldSize = this.m_buckets.Length;
int newSize = CollectionHelper.GetNextPrime(oldSize);
if (newSize > oldSize)
{
this.m_buckets = new uint[newSize];
for (uint i = 1; i <= this.m_count; i++)
{
Entry entry = this.m_entries[i >> LogChunkSize][i & ChunkMask];
int bucket = (this.m_comparer.GetHashCode(entry.m_key) & 0x7FFFFFFF) % newSize;
this.m_entries[i >> LogChunkSize][i & ChunkMask].m_next = this.m_buckets[bucket];
this.m_buckets[bucket] = i;
}
}
}
public IEnumerable<TKey> GetKeys()
{
for (int i = 0; i < this.m_buckets.Length; i++)
{
uint index = this.m_buckets[i];
while (index > 0)
{
Entry entry = this.m_entries[index >> LogChunkSize][index & ChunkMask];
yield return entry.m_key;
index = entry.m_next;
}
}
}
public IEnumerable<TValue> GetValues()
{
for (int i = 0; i < this.m_buckets.Length; i++)
{
uint index = this.m_buckets[i];
while (index > 0)
{
Entry entry = this.m_entries[index >> LogChunkSize][index & ChunkMask];
yield return entry.m_value;
index = entry.m_next;
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<Pair<TKey, TValue>> GetEnumerator()
{
for (int i = 0; i < this.m_buckets.Length; i++)
{
uint index = this.m_buckets[i];
while (index > 0)
{
Entry entry = this.m_entries[index >> LogChunkSize][index & ChunkMask];
yield return new Pair<TKey, TValue>(entry.m_key, entry.m_value);
index = entry.m_next;
}
}
}
private struct Entry
{
public TKey m_key;
public TValue m_value;
public UInt32 m_next;
public Entry(TKey key, TValue value, UInt32 next)
{
this.m_key = key;
this.m_value = value;
this.m_next = next;
}
}
}
public class BigHashSet<TElement> : IEnumerable<TElement>
{
private const int Ratio = 2;
private const int LogChunkSize = 21;
private const int ChunkSize = (1 << LogChunkSize);
private const int ChunkMask = ChunkSize - 1;
private const uint MaxCount = UInt32.MaxValue - ChunkSize;
private IEqualityComparer<TElement> m_comparer;
private UInt32[] m_buckets;
private Entry[][] m_entries;
private UInt32 m_pos1;
private UInt32 m_pos2;
private Int64 m_count;
private UInt32 m_freeList;
public BigHashSet()
: this(null, 1024)
{
}
public BigHashSet(IEqualityComparer<TElement> comparer)
: this(comparer, 1024)
{
}
public BigHashSet(IEqualityComparer<TElement> comparer, int initialCapacity)
{
this.m_comparer = (comparer == null) ? EqualityComparer<TElement>.Default : comparer;
this.m_buckets = new uint[CollectionHelper.GetNextPrime(initialCapacity)];
this.m_entries = new Entry[4][];
this.m_entries[0] = new Entry[ChunkSize];
this.m_pos1 = 0;
this.m_pos2 = 1;
this.m_count = 0;
this.m_freeList = 0;
}
public Int64 Count
{
get { return this.m_count; }
}
public bool Contains(TElement item)
{
int hashCode = this.m_comparer.GetHashCode(item) & 0x7FFFFFFF;
int bucket = hashCode % this.m_buckets.Length;
UInt32 index = this.m_buckets[bucket];
while (index > 0)
{
Entry entry = this.m_entries[index >> LogChunkSize][index & ChunkMask];
if (this.m_comparer.Equals(entry.m_item, item))
{
return true;
}
index = entry.m_next;
}
return false;
}
// Add an item into the set. Return true iff the item is not in the set and
// is added successfully into the set.
public bool Add(TElement item)
{
int hashCode = this.m_comparer.GetHashCode(item) & 0x7FFFFFFF;
int bucket = hashCode % this.m_buckets.Length;
UInt32 index = this.m_buckets[bucket];
while (index > 0)
{
Entry entry = this.m_entries[index >> LogChunkSize][index & ChunkMask];
if (this.m_comparer.Equals(entry.m_item, item))
{
return false;
}
index = entry.m_next;
}
// item is not in the set, so add it
if (this.m_freeList > 0)
{
index = this.m_freeList;
this.m_freeList = this.m_entries[index >> LogChunkSize][index & ChunkMask].m_next;
Entry newEntry = new Entry(item, this.m_buckets[bucket]);
this.m_entries[index >> LogChunkSize][index & ChunkMask] = newEntry;
}
else
{
if (this.m_count == (this.m_buckets.Length * Ratio))
{
this.Resize();
bucket = hashCode % this.m_buckets.Length;
}
Entry newEntry = new Entry(item, this.m_buckets[bucket]);
if (this.m_pos2 == ChunkSize)
{
if (this.m_count >= MaxCount)
{
throw new DryadLinqException(HpcLinqErrorCode.TooManyItems, SR.TooManyItems);
}
this.m_pos1++;
this.m_pos2 = 0;
if (this.m_pos1 == this.m_entries.Length)
{
Entry[][] newEntries = new Entry[this.m_pos1 * 2][];
Array.Copy(this.m_entries, 0, newEntries, 0, this.m_pos1);
this.m_entries = newEntries;
}
this.m_entries[this.m_pos1] = new Entry[ChunkSize];
}
this.m_entries[this.m_pos1][this.m_pos2] = newEntry;
index = ((this.m_pos1 << LogChunkSize) | this.m_pos2);
this.m_pos2++;
}
this.m_buckets[bucket] = index;
this.m_count++;
return true;
}
// Remove an item from the set. Return true iff the item is in the set and
// is removed successfully from the set.
public bool Remove(TElement item)
{
int hashCode = this.m_comparer.GetHashCode(item) & 0x7FFFFFFF;
int bucket = hashCode % this.m_buckets.Length;
uint pidx = 0;
uint cidx = this.m_buckets[bucket];
while (cidx > 0)
{
Entry entry = this.m_entries[cidx >> LogChunkSize][cidx & ChunkMask];
if (this.m_comparer.Equals(entry.m_item, item))
{
if (pidx == 0)
{
this.m_buckets[bucket] = entry.m_next;
}
else
{
this.m_entries[pidx >> LogChunkSize][pidx & ChunkMask].m_next = entry.m_next;
}
this.m_entries[cidx >> LogChunkSize][cidx & ChunkMask].m_next = this.m_freeList;
this.m_freeList = cidx;
this.m_count--;
return true;
}
pidx = cidx;
cidx = entry.m_next;
}
return false;
}
private void Resize()
{
int oldSize = this.m_buckets.Length;
int newSize = CollectionHelper.GetNextPrime(oldSize);
if (newSize > oldSize)
{
this.m_buckets = new uint[newSize];
for (uint i = 1; i <= this.m_count; i++)
{
Entry entry = this.m_entries[i >> LogChunkSize][i & ChunkMask];
int bucket = (this.m_comparer.GetHashCode(entry.m_item) & 0x7FFFFFFF) % newSize;
this.m_entries[i >> LogChunkSize][i & ChunkMask].m_next = this.m_buckets[bucket];
this.m_buckets[bucket] = i;
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<TElement> GetEnumerator()
{
for (int i = 0; i < this.m_buckets.Length; i++)
{
uint index = this.m_buckets[i];
while (index > 0)
{
Entry entry = this.m_entries[index >> LogChunkSize][index & ChunkMask];
yield return entry.m_item;
index = entry.m_next;
}
}
}
private struct Entry
{
public TElement m_item;
public UInt32 m_next;
public Entry(TElement item, UInt32 next)
{
this.m_item = item;
this.m_next = next;
}
}
}
public class Grouping<TKey, TElement> : IGrouping<TKey, TElement>
{
private static int MaxCount = Int32.MaxValue / TypeSystem.GetInMemSize(typeof(TElement));
private TKey m_key;
private TElement[] m_elements;
private int m_count;
private Grouping<TKey, TElement> m_next;
public Grouping(TKey key)
: this(key, 2)
{
}
internal Grouping(TKey key, int len)
{
this.m_key = key;
this.m_elements = new TElement[len];
this.m_count = 0;
this.m_next = null;
}
public IEnumerator<TElement> GetEnumerator()
{
for (int i = 0; i < this.m_count; i++)
{
yield return this.m_elements[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public TKey Key
{
get { return this.m_key; }
}
public int Count()
{
return this.m_count;
}
internal TElement[] Elements
{
get { return m_elements; }
}
internal Grouping<TKey, TElement> Next
{
get { return this.m_next; }
set { this.m_next = value; }
}
public void AddItem(TElement elem)
{
if (this.m_elements.Length == this.m_count)
{
if (this.m_count >= MaxCount)
{
throw new DryadLinqException("Too many elements in a single group.");
}
int newSize = this.m_count * 2;
if (newSize > MaxCount) newSize = MaxCount;
TElement[] newElements = new TElement[newSize];
Array.Copy(this.m_elements, 0, newElements, 0, this.m_count);
this.m_elements = newElements;
}
this.m_elements[this.m_count++] = elem;
}
public override string ToString()
{
return "Grouping[" + this.Key + "]";
}
}
public class BigGrouping<TKey, TElement> : IGrouping<TKey, TElement>
{
protected const int ChunkSize = (1 << 21);
private TKey m_key;
private TElement[][] m_elements;
private int m_pos1;
private int m_pos2;
private BigGrouping<TKey, TElement> m_next;
public BigGrouping(TKey key)
{
this.m_key = key;
this.m_elements = new TElement[2][];
this.m_elements[0] = new TElement[2];
this.m_pos1 = 0;
this.m_pos2 = 0;
this.m_next = null;
}
public TKey Key
{
get { return this.m_key; }
}
public long Count()
{
return (ChunkSize * (long)this.m_pos1) + this.m_pos2;
}
internal BigGrouping<TKey, TElement> Next
{
get { return this.m_next; }
set { this.m_next = value; }
}
public void AddItem(TElement elem)
{
if (this.m_pos2 == this.m_elements[this.m_pos1].Length)
{
if (this.m_pos2 == ChunkSize)
{
this.m_pos1++;
this.m_pos2 = 0;
if (this.m_pos1 == this.m_elements.Length)
{
TElement[][] elems = new TElement[this.m_pos1 * 2][];
Array.Copy(this.m_elements, 0, elems, 0, this.m_pos1);
this.m_elements = elems;
}
this.m_elements[this.m_pos1] = new TElement[ChunkSize];
}
else
{
TElement[] newElems = new TElement[this.m_pos2 * 2];
Array.Copy(this.m_elements[this.m_pos1], 0, newElems, 0, this.m_pos2);
this.m_elements[this.m_pos1] = newElems;
}
}
this.m_elements[this.m_pos1][this.m_pos2] = elem;
this.m_pos2++;
}
public IEnumerator<TElement> GetEnumerator()
{
for (int i = 0; i < this.m_pos1; i++)
{
TElement[] elems = this.m_elements[i];
for (int j = 0; j < elems.Length; j++)
{
yield return elems[j];
}
}
for (int j = 0; j < this.m_pos2; j++)
{
yield return this.m_elements[this.m_pos1][j];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public override string ToString()
{
return "Grouping[" + this.Key + "]";
}
}
public class Grouping<TKey, TElement, TResult>
{
private TKey m_key;
private TElement[] m_elems;
private TResult[] m_results;
private int m_count;
private Grouping<TKey, TElement, TResult> m_next;
public Grouping(TKey key)
: this(key, 2)
{
}
internal Grouping(TKey key, int len)
{
this.m_key = key;
this.m_elems = new TElement[len];
this.m_count = 0;
this.m_results = new TResult[2];
this.m_next = null;
}
public TKey Key
{
get { return this.m_key; }
}
public int Count()
{
return this.ElemCount;
}
private int ElemCount
{
get { return (this.m_count & 0xFFFFFF); }
}
private int ResCount
{
get { return (this.m_count >> 24); }
}
internal Grouping<TKey, TElement, TResult> Next
{
get { return this.m_next; }
set { this.m_next = value; }
}
public void Reduce(Func<IEnumerable<TElement>, TResult> resultSelector,
Func<IEnumerable<TResult>, TResult> combiner)
{
int elemCnt = this.ElemCount;
if (elemCnt > 0)
{
TElement[] curElems = this.m_elems;
if (elemCnt < this.m_elems.Length)
{
curElems = new TElement[elemCnt];
Array.Copy(this.m_elems, 0, curElems, 0, elemCnt);
}
int resCount = this.ResCount;
this.m_results[resCount] = resultSelector(curElems);
if (resCount == 1)
{
this.m_results[0] = combiner(this.m_results);
}
this.m_elems = new TElement[2];
this.m_count = 0x1000000;
}
}
public TResult GetResult(Func<IEnumerable<TElement>, TResult> resultSelector,
Func<IEnumerable<TResult>, TResult> combiner)
{
int elemCnt = this.ElemCount;
if (elemCnt > 0)
{
TElement[] curElems = this.m_elems;
if (elemCnt < this.m_elems.Length)
{
curElems = new TElement[elemCnt];
Array.Copy(this.m_elems, 0, curElems, 0, elemCnt);
}
int resCount = this.ResCount;
this.m_results[resCount] = resultSelector(curElems);
if (resCount == 1)
{
this.m_results[0] = combiner(this.m_results);
}
}
return this.m_results[0];
}
public void AddItem(TElement elem)
{
int elemCnt = this.ElemCount;
if (this.m_elems.Length == elemCnt)
{
if (elemCnt >= 0x800000)
{
throw new DryadLinqException(HpcLinqErrorCode.TooManyElementsBeforeReduction,
SR.TooManyElementsBeforeReduction);
}
TElement[] newElems = new TElement[elemCnt * 2];
Array.Copy(this.m_elems, 0, newElems, 0, elemCnt);
this.m_elems = newElems;
}
this.m_elems[elemCnt] = elem;
this.m_count++;
}
public override string ToString()
{
return "Grouping[" + this.Key + "]";
}
}
public class GroupingHashSet<TElement, TKey> : IEnumerable<IGrouping<TKey, TElement>>
{
private const int Ratio = 2;
private const int MaxGroupSize = 64;
private Grouping<TKey, TElement>[] m_buckets;
private IEqualityComparer<TKey> m_comparer;
private long m_count;
private int m_maxGroupSize;
public GroupingHashSet(IEqualityComparer<TKey> comparer)
: this(comparer, 1024, MaxGroupSize)
{
}
internal GroupingHashSet(IEqualityComparer<TKey> comparer, int capacity)
: this(comparer, capacity, MaxGroupSize)
{
}
internal GroupingHashSet(IEqualityComparer<TKey> comparer, int capacity, int maxGroupSize)
{
int size = CollectionHelper.GetNextPrime(capacity);
this.m_buckets = new Grouping<TKey, TElement>[size];
this.m_comparer = comparer;
this.m_count = 0;
this.m_maxGroupSize = maxGroupSize;
}
internal Grouping<TKey, TElement> GetGroup(TKey key)
{
int hashCode = this.m_comparer.GetHashCode(key);
int startIdx = (hashCode & 0x7FFFFFFF) % this.m_buckets.Length;
for (Grouping<TKey, TElement> g = this.m_buckets[startIdx]; g != null; g = g.Next)
{
if (hashCode == this.m_comparer.GetHashCode(g.Key) &&
this.m_comparer.Equals(key, g.Key))
{
return g;
}
}
return null;
}
public Grouping<TKey, TElement> AddItem(TKey key, TElement elem)
{
int hashCode = this.m_comparer.GetHashCode(key);
int startIdx = (hashCode & 0x7FFFFFFF) % this.m_buckets.Length;
for (Grouping<TKey, TElement> g = this.m_buckets[startIdx]; g != null; g = g.Next)
{
if (hashCode == this.m_comparer.GetHashCode(g.Key) &&
this.m_comparer.Equals(key, g.Key))
{
g.AddItem(elem);
return g;
}
}
// Add a new group for the element:
if (this.m_count == (this.m_buckets.Length * Ratio))
{
this.Resize();
startIdx = (hashCode & 0x7FFFFFFF) % this.m_buckets.Length;
}
Grouping<TKey, TElement> newGroup = new Grouping<TKey, TElement>(key);
newGroup.AddItem(elem);
newGroup.Next = this.m_buckets[startIdx];
this.m_buckets[startIdx] = newGroup;
this.m_count++;
return newGroup;
}
internal Grouping<TKey, TElement> AddItemPartial(TKey key, TElement elem)
{
int hashCode = this.m_comparer.GetHashCode(key);
int startIdx = (hashCode & 0x7FFFFFFF) % this.m_buckets.Length;
Grouping<TKey, TElement> g = this.m_buckets[startIdx];
if (g != null &&
hashCode == this.m_comparer.GetHashCode(g.Key) &&
this.m_comparer.Equals(key, g.Key) &&
g.Count() < this.m_maxGroupSize)
{
g.AddItem(elem);
return null;
}
Grouping<TKey, TElement> newGroup = new Grouping<TKey, TElement>(key);
newGroup.AddItem(elem);
this.m_buckets[startIdx] = newGroup;
if (g == null) this.m_count++;
return g;
}
private void Resize()
{
int oldSize = this.m_buckets.Length;
int newSize = CollectionHelper.GetNextPrime(oldSize);
if (newSize > oldSize)
{
Grouping<TKey, TElement>[] oldBuckets = this.m_buckets;
this.m_buckets = new Grouping<TKey, TElement>[newSize];
for (int i = 0; i < oldBuckets.Length; i++)
{
Grouping<TKey, TElement> curGroup = oldBuckets[i];
while (curGroup != null)
{
// Add the group:
Grouping<TKey, TElement> nextGroup = curGroup.Next;
int hashCode = this.m_comparer.GetHashCode(curGroup.Key);
int startIdx = (hashCode & 0x7FFFFFFF) % newSize;
curGroup.Next = this.m_buckets[startIdx];
this.m_buckets[startIdx] = curGroup;
curGroup = nextGroup;
}
}
}
}
public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator()
{
for (int i = 0; i < this.m_buckets.Length; i++)
{
Grouping<TKey, TElement> g = this.m_buckets[i];
while (g != null)
{
yield return g;
g = g.Next;
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
internal class GroupingHashSet<TResult, TElement, TKey> : IEnumerable<Grouping<TKey, TElement, TResult>>
{
private const int Ratio = 2;
private const int MaxGroupSize = 64;
private Grouping<TKey, TElement, TResult>[] m_buckets;
private IEqualityComparer<TKey> m_comparer;
private long m_count;
private long m_elemCount;
private int m_maxGroupSize;
public GroupingHashSet(IEqualityComparer<TKey> comparer)
: this(comparer, 1024, MaxGroupSize)
{
}
internal GroupingHashSet(IEqualityComparer<TKey> comparer, int capacity)
: this(comparer, capacity, MaxGroupSize)
{
}
internal GroupingHashSet(IEqualityComparer<TKey> comparer, int capacity, int maxGroupSize)
{
int size = CollectionHelper.GetNextPrime(capacity);
this.m_buckets = new Grouping<TKey, TElement, TResult>[size];
this.m_comparer = comparer;
this.m_count = 0;
this.m_elemCount = 0;
this.m_maxGroupSize = maxGroupSize;
}
public long GroupCount
{
get { return this.m_count; }
}
public long ElemCount
{
get { return this.m_elemCount; }
}
public Grouping<TKey, TElement, TResult> AddItem(TKey key, TElement elem)
{
this.m_elemCount++;
int hashCode = this.m_comparer.GetHashCode(key);
int startIdx = (hashCode & 0x7FFFFFFF) % this.m_buckets.Length;
for (Grouping<TKey, TElement, TResult> g = this.m_buckets[startIdx]; g != null; g = g.Next)
{
if (hashCode == this.m_comparer.GetHashCode(g.Key) &&
this.m_comparer.Equals(key, g.Key))
{
g.AddItem(elem);
return g;
}
}
// Add a new group for the element:
if (this.m_count == (this.m_buckets.Length * Ratio))
{
this.Resize();
startIdx = (hashCode & 0x7FFFFFFF) % this.m_buckets.Length;
}
Grouping<TKey, TElement, TResult> newGroup = new Grouping<TKey, TElement, TResult>(key);
newGroup.AddItem(elem);
newGroup.Next = this.m_buckets[startIdx];
this.m_buckets[startIdx] = newGroup;
this.m_count++;
return newGroup;
}
internal Grouping<TKey, TElement, TResult> AddItemPartial(TKey key, TElement elem)
{
this.m_elemCount++;
int hashCode = this.m_comparer.GetHashCode(key);
int startIdx = (hashCode & 0x7FFFFFFF) % this.m_buckets.Length;
Grouping<TKey, TElement, TResult> g = this.m_buckets[startIdx];
if (g != null &&
hashCode == this.m_comparer.GetHashCode(g.Key) &&
this.m_comparer.Equals(key, g.Key) &&
g.Count() < this.m_maxGroupSize)
{
g.AddItem(elem);
return null;
}
Grouping<TKey, TElement, TResult> g1 = new Grouping<TKey, TElement, TResult>(key);
g1.AddItem(elem);
this.m_buckets[startIdx] = g1;
if (g == null)
{
this.m_count++;
}
else
{
this.m_elemCount -= g.Count();
}
return g;
}
internal void Reduce(Func<IEnumerable<TElement>, TResult> resultSelector,
Func<IEnumerable<TResult>, TResult> combiner)
{
for (int i = 0; i < this.m_buckets.Length; i++)
{
Grouping<TKey, TElement, TResult> curGroup = this.m_buckets[i];
while (curGroup != null)
{
curGroup.Reduce(resultSelector, combiner);
curGroup = curGroup.Next;
}
}
this.m_elemCount = 0;
}
private void Resize()
{
int oldSize = this.m_buckets.Length;
int newSize = CollectionHelper.GetNextPrime(oldSize);
if (newSize > oldSize)
{
Grouping<TKey, TElement, TResult>[] oldBuckets = this.m_buckets;
this.m_buckets = new Grouping<TKey, TElement, TResult>[newSize];
for (int i = 0; i < oldBuckets.Length; i++)
{
Grouping<TKey, TElement, TResult> curGroup = oldBuckets[i];
while (curGroup != null)
{
// Add the group:
Grouping<TKey, TElement, TResult> nextGroup = curGroup.Next;
int hashCode = this.m_comparer.GetHashCode(curGroup.Key);
int startIdx = (hashCode & 0x7FFFFFFF) % newSize;
curGroup.Next = this.m_buckets[startIdx];
this.m_buckets[startIdx] = curGroup;
curGroup = nextGroup;
}
}
}
}
public IEnumerator<Grouping<TKey, TElement, TResult>> GetEnumerator()
{
for (int i = 0; i < this.m_buckets.Length; i++)
{
Grouping<TKey, TElement, TResult> g = this.m_buckets[i];
while (g != null)
{
yield return g;
g = g.Next;
}
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
internal static class CollectionHelper
{
private static readonly int[] primes = new int[] { 2053, 16411, 1048583, 8388617, 16777259, 33554467, 67108879 };
internal static int GetNextPrime(int p)
{
int len = primes.Length;
for (int i = 0; i < len; i++)
{
if (primes[i] > p) return primes[i];
}
return primes[len-1];
}
}
}