Esempio n. 1
0
        public bool TryUpdate(TKey key, TValue value, TValue comparisonValue)
        {
            var oldValObj = DictionaryImpl.ToObjectValue(comparisonValue);
            var newValObj = DictionaryImpl.ToObjectValue(value);

            return(_table.PutIfMatch(key, newValObj, ref oldValObj, DictionaryImpl.ValueMatch.OldValue));
        }
Esempio n. 2
0
        public bool Remove(KeyValuePair <TKey, TValue> item)
        {
            var oldValObj = DictionaryImpl.ToObjectValue(item.Value);

            return(_table.PutIfMatch(item.Key, DictionaryImpl.TOMBSTONE, ref oldValObj,
                                     DictionaryImpl.ValueMatch.OldValue));
        }
Esempio n. 3
0
        public bool TryAdd(TKey key, TValue value)
        {
            object oldValObj = null;
            var    newValObj = DictionaryImpl.ToObjectValue(value);

            return(_table.PutIfMatch(key, newValObj, ref oldValObj, DictionaryImpl.ValueMatch.NullOrDead));
        }
Esempio n. 4
0
 protected DictionaryImpl(int capacity, DictionaryImpl <TKey, TKeyStore, TValue, TComparer> other)
 {
     capacity = AlignToPowerOfTwo(capacity);
     _entries = new Entry[capacity];
     _size    = other._size;
     _topDict = other._topDict;
 }
Esempio n. 5
0
        public TValue GetOrAdd(TKey key, TValue value)
        {
            object oldValObj = null;
            var    newValObj = DictionaryImpl.ToObjectValue(value);

            if (_table.PutIfMatch(key, newValObj, ref oldValObj, DictionaryImpl.ValueMatch.NullOrDead))
            {
                return(value);
            }

            // PERF: this would be nice to have as a helper,
            // but it does not get inlined
            if (default(TValue) == null && oldValObj == DictionaryImpl.NULLVALUE)
            {
                oldValObj = null;
            }

            return((TValue)oldValObj);
        }
Esempio n. 6
0
        // System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>
        /// <param name="capacity">
        ///     The initial number of elements that the
        ///     <see cref="T:System.Collections.Concurrent.ConcurrentDictionary`2" /> can contain.
        /// </param>
        /// <summary>
        ///     Initializes a new instance of the <see cref="T:System.Collections.Concurrent.ConcurrentDictionary`2" /> class
        ///     that is empty, has the default concurrency level and uses the default comparer for the key type.
        /// </summary>
        public ConcurrentDictionary(int capacity)
        {
            if (capacity < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(capacity));
            }

            if (default(TKey) == null)
            {
                if (typeof(TKey) == typeof(ValueType) ||
                    !(default(TKey) is ValueType))
                {
                    _table = DictionaryImpl <TKey, TValue, TComparer> .CreateRefUnsafe(this, capacity);

                    return;
                }
            }
            else
            {
                if (typeof(TKey) == typeof(uint) || typeof(TKey) == typeof(ulong))
                {
                    throw new NotSupportedException(
                              "Unsupported until we have confirmation of how to by-pass the code-gen issue with the casting of Boxed<TKey>. Use int or long instead.");
                }

                if (typeof(TKey) == typeof(int))
                {
                    _table = DictionaryImpl <TKey, TValue, TComparer> .CreateIntUnsafe(this, capacity);

                    return;
                }

                if (typeof(TKey) == typeof(long))
                {
                    _table = DictionaryImpl <TKey, TValue, TComparer> .CreateLongUnsafe(this, capacity);

                    return;
                }
            }

            _table = new DictionaryImplBoxed <TKey, TValue, TComparer>(capacity, this);
        }
            public Snapshot(DictionaryImpl <TKey, TKeyStore, TValue, TComparer> dict)
            {
                _table = dict;

                // linearization point.
                // if table is quiescent and has no copy in progress,
                // we can simply iterate over its table.
                while (true)
                {
                    if (_table._newTable == null)
                    {
                        break;
                    }

                    // there is a copy in progress, finish it and try again
                    _table.HelpCopyImpl(true);
                    _table = (DictionaryImpl <TKey, TKeyStore, TValue, TComparer>)_table._topDict._table;
                }

                // Warm-up the iterator
                MoveNext();
            }
Esempio n. 8
0
        public TValue this[TKey key]
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                var oldValObj = _table.TryGetValue(key);

                Debug.Assert(!(oldValObj is DictionaryImpl.Prime));

                if (oldValObj != null)
                {
                    // PERF: this would be nice to have as a helper,
                    // but it does not get inlined
                    TValue value;
                    if (default(TValue) == null && oldValObj == DictionaryImpl.NULLVALUE)
                    {
                        value = default(TValue);
                    }
                    else
                    {
                        value = (TValue)oldValObj;
                    }

                    return(value);
                }

                return(ThrowKeyNotFound());
            }
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            set
            {
                object oldValObj = null;
                var    newValObj = DictionaryImpl.ToObjectValue(value);
                _table.PutIfMatch(key, newValObj, ref oldValObj, DictionaryImpl.ValueMatch.Any);
            }
        }
 public SnapshotKV(DictionaryImpl <TKey, TKeyStore, TValue, TComparer> dict)
     : base(dict)
 {
 }
Esempio n. 10
0
        private static bool CopySlot(ref Entry oldEntry, DictionaryImpl <TKey, TKeyStore, TValue, TComparer> newTable)
        {
            Debug.Assert(newTable != null);

            // Blindly set the hash from 0 to TOMBPRIMEHASH, to eagerly stop
            // fresh put's from claiming new slots in the old table when the old
            // table is mid-resize.
            var hash = oldEntry.hash;

            if (hash == 0)
            {
                hash = Interlocked.CompareExchange(ref oldEntry.hash, TOMBPRIMEHASH, 0);
                if (hash == 0)
                {
                    return(true);
                }
            }

            if (hash == TOMBPRIMEHASH)
            {
                return(false);
            }

            // Prevent new values from appearing in the old table.
            // Box what we see in the old table, to prevent further updates.
            // NOTE: Read of the value below must happen before reading of the key,
            // however this read does not need to be volatile since we will have
            // some fences in between reads.
            var oldval = oldEntry.value;

            // already boxed?
            var box = oldval as Prime;

            if (box != null)
            {
                Volatile.Read(ref box.originalValue);
            }
            else
            {
                do
                {
                    box = EntryValueNullOrDead(oldval) ? TOMBPRIME : new Prime(oldval);

                    // CAS down a box'd version of oldval
                    // also works as a complete fence between reading the value and the key
                    var prev = Interlocked.CompareExchange(ref oldEntry.value, box, oldval);

                    if (prev == oldval)
                    {
                        // If we made the Value slot hold a TOMBPRIME, then we both
                        // prevented further updates here but also the (absent)
                        // oldval is vacuously available in the new table.  We
                        // return with true here: any thread looking for a value for
                        // this key can correctly go straight to the new table and
                        // skip looking in the old table.
                        if (box == TOMBPRIME)
                        {
                            return(true);
                        }

                        // Break loop; oldval is now boxed by us
                        // it still needs to be copied into the new table.
                        break;
                    }

                    oldval = prev;
                    box    = oldval as Prime;
                } while (box == null);
            }

            if (box == TOMBPRIME)
            {
                return(false);
            }

            // Copy the value into the new table, but only if we overwrite a null.
            // If another value is already in the new table, then somebody else
            // wrote something there and that write is happens-after any value that
            // appears in the old table.  If putIfMatch does not find a null in the
            // new table - somebody else should have recorded the null-not_null
            // transition in this copy.
            var originalValue = box.originalValue;

            Debug.Assert(originalValue != TOMBSTONE);

            // since we have a real value, there must be a nontrivial key in the table
            // regular read is ok because value is always CASed down after the key
            // and we ensured that we read the key after the value with fences above
            var key           = oldEntry.key;
            var copiedIntoNew = newTable.PutSlotCopy(key, originalValue, hash);

            // Finally, now that any old value is exposed in the new table, we can
            // forever hide the old-table value by gently inserting TOMBPRIME value.
            // This will stop other threads from uselessly attempting to copy this slot
            // (i.e., it's a speed optimization not a correctness issue).
            // Check if we are not too late though, to not pay for MESI RFO and
            // GC fence needlessly.
            if (oldEntry.value != TOMBPRIME)
            {
                oldEntry.value = TOMBPRIME;
            }

            // if we failed to copy, it means something has already appeared in
            // the new table and old value should have been copied before that (not by us).
            return(copiedIntoNew);
        }