diff --git a/Backup.AWS/AmazonExtensions.cs b/Backup.AWS/AmazonExtensions.cs
index 1a47c1a6..11fc4eb9 100644
--- a/Backup.AWS/AmazonExtensions.cs
+++ b/Backup.AWS/AmazonExtensions.cs
@@ -1,57 +1,56 @@
-namespace Ecng.Backup.Amazon
-{
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Reflection;
+namespace Ecng.Backup.Amazon;
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+using global::Amazon;
- using global::Amazon;
+using Ecng.Common;
- using Ecng.Common;
+///
+/// Extension class for AWS.
+///
+[CLSCompliant(false)]
+public static class AmazonExtensions
+{
+ private static RegionEndpoint[] _endpoints;
///
- /// Extension class for AWS.
+ /// All regions.
///
- [CLSCompliant(false)]
- public static class AmazonExtensions
+ public static IEnumerable Endpoints
{
- private static RegionEndpoint[] _endpoints;
-
- ///
- /// All regions.
- ///
- public static IEnumerable Endpoints
+ get
{
- get
+ lock (typeof(AmazonExtensions))
{
- lock (typeof(AmazonExtensions))
- {
- _endpoints ??= [.. typeof(RegionEndpoint)
- .GetFields(BindingFlags.Static | BindingFlags.Public)
- .Where(f => f.FieldType == typeof(RegionEndpoint))
- .Select(f => (RegionEndpoint)f.GetValue(null))];
- }
-
- return _endpoints;
+ _endpoints ??= [.. typeof(RegionEndpoint)
+ .GetFields(BindingFlags.Static | BindingFlags.Public)
+ .Where(f => f.FieldType == typeof(RegionEndpoint))
+ .Select(f => (RegionEndpoint)f.GetValue(null))];
}
+
+ return _endpoints;
}
+ }
- ///
- /// Get region by name.
- ///
- /// Region name.
- /// Region.
- public static RegionEndpoint GetEndpoint(string name)
- {
- if (name.IsEmpty())
- throw new ArgumentNullException(nameof(name));
+ ///
+ /// Get region by name.
+ ///
+ /// Region name.
+ /// Region.
+ public static RegionEndpoint GetEndpoint(string name)
+ {
+ if (name.IsEmpty())
+ throw new ArgumentNullException(nameof(name));
- var region = Endpoints.FirstOrDefault(e =>
- e.SystemName.EqualsIgnoreCase(name) ||
- e.SystemName.Remove("-").EqualsIgnoreCase(name) ||
- e.DisplayName.EqualsIgnoreCase(name));
+ var region = Endpoints.FirstOrDefault(e =>
+ e.SystemName.EqualsIgnoreCase(name) ||
+ e.SystemName.Remove("-").EqualsIgnoreCase(name) ||
+ e.DisplayName.EqualsIgnoreCase(name));
- return region ?? RegionEndpoint.GetBySystemName(name);
- }
+ return region ?? RegionEndpoint.GetBySystemName(name);
}
}
\ No newline at end of file
diff --git a/Backup.AWS/AmazonGlacierService.cs b/Backup.AWS/AmazonGlacierService.cs
index 85460def..7ee148b6 100644
--- a/Backup.AWS/AmazonGlacierService.cs
+++ b/Backup.AWS/AmazonGlacierService.cs
@@ -1,144 +1,143 @@
-namespace Ecng.Backup.Amazon
-{
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Threading;
- using System.Threading.Tasks;
+namespace Ecng.Backup.Amazon;
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
- using global::Amazon;
- using global::Amazon.Runtime;
- using global::Amazon.Glacier.Model;
- using global::Amazon.Glacier;
+using global::Amazon;
+using global::Amazon.Runtime;
+using global::Amazon.Glacier.Model;
+using global::Amazon.Glacier;
- using Ecng.Common;
+using Ecng.Common;
+
+///
+/// The data storage service based on Amazon Glacier https://aws.amazon.com/s3/glacier/ .
+///
+public class AmazonGlacierService : Disposable, IBackupService
+{
+ private readonly IAmazonGlacier _client;
+ private readonly string _vaultName;
+ private readonly AWSCredentials _credentials;
+ private readonly RegionEndpoint _endpoint;
+ private const int _bufferSize = FileSizes.MB * 100;
///
- /// The data storage service based on Amazon Glacier https://aws.amazon.com/s3/glacier/ .
+ /// Initializes a new instance of the .
///
- public class AmazonGlacierService : Disposable, IBackupService
+ /// Region address.
+ /// Storage name.
+ /// Key.
+ /// Secret.
+ public AmazonGlacierService(string endpoint, string bucket, string accessKey, string secretKey)
+ : this(AmazonExtensions.GetEndpoint(endpoint), bucket, accessKey, secretKey)
{
- private readonly IAmazonGlacier _client;
- private readonly string _vaultName;
- private readonly AWSCredentials _credentials;
- private readonly RegionEndpoint _endpoint;
- private const int _bufferSize = FileSizes.MB * 100;
-
- ///
- /// Initializes a new instance of the .
- ///
- /// Region address.
- /// Storage name.
- /// Key.
- /// Secret.
- public AmazonGlacierService(string endpoint, string bucket, string accessKey, string secretKey)
- : this(AmazonExtensions.GetEndpoint(endpoint), bucket, accessKey, secretKey)
- {
- }
+ }
- ///
- /// Initializes a new instance of the .
- ///
- /// Region address.
- /// Storage name.
- /// Key.
- /// Secret.
- [CLSCompliant(false)]
- public AmazonGlacierService(RegionEndpoint endpoint, string vaultName, string accessKey, string secretKey)
- {
- _credentials = new BasicAWSCredentials(accessKey, secretKey);
- _endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint));
- _vaultName = vaultName.ThrowIfEmpty(nameof(vaultName));
- _client = new AmazonGlacierClient(_credentials, _endpoint);
- }
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// Region address.
+ /// Storage name.
+ /// Key.
+ /// Secret.
+ [CLSCompliant(false)]
+ public AmazonGlacierService(RegionEndpoint endpoint, string vaultName, string accessKey, string secretKey)
+ {
+ _credentials = new BasicAWSCredentials(accessKey, secretKey);
+ _endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint));
+ _vaultName = vaultName.ThrowIfEmpty(nameof(vaultName));
+ _client = new AmazonGlacierClient(_credentials, _endpoint);
+ }
- bool IBackupService.CanFolders => false;
- bool IBackupService.CanPublish => false;
- bool IBackupService.CanPartialDownload => true;
+ bool IBackupService.CanFolders => false;
+ bool IBackupService.CanPublish => false;
+ bool IBackupService.CanPartialDownload => true;
- IAsyncEnumerable IBackupService.FindAsync(BackupEntry parent, string criteria, CancellationToken cancellationToken)
- {
- throw new NotImplementedException();
- }
+ IAsyncEnumerable IBackupService.FindAsync(BackupEntry parent, string criteria, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
- Task IBackupService.DeleteAsync(BackupEntry entry, CancellationToken cancellationToken)
- => _client.DeleteArchiveAsync(new()
- {
- VaultName = _vaultName,
- ArchiveId = entry.Name,
- }, cancellationToken);
+ Task IBackupService.DeleteAsync(BackupEntry entry, CancellationToken cancellationToken)
+ => _client.DeleteArchiveAsync(new()
+ {
+ VaultName = _vaultName,
+ ArchiveId = entry.Name,
+ }, cancellationToken);
- Task IBackupService.FillInfoAsync(BackupEntry entry, CancellationToken cancellationToken)
- => throw new NotImplementedException();
+ Task IBackupService.FillInfoAsync(BackupEntry entry, CancellationToken cancellationToken)
+ => throw new NotImplementedException();
- async Task IBackupService.DownloadAsync(BackupEntry entry, Stream stream, long? offset, long? length, Action progress, CancellationToken cancellationToken)
+ async Task IBackupService.DownloadAsync(BackupEntry entry, Stream stream, long? offset, long? length, Action progress, CancellationToken cancellationToken)
+ {
+ GetJobOutputRequest request = new()
{
- GetJobOutputRequest request = new()
- {
- //JobId = jobId,
- VaultName = _vaultName,
- };
+ //JobId = jobId,
+ VaultName = _vaultName,
+ };
- if (offset != null || length != null)
- {
- if (offset is null || length is null)
- throw new NotSupportedException();
+ if (offset != null || length != null)
+ {
+ if (offset is null || length is null)
+ throw new NotSupportedException();
- request.Range = $"bytes={offset}-{offset + length}";
- }
+ request.Range = $"bytes={offset}-{offset + length}";
+ }
- var response = await _client.GetJobOutputAsync(request, cancellationToken);
+ var response = await _client.GetJobOutputAsync(request, cancellationToken);
- using var webStream = response.Body;
+ using var webStream = response.Body;
- var bytes = new byte[_bufferSize];
- var readTotal = 0L;
+ var bytes = new byte[_bufferSize];
+ var readTotal = 0L;
- var prevProgress = -1;
+ var prevProgress = -1;
- var objLen = 0L; //TODO
+ var objLen = 0L; //TODO
- while (readTotal < objLen)
- {
- var expected = (int)(objLen - readTotal).Min(_bufferSize);
- var actual = await webStream.ReadAsync(bytes, 0, expected, cancellationToken);
+ while (readTotal < objLen)
+ {
+ var expected = (int)(objLen - readTotal).Min(_bufferSize);
+ var actual = await webStream.ReadAsync(bytes, 0, expected, cancellationToken);
- if (actual == 0)
- break;
+ if (actual == 0)
+ break;
- await stream.WriteAsync(bytes, 0, actual, cancellationToken);
+ await stream.WriteAsync(bytes, 0, actual, cancellationToken);
- readTotal += actual;
+ readTotal += actual;
- var currProgress = (int)(readTotal * 100L / objLen);
+ var currProgress = (int)(readTotal * 100L / objLen);
- if (currProgress < 100 && prevProgress < currProgress)
- {
- progress(currProgress);
- prevProgress = currProgress;
- }
+ if (currProgress < 100 && prevProgress < currProgress)
+ {
+ progress(currProgress);
+ prevProgress = currProgress;
}
}
+ }
- Task IBackupService.UploadAsync(BackupEntry entry, Stream stream, Action progress, CancellationToken cancellationToken)
- => throw new NotImplementedException();
+ Task IBackupService.UploadAsync(BackupEntry entry, Stream stream, Action progress, CancellationToken cancellationToken)
+ => throw new NotImplementedException();
- Task IBackupService.PublishAsync(BackupEntry entry, CancellationToken cancellationToken)
- => throw new NotSupportedException();
+ Task IBackupService.PublishAsync(BackupEntry entry, CancellationToken cancellationToken)
+ => throw new NotSupportedException();
- Task IBackupService.UnPublishAsync(BackupEntry entry, CancellationToken cancellationToken)
- => throw new NotSupportedException();
+ Task IBackupService.UnPublishAsync(BackupEntry entry, CancellationToken cancellationToken)
+ => throw new NotSupportedException();
- Task IBackupService.CreateFolder(BackupEntry entry, CancellationToken cancellationToken)
- => throw new NotSupportedException();
+ Task IBackupService.CreateFolder(BackupEntry entry, CancellationToken cancellationToken)
+ => throw new NotSupportedException();
- ///
- /// Disposes the managed resources.
- ///
- protected override void DisposeManaged()
- {
- _client.Dispose();
- base.DisposeManaged();
- }
+ ///
+ /// Disposes the managed resources.
+ ///
+ protected override void DisposeManaged()
+ {
+ _client.Dispose();
+ base.DisposeManaged();
}
}
\ No newline at end of file
diff --git a/Backup.AWS/AmazonS3Service.cs b/Backup.AWS/AmazonS3Service.cs
index 84f2a7ba..da8377b3 100644
--- a/Backup.AWS/AmazonS3Service.cs
+++ b/Backup.AWS/AmazonS3Service.cs
@@ -1,307 +1,306 @@
-namespace Ecng.Backup.Amazon
+namespace Ecng.Backup.Amazon;
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Net;
+using System.Runtime.CompilerServices;
+
+using global::Amazon;
+using global::Amazon.Runtime;
+using global::Amazon.S3;
+using global::Amazon.S3.Model;
+
+using Ecng.Common;
+
+///
+/// The data storage service based on Amazon S3 https://aws.amazon.com/s3/ .
+///
+public class AmazonS3Service : Disposable, IBackupService
{
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Threading;
- using System.Threading.Tasks;
- using System.Net;
- using System.Runtime.CompilerServices;
-
- using global::Amazon;
- using global::Amazon.Runtime;
- using global::Amazon.S3;
- using global::Amazon.S3.Model;
-
- using Ecng.Common;
+ private readonly string _bucket;
+ private readonly IAmazonS3 _client;
+ private const int _bufferSize = FileSizes.MB * 10;
+ private readonly AWSCredentials _credentials;
+ private readonly RegionEndpoint _endpoint;
///
- /// The data storage service based on Amazon S3 https://aws.amazon.com/s3/ .
+ /// Initializes a new instance of the .
///
- public class AmazonS3Service : Disposable, IBackupService
+ /// Region address.
+ /// Storage name.
+ /// Key.
+ /// Secret.
+ public AmazonS3Service(string endpoint, string bucket, string accessKey, string secretKey)
+ : this(AmazonExtensions.GetEndpoint(endpoint), bucket, accessKey, secretKey)
{
- private readonly string _bucket;
- private readonly IAmazonS3 _client;
- private const int _bufferSize = FileSizes.MB * 10;
- private readonly AWSCredentials _credentials;
- private readonly RegionEndpoint _endpoint;
-
- ///
- /// Initializes a new instance of the .
- ///
- /// Region address.
- /// Storage name.
- /// Key.
- /// Secret.
- public AmazonS3Service(string endpoint, string bucket, string accessKey, string secretKey)
- : this(AmazonExtensions.GetEndpoint(endpoint), bucket, accessKey, secretKey)
- {
- }
+ }
- ///
- /// Initializes a new instance of the .
- ///
- /// Region address.
- /// Storage name.
- /// Key.
- /// Secret.
- [CLSCompliant(false)]
- public AmazonS3Service(RegionEndpoint endpoint, string bucket, string accessKey, string secretKey)
- {
- _credentials = new BasicAWSCredentials(accessKey, secretKey);
- _endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint));
- _bucket = bucket.ThrowIfEmpty(nameof(bucket));
- _client = new AmazonS3Client(_credentials, _endpoint);
- }
+ ///
+ /// Initializes a new instance of the .
+ ///
+ /// Region address.
+ /// Storage name.
+ /// Key.
+ /// Secret.
+ [CLSCompliant(false)]
+ public AmazonS3Service(RegionEndpoint endpoint, string bucket, string accessKey, string secretKey)
+ {
+ _credentials = new BasicAWSCredentials(accessKey, secretKey);
+ _endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint));
+ _bucket = bucket.ThrowIfEmpty(nameof(bucket));
+ _client = new AmazonS3Client(_credentials, _endpoint);
+ }
- bool IBackupService.CanFolders => false;
- bool IBackupService.CanPublish => true;
- bool IBackupService.CanPartialDownload => true;
+ bool IBackupService.CanFolders => false;
+ bool IBackupService.CanPublish => true;
+ bool IBackupService.CanPartialDownload => true;
- async IAsyncEnumerable IBackupService.FindAsync(BackupEntry parent, string criteria, [EnumeratorCancellation]CancellationToken cancellationToken)
+ async IAsyncEnumerable IBackupService.FindAsync(BackupEntry parent, string criteria, [EnumeratorCancellation]CancellationToken cancellationToken)
+ {
+ //if (parent != null && !parent.IsDirectory)
+ // throw new ArgumentException("{0} should be directory.".Put(parent.Name), "parent");
+
+ var request = new ListObjectsV2Request
{
- //if (parent != null && !parent.IsDirectory)
- // throw new ArgumentException("{0} should be directory.".Put(parent.Name), "parent");
+ BucketName = _bucket,
+ Prefix = parent != null ? parent.GetFullPath() : null,
+ };
- var request = new ListObjectsV2Request
- {
- BucketName = _bucket,
- Prefix = parent != null ? parent.GetFullPath() : null,
- };
+ if (!criteria.IsEmpty())
+ request.Prefix += "/" + criteria;
- if (!criteria.IsEmpty())
- request.Prefix += "/" + criteria;
+ do
+ {
+ var response = await _client.ListObjectsV2Async(request, cancellationToken);
- do
+ foreach (var entry in response.S3Objects)
{
- var response = await _client.ListObjectsV2Async(request, cancellationToken);
-
- foreach (var entry in response.S3Objects)
- {
- var be = GetPath(entry.Key);
- be.LastModified = entry.LastModified;
- be.Size = entry.Size;
- yield return be;
- }
+ var be = GetPath(entry.Key);
+ be.LastModified = entry.LastModified;
+ be.Size = entry.Size;
+ yield return be;
+ }
- foreach (var commonPrefix in response.CommonPrefixes)
+ foreach (var commonPrefix in response.CommonPrefixes)
+ {
+ yield return new()
{
- yield return new()
- {
- Name = commonPrefix,
- Parent = parent,
- };
- }
-
- if (response.IsTruncated)
- request.ContinuationToken = response.NextContinuationToken;
- else
- break;
+ Name = commonPrefix,
+ Parent = parent,
+ };
}
- while (true);
+
+ if (response.IsTruncated)
+ request.ContinuationToken = response.NextContinuationToken;
+ else
+ break;
}
+ while (true);
+ }
- Task IBackupService.DeleteAsync(BackupEntry entry, CancellationToken cancellationToken)
- => _client.DeleteObjectAsync(_bucket, entry.GetFullPath(), cancellationToken);
+ Task IBackupService.DeleteAsync(BackupEntry entry, CancellationToken cancellationToken)
+ => _client.DeleteObjectAsync(_bucket, entry.GetFullPath(), cancellationToken);
- async Task IBackupService.DownloadAsync(BackupEntry entry, Stream stream, long? offset, long? length, Action progress, CancellationToken cancellationToken)
- {
- if (entry is null)
- throw new ArgumentNullException(nameof(entry));
+ async Task IBackupService.DownloadAsync(BackupEntry entry, Stream stream, long? offset, long? length, Action progress, CancellationToken cancellationToken)
+ {
+ if (entry is null)
+ throw new ArgumentNullException(nameof(entry));
- if (stream is null)
- throw new ArgumentNullException(nameof(stream));
+ if (stream is null)
+ throw new ArgumentNullException(nameof(stream));
- if (progress is null)
- throw new ArgumentNullException(nameof(progress));
+ if (progress is null)
+ throw new ArgumentNullException(nameof(progress));
- var key = entry.GetFullPath();
+ var key = entry.GetFullPath();
- var request = new GetObjectRequest
- {
- BucketName = _bucket,
- Key = key,
- };
+ var request = new GetObjectRequest
+ {
+ BucketName = _bucket,
+ Key = key,
+ };
- if (offset != null || length != null)
- {
- if (offset is null || length is null)
- throw new NotSupportedException();
+ if (offset != null || length != null)
+ {
+ if (offset is null || length is null)
+ throw new NotSupportedException();
- request.ByteRange = new(offset.Value, offset.Value + length.Value);
- }
+ request.ByteRange = new(offset.Value, offset.Value + length.Value);
+ }
- var bytes = new byte[_bufferSize];
- var readTotal = 0L;
+ var bytes = new byte[_bufferSize];
+ var readTotal = 0L;
- var prevProgress = -1;
+ var prevProgress = -1;
- using (var response = await _client.GetObjectAsync(request, cancellationToken))
- using (var responseStream = response.ResponseStream)
- {
- var objLen = response.ContentLength;
+ using (var response = await _client.GetObjectAsync(request, cancellationToken))
+ using (var responseStream = response.ResponseStream)
+ {
+ var objLen = response.ContentLength;
- while (readTotal < objLen)
- {
- var expected = (int)(objLen - readTotal).Min(_bufferSize);
- var actual = await responseStream.ReadAsync(bytes, 0, expected, cancellationToken);
+ while (readTotal < objLen)
+ {
+ var expected = (int)(objLen - readTotal).Min(_bufferSize);
+ var actual = await responseStream.ReadAsync(bytes, 0, expected, cancellationToken);
- if (actual == 0)
- break;
+ if (actual == 0)
+ break;
- await stream.WriteAsync(bytes, 0, actual, cancellationToken);
+ await stream.WriteAsync(bytes, 0, actual, cancellationToken);
- readTotal += actual;
+ readTotal += actual;
- var currProgress = (int)(readTotal * 100L / objLen);
+ var currProgress = (int)(readTotal * 100L / objLen);
- if (currProgress < 100 && prevProgress < currProgress)
- {
- progress(currProgress);
- prevProgress = currProgress;
- }
+ if (currProgress < 100 && prevProgress < currProgress)
+ {
+ progress(currProgress);
+ prevProgress = currProgress;
}
}
-
- if (prevProgress < 100)
- progress(100);
}
- async Task IBackupService.UploadAsync(BackupEntry entry, Stream stream, Action progress, CancellationToken cancellationToken)
- {
- if (entry is null)
- throw new ArgumentNullException(nameof(entry));
-
- if (stream is null)
- throw new ArgumentNullException(nameof(stream));
-
- if (progress is null)
- throw new ArgumentNullException(nameof(progress));
-
- var key = entry.GetFullPath();
-
- var initResponse = await _client.InitiateMultipartUploadAsync(new()
- {
- BucketName = _bucket,
- Key = key,
- }, cancellationToken);
+ if (prevProgress < 100)
+ progress(100);
+ }
- var filePosition = 0L;
- var prevProgress = -1;
+ async Task IBackupService.UploadAsync(BackupEntry entry, Stream stream, Action progress, CancellationToken cancellationToken)
+ {
+ if (entry is null)
+ throw new ArgumentNullException(nameof(entry));
- var etags = new List();
+ if (stream is null)
+ throw new ArgumentNullException(nameof(stream));
- var partNum = 1;
+ if (progress is null)
+ throw new ArgumentNullException(nameof(progress));
- while (filePosition < stream.Length)
- {
- var response = await _client.UploadPartAsync(new()
- {
- BucketName = _bucket,
- UploadId = initResponse.UploadId,
- PartNumber = partNum,
- PartSize = _bufferSize,
- //FilePosition = filePosition,
- InputStream = stream,
- Key = key
- }, cancellationToken);
+ var key = entry.GetFullPath();
- etags.Add(new(partNum, response.ETag));
+ var initResponse = await _client.InitiateMultipartUploadAsync(new()
+ {
+ BucketName = _bucket,
+ Key = key,
+ }, cancellationToken);
- filePosition += _bufferSize;
+ var filePosition = 0L;
+ var prevProgress = -1;
- var currProgress = (int)(filePosition.Min(stream.Length) * 100 / stream.Length);
+ var etags = new List();
- if (currProgress > prevProgress)
- {
- progress(currProgress);
- prevProgress = currProgress;
- }
+ var partNum = 1;
- partNum++;
- }
-
- await _client.CompleteMultipartUploadAsync(new()
+ while (filePosition < stream.Length)
+ {
+ var response = await _client.UploadPartAsync(new()
{
BucketName = _bucket,
UploadId = initResponse.UploadId,
- Key = key,
- PartETags = etags
+ PartNumber = partNum,
+ PartSize = _bufferSize,
+ //FilePosition = filePosition,
+ InputStream = stream,
+ Key = key
}, cancellationToken);
- if (prevProgress < 100)
- progress(100);
- }
+ etags.Add(new(partNum, response.ETag));
- Task IBackupService.CreateFolder(BackupEntry entry, CancellationToken cancellationToken)
- => throw new NotSupportedException();
+ filePosition += _bufferSize;
- async Task IBackupService.FillInfoAsync(BackupEntry entry, CancellationToken cancellationToken)
- {
- var key = entry.GetFullPath();
+ var currProgress = (int)(filePosition.Min(stream.Length) * 100 / stream.Length);
- var response = await _client.GetObjectMetadataAsync(new()
+ if (currProgress > prevProgress)
{
- BucketName = _bucket,
- Key = key,
- }, cancellationToken);
+ progress(currProgress);
+ prevProgress = currProgress;
+ }
- entry.Size = response.ContentLength;
+ partNum++;
}
- async Task IBackupService.PublishAsync(BackupEntry entry, CancellationToken cancellationToken)
+ await _client.CompleteMultipartUploadAsync(new()
{
- var key = entry.GetFullPath();
+ BucketName = _bucket,
+ UploadId = initResponse.UploadId,
+ Key = key,
+ PartETags = etags
+ }, cancellationToken);
+
+ if (prevProgress < 100)
+ progress(100);
+ }
- var response = await _client.PutACLAsync(new()
- {
- BucketName = _bucket,
- Key = key,
- CannedACL = S3CannedACL.PublicRead,
- }, cancellationToken);
+ Task IBackupService.CreateFolder(BackupEntry entry, CancellationToken cancellationToken)
+ => throw new NotSupportedException();
- if (response.HttpStatusCode != HttpStatusCode.OK)
- throw new InvalidOperationException(response.HttpStatusCode.To());
-
- return $"https://{_bucket}.s3.{_endpoint.SystemName}.amazonaws.com/{key}";
- }
+ async Task IBackupService.FillInfoAsync(BackupEntry entry, CancellationToken cancellationToken)
+ {
+ var key = entry.GetFullPath();
- async Task IBackupService.UnPublishAsync(BackupEntry entry, CancellationToken cancellationToken)
+ var response = await _client.GetObjectMetadataAsync(new()
{
- var key = entry.GetFullPath();
+ BucketName = _bucket,
+ Key = key,
+ }, cancellationToken);
- var response = await _client.PutACLAsync(new()
- {
- BucketName = _bucket,
- Key = key,
- CannedACL = S3CannedACL.Private,
- }, cancellationToken);
+ entry.Size = response.ContentLength;
+ }
- if (response.HttpStatusCode != HttpStatusCode.OK)
- throw new InvalidOperationException(response.HttpStatusCode.To());
- }
+ async Task IBackupService.PublishAsync(BackupEntry entry, CancellationToken cancellationToken)
+ {
+ var key = entry.GetFullPath();
- private static BackupEntry GetPath(string key)
+ var response = await _client.PutACLAsync(new()
{
- var entities = key.Split('/').Select(p => new BackupEntry { Name = p }).ToArray();
+ BucketName = _bucket,
+ Key = key,
+ CannedACL = S3CannedACL.PublicRead,
+ }, cancellationToken);
+
+ if (response.HttpStatusCode != HttpStatusCode.OK)
+ throw new InvalidOperationException(response.HttpStatusCode.To());
+
+ return $"https://{_bucket}.s3.{_endpoint.SystemName}.amazonaws.com/{key}";
+ }
- BackupEntry parent = null;
+ async Task IBackupService.UnPublishAsync(BackupEntry entry, CancellationToken cancellationToken)
+ {
+ var key = entry.GetFullPath();
- foreach (var entity in entities)
- {
- entity.Parent = parent;
- parent = entity;
- }
+ var response = await _client.PutACLAsync(new()
+ {
+ BucketName = _bucket,
+ Key = key,
+ CannedACL = S3CannedACL.Private,
+ }, cancellationToken);
- return entities.Last();
- }
+ if (response.HttpStatusCode != HttpStatusCode.OK)
+ throw new InvalidOperationException(response.HttpStatusCode.To());
+ }
+
+ private static BackupEntry GetPath(string key)
+ {
+ var entities = key.Split('/').Select(p => new BackupEntry { Name = p }).ToArray();
- ///
- protected override void DisposeManaged()
+ BackupEntry parent = null;
+
+ foreach (var entity in entities)
{
- _client.Dispose();
- base.DisposeManaged();
+ entity.Parent = parent;
+ parent = entity;
}
+
+ return entities.Last();
+ }
+
+ ///
+ protected override void DisposeManaged()
+ {
+ _client.Dispose();
+ base.DisposeManaged();
}
}
\ No newline at end of file
diff --git a/Backup/IBackupService.cs b/Backup/IBackupService.cs
index 05cb85b2..744cfc33 100644
--- a/Backup/IBackupService.cs
+++ b/Backup/IBackupService.cs
@@ -1,100 +1,99 @@
-namespace Ecng.Backup
-{
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Threading;
- using System.Threading.Tasks;
+namespace Ecng.Backup;
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+///
+/// The interface describing online data storage service.
+///
+public interface IBackupService : IDisposable
+{
///
- /// The interface describing online data storage service.
+ /// Is publishing feature available.
///
- public interface IBackupService : IDisposable
- {
- ///
- /// Is publishing feature available.
- ///
- bool CanPublish { get; }
+ bool CanPublish { get; }
- ///
- /// Is folders feature available.
- ///
- bool CanFolders { get; }
+ ///
+ /// Is folders feature available.
+ ///
+ bool CanFolders { get; }
- ///
- /// Is partial download feature available.
- ///
- bool CanPartialDownload { get; }
+ ///
+ /// Is partial download feature available.
+ ///
+ bool CanPartialDownload { get; }
- ///
- /// Is partial upload feature available.
- ///
- ///
- ///
- ///
- Task CreateFolder(BackupEntry entry, CancellationToken cancellationToken = default);
+ ///
+ /// Is partial upload feature available.
+ ///
+ ///
+ ///
+ ///
+ Task CreateFolder(BackupEntry entry, CancellationToken cancellationToken = default);
- ///
- /// Find files by the specified criteria.
- ///
- /// Parent element. Can be null.
- /// Criteria.
- ///
- /// File list.
- IAsyncEnumerable FindAsync(BackupEntry parent, string criteria, CancellationToken cancellationToken = default);
+ ///
+ /// Find files by the specified criteria.
+ ///
+ /// Parent element. Can be null.
+ /// Criteria.
+ ///
+ /// File list.
+ IAsyncEnumerable FindAsync(BackupEntry parent, string criteria, CancellationToken cancellationToken = default);
- ///
- /// Fill file info.
- ///
- /// Element.
- ///
- ///
- Task FillInfoAsync(BackupEntry entry, CancellationToken cancellationToken = default);
+ ///
+ /// Fill file info.
+ ///
+ /// Element.
+ ///
+ ///
+ Task FillInfoAsync(BackupEntry entry, CancellationToken cancellationToken = default);
- ///
- /// Delete file from the service.
- ///
- /// Element.
- ///
- ///
- Task DeleteAsync(BackupEntry entry, CancellationToken cancellationToken = default);
+ ///
+ /// Delete file from the service.
+ ///
+ /// Element.
+ ///
+ ///
+ Task DeleteAsync(BackupEntry entry, CancellationToken cancellationToken = default);
- ///
- /// Save file.
- ///
- /// Element.
- ///
- ///
- ///
- /// Progress notification.
- ///
- ///
- Task DownloadAsync(BackupEntry entry, Stream stream, long? offset, long? length, Action progress, CancellationToken cancellationToken = default);
+ ///
+ /// Save file.
+ ///
+ /// Element.
+ ///
+ ///
+ ///
+ /// Progress notification.
+ ///
+ ///
+ Task DownloadAsync(BackupEntry entry, Stream stream, long? offset, long? length, Action progress, CancellationToken cancellationToken = default);
- ///
- /// Upload file.
- ///
- /// Element.
- /// The stream of the open file into which data from the service will be downloaded.
- /// Progress notification.
- ///
- ///
- Task UploadAsync(BackupEntry entry, Stream stream, Action progress, CancellationToken cancellationToken = default);
+ ///
+ /// Upload file.
+ ///
+ /// Element.
+ /// The stream of the open file into which data from the service will be downloaded.
+ /// Progress notification.
+ ///
+ ///
+ Task UploadAsync(BackupEntry entry, Stream stream, Action progress, CancellationToken cancellationToken = default);
- ///
- /// Get public url for the specified element.
- ///
- /// Element.
- ///
- /// Public url.
- Task PublishAsync(BackupEntry entry, CancellationToken cancellationToken = default);
+ ///
+ /// Get public url for the specified element.
+ ///
+ /// Element.
+ ///
+ /// Public url.
+ Task PublishAsync(BackupEntry entry, CancellationToken cancellationToken = default);
- ///
- /// Remove public url for the specified element.
- ///
- /// Element.
- ///
- ///
- Task UnPublishAsync(BackupEntry entry, CancellationToken cancellationToken = default);
- }
+ ///
+ /// Remove public url for the specified element.
+ ///
+ /// Element.
+ ///
+ ///
+ Task UnPublishAsync(BackupEntry entry, CancellationToken cancellationToken = default);
}
\ No newline at end of file
diff --git a/Collections/BackwardComparer.cs b/Collections/BackwardComparer.cs
index 2cfa5503..c9c82b6e 100644
--- a/Collections/BackwardComparer.cs
+++ b/Collections/BackwardComparer.cs
@@ -1,18 +1,17 @@
-namespace Ecng.Collections
-{
- using System;
- using System.Collections.Generic;
+namespace Ecng.Collections;
+
+using System;
+using System.Collections.Generic;
- ///
- /// Provides a comparer that compares objects in reverse order.
- ///
- /// The type of objects to compare. Must implement .
- public class BackwardComparer : IComparer
- where T : IComparable
+///
+/// Provides a comparer that compares objects in reverse order.
+///
+/// The type of objects to compare. Must implement .
+public class BackwardComparer : IComparer
+ where T : IComparable
+{
+ int IComparer.Compare(T x, T y)
{
- int IComparer.Compare(T x, T y)
- {
- return -x.CompareTo(y);
- }
+ return -x.CompareTo(y);
}
}
\ No newline at end of file
diff --git a/Collections/BaseBlockingQueue.cs b/Collections/BaseBlockingQueue.cs
index e02b4bcc..3e23313f 100644
--- a/Collections/BaseBlockingQueue.cs
+++ b/Collections/BaseBlockingQueue.cs
@@ -1,324 +1,323 @@
-namespace Ecng.Collections
+namespace Ecng.Collections;
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Threading;
+
+using Ecng.Common;
+
+// http://stackoverflow.com/questions/530211/creating-a-blocking-queuet-in-net
+///
+/// Abstract base class for a blocking queue implementation with a generic type and an inner collection.
+///
+/// The type of elements in the queue.
+/// The type of the inner collection, which must implement .
+public abstract class BaseBlockingQueue(TF innerCollection) : ISynchronizedCollection, IBlockingQueue
+ where TF : ICollection
{
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Threading;
+ ///
+ /// Gets the inner collection used to store the queue elements.
+ ///
+ protected TF InnerCollection { get; } = innerCollection;
- using Ecng.Common;
+ // -1 is unlimited
+ private int _maxSize = -1;
- // http://stackoverflow.com/questions/530211/creating-a-blocking-queuet-in-net
///
- /// Abstract base class for a blocking queue implementation with a generic type and an inner collection.
+ /// Gets or sets the maximum size of the queue. A value of -1 indicates no size limit.
///
- /// The type of elements in the queue.
- /// The type of the inner collection, which must implement .
- public abstract class BaseBlockingQueue(TF innerCollection) : ISynchronizedCollection, IBlockingQueue
- where TF : ICollection
+ /// Thrown when the value is 0 or less than -1.
+ public int MaxSize
{
- ///
- /// Gets the inner collection used to store the queue elements.
- ///
- protected TF InnerCollection { get; } = innerCollection;
-
- // -1 is unlimited
- private int _maxSize = -1;
-
- ///
- /// Gets or sets the maximum size of the queue. A value of -1 indicates no size limit.
- ///
- /// Thrown when the value is 0 or less than -1.
- public int MaxSize
+ get => _maxSize;
+ set
{
- get => _maxSize;
- set
- {
- if (value == 0 || value < -1)
- throw new ArgumentOutOfRangeException(nameof(value));
+ if (value == 0 || value < -1)
+ throw new ArgumentOutOfRangeException(nameof(value));
- _maxSize = value;
- }
+ _maxSize = value;
}
+ }
- ///
- /// Gets the synchronization object used to coordinate access to the queue.
- ///
- public SyncObject SyncRoot { get; } = new();
+ ///
+ /// Gets the synchronization object used to coordinate access to the queue.
+ ///
+ public SyncObject SyncRoot { get; } = new();
- ///
- /// Gets the current number of items in the queue.
- ///
- public int Count => InnerCollection.Count;
+ ///
+ /// Gets the current number of items in the queue.
+ ///
+ public int Count => InnerCollection.Count;
- private bool _isClosed;
+ private bool _isClosed;
- ///
- /// Gets a value indicating whether the queue is closed.
- ///
- public bool IsClosed => _isClosed;
+ ///
+ /// Gets a value indicating whether the queue is closed.
+ ///
+ public bool IsClosed => _isClosed;
- ///
- /// Closes the queue, preventing further enqueues and waking up any blocked threads.
- ///
- public void Close()
+ ///
+ /// Closes the queue, preventing further enqueues and waking up any blocked threads.
+ ///
+ public void Close()
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
- {
- _isClosed = true;
- Monitor.PulseAll(SyncRoot);
- }
+ _isClosed = true;
+ Monitor.PulseAll(SyncRoot);
}
+ }
- ///
- /// Reopens the queue, allowing enqueue operations to proceed.
- ///
- public void Open()
+ ///
+ /// Reopens the queue, allowing enqueue operations to proceed.
+ ///
+ public void Open()
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
- {
- _isClosed = false;
- }
+ _isClosed = false;
}
+ }
- ///
- /// Blocks the current thread while the queue is full, unless it is closed.
- ///
- private void WaitWhileFull()
+ ///
+ /// Blocks the current thread while the queue is full, unless it is closed.
+ ///
+ private void WaitWhileFull()
+ {
+ while (InnerCollection.Count >= _maxSize && !_isClosed)
{
- while (InnerCollection.Count >= _maxSize && !_isClosed)
- {
- Monitor.Wait(SyncRoot);
- }
+ Monitor.Wait(SyncRoot);
}
+ }
- ///
- /// Blocks the current thread until the queue is empty or closed.
- ///
- public void WaitUntilEmpty()
+ ///
+ /// Blocks the current thread until the queue is empty or closed.
+ ///
+ public void WaitUntilEmpty()
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
- {
- while (InnerCollection.Count > 0 && !_isClosed)
- Monitor.Wait(SyncRoot);
- }
+ while (InnerCollection.Count > 0 && !_isClosed)
+ Monitor.Wait(SyncRoot);
}
+ }
- ///
- /// Adds an item to the queue, optionally forcing the enqueue even if the queue is full.
- ///
- /// The item to add to the queue.
- /// If true, adds the item regardless of the maximum size; otherwise, waits if the queue is full.
- public void Enqueue(T item, bool force = false)
+ ///
+ /// Adds an item to the queue, optionally forcing the enqueue even if the queue is full.
+ ///
+ /// The item to add to the queue.
+ /// If true, adds the item regardless of the maximum size; otherwise, waits if the queue is full.
+ public void Enqueue(T item, bool force = false)
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
+ if (_isClosed)
+ return;
+
+ if (!force && _maxSize != -1)
{
- if (_isClosed)
- return;
-
- if (!force && _maxSize != -1)
- {
- if (InnerCollection.Count >= _maxSize)
- WaitWhileFull();
- }
-
- OnEnqueue(item, force);
-
- if (InnerCollection.Count == 1)
- {
- // wake up any blocked dequeue
- Monitor.PulseAll(SyncRoot);
- }
+ if (InnerCollection.Count >= _maxSize)
+ WaitWhileFull();
}
- }
- ///
- /// Performs the actual enqueue operation on the inner collection.
- ///
- /// The item to enqueue.
- /// Indicates whether the enqueue is forced.
- protected abstract void OnEnqueue(T item, bool force);
-
- ///
- /// Performs the actual dequeue operation on the inner collection.
- ///
- /// The dequeued item.
- protected abstract T OnDequeue();
-
- ///
- /// Retrieves, but does not remove, the head of the queue.
- ///
- /// The item at the head of the queue.
- protected abstract T OnPeek();
-
- ///
- /// Removes and returns the item at the head of the queue.
- ///
- /// The dequeued item.
- public T Dequeue()
- {
- TryDequeue(out T retVal, false);
- return retVal;
- }
+ OnEnqueue(item, force);
- ///
- /// Blocks the current thread while the queue is empty, based on the specified conditions.
- ///
- /// If true, exits if the queue is closed.
- /// If true, blocks until an item is available; otherwise, returns immediately.
- /// True if an item is available; otherwise, false.
- private bool WaitWhileEmpty(bool exitOnClose, bool block)
- {
- while (InnerCollection.Count == 0)
+ if (InnerCollection.Count == 1)
{
- if (exitOnClose && _isClosed)
- return false;
-
- if (!block)
- return false;
-
- Monitor.Wait(SyncRoot);
+ // wake up any blocked dequeue
+ Monitor.PulseAll(SyncRoot);
}
-
- return true;
}
+ }
- ///
- /// Attempts to remove and return the item at the head of the queue.
- ///
- /// When this method returns, contains the dequeued item if successful; otherwise, the default value.
- /// If true, exits if the queue is closed.
- /// If true, blocks until an item is available; otherwise, returns immediately.
- /// True if an item was dequeued; otherwise, false.
- public bool TryDequeue(out T value, bool exitOnClose = true, bool block = true)
- {
- lock (SyncRoot)
- {
- if (!WaitWhileEmpty(exitOnClose, block))
- {
- value = default;
- return false;
- }
+ ///
+ /// Performs the actual enqueue operation on the inner collection.
+ ///
+ /// The item to enqueue.
+ /// Indicates whether the enqueue is forced.
+ protected abstract void OnEnqueue(T item, bool force);
- value = OnDequeue();
+ ///
+ /// Performs the actual dequeue operation on the inner collection.
+ ///
+ /// The dequeued item.
+ protected abstract T OnDequeue();
- if (InnerCollection.Count == (_maxSize - 1) || InnerCollection.Count == 0)
- {
- // wake up any blocked enqueue
- Monitor.PulseAll(SyncRoot);
- }
+ ///
+ /// Retrieves, but does not remove, the head of the queue.
+ ///
+ /// The item at the head of the queue.
+ protected abstract T OnPeek();
- return true;
- }
- }
+ ///
+ /// Removes and returns the item at the head of the queue.
+ ///
+ /// The dequeued item.
+ public T Dequeue()
+ {
+ TryDequeue(out T retVal, false);
+ return retVal;
+ }
- ///
- /// Retrieves, but does not remove, the item at the head of the queue.
- ///
- /// The item at the head of the queue.
- public T Peek()
+ ///
+ /// Blocks the current thread while the queue is empty, based on the specified conditions.
+ ///
+ /// If true, exits if the queue is closed.
+ /// If true, blocks until an item is available; otherwise, returns immediately.
+ /// True if an item is available; otherwise, false.
+ private bool WaitWhileEmpty(bool exitOnClose, bool block)
+ {
+ while (InnerCollection.Count == 0)
{
- TryPeek(out T retVal, false);
- return retVal;
+ if (exitOnClose && _isClosed)
+ return false;
+
+ if (!block)
+ return false;
+
+ Monitor.Wait(SyncRoot);
}
- ///
- /// Attempts to retrieve, but not remove, the item at the head of the queue.
- ///
- /// When this method returns, contains the peeked item if successful; otherwise, the default value.
- /// If true, exits if the queue is closed.
- /// If true, blocks until an item is available; otherwise, returns immediately.
- /// True if an item was peeked; otherwise, false.
- public bool TryPeek(out T value, bool exitOnClose = true, bool block = true)
+ return true;
+ }
+
+ ///
+ /// Attempts to remove and return the item at the head of the queue.
+ ///
+ /// When this method returns, contains the dequeued item if successful; otherwise, the default value.
+ /// If true, exits if the queue is closed.
+ /// If true, blocks until an item is available; otherwise, returns immediately.
+ /// True if an item was dequeued; otherwise, false.
+ public bool TryDequeue(out T value, bool exitOnClose = true, bool block = true)
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
+ if (!WaitWhileEmpty(exitOnClose, block))
{
- if (!WaitWhileEmpty(exitOnClose, block))
- {
- value = default;
- return false;
- }
+ value = default;
+ return false;
+ }
- value = OnPeek();
+ value = OnDequeue();
- return true;
+ if (InnerCollection.Count == (_maxSize - 1) || InnerCollection.Count == 0)
+ {
+ // wake up any blocked enqueue
+ Monitor.PulseAll(SyncRoot);
}
+
+ return true;
}
+ }
+
+ ///
+ /// Retrieves, but does not remove, the item at the head of the queue.
+ ///
+ /// The item at the head of the queue.
+ public T Peek()
+ {
+ TryPeek(out T retVal, false);
+ return retVal;
+ }
- ///
- /// Removes all items from the queue and notifies blocked threads.
- ///
- public void Clear()
+ ///
+ /// Attempts to retrieve, but not remove, the item at the head of the queue.
+ ///
+ /// When this method returns, contains the peeked item if successful; otherwise, the default value.
+ /// If true, exits if the queue is closed.
+ /// If true, blocks until an item is available; otherwise, returns immediately.
+ /// True if an item was peeked; otherwise, false.
+ public bool TryPeek(out T value, bool exitOnClose = true, bool block = true)
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
+ if (!WaitWhileEmpty(exitOnClose, block))
{
- InnerCollection.Clear();
- Monitor.PulseAll(SyncRoot);
+ value = default;
+ return false;
}
+
+ value = OnPeek();
+
+ return true;
}
+ }
- ///
- /// Removes the specified item from the queue. This operation is not supported.
- ///
- /// The item to remove.
- /// Always throws .
- /// Thrown because removal of specific items is not supported.
- bool ICollection.Remove(T item)
+ ///
+ /// Removes all items from the queue and notifies blocked threads.
+ ///
+ public void Clear()
+ {
+ lock (SyncRoot)
{
- throw new NotSupportedException();
+ InnerCollection.Clear();
+ Monitor.PulseAll(SyncRoot);
}
+ }
+
+ ///
+ /// Removes the specified item from the queue. This operation is not supported.
+ ///
+ /// The item to remove.
+ /// Always throws .
+ /// Thrown because removal of specific items is not supported.
+ bool ICollection.Remove(T item)
+ {
+ throw new NotSupportedException();
+ }
- ///
- /// Gets a value indicating whether the collection is read-only. Always returns false.
- ///
- bool ICollection.IsReadOnly => false;
+ ///
+ /// Gets a value indicating whether the collection is read-only. Always returns false.
+ ///
+ bool ICollection.IsReadOnly => false;
- ///
- /// Adds an item to the queue using the method.
- ///
- /// The item to add.
- void ICollection.Add(T item)
- {
- Enqueue(item);
- }
+ ///
+ /// Adds an item to the queue using the method.
+ ///
+ /// The item to add.
+ void ICollection.Add(T item)
+ {
+ Enqueue(item);
+ }
- ///
- /// Determines whether the queue contains a specific item.
- ///
- /// The item to locate.
- /// True if the item is found; otherwise, false.
- bool ICollection.Contains(T item)
- {
- lock (SyncRoot)
- return InnerCollection.Contains(item);
- }
+ ///
+ /// Determines whether the queue contains a specific item.
+ ///
+ /// The item to locate.
+ /// True if the item is found; otherwise, false.
+ bool ICollection.Contains(T item)
+ {
+ lock (SyncRoot)
+ return InnerCollection.Contains(item);
+ }
- ///
- /// Copies the elements of the queue to an array, starting at the specified index.
- ///
- /// The destination array.
- /// The zero-based index in the array at which copying begins.
- void ICollection.CopyTo(T[] array, int arrayIndex)
- {
- lock (SyncRoot)
- InnerCollection.CopyTo(array, arrayIndex);
- }
+ ///
+ /// Copies the elements of the queue to an array, starting at the specified index.
+ ///
+ /// The destination array.
+ /// The zero-based index in the array at which copying begins.
+ void ICollection.CopyTo(T[] array, int arrayIndex)
+ {
+ lock (SyncRoot)
+ InnerCollection.CopyTo(array, arrayIndex);
+ }
- ///
- /// Returns an enumerator that iterates through the queue.
- ///
- /// An enumerator for the queue.
- public IEnumerator GetEnumerator()
- {
- return InnerCollection.GetEnumerator();
- }
+ ///
+ /// Returns an enumerator that iterates through the queue.
+ ///
+ /// An enumerator for the queue.
+ public IEnumerator GetEnumerator()
+ {
+ return InnerCollection.GetEnumerator();
+ }
- ///
- /// Returns an enumerator that iterates through the queue (non-generic version).
- ///
- /// An enumerator for the queue.
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
+ ///
+ /// Returns an enumerator that iterates through the queue (non-generic version).
+ ///
+ /// An enumerator for the queue.
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
}
}
\ No newline at end of file
diff --git a/Collections/BaseCollection.cs b/Collections/BaseCollection.cs
index c0f8afbe..63d6f171 100644
--- a/Collections/BaseCollection.cs
+++ b/Collections/BaseCollection.cs
@@ -1,576 +1,575 @@
-namespace Ecng.Collections
+namespace Ecng.Collections;
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+using Ecng.Common;
+
+///
+/// Represents a base class for a generic collection with event notifications and inner collection management.
+///
+/// The type of elements in the collection.
+/// The type of the inner collection, which must implement .
+[Serializable]
+public abstract class BaseCollection : ICollection, ICollection, INotifyList, IList
+ where TCollection : ICollection
{
- using System;
- using System.Collections;
- using System.Collections.Generic;
+ ///
+ /// Initializes a new instance of the class with the specified inner collection.
+ ///
+ /// The inner collection to manage.
+ /// Thrown when is null.
+ protected BaseCollection(TCollection innerCollection)
+ {
+ if (innerCollection.IsNull())
+ throw new ArgumentNullException(nameof(innerCollection));
+
+ InnerCollection = innerCollection;
+ }
+
+ ///
+ /// Gets or sets a value indicating whether to check for null items in the collection.
+ ///
+ public bool CheckNullableItems { get; set; }
+
+ ///
+ /// Gets the inner collection that stores the items.
+ ///
+ protected TCollection InnerCollection { get; }
- using Ecng.Common;
+ ///
+ /// Retrieves an item at the specified index from the inner collection.
+ ///
+ /// The zero-based index of the item to retrieve.
+ /// The item at the specified index.
+ protected abstract TItem OnGetItem(int index);
///
- /// Represents a base class for a generic collection with event notifications and inner collection management.
+ /// Inserts an item into the inner collection at the specified index.
///
- /// The type of elements in the collection.
- /// The type of the inner collection, which must implement .
- [Serializable]
- public abstract class BaseCollection : ICollection, ICollection, INotifyList, IList
- where TCollection : ICollection
+ /// The zero-based index at which to insert the item.
+ /// The item to insert.
+ protected abstract void OnInsert(int index, TItem item);
+
+ ///
+ /// Removes an item from the inner collection at the specified index.
+ ///
+ /// The zero-based index of the item to remove.
+ protected abstract void OnRemoveAt(int index);
+
+ ///
+ /// Adds an item to the inner collection.
+ ///
+ /// The item to add.
+ protected virtual void OnAdd(TItem item)
{
- ///
- /// Initializes a new instance of the class with the specified inner collection.
- ///
- /// The inner collection to manage.
- /// Thrown when is null.
- protected BaseCollection(TCollection innerCollection)
- {
- if (innerCollection.IsNull())
- throw new ArgumentNullException(nameof(innerCollection));
+ InnerCollection.Add(item);
+ }
- InnerCollection = innerCollection;
- }
+ ///
+ /// Removes an item from the inner collection.
+ ///
+ /// The item to remove.
+ /// True if the item was removed; otherwise, false.
+ protected virtual bool OnRemove(TItem item)
+ {
+ return InnerCollection.Remove(item);
+ }
+
+ ///
+ /// Removes all items from the inner collection.
+ ///
+ protected virtual void OnClear()
+ {
+ InnerCollection.Clear();
+ }
+
+ ///
+ /// Returns an enumerator that iterates through the collection (non-generic version).
+ ///
+ /// An enumerator for the collection.
+ IEnumerator IEnumerable.GetEnumerator()
+ => ((IEnumerable)this).GetEnumerator();
+
+ ///
+ /// Returns an enumerator that iterates through the collection.
+ ///
+ /// An enumerator for the collection.
+ public virtual IEnumerator GetEnumerator()
+ => InnerCollection.GetEnumerator();
+
+ ///
+ /// Gets the number of items in the collection.
+ ///
+ public virtual int Count => InnerCollection.Count;
+
+ ///
+ /// Determines whether the collection contains a specific item.
+ ///
+ /// The item to locate.
+ /// True if the item is found; otherwise, false.
+ public virtual bool Contains(TItem item) => InnerCollection.Contains(item);
+
+ ///
+ /// Validates the specified index to ensure it is within the valid range.
+ ///
+ /// The index to check.
+ /// Thrown when the index is less than 0 or greater than .
+ private void CheckIndex(int index)
+ {
+ if (index < 0 || index > Count)
+ throw new ArgumentOutOfRangeException(nameof(index), index, "Index has incorrect value.");
+ }
- ///
- /// Gets or sets a value indicating whether to check for null items in the collection.
- ///
- public bool CheckNullableItems { get; set; }
-
- ///
- /// Gets the inner collection that stores the items.
- ///
- protected TCollection InnerCollection { get; }
-
- ///
- /// Retrieves an item at the specified index from the inner collection.
- ///
- /// The zero-based index of the item to retrieve.
- /// The item at the specified index.
- protected abstract TItem OnGetItem(int index);
-
- ///
- /// Inserts an item into the inner collection at the specified index.
- ///
- /// The zero-based index at which to insert the item.
- /// The item to insert.
- protected abstract void OnInsert(int index, TItem item);
-
- ///
- /// Removes an item from the inner collection at the specified index.
- ///
- /// The zero-based index of the item to remove.
- protected abstract void OnRemoveAt(int index);
-
- ///
- /// Adds an item to the inner collection.
- ///
- /// The item to add.
- protected virtual void OnAdd(TItem item)
+ ///
+ /// Gets or sets the item at the specified index.
+ ///
+ /// The zero-based index of the item.
+ /// The item at the specified index.
+ /// Thrown when the index is invalid.
+ public virtual TItem this[int index]
+ {
+ get => OnGetItem(index);
+ set
{
- InnerCollection.Add(item);
+ CheckIndex(index);
+
+ if (index < Count)
+ {
+ RemoveAt(index);
+ Insert(index, value);
+ }
+ else
+ Add(value);
}
+ }
- ///
- /// Removes an item from the inner collection.
- ///
- /// The item to remove.
- /// True if the item was removed; otherwise, false.
- protected virtual bool OnRemove(TItem item)
+ ///
+ /// Returns the index of the specified item in the collection.
+ ///
+ /// The item to locate.
+ /// The zero-based index of the item, or -1 if not found.
+ public abstract int IndexOf(TItem item);
+
+ ///
+ /// Removes the item at the specified index.
+ ///
+ /// The zero-based index of the item to remove.
+ public virtual void RemoveAt(int index)
+ {
+ if (OnRemovingAt(index))
{
- return InnerCollection.Remove(item);
+ OnRemoveAt(index);
+ OnRemovedAt(index);
}
+ }
+
+ ///
+ /// Inserts an item into the collection at the specified index.
+ ///
+ /// The zero-based index at which to insert the item.
+ /// The item to insert.
+ /// Thrown when the index is invalid.
+ public virtual void Insert(int index, TItem item)
+ {
+ CheckIndex(index);
- ///
- /// Removes all items from the inner collection.
- ///
- protected virtual void OnClear()
+ if (index == Count)
+ Add(item);
+ else
{
- InnerCollection.Clear();
+ OnInserting(index, item);
+ OnInsert(index, item);
+ OnInserted(index, item);
}
+ }
+
+ ///
+ /// Gets a value indicating whether the collection is read-only.
+ ///
+ public virtual bool IsReadOnly => false;
- ///
- /// Returns an enumerator that iterates through the collection (non-generic version).
- ///
- /// An enumerator for the collection.
- IEnumerator IEnumerable.GetEnumerator()
- => ((IEnumerable)this).GetEnumerator();
-
- ///
- /// Returns an enumerator that iterates through the collection.
- ///
- /// An enumerator for the collection.
- public virtual IEnumerator GetEnumerator()
- => InnerCollection.GetEnumerator();
-
- ///
- /// Gets the number of items in the collection.
- ///
- public virtual int Count => InnerCollection.Count;
-
- ///
- /// Determines whether the collection contains a specific item.
- ///
- /// The item to locate.
- /// True if the item is found; otherwise, false.
- public virtual bool Contains(TItem item) => InnerCollection.Contains(item);
-
- ///
- /// Validates the specified index to ensure it is within the valid range.
- ///
- /// The index to check.
- /// Thrown when the index is less than 0 or greater than .
- private void CheckIndex(int index)
+ ///
+ /// Adds an item to the collection.
+ ///
+ /// The item to add.
+ /// Thrown when is null and is true.
+ public virtual void Add(TItem item)
+ {
+ if (CheckNullableItems && item.IsNull())
+ throw new ArgumentNullException(nameof(item));
+
+ if (OnAdding(item))
{
- if (index < 0 || index > Count)
- throw new ArgumentOutOfRangeException(nameof(index), index, "Index has incorrect value.");
+ OnAdd(item);
+ OnAdded(item);
}
+ }
- ///
- /// Gets or sets the item at the specified index.
- ///
- /// The zero-based index of the item.
- /// The item at the specified index.
- /// Thrown when the index is invalid.
- public virtual TItem this[int index]
+ ///
+ /// Removes all items from the collection.
+ ///
+ public virtual void Clear()
+ {
+ if (OnClearing())
{
- get => OnGetItem(index);
- set
- {
- CheckIndex(index);
-
- if (index < Count)
- {
- RemoveAt(index);
- Insert(index, value);
- }
- else
- Add(value);
- }
+ OnClear();
+ OnCleared();
}
+ }
- ///
- /// Returns the index of the specified item in the collection.
- ///
- /// The item to locate.
- /// The zero-based index of the item, or -1 if not found.
- public abstract int IndexOf(TItem item);
-
- ///
- /// Removes the item at the specified index.
- ///
- /// The zero-based index of the item to remove.
- public virtual void RemoveAt(int index)
+ ///
+ /// Removes the specified item from the collection.
+ ///
+ /// The item to remove.
+ /// True if the item was removed; otherwise, false.
+ /// Thrown when is null and is true.
+ public virtual bool Remove(TItem item)
+ {
+ if (CheckNullableItems && item.IsNull())
+ throw new ArgumentNullException(nameof(item));
+
+ if (OnRemoving(item))
{
- if (OnRemovingAt(index))
+ if (OnRemove(item))
{
- OnRemoveAt(index);
- OnRemovedAt(index);
+ OnRemoved(item);
+ return true;
}
}
- ///
- /// Inserts an item into the collection at the specified index.
- ///
- /// The zero-based index at which to insert the item.
- /// The item to insert.
- /// Thrown when the index is invalid.
- public virtual void Insert(int index, TItem item)
- {
- CheckIndex(index);
+ return false;
+ }
- if (index == Count)
- Add(item);
- else
- {
- OnInserting(index, item);
- OnInsert(index, item);
- OnInserted(index, item);
- }
- }
+ ///
+ /// Occurs before an item is added to the collection.
+ ///
+ public event Func Adding;
- ///
- /// Gets a value indicating whether the collection is read-only.
- ///
- public virtual bool IsReadOnly => false;
-
- ///
- /// Adds an item to the collection.
- ///
- /// The item to add.
- /// Thrown when is null and is true.
- public virtual void Add(TItem item)
- {
- if (CheckNullableItems && item.IsNull())
- throw new ArgumentNullException(nameof(item));
+ ///
+ /// Occurs after an item has been added to the collection.
+ ///
+ public event Action Added;
- if (OnAdding(item))
- {
- OnAdd(item);
- OnAdded(item);
- }
- }
+ ///
+ /// Occurs before an item is removed from the collection.
+ ///
+ public event Func Removing;
- ///
- /// Removes all items from the collection.
- ///
- public virtual void Clear()
- {
- if (OnClearing())
- {
- OnClear();
- OnCleared();
- }
- }
+ ///
+ /// Occurs after an item has been removed from the collection.
+ ///
+ public event Action Removed;
- ///
- /// Removes the specified item from the collection.
- ///
- /// The item to remove.
- /// True if the item was removed; otherwise, false.
- /// Thrown when is null and is true.
- public virtual bool Remove(TItem item)
- {
- if (CheckNullableItems && item.IsNull())
- throw new ArgumentNullException(nameof(item));
+ ///
+ /// Occurs before an item is removed at the specified index.
+ ///
+ public event Func RemovingAt;
- if (OnRemoving(item))
- {
- if (OnRemove(item))
- {
- OnRemoved(item);
- return true;
- }
- }
+ ///
+ /// Occurs after an item has been removed at the specified index.
+ ///
+ public event Action RemovedAt;
- return false;
- }
+ ///
+ /// Occurs before the collection is cleared.
+ ///
+ public event Func Clearing;
- ///
- /// Occurs before an item is added to the collection.
- ///
- public event Func Adding;
-
- ///
- /// Occurs after an item has been added to the collection.
- ///
- public event Action Added;
-
- ///
- /// Occurs before an item is removed from the collection.
- ///
- public event Func Removing;
-
- ///
- /// Occurs after an item has been removed from the collection.
- ///
- public event Action Removed;
-
- ///
- /// Occurs before an item is removed at the specified index.
- ///
- public event Func RemovingAt;
-
- ///
- /// Occurs after an item has been removed at the specified index.
- ///
- public event Action RemovedAt;
-
- ///
- /// Occurs before the collection is cleared.
- ///
- public event Func Clearing;
-
- ///
- /// Occurs after the collection has been cleared.
- ///
- public event Action Cleared;
-
- ///
- /// Occurs before an item is inserted at the specified index.
- ///
- public event Func Inserting;
-
- ///
- /// Occurs after an item has been inserted at the specified index.
- ///
- public event Action Inserted;
-
- ///
- /// Occurs when the collection has been modified.
- ///
- public event Action Changed;
-
- ///
- /// Invokes the event before inserting an item.
- ///
- /// The zero-based index at which to insert the item.
- /// The item to insert.
- /// True if the insertion should proceed; otherwise, false.
- protected virtual bool OnInserting(int index, TItem item)
- {
- return Inserting?.Invoke(index, item) ?? true;
- }
+ ///
+ /// Occurs after the collection has been cleared.
+ ///
+ public event Action Cleared;
- ///
- /// Invokes the event and notifies of a change after inserting an item.
- ///
- /// The zero-based index at which the item was inserted.
- /// The inserted item.
- protected virtual void OnInserted(int index, TItem item)
- {
- Inserted?.Invoke(index, item);
- OnChanged();
- }
+ ///
+ /// Occurs before an item is inserted at the specified index.
+ ///
+ public event Func Inserting;
- ///
- /// Invokes the event before adding an item.
- ///
- /// The item to add.
- /// True if the addition should proceed; otherwise, false.
- protected virtual bool OnAdding(TItem item)
- {
- return Adding?.Invoke(item) ?? true;
- }
+ ///
+ /// Occurs after an item has been inserted at the specified index.
+ ///
+ public event Action Inserted;
- ///
- /// Invokes the event and notifies of a change after adding an item.
- ///
- /// The added item.
- protected virtual void OnAdded(TItem item)
- {
- Added?.Invoke(item);
- OnChanged();
- }
+ ///
+ /// Occurs when the collection has been modified.
+ ///
+ public event Action Changed;
- ///
- /// Invokes the event before clearing the collection.
- ///
- /// True if the clearing should proceed; otherwise, false.
- protected virtual bool OnClearing()
- {
- return Clearing?.Invoke() ?? true;
- }
+ ///
+ /// Invokes the event before inserting an item.
+ ///
+ /// The zero-based index at which to insert the item.
+ /// The item to insert.
+ /// True if the insertion should proceed; otherwise, false.
+ protected virtual bool OnInserting(int index, TItem item)
+ {
+ return Inserting?.Invoke(index, item) ?? true;
+ }
- ///
- /// Invokes the event and notifies of a change after clearing the collection.
- ///
- protected virtual void OnCleared()
- {
- Cleared?.Invoke();
- OnChanged();
- }
+ ///
+ /// Invokes the event and notifies of a change after inserting an item.
+ ///
+ /// The zero-based index at which the item was inserted.
+ /// The inserted item.
+ protected virtual void OnInserted(int index, TItem item)
+ {
+ Inserted?.Invoke(index, item);
+ OnChanged();
+ }
- ///
- /// Invokes the event before removing an item.
- ///
- /// The item to remove.
- /// True if the removal should proceed; otherwise, false.
- protected virtual bool OnRemoving(TItem item)
- {
- return Removing?.Invoke(item) ?? true;
- }
+ ///
+ /// Invokes the event before adding an item.
+ ///
+ /// The item to add.
+ /// True if the addition should proceed; otherwise, false.
+ protected virtual bool OnAdding(TItem item)
+ {
+ return Adding?.Invoke(item) ?? true;
+ }
- ///
- /// Invokes the event and notifies of a change after removing an item.
- ///
- /// The removed item.
- protected virtual void OnRemoved(TItem item)
- {
- Removed?.Invoke(item);
- OnChanged();
- }
+ ///
+ /// Invokes the event and notifies of a change after adding an item.
+ ///
+ /// The added item.
+ protected virtual void OnAdded(TItem item)
+ {
+ Added?.Invoke(item);
+ OnChanged();
+ }
- ///
- /// Invokes the event before removing an item at the specified index.
- ///
- /// The zero-based index of the item to remove.
- /// True if the removal should proceed; otherwise, false.
- protected virtual bool OnRemovingAt(int index)
- {
- return RemovingAt?.Invoke(index) ?? true;
- }
+ ///
+ /// Invokes the event before clearing the collection.
+ ///
+ /// True if the clearing should proceed; otherwise, false.
+ protected virtual bool OnClearing()
+ {
+ return Clearing?.Invoke() ?? true;
+ }
- ///
- /// Invokes the event and notifies of a change after removing an item at the specified index.
- ///
- /// The zero-based index of the removed item.
- protected virtual void OnRemovedAt(int index)
- {
- RemovedAt?.Invoke(index);
- OnChanged();
- }
+ ///
+ /// Invokes the event and notifies of a change after clearing the collection.
+ ///
+ protected virtual void OnCleared()
+ {
+ Cleared?.Invoke();
+ OnChanged();
+ }
- ///
- /// Invokes the event to notify of a modification in the collection.
- ///
- protected virtual void OnChanged()
- {
- Changed?.Invoke();
- }
+ ///
+ /// Invokes the event before removing an item.
+ ///
+ /// The item to remove.
+ /// True if the removal should proceed; otherwise, false.
+ protected virtual bool OnRemoving(TItem item)
+ {
+ return Removing?.Invoke(item) ?? true;
+ }
- #region IList Members
+ ///
+ /// Invokes the event and notifies of a change after removing an item.
+ ///
+ /// The removed item.
+ protected virtual void OnRemoved(TItem item)
+ {
+ Removed?.Invoke(item);
+ OnChanged();
+ }
- ///
- /// Determines whether the collection contains a specific value (non-generic).
- ///
- /// The value to locate.
- /// True if the value is found and compatible; otherwise, false.
- bool IList.Contains(object value)
- {
- if (!IsCompatible(value))
- return false;
+ ///
+ /// Invokes the event before removing an item at the specified index.
+ ///
+ /// The zero-based index of the item to remove.
+ /// True if the removal should proceed; otherwise, false.
+ protected virtual bool OnRemovingAt(int index)
+ {
+ return RemovingAt?.Invoke(index) ?? true;
+ }
- return Contains((TItem)value);
- }
+ ///
+ /// Invokes the event and notifies of a change after removing an item at the specified index.
+ ///
+ /// The zero-based index of the removed item.
+ protected virtual void OnRemovedAt(int index)
+ {
+ RemovedAt?.Invoke(index);
+ OnChanged();
+ }
- ///
- /// Adds a value to the collection (non-generic).
- ///
- /// The value to add.
- /// The new count of items in the collection.
- /// Thrown when is null and incompatible with .
- int IList.Add(object value)
- {
- if (!IsCompatible(value))
- throw new ArgumentNullException(nameof(value));
+ ///
+ /// Invokes the event to notify of a modification in the collection.
+ ///
+ protected virtual void OnChanged()
+ {
+ Changed?.Invoke();
+ }
- Add((TItem)value);
- return Count;
- }
+ #region IList Members
- ///
- /// Gets a value indicating whether the collection is read-only (non-generic).
- ///
- bool IList.IsReadOnly => false;
-
- ///
- /// Gets or sets the item at the specified index (non-generic).
- ///
- /// The zero-based index of the item.
- /// The item at the specified index.
- /// Thrown when setting a value that is null and incompatible with .
- object IList.this[int index]
- {
- get => this[index];
- set
- {
- if (!IsCompatible(value))
- throw new ArgumentNullException(nameof(value));
+ ///
+ /// Determines whether the collection contains a specific value (non-generic).
+ ///
+ /// The value to locate.
+ /// True if the value is found and compatible; otherwise, false.
+ bool IList.Contains(object value)
+ {
+ if (!IsCompatible(value))
+ return false;
- this[index] = (TItem)value;
- }
- }
+ return Contains((TItem)value);
+ }
- ///
- /// Removes all items from the collection (non-generic).
- ///
- void IList.Clear()
- {
- ((ICollection)this).Clear();
- }
+ ///
+ /// Adds a value to the collection (non-generic).
+ ///
+ /// The value to add.
+ /// The new count of items in the collection.
+ /// Thrown when is null and incompatible with .
+ int IList.Add(object value)
+ {
+ if (!IsCompatible(value))
+ throw new ArgumentNullException(nameof(value));
- ///
- /// Returns the index of a specific value in the collection (non-generic).
- ///
- /// The value to locate.
- /// The zero-based index of the value, or -1 if not found or incompatible.
- int IList.IndexOf(object value)
- {
- if (!IsCompatible(value))
- return -1;
+ Add((TItem)value);
+ return Count;
+ }
- return IndexOf((TItem)value);
- }
+ ///
+ /// Gets a value indicating whether the collection is read-only (non-generic).
+ ///
+ bool IList.IsReadOnly => false;
- ///
- /// Inserts a value into the collection at the specified index (non-generic).
- ///
- /// The zero-based index at which to insert the value.
- /// The value to insert.
- /// Thrown when is null and incompatible with .
- void IList.Insert(int index, object value)
+ ///
+ /// Gets or sets the item at the specified index (non-generic).
+ ///
+ /// The zero-based index of the item.
+ /// The item at the specified index.
+ /// Thrown when setting a value that is null and incompatible with .
+ object IList.this[int index]
+ {
+ get => this[index];
+ set
{
if (!IsCompatible(value))
throw new ArgumentNullException(nameof(value));
- Insert(index, (TItem)value);
+ this[index] = (TItem)value;
}
+ }
- ///
- /// Removes a specific value from the collection (non-generic).
- ///
- /// The value to remove.
- void IList.Remove(object value)
- {
- if (!IsCompatible(value))
- return;
+ ///
+ /// Removes all items from the collection (non-generic).
+ ///
+ void IList.Clear()
+ {
+ ((ICollection)this).Clear();
+ }
- Remove((TItem)value);
- }
+ ///
+ /// Returns the index of a specific value in the collection (non-generic).
+ ///
+ /// The value to locate.
+ /// The zero-based index of the value, or -1 if not found or incompatible.
+ int IList.IndexOf(object value)
+ {
+ if (!IsCompatible(value))
+ return -1;
- ///
- /// Removes the item at the specified index (non-generic).
- ///
- /// The zero-based index of the item to remove.
- void IList.RemoveAt(int index)
- {
- RemoveAt(index);
- }
+ return IndexOf((TItem)value);
+ }
- ///
- /// Gets a value indicating whether the collection has a fixed size (non-generic). Always returns false.
- ///
- bool IList.IsFixedSize => false;
-
- #endregion
-
- private static readonly bool _isValueType = typeof(TItem).IsValueType;
-
- ///
- /// Determines whether a value is compatible with the collection's item type.
- ///
- /// The value to check.
- /// True if the value is compatible; otherwise, false.
- private static bool IsCompatible(object value) => !_isValueType || value != null;
-
- ///
- /// Gets a value indicating whether the collection is synchronized (non-generic). Always returns false.
- ///
- bool ICollection.IsSynchronized => false;
-
- ///
- /// Gets the synchronization root object (non-generic). Returns the current instance.
- ///
- object ICollection.SyncRoot => this;
-
- ///
- /// Copies the elements of the collection to an array (non-generic).
- ///
- /// The destination array.
- /// The zero-based index in the array at which copying begins.
- void ICollection.CopyTo(Array array, int index)
- => CopyTo((TItem[])array, index);
-
- ///
- /// Copies the elements of the collection to an array.
- ///
- /// The destination array.
- /// The zero-based index in the array at which copying begins.
- public void CopyTo(TItem[] array, int index)
- {
- int count = Count;
+ ///
+ /// Inserts a value into the collection at the specified index (non-generic).
+ ///
+ /// The zero-based index at which to insert the value.
+ /// The value to insert.
+ /// Thrown when is null and incompatible with .
+ void IList.Insert(int index, object value)
+ {
+ if (!IsCompatible(value))
+ throw new ArgumentNullException(nameof(value));
- if (count == 0)
- return;
+ Insert(index, (TItem)value);
+ }
- var i = 0;
- foreach (var item in (ICollection)this)
- {
- if (i >= count)
- break;
+ ///
+ /// Removes a specific value from the collection (non-generic).
+ ///
+ /// The value to remove.
+ void IList.Remove(object value)
+ {
+ if (!IsCompatible(value))
+ return;
- array[index] = item;
+ Remove((TItem)value);
+ }
- index++;
- i++;
- }
+ ///
+ /// Removes the item at the specified index (non-generic).
+ ///
+ /// The zero-based index of the item to remove.
+ void IList.RemoveAt(int index)
+ {
+ RemoveAt(index);
+ }
+
+ ///
+ /// Gets a value indicating whether the collection has a fixed size (non-generic). Always returns false.
+ ///
+ bool IList.IsFixedSize => false;
+
+ #endregion
+
+ private static readonly bool _isValueType = typeof(TItem).IsValueType;
+
+ ///
+ /// Determines whether a value is compatible with the collection's item type.
+ ///
+ /// The value to check.
+ /// True if the value is compatible; otherwise, false.
+ private static bool IsCompatible(object value) => !_isValueType || value != null;
+
+ ///
+ /// Gets a value indicating whether the collection is synchronized (non-generic). Always returns false.
+ ///
+ bool ICollection.IsSynchronized => false;
+
+ ///
+ /// Gets the synchronization root object (non-generic). Returns the current instance.
+ ///
+ object ICollection.SyncRoot => this;
+
+ ///
+ /// Copies the elements of the collection to an array (non-generic).
+ ///
+ /// The destination array.
+ /// The zero-based index in the array at which copying begins.
+ void ICollection.CopyTo(Array array, int index)
+ => CopyTo((TItem[])array, index);
+
+ ///
+ /// Copies the elements of the collection to an array.
+ ///
+ /// The destination array.
+ /// The zero-based index in the array at which copying begins.
+ public void CopyTo(TItem[] array, int index)
+ {
+ int count = Count;
+
+ if (count == 0)
+ return;
+
+ var i = 0;
+ foreach (var item in (ICollection)this)
+ {
+ if (i >= count)
+ break;
+
+ array[index] = item;
+
+ index++;
+ i++;
}
}
}
\ No newline at end of file
diff --git a/Collections/BaseEnumerator.cs b/Collections/BaseEnumerator.cs
index cdefdc59..8f6d6626 100644
--- a/Collections/BaseEnumerator.cs
+++ b/Collections/BaseEnumerator.cs
@@ -1,73 +1,72 @@
-namespace Ecng.Collections
-{
- using System;
- using System.Collections.Generic;
+namespace Ecng.Collections;
+
+using System;
+using System.Collections.Generic;
- using Ecng.Common;
+using Ecng.Common;
+///
+/// Represents an abstract base class for an enumerator over a generic enumerable source.
+///
+/// The type of the enumerable source, which must implement .
+/// The type of elements in the enumerable source.
+public abstract class BaseEnumerator : SimpleEnumerator
+ where TEnumerable : IEnumerable
+{
///
- /// Represents an abstract base class for an enumerator over a generic enumerable source.
+ /// Initializes a new instance of the class with the specified source.
///
- /// The type of the enumerable source, which must implement .
- /// The type of elements in the enumerable source.
- public abstract class BaseEnumerator : SimpleEnumerator
- where TEnumerable : IEnumerable
+ /// The enumerable source to iterate over.
+ /// Thrown when is null.
+ protected BaseEnumerator(TEnumerable source)
{
- ///
- /// Initializes a new instance of the class with the specified source.
- ///
- /// The enumerable source to iterate over.
- /// Thrown when is null.
- protected BaseEnumerator(TEnumerable source)
- {
- if (source.IsNull())
- throw new ArgumentException(nameof(source));
+ if (source.IsNull())
+ throw new ArgumentException(nameof(source));
- Source = source;
- Reset();
- }
-
- ///
- /// Gets or sets the enumerable source being iterated over.
- ///
- public TEnumerable Source { get; private set; }
+ Source = source;
+ Reset();
+ }
- ///
- /// Disposes of managed resources by resetting the enumerator and clearing the source.
- ///
- protected override void DisposeManaged()
- {
- Reset();
- Source = default;
- }
+ ///
+ /// Gets or sets the enumerable source being iterated over.
+ ///
+ public TEnumerable Source { get; private set; }
- ///
- /// Advances the enumerator to the next element of the collection.
- ///
- /// True if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
- /// Thrown if the enumerator has been disposed.
- public override bool MoveNext()
- {
- ThrowIfDisposed();
+ ///
+ /// Disposes of managed resources by resetting the enumerator and clearing the source.
+ ///
+ protected override void DisposeManaged()
+ {
+ Reset();
+ Source = default;
+ }
- var canProcess = true;
- Current = ProcessMove(ref canProcess);
- return canProcess;
- }
+ ///
+ /// Advances the enumerator to the next element of the collection.
+ ///
+ /// True if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
+ /// Thrown if the enumerator has been disposed.
+ public override bool MoveNext()
+ {
+ ThrowIfDisposed();
- ///
- /// Sets the enumerator to its initial position, which is before the first element in the collection.
- ///
- public override void Reset()
- {
- Current = default;
- }
+ var canProcess = true;
+ Current = ProcessMove(ref canProcess);
+ return canProcess;
+ }
- ///
- /// Processes the movement to the next element and determines whether iteration can continue.
- ///
- /// A reference parameter indicating whether the enumerator can proceed; set to false if the end is reached.
- /// The next item in the collection, or the default value if no further items are available.
- protected abstract TItem ProcessMove(ref bool canProcess);
+ ///
+ /// Sets the enumerator to its initial position, which is before the first element in the collection.
+ ///
+ public override void Reset()
+ {
+ Current = default;
}
+
+ ///
+ /// Processes the movement to the next element and determines whether iteration can continue.
+ ///
+ /// A reference parameter indicating whether the enumerator can proceed; set to false if the end is reached.
+ /// The next item in the collection, or the default value if no further items are available.
+ protected abstract TItem ProcessMove(ref bool canProcess);
}
\ No newline at end of file
diff --git a/Collections/BaseList.cs b/Collections/BaseList.cs
index 378c1980..2d67faf4 100644
--- a/Collections/BaseList.cs
+++ b/Collections/BaseList.cs
@@ -1,60 +1,59 @@
-namespace Ecng.Collections
-{
- using System;
- using System.Collections.Generic;
+namespace Ecng.Collections;
+
+using System;
+using System.Collections.Generic;
+///
+/// Represents a base class for a strongly-typed list of items.
+///
+/// The type of elements in the list.
+[Serializable]
+public abstract class BaseList(IList innerList) : BaseCollection>(innerList)
+{
///
- /// Represents a base class for a strongly-typed list of items.
+ /// Initializes a new instance of the class with an empty inner list.
///
- /// The type of elements in the list.
- [Serializable]
- public abstract class BaseList(IList innerList) : BaseCollection>(innerList)
+ protected BaseList()
+ : this([])
{
- ///
- /// Initializes a new instance of the class with an empty inner list.
- ///
- protected BaseList()
- : this([])
- {
- }
+ }
- ///
- /// Retrieves the item at the specified index from the inner list.
- ///
- /// The zero-based index of the item to retrieve.
- /// The item at the specified index.
- protected override TItem OnGetItem(int index)
- {
- return InnerCollection[index];
- }
+ ///
+ /// Retrieves the item at the specified index from the inner list.
+ ///
+ /// The zero-based index of the item to retrieve.
+ /// The item at the specified index.
+ protected override TItem OnGetItem(int index)
+ {
+ return InnerCollection[index];
+ }
- ///
- /// Inserts an item into the inner list at the specified index.
- ///
- /// The zero-based index at which the item should be inserted.
- /// The item to insert into the list.
- protected override void OnInsert(int index, TItem item)
- {
- InnerCollection.Insert(index, item);
- }
+ ///
+ /// Inserts an item into the inner list at the specified index.
+ ///
+ /// The zero-based index at which the item should be inserted.
+ /// The item to insert into the list.
+ protected override void OnInsert(int index, TItem item)
+ {
+ InnerCollection.Insert(index, item);
+ }
- ///
- /// Removes the item at the specified index from the inner list.
- ///
- /// The zero-based index of the item to remove.
- protected override void OnRemoveAt(int index)
- {
- InnerCollection.RemoveAt(index);
- }
+ ///
+ /// Removes the item at the specified index from the inner list.
+ ///
+ /// The zero-based index of the item to remove.
+ protected override void OnRemoveAt(int index)
+ {
+ InnerCollection.RemoveAt(index);
+ }
- ///
- /// Determines the index of a specific item in the inner list.
- ///
- /// The item to locate in the list.
- /// The index of the item if found in the list; otherwise, -1.
- public override int IndexOf(TItem item)
- {
- return InnerCollection.IndexOf(item);
- }
+ ///
+ /// Determines the index of a specific item in the inner list.
+ ///
+ /// The item to locate in the list.
+ /// The index of the item if found in the list; otherwise, -1.
+ public override int IndexOf(TItem item)
+ {
+ return InnerCollection.IndexOf(item);
}
}
\ No newline at end of file
diff --git a/Collections/BaseOrderedBlockingQueue.cs b/Collections/BaseOrderedBlockingQueue.cs
index 2f6d25cd..4cf3f8ef 100644
--- a/Collections/BaseOrderedBlockingQueue.cs
+++ b/Collections/BaseOrderedBlockingQueue.cs
@@ -1,64 +1,63 @@
-namespace Ecng.Collections
-{
- using System.Collections.Generic;
+namespace Ecng.Collections;
+
+using System.Collections.Generic;
+///
+/// Represents a base class for an ordered blocking queue that sorts elements based on a specified key.
+///
+/// The type used to determine the sort order of elements.
+/// The type of the values stored in the queue.
+/// The type of the inner collection, which must implement and for tuples of and .
+public abstract class BaseOrderedBlockingQueue(TCollection collection) :
+ BaseBlockingQueue<(TSort sort, TValue elem), TCollection>(collection)
+ where TCollection : ICollection<(TSort, TValue)>, IQueue<(TSort, TValue)>
+{
///
- /// Represents a base class for an ordered blocking queue that sorts elements based on a specified key.
+ /// Attempts to remove and return the next value from the queue.
///
- /// The type used to determine the sort order of elements.
- /// The type of the values stored in the queue.
- /// The type of the inner collection, which must implement and for tuples of and .
- public abstract class BaseOrderedBlockingQueue(TCollection collection) :
- BaseBlockingQueue<(TSort sort, TValue elem), TCollection>(collection)
- where TCollection : ICollection<(TSort, TValue)>, IQueue<(TSort, TValue)>
+ /// When this method returns, contains the dequeued value if successful; otherwise, the default value of .
+ /// If true, exits immediately if the queue is closed; otherwise, waits for an item.
+ /// If true, blocks until an item is available; otherwise, returns immediately.
+ /// True if a value was successfully dequeued; otherwise, false.
+ public bool TryDequeue(out TValue value, bool exitOnClose = true, bool block = true)
{
- ///
- /// Attempts to remove and return the next value from the queue.
- ///
- /// When this method returns, contains the dequeued value if successful; otherwise, the default value of .
- /// If true, exits immediately if the queue is closed; otherwise, waits for an item.
- /// If true, blocks until an item is available; otherwise, returns immediately.
- /// True if a value was successfully dequeued; otherwise, false.
- public bool TryDequeue(out TValue value, bool exitOnClose = true, bool block = true)
+ if (base.TryDequeue(out var pair, exitOnClose, block))
{
- if (base.TryDequeue(out var pair, exitOnClose, block))
- {
- value = pair.elem;
- return true;
- }
-
- value = default;
- return false;
+ value = pair.elem;
+ return true;
}
- ///
- /// Adds a new value to the queue with the specified sort order.
- ///
- /// The sort key determining the order of the value in the queue.
- /// The value to add to the queue.
- protected void Enqueue(TSort sort, TValue value)
- => Enqueue(new(sort, value));
+ value = default;
+ return false;
+ }
- ///
- /// Adds an item to the inner collection when enqueuing.
- ///
- /// The tuple containing the sort key and value to enqueue.
- /// If true, forces the item to be enqueued even if the queue is full; otherwise, respects the maximum size limit.
- protected override void OnEnqueue((TSort, TValue) item, bool force)
- => InnerCollection.Enqueue(item);
+ ///
+ /// Adds a new value to the queue with the specified sort order.
+ ///
+ /// The sort key determining the order of the value in the queue.
+ /// The value to add to the queue.
+ protected void Enqueue(TSort sort, TValue value)
+ => Enqueue(new(sort, value));
- ///
- /// Removes and returns the next item from the inner collection.
- ///
- /// The tuple containing the sort key and value of the dequeued item.
- protected override (TSort, TValue) OnDequeue()
- => InnerCollection.Dequeue();
+ ///
+ /// Adds an item to the inner collection when enqueuing.
+ ///
+ /// The tuple containing the sort key and value to enqueue.
+ /// If true, forces the item to be enqueued even if the queue is full; otherwise, respects the maximum size limit.
+ protected override void OnEnqueue((TSort, TValue) item, bool force)
+ => InnerCollection.Enqueue(item);
- ///
- /// Retrieves, but does not remove, the next item from the inner collection.
- ///
- /// The tuple containing the sort key and value of the item at the head of the queue.
- protected override (TSort, TValue) OnPeek()
- => InnerCollection.Peek();
- }
+ ///
+ /// Removes and returns the next item from the inner collection.
+ ///
+ /// The tuple containing the sort key and value of the dequeued item.
+ protected override (TSort, TValue) OnDequeue()
+ => InnerCollection.Dequeue();
+
+ ///
+ /// Retrieves, but does not remove, the next item from the inner collection.
+ ///
+ /// The tuple containing the sort key and value of the item at the head of the queue.
+ protected override (TSort, TValue) OnPeek()
+ => InnerCollection.Peek();
}
\ No newline at end of file
diff --git a/Collections/BitArrayReader.cs b/Collections/BitArrayReader.cs
index 1bef2adc..30a6f688 100644
--- a/Collections/BitArrayReader.cs
+++ b/Collections/BitArrayReader.cs
@@ -1,169 +1,256 @@
-namespace Ecng.Collections
-{
- using System;
- using System.IO;
+namespace Ecng.Collections;
+
+using System;
+using System.IO;
- using Ecng.Common;
+using Ecng.Common;
+
+///
+/// Provides a reader for bit-level data from a stream.
+///
+public class BitArrayReader
+{
+ private int _bitOffset;
+ private long _dataOffset;
+ private readonly ulong[] _data;
+ private readonly Stream _underlyingStream;
///
- /// Provides a reader for bit-level data from a stream.
+ /// Initializes a new instance of the class with the specified underlying stream.
///
- public class BitArrayReader
+ /// The stream to read bit-level data from.
+ /// Thrown if is null.
+ public BitArrayReader(Stream underlyingStream)
{
- private int _bitOffset;
- private long _dataOffset;
- private readonly ulong[] _data;
- private readonly Stream _underlyingStream;
-
- ///
- /// Initializes a new instance of the class with the specified underlying stream.
- ///
- /// The stream to read bit-level data from.
- /// Thrown if is null.
- public BitArrayReader(Stream underlyingStream)
- {
- _underlyingStream = underlyingStream ?? throw new ArgumentNullException(nameof(underlyingStream));
+ _underlyingStream = underlyingStream ?? throw new ArgumentNullException(nameof(underlyingStream));
- // TODO
- var bytes = underlyingStream.To();
+ // TODO
+ var bytes = underlyingStream.To();
- _data = new ulong[bytes.Length / 8 + 2];
- Buffer.BlockCopy(bytes, 0, _data, 0, bytes.Length);
- }
+ _data = new ulong[bytes.Length / 8 + 2];
+ Buffer.BlockCopy(bytes, 0, _data, 0, bytes.Length);
+ }
- ///
- /// Gets or sets the current bit offset within the stream.
- ///
- /// Thrown if the value is negative.
- public long Offset
- {
+ ///
+ /// Gets or sets the current bit offset within the stream.
+ ///
+ /// Thrown if the value is negative.
+ public long Offset
+ {
#pragma warning disable CS0675 // Bitwise-or operator used on a sign-extended operand
- get => (_dataOffset << 6) | _bitOffset;
+ get => (_dataOffset << 6) | _bitOffset;
#pragma warning restore CS0675 // Bitwise-or operator used on a sign-extended operand
- set
- {
- if (value < 0)// || value >= _bits.Length)
- throw new ArgumentOutOfRangeException(nameof(value));
+ set
+ {
+ if (value < 0)// || value >= _bits.Length)
+ throw new ArgumentOutOfRangeException(nameof(value));
- _dataOffset = value >> 6;
- _bitOffset = (int)(value & 63);
- }
+ _dataOffset = value >> 6;
+ _bitOffset = (int)(value & 63);
}
+ }
- ///
- /// Retrieves the 64-bit value at the specified offset.
- ///
- /// The offset to read from.
- /// The 64-bit value at the specified offset.
- private ulong Get(long offset)
+ ///
+ /// Retrieves the 64-bit value at the specified offset.
+ ///
+ /// The offset to read from.
+ /// The 64-bit value at the specified offset.
+ private ulong Get(long offset)
+ {
+ return _data[offset];
+ }
+
+ ///
+ /// Reads a single bit from the stream.
+ ///
+ /// The value of the bit read.
+ public bool Read()
+ {
+ var b = Get(_dataOffset);
+
+ var value = ((b >> _bitOffset) & 1) != 0;
+
+ if (_bitOffset == 63)
{
- return _data[offset];
+ _bitOffset = 0;
+ _dataOffset++;
}
+ else
+ _bitOffset++;
- ///
- /// Reads a single bit from the stream.
- ///
- /// The value of the bit read.
- public bool Read()
- {
- var b = Get(_dataOffset);
+ return value;
+ }
- var value = ((b >> _bitOffset) & 1) != 0;
+ ///
+ /// Reads an array of bits from the stream.
+ ///
+ /// The number of bits to read.
+ /// An array of boolean values representing the bits read.
+ public bool[] ReadArray(int count)
+ {
+ var retVal = new bool[count];
- if (_bitOffset == 63)
- {
- _bitOffset = 0;
- _dataOffset++;
- }
- else
- _bitOffset++;
+ for (var i = 0; i < count; i++)
+ retVal[i] = Read();
- return value;
- }
+ return retVal;
+ }
- ///
- /// Reads an array of bits from the stream.
- ///
- /// The number of bits to read.
- /// An array of boolean values representing the bits read.
- public bool[] ReadArray(int count)
- {
- var retVal = new bool[count];
+ ///
+ /// Reads a specified number of bits from the stream as an integer.
+ ///
+ /// The number of bits to read.
+ /// The integer value represented by the bits read.
+ /// Thrown if is invalid.
+ public int Read(int count)
+ {
+ return (int)ReadLong(count);
+ }
- for (var i = 0; i < count; i++)
- retVal[i] = Read();
+ ///
+ /// Moves the current bit offset by the specified number of bits.
+ ///
+ /// The number of bits to move the offset by.
+ public void Seek(int offset)
+ {
+ var newOffset = _bitOffset + offset;
+ _dataOffset += newOffset >> 6;
+ _bitOffset = newOffset & 63;
+ }
- return retVal;
- }
+ ///
+ /// Reads a specified number of bits from the stream as a long integer.
+ ///
+ /// The number of bits to read.
+ /// The long integer value represented by the bits read.
+ /// Thrown if is invalid.
+ public long ReadLong(int count)
+ {
+ if (count <= 0 || count > 64)
+ throw new ArgumentOutOfRangeException(nameof(count), count, "Invalid count value.");
+
+ var bitOffset = _bitOffset;
+
+ var value = Get(_dataOffset) >> bitOffset;
+
+ var shift = 64 - bitOffset;
+ if (shift < count)
+ value |= Get(_dataOffset + 1) << shift;
+
+ bitOffset += count;
+ _dataOffset += bitOffset >> 6;
+ _bitOffset = bitOffset & 63;
+
+ value &= ulong.MaxValue >> (64 - count);
+
+ return (long)value;
+ }
+
+ ///
+ /// Reads an integer value from the stream using a variable-length encoding.
+ ///
+ /// The integer value read from the stream.
+ public int ReadInt()
+ {
+ var bits = Get(_dataOffset);
+ var bitOffset = _bitOffset;
- ///
- /// Reads a specified number of bits from the stream as an integer.
- ///
- /// The number of bits to read.
- /// The integer value represented by the bits read.
- /// Thrown if is invalid.
- public int Read(int count)
+ bits >>= bitOffset;
+
+ if (bitOffset > 0)
+ bits |= Get(_dataOffset + 1) << (64 - bitOffset); // честные 64 бита в битс
+
+ var value = 0;
+
+ int seek;
+
+ if ((bits & 1) == 0)
{
- return (int)ReadLong(count);
+ seek = 1;
}
-
- ///
- /// Moves the current bit offset by the specified number of bits.
- ///
- /// The number of bits to move the offset by.
- public void Seek(int offset)
+ else if ((bits & 4) == 0)
{
- var newOffset = _bitOffset + offset;
- _dataOffset += newOffset >> 6;
- _bitOffset = newOffset & 63;
+ seek = 3;
+ value = 1;
}
-
- ///
- /// Reads a specified number of bits from the stream as a long integer.
- ///
- /// The number of bits to read.
- /// The long integer value represented by the bits read.
- /// Thrown if is invalid.
- public long ReadLong(int count)
+ else if ((bits & 8) == 0)
{
- if (count <= 0 || count > 64)
- throw new ArgumentOutOfRangeException(nameof(count), count, "Invalid count value.");
-
- var bitOffset = _bitOffset;
+ seek = 4 + 4;
+ value = ((int)(uint.MaxValue >> (32 - 4))) & (int)(bits >> 4);
+ }
+ else if ((bits & 16) == 0)
+ {
+ seek = 5 + 8;
+ value = ((int)(uint.MaxValue >> (32 - 8))) & (int)(bits >> 5);
+ }
+ else if ((bits & 32) == 0)
+ {
+ seek = 6 + 16;
+ value = ((int)(uint.MaxValue >> (32 - 16))) & (int)(bits >> 6);
+ }
+ else if ((bits & 64) == 0)
+ {
+ seek = 7 + 24;
+ value = ((int)(uint.MaxValue >> (32 - 24))) & (int)(bits >> 7);
+ }
+ else
+ {
+ seek = 7 + 32;
+ value = (int)(bits >> 7);
+ }
- var value = Get(_dataOffset) >> bitOffset;
+ value = (bits & 2) != 0 ? value : -value;
- var shift = 64 - bitOffset;
- if (shift < count)
- value |= Get(_dataOffset + 1) << shift;
+ bitOffset += seek;
+ _dataOffset += (bitOffset >> 6);
+ _bitOffset = bitOffset & 63;
- bitOffset += count;
- _dataOffset += bitOffset >> 6;
- _bitOffset = bitOffset & 63;
+ return value;
+ }
- value &= ulong.MaxValue >> (64 - count);
+ ///
+ /// Reads a long integer value from the stream using a variable-length encoding.
+ ///
+ /// The long integer value read from the stream.
+ public long ReadLong()
+ {
+ var offset = _dataOffset;
+ var bitOffset = _bitOffset;
+ var bits = Get(offset) >> bitOffset;
- return (long)value;
- }
+ if (bitOffset > 0)
+ bits |= Get(offset + 1) << (64 - bitOffset);
- ///
- /// Reads an integer value from the stream using a variable-length encoding.
- ///
- /// The integer value read from the stream.
- public int ReadInt()
+ long value;
+ if ((bits & 1) != 0)
{
- var bits = Get(_dataOffset);
- var bitOffset = _bitOffset;
+ var isPositive = (bits & 2) != 0;
+
+ bitOffset += 2;
- bits >>= bitOffset;
+ offset += bitOffset >> 6;
+ bitOffset &= 63;
+ bits = Get(offset) >> bitOffset;
if (bitOffset > 0)
- bits |= Get(_dataOffset + 1) << (64 - bitOffset); // честные 64 бита в битс
+ bits |= Get(offset + 1) << (64 - bitOffset);
+
+ bitOffset += 63;
- var value = 0;
+ value = (long)(bits & (ulong.MaxValue >> (64 - 63)));
+
+ if (!isPositive)
+ value = -value;
+ }
+ else
+ {
+ bitOffset += 1;
+ bits >>= 1;
int seek;
+ value = 0;
+
if ((bits & 1) == 0)
{
seek = 1;
@@ -200,122 +287,34 @@ public int ReadInt()
}
value = (bits & 2) != 0 ? value : -value;
-
bitOffset += seek;
- _dataOffset += (bitOffset >> 6);
- _bitOffset = bitOffset & 63;
-
- return value;
}
- ///
- /// Reads a long integer value from the stream using a variable-length encoding.
- ///
- /// The long integer value read from the stream.
- public long ReadLong()
- {
- var offset = _dataOffset;
- var bitOffset = _bitOffset;
- var bits = Get(offset) >> bitOffset;
-
- if (bitOffset > 0)
- bits |= Get(offset + 1) << (64 - bitOffset);
+ offset += bitOffset >> 6;
+ bitOffset &= 63;
+ _dataOffset = offset;
+ _bitOffset = bitOffset;
- long value;
- if ((bits & 1) != 0)
- {
- var isPositive = (bits & 2) != 0;
-
- bitOffset += 2;
-
- offset += bitOffset >> 6;
- bitOffset &= 63;
- bits = Get(offset) >> bitOffset;
-
- if (bitOffset > 0)
- bits |= Get(offset + 1) << (64 - bitOffset);
-
- bitOffset += 63;
-
- value = (long)(bits & (ulong.MaxValue >> (64 - 63)));
-
- if (!isPositive)
- value = -value;
- }
- else
- {
- bitOffset += 1;
- bits >>= 1;
-
- int seek;
-
- value = 0;
-
- if ((bits & 1) == 0)
- {
- seek = 1;
- }
- else if ((bits & 4) == 0)
- {
- seek = 3;
- value = 1;
- }
- else if ((bits & 8) == 0)
- {
- seek = 4 + 4;
- value = ((int)(uint.MaxValue >> (32 - 4))) & (int)(bits >> 4);
- }
- else if ((bits & 16) == 0)
- {
- seek = 5 + 8;
- value = ((int)(uint.MaxValue >> (32 - 8))) & (int)(bits >> 5);
- }
- else if ((bits & 32) == 0)
- {
- seek = 6 + 16;
- value = ((int)(uint.MaxValue >> (32 - 16))) & (int)(bits >> 6);
- }
- else if ((bits & 64) == 0)
- {
- seek = 7 + 24;
- value = ((int)(uint.MaxValue >> (32 - 24))) & (int)(bits >> 7);
- }
- else
- {
- seek = 7 + 32;
- value = (int)(bits >> 7);
- }
-
- value = (bits & 2) != 0 ? value : -value;
- bitOffset += seek;
- }
-
- offset += bitOffset >> 6;
- bitOffset &= 63;
- _dataOffset = offset;
- _bitOffset = bitOffset;
-
- return value;
- }
+ return value;
+ }
- ///
- /// Reads a decimal value from the stream.
- ///
- /// The decimal value read from the stream.
- public decimal ReadDecimal()
- {
- var isPos = Read();
+ ///
+ /// Reads a decimal value from the stream.
+ ///
+ /// The decimal value read from the stream.
+ public decimal ReadDecimal()
+ {
+ var isPos = Read();
- var i1 = ReadInt();
- var i2 = ReadInt();
- var i3 = ReadInt();
- var i4 = ReadInt() << 16;
- var dec = new[] { i1, i2, i3, i4 }.To();
+ var i1 = ReadInt();
+ var i2 = ReadInt();
+ var i3 = ReadInt();
+ var i4 = ReadInt() << 16;
+ var dec = new[] { i1, i2, i3, i4 }.To();
- if (!isPos)
- dec = -dec;
+ if (!isPos)
+ dec = -dec;
- return dec;
- }
+ return dec;
}
}
\ No newline at end of file
diff --git a/Collections/BitArrayWriter.cs b/Collections/BitArrayWriter.cs
index 7825d5f2..db4d25b8 100644
--- a/Collections/BitArrayWriter.cs
+++ b/Collections/BitArrayWriter.cs
@@ -1,187 +1,186 @@
-namespace Ecng.Collections
-{
- using System;
- using System.IO;
+namespace Ecng.Collections;
+
+using System;
+using System.IO;
- using Ecng.Common;
+using Ecng.Common;
+
+///
+/// Provides a writer for bit-level data to a stream.
+///
+public class BitArrayWriter(Stream underlyingStream) : Disposable
+{
+ private readonly Stream _underlyingStream = underlyingStream ?? throw new ArgumentNullException(nameof(underlyingStream));
+ private int _temp;
+ private int _bitOffset;
///
- /// Provides a writer for bit-level data to a stream.
+ /// Flushes the current byte to the underlying stream and resets the buffer.
///
- public class BitArrayWriter(Stream underlyingStream) : Disposable
+ private void Flush()
{
- private readonly Stream _underlyingStream = underlyingStream ?? throw new ArgumentNullException(nameof(underlyingStream));
- private int _temp;
- private int _bitOffset;
-
- ///
- /// Flushes the current byte to the underlying stream and resets the buffer.
- ///
- private void Flush()
- {
- _underlyingStream.WriteByte((byte)_temp);
- _temp = 0;
- _bitOffset = 0;
- }
+ _underlyingStream.WriteByte((byte)_temp);
+ _temp = 0;
+ _bitOffset = 0;
+ }
- ///
- /// Disposes the writer, ensuring any remaining bits are flushed to the stream.
- ///
- protected override void DisposeManaged()
- {
- if (_bitOffset > 0)
- Flush();
+ ///
+ /// Disposes the writer, ensuring any remaining bits are flushed to the stream.
+ ///
+ protected override void DisposeManaged()
+ {
+ if (_bitOffset > 0)
+ Flush();
- base.DisposeManaged();
- }
+ base.DisposeManaged();
+ }
- ///
- /// Writes a single bit to the stream.
- ///
- /// The bit to write.
- public void Write(bool bit)
- {
- _temp |= ((bit ? 1 : 0) << _bitOffset);
+ ///
+ /// Writes a single bit to the stream.
+ ///
+ /// The bit to write.
+ public void Write(bool bit)
+ {
+ _temp |= ((bit ? 1 : 0) << _bitOffset);
- _bitOffset++;
+ _bitOffset++;
- if (_bitOffset < 8)
- return;
+ if (_bitOffset < 8)
+ return;
- Flush();
- }
+ Flush();
+ }
- ///
- /// Writes an integer value to the stream using a variable-length encoding.
- ///
- /// The integer value to write.
- public void WriteInt(int value)
+ ///
+ /// Writes an integer value to the stream using a variable-length encoding.
+ ///
+ /// The integer value to write.
+ public void WriteInt(int value)
+ {
+ if (value == 0)
+ Write(false);
+ else
{
- if (value == 0)
+ Write(true);
+
+ if (value < 0)
+ {
+ value = -value;
+ Write(false);
+ }
+ else
+ Write(true);
+
+ if (value == 1)
Write(false);
else
{
Write(true);
- if (value < 0)
+ if (value < 16)
{
- value = -value;
Write(false);
+ WriteBits(value, 4);
}
- else
- Write(true);
-
- if (value == 1)
- Write(false);
else
{
Write(true);
- if (value < 16)
+ if (value <= byte.MaxValue)
{
Write(false);
- WriteBits(value, 4);
+ WriteBits(value, 8);
}
else
{
Write(true);
- if (value <= byte.MaxValue)
+ if (value <= ushort.MaxValue)
{
Write(false);
- WriteBits(value, 8);
+ WriteBits(value, 16);
}
else
{
Write(true);
- if (value <= ushort.MaxValue)
+ if (value <= 16777216) // 24 bits
{
Write(false);
- WriteBits(value, 16);
+ WriteBits(value, 24);
}
else
{
Write(true);
-
- if (value <= 16777216) // 24 bits
- {
- Write(false);
- WriteBits(value, 24);
- }
- else
- {
- Write(true);
- WriteBits(value, 32);
- }
+ WriteBits(value, 32);
}
}
}
}
}
}
+ }
- ///
- /// Writes a long integer value to the stream using a variable-length encoding.
- ///
- /// The long integer value to write.
- public void WriteLong(long value)
+ ///
+ /// Writes a long integer value to the stream using a variable-length encoding.
+ ///
+ /// The long integer value to write.
+ public void WriteLong(long value)
+ {
+ if (value.Abs() > int.MaxValue)
{
- if (value.Abs() > int.MaxValue)
- {
- Write(true);
- Write(value >= 0);
- WriteBits(value.Abs(), 63);
- }
- else
- {
- Write(false);
- WriteInt((int)value);
- }
+ Write(true);
+ Write(value >= 0);
+ WriteBits(value.Abs(), 63);
}
-
- ///
- /// Writes a specified number of bits from an integer value to the stream.
- ///
- /// The integer value to write.
- /// The number of bits to write.
- public void WriteBits(int value, int bitCount)
+ else
{
- for (var i = 0; i < bitCount; i++)
- Write((value & (1 << i)) != 0);
+ Write(false);
+ WriteInt((int)value);
}
+ }
- ///
- /// Writes a specified number of bits from a long integer value to the stream.
- ///
- /// The long integer value to write.
- /// The number of bits to write.
- public void WriteBits(long value, int bitCount)
- {
- for (var i = 0; i < bitCount; i++)
- Write((value & (1L << i)) != 0);
- }
+ ///
+ /// Writes a specified number of bits from an integer value to the stream.
+ ///
+ /// The integer value to write.
+ /// The number of bits to write.
+ public void WriteBits(int value, int bitCount)
+ {
+ for (var i = 0; i < bitCount; i++)
+ Write((value & (1 << i)) != 0);
+ }
- ///
- /// Writes a decimal value to the stream.
- ///
- /// The decimal value to write.
- public void WriteDecimal(decimal value)
- {
- if (value < 0)
- {
- value = -value;
- Write(false);
- }
- else
- Write(true);
-
- var bits = value.To();
+ ///
+ /// Writes a specified number of bits from a long integer value to the stream.
+ ///
+ /// The long integer value to write.
+ /// The number of bits to write.
+ public void WriteBits(long value, int bitCount)
+ {
+ for (var i = 0; i < bitCount; i++)
+ Write((value & (1L << i)) != 0);
+ }
- WriteInt(bits[0]);
- WriteInt(bits[1]);
- WriteInt(bits[2]);
- WriteInt((bits[3] >> 16) & 0xff);
+ ///
+ /// Writes a decimal value to the stream.
+ ///
+ /// The decimal value to write.
+ public void WriteDecimal(decimal value)
+ {
+ if (value < 0)
+ {
+ value = -value;
+ Write(false);
}
+ else
+ Write(true);
+
+ var bits = value.To();
+
+ WriteInt(bits[0]);
+ WriteInt(bits[1]);
+ WriteInt(bits[2]);
+ WriteInt((bits[3] >> 16) & 0xff);
}
}
\ No newline at end of file
diff --git a/Collections/BlockingQueue.cs b/Collections/BlockingQueue.cs
index 2342c758..9f5b0d88 100644
--- a/Collections/BlockingQueue.cs
+++ b/Collections/BlockingQueue.cs
@@ -1,45 +1,44 @@
-namespace Ecng.Collections
+namespace Ecng.Collections;
+
+///
+/// Represents a thread-safe blocking queue implementation for storing and retrieving items of type .
+///
+/// The type of elements in the queue.
+public sealed class BlockingQueue : BaseBlockingQueue>
{
///
- /// Represents a thread-safe blocking queue implementation for storing and retrieving items of type .
+ /// Initializes a new instance of the class with an empty underlying queue.
///
- /// The type of elements in the queue.
- public sealed class BlockingQueue : BaseBlockingQueue>
+ public BlockingQueue()
+ : base(new QueueEx())
{
- ///
- /// Initializes a new instance of the class with an empty underlying queue.
- ///
- public BlockingQueue()
- : base(new QueueEx())
- {
- }
+ }
- ///
- /// Adds an item to the underlying queue.
- ///
- /// The item to enqueue.
- /// If true, forces the item to be enqueued even if the queue is full; otherwise, respects the maximum size limit.
- protected override void OnEnqueue(T item, bool force)
- {
- InnerCollection.Enqueue(item);
- }
+ ///
+ /// Adds an item to the underlying queue.
+ ///
+ /// The item to enqueue.
+ /// If true, forces the item to be enqueued even if the queue is full; otherwise, respects the maximum size limit.
+ protected override void OnEnqueue(T item, bool force)
+ {
+ InnerCollection.Enqueue(item);
+ }
- ///
- /// Removes and returns the item at the head of the underlying queue.
- ///
- /// The dequeued item.
- protected override T OnDequeue()
- {
- return InnerCollection.Dequeue();
- }
+ ///
+ /// Removes and returns the item at the head of the underlying queue.
+ ///
+ /// The dequeued item.
+ protected override T OnDequeue()
+ {
+ return InnerCollection.Dequeue();
+ }
- ///
- /// Retrieves, but does not remove, the item at the head of the underlying queue.
- ///
- /// The item at the head of the queue.
- protected override T OnPeek()
- {
- return InnerCollection.Peek();
- }
+ ///
+ /// Retrieves, but does not remove, the item at the head of the underlying queue.
+ ///
+ /// The item at the head of the queue.
+ protected override T OnPeek()
+ {
+ return InnerCollection.Peek();
}
}
\ No newline at end of file
diff --git a/Collections/CachedSynchronizedDictionary.cs b/Collections/CachedSynchronizedDictionary.cs
index a42e1424..d30b9424 100644
--- a/Collections/CachedSynchronizedDictionary.cs
+++ b/Collections/CachedSynchronizedDictionary.cs
@@ -1,180 +1,179 @@
-namespace Ecng.Collections
-{
- using System.Collections.Generic;
+namespace Ecng.Collections;
+
+using System.Collections.Generic;
+///
+/// Represents a thread-safe dictionary with cached keys, values, and key-value pairs for improved performance.
+///
+/// The type of keys in the dictionary.
+/// The type of values in the dictionary.
+public class CachedSynchronizedDictionary : SynchronizedDictionary
+{
///
- /// Represents a thread-safe dictionary with cached keys, values, and key-value pairs for improved performance.
+ /// Initializes a new instance of the class.
///
- /// The type of keys in the dictionary.
- /// The type of values in the dictionary.
- public class CachedSynchronizedDictionary : SynchronizedDictionary
+ public CachedSynchronizedDictionary()
{
- ///
- /// Initializes a new instance of the class.
- ///
- public CachedSynchronizedDictionary()
- {
- }
+ }
- ///
- /// Initializes a new instance of the class with the specified initial capacity.
- ///
- /// The initial number of elements that the dictionary can contain.
- public CachedSynchronizedDictionary(int capacity)
- : base(capacity)
- {
- }
+ ///
+ /// Initializes a new instance of the class with the specified initial capacity.
+ ///
+ /// The initial number of elements that the dictionary can contain.
+ public CachedSynchronizedDictionary(int capacity)
+ : base(capacity)
+ {
+ }
- ///
- /// Initializes a new instance of the class with the specified equality comparer.
- ///
- /// The equality comparer to use when comparing keys.
- public CachedSynchronizedDictionary(IEqualityComparer comparer)
- : base(comparer)
- {
- }
+ ///
+ /// Initializes a new instance of the class with the specified equality comparer.
+ ///
+ /// The equality comparer to use when comparing keys.
+ public CachedSynchronizedDictionary(IEqualityComparer comparer)
+ : base(comparer)
+ {
+ }
- ///
- /// Initializes a new instance of the class with the specified initial capacity and equality comparer.
- ///
- /// The initial number of elements that the dictionary can contain.
- /// The equality comparer to use when comparing keys.
- public CachedSynchronizedDictionary(int capacity, IEqualityComparer comparer)
- : base(capacity, comparer)
- {
- }
+ ///
+ /// Initializes a new instance of the class with the specified initial capacity and equality comparer.
+ ///
+ /// The initial number of elements that the dictionary can contain.
+ /// The equality comparer to use when comparing keys.
+ public CachedSynchronizedDictionary(int capacity, IEqualityComparer comparer)
+ : base(capacity, comparer)
+ {
+ }
- private TKey[] _cachedKeys;
+ private TKey[] _cachedKeys;
- ///
- /// Gets an array of cached keys from the dictionary.
- ///
- ///
- /// The keys are cached for performance and are reset when the dictionary is modified.
- ///
- public TKey[] CachedKeys
+ ///
+ /// Gets an array of cached keys from the dictionary.
+ ///
+ ///
+ /// The keys are cached for performance and are reset when the dictionary is modified.
+ ///
+ public TKey[] CachedKeys
+ {
+ get
{
- get
- {
- lock (SyncRoot)
- return _cachedKeys ??= [.. Keys];
- }
+ lock (SyncRoot)
+ return _cachedKeys ??= [.. Keys];
}
+ }
- private TValue[] _cachedValues;
+ private TValue[] _cachedValues;
- ///
- /// Gets an array of cached values from the dictionary.
- ///
- ///
- /// The values are cached for performance and are reset when the dictionary is modified.
- ///
- public TValue[] CachedValues
+ ///
+ /// Gets an array of cached values from the dictionary.
+ ///
+ ///
+ /// The values are cached for performance and are reset when the dictionary is modified.
+ ///
+ public TValue[] CachedValues
+ {
+ get
{
- get
- {
- lock (SyncRoot)
- return _cachedValues ??= [.. Values];
- }
+ lock (SyncRoot)
+ return _cachedValues ??= [.. Values];
}
+ }
- private KeyValuePair[] _cachedPairs;
+ private KeyValuePair[] _cachedPairs;
- ///
- /// Gets an array of cached key-value pairs from the dictionary.
- ///
- ///
- /// The key-value pairs are cached for performance and are reset when the dictionary is modified.
- ///
- public KeyValuePair[] CachedPairs
+ ///
+ /// Gets an array of cached key-value pairs from the dictionary.
+ ///
+ ///
+ /// The key-value pairs are cached for performance and are reset when the dictionary is modified.
+ ///
+ public KeyValuePair[] CachedPairs
+ {
+ get
{
- get
- {
- lock (SyncRoot)
- return _cachedPairs ??= [.. this];
- }
+ lock (SyncRoot)
+ return _cachedPairs ??= [.. this];
}
+ }
- ///
- /// Gets or sets the value associated with the specified key.
- ///
- /// The key of the value to get or set.
- /// The value associated with the specified key.
- public override TValue this[TKey key]
+ ///
+ /// Gets or sets the value associated with the specified key.
+ ///
+ /// The key of the value to get or set.
+ /// The value associated with the specified key.
+ public override TValue this[TKey key]
+ {
+ set
{
- set
+ lock (SyncRoot)
{
- lock (SyncRoot)
- {
- var isKey = false;
+ var isKey = false;
- if (_cachedKeys != null && !ContainsKey(key))
- isKey = true;
+ if (_cachedKeys != null && !ContainsKey(key))
+ isKey = true;
- OnResetCache(isKey);
+ OnResetCache(isKey);
- base[key] = value;
- }
+ base[key] = value;
}
}
+ }
- ///
- /// Adds the specified key and value to the dictionary.
- ///
- /// The key of the element to add.
- /// The value of the element to add.
- public override void Add(TKey key, TValue value)
+ ///
+ /// Adds the specified key and value to the dictionary.
+ ///
+ /// The key of the element to add.
+ /// The value of the element to add.
+ public override void Add(TKey key, TValue value)
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
- {
- base.Add(key, value);
+ base.Add(key, value);
- OnResetCache(true);
- }
+ OnResetCache(true);
}
+ }
- ///
- /// Removes the value with the specified key from the dictionary.
- ///
- /// The key of the element to remove.
- /// true if the element is successfully found and removed; otherwise, false.
- public override bool Remove(TKey key)
+ ///
+ /// Removes the value with the specified key from the dictionary.
+ ///
+ /// The key of the element to remove.
+ /// true if the element is successfully found and removed; otherwise, false.
+ public override bool Remove(TKey key)
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
+ if (base.Remove(key))
{
- if (base.Remove(key))
- {
- OnResetCache(true);
-
- return true;
- }
+ OnResetCache(true);
- return false;
+ return true;
}
+
+ return false;
}
+ }
- ///
- /// Removes all keys and values from the dictionary.
- ///
- public override void Clear()
+ ///
+ /// Removes all keys and values from the dictionary.
+ ///
+ public override void Clear()
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
- {
- base.Clear();
+ base.Clear();
- OnResetCache(true);
- }
+ OnResetCache(true);
}
+ }
- ///
- /// Resets the cached keys, values, and key-value pairs when the dictionary is modified.
- ///
- /// Indicates whether the cache reset is due to a key modification.
- protected virtual void OnResetCache(bool isKey)
- {
- _cachedKeys = null;
- _cachedValues = null;
- _cachedPairs = null;
- }
+ ///
+ /// Resets the cached keys, values, and key-value pairs when the dictionary is modified.
+ ///
+ /// Indicates whether the cache reset is due to a key modification.
+ protected virtual void OnResetCache(bool isKey)
+ {
+ _cachedKeys = null;
+ _cachedValues = null;
+ _cachedPairs = null;
}
}
diff --git a/Collections/CachedSynchronizedList.cs b/Collections/CachedSynchronizedList.cs
index 942cc291..7053421a 100644
--- a/Collections/CachedSynchronizedList.cs
+++ b/Collections/CachedSynchronizedList.cs
@@ -1,52 +1,51 @@
-namespace Ecng.Collections
+namespace Ecng.Collections;
+
+///
+/// Represents a thread-safe list with a cached array of its elements for improved performance.
+///
+/// The type of elements in the list.
+public class CachedSynchronizedList : SynchronizedList
{
///
- /// Represents a thread-safe list with a cached array of its elements for improved performance.
+ /// Initializes a new instance of the class.
///
- /// The type of elements in the list.
- public class CachedSynchronizedList : SynchronizedList
+ public CachedSynchronizedList()
{
- ///
- /// Initializes a new instance of the class.
- ///
- public CachedSynchronizedList()
- {
- }
+ }
- ///
- /// Initializes a new instance of the class with the specified initial capacity.
- ///
- /// The initial number of elements that the list can contain.
- public CachedSynchronizedList(int capacity)
- : base(capacity)
- {
- }
+ ///
+ /// Initializes a new instance of the class with the specified initial capacity.
+ ///
+ /// The initial number of elements that the list can contain.
+ public CachedSynchronizedList(int capacity)
+ : base(capacity)
+ {
+ }
- private T[] _cache;
+ private T[] _cache;
- ///
- /// Gets a cached array of the elements in the list.
- ///
- ///
- /// The array is cached for performance and is reset when the list is modified.
- ///
- public T[] Cache
+ ///
+ /// Gets a cached array of the elements in the list.
+ ///
+ ///
+ /// The array is cached for performance and is reset when the list is modified.
+ ///
+ public T[] Cache
+ {
+ get
{
- get
- {
- lock (SyncRoot)
- return _cache ??= [.. this];
- }
+ lock (SyncRoot)
+ return _cache ??= [.. this];
}
+ }
- ///
- /// Called when the list is modified to reset the cached array.
- ///
- protected override void OnChanged()
- {
- _cache = null;
+ ///
+ /// Called when the list is modified to reset the cached array.
+ ///
+ protected override void OnChanged()
+ {
+ _cache = null;
- base.OnChanged();
- }
+ base.OnChanged();
}
}
\ No newline at end of file
diff --git a/Collections/CachedSynchronizedOrderedDictionary.cs b/Collections/CachedSynchronizedOrderedDictionary.cs
index 68aaedcc..99c5b4c7 100644
--- a/Collections/CachedSynchronizedOrderedDictionary.cs
+++ b/Collections/CachedSynchronizedOrderedDictionary.cs
@@ -1,171 +1,170 @@
-namespace Ecng.Collections
-{
- using System;
- using System.Collections.Generic;
+namespace Ecng.Collections;
+
+using System;
+using System.Collections.Generic;
+///
+/// Represents a thread-safe ordered dictionary with cached keys, values, and key-value pairs for improved performance.
+///
+/// The type of keys in the dictionary.
+/// The type of values in the dictionary.
+public class CachedSynchronizedOrderedDictionary : SynchronizedOrderedDictionary
+{
///
- /// Represents a thread-safe ordered dictionary with cached keys, values, and key-value pairs for improved performance.
+ /// Initializes a new instance of the class.
///
- /// The type of keys in the dictionary.
- /// The type of values in the dictionary.
- public class CachedSynchronizedOrderedDictionary : SynchronizedOrderedDictionary
+ public CachedSynchronizedOrderedDictionary()
{
- ///
- /// Initializes a new instance of the class.
- ///
- public CachedSynchronizedOrderedDictionary()
- {
- }
+ }
- ///
- /// Initializes a new instance of the class with the specified key comparer.
- ///
- /// The comparer to use when comparing keys.
- public CachedSynchronizedOrderedDictionary(IComparer comparer)
- : base(comparer)
- {
- }
+ ///
+ /// Initializes a new instance of the class with the specified key comparer.
+ ///
+ /// The comparer to use when comparing keys.
+ public CachedSynchronizedOrderedDictionary(IComparer comparer)
+ : base(comparer)
+ {
+ }
- ///
- /// Initializes a new instance of the class with the specified key comparison function.
- ///
- /// The function to use when comparing keys.
- public CachedSynchronizedOrderedDictionary(Func comparer)
- : base(comparer)
- {
- }
+ ///
+ /// Initializes a new instance of the class with the specified key comparison function.
+ ///
+ /// The function to use when comparing keys.
+ public CachedSynchronizedOrderedDictionary(Func comparer)
+ : base(comparer)
+ {
+ }
- private TKey[] _cachedKeys;
+ private TKey[] _cachedKeys;
- ///
- /// Gets an array of cached keys from the dictionary.
- ///
- ///
- /// The keys are cached for performance and are reset when the dictionary is modified.
- ///
- public TKey[] CachedKeys
+ ///
+ /// Gets an array of cached keys from the dictionary.
+ ///
+ ///
+ /// The keys are cached for performance and are reset when the dictionary is modified.
+ ///
+ public TKey[] CachedKeys
+ {
+ get
{
- get
- {
- lock (SyncRoot)
- return _cachedKeys ??= [.. Keys];
- }
+ lock (SyncRoot)
+ return _cachedKeys ??= [.. Keys];
}
+ }
- private TValue[] _cachedValues;
+ private TValue[] _cachedValues;
- ///
- /// Gets an array of cached values from the dictionary.
- ///
- ///
- /// The values are cached for performance and are reset when the dictionary is modified.
- ///
- public TValue[] CachedValues
+ ///
+ /// Gets an array of cached values from the dictionary.
+ ///
+ ///
+ /// The values are cached for performance and are reset when the dictionary is modified.
+ ///
+ public TValue[] CachedValues
+ {
+ get
{
- get
- {
- lock (SyncRoot)
- return _cachedValues ??= [.. Values];
- }
+ lock (SyncRoot)
+ return _cachedValues ??= [.. Values];
}
+ }
- private KeyValuePair[] _cachedPairs;
+ private KeyValuePair[] _cachedPairs;
- ///
- /// Gets an array of cached key-value pairs from the dictionary.
- ///
- ///
- /// The key-value pairs are cached for performance and are reset when the dictionary is modified.
- ///
- public KeyValuePair[] CachedPairs
+ ///
+ /// Gets an array of cached key-value pairs from the dictionary.
+ ///
+ ///
+ /// The key-value pairs are cached for performance and are reset when the dictionary is modified.
+ ///
+ public KeyValuePair[] CachedPairs
+ {
+ get
{
- get
- {
- lock (SyncRoot)
- return _cachedPairs ??= [.. this];
- }
+ lock (SyncRoot)
+ return _cachedPairs ??= [.. this];
}
+ }
- ///
- /// Gets or sets the value associated with the specified key.
- ///
- /// The key of the value to get or set.
- /// The value associated with the specified key.
- public override TValue this[TKey key]
+ ///
+ /// Gets or sets the value associated with the specified key.
+ ///
+ /// The key of the value to get or set.
+ /// The value associated with the specified key.
+ public override TValue this[TKey key]
+ {
+ set
{
- set
+ lock (SyncRoot)
{
- lock (SyncRoot)
- {
- var isKey = false;
+ var isKey = false;
- if (!ContainsKey(key))
- isKey = true;
+ if (!ContainsKey(key))
+ isKey = true;
- OnResetCache(isKey);
+ OnResetCache(isKey);
- base[key] = value;
- }
+ base[key] = value;
}
}
+ }
- ///
- /// Adds the specified key and value to the dictionary.
- ///
- /// The key of the element to add.
- /// The value of the element to add.
- public override void Add(TKey key, TValue value)
+ ///
+ /// Adds the specified key and value to the dictionary.
+ ///
+ /// The key of the element to add.
+ /// The value of the element to add.
+ public override void Add(TKey key, TValue value)
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
- {
- base.Add(key, value);
+ base.Add(key, value);
- OnResetCache(true);
- }
+ OnResetCache(true);
}
+ }
- ///
- /// Removes the value with the specified key from the dictionary.
- ///
- /// The key of the element to remove.
- /// true if the element is successfully found and removed; otherwise, false.
- public override bool Remove(TKey key)
+ ///
+ /// Removes the value with the specified key from the dictionary.
+ ///
+ /// The key of the element to remove.
+ /// true if the element is successfully found and removed; otherwise, false.
+ public override bool Remove(TKey key)
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
+ if (base.Remove(key))
{
- if (base.Remove(key))
- {
- OnResetCache(true);
-
- return true;
- }
+ OnResetCache(true);
- return false;
+ return true;
}
+
+ return false;
}
+ }
- ///
- /// Removes all keys and values from the dictionary.
- ///
- public override void Clear()
+ ///
+ /// Removes all keys and values from the dictionary.
+ ///
+ public override void Clear()
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
- {
- base.Clear();
+ base.Clear();
- OnResetCache(true);
- }
+ OnResetCache(true);
}
+ }
- ///
- /// Resets the cached keys, values, and key-value pairs when the dictionary is modified.
- ///
- /// Indicates whether the cache reset is due to a key modification.
- protected virtual void OnResetCache(bool isKey)
- {
- _cachedKeys = null;
- _cachedValues = null;
- _cachedPairs = null;
- }
+ ///
+ /// Resets the cached keys, values, and key-value pairs when the dictionary is modified.
+ ///
+ /// Indicates whether the cache reset is due to a key modification.
+ protected virtual void OnResetCache(bool isKey)
+ {
+ _cachedKeys = null;
+ _cachedValues = null;
+ _cachedPairs = null;
}
}
\ No newline at end of file
diff --git a/Collections/CachedSynchronizedPairSet.cs b/Collections/CachedSynchronizedPairSet.cs
index 10d08dfc..79f3c2a0 100644
--- a/Collections/CachedSynchronizedPairSet.cs
+++ b/Collections/CachedSynchronizedPairSet.cs
@@ -1,171 +1,170 @@
-namespace Ecng.Collections
-{
- using System.Collections.Generic;
+namespace Ecng.Collections;
+
+using System.Collections.Generic;
+///
+/// Represents a thread-safe set of key-value pairs with cached keys, values, and pairs for improved performance.
+///
+/// The type of keys in the set.
+/// The type of values in the set.
+public class CachedSynchronizedPairSet : SynchronizedPairSet
+{
///
- /// Represents a thread-safe set of key-value pairs with cached keys, values, and pairs for improved performance.
+ /// Initializes a new instance of the class.
///
- /// The type of keys in the set.
- /// The type of values in the set.
- public class CachedSynchronizedPairSet : SynchronizedPairSet
+ public CachedSynchronizedPairSet()
{
- ///
- /// Initializes a new instance of the class.
- ///
- public CachedSynchronizedPairSet()
- {
- }
+ }
- ///
- /// Initializes a new instance of the class with the specified key comparer.
- ///
- /// The equality comparer to use when comparing keys.
- public CachedSynchronizedPairSet(IEqualityComparer comparer)
- : base(comparer)
- {
- }
+ ///
+ /// Initializes a new instance of the class with the specified key comparer.
+ ///
+ /// The equality comparer to use when comparing keys.
+ public CachedSynchronizedPairSet(IEqualityComparer comparer)
+ : base(comparer)
+ {
+ }
- ///
- /// Initializes a new instance of the class with the specified key and value comparers.
- ///
- /// The equality comparer to use when comparing keys.
- /// The equality comparer to use when comparing values.
- public CachedSynchronizedPairSet(IEqualityComparer keyComparer, IEqualityComparer valueComparer)
- : base(keyComparer, valueComparer)
- {
- }
+ ///
+ /// Initializes a new instance of the class with the specified key and value comparers.
+ ///
+ /// The equality comparer to use when comparing keys.
+ /// The equality comparer to use when comparing values.
+ public CachedSynchronizedPairSet(IEqualityComparer keyComparer, IEqualityComparer valueComparer)
+ : base(keyComparer, valueComparer)
+ {
+ }
- private TKey[] _cachedKeys;
+ private TKey[] _cachedKeys;
- ///
- /// Gets an array of cached keys from the set.
- ///
- ///
- /// The keys are cached for performance and are reset when the set is modified.
- ///
- public TKey[] CachedKeys
+ ///
+ /// Gets an array of cached keys from the set.
+ ///
+ ///
+ /// The keys are cached for performance and are reset when the set is modified.
+ ///
+ public TKey[] CachedKeys
+ {
+ get
{
- get
- {
- lock (SyncRoot)
- return _cachedKeys ??= [.. Keys];
- }
+ lock (SyncRoot)
+ return _cachedKeys ??= [.. Keys];
}
+ }
- private TValue[] _cachedValues;
+ private TValue[] _cachedValues;
- ///
- /// Gets an array of cached values from the set.
- ///
- ///
- /// The values are cached for performance and are reset when the set is modified.
- ///
- public TValue[] CachedValues
+ ///
+ /// Gets an array of cached values from the set.
+ ///
+ ///
+ /// The values are cached for performance and are reset when the set is modified.
+ ///
+ public TValue[] CachedValues
+ {
+ get
{
- get
- {
- lock (SyncRoot)
- return _cachedValues ??= [.. Values];
- }
+ lock (SyncRoot)
+ return _cachedValues ??= [.. Values];
}
+ }
- private KeyValuePair[] _cachedPairs;
+ private KeyValuePair[] _cachedPairs;
- ///
- /// Gets an array of cached key-value pairs from the set.
- ///
- ///
- /// The key-value pairs are cached for performance and are reset when the set is modified.
- ///
- public KeyValuePair[] CachedPairs
+ ///
+ /// Gets an array of cached key-value pairs from the set.
+ ///
+ ///
+ /// The key-value pairs are cached for performance and are reset when the set is modified.
+ ///
+ public KeyValuePair[] CachedPairs
+ {
+ get
{
- get
- {
- lock (SyncRoot)
- return _cachedPairs ??= [.. this];
- }
+ lock (SyncRoot)
+ return _cachedPairs ??= [.. this];
}
+ }
- ///
- /// Gets or sets the value associated with the specified key.
- ///
- /// The key of the value to get or set.
- /// The value associated with the specified key.
- public override TValue this[TKey key]
+ ///
+ /// Gets or sets the value associated with the specified key.
+ ///
+ /// The key of the value to get or set.
+ /// The value associated with the specified key.
+ public override TValue this[TKey key]
+ {
+ set
{
- set
+ lock (SyncRoot)
{
- lock (SyncRoot)
- {
- var isKey = false;
+ var isKey = false;
- if (_cachedKeys != null && !ContainsKey(key))
- isKey = true;
+ if (_cachedKeys != null && !ContainsKey(key))
+ isKey = true;
- OnResetCache(isKey);
+ OnResetCache(isKey);
- base[key] = value;
- }
+ base[key] = value;
}
}
+ }
- ///
- /// Adds the specified key and value to the set.
- ///
- /// The key of the element to add.
- /// The value of the element to add.
- public override void Add(TKey key, TValue value)
+ ///
+ /// Adds the specified key and value to the set.
+ ///
+ /// The key of the element to add.
+ /// The value of the element to add.
+ public override void Add(TKey key, TValue value)
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
- {
- base.Add(key, value);
+ base.Add(key, value);
- OnResetCache(true);
- }
+ OnResetCache(true);
}
+ }
- ///
- /// Removes the value with the specified key from the set.
- ///
- /// The key of the element to remove.
- /// true if the element is successfully found and removed; otherwise, false.
- public override bool Remove(TKey key)
+ ///
+ /// Removes the value with the specified key from the set.
+ ///
+ /// The key of the element to remove.
+ /// true if the element is successfully found and removed; otherwise, false.
+ public override bool Remove(TKey key)
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
+ if (base.Remove(key))
{
- if (base.Remove(key))
- {
- OnResetCache(true);
-
- return true;
- }
+ OnResetCache(true);
- return false;
+ return true;
}
+
+ return false;
}
+ }
- ///
- /// Removes all keys and values from the set.
- ///
- public override void Clear()
+ ///
+ /// Removes all keys and values from the set.
+ ///
+ public override void Clear()
+ {
+ lock (SyncRoot)
{
- lock (SyncRoot)
- {
- base.Clear();
+ base.Clear();
- OnResetCache(true);
- }
+ OnResetCache(true);
}
+ }
- ///
- /// Resets the cached keys, values, and key-value pairs when the set is modified.
- ///
- /// Indicates whether the cache reset is due to a key modification.
- protected virtual void OnResetCache(bool isKey)
- {
- _cachedKeys = null;
- _cachedValues = null;
- _cachedPairs = null;
- }
+ ///
+ /// Resets the cached keys, values, and key-value pairs when the set is modified.
+ ///
+ /// Indicates whether the cache reset is due to a key modification.
+ protected virtual void OnResetCache(bool isKey)
+ {
+ _cachedKeys = null;
+ _cachedValues = null;
+ _cachedPairs = null;
}
}
\ No newline at end of file
diff --git a/Collections/CachedSynchronizedSet.cs b/Collections/CachedSynchronizedSet.cs
index 76fc14d8..1098a9be 100644
--- a/Collections/CachedSynchronizedSet.cs
+++ b/Collections/CachedSynchronizedSet.cs
@@ -1,103 +1,102 @@
-namespace Ecng.Collections
-{
- using System.Collections.Generic;
+namespace Ecng.Collections;
+
+using System.Collections.Generic;
+///
+/// Represents a thread-safe set with a cached array of its elements for improved performance.
+///
+/// The type of elements in the set.
+public class CachedSynchronizedSet : SynchronizedSet
+{
///
- /// Represents a thread-safe set with a cached array of its elements for improved performance.
+ /// Initializes a new instance of the class.
///
- /// The type of elements in the set.
- public class CachedSynchronizedSet : SynchronizedSet
+ public CachedSynchronizedSet()
{
- ///
- /// Initializes a new instance of the class.
- ///
- public CachedSynchronizedSet()
- {
- }
+ }
- ///
- /// Initializes a new instance of the class with the specified indexing option.
- ///
- /// A value indicating whether indexing is allowed.
- public CachedSynchronizedSet(bool allowIndexing)
- : base(allowIndexing)
- {
- }
+ ///
+ /// Initializes a new instance of the class with the specified indexing option.
+ ///
+ /// A value indicating whether indexing is allowed.
+ public CachedSynchronizedSet(bool allowIndexing)
+ : base(allowIndexing)
+ {
+ }
- ///
- /// Initializes a new instance of the class with the specified collection.
- ///
- /// The collection whose elements are copied to the new set.
- public CachedSynchronizedSet(IEnumerable collection)
- : base(collection)
- {
- }
+ ///
+ /// Initializes a new instance of the class with the specified collection.
+ ///
+ /// The collection whose elements are copied to the new set.
+ public CachedSynchronizedSet(IEnumerable collection)
+ : base(collection)
+ {
+ }
- ///
- /// Initializes a new instance of the class with the specified equality comparer.
- ///
- /// The equality comparer to use when comparing elements.
- public CachedSynchronizedSet(IEqualityComparer comparer)
- : base(comparer)
- {
- }
+ ///
+ /// Initializes a new instance of the class with the specified equality comparer.
+ ///
+ /// The equality comparer to use when comparing elements.
+ public CachedSynchronizedSet(IEqualityComparer comparer)
+ : base(comparer)
+ {
+ }
- ///
- /// Initializes a new instance of the class with the specified collection and equality comparer.
- ///
- /// The collection whose elements are copied to the new set.
- /// The equality comparer to use when comparing elements.
- public CachedSynchronizedSet(IEnumerable collection, IEqualityComparer comparer)
- : base(collection, comparer)
- {
- }
+ ///
+ /// Initializes a new instance of the class with the specified collection and equality comparer.
+ ///
+ /// The collection whose elements are copied to the new set.
+ /// The equality comparer to use when comparing elements.
+ public CachedSynchronizedSet(IEnumerable collection, IEqualityComparer comparer)
+ : base(collection, comparer)
+ {
+ }
- ///
- /// Initializes a new instance of the class with the specified indexing option and equality comparer.
- ///
- /// A value indicating whether indexing is allowed.
- /// The equality comparer to use when comparing elements.
- public CachedSynchronizedSet(bool allowIndexing, IEqualityComparer comparer)
- : base(allowIndexing, comparer)
- {
- }
+ ///
+ /// Initializes a new instance of the class with the specified indexing option and equality comparer.
+ ///
+ /// A value indicating whether indexing is allowed.
+ /// The equality comparer to use when comparing elements.
+ public CachedSynchronizedSet(bool allowIndexing, IEqualityComparer comparer)
+ : base(allowIndexing, comparer)
+ {
+ }
- ///
- /// Initializes a new instance of the class with the specified indexing option, collection, and equality comparer.
- ///
- /// A value indicating whether indexing is allowed.
- /// The collection whose elements are copied to the new set.
- /// The equality comparer to use when comparing elements.
- public CachedSynchronizedSet(bool allowIndexing, IEnumerable collection, IEqualityComparer comparer)
- : base(allowIndexing, collection, comparer)
- {
- }
+ ///
+ /// Initializes a new instance of the class with the specified indexing option, collection, and equality comparer.
+ ///
+ /// A value indicating whether indexing is allowed.
+ /// The collection whose elements are copied to the new set.
+ /// The equality comparer to use when comparing elements.
+ public CachedSynchronizedSet(bool allowIndexing, IEnumerable collection, IEqualityComparer comparer)
+ : base(allowIndexing, collection, comparer)
+ {
+ }
- private T[] _cache;
+ private T[] _cache;
- ///
- /// Gets a cached array of the elements in the set.
- ///
- ///
- /// The array is cached for performance and is reset when the set is modified.
- ///
- public T[] Cache
+ ///
+ /// Gets a cached array of the elements in the set.
+ ///
+ ///
+ /// The array is cached for performance and is reset when the set is modified.
+ ///
+ public T[] Cache
+ {
+ get
{
- get
- {
- lock (SyncRoot)
- return _cache ??= [.. this];
- }
+ lock (SyncRoot)
+ return _cache ??= [.. this];
}
+ }
- ///
- /// Called when the set is modified to reset the cached array.
- ///
- protected override void OnChanged()
- {
- _cache = null;
+ ///
+ /// Called when the set is modified to reset the cached array.
+ ///
+ protected override void OnChanged()
+ {
+ _cache = null;
- base.OnChanged();
- }
+ base.OnChanged();
}
}
\ No newline at end of file
diff --git a/Collections/CircularBuffer.cs b/Collections/CircularBuffer.cs
index fd04e5ac..d68546ad 100644
--- a/Collections/CircularBuffer.cs
+++ b/Collections/CircularBuffer.cs
@@ -1,429 +1,428 @@
+namespace Ecng.Collections;
+
// Source: https://github.com/joaoportela/CircularBuffer-CSharp
using System;
using System.Collections;
using System.Collections.Generic;
-namespace Ecng.Collections
+///
+/// Circular buffer.
+///
+/// When writing to a full buffer:
+/// PushBack -> removes this[0] / Front()
+/// PushFront -> removes this[Size-1] / Back()
+///
+/// this implementation is inspired by
+/// http://www.boost.org/doc/libs/1_53_0/libs/circular_buffer/doc/circular_buffer.html
+/// because I liked their interface.
+///
+public class CircularBuffer : IEnumerable, IList
{
+ private T[] _buffer;
+
+ ///
+ /// The _start. Index of the first element in buffer.
+ ///
+ private int _start;
+
+ ///
+ /// The _end. Index after the last element in the buffer.
+ ///
+ private int _end;
+
+ ///
+ /// The _size. Buffer size.
+ ///
+ private int _count;
+
///
- /// Circular buffer.
+ /// Initializes a new instance of the class.
///
- /// When writing to a full buffer:
- /// PushBack -> removes this[0] / Front()
- /// PushFront -> removes this[Size-1] / Back()
+ ///
+ ///
+ /// Buffer capacity. Must be positive.
+ ///
+ public CircularBuffer(int capacity)
+ : this(capacity, [])
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
///
- /// this implementation is inspired by
- /// http://www.boost.org/doc/libs/1_53_0/libs/circular_buffer/doc/circular_buffer.html
- /// because I liked their interface.
///
- public class CircularBuffer : IEnumerable, IList
+ ///
+ /// Buffer capacity. Must be positive.
+ ///
+ ///
+ /// Items to fill buffer with. Items length must be less than capacity.
+ /// Suggestion: use Skip(x).Take(y).ToArray() to build this argument from
+ /// any enumerable.
+ ///
+ public CircularBuffer(int capacity, T[] items)
{
- private T[] _buffer;
-
- ///
- /// The _start. Index of the first element in buffer.
- ///
- private int _start;
-
- ///
- /// The _end. Index after the last element in the buffer.
- ///
- private int _end;
-
- ///
- /// The _size. Buffer size.
- ///
- private int _count;
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- ///
- /// Buffer capacity. Must be positive.
- ///
- public CircularBuffer(int capacity)
- : this(capacity, [])
+ if (capacity < 1)
{
+ throw new ArgumentException(
+ "Circular buffer cannot have negative or zero capacity.", nameof(capacity));
}
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- ///
- /// Buffer capacity. Must be positive.
- ///
- ///
- /// Items to fill buffer with. Items length must be less than capacity.
- /// Suggestion: use Skip(x).Take(y).ToArray() to build this argument from
- /// any enumerable.
- ///
- public CircularBuffer(int capacity, T[] items)
+ if (items == null)
{
- if (capacity < 1)
- {
- throw new ArgumentException(
- "Circular buffer cannot have negative or zero capacity.", nameof(capacity));
- }
- if (items == null)
- {
- throw new ArgumentNullException(nameof(items));
- }
- if (items.Length > capacity)
- {
- throw new ArgumentException(
- "Too many items to fit circular buffer", nameof(items));
- }
+ throw new ArgumentNullException(nameof(items));
+ }
+ if (items.Length > capacity)
+ {
+ throw new ArgumentException(
+ "Too many items to fit circular buffer", nameof(items));
+ }
- _buffer = new T[capacity];
+ _buffer = new T[capacity];
- Array.Copy(items, _buffer, items.Length);
- _count = items.Length;
+ Array.Copy(items, _buffer, items.Length);
+ _count = items.Length;
- _start = 0;
- _end = _count == capacity ? 0 : _count;
- }
+ _start = 0;
+ _end = _count == capacity ? 0 : _count;
+ }
- ///
- /// Maximum capacity of the buffer. Elements pushed into the buffer after
- /// maximum capacity is reached (IsFull = true), will remove an element.
- ///
- public virtual int Capacity
+ ///
+ /// Maximum capacity of the buffer. Elements pushed into the buffer after
+ /// maximum capacity is reached (IsFull = true), will remove an element.
+ ///
+ public virtual int Capacity
+ {
+ get => _buffer.Length;
+ set
{
- get => _buffer.Length;
- set
- {
- Array.Resize(ref _buffer, value);
- }
+ Array.Resize(ref _buffer, value);
}
+ }
- ///
- /// Boolean indicating if Circular is at full capacity.
- /// Adding more elements when the buffer is full will
- /// cause elements to be removed from the other end
- /// of the buffer.
- ///
- public bool IsFull
+ ///
+ /// Boolean indicating if Circular is at full capacity.
+ /// Adding more elements when the buffer is full will
+ /// cause elements to be removed from the other end
+ /// of the buffer.
+ ///
+ public bool IsFull
+ {
+ get
{
- get
- {
- return Count == Capacity;
- }
+ return Count == Capacity;
}
+ }
- ///
- /// True if has no elements.
- ///
- public bool IsEmpty => Count == 0;
-
- ///
- /// Current buffer size (the number of elements that the buffer has).
- ///
- public int Count => _count;
-
- ///
- /// Element at the front of the buffer - this[0].
- ///
- /// The value of the element of type T at the front of the buffer.
- public T Front()
- {
- ThrowIfEmpty();
- return _buffer[_start];
- }
+ ///
+ /// True if has no elements.
+ ///
+ public bool IsEmpty => Count == 0;
- ///
- /// Element at the back of the buffer - this[Size - 1].
- ///
- /// The value of the element of type T at the back of the buffer.
- public T Back()
- {
- ThrowIfEmpty();
- return _buffer[(_end != 0 ? _end : Capacity) - 1];
- }
+ ///
+ /// Current buffer size (the number of elements that the buffer has).
+ ///
+ public int Count => _count;
+
+ ///
+ /// Element at the front of the buffer - this[0].
+ ///
+ /// The value of the element of type T at the front of the buffer.
+ public T Front()
+ {
+ ThrowIfEmpty();
+ return _buffer[_start];
+ }
- ///
- /// Index access to elements in buffer.
- /// Index does not loop around like when adding elements,
- /// valid interval is [0;Size[
- ///
- /// Index of element to access.
- /// Thrown when index is outside of [; Size[ interval.
- public T this[int index]
+ ///
+ /// Element at the back of the buffer - this[Size - 1].
+ ///
+ /// The value of the element of type T at the back of the buffer.
+ public T Back()
+ {
+ ThrowIfEmpty();
+ return _buffer[(_end != 0 ? _end : Capacity) - 1];
+ }
+
+ ///
+ /// Index access to elements in buffer.
+ /// Index does not loop around like when adding elements,
+ /// valid interval is [0;Size[
+ ///
+ /// Index of element to access.
+ /// Thrown when index is outside of [; Size[ interval.
+ public T this[int index]
+ {
+ get
{
- get
+ if (IsEmpty)
{
- if (IsEmpty)
- {
- throw new IndexOutOfRangeException(string.Format("Cannot access index {0}. Buffer is empty", index));
- }
- if (index >= _count)
- {
- throw new IndexOutOfRangeException(string.Format("Cannot access index {0}. Buffer size is {1}", index, _count));
- }
- int actualIndex = InternalIndex(index);
- return _buffer[actualIndex];
+ throw new IndexOutOfRangeException(string.Format("Cannot access index {0}. Buffer is empty", index));
}
- set
+ if (index >= _count)
{
- if (IsEmpty)
- {
- throw new IndexOutOfRangeException(string.Format("Cannot access index {0}. Buffer is empty", index));
- }
- if (index >= _count)
- {
- throw new IndexOutOfRangeException(string.Format("Cannot access index {0}. Buffer size is {1}", index, _count));
- }
- int actualIndex = InternalIndex(index);
- _buffer[actualIndex] = value;
+ throw new IndexOutOfRangeException(string.Format("Cannot access index {0}. Buffer size is {1}", index, _count));
}
+ int actualIndex = InternalIndex(index);
+ return _buffer[actualIndex];
}
-
- ///
- /// Pushes a new element to the back of the buffer. Back()/this[Size-1]
- /// will now return this element.
- ///
- /// When the buffer is full, the element at Front()/this[0] will be
- /// popped to allow for this new element to fit.
- ///
- /// Item to push to the back of the buffer
- public virtual void PushBack(T item)
+ set
{
- if (IsFull)
+ if (IsEmpty)
{
- _buffer[_end] = item;
- Increment(ref _end);
- _start = _end;
+ throw new IndexOutOfRangeException(string.Format("Cannot access index {0}. Buffer is empty", index));
}
- else
+ if (index >= _count)
{
- _buffer[_end] = item;
- Increment(ref _end);
- ++_count;
+ throw new IndexOutOfRangeException(string.Format("Cannot access index {0}. Buffer size is {1}", index, _count));
}
+ int actualIndex = InternalIndex(index);
+ _buffer[actualIndex] = value;
}
+ }
- ///
- /// Pushes a new element to the front of the buffer. Front()/this[0]
- /// will now return this element.
- ///
- /// When the buffer is full, the element at Back()/this[Size-1] will be
- /// popped to allow for this new element to fit.
- ///
- /// Item to push to the front of the buffer
- public void PushFront(T item)
+ ///
+ /// Pushes a new element to the back of the buffer. Back()/this[Size-1]
+ /// will now return this element.
+ ///
+ /// When the buffer is full, the element at Front()/this[0] will be
+ /// popped to allow for this new element to fit.
+ ///
+ /// Item to push to the back of the buffer
+ public virtual void PushBack(T item)
+ {
+ if (IsFull)
{
- if (IsFull)
- {
- Decrement(ref _start);
- _end = _start;
- _buffer[_start] = item;
- }
- else
- {
- Decrement(ref _start);
- _buffer[_start] = item;
- ++_count;
- }
+ _buffer[_end] = item;
+ Increment(ref _end);
+ _start = _end;
}
-
- ///
- /// Removes the element at the back of the buffer. Decreasing the
- /// Buffer size by 1.
- ///
- public void PopBack()
+ else
{
- ThrowIfEmpty("Cannot take elements from an empty buffer.");
- Decrement(ref _end);
- _buffer[_end] = default;
- --_count;
+ _buffer[_end] = item;
+ Increment(ref _end);
+ ++_count;
}
+ }
- ///
- /// Removes the element at the front of the buffer. Decreasing the
- /// Buffer size by 1.
- ///
- public void PopFront()
+ ///
+ /// Pushes a new element to the front of the buffer. Front()/this[0]
+ /// will now return this element.
+ ///
+ /// When the buffer is full, the element at Back()/this[Size-1] will be
+ /// popped to allow for this new element to fit.
+ ///
+ /// Item to push to the front of the buffer
+ public void PushFront(T item)
+ {
+ if (IsFull)
+ {
+ Decrement(ref _start);
+ _end = _start;
+ _buffer[_start] = item;
+ }
+ else
{
- ThrowIfEmpty("Cannot take elements from an empty buffer.");
- _buffer[_start] = default;
- Increment(ref _start);
- --_count;
+ Decrement(ref _start);
+ _buffer[_start] = item;
+ ++_count;
}
+ }
- ///
- /// Clears the contents of the array. Size = 0, Capacity is unchanged.
- ///
- ///
- public virtual void Clear()
+ ///
+ /// Removes the element at the back of the buffer. Decreasing the
+ /// Buffer size by 1.
+ ///
+ public void PopBack()
+ {
+ ThrowIfEmpty("Cannot take elements from an empty buffer.");
+ Decrement(ref _end);
+ _buffer[_end] = default;
+ --_count;
+ }
+
+ ///
+ /// Removes the element at the front of the buffer. Decreasing the
+ /// Buffer size by 1.
+ ///
+ public void PopFront()
+ {
+ ThrowIfEmpty("Cannot take elements from an empty buffer.");
+ _buffer[_start] = default;
+ Increment(ref _start);
+ --_count;
+ }
+
+ ///
+ /// Clears the contents of the array. Size = 0, Capacity is unchanged.
+ ///
+ ///
+ public virtual void Clear()
+ {
+ // to clear we just reset everything.
+ _start = 0;
+ _end = 0;
+ _count = 0;
+ Array.Clear(_buffer, 0, _buffer.Length);
+ }
+
+ ///
+ /// Copies the buffer contents to an array, according to the logical
+ /// contents of the buffer (i.e. independent of the internal
+ /// order/contents)
+ ///
+ /// A new array with a copy of the buffer contents.
+ public T[] ToArray()
+ {
+ T[] newArray = new T[Count];
+ int newArrayOffset = 0;
+ var segments = ToArraySegments();
+ foreach (var segment in segments)
{
- // to clear we just reset everything.
- _start = 0;
- _end = 0;
- _count = 0;
- Array.Clear(_buffer, 0, _buffer.Length);
+ Array.Copy(segment.Array, segment.Offset, newArray, newArrayOffset, segment.Count);
+ newArrayOffset += segment.Count;
}
+ return newArray;
+ }
- ///
- /// Copies the buffer contents to an array, according to the logical
- /// contents of the buffer (i.e. independent of the internal
- /// order/contents)
- ///
- /// A new array with a copy of the buffer contents.
- public T[] ToArray()
+ ///
+ /// Get the contents of the buffer as 2 ArraySegments.
+ /// Respects the logical contents of the buffer, where
+ /// each segment and items in each segment are ordered
+ /// according to insertion.
+ ///
+ /// Fast: does not copy the array elements.
+ /// Useful for methods like Send(IList<ArraySegment<Byte>>).
+ ///
+ /// Segments may be empty.
+ ///
+ /// An IList with 2 segments corresponding to the buffer content.
+ public IList> ToArraySegments()
+ {
+ return [ArrayOne(), ArrayTwo()];
+ }
+
+ #region IEnumerable implementation
+ ///
+ /// Returns an enumerator that iterates through this buffer.
+ ///
+ /// An enumerator that can be used to iterate this collection.
+ public IEnumerator GetEnumerator()
+ {
+ var segments = ToArraySegments();
+ foreach (var segment in segments)
{
- T[] newArray = new T[Count];
- int newArrayOffset = 0;
- var segments = ToArraySegments();
- foreach (var segment in segments)
+ for (int i = 0; i < segment.Count; i++)
{
- Array.Copy(segment.Array, segment.Offset, newArray, newArrayOffset, segment.Count);
- newArrayOffset += segment.Count;
+ yield return segment.Array[segment.Offset + i];
}
- return newArray;
}
+ }
+ #endregion
+ #region IEnumerable implementation
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ #endregion
- ///
- /// Get the contents of the buffer as 2 ArraySegments.
- /// Respects the logical contents of the buffer, where
- /// each segment and items in each segment are ordered
- /// according to insertion.
- ///
- /// Fast: does not copy the array elements.
- /// Useful for methods like Send(IList<ArraySegment<Byte>>).
- ///
- /// Segments may be empty.
- ///
- /// An IList with 2 segments corresponding to the buffer content.
- public IList> ToArraySegments()
+ private void ThrowIfEmpty(string message = "Cannot access an empty buffer.")
+ {
+ if (IsEmpty)
{
- return [ArrayOne(), ArrayTwo()];
+ throw new InvalidOperationException(message);
}
+ }
- #region IEnumerable implementation
- ///
- /// Returns an enumerator that iterates through this buffer.
- ///
- /// An enumerator that can be used to iterate this collection.
- public IEnumerator GetEnumerator()
+ ///
+ /// Increments the provided index variable by one, wrapping
+ /// around if necessary.
+ ///
+ ///
+ private void Increment(ref int index)
+ {
+ if (++index == Capacity)
{
- var segments = ToArraySegments();
- foreach (var segment in segments)
- {
- for (int i = 0; i < segment.Count; i++)
- {
- yield return segment.Array[segment.Offset + i];
- }
- }
+ index = 0;
}
- #endregion
- #region IEnumerable implementation
- IEnumerator IEnumerable.GetEnumerator()
+ }
+
+ ///
+ /// Decrements the provided index variable by one, wrapping
+ /// around if necessary.
+ ///
+ ///
+ private void Decrement(ref int index)
+ {
+ if (index == 0)
{
- return GetEnumerator();
+ index = Capacity;
}
- #endregion
+ index--;
+ }
- private void ThrowIfEmpty(string message = "Cannot access an empty buffer.")
+ ///
+ /// Converts the index in the argument to an index in _buffer
+ ///
+ ///
+ /// The transformed index.
+ ///
+ ///
+ /// External index.
+ ///
+ private int InternalIndex(int index)
+ {
+ return _start + (index < (Capacity - _start) ? index : index - Capacity);
+ }
+
+ // doing ArrayOne and ArrayTwo methods returning ArraySegment as seen here:
+ // http://www.boost.org/doc/libs/1_37_0/libs/circular_buffer/doc/circular_buffer.html#classboost_1_1circular__buffer_1957cccdcb0c4ef7d80a34a990065818d
+ // http://www.boost.org/doc/libs/1_37_0/libs/circular_buffer/doc/circular_buffer.html#classboost_1_1circular__buffer_1f5081a54afbc2dfc1a7fb20329df7d5b
+ // should help a lot with the code.
+
+ #region Array items easy access.
+ // The array is composed by at most two non-contiguous segments,
+ // the next two methods allow easy access to those.
+
+ private ArraySegment ArrayOne()
+ {
+ if (IsEmpty)
{
- if (IsEmpty)
- {
- throw new InvalidOperationException(message);
- }
+ return new([]);
}
-
- ///
- /// Increments the provided index variable by one, wrapping
- /// around if necessary.
- ///
- ///
- private void Increment(ref int index)
+ else if (_start < _end)
{
- if (++index == Capacity)
- {
- index = 0;
- }
+ return new(_buffer, _start, _end - _start);
}
-
- ///
- /// Decrements the provided index variable by one, wrapping
- /// around if necessary.
- ///
- ///
- private void Decrement(ref int index)
+ else
{
- if (index == 0)
- {
- index = Capacity;
- }
- index--;
+ return new(_buffer, _start, _buffer.Length - _start);
}
+ }
- ///
- /// Converts the index in the argument to an index in _buffer
- ///
- ///
- /// The transformed index.
- ///
- ///
- /// External index.
- ///
- private int InternalIndex(int index)
+ private ArraySegment ArrayTwo()
+ {
+ if (IsEmpty)
{
- return _start + (index < (Capacity - _start) ? index : index - Capacity);
+ return new([]);
}
-
- // doing ArrayOne and ArrayTwo methods returning ArraySegment as seen here:
- // http://www.boost.org/doc/libs/1_37_0/libs/circular_buffer/doc/circular_buffer.html#classboost_1_1circular__buffer_1957cccdcb0c4ef7d80a34a990065818d
- // http://www.boost.org/doc/libs/1_37_0/libs/circular_buffer/doc/circular_buffer.html#classboost_1_1circular__buffer_1f5081a54afbc2dfc1a7fb20329df7d5b
- // should help a lot with the code.
-
- #region Array items easy access.
- // The array is composed by at most two non-contiguous segments,
- // the next two methods allow easy access to those.
-
- private ArraySegment ArrayOne()
+ else if (_start < _end)
{
- if (IsEmpty)
- {
- return new([]);
- }
- else if (_start < _end)
- {
- return new(_buffer, _start, _end - _start);
- }
- else
- {
- return new(_buffer, _start, _buffer.Length - _start);
- }
+ return new(_buffer, _end, 0);
}
-
- private ArraySegment ArrayTwo()
+ else
{
- if (IsEmpty)
- {
- return new([]);
- }
- else if (_start < _end)
- {
- return new(_buffer, _end, 0);
- }
- else
- {
- return new(_buffer, 0, _end);
- }
+ return new(_buffer, 0, _end);
}
+ }
- #endregion
+ #endregion
- int IList.IndexOf(T item) => throw new NotSupportedException();
- void IList.Insert(int index, T item) => throw new NotSupportedException();
- void IList.RemoveAt(int index) => throw new NotSupportedException();
- bool ICollection.IsReadOnly => false;
- void ICollection.Add(T item) => PushBack(item);
- bool ICollection.Contains(T item) => throw new NotSupportedException();
- void ICollection.CopyTo(T[] array, int arrayIndex) => throw new NotSupportedException();
- bool ICollection.Remove(T item) => throw new NotSupportedException();
- }
+ int IList.IndexOf(T item) => throw new NotSupportedException();
+ void IList.Insert(int index, T item) => throw new NotSupportedException();
+ void IList.RemoveAt(int index) => throw new NotSupportedException();
+ bool ICollection.IsReadOnly => false;
+ void ICollection.Add(T item) => PushBack(item);
+ bool ICollection.Contains(T item) => throw new NotSupportedException();
+ void ICollection.CopyTo(T[] array, int arrayIndex) => throw new NotSupportedException();
+ bool ICollection.Remove(T item) => throw new NotSupportedException();
}
\ No newline at end of file
diff --git a/Collections/CollectionHelper.cs b/Collections/CollectionHelper.cs
index 4578f1ae..484a3c12 100644
--- a/Collections/CollectionHelper.cs
+++ b/Collections/CollectionHelper.cs
@@ -1,2330 +1,2329 @@
-namespace Ecng.Collections
-{
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading;
- using System.Threading.Tasks;
+namespace Ecng.Collections;
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
- using Nito.AsyncEx;
+using Nito.AsyncEx;
- using Ecng.Common;
+using Ecng.Common;
+///
+/// Provides extension methods and helper utilities for working with collections.
+///
+public static class CollectionHelper
+{
///
- /// Provides extension methods and helper utilities for working with collections.
+ /// A private implementation of using a custom equality comparison function.
///
- public static class CollectionHelper
+ /// The type of objects to compare.
+ private sealed class EqualityComparer(Func comparer) : IEqualityComparer
{
+ private readonly Func _comparer = comparer ?? throw new ArgumentNullException(nameof(comparer));
+
///
- /// A private implementation of using a custom equality comparison function.
+ /// Determines whether two objects are equal using the provided comparison function.
///
- /// The type of objects to compare.
- private sealed class EqualityComparer(Func comparer) : IEqualityComparer
- {
- private readonly Func _comparer = comparer ?? throw new ArgumentNullException(nameof(comparer));
-
- ///
- /// Determines whether two objects are equal using the provided comparison function.
- ///
- public bool Equals(T x, T y) => _comparer(x, y);
-
- ///
- /// Returns a hash code for the specified object.
- ///
- public int GetHashCode(T obj) => obj.GetHashCode();
- }
+ public bool Equals(T x, T y) => _comparer(x, y);
///
- /// A private implementation of using a custom comparison function.
+ /// Returns a hash code for the specified object.
///
- /// The type of objects to compare.
- private sealed class Comparer(Func comparer) : IComparer
- {
- private readonly Func _comparer = comparer ?? throw new ArgumentNullException(nameof(comparer));
+ public int GetHashCode(T obj) => obj.GetHashCode();
+ }
- ///
- /// Compares two objects and returns a value indicating their relative order.
- ///
- public int Compare(T x, T y) => _comparer(x, y);
- }
+ ///
+ /// A private implementation of using a custom comparison function.
+ ///
+ /// The type of objects to compare.
+ private sealed class Comparer(Func comparer) : IComparer
+ {
+ private readonly Func _comparer = comparer ?? throw new ArgumentNullException(nameof(comparer));
///
- /// Converts a function to an instance.
+ /// Compares two objects and returns a value indicating their relative order.
///
- /// The type of objects to compare.
- /// The function to determine equality between two objects.
- /// An instance.
- public static IEqualityComparer ToComparer(this Func comparer)
+ public int Compare(T x, T y) => _comparer(x, y);
+ }
+
+ ///
+ /// Converts a function to an instance.
+ ///
+ /// The type of objects to compare.
+ /// The function to determine equality between two objects.
+ /// An instance.
+ public static IEqualityComparer ToComparer(this Func comparer)
+ {
+ return new EqualityComparer(comparer);
+ }
+
+ ///
+ /// Converts a function to an instance.
+ ///
+ /// The type of objects to compare.
+ /// The function to compare two objects.
+ /// An instance.
+ public static IComparer ToComparer(this Func comparer)
+ {
+ return new Comparer(comparer);
+ }
+
+ ///
+ /// Converts a delegate to an instance.
+ ///
+ /// The type of objects to compare.
+ /// The comparison delegate.
+ /// An instance.
+ public static IComparer ToComparer(this Comparison comparer)
+ {
+ return comparer.ToFunc().ToComparer();
+ }
+
+ ///
+ /// Converts a delegate to a function.
+ ///
+ /// The type of objects to compare.
+ /// The comparison delegate.
+ /// A function that compares two objects.
+ public static Func ToFunc(this Comparison comparer)
+ {
+ return (t1, t2) => comparer(t1, t2);
+ }
+
+ ///
+ /// Determines whether two sequences are equal using a custom equality comparer function.
+ ///
+ /// The type of elements in the sequences.
+ /// The first sequence to compare.
+ /// The second sequence to compare.
+ /// The function to determine equality between elements.
+ /// True if the sequences are equal; otherwise, false.
+ public static bool SequenceEqual(this IEnumerable first, IEnumerable second, Func comparer)
+ {
+ return first.SequenceEqual(second, comparer.ToComparer());
+ }
+
+ ///
+ /// Sorts a collection using a delegate.
+ ///
+ /// The type of elements in the collection.
+ /// The collection to sort.
+ /// The comparison delegate to determine order.
+ /// An ordered enumerable of the collection.
+ public static IOrderedEnumerable OrderBy(this IEnumerable collection, Comparison