Tools.Collections
Changes
.gitignore 28(+26 -2)
src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Fake/EnumTestPrioriry.cs 40(+40 -0)
src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Properties/AssemblyInfo.cs 20(+20 -0)
src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/BufferTest.cs 57(+57 -0)
src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/PriorityBufferTest.cs 132(+132 -0)
src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/StoreTest.cs 66(+66 -0)
src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Tools.Collections.Concurrent.AsyncBuffer.UnitTest.csproj 78(+78 -0)
src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/ConcurrentBufferPriorityWrapper.cs 44(+44 -0)
src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/ConcurrentStorePriorityWrapper.cs 107(+107 -0)
src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/IConcurrentBufferPriorityWrapper.cs 30(+30 -0)
src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/IConcurrentStorePriorityWrapper.cs 22(+22 -0)
src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Properties/AssemblyInfo.cs 36(+36 -0)
src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Tools.Collections.Concurrent.AsyncBuffer.csproj 63(+63 -0)
src/Tools.Collections/Tools.Collections.sln 22(+18 -4)
Details
.gitignore 28(+26 -2)
diff --git a/.gitignore b/.gitignore
index f5eb3a9..ebb391b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,17 @@
+src/ManagetLinkCollection/.vs/ManagetLinkCollection/*
+
+
+src/ManagetLinkCollection/ManagetLinkCollection.ConsoleTest/bin/*
+src/ManagetLinkCollection/ManagetLinkCollection.ConsoleTest/obj/*
+
+src/ManagetLinkCollection/ManagetLinkCollection/bin/*
+src/ManagetLinkCollection/ManagetLinkCollection/obj/*
+
+src/ManagetLinkCollection/packages/*
+
+
+
src/Tools.Collections/.vs/*
/.vs/*
@@ -17,5 +30,16 @@ src/Tools.Collections/Tools.Collections.SortedDictionarySortKeyItemKey/obj/*
src/Tools.Collections/Tools.Collections.ConsoleTest/bin/*
src/Tools.Collections/Tools.Collections.ConsoleTest/obj/*
-/src/Tools.Collections/NugetBuild/Packages/*
-/src/Tools.Collections/NugetBuild/nuget.exe
+src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/bin/*
+src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/obj/*
+src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Tools.Collections.Concurrent.AsyncBuffer.csproj.user
+
+src/Tools.Collections/Tools.CancellationTokenAsync/bin/*
+src/Tools.Collections/Tools.CancellationTokenAsync/obj/*
+
+src/Tools.Collections/Tools.Collections.Concurrent.AsyncBufferюUnitTest/bin/*
+src/Tools.Collections/Tools.Collections.Concurrent.AsyncBufferюUnitTest/obj/*
+
+src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/bin/*
+src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/obj/*
+src/Tools.Collections/packages/*
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Fake/EnumTestPrioriry.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Fake/EnumTestPrioriry.cs
new file mode 100644
index 0000000..098a5cf
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Fake/EnumTestPrioriry.cs
@@ -0,0 +1,40 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Linq;
+
+using Tools.Collections.Concurrent.AsyncBuffer;
+using Tools.Collections.Concurrent.AsyncBuffer.Store;
+using Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.UnitTest.Fake
+{
+ enum EnumTestPrioriry
+ {
+ Low = 0,
+ MiddleLow = 25,
+ Middle = 50,
+ MiddleHish = 75,
+ High = 100
+ }
+
+ class PriorityComparer
+ : IComparer<EnumTestPrioriry>
+ {
+ public Func<EnumTestPrioriry, EnumTestPrioriry,int> CompareFunc { set; get; }
+ public int Compare(EnumTestPrioriry x, EnumTestPrioriry y)
+ {
+ if (x > y)
+ {
+ return -1;
+ }
+ if (x < y)
+ {
+ return 1;
+ }
+
+ return 0;
+ }
+ }
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/packages.config b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/packages.config
new file mode 100644
index 0000000..cc5fd64
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="MSTest.TestAdapter" version="2.1.1" targetFramework="net45" />
+ <package id="MSTest.TestFramework" version="2.1.1" targetFramework="net45" />
+</packages>
\ No newline at end of file
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Properties/AssemblyInfo.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..2c40d81
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Properties/AssemblyInfo.cs
@@ -0,0 +1,20 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Tools.Collections.Concurrent.AsyncBuffer.UnitTest")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Tools.Collections.Concurrent.AsyncBuffer.UnitTest")]
+[assembly: AssemblyCopyright("Copyright © 2021")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+
+[assembly: Guid("3ac3937e-72b5-47fe-bdbe-44f6e4879215")]
+
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Settings.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Settings.cs
new file mode 100644
index 0000000..8662451
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Settings.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.UnitTest
+{
+ public static class Settings
+ {
+ public static int Count { private set; get; }
+ = 100000;
+ }
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/BufferTest.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/BufferTest.cs
new file mode 100644
index 0000000..70d94d9
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/BufferTest.cs
@@ -0,0 +1,57 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Linq;
+
+using Tools.Collections.Concurrent.AsyncBuffer;
+using Tools.Collections.Concurrent.AsyncBuffer.Store;
+using Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.UnitTest
+{
+ [TestClass]
+ public class BufferTest
+ {
+ [TestMethod]
+ public void TestConcurrentBuffer()
+ {
+ IConcurrentStore<string> store
+ = new QueueStore<string>();
+ IConcurrentBuffer<string> dataStor
+ = new ConcurrentBuffer<string>(100, store);
+
+ var producerTask = Task.Run(
+ () =>
+ {
+ for (int i = 0; i < Settings.Count; i++)
+ {
+ dataStor.AddForce(i.ToString());
+ }
+ }
+ );
+
+ var consumerTask = Task.Run(
+ async () =>
+ {
+ for (int i = 0; i < Settings.Count; i++)
+ {
+ await dataStor.ConsumeOrWaitAsync()
+ .ConfigureAwait(false);
+ }
+ }
+ );
+
+ Task.WaitAll(
+ producerTask,
+ consumerTask
+ );
+
+ if (dataStor.Size != 0)
+ {
+ throw new Exception();
+ }
+ }
+
+ }
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/PriorityBufferTest.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/PriorityBufferTest.cs
new file mode 100644
index 0000000..eb38691
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/PriorityBufferTest.cs
@@ -0,0 +1,132 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Linq;
+
+using Tools.Collections.Concurrent.AsyncBuffer;
+using Tools.Collections.Concurrent.AsyncBuffer.Store;
+using Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper;
+
+using Tools.Collections.Concurrent.AsyncBuffer.UnitTest.Fake;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.UnitTest
+{
+ [TestClass]
+ public class PriorityBufferTest
+ {
+ [TestMethod]
+ public void TestConcurrentBuffer()
+ {
+ IConcurrentStore<string> store
+ = new QueueStore<string>();
+ IConcurrentBuffer<string> dataStor
+ = new ConcurrentBuffer<string>(100, store);
+
+ var producerTask = Task.Run(
+ () =>
+ {
+ for (int i = 0; i < Settings.Count; i++)
+ {
+ dataStor.AddForce(i.ToString());
+ }
+ }
+ );
+
+ var consumerTask = Task.Run(
+ async () =>
+ {
+ for (int i = 0; i < Settings.Count; i++)
+ {
+ await dataStor.ConsumeOrWaitAsync()
+ .ConfigureAwait(false);
+ }
+ }
+ );
+
+ Task.WaitAll(
+ producerTask,
+ consumerTask
+ );
+
+ if (dataStor.Size != 0)
+ {
+ throw new Exception();
+ }
+ }
+
+ [TestMethod]
+ public void TestConcurrentBufferPriorityWrapper2()
+ {
+ EnumTestPrioriry[] priorityValues
+ = (EnumTestPrioriry[])Enum.GetValues(typeof(EnumTestPrioriry));
+
+ if (Settings.Count % priorityValues.Length != 0)
+ {
+ throw new Exception("Count % priorityValues.Length != 0");
+ }
+ var cnt = Settings.Count / priorityValues.Length;
+
+ // Key - приоритет
+ // Value - соответсующее приоритету хранилище
+ var concurrentStores
+ = new SortedDictionary<EnumTestPrioriry, IConcurrentStore<EnumTestPrioriry>>(
+ priorityValues
+ .ToDictionary(
+ e => e,
+ e => new QueueStore<EnumTestPrioriry>() as IConcurrentStore<EnumTestPrioriry>
+ ),
+ new PriorityComparer()
+ );
+
+ var priorityStore
+ = new ConcurrentStorePriorityWrapper<EnumTestPrioriry, EnumTestPrioriry>(concurrentStores);
+
+ var priorityBuffer
+ = new ConcurrentBufferPriorityWrapper<EnumTestPrioriry, EnumTestPrioriry>(Settings.Count, priorityStore);
+
+
+ foreach (var elem in priorityValues)
+ {
+ for (int i = 0; i < cnt; i++)
+ {
+ priorityBuffer.AddForce(elem, elem);
+ }
+ }
+
+ foreach (var elem in priorityValues)
+ {
+ if (concurrentStores[elem].Size != cnt)
+ {
+ throw new Exception("Ошибка заполнения хранилища с приоритетами");
+ }
+ }
+
+ //Проверяем, что порядок извлечения элементов из буфера идет по убыванию за счет PriorityComparer
+ foreach (var elem in priorityValues.OrderByDescending(e => e))
+ {
+ for (int i = 0; i < cnt; i++)
+ {
+ var consumeResult = priorityBuffer
+ .ConsumeOrWaitAsync()
+ .GetAwaiter()
+ .GetResult();
+
+ if (consumeResult != elem)
+ {
+ throw new Exception($"Неверный порядок приоритета {consumeResult}");
+ }
+ }
+ }
+
+ if (
+ priorityStore.Size != 0
+ || priorityBuffer.Size != 0
+ )
+ {
+ throw new Exception();
+ }
+ }
+
+ }
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/StoreTest.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/StoreTest.cs
new file mode 100644
index 0000000..57ff6d7
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Test/StoreTest.cs
@@ -0,0 +1,66 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Linq;
+
+using Tools.Collections.Concurrent.AsyncBuffer;
+using Tools.Collections.Concurrent.AsyncBuffer.Store;
+using Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.UnitTest
+{
+ [TestClass]
+ public class StoreTest
+ {
+
+ [TestMethod]
+ public void TestQueueStore()
+ {
+ IConcurrentStore<string> store = new QueueStore<string>();
+
+ for (int i = 0; i < Settings.Count; i++)
+ {
+ store.Add(i.ToString());
+ }
+
+ while (store.Size != 0)
+ {
+ store.TryTake(out string s);
+ }
+ }
+
+ [TestMethod]
+ public void TestStackStore()
+ {
+ IConcurrentStore<string> store = new StackStore<string>();
+
+ for (int i = 0; i < Settings.Count; i++)
+ {
+ store.Add(i.ToString());
+ }
+
+ while (store.Size != 0)
+ {
+ store.TryTake(out string s);
+ }
+ }
+
+ [TestMethod]
+ public void TestBagStore()
+ {
+ IConcurrentStore<string> store = new BagStore<string>();
+
+ for (int i = 0; i < Settings.Count; i++)
+ {
+ store.Add(i.ToString());
+ }
+
+ while (store.Size != 0)
+ {
+ store.TryTake(out string s);
+ }
+ }
+
+ }
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Tools.Collections.Concurrent.AsyncBuffer.UnitTest.csproj b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Tools.Collections.Concurrent.AsyncBuffer.UnitTest.csproj
new file mode 100644
index 0000000..6faccd5
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer.UnitTest/Tools.Collections.Concurrent.AsyncBuffer.UnitTest.csproj
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props')" />
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{3AC3937E-72B5-47FE-BDBE-44F6E4879215}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Tools.Collections.Concurrent.AsyncBuffer.UnitTest</RootNamespace>
+ <AssemblyName>Tools.Collections.Concurrent.AsyncBuffer.UnitTest</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
+ <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
+ <IsCodedUITest>False</IsCodedUITest>
+ <TestProjectType>UnitTest</TestProjectType>
+ <NuGetPackageImportStamp>
+ </NuGetPackageImportStamp>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\packages\MSTest.TestFramework.2.1.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <HintPath>..\packages\MSTest.TestFramework.2.1.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Fake\EnumTestPrioriry.cs" />
+ <Compile Include="Settings.cs" />
+ <Compile Include="Test\BufferTest.cs" />
+ <Compile Include="Test\PriorityBufferTest.cs" />
+ <Compile Include="Test\StoreTest.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Tools.Collections.Concurrent.AsyncBuffer\Tools.Collections.Concurrent.AsyncBuffer.csproj">
+ <Project>{97e537c2-2737-46ad-966e-d48e0a93966e}</Project>
+ <Name>Tools.Collections.Concurrent.AsyncBuffer</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+ <PropertyGroup>
+ <ErrorText>Данный проект ссылается на пакеты NuGet, отсутствующие на этом компьютере. Используйте восстановление пакетов NuGet, чтобы скачать их. Дополнительную информацию см. по адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.</ErrorText>
+ </PropertyGroup>
+ <Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.props'))" />
+ <Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets'))" />
+ </Target>
+ <Import Project="..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.1.1\build\net45\MSTest.TestAdapter.targets')" />
+</Project>
\ No newline at end of file
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/ConcurrentBuffer.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/ConcurrentBuffer.cs
new file mode 100644
index 0000000..d2be973
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/ConcurrentBuffer.cs
@@ -0,0 +1,198 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Threading;
+using System.Collections.Concurrent;
+using System.Collections.Specialized;
+using System.Collections.ObjectModel;
+
+using Tools.CancellationTokenAsync;
+
+using Tools.Collections.Concurrent.AsyncBuffer.Store;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer
+{
+ public class ConcurrentBuffer<T>
+ : IConcurrentBuffer<T>
+ {
+ public int RecommendedMaxSize { private set; get; }
+
+ private readonly IConcurrentStore<T> _Storage;
+
+
+ public int Size
+ => _Storage.Size;
+
+ public ConcurrentBuffer(
+ int recommendedMaxSize,
+ IConcurrentStore<T> store
+ )
+ {
+ RecommendedMaxSize = recommendedMaxSize;
+ _Storage = store;
+ }
+
+ public void AddForce(T dateEntity)
+ {
+ _Storage.Add(dateEntity);
+ }
+
+ public bool TryAdd(T dataEntity)
+ {
+ if (Size >= RecommendedMaxSize)
+ {
+ return false;
+ }
+
+ AddForce(dataEntity);
+ return true;
+ }
+
+
+ /// <summary>
+ /// Ожидание поступления нового элемента в хранилище.
+ /// </summary>
+ private async Task WaitUntilNotEmpty(
+ CancellationToken cancellation
+ )
+ {
+ //Если элемент был добавлен в промежутке
+ if (_Storage.Size != 0)
+ {
+ //то выходим
+ return;
+ }
+
+ var cancellationTokenSource = CancellationTokenSource
+ .CreateLinkedTokenSource(cancellation);
+
+ var token = cancellationTokenSource.Token;
+
+ var taskCompletion
+ = new TaskCompletionSource<int>();
+
+ using (
+ token.Register(
+ () => taskCompletion.SetResult(0)
+ )
+ )
+ {
+ void StopWait(
+ IConcurrentStore<T> store,
+ T item
+ )
+ {
+ cancellationTokenSource.Cancel();
+ }
+
+ //Добавляем заявку ожидания нового элемента
+ _Storage.OnItemAdded += StopWait;
+
+ //Если элемент был добавлен в промежутке
+ if (_Storage.Size != 0)
+ {
+ //то выходим
+ return;
+ }
+
+ try
+ {
+ //Ждем оповещения о поступлении элемента
+ await taskCompletion
+ .Task
+ .ConfigureAwait(false);
+ }
+ finally
+ {
+ //Удаляем заявку ожидания поступления нового элемента
+ _Storage.OnItemAdded -= StopWait;
+ }
+ }
+ }
+
+
+ public async Task<T[]> ConsumeBatchOrWaitAsync(
+ int maxBatchSize,
+ CancellationToken cancellation = default,
+ bool configureAwait = false,
+ bool throwOperationCanceledException = false
+ )
+ {
+ do
+ {
+ //Если удалось получить хотя бы 1 элемент из хранилища
+ if (_Storage.TryTake(out T data))
+ {
+ List<T> result = new List<T>(maxBatchSize);
+
+ //То извлекаем пока не пусто или не достигнут maxBatchSize
+ do
+ {
+ result.Add(data);
+ }
+ while (
+ !cancellation.IsCancellationRequested
+ && result.Count <= maxBatchSize
+ && _Storage.TryTake(out data)
+ );
+
+ return result.ToArray();
+ }
+
+ //хранилище пустое
+
+ //Ждем, пока в хранилище не добавят новый элемент
+ //или сработает cancellation
+ await WaitUntilNotEmpty(cancellation)
+ .ConfigureAwait(configureAwait);
+ }
+ while (
+ !cancellation.IsCancellationRequested
+ );
+
+ if (throwOperationCanceledException)
+ {
+ cancellation.ThrowIfCancellationRequested();
+ }
+
+ return new T[0];
+ }
+
+ public async Task<T> ConsumeOrWaitAsync(
+ CancellationToken cancellation = default,
+ bool configureAwait = false,
+ bool throwOperationCanceledException = false
+ )
+ {
+ do
+ {
+ //Если удалось получить элемент из хранилища
+ if (_Storage.TryTake(out T data))
+ {
+ //То берем его
+ return data;
+ }
+
+ //хранилище пустое
+
+ //Ждем, пока в хранилище не добавят новый элемент
+ //или пока запрос не отменят
+ await WaitUntilNotEmpty(cancellation)
+ .ConfigureAwait(configureAwait);
+ } while (
+ !cancellation.IsCancellationRequested
+ );
+
+ if (throwOperationCanceledException)
+ {
+ cancellation.ThrowIfCancellationRequested();
+ }
+
+ return default;
+ }
+ }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/IConcurrentBuffer.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/IConcurrentBuffer.cs
new file mode 100644
index 0000000..9f8279d
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/IConcurrentBuffer.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Threading;
+using System.Collections.Concurrent;
+using System.Collections.Specialized;
+using System.Collections.ObjectModel;
+
+using Tools.CancellationTokenAsync;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer
+{
+ public interface IConcurrentBuffer<T>
+ {
+ /// <summary>
+ /// Рекомендуемый максимальный размер.
+ /// Само хранилище не контролирует размер
+ /// </summary>
+ int RecommendedMaxSize { get; }
+
+ /// <summary>
+ /// Текущий размер коллекции
+ /// </summary>
+ int Size { get; }
+
+ //IConcurrentStore<T> Storage { get; }
+
+ /// <summary>
+ /// Запрашивает группу данных из хранилища для обработки. n - кол-во данных в хранилище.
+ /// Если n = 0, то ожидает поступления данных.
+ /// Если n <= maxBatchSize, то возвращает n записей.
+ /// Если n > maxBatchSize, то возвращает maxBatchSize записей.
+ /// </summary>
+ /// <param name="maxBatchSize">Максимальный размер группы</param>
+ /// <param name="cancellation">Токен, прерывает ожидание новых данных в случае n = 0</param>
+ /// <returns></returns>
+ Task<T[]> ConsumeBatchOrWaitAsync(
+ int maxBatchSize,
+ CancellationToken cancellation = default,
+ bool configureAwait = false,
+ bool throwOperationCanceledException = false
+ );
+
+ /// <summary>
+ /// Извлекает один элемент или ожидает, пока он не появиться или до отмены.
+ /// </summary>
+ Task<T> ConsumeOrWaitAsync(
+ CancellationToken cancellation = default,
+ bool configureAwait = false,
+ bool throwOperationCanceledException = false
+ );
+
+
+ /// <summary>
+ /// Принудительно добавить в хранилище.
+ /// Не проверяет значение RecommendedMaxSize
+ /// </summary>
+ /// <param name="dateEntity"></param>
+ void AddForce(T dateEntity);
+
+ /// <summary>
+ /// Попытка добавить запись в хранилище.
+ /// Запись не будет добавлена, если хранилище заполнено (RecommendedMaxSize).
+ /// При выполнении хранилище не блокируется и значение Size может превысить RecommendedMaxSize.
+ /// </summary>
+ bool TryAdd(T dataEntity);
+
+ }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/ConcurrentBufferPriorityWrapper.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/ConcurrentBufferPriorityWrapper.cs
new file mode 100644
index 0000000..83a31e0
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/ConcurrentBufferPriorityWrapper.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Tools.CancellationTokenAsync;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper
+{
+ public class ConcurrentBufferPriorityWrapper<T, TPriority>
+ : ConcurrentBuffer<T>,
+ IConcurrentBufferPriorityWrapper<T, TPriority>
+ {
+ private readonly IConcurrentStorePriorityWrapper<T, TPriority> _PriorityStorage;
+
+ public ConcurrentBufferPriorityWrapper(
+ int recommendedMaxSize,
+ IConcurrentStorePriorityWrapper<T, TPriority> storage
+ )
+ : base(recommendedMaxSize, storage)
+ {
+ _PriorityStorage = storage;
+ }
+
+ public void AddForce(T dateEntity, TPriority priority)
+ {
+ _PriorityStorage.Add(dateEntity, priority);
+ }
+
+ public bool TryAdd(T dataEntity, TPriority priority)
+ {
+ if (Size >= RecommendedMaxSize)
+ {
+ return false;
+ }
+
+ AddForce(dataEntity, priority);
+ return true;
+ }
+
+ }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/ConcurrentStorePriorityWrapper.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/ConcurrentStorePriorityWrapper.cs
new file mode 100644
index 0000000..f37813a
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/ConcurrentStorePriorityWrapper.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Threading;
+
+using Tools.Collections.Concurrent.AsyncBuffer.Store;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper
+{
+
+ public class ConcurrentStorePriorityWrapper<T, TPriority>
+ : IConcurrentStorePriorityWrapper<T, TPriority>
+ {
+ public readonly SortedDictionary<TPriority, IConcurrentStore<T>> PriorityStorages;
+
+ private int _Size;
+ public int Size
+ => _Size;
+
+ public event Action<IConcurrentStore<T>, T> OnItemAdded;
+ public event Action<IConcurrentStore<T>> OnEmpty;
+
+ public ConcurrentStorePriorityWrapper(
+ SortedDictionary<TPriority, IConcurrentStore<T>> priorityStorages
+ )
+ {
+ _Size = priorityStorages.Sum(e => e.Value.Size);
+ PriorityStorages = priorityStorages;
+ }
+
+ public int Add(T data)
+ {
+ return Add(data, default);
+ }
+ public int Add(T data, TPriority priority)
+ {
+ PriorityStorages[priority].Add(data);
+ Interlocked.Increment(ref _Size);
+ OnItemAdded?.Invoke(this, data);
+ return _Size;
+ }
+
+ public bool TryTake(out T data)
+ {
+ foreach (var elem in PriorityStorages)
+ {
+ if (elem.Value.TryTake(out data))
+ {
+ Interlocked.Decrement(ref _Size);
+
+ if (_Size == 0)
+ {
+ OnEmpty?.Invoke(this);
+ }
+
+ return true;
+ }
+ }
+
+ data = default;
+ return false;
+ }
+ public bool TryTake(out T data, TPriority priority)
+ {
+ if (PriorityStorages[priority].TryTake(out data))
+ {
+ Interlocked.Decrement(ref _Size);
+
+ if (_Size == 0)
+ {
+ OnEmpty?.Invoke(this);
+ }
+
+ return true;
+ }
+
+ data = default;
+ return false;
+ }
+
+
+ public IEnumerable<T> AsIEnumerable()
+ {
+ return PriorityStorages
+ .Values
+ .SelectMany(e => e.AsIEnumerable());
+ }
+
+ public void ForEach(Action<T> action)
+ {
+ foreach (var elem in PriorityStorages)
+ {
+ elem.Value.ForEach(action);
+ }
+ }
+
+ public IReadOnlyDictionary<TPriority, IConcurrentStore<T>> AsDictionary()
+ {
+ return PriorityStorages
+ as IReadOnlyDictionary<TPriority, IConcurrentStore<T>>;
+ }
+ }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/IConcurrentBufferPriorityWrapper.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/IConcurrentBufferPriorityWrapper.cs
new file mode 100644
index 0000000..c453c05
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/IConcurrentBufferPriorityWrapper.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Tools.CancellationTokenAsync;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper
+{
+ public interface IConcurrentBufferPriorityWrapper<T, TPriority>
+ : IConcurrentBuffer<T>
+ {
+ /// <summary>
+ /// Принудительно добавить в хранилище.
+ /// Не проверяет значение RecommendedMaxSize
+ /// </summary>
+ /// <param name="dateEntity"></param>
+ void AddForce(T dateEntity, TPriority priority);
+
+ /// <summary>
+ /// Попытка добавить запись в хранилище.
+ /// Запись не будет добавлена, если хранилище заполнено (RecommendedMaxSize).
+ /// При выполнении хранилище не блокируется, и значение Size может превысить RecommendedMaxSize.
+ /// </summary>
+ bool TryAdd(T dataEntity, TPriority priority);
+
+ }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/IConcurrentStorePriorityWrapper.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/IConcurrentStorePriorityWrapper.cs
new file mode 100644
index 0000000..872686b
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/PriorityWrapper/IConcurrentStorePriorityWrapper.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Tools.Collections.Concurrent.AsyncBuffer.Store;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.PriorityWrapper
+{
+
+ public interface IConcurrentStorePriorityWrapper<T, TPriority>
+ : IConcurrentStore<T>
+ {
+ int Add(T data, TPriority priority);
+
+ bool TryTake(out T data, TPriority priority);
+
+ IReadOnlyDictionary<TPriority, IConcurrentStore<T>> AsDictionary();
+ }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Properties/AssemblyInfo.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..f279ed4
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Общие сведения об этой сборке предоставляются следующим набором
+// набора атрибутов. Измените значения этих атрибутов для изменения сведений,
+// связанные со сборкой.
+[assembly: AssemblyTitle("Tools.Collections.Concurrent.AsyncBuffer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Tools.Collections.Concurrent.AsyncBuffer")]
+[assembly: AssemblyCopyright("Copyright © 2021")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми
+// для компонентов COM. Если необходимо обратиться к типу в этой сборке через
+// COM, задайте атрибуту ComVisible значение TRUE для этого типа.
+[assembly: ComVisible(false)]
+
+// Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM
+[assembly: Guid("97e537c2-2737-46ad-966e-d48e0a93966e")]
+
+// Сведения о версии сборки состоят из указанных ниже четырех значений:
+//
+// Основной номер версии
+// Дополнительный номер версии
+// Номер сборки
+// Редакция
+//
+// Можно задать все значения или принять номера сборки и редакции по умолчанию
+// используя "*", как показано ниже:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/BagStore.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/BagStore.cs
new file mode 100644
index 0000000..7266b0c
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/BagStore.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Threading;
+using System.Collections.Concurrent;
+using System.Collections.Specialized;
+using System.Collections.ObjectModel;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.Store
+{
+
+ public class BagStore<T>
+ : IConcurrentStore<T>
+ {
+ private readonly ConcurrentBag<T> Storage
+ = new ConcurrentBag<T>();
+
+ private int _Size;
+
+ public event Action<IConcurrentStore<T>, T> OnItemAdded;
+ public event Action<IConcurrentStore<T>> OnEmpty;
+
+ public int Size
+ => _Size;
+
+ public int Add(T data)
+ {
+ Storage.Add(data);
+ Interlocked.Increment(ref _Size);
+ OnItemAdded?.Invoke(this, data);
+
+ return _Size;
+ }
+ public bool TryTake(out T data)
+ {
+ if (Storage.TryTake(out data))
+ {
+ Interlocked.Decrement(ref _Size);
+
+ if (_Size == 0)
+ {
+ OnEmpty?.Invoke(this);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public IEnumerable<T> AsIEnumerable()
+ {
+ return Storage;
+ }
+
+ public void ForEach(Action<T> action)
+ {
+ foreach (var elem in Storage)
+ {
+ action(elem);
+ }
+ }
+ }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/IConcurrentStore.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/IConcurrentStore.cs
new file mode 100644
index 0000000..ae016fd
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/IConcurrentStore.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Threading;
+using System.Collections.Concurrent;
+using System.Collections.Specialized;
+using System.Collections.ObjectModel;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.Store
+{
+
+ public interface IConcurrentStore<T>
+ {
+ int Size { get; }
+
+ int Add(T data);
+ bool TryTake(out T data);
+
+ IEnumerable<T> AsIEnumerable();
+ void ForEach(Action<T> action);
+
+
+ /// <summary>
+ /// В хранилище добавлен новый элемент.
+ /// </summary>
+ event Action<IConcurrentStore<T>, T> OnItemAdded;
+
+ /// <summary>
+ /// Хранилище опустело.
+ /// </summary>
+ event Action<IConcurrentStore<T>> OnEmpty;
+
+ }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/QueueStore.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/QueueStore.cs
new file mode 100644
index 0000000..0a94912
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/QueueStore.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Threading;
+using System.Collections.Concurrent;
+using System.Collections.Specialized;
+using System.Collections.ObjectModel;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.Store
+{
+ public class QueueStore<T>
+ : IConcurrentStore<T>
+ {
+ public readonly ConcurrentQueue<T> Storage
+ = new ConcurrentQueue<T>();
+
+ private int _Size;
+ public int Size
+ => _Size;
+
+ public event Action<IConcurrentStore<T>, T> OnItemAdded;
+ public event Action<IConcurrentStore<T>> OnEmpty;
+
+ public int Add(T data)
+ {
+ Storage.Enqueue(data);
+ Interlocked.Increment(ref _Size);
+ OnItemAdded?.Invoke(this, data);
+
+ return _Size;
+ }
+
+ public bool TryTake(out T data)
+ {
+ if (Storage.TryDequeue(out data))
+ {
+ Interlocked.Decrement(ref _Size);
+
+ if (_Size == 0)
+ {
+ OnEmpty?.Invoke(this);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public IEnumerable<T> AsIEnumerable()
+ {
+ return Storage;
+ }
+ public void ForEach(Action<T> action)
+ {
+ foreach (var elem in Storage)
+ {
+ action(elem);
+ }
+ }
+ }
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/StackStore.cs b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/StackStore.cs
new file mode 100644
index 0000000..9c9ba93
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Store/StackStore.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.Threading;
+using System.Collections.Concurrent;
+using System.Collections.Specialized;
+using System.Collections.ObjectModel;
+
+namespace Tools.Collections.Concurrent.AsyncBuffer.Store
+{
+
+ public class StackStore<T>
+ : IConcurrentStore<T>
+ {
+ private readonly ConcurrentStack<T> Storage
+ = new ConcurrentStack<T>();
+
+ private int _Size;
+
+ public event Action<IConcurrentStore<T>, T> OnItemAdded;
+ public event Action<IConcurrentStore<T>> OnEmpty;
+
+ public int Size
+ => _Size;
+
+ public int Add(T data)
+ {
+ Storage.Push(data);
+ Interlocked.Increment(ref _Size);
+ OnItemAdded?.Invoke(this, data);
+
+ return _Size;
+ }
+
+ public bool TryTake(out T data)
+ {
+ if (Storage.TryPop(out data))
+ {
+ Interlocked.Decrement(ref _Size);
+
+ if (_Size == 0)
+ {
+ OnEmpty?.Invoke(this);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ public IEnumerable<T> AsIEnumerable()
+ {
+ return Storage;
+ }
+
+ public void ForEach(Action<T> action)
+ {
+ foreach (var elem in Storage)
+ {
+ action(elem);
+ }
+ }
+ }
+
+
+}
diff --git a/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Tools.Collections.Concurrent.AsyncBuffer.csproj b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Tools.Collections.Concurrent.AsyncBuffer.csproj
new file mode 100644
index 0000000..c3ff244
--- /dev/null
+++ b/src/Tools.Collections/Tools.Collections.Concurrent.AsyncBuffer/Tools.Collections.Concurrent.AsyncBuffer.csproj
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{97E537C2-2737-46AD-966E-D48E0A93966E}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Tools.Collections.Concurrent.AsyncBuffer</RootNamespace>
+ <AssemblyName>Tools.Collections.Concurrent.AsyncBuffer</AssemblyName>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <Deterministic>true</Deterministic>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="ConcurrentBuffer.cs" />
+ <Compile Include="IConcurrentBuffer.cs" />
+ <Compile Include="PriorityWrapper\ConcurrentStorePriorityWrapper.cs" />
+ <Compile Include="PriorityWrapper\ConcurrentBufferPriorityWrapper.cs" />
+ <Compile Include="Store\StackStore.cs" />
+ <Compile Include="Store\BagStore.cs" />
+ <Compile Include="Store\QueueStore.cs" />
+ <Compile Include="Store\IConcurrentStore.cs" />
+ <Compile Include="PriorityWrapper\IConcurrentBufferPriorityWrapper.cs" />
+ <Compile Include="PriorityWrapper\IConcurrentStorePriorityWrapper.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Tools.CancellationTokenAsync\Tools.CancellationTokenAsync.csproj">
+ <Project>{f1de016d-9ac4-4d10-a89a-0142a424c3ad}</Project>
+ <Name>Tools.CancellationTokenAsync</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>
\ No newline at end of file
src/Tools.Collections/Tools.Collections.sln 22(+18 -4)
diff --git a/src/Tools.Collections/Tools.Collections.sln b/src/Tools.Collections/Tools.Collections.sln
index 72e2819..637e8d1 100644
--- a/src/Tools.Collections/Tools.Collections.sln
+++ b/src/Tools.Collections/Tools.Collections.sln
@@ -9,13 +9,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Lib", "Lib", "{E674A5DB-8D7
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{4762CF50-BA4B-443A-954A-803E4CEF6451}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.Concurrent.Extensions", "Tools.Collections.ConcurrentDictonary.Extensions\Tools.Collections.Concurrent.Extensions.csproj", "{7531E7FD-16D7-4111-8FBD-D98F23D7C53C}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tools.Collections.Concurrent.Extensions", "Tools.Collections.ConcurrentDictonary.Extensions\Tools.Collections.Concurrent.Extensions.csproj", "{7531E7FD-16D7-4111-8FBD-D98F23D7C53C}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.SortedDictionarySortKeyItemKey", "Tools.Collections.SortedDictionarySortKeyItemKey\Tools.Collections.SortedDictionarySortKeyItemKey.csproj", "{83C77E76-7114-4494-A7D3-6B4D54767AC6}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tools.Collections.SortedDictionarySortKeyItemKey", "Tools.Collections.SortedDictionarySortKeyItemKey\Tools.Collections.SortedDictionarySortKeyItemKey.csproj", "{83C77E76-7114-4494-A7D3-6B4D54767AC6}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.Concurrent.LinkItemDictionary", "Tools.Collections.LinkItemDictionary\Tools.Collections.Concurrent.LinkItemDictionary.csproj", "{E221963A-526E-43C1-A6D5-BF4D9721BC59}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tools.Collections.Concurrent.LinkItemDictionary", "Tools.Collections.LinkItemDictionary\Tools.Collections.Concurrent.LinkItemDictionary.csproj", "{E221963A-526E-43C1-A6D5-BF4D9721BC59}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.Concurrent.ObjectLinkItemDictionary", "Tools.Collections.ObjectLinkItemDictionary\Tools.Collections.Concurrent.ObjectLinkItemDictionary.csproj", "{0792B9B8-BBB9-4421-81A1-A534B43CA6B8}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tools.Collections.Concurrent.ObjectLinkItemDictionary", "Tools.Collections.ObjectLinkItemDictionary\Tools.Collections.Concurrent.ObjectLinkItemDictionary.csproj", "{0792B9B8-BBB9-4421-81A1-A534B43CA6B8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.Concurrent.AsyncBuffer", "Tools.Collections.Concurrent.AsyncBuffer\Tools.Collections.Concurrent.AsyncBuffer.csproj", "{97E537C2-2737-46AD-966E-D48E0A93966E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.Collections.Concurrent.AsyncBuffer.UnitTest", "Tools.Collections.Concurrent.AsyncBuffer.UnitTest\Tools.Collections.Concurrent.AsyncBuffer.UnitTest.csproj", "{3AC3937E-72B5-47FE-BDBE-44F6E4879215}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -43,6 +47,14 @@ Global
{0792B9B8-BBB9-4421-81A1-A534B43CA6B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0792B9B8-BBB9-4421-81A1-A534B43CA6B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0792B9B8-BBB9-4421-81A1-A534B43CA6B8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {97E537C2-2737-46AD-966E-D48E0A93966E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {97E537C2-2737-46AD-966E-D48E0A93966E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {97E537C2-2737-46AD-966E-D48E0A93966E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {97E537C2-2737-46AD-966E-D48E0A93966E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3AC3937E-72B5-47FE-BDBE-44F6E4879215}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3AC3937E-72B5-47FE-BDBE-44F6E4879215}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3AC3937E-72B5-47FE-BDBE-44F6E4879215}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3AC3937E-72B5-47FE-BDBE-44F6E4879215}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -53,6 +65,8 @@ Global
{83C77E76-7114-4494-A7D3-6B4D54767AC6} = {E674A5DB-8D7A-4650-9D6B-B1881F5B57B4}
{E221963A-526E-43C1-A6D5-BF4D9721BC59} = {E674A5DB-8D7A-4650-9D6B-B1881F5B57B4}
{0792B9B8-BBB9-4421-81A1-A534B43CA6B8} = {E674A5DB-8D7A-4650-9D6B-B1881F5B57B4}
+ {97E537C2-2737-46AD-966E-D48E0A93966E} = {E674A5DB-8D7A-4650-9D6B-B1881F5B57B4}
+ {3AC3937E-72B5-47FE-BDBE-44F6E4879215} = {4762CF50-BA4B-443A-954A-803E4CEF6451}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C32931BC-9551-4A06-9A76-F7E4F162B3C7}