25.09.22, Alice, CircularBuffer, Collections, Arrays
Alisa, CircualarBuffer,
Collections
Для реализации такой функциональности можно
создать несколько вариантов методов, которые будут заполнять различные типы
коллекций. Вот несколько подходов:
1. Через ICollection<T>
csharp
public void GetAllFromLeft(ICollection<T>
collection)
{
_lock.EnterReadLock();
try
{
int current = start;
for (int i = 0; i < count; i++)
{
collection.Add(buffer[current]);
current = (current + 1) % capacity;
}
}
finally
{
_lock.ExitReadLock();
}
}
public void GetAllFromRight(ICollection<T>
collection)
{
_lock.EnterReadLock();
try
{
int current = (start + count - 1) % capacity;
for (int i = 0; i < count; i++)
{
collection.Add(buffer[current]);
current = (current - 1 + capacity) % capacity;
}
}
finally
{
_lock.ExitReadLock();
}
}
2. Через массивы
csharp
public void GetAllFromLeft(T[] array)
{
if (array.Length < count)
throw new ArgumentException("Массив слишком мал для хранения всех элементов");
_lock.EnterReadLock();
try
{
int current = start;
for (int i = 0; i < count; i++)
{
array[i]
= buffer[current];
current = (current + 1) % capacity;
}
}
finally
{
_lock.ExitReadLock();
}
}
public void GetAllFromRight(T[] array)
{
if (array.Length < count)
throw new ArgumentException("Массив слишком мал для хранения всех элементов");
_lock.EnterReadLock();
try
{
int current = (start + count - 1) % capacity;
for (int i = 0; i < count; i++)
{
array[i]
= buffer[current];
current = (current - 1 + capacity) % capacity;
}
}
finally
{
_lock.ExitReadLock();
}
}
3. Комбинированный подход с использованием
обобщений
Можно создать универсальный метод, который будет
работать с любыми коллекциями, реализующими ICollection<T>:
csharp
public void PopulateCollection<TCollection>(TCollection collection)
where TCollection : ICollection<T>
{
_lock.EnterReadLock();
try
{
int current = start;
for (int i = 0; i < count; i++)
{
collection.Add(buffer[current]);
current = (current + 1) % capacity;
}
}
finally
{
_lock.ExitReadLock();
}
}
Важные замечания:
- При работе с
массивами нужно заранее выделять память нужного размера.
- Методы с ICollection<T> будут
работать с любыми коллекциями, которые реализуют этот интерфейс
(например, List<T>, HashSet<T> и т. д.).
- Для безопасности
потоков используется блокировка _lock.
- В случае с
массивами добавлена проверка на достаточный размер.
- Можно
дополнительно добавить обработку исключений и валидацию входных
параметров.
Пример использования:
csharp
List<int> list = new List<int>();
buffer.GetAllFromLeft(list);
int[] array = new int[buffer.Count];
buffer.GetAllFromRight(array);
Такой подход обеспечивает
гибкость и возможность выбора оптимального способа извлечения данных в
зависимости от конкретной задачи.
public void
PopulateCollection<TCollection>(TCollection collection) where TCollection
: ICollection<T> { _lock.EnterReadLock(); try { int current = start; for
(int i = 0; i < count; i++) { collection.Add(buffer[current]); current =
(current + 1) % capacity; } } finally { _lock.ExitReadLock(); } } Надо две таких функций -
PopulateCollectionFromLeft и - PopulateCollectiomFromRight
Вот реализация двух методов:
csharp
// Заполнение
коллекции элементами слева направо
public void PopulateCollectionFromLeft<TCollection>(TCollection collection)
where TCollection : ICollection<T>
{
_lock.EnterReadLock();
try
{
int current = start; // начинаем с начальной позиции
for (int i = 0; i < count; i++)
{
collection.Add(buffer[current]); // добавляем элемент в коллекцию
current = (current + 1) % capacity; // переходим к следующему элементу с
учётом цикличности
}
}
finally
{
_lock.ExitReadLock();
}
}
// Заполнение
коллекции элементами справа налево
public void PopulateCollectionFromRight<TCollection>(TCollection collection)
where TCollection : ICollection<T>
{
_lock.EnterReadLock();
try
{
int current = (start + count - 1) % capacity; // начинаем с последнего элемента
for (int i = 0; i < count; i++)
{
collection.Add(buffer[current]); // добавляем элемент в коллекцию
current = (current - 1 + capacity) % capacity; // переходим к предыдущему элементу с
учётом цикличности
}
}
finally
{
_lock.ExitReadLock();
}
}
Объяснение работы методов:
- PopulateCollectionFromLeft:
- начинает обход
буфера с позиции start;
- последовательно
добавляет элементы слева направо;
- использует
операцию % capacity для корректной работы
с кольцевым буфером;
- работает с любой
коллекцией, реализующей интерфейс ICollection<T>.
- PopulateCollectionFromRight:
- начинает обход с
последнего элемента буфера (start + count -
1);
- добавляет
элементы в обратном направлении (справа налево);
- корректно
обрабатывает цикличность буфера через (current - 1 +
capacity) % capacity;
- также работает с
любыми коллекциями, реализующими ICollection<T>.
Пример использования:
csharp
var buffer = new ThreadSafeCircularBuffer<int>(5);
buffer.EnqueueRight(1);
buffer.EnqueueRight(2);
buffer.EnqueueRight(3);
buffer.EnqueueRight(4);
buffer.EnqueueRight(5);
var listLeft = new List<int>();
buffer.PopulateCollectionFromLeft(listLeft); // [1, 2, 3, 4, 5]
var listRight = new List<int>();
buffer.PopulateCollectionFromRight(listRight); // [5, 4, 3, 2, 1]
Дополнительные улучшения:
- можно добавить
проверку на null для параметра collection;
- добавить
обработку исключений при добавлении элементов;
- добавить проверку
на достаточный размер коллекции (если это необходимо);
- создать
перегруженные версии методов с ограничением количества копируемых
элементов.
Эти методы обеспечивают гибкую
работу с кольцевым буфером и позволяют легко переносить данные в различные типы
коллекций.
Комментариев нет:
Отправить комментарий