using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Threading;
public partial class LockFreeDictionary<K, V> : IDictionary<K, V>
where K : IEquatable<K>
where V : IEquatable<V>
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
uint _check_key(ref K key, out int mtid)
{
if (Config.EntryBlock.Entry.f_key_null_check && key == null)
throw new ArgumentNullException("key");
mtid = -1;
m_config.CheckAssist(ref mtid);
/// hash zero indicates a freelist entry so ensure that it's not used
uint h = (uint)key.GetHashCode();
return h == 0 ? 1 : h;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Obtain a chain head that doesn't contain the key and attempt to atomically insert the new Entry into it.
/// If the atomic operation fails, start over.
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool _try_add(ref K key, V value)
{
int mtid;
uint h = _check_key(ref key, out mtid);
Config.EntryBlock.Entry e_new = new Config.EntryBlock.Entry(h, key, value);
while (true)
{
Config.BucketList.BucketHead bh;
if (!m_config.m_buckets.GetBucketHead(ref mtid, h, out bh))
continue;
int gx;
if (!bh.TryFindKey(h, key, out gx))
continue;
if (gx != -1)
return false;
if (bh.TryInsertFirstItem(ref mtid, ref e_new))
{
bh.Config.IncrementCountAndCheck(ref mtid);
return true;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Obtain a chain head that doesn't contain the key and attempt to atomically insert the new Entry into it.
/// If the atomic operation fails, start over.
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
V _transact_get_add(ref K key, V in_value)
{
int mtid;
uint h = _check_key(ref key, out mtid);
Config.EntryBlock.Entry e_new = new Config.EntryBlock.Entry(h, key, in_value);
while (true)
{
Config.BucketList.BucketHead bh;
int gx;
if (m_config.m_buckets.GetBucketHead(ref mtid, h, out bh) && bh.TryFindKey(h, key, out gx))
{
/// get
if (gx != -1)
{
V out_value;
if (bh.TryGetValue(gx, out out_value))
return out_value;
}
/// add
if (bh.TryInsertFirstItem(ref mtid, ref e_new))
{
bh.Config.IncrementCountAndCheck(ref mtid);
return in_value;
}
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool _try_get(ref K key, out V out_value)
{
int mtid;
uint h = _check_key(ref key, out mtid);
while (true)
{
Config.BucketList.BucketHead bh;
int gx;
if (m_config.m_buckets.GetBucketHead(ref mtid, h, out bh) && bh.TryFindKey(h, key, out gx))
{
if (gx == -1)
{
out_value = default(V);
return false;
}
if (bh.TryGetValue(gx, out out_value))
return true;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool _try_remove(ref K key, out V out_value)
{
int mtid;
uint h = _check_key(ref key, out mtid);
while (true)
{
Config.BucketList.BucketHead bh;
if (!m_config.m_buckets.GetBucketHead(ref mtid, h, out bh))
continue;
int c = bh.CapturedEntryCount;
if (c == 0)
break;
int gx_found, i, gx;
if (!bh.TryFindKey(h, ref key, out gx_found, out i, out gx))
continue;
if (gx_found == -1)
break;
if (!bh.TryGetValue(gx_found, out out_value))
continue;
TryResult tr = TryResult.Impossible;
if (c == 1)
{
/// remove the only one
gx = -1;
/// continues below...
}
else if (i == 0 || (tr = bh.CanCarouselTo(gx, gx_found, ref bh)) != TryResult.Impossible)
{
if (tr == TryResult.Expired)
continue;
/// remove the first one
gx = bh.Config.GetNextHot(gx_found);
/// continues below...
}
else if (i == c - 1 || bh.TryRotateToEnd(ref mtid, gx, i, ref bh))
{
/// remove the last one by decrementing the count
gx = bh.CapturedFirstEntryIndex;
/// continues below...
}
else
continue;
/// ...final update
if (bh.TryUpdate(gx, c - 1))
{
bh.Config.ReleaseIndex(ref mtid, gx_found);
Interlocked.Decrement(ref bh.Config.m_count);
return true;
}
}
/// nothing to remove
out_value = default(V);
return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool _try_update(ref K key, ref V value)
{
int mtid;
uint h = _check_key(ref key, out mtid);
Config.EntryBlock.Entry e_update = new Config.EntryBlock.Entry(h, key, value);
while (true)
{
Config.BucketList.BucketHead bh;
if (!m_config.m_buckets.GetBucketHead(ref mtid, h, out bh))
continue;
int c = bh.CapturedEntryCount;
if (c == 0)
return false;
int gx_found, i, gx_last;
if (!bh.TryFindKey(h, ref key, out gx_found, out i, out gx_last))
continue;
if (gx_found == -1)
return false;
Config cfg = bh.Config;
if ((cfg.d.m_options & Options.CheckForVacuousValueUpdates) > 0)
{
V cur_val;
if (bh.TryGetValue(gx_found, out cur_val) && Config.EntryBlock.Entry.CompareValues(cur_val, value))
return true;
}
TryResult tr = TryResult.Impossible;
if (c == 1)
{
e_update.gx_next = -1;
/// continues below...
}
else if (i == 0 || (tr = bh.CanCarouselTo(gx_last, gx_found, ref bh)) != TryResult.Impossible)
{
if (tr == TryResult.Expired)
continue;
e_update.gx_next = cfg.GetNextHot(bh.CapturedFirstEntryIndex);
/// continues below...
}
else if (i == c - 1 || bh.TryRotateToEnd(ref mtid, gx_last, i, ref bh))
{
e_update.gx_next = bh.CapturedFirstEntryIndex;
/// continues below...
}
else
continue;
/// ...try e_update
if (bh.TryReplaceFirst(ref mtid, ref e_update))
{
cfg.ReleaseIndex(ref mtid, gx_found);
return true;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
///
/// </summary>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool _transact_update(ref K key, ref V in_value, ref V cmp_value)
{
int mtid;
uint h = _check_key(ref key, out mtid);
Config.EntryBlock.Entry e_update = new Config.EntryBlock.Entry(h, key, in_value);
while (true)
{
Config.BucketList.BucketHead bh;
if (!m_config.m_buckets.GetBucketHead(ref mtid, h, out bh))
continue;
int c = bh.CapturedEntryCount;
if (c == 0)
return false;
int gx_found, i, gx_last;
if (!bh.TryFindKey(h, ref key, out gx_found, out i, out gx_last))
continue;
if (gx_found == -1)
return false;
V cur_val;
if (!bh.TryGetValue(gx_found, out cur_val))
continue;
if (!Config.EntryBlock.Entry.CompareValues(cur_val, cmp_value))
return false;
Config cfg = bh.Config;
if ((cfg.d.m_options & Options.CheckForVacuousValueUpdates) > 0 && Config.EntryBlock.Entry.CompareValues(in_value, cur_val))
return true;
TryResult tr = TryResult.Impossible;
if (c == 1)
{
e_update.gx_next = -1;
/// continues below...
}
else if (i == 0 || (tr = bh.CanCarouselTo(gx_last, gx_found, ref bh)) != TryResult.Impossible)
{
if (tr == TryResult.Expired)
continue;
e_update.gx_next = cfg.GetNextHot(bh.CapturedFirstEntryIndex);
/// continues below...
}
else if (i == c - 1 || bh.TryRotateToEnd(ref mtid, gx_last, i, ref bh))
{
e_update.gx_next = bh.CapturedFirstEntryIndex;
/// continues below...
}
else
continue;
/// ...try e_update
if (bh.TryReplaceFirst(ref mtid, ref e_update))
{
cfg.ReleaseIndex(ref mtid, gx_found);
return true;
}
}
}
};