mirror of
https://github.com/Stone-Red-Code/RemSox.git
synced 2026-09-09 15:56:32 +02:00
Code cleanup
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
global using Sys = Cosmos.Kernel.System;
|
global using Sys = Cosmos.Kernel.System;
|
||||||
|
|
||||||
using Cosmos.Kernel.Core;
|
|
||||||
using RemSox.Logging;
|
|
||||||
using RemSox.Processes;
|
using RemSox.Processes;
|
||||||
using RemSox.Processing;
|
using RemSox.Processing;
|
||||||
using RemSox.Processing.IPC;
|
using RemSox.Processing.IPC;
|
||||||
@@ -37,7 +35,7 @@ public class Kernel : Sys.Kernel
|
|||||||
Sys.Mouse.MouseManager.Initialize();
|
Sys.Mouse.MouseManager.Initialize();
|
||||||
Sys.Keyboard.KeyboardManager.Initialize();
|
Sys.Keyboard.KeyboardManager.Initialize();
|
||||||
|
|
||||||
ProcessManager.SpawnProcess<CliProcess>();
|
_ = ProcessManager.SpawnProcess<CliProcess>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Run()
|
protected override void Run()
|
||||||
@@ -47,7 +45,7 @@ public class Kernel : Sys.Kernel
|
|||||||
|
|
||||||
if (!desktopRunning && !cliRunning)
|
if (!desktopRunning && !cliRunning)
|
||||||
{
|
{
|
||||||
ProcessManager.SpawnProcess<CliProcess>();
|
_ = ProcessManager.SpawnProcess<CliProcess>();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-13
@@ -1,20 +1,14 @@
|
|||||||
using System;
|
namespace RemSox.Logging;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace RemSox.Logging
|
public interface ILogger
|
||||||
{
|
{
|
||||||
public interface ILogger
|
void Log(string message, LogSeverity severity);
|
||||||
{
|
|
||||||
void Log(string message, LogSeverity severity);
|
|
||||||
|
|
||||||
void LogInfo(string message);
|
void LogInfo(string message);
|
||||||
|
|
||||||
void LogError(string message);
|
void LogError(string message);
|
||||||
|
|
||||||
void LogWarning(string message);
|
void LogWarning(string message);
|
||||||
|
|
||||||
IEnumerable<LogEntry> GetLogs(int? count = null);
|
IEnumerable<LogEntry> GetLogs(int? count = null);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+24
-29
@@ -1,39 +1,34 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
namespace RemSox.Logging
|
namespace RemSox.Logging;
|
||||||
|
|
||||||
|
public class InMemoryLogger : ILogger
|
||||||
{
|
{
|
||||||
public class InMemoryLogger : ILogger
|
private readonly ConcurrentBag<LogEntry> logs = [];
|
||||||
|
|
||||||
|
public void Log(string message, LogSeverity severity)
|
||||||
{
|
{
|
||||||
readonly ConcurrentBag<LogEntry> logs = [];
|
logs.Add(new LogEntry(message, severity, DateTimeOffset.UtcNow));
|
||||||
|
}
|
||||||
|
|
||||||
public void Log(string message, LogSeverity severity)
|
public void LogError(string message)
|
||||||
{
|
{
|
||||||
logs.Add(new LogEntry(message, severity, DateTimeOffset.UtcNow));
|
Log(message, LogSeverity.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LogError(string message)
|
public void LogInfo(string message)
|
||||||
{
|
{
|
||||||
Log(message, LogSeverity.Error);
|
Log(message, LogSeverity.Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LogInfo(string message)
|
public void LogWarning(string message)
|
||||||
{
|
{
|
||||||
Log(message, LogSeverity.Info);
|
Log(message, LogSeverity.Warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LogWarning(string message)
|
public IEnumerable<LogEntry> GetLogs(int? count = null)
|
||||||
{
|
{
|
||||||
Log(message, LogSeverity.Warning);
|
IEnumerable<LogEntry> orderedLogs = logs.OrderBy(l => l.Timestamp);
|
||||||
}
|
return count.HasValue ? orderedLogs.TakeLast(count.Value) : orderedLogs;
|
||||||
|
|
||||||
public IEnumerable<LogEntry> GetLogs(int? count = null)
|
|
||||||
{
|
|
||||||
IEnumerable<LogEntry> orderedLogs = logs.OrderBy(l => l.Timestamp);
|
|
||||||
return count.HasValue ? orderedLogs.TakeLast(count.Value) : orderedLogs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-8
@@ -1,9 +1,3 @@
|
|||||||
using System;
|
namespace RemSox.Logging;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace RemSox.Logging
|
public record LogEntry(string Message, LogSeverity Severity, DateTimeOffset Timestamp);
|
||||||
{
|
|
||||||
public record LogEntry(string Message, LogSeverity Severity, DateTimeOffset Timestamp);
|
|
||||||
}
|
|
||||||
+5
-11
@@ -1,14 +1,8 @@
|
|||||||
using System;
|
namespace RemSox.Logging;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace RemSox.Logging
|
public enum LogSeverity
|
||||||
{
|
{
|
||||||
public enum LogSeverity
|
Info,
|
||||||
{
|
Warning,
|
||||||
Info,
|
Error
|
||||||
Warning,
|
|
||||||
Error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+25
-31
@@ -1,38 +1,32 @@
|
|||||||
using System;
|
namespace RemSox.Logging;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace RemSox.Logging
|
public class ProxyLogger(IEnumerable<ILogger> loggers) : ILogger
|
||||||
{
|
{
|
||||||
public class ProxyLogger(IEnumerable<ILogger> loggers) : ILogger
|
public void Log(string message, LogSeverity severity)
|
||||||
{
|
{
|
||||||
public void Log(string message, LogSeverity severity)
|
foreach (ILogger logger in loggers)
|
||||||
{
|
{
|
||||||
foreach (var logger in loggers)
|
logger.Log(message, severity);
|
||||||
{
|
|
||||||
logger.Log(message, severity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LogError(string message)
|
|
||||||
{
|
|
||||||
Log(message, LogSeverity.Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LogInfo(string message)
|
|
||||||
{
|
|
||||||
Log(message, LogSeverity.Info);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LogWarning(string message)
|
|
||||||
{
|
|
||||||
Log(message, LogSeverity.Warning);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<LogEntry> GetLogs(int? count = null)
|
|
||||||
{
|
|
||||||
return loggers.SelectMany(logger => logger.GetLogs(count / loggers.Count())).OrderBy(entry => entry.Timestamp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void LogError(string message)
|
||||||
|
{
|
||||||
|
Log(message, LogSeverity.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogInfo(string message)
|
||||||
|
{
|
||||||
|
Log(message, LogSeverity.Info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LogWarning(string message)
|
||||||
|
{
|
||||||
|
Log(message, LogSeverity.Warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<LogEntry> GetLogs(int? count = null)
|
||||||
|
{
|
||||||
|
return loggers.SelectMany(logger => logger.GetLogs(count / loggers.Count())).OrderBy(entry => entry.Timestamp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,7 @@ public static class ProcessManager
|
|||||||
InMemoryLogger processLogger = new();
|
InMemoryLogger processLogger = new();
|
||||||
ProxyLogger proxyLogger = new([logger, processLogger]);
|
ProxyLogger proxyLogger = new([logger, processLogger]);
|
||||||
|
|
||||||
processLoggers.TryAdd(id, processLogger);
|
_ = processLoggers.TryAdd(id, processLogger);
|
||||||
|
|
||||||
T process = new()
|
T process = new()
|
||||||
{
|
{
|
||||||
@@ -41,7 +41,7 @@ public static class ProcessManager
|
|||||||
Logger = proxyLogger
|
Logger = proxyLogger
|
||||||
};
|
};
|
||||||
|
|
||||||
processesByType.AddOrUpdate(typeof(T), _ => [id], (_, set) =>
|
_ = processesByType.AddOrUpdate(typeof(T), _ => [id], (_, set) =>
|
||||||
{
|
{
|
||||||
set.Add(id);
|
set.Add(id);
|
||||||
return set;
|
return set;
|
||||||
@@ -59,24 +59,26 @@ public static class ProcessManager
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
processes.TryRemove(id, out _);
|
_ = processes.TryRemove(id, out _);
|
||||||
|
|
||||||
if (processesByType.TryGetValue(typeof(T), out var set))
|
if (processesByType.TryGetValue(typeof(T), out ConcurrentHashSet<int>? set))
|
||||||
{
|
{
|
||||||
set.TryRemove(id);
|
_ = set.TryRemove(id);
|
||||||
if (set.Count == 0)
|
if (set.Count == 0)
|
||||||
processesByType.TryRemove(typeof(T), out _);
|
{
|
||||||
|
_ = processesByType.TryRemove(typeof(T), out _);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowManager.CloseWindowsForProcess(id);
|
WindowManager.CloseWindowsForProcess(id);
|
||||||
|
|
||||||
logger.Log($"Process {process.Name} (ID: {process.Id}) has stopped.", LogSeverity.Info);
|
logger.Log($"Process {process.Name} (ID: {process.Id}) has stopped.", LogSeverity.Info);
|
||||||
|
|
||||||
processLoggers.TryRemove(id, out _);
|
_ = processLoggers.TryRemove(id, out _);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
processes.TryAdd(id, (process, thread));
|
_ = processes.TryAdd(id, (process, thread));
|
||||||
thread.Start();
|
thread.Start();
|
||||||
|
|
||||||
logger.Log($"Spawned process {process.Name} of type {typeof(T).Name} with ID {id}.", LogSeverity.Info);
|
logger.Log($"Spawned process {process.Name} of type {typeof(T).Name} with ID {id}.", LogSeverity.Info);
|
||||||
@@ -106,7 +108,7 @@ public static class ProcessManager
|
|||||||
entry.Process.RequestStop();
|
entry.Process.RequestStop();
|
||||||
|
|
||||||
logger.Log($"Waiting for process {entry.Process.Name} (ID: {entry.Process.Id}) to stop.", LogSeverity.Info);
|
logger.Log($"Waiting for process {entry.Process.Name} (ID: {entry.Process.Id}) to stop.", LogSeverity.Info);
|
||||||
await Task.Run(() => entry.Thread.Join());
|
await Task.Run(entry.Thread.Join);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void StopAllProcesses()
|
public static void StopAllProcesses()
|
||||||
@@ -131,12 +133,12 @@ public static class ProcessManager
|
|||||||
|
|
||||||
public static bool IsProcessRunning<T>() where T : Process
|
public static bool IsProcessRunning<T>() where T : Process
|
||||||
{
|
{
|
||||||
return processesByType.TryGetValue(typeof(T), out var set) && set.Count > 0;
|
return processesByType.TryGetValue(typeof(T), out ConcurrentHashSet<int>? set) && set.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<T> GetProcessesOfType<T>() where T : Process
|
public static IEnumerable<T> GetProcessesOfType<T>() where T : Process
|
||||||
{
|
{
|
||||||
if (processesByType.TryGetValue(typeof(T), out var set))
|
if (processesByType.TryGetValue(typeof(T), out ConcurrentHashSet<int>? set))
|
||||||
{
|
{
|
||||||
foreach (int processId in set)
|
foreach (int processId in set)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,36 +1,30 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using RemSox.Processes;
|
using RemSox.Processes;
|
||||||
using RemSox.Processing;
|
|
||||||
|
|
||||||
namespace RemSox.Processing
|
namespace RemSox.Processing;
|
||||||
|
|
||||||
|
public static class ProcessManifest
|
||||||
{
|
{
|
||||||
public static class ProcessManifest
|
[Flags]
|
||||||
|
public enum ProcessManifestFlags
|
||||||
{
|
{
|
||||||
[Flags]
|
None = 0,
|
||||||
public enum ProcessManifestFlags
|
Singleton = 1 << 0,
|
||||||
{
|
System = 1 << 1
|
||||||
None = 0,
|
}
|
||||||
Singleton = 1 << 0,
|
|
||||||
System = 1 << 1
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly Dictionary<Type, ProcessManifestFlags> map = new()
|
private static readonly Dictionary<Type, ProcessManifestFlags> map = new()
|
||||||
{
|
{
|
||||||
{ typeof(DesktopProcess), ProcessManifestFlags.Singleton | ProcessManifestFlags.System },
|
{ typeof(DesktopProcess), ProcessManifestFlags.Singleton | ProcessManifestFlags.System },
|
||||||
{ typeof(CliProcess), ProcessManifestFlags.Singleton | ProcessManifestFlags.System }
|
{ typeof(CliProcess), ProcessManifestFlags.Singleton | ProcessManifestFlags.System }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static bool HasFlag<T>(ProcessManifestFlags flag) where T : Process
|
public static bool HasFlag<T>(ProcessManifestFlags flag) where T : Process
|
||||||
{
|
{
|
||||||
return map.TryGetValue(typeof(T), out var flags) && flags.HasFlag(flag);
|
return map.TryGetValue(typeof(T), out ProcessManifestFlags flags) && flags.HasFlag(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool HasFlag(Type t, ProcessManifestFlags flag)
|
public static bool HasFlag(Type t, ProcessManifestFlags flag)
|
||||||
{
|
{
|
||||||
return map.TryGetValue(t, out var flags) && flags.HasFlag(flag);
|
return map.TryGetValue(t, out ProcessManifestFlags flags) && flags.HasFlag(flag);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
using Cosmos.Kernel.System.Graphics;
|
|
||||||
using Org.BouncyCastle.Bcpg;
|
|
||||||
using RemSox.Processes;
|
using RemSox.Processes;
|
||||||
using RemSox.Processing;
|
using RemSox.Processing;
|
||||||
using RemSox.UI.GUI.Windows;
|
|
||||||
|
|
||||||
namespace RemSox.UI.CLI.Commands;
|
namespace RemSox.UI.CLI.Commands;
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +1,39 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using RemSox.Logging;
|
using RemSox.Logging;
|
||||||
using RemSox.Processing;
|
using RemSox.Processing;
|
||||||
|
|
||||||
namespace RemSox.UI.CLI.Commands
|
namespace RemSox.UI.CLI.Commands;
|
||||||
|
|
||||||
|
public class ViewProcessLogs : ICommand
|
||||||
{
|
{
|
||||||
public class ViewProcessLogs : ICommand
|
public string Name => "logs";
|
||||||
|
|
||||||
|
public string Description => "View logs for a process";
|
||||||
|
|
||||||
|
public void Execute(string? arguments, Action<string> printLine)
|
||||||
{
|
{
|
||||||
public string Name => "logs";
|
if (int.TryParse(arguments, out int processId))
|
||||||
|
|
||||||
public string Description => "View logs for a process";
|
|
||||||
|
|
||||||
public void Execute(string? arguments, Action<string> printLine)
|
|
||||||
{
|
{
|
||||||
if (int.TryParse(arguments, out int processId))
|
IEnumerable<LogEntry> logs = ProcessManager.GetProcessLogs(processId);
|
||||||
{
|
PrintLogs(logs, printLine);
|
||||||
IEnumerable<LogEntry> logs = ProcessManager.GetProcessLogs(processId);
|
}
|
||||||
PrintLogs(logs, printLine);
|
else
|
||||||
}
|
{
|
||||||
else
|
IEnumerable<LogEntry> logs = ProcessManager.GetLogs();
|
||||||
{
|
PrintLogs(logs, printLine);
|
||||||
IEnumerable<LogEntry> logs = ProcessManager.GetLogs();
|
}
|
||||||
PrintLogs(logs, printLine);
|
}
|
||||||
}
|
|
||||||
|
private static void PrintLogs(IEnumerable<LogEntry> logs, Action<string> printLine)
|
||||||
|
{
|
||||||
|
if (!logs.Any())
|
||||||
|
{
|
||||||
|
printLine("No logs found!");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PrintLogs(IEnumerable<LogEntry> logs, Action<string> printLine)
|
foreach (LogEntry log in logs)
|
||||||
{
|
{
|
||||||
if (!logs.Any())
|
printLine($"[{log.Timestamp:HH:mm:ss}] [{log.Severity}] {log.Message}");
|
||||||
{
|
|
||||||
printLine("No logs found!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (LogEntry log in logs)
|
|
||||||
{
|
|
||||||
printLine($"[{log.Timestamp:HH:mm:ss}] [{log.Severity}] {log.Message}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+58
-17
@@ -1,8 +1,5 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a thread-safe hash set, backed by a <see cref="ConcurrentDictionary{TKey, TValue}"/>.
|
/// Represents a thread-safe hash set, backed by a <see cref="ConcurrentDictionary{TKey, TValue}"/>.
|
||||||
@@ -92,17 +89,27 @@ public partial class ConcurrentHashSet<T> :
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
/// <summary>Removes all elements from the set.</summary>
|
/// <summary>Removes all elements from the set.</summary>
|
||||||
public void Clear() => _dictionary.Clear();
|
public void Clear()
|
||||||
|
{
|
||||||
|
_dictionary.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Determines whether the set contains the specified element.</summary>
|
/// <summary>Determines whether the set contains the specified element.</summary>
|
||||||
public bool Contains(T item)
|
public bool Contains(T item)
|
||||||
{
|
{
|
||||||
if (item is null) throw new ArgumentNullException(nameof(item));
|
if (item is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(item));
|
||||||
|
}
|
||||||
|
|
||||||
return _dictionary.ContainsKey(item);
|
return _dictionary.ContainsKey(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Returns an enumerator that iterates through the elements of the set.</summary>
|
/// <summary>Returns an enumerator that iterates through the elements of the set.</summary>
|
||||||
public IEnumerator<T> GetEnumerator() => _dictionary.Keys.GetEnumerator();
|
public IEnumerator<T> GetEnumerator()
|
||||||
|
{
|
||||||
|
return _dictionary.Keys.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the element from the set if it already exists, or adds and returns
|
/// Returns the element from the set if it already exists, or adds and returns
|
||||||
@@ -112,10 +119,13 @@ public partial class ConcurrentHashSet<T> :
|
|||||||
/// <returns>The existing element if found; otherwise <paramref name="item"/> after it was added.</returns>
|
/// <returns>The existing element if found; otherwise <paramref name="item"/> after it was added.</returns>
|
||||||
public T GetOrAdd(T item)
|
public T GetOrAdd(T item)
|
||||||
{
|
{
|
||||||
if (item is null) throw new ArgumentNullException(nameof(item));
|
if (item is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(item));
|
||||||
|
}
|
||||||
|
|
||||||
// TryAdd is atomic; if it fails the item was already present.
|
// TryAdd is atomic; if it fails the item was already present.
|
||||||
_dictionary.TryAdd(item, DummyValue);
|
_ = _dictionary.TryAdd(item, DummyValue);
|
||||||
|
|
||||||
// Because ConcurrentDictionary keys are de-duplicated by the comparer,
|
// Because ConcurrentDictionary keys are de-duplicated by the comparer,
|
||||||
// we need to retrieve the canonical key that is actually stored.
|
// we need to retrieve the canonical key that is actually stored.
|
||||||
@@ -123,7 +133,9 @@ public partial class ConcurrentHashSet<T> :
|
|||||||
foreach (T key in _dictionary.Keys)
|
foreach (T key in _dictionary.Keys)
|
||||||
{
|
{
|
||||||
if (_dictionary.Comparer.Equals(key, item))
|
if (_dictionary.Comparer.Equals(key, item))
|
||||||
|
{
|
||||||
return key;
|
return key;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback — should not happen in practice.
|
// Fallback — should not happen in practice.
|
||||||
@@ -134,13 +146,20 @@ public partial class ConcurrentHashSet<T> :
|
|||||||
/// Adds the specified element to the set. Duplicate elements are silently ignored.
|
/// Adds the specified element to the set. Duplicate elements are silently ignored.
|
||||||
/// This overload exists to support collection initializer syntax (<c>new ConcurrentHashSet<T> { item }</c>).
|
/// This overload exists to support collection initializer syntax (<c>new ConcurrentHashSet<T> { item }</c>).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Add(T item) => TryAdd(item);
|
public void Add(T item)
|
||||||
|
{
|
||||||
|
_ = TryAdd(item);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Attempts to add the specified element to the set.</summary>
|
/// <summary>Attempts to add the specified element to the set.</summary>
|
||||||
/// <returns><see langword="true"/> if the element was added; <see langword="false"/> if it was already present.</returns>
|
/// <returns><see langword="true"/> if the element was added; <see langword="false"/> if it was already present.</returns>
|
||||||
public bool TryAdd(T item)
|
public bool TryAdd(T item)
|
||||||
{
|
{
|
||||||
if (item is null) throw new ArgumentNullException(nameof(item));
|
if (item is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(item));
|
||||||
|
}
|
||||||
|
|
||||||
return _dictionary.TryAdd(item, DummyValue);
|
return _dictionary.TryAdd(item, DummyValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,15 +167,25 @@ public partial class ConcurrentHashSet<T> :
|
|||||||
/// <returns><see langword="true"/> if the element was removed; <see langword="false"/> if it was not found.</returns>
|
/// <returns><see langword="true"/> if the element was removed; <see langword="false"/> if it was not found.</returns>
|
||||||
public bool TryRemove(T item)
|
public bool TryRemove(T item)
|
||||||
{
|
{
|
||||||
if (item is null) throw new ArgumentNullException(nameof(item));
|
if (item is null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(item));
|
||||||
|
}
|
||||||
|
|
||||||
return _dictionary.TryRemove(item, out _);
|
return _dictionary.TryRemove(item, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Copies the elements of the set to a new array.</summary>
|
/// <summary>Copies the elements of the set to a new array.</summary>
|
||||||
public T[] ToArray() => [.. _dictionary.Keys];
|
public T[] ToArray()
|
||||||
|
{
|
||||||
|
return [.. _dictionary.Keys];
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Returns a (non-thread-safe) <see cref="HashSet{T}"/> snapshot of the current elements.</summary>
|
/// <summary>Returns a (non-thread-safe) <see cref="HashSet{T}"/> snapshot of the current elements.</summary>
|
||||||
public HashSet<T> ToHashSet() => new(_dictionary.Keys, _dictionary.Comparer);
|
public HashSet<T> ToHashSet()
|
||||||
|
{
|
||||||
|
return new(_dictionary.Keys, _dictionary.Comparer);
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// ICollection<T> explicit implementation
|
// ICollection<T> explicit implementation
|
||||||
@@ -164,9 +193,15 @@ public partial class ConcurrentHashSet<T> :
|
|||||||
|
|
||||||
bool ICollection<T>.IsReadOnly => false;
|
bool ICollection<T>.IsReadOnly => false;
|
||||||
|
|
||||||
void ICollection<T>.Add(T item) => Add(item);
|
void ICollection<T>.Add(T item)
|
||||||
|
{
|
||||||
|
Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
bool ICollection<T>.Contains(T item) => Contains(item);
|
bool ICollection<T>.Contains(T item)
|
||||||
|
{
|
||||||
|
return Contains(item);
|
||||||
|
}
|
||||||
|
|
||||||
void ICollection<T>.CopyTo(T[] array, int index)
|
void ICollection<T>.CopyTo(T[] array, int index)
|
||||||
{
|
{
|
||||||
@@ -176,7 +211,10 @@ public partial class ConcurrentHashSet<T> :
|
|||||||
Array.Copy(snapshot, 0, array, index, snapshot.Length);
|
Array.Copy(snapshot, 0, array, index, snapshot.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ICollection<T>.Remove(T item) => TryRemove(item);
|
bool ICollection<T>.Remove(T item)
|
||||||
|
{
|
||||||
|
return TryRemove(item);
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// ICollection (non-generic) explicit implementation
|
// ICollection (non-generic) explicit implementation
|
||||||
@@ -210,5 +248,8 @@ public partial class ConcurrentHashSet<T> :
|
|||||||
// IEnumerable explicit implementation
|
// IEnumerable explicit implementation
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user