LinkStorage.cs

157 lines | 4.544 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 ManagetLinkCollection.LinkStorage.Entities;

namespace ManagetLinkCollection.LinkStorage
{
    /// <summary>
    /// KeyValue хранилище ссылок на данные
    /// Запись удаляется из хранилища, когда кол-во ссылок на нее становиться равным 0
    /// </summary>
    /// <typeparam name="TKey">Ключ</typeparam>
    /// <typeparam name="TData">Данные</typeparam>
    public class LinkStorage<TKey, TData>
    {

        #region

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


        private readonly ConcurrentDictionary<TKey, ILinkItem<TKey, TData>> _Storage
            = new ConcurrentDictionary<TKey, ILinkItem<TKey, TData>>();
        private readonly ICollection<KeyValuePair<TKey, ILinkItem<TKey, TData>>> _StorageAsCollection;

        #endregion


        #region

        public LinkStorage()
        {
            Storage = (IReadOnlyDictionary<TKey, ILinkItem<TKey, TData>>)_Storage;
            _StorageAsCollection = _Storage;
        }

        #endregion


        #region

        /// <summary>
        /// Добавить ссылку на ключ
        /// </summary>
        /// <param name="key">ключ</param>
        /// <param name="addFactory">Фабрика создания данных записи</param>
        /// <param name="updateFactory">Фабрика обновления данных по записи</param>
        public ILinkItem<TKey, TData> AddLink(
            TKey key, 
            Func<TKey, TData> addFactory, 
            Func<ILinkItem<TKey, TData>, TData> updateFactory
            )
        {
            return _Storage.AddOrUpdate(key,
                (TKey k) =>
                {
                    return new RealLinkItem<TKey, TData>(
                        key,
                        1, 
                        addFactory != null ? addFactory(key) : default(TData)
                    );
                },
                (TKey k, ILinkItem<TKey, TData> old_value) =>
                {
                    return new RealLinkItem<TKey, TData>(
                        key,
                        old_value.LinkCount + 1, 
                        updateFactory != null ? updateFactory(old_value) : old_value.Data
                        );
                }
            );

        }

        public ILinkItem<TKey, TData> AddLink(
            TKey key, 
            Func<TKey, TData> addFactory)
        {
            return AddLink(key, addFactory, null);
        }

        public ILinkItem<TKey, TData> AddLink(
            TKey key, 
            Func<ILinkItem<TKey, TData>, TData> updateFactory)
        {
            return AddLink(key, null, updateFactory);
        }

        public ILinkItem<TKey, TData> AddLink(
            TKey key
            )
        {
            return AddLink(key, null, null);
        }


        /// <summary>
        /// Удалить ссылку по ключу
        /// </summary>
        public ILinkItem<TKey, TData> RemoveLink(
            TKey key, 
            Func<ILinkItem<TKey, TData>, TData> updateFactory)
        {
            var item = _Storage.AddOrUpdate(key,
                (TKey k) =>
                {
                    return new RealLinkItem<TKey, TData>(
                        key,
                        0, 
                        default(TData)
                        );
                },
                (TKey k, ILinkItem<TKey, TData> old_value) =>
                {
                    return new RealLinkItem<TKey, TData>(
                        key,
                        old_value.LinkCount - 1, 
                        updateFactory != null ? updateFactory(old_value) : old_value.Data
                        );
                }
            );

            if (item.LinkCount == 0)
            {
                RemoveIfLinkIsNull(key);
            }

            return item;
        }

        public ILinkItem<TKey, TData> RemoveLink(TKey key)
        {
            return RemoveLink(key, null);
        }

        #endregion



        private static readonly RemoveLinkItem<TKey, TData> RemoveItem
            = new RemoveLinkItem<TKey, TData>();
        private void RemoveIfLinkIsNull(TKey key)
        {
            _StorageAsCollection.Remove
            (
                new KeyValuePair<TKey, ILinkItem<TKey, TData>>(key, RemoveItem)
            );
        }

    }
}