Skip to content

Commit

Permalink
Rename Lookup to HashLookup to avoid name conflicts with System.Linq.…
Browse files Browse the repository at this point in the history
…Lookup
  • Loading branch information
busterwood committed Mar 16, 2016
1 parent ac4f5a0 commit af97765
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 26 deletions.
8 changes: 4 additions & 4 deletions Mapper/CommandExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,23 +109,23 @@ public static async Task<Dictionary<TKey, TValue>> ToDictionaryAsync<TKey, TValu
}

/// <summary>Executes the <paramref name="cmd"/> and reads all the records in a lookup, grouped by key, using the supplied <paramref name="keyFunc"/> to generate the key</summary>
public static Lookup<TKey, TValue> ToLookup<TKey, TValue>(this IDbCommand cmd, Func<TValue, TKey> keyFunc)
public static HashLookup<TKey, TValue> ToLookup<TKey, TValue>(this IDbCommand cmd, Func<TValue, TKey> keyFunc)
{
Contract.Requires(cmd != null);
Contract.Requires(keyFunc != null);
Contract.Ensures(Contract.Result<Lookup<TKey, TValue>>() != null);
Contract.Ensures(Contract.Result<HashLookup<TKey, TValue>>() != null);
using (var reader = cmd.ExecuteReader())
{
return reader.ToLookup(keyFunc);
}
}

/// <summary>Executes the <paramref name="cmd"/> and reads all the records in a lookup, grouped by key, using the supplied <paramref name="keyFunc"/> to generate the key</summary>
public static async Task<Lookup<TKey, TValue>> ToLookupAsync<TKey, TValue>(this SqlCommand cmd, Func<TValue, TKey> keyFunc)
public static async Task<HashLookup<TKey, TValue>> ToLookupAsync<TKey, TValue>(this SqlCommand cmd, Func<TValue, TKey> keyFunc)
{
Contract.Requires(cmd != null);
Contract.Requires(keyFunc != null);
Contract.Ensures(Contract.Result<Lookup<TKey, TValue>>() != null);
Contract.Ensures(Contract.Result<HashLookup<TKey, TValue>>() != null);
using (var reader = await cmd.ExecuteReaderAsync())
{
return await reader.ToLookupAsync(keyFunc);
Expand Down
8 changes: 4 additions & 4 deletions Mapper/ConnectionExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,13 @@ public static ILookup<TKey, TValue> QueryLookup<TKey, TValue>(this IDbConnection
}

/// <summary>Executes a command using the <paramref name="sql"/> and reads all the records into a lookup</summary>
public static async Task<Lookup<TKey, TValue>> QueryLookupAsync<TKey, TValue>(this SqlConnection cnn, string sql, Func<TValue, TKey> keyFunc)
public static async Task<HashLookup<TKey, TValue>> QueryLookupAsync<TKey, TValue>(this SqlConnection cnn, string sql, Func<TValue, TKey> keyFunc)
{
Contract.Requires(cnn != null);
Contract.Requires(cnn.State == ConnectionState.Open);
Contract.Requires(!string.IsNullOrWhiteSpace(sql));
Contract.Requires(keyFunc != null);
Contract.Ensures(Contract.Result<Lookup<TKey, TValue>>() != null);
Contract.Ensures(Contract.Result<HashLookup<TKey, TValue>>() != null);
using (var cmd = cnn.CreateCommand())
{
SetupCommand(cmd, cnn, sql, null);
Expand All @@ -200,14 +200,14 @@ public static async Task<Lookup<TKey, TValue>> QueryLookupAsync<TKey, TValue>(th
}

/// <summary>Executes a command using the <paramref name="sql"/> and <paramref name="parameters"/> and reads all the records into a lookup</summary>
public static async Task<Lookup<TKey, TValue>> QueryLookupAsync<TKey, TValue>(this SqlConnection cnn, string sql, object parameters, Func<TValue, TKey> keyFunc)
public static async Task<HashLookup<TKey, TValue>> QueryLookupAsync<TKey, TValue>(this SqlConnection cnn, string sql, object parameters, Func<TValue, TKey> keyFunc)
{
Contract.Requires(cnn != null);
Contract.Requires(cnn.State == ConnectionState.Open);
Contract.Requires(!string.IsNullOrWhiteSpace(sql));
Contract.Requires(parameters != null);
Contract.Requires(keyFunc != null);
Contract.Ensures(Contract.Result<Lookup<TKey, TValue>>() != null);
Contract.Ensures(Contract.Result<HashLookup<TKey, TValue>>() != null);
using (var cmd = cnn.CreateCommand())
{
SetupCommand(cmd, cnn, sql, parameters);
Expand Down
8 changes: 4 additions & 4 deletions Mapper/DataReaderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,13 @@ public static async Task<Dictionary<TKey, TValue>> ToDictionaryAsync<TKey, TValu
}

/// <summary>Reads all the records in the lookup, group by key, using the supplied <paramref name="keyFunc"/> to generate the key</summary>
public static Lookup<TKey, TValue> ToLookup<TKey, TValue>(this IDataReader reader, Func<TValue, TKey> keyFunc)
public static HashLookup<TKey, TValue> ToLookup<TKey, TValue>(this IDataReader reader, Func<TValue, TKey> keyFunc)
{
Contract.Requires(reader != null);
Contract.Requires(keyFunc != null);
Contract.Requires(reader.IsClosed == false);
var map = GetMappingFunc<TValue>(reader);
var lookup = new Lookup<TKey, TValue>();
var lookup = new HashLookup<TKey, TValue>();
while (reader.Read())
{
TValue value = map(reader);
Expand All @@ -148,13 +148,13 @@ public static Lookup<TKey, TValue> ToLookup<TKey, TValue>(this IDataReader reade
}

/// <summary>Reads all the records in the lookup, group by key, using the supplied <paramref name="keyFunc"/> to generate the key</summary>
public static async Task<Lookup<TKey, TValue>> ToLookupAsync<TKey, TValue>(this SqlDataReader reader, Func<TValue, TKey> keyFunc)
public static async Task<HashLookup<TKey, TValue>> ToLookupAsync<TKey, TValue>(this SqlDataReader reader, Func<TValue, TKey> keyFunc)
{
Contract.Requires(reader != null);
Contract.Requires(keyFunc != null);
Contract.Requires(reader.IsClosed == false);
var map = GetMappingFunc<TValue>(reader);
var lookup = new Lookup<TKey, TValue>();
var lookup = new HashLookup<TKey, TValue>();
while (await reader.ReadAsync())
{
TValue value = map(reader);
Expand Down
60 changes: 49 additions & 11 deletions Mapper/Lookup.cs → Mapper/HashLookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,50 @@ namespace Mapper
/// <summary>
/// A key to many value dictionary data type
/// </summary>
public class Lookup<TKey, TElement> : ILookup<TKey, TElement>
public class HashLookup<TKey, TElement> : ILookup<TKey, TElement>
{
private static readonly TElement[] Empty = new TElement[0];
private readonly IEqualityComparer<TKey> _comparer;
private Grouping<TKey, TElement>[] _groupings;
private Grouping<TKey, TElement> _lastGrouping;
private int _count;

public Lookup(IEqualityComparer<TKey> comparer = null)
public HashLookup(IEqualityComparer<TKey> comparer = null)
{
_comparer = comparer ?? EqualityComparer<TKey>.Default;
_groupings = new Grouping<TKey, TElement>[7];
}

/// <summary>Gets the number of groupings (unique keys) in the <see cref="HashLookup{TKey,TElement}"/>.</summary>
/// <remarks>Does NOT return the number of items in the lookup</remarks>
public int Count => _count;

public void Add(TKey key, TElement item)
/// <summary>
/// Add an <paramref name="element"/> to the lookup using supplied <paramref name="key"/>
/// </summary>
public void Add(TKey key, TElement element)
{
GetGrouping(key, create: true).Add(item);
GetOrAddGrouping(key).Add(element);
}

/// <summary>
/// Add some <paramref name="items"/> to the lookup using the <paramref name="keyFunc"/> to get the key for each element
/// </summary>
public void AddRange(IEnumerable<TElement> items, Func<TElement, TKey> keyFunc)
{
Contract.Requires(items != null);
Contract.Requires(keyFunc != null);

TKey lastKey = default(TKey);
Grouping<TKey, TElement> grouping = null;
foreach (var element in items)
{
var key = keyFunc(element);
if (grouping == null || _comparer.Equals(key, lastKey) == false)
grouping = GetOrAddGrouping(key);
grouping.Add(element);
lastKey = key;
}
}

/// <summary>Gets the <see cref="T:System.Collections.Generic.IEnumerable`1"/> sequence of values indexed by a specified key.</summary>
Expand All @@ -42,14 +67,20 @@ public IEnumerable<TElement> this[TKey key]
{
get
{
Grouping<TKey, TElement> grouping = GetGrouping(key, create: false);
Contract.Ensures(Contract.Result<IEnumerable<TElement>>() != null);
int hashCode = InternalGetHashCode(key);
Grouping<TKey, TElement> grouping = FindGrouping(key, hashCode);
return grouping ?? (IEnumerable<TElement>) Empty;
}
}

/// <summary>
/// Determines whether a specified key exists in the <see cref="HashLookup{TKey,TElement}"/>.
/// </summary>
public bool Contains(TKey key)
{
return GetGrouping(key, create: false) != null;
int hashCode = InternalGetHashCode(key);
return FindGrouping(key, hashCode) != null;
}

public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator()
Expand Down Expand Up @@ -77,20 +108,27 @@ internal int InternalGetHashCode(TKey key)
return (key == null) ? 0 : _comparer.GetHashCode(key) & 0x7FFFFFFF;
}

internal Grouping<TKey, TElement> GetGrouping(TKey key, bool create)
internal Grouping<TKey, TElement> GetOrAddGrouping(TKey key)
{
int hashCode = InternalGetHashCode(key);
for (Grouping<TKey, TElement> grouping = _groupings[hashCode % _groupings.Length]; grouping != null; grouping = grouping._hashNext)
var grouping = FindGrouping(key, hashCode);
return grouping ?? AddGrouping(key, hashCode);
}

private Grouping<TKey, TElement> FindGrouping(TKey key, int hashCode)
{
for (Grouping<TKey, TElement> grouping = _groupings[hashCode%_groupings.Length]; grouping != null; grouping = grouping._hashNext)
{
if (grouping._hashCode == hashCode && _comparer.Equals(grouping._key, key))
{
return grouping;
}
}
return null;
}

if (!create)
return null;

private Grouping<TKey, TElement> AddGrouping(TKey key, int hashCode)
{
if (_count == _groupings.Length)
{
Resize();
Expand Down
2 changes: 1 addition & 1 deletion Mapper/Mapper.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Grouping.cs" />
<Compile Include="Lookup.cs" />
<Compile Include="HashLookup.cs" />
<Compile Include="Names.cs" />
<Compile Include="SqlDataRecordExtensions.cs" />
<Compile Include="CommandExtension.cs" />
Expand Down
2 changes: 1 addition & 1 deletion Mapper/Mapper.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<package >
<metadata>
<id>Mapper</id>
<version>1.0.1.0</version>
<version>1.0.1.1</version>
<authors>BusterWood</authors>
<description>A convention-based object cloner, object-object mapper (like AutoMapper), IDataReader to object mapper, object to IDbDataParameter mapper, etc.</description>
<projectUrl>https://github.com/busterwood/mapper</projectUrl>
Expand Down
2 changes: 1 addition & 1 deletion Mapper/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyFileVersion("1.0.1.1")]

[assembly: InternalsVisibleTo("Mapper.UnitTests")]

0 comments on commit af97765

Please sign in to comment.