/// <summary> /// Removes all items from the concurrent weak dictionary /// </summary> /// <returns>An array of all the key/value pairs removed</returns> public KeyValuePair <TKey, TValue>[] RemoveAll() { //**************************************** var MyValues = new List <KeyValuePair <TKey, TValue> >(_Dictionary.Count); TValue?MyValue; //**************************************** while (!_Dictionary.IsEmpty) { foreach (var MyKey in _Dictionary.Keys) { if (!_Dictionary.TryRemove(MyKey, out var MyHandle)) { continue; } MyValue = (TValue?)MyHandle.Target; if (MyValue != null) { MyValues.Add(new KeyValuePair <TKey, TValue>(MyKey, MyValue)); } MyHandle.Dispose(); } } return(MyValues.ToArray()); }
//**************************************** /// <summary> /// Adds a new pair to the dictionary /// </summary> /// <param name="key">The key of the item to add</param> /// <param name="value">The value that will be weakly referenced</param> /// <exception cref="ArgumentNullException">Value was null</exception> /// <exception cref="ArgumentException">Key already exists</exception> public void Add(TKey key, TValue value) { if (value == null) { throw new ArgumentNullException(nameof(value), "Cannot add null to a Weak Dictionary"); } // Is this key already in the dictionary? if (_Dictionary.TryGetValue(key, out var MyHandle)) { // Yes, is the object available? if (MyHandle.IsAlive) { throw new ArgumentException("Key already exists in the Weak Dictionary"); } // No, free the handle and replace it MyHandle.Dispose(); _Dictionary[key] = new GCReference(value, _HandleType); } else { // Not in the dictionary, add it _Dictionary.Add(key, new GCReference(value, _HandleType)); } }
/// <summary> /// Removes all elements from the collection /// </summary> public void Clear() { foreach (var MyHandle in _Values) { MyHandle.Dispose(); } _Values.Clear(); }
/// <summary> /// Removes all elements from the collection /// </summary> public void Clear() { foreach (var MyHandle in _Dictionary.Values) { MyHandle.Dispose(); } _Dictionary.Clear(); }
/// <summary> /// Removes all elements from the collection /// </summary> public void Clear() { foreach (var MyPair in _Dictionary) { if (_Dictionary.TryRemove(MyPair.Key, out var MyHandle)) { MyHandle.Dispose(); } } }
/// <summary> /// Adds an item to the dictionary /// </summary> /// <param name="key">The key of the item to add</param> /// <param name="value">The value of the item to add</param> /// <returns>True if the item was added, otherwise false</returns> /// <remarks>Will add if the key is not set, and replace if the value is no longer available</remarks> public bool TryAdd(TKey key, TValue value) { //**************************************** GCReference NewHandle; //**************************************** if (value == null) { throw new InvalidOperationException("Cannot add null to a Weak Dictionary"); } for (; ;) { // Is this key already in the dictionary? if (!_Dictionary.TryGetValue(key, out var MyHandle)) { // Key not found, so let's try and add it // Create a GC Handle to reference the object NewHandle = new GCReference(value, _HandleType); // Try and add it to the dictionary if (_Dictionary.TryAdd(key, NewHandle)) { return(true); // Success, return the result } // Key was added concurrently, free the handle we no longer need NewHandle.Dispose(); return(false); } // Key found, is the weak reference still valid? if (MyHandle.IsAlive) { return(false); // Yes, can't add } // Target reference has vanished, we can replace it with the new value NewHandle = new GCReference(value, _HandleType); // Try and update the dictionary with the replacement value if (_Dictionary.TryUpdate(key, NewHandle, MyHandle)) { // Success, now we can safely expire the old handle MyHandle.Dispose(); return(true); } // Key was updated elsewhere. Could have been removed or simply updated with a valid value elsewhere // Ditch the updated value and try again NewHandle.Dispose(); } }
/// <summary> /// Removes the value associated with the specified key /// </summary> /// <param name="key">The key to remove</param> /// <returns>True if the key was found and still referenced, otherwise false</returns> public bool Remove(TKey key) { if (!_Dictionary.TryRemove(key, out var MyHandle)) { return(false); } var IsValid = MyHandle.IsAlive; MyHandle.Dispose(); return(IsValid); }
public static int test_0_safehandle_ref () { MyHandle m = new MyHandle ((IntPtr) 0xdead); mono_safe_handle_ref (ref m); if (m.DangerousGetHandle () != (IntPtr) 0x800d){ Console.WriteLine ("test_0_safehandle_ref: fail; Expected 0x800d, got: {0:x}", m.DangerousGetHandle ()); return 1; } Console.WriteLine ("test_0_safehandle_ref: pass"); return 0; }
public static int test_0_safehandle_ref() { MyHandle m = new MyHandle((IntPtr)0xdead); mono_safe_handle_ref(ref m); if (m.DangerousGetHandle() != (IntPtr)0x800d) { Console.WriteLine("test_0_safehandle_ref: fail; Expected 0x800d, got: {0:x}", m.DangerousGetHandle()); return(1); } Console.WriteLine("test_0_safehandle_ref: pass"); return(0); }
public void TryTakeNoMaxTime() { //**************************************** var MyLock = new AsyncSemaphore(); //**************************************** Assert.True(MyLock.TryTake(out var MyHandle, TimeSpan.FromMilliseconds(50)), "Lock not taken"); MyHandle.Dispose(); //**************************************** Assert.AreEqual(0, MyLock.WaitingCount, "Still waiting for Semaphore"); Assert.AreEqual(MyLock.MaxCount, MyLock.CurrentCount, "Semaphore still held"); }
/// <summary> /// Removes the value associated with the specified key /// </summary> /// <param name="key">The key to remove</param> /// <param name="value">The value to remove, if still referenced. Null if the key was not found or was found but the reference expired</param> /// <returns>True if the key was found and still referenced, otherwise false</returns> public bool TryRemove(TKey key, #if !NETSTANDARD2_0 && !NET40 [MaybeNullWhen(false)] #endif out TValue value) { if (_Dictionary.TryRemove(key, out var MyHandle)) { value = (TValue?)MyHandle.Target !; MyHandle.Dispose(); return(value != null); } value = null !; return(false); }
/// <summary> /// Removes the specified key/value pair /// </summary> /// <param name="key">The key to remove</param> /// <param name="value">The value to remove</param> /// <returns>True if the key was found with the expected value, otherwise false</returns> public bool Remove(TKey key, TValue value) { if (value == null) { throw new ArgumentNullException(nameof(value), "Cannot have a null in a Weak Dictionary"); } // Is this key in the dictionary? if (!_Dictionary.TryGetValue(key, out var MyHandle)) { return(false); } try { var MyValue = (TValue?)MyHandle.Target; // Is the referenced value as expected? if (MyValue != value) { return(false); } } catch (InvalidOperationException) { // The GCHandle was disposed, so someone concurrently removed it return(false); } // Yes, try and remove this key/GCReference pair if (!((IDictionary <TKey, GCReference>)_Dictionary).Remove(new KeyValuePair <TKey, GCReference>(key, MyHandle))) { return(false); } // Success, free the handle MyHandle.Dispose(); return(true); }
public async Task TryTakeLock() { //**************************************** var MyLock = new AsyncSemaphore(); //**************************************** Assert.True(MyLock.TryTake(out var MyHandle), "Lock not taken"); var MyWait = MyLock.Take(); Assert.IsFalse(MyWait.IsCompleted, "Nested lock taken"); MyHandle.Dispose(); MyHandle = await MyWait; MyHandle.Dispose(); //**************************************** Assert.AreEqual(0, MyLock.WaitingCount, "Still waiting for Semaphore"); Assert.AreEqual(MyLock.MaxCount, MyLock.CurrentCount, "Semaphore still held"); }
public static extern void mono_safe_handle_ref(ref MyHandle handle);
public static extern void UseResource(MyHandle resource);
public Resource(int id, string name) { ptr = OpenResource(id, name); }
/// <summary> /// Adds or updates a key/value pair /// </summary> /// <param name="key">The key to add or replace</param> /// <param name="valueCallback">A callback providing the new value</param> /// <param name="updateCallback">A callback updating an existing value</param> /// <returns>The added or updated value</returns> public TValue AddOrUpdate(TKey key, Func <TKey, TValue> valueCallback, Func <TKey, TValue, TValue> updateCallback) { //**************************************** GCReference NewHandle; TValue?OldValue; TValue NewValue; //**************************************** for (; ;) { // Is this key already in the dictionary? if (_Dictionary.TryGetValue(key, out var MyHandle)) { try { OldValue = (TValue?)MyHandle.Target; } catch (InvalidOperationException) { // The GCHandle was disposed, try again continue; } // Yes, does the target still exist? if (OldValue != null) { // Yes, let's try and update it NewValue = updateCallback(key, OldValue); // If the reference is the same, no need to change anything if (object.ReferenceEquals(OldValue, NewValue)) { return(NewValue); } } else { // Target reference has vanished, replace it with the new value NewValue = valueCallback(key); if (NewValue == null) { throw new InvalidOperationException("Cannot add null to a Weak Dictionary"); } } // Reference has changed, create a new GCReference NewHandle = new GCReference(NewValue, _HandleType); // Try and update the dictionary with the replacement value if (_Dictionary.TryUpdate(key, NewHandle, MyHandle)) { // Success, now we can safely expire the old handle MyHandle.Dispose(); return(NewValue); } // Key was updated elsewhere, ditch the updated value and try again NewHandle.Dispose(); continue; } // Key not found, so let's try and add it NewValue = valueCallback(key); if (NewValue == null) { throw new InvalidOperationException("Cannot add null to a Weak Dictionary"); } // Create a GC Handle to reference the object NewHandle = new GCReference(NewValue, _HandleType); // Try and add it to the dictionary if (_Dictionary.TryAdd(key, NewHandle)) { return(NewValue); // Success, return the result } // Key was added concurrently, free the handle we no longer need NewHandle.Dispose(); // Loop back and try again } }
/// <summary> /// Adds or retrieves a value based on the key /// </summary> /// <param name="key">The key to add or retrieve</param> /// <param name="value">A value to associate if the key doesn't exist</param> /// <param name="wasAdded">Receives whether the value was added or simply retrieved</param> /// <returns>The new or existing value</returns> public TValue GetOrAdd(TKey key, TValue value, out bool wasAdded) { //**************************************** GCReference NewHandle; //**************************************** if (value == null) { throw new InvalidOperationException("Cannot add null to a Weak Dictionary"); } for (; ;) { // Is this key already in the dictionary? if (_Dictionary.TryGetValue(key, out var MyHandle)) { try { var MyValue = (TValue?)MyHandle.Target; // Yes, does the target still exist? if (MyValue != null) { wasAdded = false; return(MyValue); // Yes, return it } } catch (InvalidOperationException) { // The GCHandle was disposed, try again continue; } // Target reference has vanished, replace it with the new value NewHandle = new GCReference(value, _HandleType); // Try and update the dictionary with the replacement value if (_Dictionary.TryUpdate(key, NewHandle, MyHandle)) { // Success, now we can safely expire the old handle MyHandle.Dispose(); wasAdded = true; return(value); } // Key was updated elsewhere, ditch the updated value and try again NewHandle.Dispose(); continue; } // Key not found, so let's try and add it // Create a GC Handle to reference the object NewHandle = new GCReference(value, _HandleType); // Try and add it to the dictionary if (_Dictionary.TryAdd(key, NewHandle)) { wasAdded = true; return(value); // Success, return the result } // Key was added concurrently, free the handle we no longer need NewHandle.Dispose(); // Loop back and try again } }
//**************************************** /// <summary> /// Adds or replaces a key/value pair /// </summary> /// <param name="key">The key to add or replace</param> /// <param name="value">The value to associate with the key</param> public void AddOrReplace(TKey key, TValue value) { //**************************************** GCReference NewHandle; //**************************************** if (value == null) { throw new InvalidOperationException("Cannot add null to a Weak Dictionary"); } for (; ;) { // Is this key already in the dictionary? if (_Dictionary.TryGetValue(key, out var MyHandle)) { try { var OldValue = (TValue?)MyHandle.Target; // Yes. If the reference is the same, no need to change anything if (object.ReferenceEquals(OldValue, value)) { return; } } catch (InvalidOperationException) { // The GCHandle was disposed, try again continue; } // Reference has changed, create a new GCReference NewHandle = new GCReference(value, _HandleType); // Try and update the dictionary with the replacement value if (_Dictionary.TryUpdate(key, NewHandle, MyHandle)) { // Success, now we can safely expire the old handle MyHandle.Dispose(); return; } // Key was updated elsewhere, ditch the updated value and try again NewHandle.Dispose(); continue; } // Create a GC Handle to reference the object NewHandle = new GCReference(value, _HandleType); // Try and add it to the dictionary if (_Dictionary.TryAdd(key, NewHandle)) { return; // Success, return the result } // Key was added concurrently, free the handle we no longer need NewHandle.Dispose(); // Loop back and try again } }
/// <summary> /// Updates an item in the dictionary /// </summary> /// <param name="key">The key of the item to update</param> /// <param name="newValue">The new value of the item</param> /// <param name="oldValue">The old value we expect to replace</param> /// <returns>True if the key exists and old value was replaced with new value, otherwise false</returns> /// <remarks>Will return false if the reference has expired</remarks> public bool TryUpdate(TKey key, TValue newValue, TValue oldValue) { //**************************************** GCReference NewHandle; TValue?OldValue; //**************************************** if (newValue == null) { throw new ArgumentNullException(nameof(newValue), "Cannot add null to a Weak Dictionary"); } if (oldValue == null) { throw new ArgumentNullException(nameof(oldValue), "Cannot have a null in a Weak Dictionary"); } for (; ;) { // Is this key already in the dictionary? if (!_Dictionary.TryGetValue(key, out var MyHandle)) { return(false); // No, update fails } try { OldValue = (TValue?)MyHandle.Target; } catch (InvalidOperationException) { // The GCHandle was disposed, try again continue; } // Yes, is it what we expected? if (!object.ReferenceEquals(oldValue, OldValue)) { return(false); // No, update fails } // Yes. If the old and new references are the same, no need to change anything // Check now, rather than earlier, so we can return true if it was 'updated' correctly if (object.ReferenceEquals(OldValue, newValue)) { return(true); } // Reference has changed, create a new GCReference NewHandle = new GCReference(newValue, _HandleType); // Try and update the dictionary with the replacement value if (_Dictionary.TryUpdate(key, NewHandle, MyHandle)) { // Success, now we can safely expire the old handle MyHandle.Dispose(); return(true); } // Key was updated elsewhere, ditch the updated value and try again NewHandle.Dispose(); } }
public static extern void mono_safe_handle_ref (ref MyHandle handle);
/// <summary> /// Updates an item if it exists in the dictionary /// </summary> /// <param name="key">The key of the item to update</param> /// <param name="updateCallback">A callback that performs the update</param> /// <param name="newValue">Receives the new value if the dictionary was updated</param> /// <returns>True if the item was updated, False if it does not exist or the reference expired</returns> public bool TryUpdate(TKey key, Func <TKey, TValue, TValue> updateCallback, #if !NETSTANDARD2_0 && !NET40 [MaybeNullWhen(false)] #endif out TValue newValue) { //**************************************** GCReference NewHandle; TValue?OldValue; TValue NewValue; //**************************************** for (; ;) { // Is this key already in the dictionary? if (!_Dictionary.TryGetValue(key, out var MyHandle)) { newValue = null !; return(false); // No, update fails } try { OldValue = (TValue?)MyHandle.Target; } catch (InvalidOperationException) { // The GCHandle was disposed, try again continue; } // Yes, is the reference still valid? if (OldValue == null) { newValue = null !; return(false); // No, update fails } // Yes, update it NewValue = updateCallback(key, OldValue); if (NewValue == null) { throw new InvalidOperationException("Cannot add null to a Weak Dictionary"); } // Yes. If the old and new references are the same, no need to change anything // Check now, rather than earlier, so we can return true if it was 'updated' correctly if (object.ReferenceEquals(OldValue, NewValue)) { newValue = NewValue; return(true); } // Reference has changed, create a new GCReference NewHandle = new GCReference(NewValue, _HandleType); // Try and update the dictionary with the replacement value if (_Dictionary.TryUpdate(key, NewHandle, MyHandle)) { // Success, now we can safely expire the old handle MyHandle.Dispose(); newValue = NewValue; return(true); } // Key was updated elsewhere, ditch the updated value and try again NewHandle.Dispose(); } }