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)
);
}
}
}