diff --git a/CHANGELOG.md b/CHANGELOG.md
index 63d0985b..abd13f7d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,16 +4,20 @@
[Full Changelog](https://github.com/nanoframework/lib-CoreLibrary/compare/v1.1.0...HEAD)
+**Fixed bugs:**
+
+- Major fix on HashTable [\#64](https://github.com/nanoframework/lib-CoreLibrary/pull/64)
+
**Documentation and other chores:**
-- Release 1.1.0 [\#62](https://github.com/nanoframework/lib-CoreLibrary/pull/62)
+- Merge back from Release v1.1.0 [\#63](https://github.com/nanoframework/lib-CoreLibrary/pull/63)
## [v1.1.0](https://github.com/nanoframework/lib-CoreLibrary/tree/v1.1.0) (2018-12-14)
[Full Changelog](https://github.com/nanoframework/lib-CoreLibrary/compare/v1.0.6-preview-021...v1.1.0)
**Documentation and other chores:**
-- Release v1.1.0 [\#60](https://github.com/nanoframework/lib-CoreLibrary/pull/60)
+- Release 1.1.0 [\#62](https://github.com/nanoframework/lib-CoreLibrary/pull/62)
## [v1.0.6-preview-021](https://github.com/nanoframework/lib-CoreLibrary/tree/v1.0.6-preview-021) (2018-11-30)
[Full Changelog](https://github.com/nanoframework/lib-CoreLibrary/compare/v1.0.6-preview-019...v1.0.6-preview-021)
diff --git a/source/nanoFramework.CoreLibrary/System/Collections/HashTable.cs b/source/nanoFramework.CoreLibrary/System/Collections/HashTable.cs
index 154d747a..82c7d654 100644
--- a/source/nanoFramework.CoreLibrary/System/Collections/HashTable.cs
+++ b/source/nanoFramework.CoreLibrary/System/Collections/HashTable.cs
@@ -19,15 +19,15 @@ public class Hashtable : ICloneable, IDictionary
private int _loadFactor;
private int _maxLoadFactor;
private double _growthFactor;
- private const int HashTableDefaultCapacity = 4;
- private const int HashTableDefaultLoadFactor = 2;
+ private const int _defaultCapacity = 4;
+ private const int _defaultLoadFactor = 2;
///
/// Initializes a new, empty instance of the Hashtable class using the default initial capacity and load factor.
///
public Hashtable()
{
- InitializeHashTable(HashTableDefaultCapacity, HashTableDefaultLoadFactor);
+ InitializeHashTable(_defaultCapacity, _defaultLoadFactor);
}
///
@@ -37,7 +37,7 @@ public Hashtable()
/// The initial capacity of the HashTable
public Hashtable(int capacity)
{
- InitializeHashTable(capacity, HashTableDefaultLoadFactor);
+ InitializeHashTable(capacity, _defaultLoadFactor);
}
///
@@ -89,15 +89,21 @@ private void Add(ref Entry[] buckets, object key, object value, bool overwrite)
var match = EntryForKey(key, buckets[whichBucket]);
if (match != null && overwrite)
- { //i.e. already exists in table
+ {
+ //i.e. already exists in table
match.value = value;
return;
}
- if (match != null && !overwrite) throw new ArgumentException("key exists");
- // insert at front
- var newOne = new Entry(key, value, ref buckets[whichBucket]);
- buckets[whichBucket] = newOne;
- _count++;
+ else if ((match != null && !overwrite))
+ {
+ throw new ArgumentException("key exists");
+ }
+ else
+ { // insert at front
+ var newOne = new Entry(key, value, ref buckets[whichBucket]);
+ buckets[whichBucket] = newOne;
+ _count++;
+ }
_loadFactor = _count / _numberOfBuckets;
}
@@ -107,7 +113,11 @@ private int Hash(object key, int numOfBuckets)
{
var hashcode = key.GetHashCode();
- if (hashcode < 0) hashcode = hashcode * -1; // don't know how to mod with a negative number
+ if (hashcode < 0)
+ {
+ // don't know how to mod with a negative number
+ hashcode = hashcode * -1;
+ }
return hashcode % numOfBuckets;
}
@@ -115,43 +125,60 @@ private int Hash(object key, int numOfBuckets)
//looks up value in bucket
private Entry EntryForKey(object key, Entry head)
{
- for (var cur = head; cur != null; cur = cur.next)
- if (cur.key.Equals(key)) return cur;
+ for (Entry cur = head; cur != null; cur = cur.next)
+ {
+ if (cur.key.Equals(key))
+ {
+ return cur;
+ }
+ }
+
return null;
}
//Rehashes the table to reduce the load factor
private void Rehash(int newSize)
{
- var newTable = new Entry[newSize];
+ Entry[] newTable = new Entry[newSize];
_numberOfBuckets = newSize;
_count = 0;
+
for (var i = 0; i < _buckets.Length; i++)
{
if (_buckets[i] != null)
{
- for (var cur = _buckets[i]; cur != null; cur = cur.next)
+ for (Entry cur = _buckets[i]; cur != null; cur = cur.next)
+ {
Add(ref newTable, cur.key, cur.value, false);
+ }
}
}
+
_buckets = newTable;
}
//implementation for KeyCollection and ValueCollection copyTo method
private void CopyToCollection(Array array, int index, EnumeratorType type)
{
- if (index < 0 || index >= array.Length) throw new IndexOutOfRangeException("index");
- if ((index + Count) > array.Length) throw new IndexOutOfRangeException("array length");
-
- var j = index;
- var len = array.Length;
+ if (index < 0 && index > _numberOfBuckets)
+ {
+ throw new IndexOutOfRangeException("index");
+ }
- for (var i = 0; i < _numberOfBuckets; i++)
+ for (int i = index; i < _numberOfBuckets; i++)
{
- for (var cur = _buckets[i]; cur != null && j < len; cur = cur.next)
+ var j = 0;
+
+ for (Entry cur = _buckets[i]; cur != null && j < array.Length; cur = cur.next)
{
- if (type == EnumeratorType.KEY) ((IList)array)[j] = cur.key;
- else ((IList)array)[j] = cur.value;
+ if (type == EnumeratorType.KEY)
+ {
+ ((IList)array)[j] = cur.key;
+ }
+ else
+ {
+ ((IList)array)[j] = cur.value;
+ }
j++;
}
@@ -230,18 +257,16 @@ public object SyncRoot
/// The zero-based index in array at which copying begins.
public void CopyTo(Array array, int index)
{
- if (index < 0 || index >= array.Length) throw new IndexOutOfRangeException("index");
- if ((index + _count) > array.Length) throw new IndexOutOfRangeException("array length");
+ if (index < 0 && index > _buckets.Length)
+ throw new IndexOutOfRangeException("index");
- var j = index;
- var len = array.Length;
-
- for (var i = 0; i < _numberOfBuckets; i++)
+ for (int i = index; i < _buckets.Length; i++)
{
- for (var cur = _buckets[i]; cur != null && j < len; cur = cur.next)
+ var j = 0;
+
+ for (Entry cur = _buckets[i]; cur != null && j < array.Length; cur = cur.next)
{
((IList)array)[j] = new DictionaryEntry(cur.key, cur.value);
-
j++;
}
}
@@ -310,18 +335,34 @@ public object this[object key]
{
get
{
- if (key == null) throw new ArgumentNullException("key is null");
+ if (key == null)
+ {
+ throw new ArgumentNullException("key is null");
+ }
+
var whichBucket = Hash(key, _numberOfBuckets);
var match = EntryForKey(key, _buckets[whichBucket]);
- return match != null ? match.value : null;
+ if (match != null)
+ {
+ return match.value;
+ }
+
+ return null;
}
set
{
- if (key == null) throw new ArgumentNullException("key is null");
+ if (key == null)
+ {
+ throw new ArgumentNullException("key is null");
+ }
+
+ Add(ref _buckets ,key,value,true);
- Add(ref _buckets, key, value, true);
- if (_loadFactor >= _maxLoadFactor) Rehash((int)(_numberOfBuckets * _growthFactor));
+ if (_loadFactor >= _maxLoadFactor)
+ {
+ Rehash((int)(_numberOfBuckets * _growthFactor));
+ }
}
}
@@ -335,7 +376,11 @@ public void Add(object key, object value)
if (key == null) throw new ArgumentNullException("key is null");
Add(ref _buckets, key, value, false);
- if (_loadFactor >= _maxLoadFactor) Rehash((int)(_numberOfBuckets * _growthFactor));
+
+ if (_loadFactor >= _maxLoadFactor)
+ {
+ Rehash((int)(_numberOfBuckets * _growthFactor));
+ }
}
///
@@ -343,8 +388,8 @@ public void Add(object key, object value)
///
public void Clear()
{
- _buckets = new Entry[HashTableDefaultCapacity];
- _numberOfBuckets = HashTableDefaultCapacity;
+ _buckets = new Entry[_defaultCapacity];
+ _numberOfBuckets = _defaultCapacity;
_loadFactor = 0;
_count = 0;
}
@@ -356,11 +401,20 @@ public void Clear()
/// true if the IDictionary contains an element with the key; otherwise, false.
public bool Contains(object key)
{
- if (key == null) throw new ArgumentNullException("key is null");
+ if (key == null)
+ {
+ throw new ArgumentNullException("key is null");
+ }
+
var whichBucket = Hash(key, _numberOfBuckets);
var match = EntryForKey(key, _buckets[whichBucket]);
- return match != null;
+ if (match != null)
+ {
+ return true;
+ }
+
+ return false;
}
///
@@ -369,12 +423,19 @@ public bool Contains(object key)
/// The key of the element to remove.
public void Remove(object key)
{
- if (key == null) throw new ArgumentNullException("key is null");
+ if (key == null)
+ {
+ throw new ArgumentNullException("key is null");
+ }
+
var whichBucket = Hash(key, _numberOfBuckets);
var match = EntryForKey(key, _buckets[whichBucket]);
//does entry exist?
- if (match == null) return;
+ if (match == null)
+ {
+ return;
+ }
//is entry at front?
if (_buckets[whichBucket] == match)
@@ -385,7 +446,7 @@ public void Remove(object key)
}
//handle entry in middle and at the end
- for (var cur = _buckets[whichBucket]; cur != null; cur = cur.next)
+ for (Entry cur = _buckets[whichBucket]; cur != null; cur = cur.next)
{
if (cur.next == match)
{
@@ -400,7 +461,7 @@ public void Remove(object key)
private class Entry
{
- public readonly Object key;
+ public Object key;
public Object value;
public Entry next;
@@ -414,15 +475,15 @@ public Entry(object key, object value, ref Entry n)
private class HashtableEnumerator : IEnumerator
{
- private readonly Hashtable _ht;
- private Entry _temp;
- private Int32 _index = -1;
- private readonly EnumeratorType _returnType;
+ Hashtable ht;
+ Entry temp;
+ Int32 index = -1;
+ EnumeratorType returnType;
public HashtableEnumerator(Hashtable hashtable, EnumeratorType type)
{
- _ht = hashtable;
- _returnType = type;
+ ht = hashtable;
+ returnType = type;
}
// Return the current item.
@@ -430,44 +491,59 @@ public Object Current
{
get
{
- switch (_returnType)
+ switch (returnType)
{
case EnumeratorType.DE:
- return new DictionaryEntry(_temp.key, _temp.value);
+ return new DictionaryEntry(temp.key, temp.value);
case EnumeratorType.KEY:
- return _temp.key;
+ return temp.key;
case EnumeratorType.VALUE:
- return _temp.value;
+ return temp.value;
+
+ default:
+ break;
}
- return new DictionaryEntry(_temp.key, _temp.value);
+ return new DictionaryEntry(temp.key, temp.value);
}
}
// Advance to the next item.
public Boolean MoveNext()
{
-startLoop:
-//iterate index or list
- if (_temp == null)
+ startLoop:
+ //iterate index or list
+ if (temp == null)
+ {
+ index++;
+ if (index < ht._numberOfBuckets)
+ {
+ temp = ht._buckets[index];
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
{
- _index++;
- if (_index < _ht._numberOfBuckets) _temp = _ht._buckets[_index];
- else return false;
+ temp = temp.next;
}
- else _temp = _temp.next;
//null check
- if (_temp == null) goto startLoop;
-
+ if (temp == null)
+ {
+ goto startLoop;
+ }
+
return true;
}
// Reset the index to restart the enumeration.
public void Reset()
{
- _index = -1;
+ index = -1;
}
}
@@ -484,11 +560,11 @@ private enum EnumeratorType
private class KeyCollection : ICollection
{
- private readonly Hashtable _ht;
+ Hashtable ht;
- public KeyCollection(Hashtable hashtable)
+ public KeyCollection(Hashtable hashtable)
{
- _ht = hashtable;
+ ht = hashtable;
}
#region ICollection Members
@@ -497,7 +573,7 @@ public int Count
{
get
{
- return _ht._count;
+ return ht._count;
}
}
@@ -505,7 +581,7 @@ public bool IsSynchronized
{
get
{
- return _ht.IsSynchronized;
+ return ht.IsSynchronized;
}
}
@@ -513,13 +589,13 @@ public object SyncRoot
{
get
{
- return _ht.SyncRoot;
+ return ht.SyncRoot;
}
}
public void CopyTo(Array array, int index)
{
- _ht.CopyToCollection(array, index, EnumeratorType.KEY);
+ ht.CopyToCollection(array, index, EnumeratorType.KEY);
}
#endregion
@@ -528,7 +604,7 @@ public void CopyTo(Array array, int index)
public IEnumerator GetEnumerator()
{
- return new HashtableEnumerator(_ht, EnumeratorType.KEY);
+ return new HashtableEnumerator(ht, EnumeratorType.KEY);
}
#endregion
@@ -536,11 +612,11 @@ public IEnumerator GetEnumerator()
private class ValueCollection : ICollection
{
- private readonly Hashtable _ht;
+ Hashtable ht;
public ValueCollection(Hashtable hashtable)
{
- _ht = hashtable;
+ ht = hashtable;
}
#region ICollection Members
@@ -549,7 +625,7 @@ public int Count
{
get
{
- return _ht._count;
+ return ht._count;
}
}
@@ -557,7 +633,7 @@ public bool IsSynchronized
{
get
{
- return _ht.IsSynchronized;
+ return ht.IsSynchronized;
}
}
@@ -565,13 +641,13 @@ public object SyncRoot
{
get
{
- return _ht.SyncRoot;
+ return ht.SyncRoot;
}
}
public void CopyTo(Array array, int index)
{
- _ht.CopyToCollection(array, index, EnumeratorType.VALUE);
+ ht.CopyToCollection(array, index, EnumeratorType.VALUE);
}
#endregion
@@ -580,7 +656,7 @@ public void CopyTo(Array array, int index)
public IEnumerator GetEnumerator()
{
- return new HashtableEnumerator(_ht, EnumeratorType.VALUE);
+ return new HashtableEnumerator(ht, EnumeratorType.VALUE);
}
#endregion
diff --git a/source/version.json b/source/version.json
index 51a7e9dc..48e10b5f 100644
--- a/source/version.json
+++ b/source/version.json
@@ -1,6 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
- "version": "1.1.0",
+ "version": "1.1.1",
"assemblyVersion": {
"precision": "revision"
},
@@ -16,4 +16,4 @@
"setVersionVariables": true,
"setAllVariables": true
}
-}
\ No newline at end of file
+}