/// <summary> /// Mutates a value in-place with optimistic locking transaction semantics via a specified transformation /// function. The transformation is retried as many times as necessary to win the optimistic locking race. /// </summary> /// <typeparam name="T">The type of value stored by the set.</typeparam> /// <typeparam name="TArg">The type of argument passed to the <paramref name="transformer"/>.</typeparam> /// <param name="location"> /// The variable or field to be changed, which may be accessed by multiple threads. /// </param> /// <param name="transformer"> /// A function that mutates the value. This function should be side-effect free, as it may run multiple times /// when races occur with other threads.</param> /// <param name="transformerArgument">The argument to pass to <paramref name="transformer"/>.</param> /// <returns> /// <see langword="true"/> if the location's value is changed by applying the result of the /// <paramref name="transformer"/> function; otherwise, <see langword="false"/> if the location's value remained /// the same because the last invocation of <paramref name="transformer"/> returned the existing value. /// </returns> public static bool Update <T, TArg>(ref ImmutableSegmentedHashSet <T> location, Func <ImmutableSegmentedHashSet <T>, TArg, ImmutableSegmentedHashSet <T> > transformer, TArg transformerArgument) { if (transformer is null) { throw new ArgumentNullException(nameof(transformer)); } var oldValue = ImmutableSegmentedHashSet <T> .PrivateInterlocked.VolatileRead(in location); while (true) { var newValue = transformer(oldValue, transformerArgument); if (oldValue == newValue) { // No change was actually required. return(false); } var interlockedResult = InterlockedCompareExchange(ref location, newValue, oldValue); if (oldValue == interlockedResult) { return(true); } oldValue = interlockedResult; // we already have a volatile read that we can reuse for the next loop } }
/// <inheritdoc cref="ImmutableHashSet{T}.Builder.Clear()"/> public void Clear() { if (ReadOnlySet.Count != 0) { if (_mutableSet is null) { _mutableSet = new SegmentedHashSet <T>(KeyComparer); _set = default; } else { _mutableSet.Clear(); } } }
/// <inheritdoc cref="ImmutableHashSet.ToImmutableHashSet{TSource}(ImmutableHashSet{TSource}.Builder)"/> public static ImmutableSegmentedHashSet <TSource> ToImmutableSegmentedHashSet <TSource>(this ImmutableSegmentedHashSet <TSource> .Builder builder) { if (builder is null) { throw new ArgumentNullException(nameof(builder)); } return(builder.ToImmutable()); }
internal Builder(ImmutableSegmentedHashSet <T> set) { _set = set; _mutableSet = null; }
/// <summary> /// Assigns a field or variable containing an immutable set to the specified value if it is has not yet /// been initialized. /// </summary> /// <typeparam name="T">The type of value stored by the set.</typeparam> /// <param name="location">The field or local variable to change.</param> /// <param name="value">The new value to assign.</param> /// <returns><see langword="true"/> if the field was assigned the specified value; otherwise, /// <see langword="false"/> if it was previously initialized.</returns> public static bool InterlockedInitialize <T>(ref ImmutableSegmentedHashSet <T> location, ImmutableSegmentedHashSet <T> value) { return(InterlockedCompareExchange(ref location, value, default(ImmutableSegmentedHashSet <T>)).IsDefault); }
/// <summary> /// Assigns a field or variable containing an immutable set to the specified value if it is currently /// equal to another specified value. Returns the previous value. /// </summary> /// <typeparam name="T">The type of value stored by the set.</typeparam> /// <param name="location">The field or local variable to change.</param> /// <param name="value">The new value to assign.</param> /// <param name="comparand">The value to check equality for before assigning.</param> /// <returns>The prior value at the specified <paramref name="location"/>.</returns> public static ImmutableSegmentedHashSet <T> InterlockedCompareExchange <T>(ref ImmutableSegmentedHashSet <T> location, ImmutableSegmentedHashSet <T> value, ImmutableSegmentedHashSet <T> comparand) { return(ImmutableSegmentedHashSet <T> .PrivateInterlocked.InterlockedCompareExchange(ref location, value, comparand)); }
/// <summary> /// Assigns a field or variable containing an immutable set to the specified value and returns the /// previous value. /// </summary> /// <typeparam name="T">The type of value stored by the set.</typeparam> /// <param name="location">The field or local variable to change.</param> /// <param name="value">The new value to assign.</param> /// <returns>The prior value at the specified <paramref name="location"/>.</returns> public static ImmutableSegmentedHashSet <T> InterlockedExchange <T>(ref ImmutableSegmentedHashSet <T> location, ImmutableSegmentedHashSet <T> value) { return(ImmutableSegmentedHashSet <T> .PrivateInterlocked.InterlockedExchange(ref location, value)); }