mirror of
https://github.com/vale981/VoiDPlugins
synced 2025-03-05 09:11:38 -05:00
Improve SharedStore implementation
This commit is contained in:
parent
a74c74f95d
commit
bbc7c721da
12 changed files with 173 additions and 120 deletions
|
@ -1,3 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using OpenTabletDriver.Plugin.Platform.Display;
|
||||
using OpenTabletDriver.Plugin.Platform.Pointer;
|
||||
|
@ -5,6 +6,7 @@ using OpenTabletDriver.Plugin.Tablet;
|
|||
using VoiDPlugins.Library.VMulti;
|
||||
using VoiDPlugins.Library.VMulti.Device;
|
||||
using VoiDPlugins.Library.VoiD;
|
||||
using static VoiDPlugins.OutputMode.VMultiModeConstants;
|
||||
|
||||
namespace VoiDPlugins.OutputMode
|
||||
{
|
||||
|
@ -13,20 +15,27 @@ namespace VoiDPlugins.OutputMode
|
|||
private readonly AbsoluteInputReport* _rawPointer;
|
||||
private readonly VMultiInstance<AbsoluteInputReport>? _instance;
|
||||
private Vector2 _conversionFactor;
|
||||
private Vector2 _prev;
|
||||
private bool _dirty;
|
||||
|
||||
public VMultiAbsolutePointer(TabletReference tabletReference, IVirtualScreen virtualScreen)
|
||||
{
|
||||
_instance = GlobalStore<VMultiInstance>.Set(tabletReference, () => new VMultiInstance<AbsoluteInputReport>("VMultiAbs", new AbsoluteInputReport()));
|
||||
_instance = new VMultiInstance<AbsoluteInputReport>("VMultiAbs", new AbsoluteInputReport());
|
||||
SharedStore.GetStore(tabletReference, STORE_KEY).Add(INSTANCE, _instance);
|
||||
_rawPointer = _instance.Pointer;
|
||||
_conversionFactor = new Vector2(32767, 32767) / new Vector2(virtualScreen.Width, virtualScreen.Height);
|
||||
}
|
||||
|
||||
public void SetPosition(Vector2 pos)
|
||||
{
|
||||
if (pos == _prev)
|
||||
return;
|
||||
|
||||
pos *= _conversionFactor;
|
||||
_rawPointer->X = (ushort)pos.X;
|
||||
_rawPointer->Y = (ushort)pos.Y;
|
||||
_dirty = true;
|
||||
_prev = pos;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
|
|
|
@ -4,6 +4,7 @@ using OpenTabletDriver.Plugin.Tablet;
|
|||
using VoiDPlugins.Library.VMulti;
|
||||
using VoiDPlugins.Library.VMulti.Device;
|
||||
using VoiDPlugins.Library.VoiD;
|
||||
using static VoiDPlugins.OutputMode.VMultiModeConstants;
|
||||
|
||||
namespace VoiDPlugins.OutputMode
|
||||
{
|
||||
|
@ -12,21 +13,27 @@ namespace VoiDPlugins.OutputMode
|
|||
private readonly RelativeInputReport* _rawPointer;
|
||||
private readonly VMultiInstance<RelativeInputReport>? _instance;
|
||||
private Vector2 _error;
|
||||
private Vector2 _prev;
|
||||
private bool _dirty;
|
||||
|
||||
public VMultiRelativePointer(TabletReference tabletReference)
|
||||
{
|
||||
_instance = GlobalStore<VMultiInstance>.Set(tabletReference, () => new VMultiInstance<RelativeInputReport>("VMultiAbs", new RelativeInputReport()));
|
||||
_instance = new VMultiInstance<RelativeInputReport>("VMultiRel", new RelativeInputReport());
|
||||
SharedStore.GetStore(tabletReference, STORE_KEY).Add(INSTANCE, _instance);
|
||||
_rawPointer = _instance.Pointer;
|
||||
}
|
||||
|
||||
public void SetPosition(Vector2 delta)
|
||||
{
|
||||
if (delta == Vector2.Zero && _prev == Vector2.Zero)
|
||||
return;
|
||||
|
||||
delta += _error;
|
||||
_error = new Vector2(delta.X % 1, delta.Y % 1);
|
||||
_rawPointer->X = (byte)delta.X;
|
||||
_rawPointer->Y = (byte)delta.Y;
|
||||
_dirty = true;
|
||||
_prev = delta;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
|
|
|
@ -5,6 +5,7 @@ using OpenTabletDriver.Plugin.Attributes;
|
|||
using OpenTabletDriver.Plugin.Tablet;
|
||||
using VoiDPlugins.Library.VMulti;
|
||||
using VoiDPlugins.Library.VoiD;
|
||||
using static VoiDPlugins.OutputMode.VMultiModeConstants;
|
||||
|
||||
namespace VoiDPlugins.OutputMode
|
||||
{
|
||||
|
@ -30,7 +31,7 @@ namespace VoiDPlugins.OutputMode
|
|||
|
||||
private void Initialize(TabletReference tabletReference)
|
||||
{
|
||||
_instance = GlobalStore<VMultiInstance>.Get(tabletReference);
|
||||
_instance = SharedStore.GetStore(tabletReference, STORE_KEY).Get<VMultiInstance>(INSTANCE);
|
||||
}
|
||||
|
||||
public void Press(TabletReference tablet, IDeviceReport report)
|
||||
|
|
8
src/OutputMode/VMultiMode/VMultiModeConstants.cs
Normal file
8
src/OutputMode/VMultiMode/VMultiModeConstants.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace VoiDPlugins.OutputMode
|
||||
{
|
||||
public static class VMultiModeConstants
|
||||
{
|
||||
public const string STORE_KEY = "VMultiMode";
|
||||
public const int INSTANCE = 0;
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ namespace VoiDPlugins.OutputMode
|
|||
public unsafe class WinInkAbsolutePointer : WinInkBasePointer, IAbsolutePointer
|
||||
{
|
||||
private readonly Vector2 _conversionFactor;
|
||||
private Vector2 _prev;
|
||||
|
||||
public WinInkAbsolutePointer(TabletReference tabletReference, IVirtualScreen screen) : base("Windows Ink", tabletReference)
|
||||
{
|
||||
|
@ -16,11 +17,15 @@ namespace VoiDPlugins.OutputMode
|
|||
|
||||
public void SetPosition(Vector2 pos)
|
||||
{
|
||||
if (pos == _prev)
|
||||
return;
|
||||
|
||||
Instance!.EnableButtonBit((int)WindowsInkButtonFlags.InRange);
|
||||
pos *= _conversionFactor;
|
||||
RawPointer->X = (ushort)pos.X;
|
||||
RawPointer->Y = (ushort)pos.Y;
|
||||
Dirty = true;
|
||||
_prev = pos;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
using System.Numerics;
|
||||
using OpenTabletDriver.Plugin.Platform.Pointer;
|
||||
using OpenTabletDriver.Plugin.Tablet;
|
||||
using VoiDPlugins.Library;
|
||||
using VoiDPlugins.Library.VMulti;
|
||||
using VoiDPlugins.Library.VMulti.Device;
|
||||
using VoiDPlugins.Library.VoiD;
|
||||
|
@ -12,26 +11,26 @@ namespace VoiDPlugins.OutputMode
|
|||
public unsafe abstract class WinInkBasePointer : IPressureHandler, ITiltHandler, IEraserHandler, ISynchronousPointer
|
||||
{
|
||||
protected DigitizerInputReport* RawPointer { get; }
|
||||
protected VMultiInstance<DigitizerInputReport>? Instance { get; }
|
||||
protected SharedStore? SharedStore { get; }
|
||||
protected VMultiInstance<DigitizerInputReport> Instance { get; }
|
||||
protected SharedStore SharedStore { get; }
|
||||
protected bool Dirty { get; set; }
|
||||
|
||||
public WinInkBasePointer(string name, TabletReference tabletReference)
|
||||
{
|
||||
Instance = new VMultiInstance<DigitizerInputReport>(name, new DigitizerInputReport());
|
||||
SharedStore = GlobalStore<SharedStore>.Set(tabletReference, () => new SharedStore());
|
||||
SharedStore.InitializeData(INSTANCE, Instance);
|
||||
SharedStore.InitializeData(POINTER, this);
|
||||
SharedStore.InitializeData(ERASER_STATE, new Boxed<bool>(false));
|
||||
SharedStore.InitializeData(MANUAL_ERASER, new Boxed<bool>(false));
|
||||
SharedStore = SharedStore.GetStore(tabletReference, STORE_KEY);
|
||||
SharedStore.Add(INSTANCE, Instance);
|
||||
SharedStore.Add(POINTER, this);
|
||||
SharedStore.Add(ERASER_STATE, false);
|
||||
SharedStore.Add(MANUAL_ERASER, false);
|
||||
RawPointer = Instance.Pointer;
|
||||
}
|
||||
|
||||
public void SetEraser(bool isEraser)
|
||||
{
|
||||
if (!SharedStore!.GetData<Boxed<bool>>(MANUAL_ERASER).Value)
|
||||
if (!SharedStore.Get<bool>(MANUAL_ERASER))
|
||||
{
|
||||
WindowsInkButtonHandler.EraserStateTransition(Instance!, ref GetEraser(), isEraser);
|
||||
WindowsInkButtonHandler.EraserStateTransition(SharedStore, Instance, isEraser);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,10 +57,5 @@ namespace VoiDPlugins.OutputMode
|
|||
Instance!.Write();
|
||||
}
|
||||
}
|
||||
|
||||
private ref Boxed<bool> GetEraser()
|
||||
{
|
||||
return ref SharedStore!.GetData<Boxed<bool>>(ERASER_STATE);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ namespace VoiDPlugins.OutputMode
|
|||
private Vector2 _maxPoint;
|
||||
private Vector2 _currentPoint;
|
||||
private Vector2 _error;
|
||||
private Vector2 _prev;
|
||||
|
||||
public WinInkRelativePointer(TabletReference tabletReference, IVirtualScreen screen) : base("Windows Ink", tabletReference)
|
||||
{
|
||||
|
@ -19,14 +20,17 @@ namespace VoiDPlugins.OutputMode
|
|||
|
||||
public void SetPosition(Vector2 delta)
|
||||
{
|
||||
if (_prev == Vector2.Zero && delta == Vector2.Zero)
|
||||
return;
|
||||
|
||||
Instance!.EnableButtonBit((int)WindowsInkButtonFlags.InRange);
|
||||
delta += _error;
|
||||
_error = new Vector2(delta.X % 1, delta.Y % 1);
|
||||
|
||||
_currentPoint = Vector2.Clamp(_currentPoint + delta, Vector2.Zero, _maxPoint);
|
||||
RawPointer->X = (ushort)_currentPoint.X;
|
||||
RawPointer->Y = (ushort)_currentPoint.Y;
|
||||
Dirty = true;
|
||||
_prev = delta;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
using OpenTabletDriver.Plugin;
|
||||
using OpenTabletDriver.Plugin.Attributes;
|
||||
using OpenTabletDriver.Plugin.Tablet;
|
||||
using VoiDPlugins.Library;
|
||||
using VoiDPlugins.Library.VMulti;
|
||||
using VoiDPlugins.Library.VMulti.Device;
|
||||
using VoiDPlugins.Library.VoiD;
|
||||
|
@ -12,8 +11,8 @@ namespace VoiDPlugins.OutputMode
|
|||
[PluginName("Windows Ink")]
|
||||
public unsafe partial class WindowsInkButtonHandler : IStateBinding
|
||||
{
|
||||
private VMultiInstance? _instance;
|
||||
private SharedStore? _sharedStore;
|
||||
private VMultiInstance _instance = null!;
|
||||
private SharedStore _sharedStore = null!;
|
||||
|
||||
public static string[] ValidButtons { get; } = new string[]
|
||||
{
|
||||
|
@ -31,34 +30,34 @@ namespace VoiDPlugins.OutputMode
|
|||
|
||||
private void Initialize(TabletReference tabletReference)
|
||||
{
|
||||
_sharedStore = GlobalStore<SharedStore>.Get(tabletReference);
|
||||
_instance = _sharedStore.GetData<VMultiInstance>(INSTANCE);
|
||||
_sharedStore = SharedStore.GetStore(tabletReference, STORE_KEY);
|
||||
_instance = _sharedStore.Get<VMultiInstance>(INSTANCE);
|
||||
}
|
||||
|
||||
public void Press(TabletReference tablet, IDeviceReport report)
|
||||
{
|
||||
ref var eraserState = ref GetEraser();
|
||||
var eraserState = _sharedStore.Get<bool>(ERASER_STATE);
|
||||
switch (Button)
|
||||
{
|
||||
case "Pen Tip":
|
||||
_instance!.EnableButtonBit((int)(eraserState.Value ? WindowsInkButtonFlags.Eraser : WindowsInkButtonFlags.Press));
|
||||
_instance.EnableButtonBit((int)(eraserState ? WindowsInkButtonFlags.Eraser : WindowsInkButtonFlags.Press));
|
||||
break;
|
||||
|
||||
case "Pen Button":
|
||||
_instance!.EnableButtonBit((int)WindowsInkButtonFlags.Barrel);
|
||||
_instance.EnableButtonBit((int)WindowsInkButtonFlags.Barrel);
|
||||
break;
|
||||
|
||||
case "Eraser (Toggle)":
|
||||
_sharedStore!.GetData<Boxed<bool>>(MANUAL_ERASER).Value = !eraserState.Value;
|
||||
EraserStateTransition(_instance!, ref eraserState, !eraserState.Value);
|
||||
_sharedStore.Set(MANUAL_ERASER, !eraserState);
|
||||
EraserStateTransition(_sharedStore, _instance, !eraserState);
|
||||
break;
|
||||
|
||||
case "Eraser (Hold)":
|
||||
_sharedStore!.GetData<Boxed<bool>>(MANUAL_ERASER).Value = true;
|
||||
EraserStateTransition(_instance!, ref eraserState, true);
|
||||
_sharedStore.Set(MANUAL_ERASER, true);
|
||||
EraserStateTransition(_sharedStore, _instance, true);
|
||||
break;
|
||||
}
|
||||
_instance!.Write();
|
||||
_instance.Write();
|
||||
}
|
||||
|
||||
public void Release(TabletReference tablet, IDeviceReport report)
|
||||
|
@ -66,26 +65,28 @@ namespace VoiDPlugins.OutputMode
|
|||
switch (Button)
|
||||
{
|
||||
case "Pen Tip":
|
||||
_instance!.DisableButtonBit((int)(WindowsInkButtonFlags.Press | WindowsInkButtonFlags.Eraser));
|
||||
_instance.DisableButtonBit((int)(WindowsInkButtonFlags.Press | WindowsInkButtonFlags.Eraser));
|
||||
break;
|
||||
|
||||
case "Pen Button":
|
||||
_instance!.DisableButtonBit((int)WindowsInkButtonFlags.Barrel);
|
||||
_instance.DisableButtonBit((int)WindowsInkButtonFlags.Barrel);
|
||||
break;
|
||||
|
||||
case "Eraser (Hold)":
|
||||
_sharedStore!.GetData<Boxed<bool>>(MANUAL_ERASER).Value = false;
|
||||
EraserStateTransition(_instance!, ref GetEraser(), false);
|
||||
_sharedStore.Set(MANUAL_ERASER, false);
|
||||
EraserStateTransition(_sharedStore, _instance, false);
|
||||
break;
|
||||
}
|
||||
_instance!.Write();
|
||||
_instance.Write();
|
||||
}
|
||||
|
||||
public static void EraserStateTransition(VMultiInstance instance, ref Boxed<bool> eraserState, bool isEraser)
|
||||
public static void EraserStateTransition(SharedStore store, VMultiInstance instance, bool isEraser)
|
||||
{
|
||||
if (eraserState.Value != isEraser)
|
||||
var eraserState = store.Get<bool>(ERASER_STATE);
|
||||
if (eraserState != isEraser)
|
||||
{
|
||||
eraserState.Value = isEraser;
|
||||
store.Set(ERASER_STATE, isEraser);
|
||||
eraserState = isEraser;
|
||||
var report = (DigitizerInputReport*)instance.Header;
|
||||
var buttons = report->Header.Buttons;
|
||||
var pressure = report->Pressure;
|
||||
|
@ -101,21 +102,16 @@ namespace VoiDPlugins.OutputMode
|
|||
|
||||
// Send In-Range but no tips
|
||||
instance.EnableButtonBit((int)WindowsInkButtonFlags.InRange);
|
||||
if (eraserState.Value)
|
||||
if (eraserState)
|
||||
instance.EnableButtonBit((int)WindowsInkButtonFlags.Invert);
|
||||
|
||||
instance.Write();
|
||||
|
||||
// Set Proper Report
|
||||
if (VMultiInstance.HasBit(buttons, (int)(WindowsInkButtonFlags.Press | WindowsInkButtonFlags.Eraser)))
|
||||
instance.EnableButtonBit((int)(eraserState.Value ? WindowsInkButtonFlags.Eraser : WindowsInkButtonFlags.Press));
|
||||
instance.EnableButtonBit((int)(eraserState ? WindowsInkButtonFlags.Eraser : WindowsInkButtonFlags.Press));
|
||||
report->Pressure = pressure;
|
||||
}
|
||||
}
|
||||
|
||||
private ref Boxed<bool> GetEraser()
|
||||
{
|
||||
return ref _sharedStore!.GetData<Boxed<bool>>(ERASER_STATE);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ namespace VoiDPlugins.OutputMode
|
|||
{
|
||||
public static class WindowsInkConstants
|
||||
{
|
||||
public const string STORE_KEY = "WindowsInk";
|
||||
public const int INSTANCE = 0;
|
||||
public const int POINTER = 1;
|
||||
public const int ERASER_STATE = 2;
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
namespace VoiDPlugins.Library
|
||||
{
|
||||
public class Boxed<T> where T : unmanaged
|
||||
{
|
||||
public Boxed(T value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public T Value { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using OpenTabletDriver.Plugin.Tablet;
|
||||
|
||||
namespace VoiDPlugins.Library.VoiD
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores one instance of <typeparamref name="T"/> per <see cref="TabletReference"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">A class.</typeparam>
|
||||
public static class GlobalStore<T> where T : class
|
||||
{
|
||||
private static readonly object _syncLock = new();
|
||||
private static readonly Dictionary<string, T> _map = new();
|
||||
|
||||
public static U Set<U>(TabletReference tabletReference, Func<U> factory) where U : T
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
ref var instance = ref CollectionsMarshal.GetValueRefOrAddDefault(_map, tabletReference.Properties.Name, out var exists);
|
||||
instance = factory();
|
||||
return (U)instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static U GetOrInitialize<U>(TabletReference tabletReference, Func<U> initialValue) where U : T
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
ref var instance = ref CollectionsMarshal.GetValueRefOrAddDefault(_map, tabletReference.Properties.Name, out var exists);
|
||||
if (!exists)
|
||||
instance = initialValue();
|
||||
return (U)instance!;
|
||||
}
|
||||
}
|
||||
|
||||
public static U Get<U>(TabletReference tabletReference) where U : T
|
||||
{
|
||||
return (U)_map[tabletReference.Properties.Name];
|
||||
}
|
||||
|
||||
public static T Get(TabletReference tabletReference)
|
||||
{
|
||||
return _map[tabletReference.Properties.Name];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,27 +1,115 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using OpenTabletDriver.Plugin.Tablet;
|
||||
|
||||
namespace VoiDPlugins.Library.VoiD
|
||||
{
|
||||
/// <summary>
|
||||
/// Fast shared store with support for generic ref returning <see cref="GetData"/>.
|
||||
/// </summary>
|
||||
public class SharedStore
|
||||
public class SharedStore : IDictionary<int, object>
|
||||
{
|
||||
private readonly object[] _data;
|
||||
private static readonly Dictionary<TabletReference, Dictionary<string, SharedStore>> _storeMap = new(new Comparer());
|
||||
|
||||
public SharedStore()
|
||||
private readonly Dictionary<int, object> _sharedStore = new();
|
||||
|
||||
public object this[int key] { get => ((IDictionary<int, object>)_sharedStore)[key]; set => ((IDictionary<int, object>)_sharedStore)[key] = value; }
|
||||
public ICollection<int> Keys => ((IDictionary<int, object>)_sharedStore).Keys;
|
||||
public ICollection<object> Values => ((IDictionary<int, object>)_sharedStore).Values;
|
||||
public int Count => ((ICollection<KeyValuePair<int, object>>)_sharedStore).Count;
|
||||
public bool IsReadOnly => ((ICollection<KeyValuePair<int, object>>)_sharedStore).IsReadOnly;
|
||||
|
||||
public static SharedStore GetStore(TabletReference reference, string storeKey)
|
||||
{
|
||||
_data = new object[32];
|
||||
lock (_storeMap)
|
||||
{
|
||||
ref var tabletStore = ref CollectionsMarshal.GetValueRefOrAddDefault(_storeMap, reference, out var exists);
|
||||
if (!exists)
|
||||
tabletStore = new Dictionary<string, SharedStore>();
|
||||
|
||||
ref var store = ref CollectionsMarshal.GetValueRefOrAddDefault(tabletStore!, storeKey, out var exists2);
|
||||
if (!exists2)
|
||||
store = new SharedStore();
|
||||
|
||||
return store!;
|
||||
}
|
||||
}
|
||||
|
||||
public void InitializeData<T>(int i, T data)
|
||||
public T Get<T>(int key)
|
||||
{
|
||||
_data[i] = data!;
|
||||
return (T)_sharedStore[key];
|
||||
}
|
||||
|
||||
public unsafe ref T GetData<T>(int i)
|
||||
public void Set<T>(int key, T value)
|
||||
{
|
||||
return ref Unsafe.AsRef<T>(Unsafe.AsPointer(ref _data[i]));
|
||||
_sharedStore[key] = value!;
|
||||
}
|
||||
|
||||
public void Add(int key, object value)
|
||||
{
|
||||
((IDictionary<int, object>)_sharedStore).Add(key, value);
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<int, object> item)
|
||||
{
|
||||
((ICollection<KeyValuePair<int, object>>)_sharedStore).Add(item);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
((ICollection<KeyValuePair<int, object>>)_sharedStore).Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<int, object> item)
|
||||
{
|
||||
return ((ICollection<KeyValuePair<int, object>>)_sharedStore).Contains(item);
|
||||
}
|
||||
|
||||
public bool ContainsKey(int key)
|
||||
{
|
||||
return ((IDictionary<int, object>)_sharedStore).ContainsKey(key);
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<int, object>[] array, int arrayIndex)
|
||||
{
|
||||
((ICollection<KeyValuePair<int, object>>)_sharedStore).CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<int, object>> GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<KeyValuePair<int, object>>)_sharedStore).GetEnumerator();
|
||||
}
|
||||
|
||||
public bool Remove(int key)
|
||||
{
|
||||
return ((IDictionary<int, object>)_sharedStore).Remove(key);
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<int, object> item)
|
||||
{
|
||||
return ((ICollection<KeyValuePair<int, object>>)_sharedStore).Remove(item);
|
||||
}
|
||||
|
||||
public bool TryGetValue(int key, [MaybeNullWhen(false)] out object value)
|
||||
{
|
||||
return ((IDictionary<int, object>)_sharedStore).TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable)_sharedStore).GetEnumerator();
|
||||
}
|
||||
|
||||
private class Comparer : IEqualityComparer<TabletReference>
|
||||
{
|
||||
public bool Equals(TabletReference? x, TabletReference? y)
|
||||
{
|
||||
return x?.Properties.Name == y?.Properties.Name;
|
||||
}
|
||||
|
||||
public int GetHashCode(TabletReference obj)
|
||||
{
|
||||
return obj.Properties.Name.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue