// 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(this IBucket 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(this IBucket bucket, int index, Func 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; } /// /// Inserts or replaces the item at the specified index. /// /// The bucket on which to operate. /// The index. /// The item set. /// The item factory to create the item to replace with. /// A predicate to decide if a particular item should be replaced. /// /// true if the item or repalced inserted; otherwise, false. /// /// index;index must be greater or equal to 0 and less than capacity /// /// The operation will be attempted as long as check returns true - this operation may starve. /// public static bool InsertOrUpdate(this IBucket bucket, int index, T item, Func itemUpdateFactory, Predicate check) { bool isNew; return InsertOrUpdate(bucket, index, item, itemUpdateFactory, check, out isNew); } /// /// Inserts or replaces the item at the specified index. /// /// The bucket on which to operate. /// The index. /// The item insert. /// The item factory to create the item to replace with. /// A predicate to decide if a particular item should be replaced. /// if set to true the index was not previously used. /// /// true if the item or repalced inserted; otherwise, false. /// /// index;index must be greater or equal to 0 and less than capacity /// /// The operation will be attempted as long as check returns true - this operation may starve. /// public static bool InsertOrUpdate(this IBucket bucket, int index, T item, Func itemUpdateFactory, Predicate 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 } } } } /// /// Inserts or replaces the item at the specified index. /// /// The bucket on which to operate. /// The index. /// The item set. /// The item factory to create the item to replace with. /// index;index must be greater or equal to 0 and less than capacity /// /// The operation will be attempted as long as check returns true - this operation may starve. /// public static void InsertOrUpdate(this IBucket bucket, int index, T item, Func itemUpdateFactory) { bool isNew; InsertOrUpdate(bucket, index, item, itemUpdateFactory, out isNew); } /// /// Inserts or replaces the item at the specified index. /// /// The bucket on which to operate. /// The index. /// The item insert. /// The item factory to create the item to replace with. /// if set to true the index was not previously used. /// index;index must be greater or equal to 0 and less than capacity /// /// The operation will be attempted as long as check returns true - this operation may starve. /// public static void InsertOrUpdate(this IBucket bucket, int index, T item, Func 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; } } } } /// /// Inserts or replaces the item at the specified index. /// /// The bucket on which to operate. /// The index. /// The item set. /// A predicate to decide if a particular item should be replaced. /// /// true if the item or repalced inserted; otherwise, false. /// /// index;index must be greater or equal to 0 and less than capacity /// /// The operation will be attempted as long as check returns true - this operation may starve. /// public static bool InsertOrUpdate(this IBucket bucket, int index, T item, Predicate check) { bool isNew; return InsertOrUpdate(bucket, index, item, check, out isNew); } /// /// Inserts or replaces the item at the specified index. /// /// The bucket on which to operate. /// The index. /// The item set. /// A predicate to decide if a particular item should be replaced. /// if set to true the index was not previously used. /// /// true if the item or repalced inserted; otherwise, false. /// /// index;index must be greater or equal to 0 and less than capacity /// /// The operation will be attempted as long as check returns true - this operation may starve. /// public static bool InsertOrUpdate(this IBucket bucket, int index, T item, Predicate 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 } } } } /// /// Inserts or replaces the item at the specified index. /// /// The bucket on which to operate. /// The index. /// The item factory to create the item to insert. /// The item factory to create the item to replace with. /// A predicate to decide if a particular item should be replaced. /// /// true if the item or repalced inserted; otherwise, false. /// /// index;index must be greater or equal to 0 and less than capacity /// /// The operation will be attempted as long as check returns true - this operation may starve. /// public static bool InsertOrUpdate(this IBucket bucket, int index, Func itemFactory, Func itemUpdateFactory, Predicate check) { if (bucket == null) { throw new ArgumentNullException("bucket"); } bool isNew; return InsertOrUpdate(bucket, index, itemFactory, itemUpdateFactory, check, out isNew); } /// /// Inserts or replaces the item at the specified index. /// /// The bucket on which to operate. /// The index. /// The item factory to create the item to insert. /// The item factory to create the item to replace with. /// A predicate to decide if a particular item should be replaced. /// if set to true the index was not previously used. /// /// true if the item or repalced inserted; otherwise, false. /// /// index;index must be greater or equal to 0 and less than capacity /// /// The operation will be attempted as long as check returns true - this operation may starve. /// public static bool InsertOrUpdate(this IBucket bucket, int index, Func itemFactory, Func itemUpdateFactory, Predicate 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 } } } } /// /// Inserts or replaces the item at the specified index. /// /// The bucket on which to operate. /// The index. /// The item factory to create the item to insert. /// The item factory to create the item to replace with. /// index;index must be greater or equal to 0 and less than capacity /// /// The operation will be attempted as long as check returns true - this operation may starve. /// public static void InsertOrUpdate(this IBucket bucket, int index, Func itemFactory, Func itemUpdateFactory) { if (bucket == null) { throw new ArgumentNullException("bucket"); } bool isNew; InsertOrUpdate(bucket, index, itemFactory, itemUpdateFactory, out isNew); } /// /// Inserts or replaces the item at the specified index. /// /// The bucket on which to operate. /// The index. /// The item factory to create the item to insert. /// The item factory to create the item to replace with. /// if set to true the index was not previously used. /// index;index must be greater or equal to 0 and less than capacity /// /// The operation will be attempted as long as check returns true - this operation may starve. /// public static void InsertOrUpdate(this IBucket bucket, int index, Func itemFactory, Func 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; } } } } /// /// Inserts or replaces the item at the specified index. /// /// The bucket on which to operate. /// The index. /// The item factory to create the item to set. /// A predicate to decide if a particular item should be replaced. /// /// true if the item or repalced inserted; otherwise, false. /// /// index;index must be greater or equal to 0 and less than capacity /// /// The operation will be attempted as long as check returns true - this operation may starve. /// public static bool InsertOrUpdate(this IBucket bucket, int index, Func itemFactory, Predicate check) { if (bucket == null) { throw new ArgumentNullException("bucket"); } bool isNew; return InsertOrUpdate(bucket, index, itemFactory, check, out isNew); } /// /// Inserts or replaces the item at the specified index. /// /// The bucket on which to operate. /// The index. /// The item factory to create the item to set. /// A predicate to decide if a particular item should be replaced. /// if set to true the index was not previously used. /// /// true if the item or repalced inserted; otherwise, false. /// /// index;index must be greater or equal to 0 and less than capacity /// /// The operation will be attempted as long as check returns true - this operation may starve. /// public static bool InsertOrUpdate(this IBucket bucket, int index, Func itemFactory, Predicate 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(this IBucket bucket, int index, T value) { if (bucket == null) { throw new ArgumentNullException("bucket"); } bool isNew; bucket.Set(index, value, out isNew); } public static bool TryGetOrInsert(this IBucket 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(this IBucket bucket, int index, Func 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(this IBucket bucket, int index, T item, Predicate check) { if (bucket == null) { throw new ArgumentNullException("bucket"); } bool isEmpty; return bucket.Update(index, _ => item, check, out isEmpty); } public static bool Update(this IBucket bucket, int index, T item, Predicate check, out bool isEmpty) { if (bucket == null) { throw new ArgumentNullException("bucket"); } return bucket.Update(index, _ => item, check, out isEmpty); } public static bool Update(this IBucket bucket, int index, Func itemUpdateFactory) { if (bucket == null) { throw new ArgumentNullException("bucket"); } bool isEmpty; return bucket.Update(index, itemUpdateFactory, Tautology, out isEmpty); } public static bool Update(this IBucket bucket, int index, Func itemUpdateFactory, out bool isEmpty) { if (bucket == null) { throw new ArgumentNullException("bucket"); } return bucket.Update(index, itemUpdateFactory, Tautology, out isEmpty); } private static bool Tautology(T item) { GC.KeepAlive(item); return true; } } } #endif