LinkItemDictionary.cs

180 lines | 5.188 kB Blame History Raw Download
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Collections.Concurrent;

using Tools.Collections.Concurrent.Extensions;

namespace Tools.Collections.Concurrent
{

    /// <summary>
    /// Thread safe key value link-item collection.
    /// Item remove if link count is 0.
    /// Base on ConcurrentDictionary.
    /// </summary>
    public class LinkItemDictionary<TKey, TData>
    {

        #region

        public IReadOnlyDictionary<TKey, IValueWrapper<LinkItem<TKey, TData>>> Storage { private set; get; }


        private readonly ConcurrentDictionary<TKey, IValueWrapper<LinkItem<TKey, TData>>> _Storage
            = new ConcurrentDictionary<TKey, IValueWrapper<LinkItem<TKey, TData>>>();

        private readonly ICollection<KeyValuePair<TKey, IValueWrapper<LinkItem<TKey, TData>>>> _StorageAsCollection;

        #endregion


        #region

        public LinkItemDictionary()
        {
            Storage = (IReadOnlyDictionary<TKey, IValueWrapper<LinkItem<TKey, TData>>>)_Storage;
            _StorageAsCollection = _Storage;
        }

        #endregion


        #region

        /// <summary>
        /// Add link. Add or update Value
        /// </summary>
        public LinkItem<TKey, TData> AddLink(
            TKey key,
            Func<TKey, TData> addFactory,
            Func<LinkItem<TKey, TData>, TData> updateFactory
            )
        {
            return _Storage.AddOrUpdate(
                key,
                (TKey k) =>
                {
                    return
                        new RealItemWrapper<LinkItem<TKey, TData>>(
                            new LinkItem<TKey, TData>
                            (
                                key,
                                1,
                                addFactory != null ? addFactory(key) : default(TData)
                            )
                        );
                },
                (TKey k, IValueWrapper<LinkItem<TKey, TData>> old_value) =>
                {
                    return
                        new RealItemWrapper<LinkItem<TKey, TData>>(
                            new LinkItem<TKey, TData>(
                                key,
                                old_value.Value.LinkCount + 1,
                                updateFactory != null
                                    ? updateFactory(old_value.Value)
                                    : old_value.Value.Value
                            )
                        );
                }
                )
                .Value;
        }

        /// <summary>
        /// Add link. Add Value
        /// </summary>
        public LinkItem<TKey, TData> AddLink(
            TKey key,
            Func<TKey, TData> addFactory)
        {
            return AddLink(key, addFactory, null);
        }

        /// <summary>
        /// Add link. Update value if exsist
        /// </summary>
        public LinkItem<TKey, TData> AddLink(
            TKey key,
            Func<LinkItem<TKey, TData>, TData> updateFactory)
        {
            return AddLink(key, null, updateFactory);
        }

        /// <summary>
        /// Add link. No change value
        /// </summary>
        public LinkItem<TKey, TData> AddLink(
            TKey key
            )
        {
            return AddLink(key, null, null);
        }


        /// <summary>
        /// Remove link. Update value
        /// </summary>
        public LinkItem<TKey, TData> RemoveLink(
            TKey key,
            Func<LinkItem<TKey, TData>, TData> updateFactory)
        {
            var item = _Storage.AddOrUpdate(
                key,
                (TKey k) =>
                {
                    return
                        new RealItemWrapper<LinkItem<TKey, TData>>(
                            new LinkItem<TKey, TData>(
                                key,
                                0,
                                default(TData)
                            )
                        );
                },
                (TKey k, IValueWrapper<LinkItem<TKey, TData>> old_value) =>
                {
                    return 
                        new RealItemWrapper<LinkItem<TKey, TData>>(
                            new LinkItem<TKey, TData>(
                                key,
                                old_value.Value.LinkCount - 1,
                                updateFactory != null 
                                    ? updateFactory(old_value.Value) 
                                    : old_value.Value.Value
                            )
                        );
                }
            );

            if (item.Value.LinkCount == 0)
            {
                _StorageAsCollection.RemoveIf(
                    key,
                    (value) =>
                    {
                        return value.Value.LinkCount == 0;
                    }
                );
            }

            return item.Value;
        }

        /// <summary>
        /// Remove link. No change value if not remove
        /// </summary>
        public LinkItem<TKey, TData> RemoveLink(TKey key)
        {
            return RemoveLink(key, null);
        }

        #endregion

    }
}