You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
563 lines
23 KiB
563 lines
23 KiB
// Needed for NET40 |
|
#if !NET_4_6 |
|
using System; |
|
|
|
namespace LinqInternal.Collections.ThreadSafe |
|
{ |
|
internal static class BucketHelper |
|
{ |
|
private static readonly object _null; |
|
|
|
static BucketHelper() |
|
{ |
|
_null = new object(); |
|
} |
|
|
|
internal static object Null |
|
{ |
|
get { return _null; } |
|
} |
|
|
|
public static T GetOrInsert<T>(this IBucket<T> bucket, int index, T item) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
T previous; |
|
if (bucket.Insert(index, item, out previous)) |
|
{ |
|
return item; |
|
} |
|
return previous; |
|
} |
|
|
|
public static T GetOrInsert<T>(this IBucket<T> bucket, int index, Func<T> itemFactory) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
T stored; |
|
if (!bucket.TryGet(index, out stored)) |
|
{ |
|
var created = itemFactory.Invoke(); |
|
if (bucket.Insert(index, created, out stored)) |
|
{ |
|
return created; |
|
} |
|
} |
|
return stored; |
|
} |
|
|
|
/// <summary> |
|
/// Inserts or replaces the item at the specified index. |
|
/// </summary> |
|
/// <param name="bucket">The bucket on which to operate.</param> |
|
/// <param name="index">The index.</param> |
|
/// <param name="item">The item set.</param> |
|
/// <param name="itemUpdateFactory">The item factory to create the item to replace with.</param> |
|
/// <param name="check">A predicate to decide if a particular item should be replaced.</param> |
|
/// <returns> |
|
/// <c>true</c> if the item or repalced inserted; otherwise, <c>false</c>. |
|
/// </returns> |
|
/// <exception cref="System.ArgumentOutOfRangeException">index;index must be greater or equal to 0 and less than capacity</exception> |
|
/// <remarks> |
|
/// The operation will be attempted as long as check returns true - this operation may starve. |
|
/// </remarks> |
|
public static bool InsertOrUpdate<T>(this IBucket<T> bucket, int index, T item, Func<T, T> itemUpdateFactory, Predicate<T> check) |
|
{ |
|
bool isNew; |
|
return InsertOrUpdate(bucket, index, item, itemUpdateFactory, check, out isNew); |
|
} |
|
|
|
/// <summary> |
|
/// Inserts or replaces the item at the specified index. |
|
/// </summary> |
|
/// <param name="bucket">The bucket on which to operate.</param> |
|
/// <param name="index">The index.</param> |
|
/// <param name="item">The item insert.</param> |
|
/// <param name="itemUpdateFactory">The item factory to create the item to replace with.</param> |
|
/// <param name="check">A predicate to decide if a particular item should be replaced.</param> |
|
/// <param name="isNew">if set to <c>true</c> the index was not previously used.</param> |
|
/// <returns> |
|
/// <c>true</c> if the item or repalced inserted; otherwise, <c>false</c>. |
|
/// </returns> |
|
/// <exception cref="System.ArgumentOutOfRangeException">index;index must be greater or equal to 0 and less than capacity</exception> |
|
/// <remarks> |
|
/// The operation will be attempted as long as check returns true - this operation may starve. |
|
/// </remarks> |
|
public static bool InsertOrUpdate<T>(this IBucket<T> bucket, int index, T item, Func<T, T> itemUpdateFactory, Predicate<T> check, out bool isNew) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
isNew = true; |
|
while (true) |
|
{ |
|
if (isNew) |
|
{ |
|
T stored; |
|
if (bucket.Insert(index, item, out stored)) |
|
{ |
|
return true; |
|
} |
|
isNew = false; |
|
} |
|
else |
|
{ |
|
if (bucket.Update(index, itemUpdateFactory, check, out isNew)) |
|
{ |
|
return true; |
|
} |
|
if (!isNew) |
|
{ |
|
return false; // returns false only when check returns false |
|
} |
|
} |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Inserts or replaces the item at the specified index. |
|
/// </summary> |
|
/// <param name="bucket">The bucket on which to operate.</param> |
|
/// <param name="index">The index.</param> |
|
/// <param name="item">The item set.</param> |
|
/// <param name="itemUpdateFactory">The item factory to create the item to replace with.</param> |
|
/// <exception cref="System.ArgumentOutOfRangeException">index;index must be greater or equal to 0 and less than capacity</exception> |
|
/// <remarks> |
|
/// The operation will be attempted as long as check returns true - this operation may starve. |
|
/// </remarks> |
|
public static void InsertOrUpdate<T>(this IBucket<T> bucket, int index, T item, Func<T, T> itemUpdateFactory) |
|
{ |
|
bool isNew; |
|
InsertOrUpdate(bucket, index, item, itemUpdateFactory, out isNew); |
|
} |
|
|
|
/// <summary> |
|
/// Inserts or replaces the item at the specified index. |
|
/// </summary> |
|
/// <param name="bucket">The bucket on which to operate.</param> |
|
/// <param name="index">The index.</param> |
|
/// <param name="item">The item insert.</param> |
|
/// <param name="itemUpdateFactory">The item factory to create the item to replace with.</param> |
|
/// <param name="isNew">if set to <c>true</c> the index was not previously used.</param> |
|
/// <exception cref="System.ArgumentOutOfRangeException">index;index must be greater or equal to 0 and less than capacity</exception> |
|
/// <remarks> |
|
/// The operation will be attempted as long as check returns true - this operation may starve. |
|
/// </remarks> |
|
public static void InsertOrUpdate<T>(this IBucket<T> bucket, int index, T item, Func<T, T> itemUpdateFactory, out bool isNew) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
isNew = true; |
|
while (true) |
|
{ |
|
if (isNew) |
|
{ |
|
T stored; |
|
if (bucket.Insert(index, item, out stored)) |
|
{ |
|
return; |
|
} |
|
isNew = false; |
|
} |
|
else |
|
{ |
|
if (bucket.Update(index, itemUpdateFactory, Tautology, out isNew)) |
|
{ |
|
return; |
|
} |
|
} |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Inserts or replaces the item at the specified index. |
|
/// </summary> |
|
/// <param name="bucket">The bucket on which to operate.</param> |
|
/// <param name="index">The index.</param> |
|
/// <param name="item">The item set.</param> |
|
/// <param name="check">A predicate to decide if a particular item should be replaced.</param> |
|
/// <returns> |
|
/// <c>true</c> if the item or repalced inserted; otherwise, <c>false</c>. |
|
/// </returns> |
|
/// <exception cref="System.ArgumentOutOfRangeException">index;index must be greater or equal to 0 and less than capacity</exception> |
|
/// <remarks> |
|
/// The operation will be attempted as long as check returns true - this operation may starve. |
|
/// </remarks> |
|
public static bool InsertOrUpdate<T>(this IBucket<T> bucket, int index, T item, Predicate<T> check) |
|
{ |
|
bool isNew; |
|
return InsertOrUpdate(bucket, index, item, check, out isNew); |
|
} |
|
|
|
/// <summary> |
|
/// Inserts or replaces the item at the specified index. |
|
/// </summary> |
|
/// <param name="bucket">The bucket on which to operate.</param> |
|
/// <param name="index">The index.</param> |
|
/// <param name="item">The item set.</param> |
|
/// <param name="check">A predicate to decide if a particular item should be replaced.</param> |
|
/// <param name="isNew">if set to <c>true</c> the index was not previously used.</param> |
|
/// <returns> |
|
/// <c>true</c> if the item or repalced inserted; otherwise, <c>false</c>. |
|
/// </returns> |
|
/// <exception cref="System.ArgumentOutOfRangeException">index;index must be greater or equal to 0 and less than capacity</exception> |
|
/// <remarks> |
|
/// The operation will be attempted as long as check returns true - this operation may starve. |
|
/// </remarks> |
|
public static bool InsertOrUpdate<T>(this IBucket<T> bucket, int index, T item, Predicate<T> check, out bool isNew) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
isNew = true; |
|
while (true) |
|
{ |
|
if (isNew) |
|
{ |
|
T stored; |
|
if (bucket.Insert(index, item, out stored)) |
|
{ |
|
return true; |
|
} |
|
isNew = false; |
|
} |
|
else |
|
{ |
|
if (bucket.Update(index, _ => item, check, out isNew)) |
|
{ |
|
return true; |
|
} |
|
if (!isNew) |
|
{ |
|
return false; // returns false only when check returns false |
|
} |
|
} |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Inserts or replaces the item at the specified index. |
|
/// </summary> |
|
/// <param name="bucket">The bucket on which to operate.</param> |
|
/// <param name="index">The index.</param> |
|
/// <param name="itemFactory">The item factory to create the item to insert.</param> |
|
/// <param name="itemUpdateFactory">The item factory to create the item to replace with.</param> |
|
/// <param name="check">A predicate to decide if a particular item should be replaced.</param> |
|
/// <returns> |
|
/// <c>true</c> if the item or repalced inserted; otherwise, <c>false</c>. |
|
/// </returns> |
|
/// <exception cref="System.ArgumentOutOfRangeException">index;index must be greater or equal to 0 and less than capacity</exception> |
|
/// <remarks> |
|
/// The operation will be attempted as long as check returns true - this operation may starve. |
|
/// </remarks> |
|
public static bool InsertOrUpdate<T>(this IBucket<T> bucket, int index, Func<T> itemFactory, Func<T, T> itemUpdateFactory, Predicate<T> check) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
bool isNew; |
|
return InsertOrUpdate(bucket, index, itemFactory, itemUpdateFactory, check, out isNew); |
|
} |
|
|
|
/// <summary> |
|
/// Inserts or replaces the item at the specified index. |
|
/// </summary> |
|
/// <param name="bucket">The bucket on which to operate.</param> |
|
/// <param name="index">The index.</param> |
|
/// <param name="itemFactory">The item factory to create the item to insert.</param> |
|
/// <param name="itemUpdateFactory">The item factory to create the item to replace with.</param> |
|
/// <param name="check">A predicate to decide if a particular item should be replaced.</param> |
|
/// <param name="isNew">if set to <c>true</c> the index was not previously used.</param> |
|
/// <returns> |
|
/// <c>true</c> if the item or repalced inserted; otherwise, <c>false</c>. |
|
/// </returns> |
|
/// <exception cref="System.ArgumentOutOfRangeException">index;index must be greater or equal to 0 and less than capacity</exception> |
|
/// <remarks> |
|
/// The operation will be attempted as long as check returns true - this operation may starve. |
|
/// </remarks> |
|
public static bool InsertOrUpdate<T>(this IBucket<T> bucket, int index, Func<T> itemFactory, Func<T, T> itemUpdateFactory, Predicate<T> check, out bool isNew) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
isNew = true; |
|
var factoryUsed = false; |
|
var created = default(T); |
|
while (true) |
|
{ |
|
if (isNew) |
|
{ |
|
T stored; |
|
if (!factoryUsed) |
|
{ |
|
created = itemFactory.Invoke(); |
|
factoryUsed = true; |
|
} |
|
if (bucket.Insert(index, created, out stored)) |
|
{ |
|
return true; |
|
} |
|
isNew = false; |
|
} |
|
else |
|
{ |
|
if (bucket.Update(index, itemUpdateFactory, check, out isNew)) |
|
{ |
|
return true; |
|
} |
|
if (!isNew) |
|
{ |
|
return false; // returns false only when check returns false |
|
} |
|
} |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Inserts or replaces the item at the specified index. |
|
/// </summary> |
|
/// <param name="bucket">The bucket on which to operate.</param> |
|
/// <param name="index">The index.</param> |
|
/// <param name="itemFactory">The item factory to create the item to insert.</param> |
|
/// <param name="itemUpdateFactory">The item factory to create the item to replace with.</param> |
|
/// <exception cref="System.ArgumentOutOfRangeException">index;index must be greater or equal to 0 and less than capacity</exception> |
|
/// <remarks> |
|
/// The operation will be attempted as long as check returns true - this operation may starve. |
|
/// </remarks> |
|
public static void InsertOrUpdate<T>(this IBucket<T> bucket, int index, Func<T> itemFactory, Func<T, T> itemUpdateFactory) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
bool isNew; |
|
InsertOrUpdate(bucket, index, itemFactory, itemUpdateFactory, out isNew); |
|
} |
|
|
|
/// <summary> |
|
/// Inserts or replaces the item at the specified index. |
|
/// </summary> |
|
/// <param name="bucket">The bucket on which to operate.</param> |
|
/// <param name="index">The index.</param> |
|
/// <param name="itemFactory">The item factory to create the item to insert.</param> |
|
/// <param name="itemUpdateFactory">The item factory to create the item to replace with.</param> |
|
/// <param name="isNew">if set to <c>true</c> the index was not previously used.</param> |
|
/// <exception cref="System.ArgumentOutOfRangeException">index;index must be greater or equal to 0 and less than capacity</exception> |
|
/// <remarks> |
|
/// The operation will be attempted as long as check returns true - this operation may starve. |
|
/// </remarks> |
|
public static void InsertOrUpdate<T>(this IBucket<T> bucket, int index, Func<T> itemFactory, Func<T, T> itemUpdateFactory, out bool isNew) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
isNew = true; |
|
var factoryUsed = false; |
|
var created = default(T); |
|
while (true) |
|
{ |
|
if (isNew) |
|
{ |
|
T stored; |
|
if (!factoryUsed) |
|
{ |
|
created = itemFactory.Invoke(); |
|
factoryUsed = true; |
|
} |
|
if (bucket.Insert(index, created, out stored)) |
|
{ |
|
return; |
|
} |
|
isNew = false; |
|
} |
|
else |
|
{ |
|
if (bucket.Update(index, itemUpdateFactory, Tautology, out isNew)) |
|
{ |
|
return; |
|
} |
|
} |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Inserts or replaces the item at the specified index. |
|
/// </summary> |
|
/// <param name="bucket">The bucket on which to operate.</param> |
|
/// <param name="index">The index.</param> |
|
/// <param name="itemFactory">The item factory to create the item to set.</param> |
|
/// <param name="check">A predicate to decide if a particular item should be replaced.</param> |
|
/// <returns> |
|
/// <c>true</c> if the item or repalced inserted; otherwise, <c>false</c>. |
|
/// </returns> |
|
/// <exception cref="System.ArgumentOutOfRangeException">index;index must be greater or equal to 0 and less than capacity</exception> |
|
/// <remarks> |
|
/// The operation will be attempted as long as check returns true - this operation may starve. |
|
/// </remarks> |
|
public static bool InsertOrUpdate<T>(this IBucket<T> bucket, int index, Func<T> itemFactory, Predicate<T> check) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
bool isNew; |
|
return InsertOrUpdate(bucket, index, itemFactory, check, out isNew); |
|
} |
|
|
|
/// <summary> |
|
/// Inserts or replaces the item at the specified index. |
|
/// </summary> |
|
/// <param name="bucket">The bucket on which to operate.</param> |
|
/// <param name="index">The index.</param> |
|
/// <param name="itemFactory">The item factory to create the item to set.</param> |
|
/// <param name="check">A predicate to decide if a particular item should be replaced.</param> |
|
/// <param name="isNew">if set to <c>true</c> the index was not previously used.</param> |
|
/// <returns> |
|
/// <c>true</c> if the item or repalced inserted; otherwise, <c>false</c>. |
|
/// </returns> |
|
/// <exception cref="System.ArgumentOutOfRangeException">index;index must be greater or equal to 0 and less than capacity</exception> |
|
/// <remarks> |
|
/// The operation will be attempted as long as check returns true - this operation may starve. |
|
/// </remarks> |
|
public static bool InsertOrUpdate<T>(this IBucket<T> bucket, int index, Func<T> itemFactory, Predicate<T> check, out bool isNew) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
isNew = true; |
|
var factoryUsed = false; |
|
var created = default(T); |
|
while (true) |
|
{ |
|
if (isNew) |
|
{ |
|
T stored; |
|
if (!factoryUsed) |
|
{ |
|
created = itemFactory.Invoke(); |
|
factoryUsed = true; |
|
} |
|
if (bucket.Insert(index, created, out stored)) |
|
{ |
|
return true; |
|
} |
|
isNew = false; |
|
} |
|
else |
|
{ |
|
var result = itemFactory.Invoke(); |
|
if (bucket.Update(index, _ => result, check, out isNew)) |
|
{ |
|
return true; |
|
} |
|
if (!isNew) |
|
{ |
|
return false; // returns false only when check returns false |
|
} |
|
} |
|
} |
|
} |
|
|
|
public static void Set<T>(this IBucket<T> bucket, int index, T value) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
bool isNew; |
|
bucket.Set(index, value, out isNew); |
|
} |
|
|
|
public static bool TryGetOrInsert<T>(this IBucket<T> bucket, int index, T item, out T stored) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
T previous; |
|
if (bucket.Insert(index, item, out previous)) |
|
{ |
|
stored = item; |
|
return true; |
|
} |
|
stored = previous; |
|
return false; |
|
} |
|
|
|
public static bool TryGetOrInsert<T>(this IBucket<T> bucket, int index, Func<T> itemFactory, out T stored) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
if (bucket.TryGet(index, out stored)) |
|
{ |
|
return false; |
|
} |
|
var created = itemFactory.Invoke(); |
|
if (bucket.Insert(index, created, out stored)) |
|
{ |
|
stored = created; |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
public static bool Update<T>(this IBucket<T> bucket, int index, T item, Predicate<T> check) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
bool isEmpty; |
|
return bucket.Update(index, _ => item, check, out isEmpty); |
|
} |
|
|
|
public static bool Update<T>(this IBucket<T> bucket, int index, T item, Predicate<T> check, out bool isEmpty) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
return bucket.Update(index, _ => item, check, out isEmpty); |
|
} |
|
|
|
public static bool Update<T>(this IBucket<T> bucket, int index, Func<T, T> itemUpdateFactory) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
bool isEmpty; |
|
return bucket.Update(index, itemUpdateFactory, Tautology, out isEmpty); |
|
} |
|
|
|
public static bool Update<T>(this IBucket<T> bucket, int index, Func<T, T> itemUpdateFactory, out bool isEmpty) |
|
{ |
|
if (bucket == null) |
|
{ |
|
throw new ArgumentNullException("bucket"); |
|
} |
|
return bucket.Update(index, itemUpdateFactory, Tautology, out isEmpty); |
|
} |
|
|
|
private static bool Tautology<T>(T item) |
|
{ |
|
GC.KeepAlive(item); |
|
return true; |
|
} |
|
} |
|
} |
|
#endif |