forked from Mirror/Ryujinx
[Ryujinx.Common] Address dotnet-format issues (#5358)
* dotnet format style --severity info Some changes were manually reverted. * dotnet format analyzers --serverity info Some changes have been minimally adapted. * Restore a few unused methods and variables * Silence dotnet format IDE0060 warnings * Silence dotnet format IDE0059 warnings * Address or silence dotnet format IDE1006 warnings * Address dotnet format CA1816 warnings * Address or silence dotnet format CA2211 warnings * Silence CA1806 and CA1834 issues * Fix formatting for switch expressions * Address most dotnet format whitespace warnings * Apply dotnet format whitespace formatting A few of them have been manually reverted and the corresponding warning was silenced * Revert formatting changes for while and for-loops * Format if-blocks correctly * Run dotnet format whitespace after rebase * Run dotnet format style after rebase * Run dotnet format analyzers after rebase * Run dotnet format after rebase and remove unused usings - analyzers - style - whitespace * Add comments to disabled warnings * Remove a few unused parameters * Replace MmeShadowScratch with Array256<uint> * Simplify properties and array initialization, Use const when possible, Remove trailing commas * Run dotnet format after rebase * Address IDE0251 warnings * Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas" This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e. * dotnet format whitespace after rebase * First dotnet format pass * Second dotnet format pass * Fix build issues * Fix StructArrayHelpers.cs * Apply suggestions from code review Co-authored-by: Ac_K <Acoustik666@gmail.com> * Fix return statements * Fix naming rule violations * Update src/Ryujinx.Common/Utilities/StreamUtils.cs Co-authored-by: Ac_K <Acoustik666@gmail.com> * Add trailing commas * Address review feedback * Address review feedback * Rename remaining type parameters to TKey and TValue * Fix manual formatting for logging levels * Fix spacing before comments --------- Co-authored-by: Ac_K <Acoustik666@gmail.com>
This commit is contained in:
parent
0a75b73fa4
commit
fc20d9b925
96 changed files with 965 additions and 969 deletions
|
@ -7,9 +7,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// <summary>
|
||||
/// An Augmented Interval Tree based off of the "TreeDictionary"'s Red-Black Tree. Allows fast overlap checking of ranges.
|
||||
/// </summary>
|
||||
/// <typeparam name="K">Key</typeparam>
|
||||
/// <typeparam name="V">Value</typeparam>
|
||||
public class IntervalTree<K, V> : IntrusiveRedBlackTreeImpl<IntervalTreeNode<K, V>> where K : IComparable<K>
|
||||
/// <typeparam name="TKey">Key</typeparam>
|
||||
/// <typeparam name="TValue">Value</typeparam>
|
||||
public class IntervalTree<TKey, TValue> : IntrusiveRedBlackTreeImpl<IntervalTreeNode<TKey, TValue>> where TKey : IComparable<TKey>
|
||||
{
|
||||
private const int ArrayGrowthSize = 32;
|
||||
|
||||
|
@ -22,11 +22,11 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="overlaps">Overlaps array to place results in</param>
|
||||
/// <returns>Number of values found</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
public int Get(K key, ref V[] overlaps)
|
||||
public int Get(TKey key, ref TValue[] overlaps)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
IntervalTreeNode<K, V> node = GetNode(key);
|
||||
IntervalTreeNode<TKey, TValue> node = GetNode(key);
|
||||
|
||||
if (node == null)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ namespace Ryujinx.Common.Collections
|
|||
}
|
||||
|
||||
int overlapsCount = 0;
|
||||
foreach (RangeNode<K, V> value in node.Values)
|
||||
foreach (RangeNode<TKey, TValue> value in node.Values)
|
||||
{
|
||||
overlaps[overlapsCount++] = value.Value;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="overlapCount">Index to start writing results into the array. Defaults to 0</param>
|
||||
/// <returns>Number of values found</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="start"/> or <paramref name="end"/> is null</exception>
|
||||
public int Get(K start, K end, ref V[] overlaps, int overlapCount = 0)
|
||||
public int Get(TKey start, TKey end, ref TValue[] overlaps, int overlapCount = 0)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(start);
|
||||
ArgumentNullException.ThrowIfNull(end);
|
||||
|
@ -73,7 +73,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="end">End of the range to insert</param>
|
||||
/// <param name="value">Value to add</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="start"/>, <paramref name="end"/> or <paramref name="value"/> are null</exception>
|
||||
public void Add(K start, K end, V value)
|
||||
public void Add(TKey start, TKey end, TValue value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(start);
|
||||
ArgumentNullException.ThrowIfNull(end);
|
||||
|
@ -89,7 +89,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="value">Value to remove</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
/// <returns>Number of deleted values</returns>
|
||||
public int Remove(K key, V value)
|
||||
public int Remove(TKey key, TValue value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
|
@ -104,9 +104,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// Adds all the nodes in the dictionary into <paramref name="list"/>.
|
||||
/// </summary>
|
||||
/// <returns>A list of all RangeNodes sorted by Key Order</returns>
|
||||
public List<RangeNode<K, V>> AsList()
|
||||
public List<RangeNode<TKey, TValue>> AsList()
|
||||
{
|
||||
List<RangeNode<K, V>> list = new List<RangeNode<K, V>>();
|
||||
List<RangeNode<TKey, TValue>> list = new();
|
||||
|
||||
AddToList(Root, list);
|
||||
|
||||
|
@ -122,7 +122,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// </summary>
|
||||
/// <param name="node">The node to search for RangeNodes within</param>
|
||||
/// <param name="list">The list to add RangeNodes to</param>
|
||||
private void AddToList(IntervalTreeNode<K, V> node, List<RangeNode<K, V>> list)
|
||||
private void AddToList(IntervalTreeNode<TKey, TValue> node, List<RangeNode<TKey, TValue>> list)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
|
@ -142,11 +142,11 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key of the node to get</param>
|
||||
/// <returns>Node reference in the tree</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
private IntervalTreeNode<K, V> GetNode(K key)
|
||||
private IntervalTreeNode<TKey, TValue> GetNode(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
IntervalTreeNode<K, V> node = Root;
|
||||
IntervalTreeNode<TKey, TValue> node = Root;
|
||||
while (node != null)
|
||||
{
|
||||
int cmp = key.CompareTo(node.Start);
|
||||
|
@ -173,7 +173,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="end">End of the range</param>
|
||||
/// <param name="overlaps">Overlaps array to place results in</param>
|
||||
/// <param name="overlapCount">Overlaps count to update</param>
|
||||
private void GetValues(IntervalTreeNode<K, V> node, K start, K end, ref V[] overlaps, ref int overlapCount)
|
||||
private void GetValues(IntervalTreeNode<TKey, TValue> node, TKey start, TKey end, ref TValue[] overlaps, ref int overlapCount)
|
||||
{
|
||||
if (node == null || start.CompareTo(node.Max) >= 0)
|
||||
{
|
||||
|
@ -188,7 +188,7 @@ namespace Ryujinx.Common.Collections
|
|||
if (start.CompareTo(node.End) < 0)
|
||||
{
|
||||
// Contains this node. Add overlaps to list.
|
||||
foreach (RangeNode<K,V> overlap in node.Values)
|
||||
foreach (RangeNode<TKey, TValue> overlap in node.Values)
|
||||
{
|
||||
if (start.CompareTo(overlap.End) < 0)
|
||||
{
|
||||
|
@ -212,9 +212,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="start">Start of the range to insert</param>
|
||||
/// <param name="end">End of the range to insert</param>
|
||||
/// <param name="value">Value to insert</param>
|
||||
private void Insert(K start, K end, V value)
|
||||
private void Insert(TKey start, TKey end, TValue value)
|
||||
{
|
||||
IntervalTreeNode<K, V> newNode = BSTInsert(start, end, value);
|
||||
IntervalTreeNode<TKey, TValue> newNode = BSTInsert(start, end, value);
|
||||
RestoreBalanceAfterInsertion(newNode);
|
||||
}
|
||||
|
||||
|
@ -223,10 +223,10 @@ namespace Ryujinx.Common.Collections
|
|||
/// This should only be called if the max increases - not for rebalancing or removals.
|
||||
/// </summary>
|
||||
/// <param name="node">The node to start propagating from</param>
|
||||
private void PropagateIncrease(IntervalTreeNode<K, V> node)
|
||||
private static void PropagateIncrease(IntervalTreeNode<TKey, TValue> node)
|
||||
{
|
||||
K max = node.Max;
|
||||
IntervalTreeNode<K, V> ptr = node;
|
||||
TKey max = node.Max;
|
||||
IntervalTreeNode<TKey, TValue> ptr = node;
|
||||
|
||||
while ((ptr = ptr.Parent) != null)
|
||||
{
|
||||
|
@ -246,13 +246,13 @@ namespace Ryujinx.Common.Collections
|
|||
/// This fully recalculates the max value from all children when there is potential for it to decrease.
|
||||
/// </summary>
|
||||
/// <param name="node">The node to start propagating from</param>
|
||||
private void PropagateFull(IntervalTreeNode<K, V> node)
|
||||
private static void PropagateFull(IntervalTreeNode<TKey, TValue> node)
|
||||
{
|
||||
IntervalTreeNode<K, V> ptr = node;
|
||||
IntervalTreeNode<TKey, TValue> ptr = node;
|
||||
|
||||
do
|
||||
{
|
||||
K max = ptr.End;
|
||||
TKey max = ptr.End;
|
||||
|
||||
if (ptr.Left != null && ptr.Left.Max.CompareTo(max) > 0)
|
||||
{
|
||||
|
@ -278,10 +278,10 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="end">End of the range to insert</param>
|
||||
/// <param name="value">Value to insert</param>
|
||||
/// <returns>The inserted Node</returns>
|
||||
private IntervalTreeNode<K, V> BSTInsert(K start, K end, V value)
|
||||
private IntervalTreeNode<TKey, TValue> BSTInsert(TKey start, TKey end, TValue value)
|
||||
{
|
||||
IntervalTreeNode<K, V> parent = null;
|
||||
IntervalTreeNode<K, V> node = Root;
|
||||
IntervalTreeNode<TKey, TValue> parent = null;
|
||||
IntervalTreeNode<TKey, TValue> node = Root;
|
||||
|
||||
while (node != null)
|
||||
{
|
||||
|
@ -297,7 +297,7 @@ namespace Ryujinx.Common.Collections
|
|||
}
|
||||
else
|
||||
{
|
||||
node.Values.Add(new RangeNode<K, V>(start, end, value));
|
||||
node.Values.Add(new RangeNode<TKey, TValue>(start, end, value));
|
||||
|
||||
if (end.CompareTo(node.End) > 0)
|
||||
{
|
||||
|
@ -313,7 +313,7 @@ namespace Ryujinx.Common.Collections
|
|||
return node;
|
||||
}
|
||||
}
|
||||
IntervalTreeNode<K, V> newNode = new IntervalTreeNode<K, V>(start, end, value, parent);
|
||||
IntervalTreeNode<TKey, TValue> newNode = new(start, end, value, parent);
|
||||
if (newNode.Parent == null)
|
||||
{
|
||||
Root = newNode;
|
||||
|
@ -338,9 +338,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key to search for</param>
|
||||
/// <param name="value">Value to delete</param>
|
||||
/// <returns>Number of deleted values</returns>
|
||||
private int Delete(K key, V value)
|
||||
private int Delete(TKey key, TValue value)
|
||||
{
|
||||
IntervalTreeNode<K, V> nodeToDelete = GetNode(key);
|
||||
IntervalTreeNode<TKey, TValue> nodeToDelete = GetNode(key);
|
||||
|
||||
if (nodeToDelete == null)
|
||||
{
|
||||
|
@ -362,7 +362,7 @@ namespace Ryujinx.Common.Collections
|
|||
return removed;
|
||||
}
|
||||
|
||||
IntervalTreeNode<K, V> replacementNode;
|
||||
IntervalTreeNode<TKey, TValue> replacementNode;
|
||||
|
||||
if (LeftOf(nodeToDelete) == null || RightOf(nodeToDelete) == null)
|
||||
{
|
||||
|
@ -373,7 +373,7 @@ namespace Ryujinx.Common.Collections
|
|||
replacementNode = PredecessorOf(nodeToDelete);
|
||||
}
|
||||
|
||||
IntervalTreeNode<K, V> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
||||
IntervalTreeNode<TKey, TValue> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
||||
|
||||
if (tmp != null)
|
||||
{
|
||||
|
@ -413,7 +413,7 @@ namespace Ryujinx.Common.Collections
|
|||
|
||||
#endregion
|
||||
|
||||
protected override void RotateLeft(IntervalTreeNode<K, V> node)
|
||||
protected override void RotateLeft(IntervalTreeNode<TKey, TValue> node)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
|
@ -423,7 +423,7 @@ namespace Ryujinx.Common.Collections
|
|||
}
|
||||
}
|
||||
|
||||
protected override void RotateRight(IntervalTreeNode<K, V> node)
|
||||
protected override void RotateRight(IntervalTreeNode<TKey, TValue> node)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
|
@ -433,7 +433,7 @@ namespace Ryujinx.Common.Collections
|
|||
}
|
||||
}
|
||||
|
||||
public bool ContainsKey(K key)
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
|
@ -444,15 +444,15 @@ namespace Ryujinx.Common.Collections
|
|||
/// <summary>
|
||||
/// Represents a value and its start and end keys.
|
||||
/// </summary>
|
||||
/// <typeparam name="K"></typeparam>
|
||||
/// <typeparam name="V"></typeparam>
|
||||
public readonly struct RangeNode<K, V>
|
||||
/// <typeparam name="TKey"></typeparam>
|
||||
/// <typeparam name="TValue"></typeparam>
|
||||
public readonly struct RangeNode<TKey, TValue>
|
||||
{
|
||||
public readonly K Start;
|
||||
public readonly K End;
|
||||
public readonly V Value;
|
||||
public readonly TKey Start;
|
||||
public readonly TKey End;
|
||||
public readonly TValue Value;
|
||||
|
||||
public RangeNode(K start, K end, V value)
|
||||
public RangeNode(TKey start, TKey end, TValue value)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
|
@ -463,36 +463,36 @@ namespace Ryujinx.Common.Collections
|
|||
/// <summary>
|
||||
/// Represents a node in the IntervalTree which contains start and end keys of type K, and a value of generic type V.
|
||||
/// </summary>
|
||||
/// <typeparam name="K">Key type of the node</typeparam>
|
||||
/// <typeparam name="V">Value type of the node</typeparam>
|
||||
public class IntervalTreeNode<K, V> : IntrusiveRedBlackTreeNode<IntervalTreeNode<K, V>>
|
||||
/// <typeparam name="TKey">Key type of the node</typeparam>
|
||||
/// <typeparam name="TValue">Value type of the node</typeparam>
|
||||
public class IntervalTreeNode<TKey, TValue> : IntrusiveRedBlackTreeNode<IntervalTreeNode<TKey, TValue>>
|
||||
{
|
||||
/// <summary>
|
||||
/// The start of the range.
|
||||
/// </summary>
|
||||
internal K Start;
|
||||
internal TKey Start;
|
||||
|
||||
/// <summary>
|
||||
/// The end of the range - maximum of all in the Values list.
|
||||
/// </summary>
|
||||
internal K End;
|
||||
internal TKey End;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum end value of this node and all its children.
|
||||
/// </summary>
|
||||
internal K Max;
|
||||
internal TKey Max;
|
||||
|
||||
/// <summary>
|
||||
/// Values contained on the node that shares a common Start value.
|
||||
/// </summary>
|
||||
internal List<RangeNode<K, V>> Values;
|
||||
internal List<RangeNode<TKey, TValue>> Values;
|
||||
|
||||
internal IntervalTreeNode(K start, K end, V value, IntervalTreeNode<K, V> parent)
|
||||
internal IntervalTreeNode(TKey start, TKey end, TValue value, IntervalTreeNode<TKey, TValue> parent)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
Max = end;
|
||||
Values = new List<RangeNode<K, V>> { new RangeNode<K, V>(start, end, value) };
|
||||
Values = new List<RangeNode<TKey, TValue>> { new RangeNode<TKey, TValue>(start, end, value) };
|
||||
Parent = parent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,11 +180,6 @@ namespace Ryujinx.Common.Collections
|
|||
parent.Right = child;
|
||||
}
|
||||
|
||||
if (ParentOf(element) == old)
|
||||
{
|
||||
parent = element;
|
||||
}
|
||||
|
||||
element.Color = old.Color;
|
||||
element.Left = old.Left;
|
||||
element.Right = old.Right;
|
||||
|
@ -258,11 +253,11 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="tree">Tree to search at</param>
|
||||
/// <param name="key">Key of the node to be found</param>
|
||||
/// <returns>Node that is equal to <paramref name="key"/></returns>
|
||||
public static N GetNodeByKey<N, K>(this IntrusiveRedBlackTree<N> tree, K key)
|
||||
where N : IntrusiveRedBlackTreeNode<N>, IComparable<N>, IComparable<K>
|
||||
where K : struct
|
||||
public static TNode GetNodeByKey<TNode, TKey>(this IntrusiveRedBlackTree<TNode> tree, TKey key)
|
||||
where TNode : IntrusiveRedBlackTreeNode<TNode>, IComparable<TNode>, IComparable<TKey>
|
||||
where TKey : struct
|
||||
{
|
||||
N node = tree.RootNode;
|
||||
TNode node = tree.RootNode;
|
||||
while (node != null)
|
||||
{
|
||||
int cmp = node.CompareTo(key);
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Ryujinx.Common.Collections
|
|||
{
|
||||
protected const bool Black = true;
|
||||
protected const bool Red = false;
|
||||
protected T Root = null;
|
||||
protected T Root;
|
||||
|
||||
internal T RootNode => Root;
|
||||
|
||||
|
|
|
@ -8,9 +8,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// <summary>
|
||||
/// Dictionary that provides the ability for O(logN) Lookups for keys that exist in the Dictionary, and O(logN) lookups for keys immediately greater than or less than a specified key.
|
||||
/// </summary>
|
||||
/// <typeparam name="K">Key</typeparam>
|
||||
/// <typeparam name="V">Value</typeparam>
|
||||
public class TreeDictionary<K, V> : IntrusiveRedBlackTreeImpl<Node<K, V>>, IDictionary<K, V> where K : IComparable<K>
|
||||
/// <typeparam name="TKey">Key</typeparam>
|
||||
/// <typeparam name="TValue">Value</typeparam>
|
||||
public class TreeDictionary<TKey, TValue> : IntrusiveRedBlackTreeImpl<Node<TKey, TValue>>, IDictionary<TKey, TValue> where TKey : IComparable<TKey>
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
|
@ -20,11 +20,11 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key of the node value to get</param>
|
||||
/// <returns>Value associated w/ <paramref name="key"/></returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
public V Get(K key)
|
||||
public TValue Get(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> node = GetNode(key);
|
||||
Node<TKey, TValue> node = GetNode(key);
|
||||
|
||||
if (node == null)
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key of the node to add</param>
|
||||
/// <param name="value">Value of the node to add</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> or <paramref name="value"/> are null</exception>
|
||||
public void Add(K key, V value)
|
||||
public void Add(TKey key, TValue value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
|
@ -55,7 +55,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// </summary>
|
||||
/// <param name="key">Key of the node to remove</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
public void Remove(K key)
|
||||
public void Remove(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
|
@ -71,9 +71,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key for which to find the floor value of</param>
|
||||
/// <returns>Key of node immediately less than <paramref name="key"/></returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
public K Floor(K key)
|
||||
public TKey Floor(TKey key)
|
||||
{
|
||||
Node<K, V> node = FloorNode(key);
|
||||
Node<TKey, TValue> node = FloorNode(key);
|
||||
if (node != null)
|
||||
{
|
||||
return node.Key;
|
||||
|
@ -87,9 +87,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key for which to find the ceiling node of</param>
|
||||
/// <returns>Key of node immediately greater than <paramref name="key"/></returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
public K Ceiling(K key)
|
||||
public TKey Ceiling(TKey key)
|
||||
{
|
||||
Node<K, V> node = CeilingNode(key);
|
||||
Node<TKey, TValue> node = CeilingNode(key);
|
||||
if (node != null)
|
||||
{
|
||||
return node.Key;
|
||||
|
@ -102,12 +102,12 @@ namespace Ryujinx.Common.Collections
|
|||
/// </summary>
|
||||
/// <param name="key">Key to find the successor of</param>
|
||||
/// <returns>Value</returns>
|
||||
public K SuccessorOf(K key)
|
||||
public TKey SuccessorOf(TKey key)
|
||||
{
|
||||
Node<K, V> node = GetNode(key);
|
||||
Node<TKey, TValue> node = GetNode(key);
|
||||
if (node != null)
|
||||
{
|
||||
Node<K, V> successor = SuccessorOf(node);
|
||||
Node<TKey, TValue> successor = SuccessorOf(node);
|
||||
|
||||
return successor != null ? successor.Key : default;
|
||||
}
|
||||
|
@ -119,12 +119,12 @@ namespace Ryujinx.Common.Collections
|
|||
/// </summary>
|
||||
/// <param name="key">Key to find the predecessor of</param>
|
||||
/// <returns>Value</returns>
|
||||
public K PredecessorOf(K key)
|
||||
public TKey PredecessorOf(TKey key)
|
||||
{
|
||||
Node<K, V> node = GetNode(key);
|
||||
Node<TKey, TValue> node = GetNode(key);
|
||||
if (node != null)
|
||||
{
|
||||
Node<K, V> predecessor = PredecessorOf(node);
|
||||
Node<TKey, TValue> predecessor = PredecessorOf(node);
|
||||
|
||||
return predecessor != null ? predecessor.Key : default;
|
||||
}
|
||||
|
@ -137,19 +137,19 @@ namespace Ryujinx.Common.Collections
|
|||
/// The key/value pairs will be added in Level Order.
|
||||
/// </summary>
|
||||
/// <param name="list">List to add the tree pairs into</param>
|
||||
public List<KeyValuePair<K, V>> AsLevelOrderList()
|
||||
public List<KeyValuePair<TKey, TValue>> AsLevelOrderList()
|
||||
{
|
||||
List<KeyValuePair<K, V>> list = new List<KeyValuePair<K, V>>();
|
||||
List<KeyValuePair<TKey, TValue>> list = new();
|
||||
|
||||
Queue<Node<K, V>> nodes = new Queue<Node<K, V>>();
|
||||
Queue<Node<TKey, TValue>> nodes = new();
|
||||
|
||||
if (this.Root != null)
|
||||
{
|
||||
nodes.Enqueue(this.Root);
|
||||
}
|
||||
while (nodes.TryDequeue(out Node<K, V> node))
|
||||
while (nodes.TryDequeue(out Node<TKey, TValue> node))
|
||||
{
|
||||
list.Add(new KeyValuePair<K, V>(node.Key, node.Value));
|
||||
list.Add(new KeyValuePair<TKey, TValue>(node.Key, node.Value));
|
||||
if (node.Left != null)
|
||||
{
|
||||
nodes.Enqueue(node.Left);
|
||||
|
@ -166,9 +166,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// Adds all the nodes in the dictionary into <paramref name="list"/>.
|
||||
/// </summary>
|
||||
/// <returns>A list of all KeyValuePairs sorted by Key Order</returns>
|
||||
public List<KeyValuePair<K, V>> AsList()
|
||||
public List<KeyValuePair<TKey, TValue>> AsList()
|
||||
{
|
||||
List<KeyValuePair<K, V>> list = new List<KeyValuePair<K, V>>();
|
||||
List<KeyValuePair<TKey, TValue>> list = new();
|
||||
|
||||
AddToList(Root, list);
|
||||
|
||||
|
@ -184,7 +184,7 @@ namespace Ryujinx.Common.Collections
|
|||
/// </summary>
|
||||
/// <param name="node">The node to search for nodes within</param>
|
||||
/// <param name="list">The list to add node to</param>
|
||||
private void AddToList(Node<K, V> node, List<KeyValuePair<K, V>> list)
|
||||
private void AddToList(Node<TKey, TValue> node, List<KeyValuePair<TKey, TValue>> list)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
|
@ -193,7 +193,7 @@ namespace Ryujinx.Common.Collections
|
|||
|
||||
AddToList(node.Left, list);
|
||||
|
||||
list.Add(new KeyValuePair<K, V>(node.Key, node.Value));
|
||||
list.Add(new KeyValuePair<TKey, TValue>(node.Key, node.Value));
|
||||
|
||||
AddToList(node.Right, list);
|
||||
}
|
||||
|
@ -204,11 +204,11 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key of the node to get</param>
|
||||
/// <returns>Node reference in the tree</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
private Node<K, V> GetNode(K key)
|
||||
private Node<TKey, TValue> GetNode(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> node = Root;
|
||||
Node<TKey, TValue> node = Root;
|
||||
while (node != null)
|
||||
{
|
||||
int cmp = key.CompareTo(node.Key);
|
||||
|
@ -235,9 +235,9 @@ namespace Ryujinx.Common.Collections
|
|||
/// </summary>
|
||||
/// <param name="key">Key of the node to insert</param>
|
||||
/// <param name="value">Value of the node to insert</param>
|
||||
private void Insert(K key, V value)
|
||||
private void Insert(TKey key, TValue value)
|
||||
{
|
||||
Node<K, V> newNode = BSTInsert(key, value);
|
||||
Node<TKey, TValue> newNode = BSTInsert(key, value);
|
||||
RestoreBalanceAfterInsertion(newNode);
|
||||
}
|
||||
|
||||
|
@ -251,10 +251,10 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key of the node to insert</param>
|
||||
/// <param name="value">Value of the node to insert</param>
|
||||
/// <returns>The inserted Node</returns>
|
||||
private Node<K, V> BSTInsert(K key, V value)
|
||||
private Node<TKey, TValue> BSTInsert(TKey key, TValue value)
|
||||
{
|
||||
Node<K, V> parent = null;
|
||||
Node<K, V> node = Root;
|
||||
Node<TKey, TValue> parent = null;
|
||||
Node<TKey, TValue> node = Root;
|
||||
|
||||
while (node != null)
|
||||
{
|
||||
|
@ -274,7 +274,7 @@ namespace Ryujinx.Common.Collections
|
|||
return node;
|
||||
}
|
||||
}
|
||||
Node<K, V> newNode = new Node<K, V>(key, value, parent);
|
||||
Node<TKey, TValue> newNode = new(key, value, parent);
|
||||
if (newNode.Parent == null)
|
||||
{
|
||||
Root = newNode;
|
||||
|
@ -296,14 +296,17 @@ namespace Ryujinx.Common.Collections
|
|||
/// </summary>
|
||||
/// <param name="key">Key of the node to delete</param>
|
||||
/// <returns>The deleted Node</returns>
|
||||
private Node<K, V> Delete(K key)
|
||||
private Node<TKey, TValue> Delete(TKey key)
|
||||
{
|
||||
// O(1) Retrieval
|
||||
Node<K, V> nodeToDelete = GetNode(key);
|
||||
Node<TKey, TValue> nodeToDelete = GetNode(key);
|
||||
|
||||
if (nodeToDelete == null) return null;
|
||||
if (nodeToDelete == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Node<K, V> replacementNode;
|
||||
Node<TKey, TValue> replacementNode;
|
||||
|
||||
if (LeftOf(nodeToDelete) == null || RightOf(nodeToDelete) == null)
|
||||
{
|
||||
|
@ -314,7 +317,7 @@ namespace Ryujinx.Common.Collections
|
|||
replacementNode = PredecessorOf(nodeToDelete);
|
||||
}
|
||||
|
||||
Node<K, V> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
||||
Node<TKey, TValue> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
|
||||
|
||||
if (tmp != null)
|
||||
{
|
||||
|
@ -354,11 +357,11 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key for which to find the floor node of</param>
|
||||
/// <returns>Node whose key is immediately less than or equal to <paramref name="key"/>, or null if no such node is found.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
private Node<K, V> FloorNode(K key)
|
||||
private Node<TKey, TValue> FloorNode(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> tmp = Root;
|
||||
Node<TKey, TValue> tmp = Root;
|
||||
|
||||
while (tmp != null)
|
||||
{
|
||||
|
@ -382,8 +385,8 @@ namespace Ryujinx.Common.Collections
|
|||
}
|
||||
else
|
||||
{
|
||||
Node<K, V> parent = tmp.Parent;
|
||||
Node<K, V> ptr = tmp;
|
||||
Node<TKey, TValue> parent = tmp.Parent;
|
||||
Node<TKey, TValue> ptr = tmp;
|
||||
while (parent != null && ptr == parent.Left)
|
||||
{
|
||||
ptr = parent;
|
||||
|
@ -406,11 +409,11 @@ namespace Ryujinx.Common.Collections
|
|||
/// <param name="key">Key for which to find the ceiling node of</param>
|
||||
/// <returns>Node whose key is immediately greater than or equal to <paramref name="key"/>, or null if no such node is found.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
|
||||
private Node<K, V> CeilingNode(K key)
|
||||
private Node<TKey, TValue> CeilingNode(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> tmp = Root;
|
||||
Node<TKey, TValue> tmp = Root;
|
||||
|
||||
while (tmp != null)
|
||||
{
|
||||
|
@ -434,8 +437,8 @@ namespace Ryujinx.Common.Collections
|
|||
}
|
||||
else
|
||||
{
|
||||
Node<K, V> parent = tmp.Parent;
|
||||
Node<K, V> ptr = tmp;
|
||||
Node<TKey, TValue> parent = tmp.Parent;
|
||||
Node<TKey, TValue> ptr = tmp;
|
||||
while (parent != null && ptr == parent.Right)
|
||||
{
|
||||
ptr = parent;
|
||||
|
@ -457,44 +460,44 @@ namespace Ryujinx.Common.Collections
|
|||
#region Interface Implementations
|
||||
|
||||
// Method descriptions are not provided as they are already included as part of the interface.
|
||||
public bool ContainsKey(K key)
|
||||
public bool ContainsKey(TKey key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
return GetNode(key) != null;
|
||||
}
|
||||
|
||||
bool IDictionary<K, V>.Remove(K key)
|
||||
bool IDictionary<TKey, TValue>.Remove(TKey key)
|
||||
{
|
||||
int count = Count;
|
||||
Remove(key);
|
||||
return count > Count;
|
||||
}
|
||||
|
||||
public bool TryGetValue(K key, [MaybeNullWhen(false)] out V value)
|
||||
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(key);
|
||||
|
||||
Node<K, V> node = GetNode(key);
|
||||
Node<TKey, TValue> node = GetNode(key);
|
||||
value = node != null ? node.Value : default;
|
||||
return node != null;
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<K, V> item)
|
||||
public void Add(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(item.Key);
|
||||
|
||||
Add(item.Key, item.Value);
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<K, V> item)
|
||||
public bool Contains(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
if (item.Key == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Node<K, V> node = GetNode(item.Key);
|
||||
Node<TKey, TValue> node = GetNode(item.Key);
|
||||
if (node != null)
|
||||
{
|
||||
return node.Key.Equals(item.Key) && node.Value.Equals(item.Value);
|
||||
|
@ -502,27 +505,27 @@ namespace Ryujinx.Common.Collections
|
|||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex)
|
||||
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
|
||||
{
|
||||
if (arrayIndex < 0 || array.Length - arrayIndex < this.Count)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(arrayIndex));
|
||||
}
|
||||
|
||||
SortedList<K, V> list = GetKeyValues();
|
||||
SortedList<TKey, TValue> list = GetKeyValues();
|
||||
|
||||
int offset = 0;
|
||||
|
||||
for (int i = arrayIndex; i < array.Length && offset < list.Count; i++)
|
||||
{
|
||||
array[i] = new KeyValuePair<K, V>(list.Keys[i], list.Values[i]);
|
||||
array[i] = new KeyValuePair<TKey, TValue>(list.Keys[i], list.Values[i]);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<K, V> item)
|
||||
public bool Remove(KeyValuePair<TKey, TValue> item)
|
||||
{
|
||||
Node<K, V> node = GetNode(item.Key);
|
||||
Node<TKey, TValue> node = GetNode(item.Key);
|
||||
|
||||
if (node == null)
|
||||
{
|
||||
|
@ -539,7 +542,7 @@ namespace Ryujinx.Common.Collections
|
|||
return false;
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
|
||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
|
||||
{
|
||||
return GetKeyValues().GetEnumerator();
|
||||
}
|
||||
|
@ -549,13 +552,13 @@ namespace Ryujinx.Common.Collections
|
|||
return GetKeyValues().GetEnumerator();
|
||||
}
|
||||
|
||||
public ICollection<K> Keys => GetKeyValues().Keys;
|
||||
public ICollection<TKey> Keys => GetKeyValues().Keys;
|
||||
|
||||
public ICollection<V> Values => GetKeyValues().Values;
|
||||
public ICollection<TValue> Values => GetKeyValues().Values;
|
||||
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public V this[K key]
|
||||
public TValue this[TKey key]
|
||||
{
|
||||
get => Get(key);
|
||||
set => Add(key, value);
|
||||
|
@ -569,16 +572,16 @@ namespace Ryujinx.Common.Collections
|
|||
/// Returns a sorted list of all the node keys / values in the tree.
|
||||
/// </summary>
|
||||
/// <returns>List of node keys</returns>
|
||||
private SortedList<K, V> GetKeyValues()
|
||||
private SortedList<TKey, TValue> GetKeyValues()
|
||||
{
|
||||
SortedList<K, V> set = new SortedList<K, V>();
|
||||
Queue<Node<K, V>> queue = new Queue<Node<K, V>>();
|
||||
SortedList<TKey, TValue> set = new();
|
||||
Queue<Node<TKey, TValue>> queue = new();
|
||||
if (Root != null)
|
||||
{
|
||||
queue.Enqueue(Root);
|
||||
}
|
||||
|
||||
while (queue.TryDequeue(out Node<K, V> node))
|
||||
while (queue.TryDequeue(out Node<TKey, TValue> node))
|
||||
{
|
||||
set.Add(node.Key, node.Value);
|
||||
if (null != node.Left)
|
||||
|
@ -600,14 +603,14 @@ namespace Ryujinx.Common.Collections
|
|||
/// <summary>
|
||||
/// Represents a node in the TreeDictionary which contains a key and value of generic type K and V, respectively.
|
||||
/// </summary>
|
||||
/// <typeparam name="K">Key of the node</typeparam>
|
||||
/// <typeparam name="V">Value of the node</typeparam>
|
||||
public class Node<K, V> : IntrusiveRedBlackTreeNode<Node<K, V>> where K : IComparable<K>
|
||||
/// <typeparam name="TKey">Key of the node</typeparam>
|
||||
/// <typeparam name="TValue">Value of the node</typeparam>
|
||||
public class Node<TKey, TValue> : IntrusiveRedBlackTreeNode<Node<TKey, TValue>> where TKey : IComparable<TKey>
|
||||
{
|
||||
internal K Key;
|
||||
internal V Value;
|
||||
internal TKey Key;
|
||||
internal TValue Value;
|
||||
|
||||
internal Node(K key, V value, Node<K, V> parent)
|
||||
internal Node(TKey key, TValue value, Node<TKey, TValue> parent)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
|
|
|
@ -11,6 +11,6 @@ namespace Ryujinx.Common.Configuration
|
|||
SmaaLow,
|
||||
SmaaMedium,
|
||||
SmaaHigh,
|
||||
SmaaUltra
|
||||
SmaaUltra,
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ namespace Ryujinx.Common.Configuration
|
|||
{
|
||||
UserProfile,
|
||||
Portable,
|
||||
Custom
|
||||
Custom,
|
||||
}
|
||||
|
||||
public static LaunchMode Mode { get; private set; }
|
||||
|
@ -34,7 +34,7 @@ namespace Ryujinx.Common.Configuration
|
|||
private const string DefaultModsDir = "mods";
|
||||
|
||||
public static string CustomModsPath { get; set; }
|
||||
public static string CustomSdModsPath {get; set; }
|
||||
public static string CustomSdModsPath { get; set; }
|
||||
public static string CustomNandPath { get; set; } // TODO: Actually implement this into VFS
|
||||
public static string CustomSdCardPath { get; set; } // TODO: Actually implement this into VFS
|
||||
|
||||
|
@ -151,7 +151,7 @@ namespace Ryujinx.Common.Configuration
|
|||
}
|
||||
}
|
||||
|
||||
public static string GetModsPath() => CustomModsPath ?? Directory.CreateDirectory(Path.Combine(BaseDirPath, DefaultModsDir)).FullName;
|
||||
public static string GetModsPath() => CustomModsPath ?? Directory.CreateDirectory(Path.Combine(BaseDirPath, DefaultModsDir)).FullName;
|
||||
public static string GetSdModsPath() => CustomSdModsPath ?? Directory.CreateDirectory(Path.Combine(BaseDirPath, DefaultSdcardDir, "atmosphere")).FullName;
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.Common.Configuration
|
|||
Fixed16x10,
|
||||
Fixed21x9,
|
||||
Fixed32x9,
|
||||
Stretched
|
||||
Stretched,
|
||||
}
|
||||
|
||||
public static class AspectRatioExtensions
|
||||
|
@ -25,12 +25,14 @@ namespace Ryujinx.Common.Configuration
|
|||
{
|
||||
return aspectRatio switch
|
||||
{
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
AspectRatio.Fixed4x3 => 4.0f,
|
||||
AspectRatio.Fixed16x9 => 16.0f,
|
||||
AspectRatio.Fixed16x10 => 16.0f,
|
||||
AspectRatio.Fixed21x9 => 21.0f,
|
||||
AspectRatio.Fixed32x9 => 32.0f,
|
||||
_ => 16.0f
|
||||
_ => 16.0f,
|
||||
#pragma warning restore IDE0055
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -38,12 +40,14 @@ namespace Ryujinx.Common.Configuration
|
|||
{
|
||||
return aspectRatio switch
|
||||
{
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
AspectRatio.Fixed4x3 => 3.0f,
|
||||
AspectRatio.Fixed16x9 => 9.0f,
|
||||
AspectRatio.Fixed16x10 => 10.0f,
|
||||
AspectRatio.Fixed21x9 => 9.0f,
|
||||
AspectRatio.Fixed32x9 => 9.0f,
|
||||
_ => 9.0f
|
||||
_ => 9.0f,
|
||||
#pragma warning restore IDE0055
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -51,12 +55,14 @@ namespace Ryujinx.Common.Configuration
|
|||
{
|
||||
return aspectRatio switch
|
||||
{
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
AspectRatio.Fixed4x3 => "4:3",
|
||||
AspectRatio.Fixed16x9 => "16:9",
|
||||
AspectRatio.Fixed16x10 => "16:10",
|
||||
AspectRatio.Fixed21x9 => "21:9",
|
||||
AspectRatio.Fixed32x9 => "32:9",
|
||||
_ => "Stretched"
|
||||
_ => "Stretched",
|
||||
#pragma warning restore IDE0055
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ namespace Ryujinx.Common.Configuration
|
|||
[JsonPropertyName("path")]
|
||||
public string FullPath { get; set; }
|
||||
[JsonPropertyName("title_id")]
|
||||
public ulong TitleId { get; set; }
|
||||
public ulong TitleId { get; set; }
|
||||
[JsonPropertyName("is_enabled")]
|
||||
public bool Enabled { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
}
|
||||
}
|
|
@ -53,6 +53,6 @@ namespace Ryujinx.Common.Configuration.Hid.Controller
|
|||
SingleLeftTrigger1,
|
||||
SingleRightTrigger1,
|
||||
|
||||
Count
|
||||
Count,
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ using System.Text.Json.Serialization;
|
|||
|
||||
namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||
{
|
||||
public class GenericControllerInputConfig<Button, Stick> : GenericInputConfigurationCommon<Button> where Button : unmanaged where Stick : unmanaged
|
||||
public class GenericControllerInputConfig<TButton, TStick> : GenericInputConfigurationCommon<TButton> where TButton : unmanaged where TStick : unmanaged
|
||||
{
|
||||
[JsonIgnore]
|
||||
private float _deadzoneLeft;
|
||||
|
@ -16,12 +16,12 @@ namespace Ryujinx.Common.Configuration.Hid.Controller
|
|||
/// <summary>
|
||||
/// Left JoyCon Controller Stick Bindings
|
||||
/// </summary>
|
||||
public JoyconConfigControllerStick<Button, Stick> LeftJoyconStick { get; set; }
|
||||
public JoyconConfigControllerStick<TButton, TStick> LeftJoyconStick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Right JoyCon Controller Stick Bindings
|
||||
/// </summary>
|
||||
public JoyconConfigControllerStick<Button, Stick> RightJoyconStick { get; set; }
|
||||
public JoyconConfigControllerStick<TButton, TStick> RightJoyconStick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Controller Left Analog Stick Deadzone
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||
{
|
||||
public class JoyconConfigControllerStick<Button, Stick> where Button: unmanaged where Stick: unmanaged
|
||||
public class JoyconConfigControllerStick<TButton, TStick> where TButton : unmanaged where TStick : unmanaged
|
||||
{
|
||||
public Stick Joystick { get; set; }
|
||||
public TStick Joystick { get; set; }
|
||||
public bool InvertStickX { get; set; }
|
||||
public bool InvertStickY { get; set; }
|
||||
public bool Rotate90CW { get; set; }
|
||||
public Button StickButton { get; set; }
|
||||
public TButton StickButton { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
|||
{
|
||||
class JsonMotionConfigControllerConverter : JsonConverter<MotionConfigController>
|
||||
{
|
||||
private static readonly MotionConfigJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||
private static readonly MotionConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||
|
||||
private static MotionInputBackendType GetMotionInputBackendType(ref Utf8JsonReader reader)
|
||||
{
|
||||
|
@ -55,8 +55,8 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
|||
|
||||
return motionBackendType switch
|
||||
{
|
||||
MotionInputBackendType.GamepadDriver => JsonSerializer.Deserialize(ref reader, SerializerContext.StandardMotionConfigController),
|
||||
MotionInputBackendType.CemuHook => JsonSerializer.Deserialize(ref reader, SerializerContext.CemuHookMotionConfigController),
|
||||
MotionInputBackendType.GamepadDriver => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardMotionConfigController),
|
||||
MotionInputBackendType.CemuHook => JsonSerializer.Deserialize(ref reader, _serializerContext.CemuHookMotionConfigController),
|
||||
_ => throw new InvalidOperationException($"Unknown backend type {motionBackendType}"),
|
||||
};
|
||||
}
|
||||
|
@ -66,10 +66,10 @@ namespace Ryujinx.Common.Configuration.Hid.Controller.Motion
|
|||
switch (value.MotionBackend)
|
||||
{
|
||||
case MotionInputBackendType.GamepadDriver:
|
||||
JsonSerializer.Serialize(writer, value as StandardMotionConfigController, SerializerContext.StandardMotionConfigController);
|
||||
JsonSerializer.Serialize(writer, value as StandardMotionConfigController, _serializerContext.StandardMotionConfigController);
|
||||
break;
|
||||
case MotionInputBackendType.CemuHook:
|
||||
JsonSerializer.Serialize(writer, value as CemuHookMotionConfigController, SerializerContext.CemuHookMotionConfigController);
|
||||
JsonSerializer.Serialize(writer, value as CemuHookMotionConfigController, _serializerContext.CemuHookMotionConfigController);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException($"Unknown motion backend type {value.MotionBackend}");
|
||||
|
|
|
@ -10,6 +10,6 @@ namespace Ryujinx.Common.Configuration.Hid.Controller
|
|||
Left,
|
||||
Right,
|
||||
|
||||
Count
|
||||
Count,
|
||||
}
|
||||
}
|
|
@ -10,14 +10,14 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||
public enum ControllerType
|
||||
{
|
||||
None,
|
||||
ProController = 1 << 0,
|
||||
Handheld = 1 << 1,
|
||||
JoyconPair = 1 << 2,
|
||||
JoyconLeft = 1 << 3,
|
||||
JoyconRight = 1 << 4,
|
||||
Invalid = 1 << 5,
|
||||
Pokeball = 1 << 6,
|
||||
ProController = 1 << 0,
|
||||
Handheld = 1 << 1,
|
||||
JoyconPair = 1 << 2,
|
||||
JoyconLeft = 1 << 3,
|
||||
JoyconRight = 1 << 4,
|
||||
Invalid = 1 << 5,
|
||||
Pokeball = 1 << 6,
|
||||
SystemExternal = 1 << 29,
|
||||
System = 1 << 30
|
||||
System = 1 << 30,
|
||||
}
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
public class GenericInputConfigurationCommon<Button> : InputConfig where Button : unmanaged
|
||||
public class GenericInputConfigurationCommon<TButton> : InputConfig where TButton : unmanaged
|
||||
{
|
||||
/// <summary>
|
||||
/// Left JoyCon Controller Bindings
|
||||
/// </summary>
|
||||
public LeftJoyconCommonConfig<Button> LeftJoycon { get; set; }
|
||||
public LeftJoyconCommonConfig<TButton> LeftJoycon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Right JoyCon Controller Bindings
|
||||
/// </summary>
|
||||
public RightJoyconCommonConfig<Button> RightJoycon { get; set; }
|
||||
public RightJoyconCommonConfig<TButton> RightJoycon { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||
{
|
||||
public class JsonInputConfigConverter : JsonConverter<InputConfig>
|
||||
{
|
||||
private static readonly InputConfigJsonSerializerContext SerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||
|
||||
private static InputBackendType GetInputBackendType(ref Utf8JsonReader reader)
|
||||
{
|
||||
|
@ -57,8 +57,8 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||
|
||||
return backendType switch
|
||||
{
|
||||
InputBackendType.WindowKeyboard => JsonSerializer.Deserialize(ref reader, SerializerContext.StandardKeyboardInputConfig),
|
||||
InputBackendType.GamepadSDL2 => JsonSerializer.Deserialize(ref reader, SerializerContext.StandardControllerInputConfig),
|
||||
InputBackendType.WindowKeyboard => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardKeyboardInputConfig),
|
||||
InputBackendType.GamepadSDL2 => JsonSerializer.Deserialize(ref reader, _serializerContext.StandardControllerInputConfig),
|
||||
_ => throw new InvalidOperationException($"Unknown backend type {backendType}"),
|
||||
};
|
||||
}
|
||||
|
@ -68,10 +68,10 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||
switch (value.Backend)
|
||||
{
|
||||
case InputBackendType.WindowKeyboard:
|
||||
JsonSerializer.Serialize(writer, value as StandardKeyboardInputConfig, SerializerContext.StandardKeyboardInputConfig);
|
||||
JsonSerializer.Serialize(writer, value as StandardKeyboardInputConfig, _serializerContext.StandardKeyboardInputConfig);
|
||||
break;
|
||||
case InputBackendType.GamepadSDL2:
|
||||
JsonSerializer.Serialize(writer, value as StandardControllerInputConfig, SerializerContext.StandardControllerInputConfig);
|
||||
JsonSerializer.Serialize(writer, value as StandardControllerInputConfig, _serializerContext.StandardControllerInputConfig);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException($"Unknown backend type {value.Backend}");
|
||||
|
|
|
@ -138,6 +138,6 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||
BackSlash,
|
||||
Unbound,
|
||||
|
||||
Count
|
||||
Count,
|
||||
}
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
namespace Ryujinx.Common.Configuration.Hid.Keyboard
|
||||
{
|
||||
public class GenericKeyboardInputConfig<Key> : GenericInputConfigurationCommon<Key> where Key : unmanaged
|
||||
public class GenericKeyboardInputConfig<TKey> : GenericInputConfigurationCommon<TKey> where TKey : unmanaged
|
||||
{
|
||||
/// <summary>
|
||||
/// Left JoyCon Controller Stick Bindings
|
||||
/// </summary>
|
||||
public JoyconConfigKeyboardStick<Key> LeftJoyconStick { get; set; }
|
||||
public JoyconConfigKeyboardStick<TKey> LeftJoyconStick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Right JoyCon Controller Stick Bindings
|
||||
/// </summary>
|
||||
public JoyconConfigKeyboardStick<Key> RightJoyconStick { get; set; }
|
||||
public JoyconConfigKeyboardStick<TKey> RightJoyconStick { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
namespace Ryujinx.Common.Configuration.Hid.Keyboard
|
||||
{
|
||||
public class JoyconConfigKeyboardStick<Key> where Key: unmanaged
|
||||
public class JoyconConfigKeyboardStick<TKey> where TKey : unmanaged
|
||||
{
|
||||
public Key StickUp { get; set; }
|
||||
public Key StickDown { get; set; }
|
||||
public Key StickLeft { get; set; }
|
||||
public Key StickRight { get; set; }
|
||||
public Key StickButton { get; set; }
|
||||
public TKey StickUp { get; set; }
|
||||
public TKey StickDown { get; set; }
|
||||
public TKey StickLeft { get; set; }
|
||||
public TKey StickRight { get; set; }
|
||||
public TKey StickButton { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
public class LeftJoyconCommonConfig<Button>
|
||||
public class LeftJoyconCommonConfig<TButton>
|
||||
{
|
||||
public Button ButtonMinus { get; set; }
|
||||
public Button ButtonL { get; set; }
|
||||
public Button ButtonZl { get; set; }
|
||||
public Button ButtonSl { get; set; }
|
||||
public Button ButtonSr { get; set; }
|
||||
public Button DpadUp { get; set; }
|
||||
public Button DpadDown { get; set; }
|
||||
public Button DpadLeft { get; set; }
|
||||
public Button DpadRight { get; set; }
|
||||
public TButton ButtonMinus { get; set; }
|
||||
public TButton ButtonL { get; set; }
|
||||
public TButton ButtonZl { get; set; }
|
||||
public TButton ButtonSl { get; set; }
|
||||
public TButton ButtonSr { get; set; }
|
||||
public TButton DpadUp { get; set; }
|
||||
public TButton DpadDown { get; set; }
|
||||
public TButton DpadLeft { get; set; }
|
||||
public TButton DpadRight { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,16 +7,16 @@ namespace Ryujinx.Common.Configuration.Hid
|
|||
[JsonConverter(typeof(TypedStringEnumConverter<PlayerIndex>))]
|
||||
public enum PlayerIndex
|
||||
{
|
||||
Player1 = 0,
|
||||
Player2 = 1,
|
||||
Player3 = 2,
|
||||
Player4 = 3,
|
||||
Player5 = 4,
|
||||
Player6 = 5,
|
||||
Player7 = 6,
|
||||
Player8 = 7,
|
||||
Player1 = 0,
|
||||
Player2 = 1,
|
||||
Player3 = 2,
|
||||
Player4 = 3,
|
||||
Player5 = 4,
|
||||
Player6 = 5,
|
||||
Player7 = 6,
|
||||
Player8 = 7,
|
||||
Handheld = 8,
|
||||
Unknown = 9,
|
||||
Auto = 10 // Shouldn't be used directly
|
||||
Unknown = 9,
|
||||
Auto = 10, // Shouldn't be used directly
|
||||
}
|
||||
}
|
|
@ -1,15 +1,15 @@
|
|||
namespace Ryujinx.Common.Configuration.Hid
|
||||
{
|
||||
public class RightJoyconCommonConfig<Button>
|
||||
public class RightJoyconCommonConfig<TButton>
|
||||
{
|
||||
public Button ButtonPlus { get; set; }
|
||||
public Button ButtonR { get; set; }
|
||||
public Button ButtonZr { get; set; }
|
||||
public Button ButtonSl { get; set; }
|
||||
public Button ButtonSr { get; set; }
|
||||
public Button ButtonX { get; set; }
|
||||
public Button ButtonB { get; set; }
|
||||
public Button ButtonY { get; set; }
|
||||
public Button ButtonA { get; set; }
|
||||
public TButton ButtonPlus { get; set; }
|
||||
public TButton ButtonR { get; set; }
|
||||
public TButton ButtonZr { get; set; }
|
||||
public TButton ButtonSl { get; set; }
|
||||
public TButton ButtonSr { get; set; }
|
||||
public TButton ButtonX { get; set; }
|
||||
public TButton ButtonB { get; set; }
|
||||
public TButton ButtonY { get; set; }
|
||||
public TButton ButtonA { get; set; }
|
||||
}
|
||||
}
|
|
@ -4,6 +4,6 @@ namespace Ryujinx.Common.Configuration
|
|||
{
|
||||
Never,
|
||||
OnIdle,
|
||||
Always
|
||||
Always,
|
||||
}
|
||||
}
|
|
@ -8,6 +8,6 @@ namespace Ryujinx.Common.Configuration
|
|||
{
|
||||
Bilinear,
|
||||
Nearest,
|
||||
Fsr
|
||||
Fsr,
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ namespace Ryujinx.Common.Configuration
|
|||
{
|
||||
public struct TitleUpdateMetadata
|
||||
{
|
||||
public string Selected { get; set; }
|
||||
public List<string> Paths { get; set; }
|
||||
public string Selected { get; set; }
|
||||
public List<string> Paths { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
@ -7,8 +6,7 @@ namespace Ryujinx.Common
|
|||
{
|
||||
public static class BinaryReaderExtensions
|
||||
{
|
||||
public unsafe static T ReadStruct<T>(this BinaryReader reader)
|
||||
where T : unmanaged
|
||||
public static T ReadStruct<T>(this BinaryReader reader) where T : unmanaged
|
||||
{
|
||||
return MemoryMarshal.Cast<byte, T>(reader.ReadBytes(Unsafe.SizeOf<T>()))[0];
|
||||
}
|
||||
|
|
|
@ -6,8 +6,7 @@ namespace Ryujinx.Common
|
|||
{
|
||||
public static class BinaryWriterExtensions
|
||||
{
|
||||
public unsafe static void WriteStruct<T>(this BinaryWriter writer, T value)
|
||||
where T : unmanaged
|
||||
public static void WriteStruct<T>(this BinaryWriter writer, T value) where T : unmanaged
|
||||
{
|
||||
ReadOnlySpan<byte> data = MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Common.GraphicsDriver.NVAPI
|
|||
Set(text);
|
||||
}
|
||||
|
||||
public string Get()
|
||||
public readonly string Get()
|
||||
{
|
||||
fixed (byte* data = _data)
|
||||
{
|
||||
|
@ -29,7 +29,7 @@ namespace Ryujinx.Common.GraphicsDriver.NVAPI
|
|||
}
|
||||
}
|
||||
|
||||
public void Set(string text)
|
||||
public readonly void Set(string text)
|
||||
{
|
||||
text += '\0';
|
||||
fixed (char* textPtr = text)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Ryujinx.Common.GraphicsDriver.NVAPI
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
unsafe struct NvdrsApplicationV4
|
||||
struct NvdrsApplicationV4
|
||||
{
|
||||
public uint Version;
|
||||
public uint IsPredefined;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Ryujinx.Common.GraphicsDriver.NVAPI
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
unsafe struct NvdrsProfile
|
||||
struct NvdrsProfile
|
||||
{
|
||||
public uint Version;
|
||||
public NvapiUnicodeString ProfileName;
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Ryujinx.Common.GraphicsDriver.NVAPI
|
|||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x3020)]
|
||||
unsafe struct NvdrsSetting
|
||||
struct NvdrsSetting
|
||||
{
|
||||
[FieldOffset(0x0)]
|
||||
public uint Version;
|
||||
|
|
|
@ -97,27 +97,26 @@ namespace Ryujinx.Common.GraphicsDriver
|
|||
|
||||
Check(NvAPI_DRS_LoadSettings(handle));
|
||||
|
||||
IntPtr profileHandle;
|
||||
|
||||
// Check if the profile already exists.
|
||||
|
||||
int status = NvAPI_DRS_FindProfileByName(handle, new NvapiUnicodeString(ProfileName), out profileHandle);
|
||||
int status = NvAPI_DRS_FindProfileByName(handle, new NvapiUnicodeString(ProfileName), out nint profileHandle);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
NvdrsProfile profile = new NvdrsProfile {
|
||||
NvdrsProfile profile = new()
|
||||
{
|
||||
Version = MakeVersion<NvdrsProfile>(1),
|
||||
IsPredefined = 0,
|
||||
GpuSupport = uint.MaxValue
|
||||
GpuSupport = uint.MaxValue,
|
||||
};
|
||||
profile.ProfileName.Set(ProfileName);
|
||||
Check(NvAPI_DRS_CreateProfile(handle, ref profile, out profileHandle));
|
||||
|
||||
NvdrsApplicationV4 application = new NvdrsApplicationV4
|
||||
NvdrsApplicationV4 application = new()
|
||||
{
|
||||
Version = MakeVersion<NvdrsApplicationV4>(4),
|
||||
IsPredefined = 0,
|
||||
Flags = 3 // IsMetro, IsCommandLine
|
||||
Flags = 3, // IsMetro, IsCommandLine
|
||||
};
|
||||
application.AppName.Set("Ryujinx.exe");
|
||||
application.UserFriendlyName.Set("Ryujinx");
|
||||
|
@ -127,7 +126,7 @@ namespace Ryujinx.Common.GraphicsDriver
|
|||
Check(NvAPI_DRS_CreateApplication(handle, profileHandle, ref application));
|
||||
}
|
||||
|
||||
NvdrsSetting setting = new NvdrsSetting
|
||||
NvdrsSetting setting = new()
|
||||
{
|
||||
Version = MakeVersion<NvdrsSetting>(1),
|
||||
SettingId = Nvapi.OglThreadControlId,
|
||||
|
@ -136,7 +135,7 @@ namespace Ryujinx.Common.GraphicsDriver
|
|||
IsCurrentPredefined = 0,
|
||||
IsPredefinedValid = 0,
|
||||
CurrentValue = targetValue,
|
||||
PredefinedValue = targetValue
|
||||
PredefinedValue = targetValue,
|
||||
};
|
||||
|
||||
Check(NvAPI_DRS_SetSetting(handle, profileHandle, ref setting));
|
||||
|
@ -154,10 +153,8 @@ namespace Ryujinx.Common.GraphicsDriver
|
|||
{
|
||||
return Marshal.GetDelegateForFunctionPointer<T>(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Ryujinx.Common
|
|||
High = high;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
public readonly override string ToString()
|
||||
{
|
||||
return $"{High:x16}{Low:x16}";
|
||||
}
|
||||
|
@ -30,17 +30,17 @@ namespace Ryujinx.Common
|
|||
return !x.Equals(y);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public readonly override bool Equals(object obj)
|
||||
{
|
||||
return obj is Hash128 hash128 && Equals(hash128);
|
||||
}
|
||||
|
||||
public bool Equals(Hash128 cmpObj)
|
||||
public readonly bool Equals(Hash128 cmpObj)
|
||||
{
|
||||
return Low == cmpObj.Low && High == cmpObj.High;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
public readonly override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Low, High);
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@ namespace Ryujinx.Common.Logging.Formatters
|
|||
{
|
||||
internal class DefaultLogFormatter : ILogFormatter
|
||||
{
|
||||
private static readonly ObjectPool<StringBuilder> StringBuilderPool = SharedPools.Default<StringBuilder>();
|
||||
private static readonly ObjectPool<StringBuilder> _stringBuilderPool = SharedPools.Default<StringBuilder>();
|
||||
|
||||
public string Format(LogEventArgs args)
|
||||
{
|
||||
StringBuilder sb = StringBuilderPool.Allocate();
|
||||
StringBuilder sb = _stringBuilderPool.Allocate();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -44,7 +44,7 @@ namespace Ryujinx.Common.Logging.Formatters
|
|||
}
|
||||
finally
|
||||
{
|
||||
StringBuilderPool.Release(sb);
|
||||
_stringBuilderPool.Release(sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.Common.Logging.Formatters
|
|||
{
|
||||
internal static class DynamicObjectFormatter
|
||||
{
|
||||
private static readonly ObjectPool<StringBuilder> StringBuilderPool = SharedPools.Default<StringBuilder>();
|
||||
private static readonly ObjectPool<StringBuilder> _stringBuilderPool = SharedPools.Default<StringBuilder>();
|
||||
|
||||
public static string? Format(object? dynamicObject)
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ namespace Ryujinx.Common.Logging.Formatters
|
|||
return null;
|
||||
}
|
||||
|
||||
StringBuilder sb = StringBuilderPool.Allocate();
|
||||
StringBuilder sb = _stringBuilderPool.Allocate();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -26,7 +26,7 @@ namespace Ryujinx.Common.Logging.Formatters
|
|||
}
|
||||
finally
|
||||
{
|
||||
StringBuilderPool.Release(sb);
|
||||
_stringBuilderPool.Release(sb);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ namespace Ryujinx.Common.Logging.Formatters
|
|||
|
||||
if (typeof(Array).IsAssignableFrom(prop.PropertyType))
|
||||
{
|
||||
Array? array = (Array?) prop.GetValue(dynamicObject);
|
||||
Array? array = (Array?)prop.GetValue(dynamicObject);
|
||||
|
||||
if (array is not null)
|
||||
{
|
||||
|
|
|
@ -71,6 +71,6 @@ namespace Ryujinx.Common.Logging
|
|||
SurfaceFlinger,
|
||||
TamperMachine,
|
||||
Ui,
|
||||
Vic
|
||||
Vic,
|
||||
}
|
||||
}
|
|
@ -6,18 +6,18 @@ namespace Ryujinx.Common.Logging
|
|||
{
|
||||
public readonly LogLevel Level;
|
||||
public readonly TimeSpan Time;
|
||||
public readonly string ThreadName;
|
||||
public readonly string ThreadName;
|
||||
|
||||
public readonly string Message;
|
||||
public readonly object Data;
|
||||
|
||||
public LogEventArgs(LogLevel level, TimeSpan time, string threadName, string message, object data = null)
|
||||
{
|
||||
Level = level;
|
||||
Time = time;
|
||||
Level = level;
|
||||
Time = time;
|
||||
ThreadName = threadName;
|
||||
Message = message;
|
||||
Data = data;
|
||||
Message = message;
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.Common.Logging
|
|||
{
|
||||
public LogLevel Level { get; }
|
||||
public TimeSpan Time { get; }
|
||||
public string ThreadName { get; }
|
||||
public string ThreadName { get; }
|
||||
|
||||
public string Message { get; }
|
||||
public string Data { get; }
|
||||
|
@ -16,11 +16,11 @@ namespace Ryujinx.Common.Logging
|
|||
[JsonConstructor]
|
||||
public LogEventArgsJson(LogLevel level, TimeSpan time, string threadName, string message, string data = null)
|
||||
{
|
||||
Level = level;
|
||||
Time = time;
|
||||
Level = level;
|
||||
Time = time;
|
||||
ThreadName = threadName;
|
||||
Message = message;
|
||||
Data = data;
|
||||
Message = message;
|
||||
Data = data;
|
||||
}
|
||||
|
||||
public static LogEventArgsJson FromLogEventArgs(LogEventArgs args)
|
||||
|
|
|
@ -10,11 +10,11 @@ namespace Ryujinx.Common.Logging
|
|||
{
|
||||
public static class Logger
|
||||
{
|
||||
private static readonly Stopwatch m_Time;
|
||||
private static readonly Stopwatch _time;
|
||||
|
||||
private static readonly bool[] m_EnabledClasses;
|
||||
private static readonly bool[] _enabledClasses;
|
||||
|
||||
private static readonly List<ILogTarget> m_LogTargets;
|
||||
private static readonly List<ILogTarget> _logTargets;
|
||||
|
||||
private static readonly StdErrAdapter _stdErrAdapter;
|
||||
|
||||
|
@ -32,27 +32,27 @@ namespace Ryujinx.Common.Logging
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void PrintMsg(LogClass logClass, string message)
|
||||
{
|
||||
if (m_EnabledClasses[(int)logClass])
|
||||
if (_enabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, "", message)));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, "", message)));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Print(LogClass logClass, string message, [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (m_EnabledClasses[(int)logClass])
|
||||
if (_enabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message)));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message)));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Print(LogClass logClass, string message, object data, [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (m_EnabledClasses[(int)logClass])
|
||||
if (_enabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message), data));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message), data));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,71 +60,71 @@ namespace Ryujinx.Common.Logging
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void PrintStack(LogClass logClass, string message, [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (m_EnabledClasses[(int)logClass])
|
||||
if (_enabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message), new StackTrace(true)));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, message), new StackTrace(true)));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void PrintStub(LogClass logClass, string message = "", [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (m_EnabledClasses[(int)logClass])
|
||||
if (_enabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed. " + message)));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed. " + message)));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void PrintStub(LogClass logClass, object data, [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (m_EnabledClasses[(int)logClass])
|
||||
if (_enabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed."), data));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed."), data));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void PrintStub(LogClass logClass, string message, object data, [CallerMemberName] string caller = "")
|
||||
{
|
||||
if (m_EnabledClasses[(int)logClass])
|
||||
if (_enabledClasses[(int)logClass])
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed. " + message), data));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, caller, "Stubbed. " + message), data));
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void PrintRawMsg(string message)
|
||||
{
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, m_Time.Elapsed, Thread.CurrentThread.Name, message));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, message));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static string FormatMessage(LogClass Class, string Caller, string Message) => $"{Class} {Caller}: {Message}";
|
||||
private static string FormatMessage(LogClass logClass, string caller, string message) => $"{logClass} {caller}: {message}";
|
||||
}
|
||||
|
||||
public static Log? Debug { get; private set; }
|
||||
public static Log? Info { get; private set; }
|
||||
public static Log? Warning { get; private set; }
|
||||
public static Log? Error { get; private set; }
|
||||
public static Log? Guest { get; private set; }
|
||||
public static Log? Debug { get; private set; }
|
||||
public static Log? Info { get; private set; }
|
||||
public static Log? Warning { get; private set; }
|
||||
public static Log? Error { get; private set; }
|
||||
public static Log? Guest { get; private set; }
|
||||
public static Log? AccessLog { get; private set; }
|
||||
public static Log? Stub { get; private set; }
|
||||
public static Log? Trace { get; private set; }
|
||||
public static Log Notice { get; } // Always enabled
|
||||
public static Log? Stub { get; private set; }
|
||||
public static Log? Trace { get; private set; }
|
||||
public static Log Notice { get; } // Always enabled
|
||||
|
||||
static Logger()
|
||||
{
|
||||
m_EnabledClasses = new bool[Enum.GetNames<LogClass>().Length];
|
||||
_enabledClasses = new bool[Enum.GetNames<LogClass>().Length];
|
||||
|
||||
for (int index = 0; index < m_EnabledClasses.Length; index++)
|
||||
for (int index = 0; index < _enabledClasses.Length; index++)
|
||||
{
|
||||
m_EnabledClasses[index] = true;
|
||||
_enabledClasses[index] = true;
|
||||
}
|
||||
|
||||
m_LogTargets = new List<ILogTarget>();
|
||||
_logTargets = new List<ILogTarget>();
|
||||
|
||||
m_Time = Stopwatch.StartNew();
|
||||
_time = Stopwatch.StartNew();
|
||||
|
||||
// Logger should log to console by default
|
||||
AddTarget(new AsyncLogTargetWrapper(
|
||||
|
@ -145,12 +145,12 @@ namespace Ryujinx.Common.Logging
|
|||
|
||||
public static void RestartTime()
|
||||
{
|
||||
m_Time.Restart();
|
||||
_time.Restart();
|
||||
}
|
||||
|
||||
private static ILogTarget GetTarget(string targetName)
|
||||
{
|
||||
foreach (var target in m_LogTargets)
|
||||
foreach (var target in _logTargets)
|
||||
{
|
||||
if (target.Name.Equals(targetName))
|
||||
{
|
||||
|
@ -163,7 +163,7 @@ namespace Ryujinx.Common.Logging
|
|||
|
||||
public static void AddTarget(ILogTarget target)
|
||||
{
|
||||
m_LogTargets.Add(target);
|
||||
_logTargets.Add(target);
|
||||
|
||||
Updated += target.Log;
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ namespace Ryujinx.Common.Logging
|
|||
{
|
||||
Updated -= logTarget.Log;
|
||||
|
||||
m_LogTargets.Remove(logTarget);
|
||||
_logTargets.Remove(logTarget);
|
||||
|
||||
logTarget.Dispose();
|
||||
}
|
||||
|
@ -188,18 +188,18 @@ namespace Ryujinx.Common.Logging
|
|||
|
||||
_stdErrAdapter.Dispose();
|
||||
|
||||
foreach (var target in m_LogTargets)
|
||||
foreach (var target in _logTargets)
|
||||
{
|
||||
target.Dispose();
|
||||
}
|
||||
|
||||
m_LogTargets.Clear();
|
||||
_logTargets.Clear();
|
||||
}
|
||||
|
||||
public static IReadOnlyCollection<LogLevel> GetEnabledLevels()
|
||||
{
|
||||
var logs = new Log?[] { Debug, Info, Warning, Error, Guest, AccessLog, Stub, Trace };
|
||||
List<LogLevel> levels = new List<LogLevel>(logs.Length);
|
||||
var logs = new[] { Debug, Info, Warning, Error, Guest, AccessLog, Stub, Trace };
|
||||
List<LogLevel> levels = new(logs.Length);
|
||||
foreach (var log in logs)
|
||||
{
|
||||
if (log.HasValue)
|
||||
|
@ -215,21 +215,23 @@ namespace Ryujinx.Common.Logging
|
|||
{
|
||||
switch (logLevel)
|
||||
{
|
||||
case LogLevel.Debug : Debug = enabled ? new Log(LogLevel.Debug) : new Log?(); break;
|
||||
case LogLevel.Info : Info = enabled ? new Log(LogLevel.Info) : new Log?(); break;
|
||||
case LogLevel.Warning : Warning = enabled ? new Log(LogLevel.Warning) : new Log?(); break;
|
||||
case LogLevel.Error : Error = enabled ? new Log(LogLevel.Error) : new Log?(); break;
|
||||
case LogLevel.Guest : Guest = enabled ? new Log(LogLevel.Guest) : new Log?(); break;
|
||||
case LogLevel.AccessLog : AccessLog = enabled ? new Log(LogLevel.AccessLog): new Log?(); break;
|
||||
case LogLevel.Stub : Stub = enabled ? new Log(LogLevel.Stub) : new Log?(); break;
|
||||
case LogLevel.Trace : Trace = enabled ? new Log(LogLevel.Trace) : new Log?(); break;
|
||||
#pragma warning disable IDE0055 // Disable formatting
|
||||
case LogLevel.Debug : Debug = enabled ? new Log(LogLevel.Debug) : new Log?(); break;
|
||||
case LogLevel.Info : Info = enabled ? new Log(LogLevel.Info) : new Log?(); break;
|
||||
case LogLevel.Warning : Warning = enabled ? new Log(LogLevel.Warning) : new Log?(); break;
|
||||
case LogLevel.Error : Error = enabled ? new Log(LogLevel.Error) : new Log?(); break;
|
||||
case LogLevel.Guest : Guest = enabled ? new Log(LogLevel.Guest) : new Log?(); break;
|
||||
case LogLevel.AccessLog : AccessLog = enabled ? new Log(LogLevel.AccessLog) : new Log?(); break;
|
||||
case LogLevel.Stub : Stub = enabled ? new Log(LogLevel.Stub) : new Log?(); break;
|
||||
case LogLevel.Trace : Trace = enabled ? new Log(LogLevel.Trace) : new Log?(); break;
|
||||
default: throw new ArgumentException("Unknown Log Level");
|
||||
#pragma warning restore IDE0055
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetEnable(LogClass logClass, bool enabled)
|
||||
{
|
||||
m_EnabledClasses[(int)logClass] = enabled;
|
||||
_enabledClasses[(int)logClass] = enabled;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,16 +14,16 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
/// <summary>
|
||||
/// Discard the overflowing item
|
||||
/// </summary>
|
||||
Discard = 1
|
||||
Discard = 1,
|
||||
}
|
||||
|
||||
public class AsyncLogTargetWrapper : ILogTarget
|
||||
{
|
||||
private ILogTarget _target;
|
||||
private readonly ILogTarget _target;
|
||||
|
||||
private Thread _messageThread;
|
||||
private readonly Thread _messageThread;
|
||||
|
||||
private BlockingCollection<LogEventArgs> _messageQueue;
|
||||
private readonly BlockingCollection<LogEventArgs> _messageQueue;
|
||||
|
||||
private readonly int _overflowTimeout;
|
||||
|
||||
|
@ -35,11 +35,12 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
|
||||
public AsyncLogTargetWrapper(ILogTarget target, int queueLimit, AsyncLogTargetOverflowAction overflowAction)
|
||||
{
|
||||
_target = target;
|
||||
_messageQueue = new BlockingCollection<LogEventArgs>(queueLimit);
|
||||
_target = target;
|
||||
_messageQueue = new BlockingCollection<LogEventArgs>(queueLimit);
|
||||
_overflowTimeout = overflowAction == AsyncLogTargetOverflowAction.Block ? -1 : 0;
|
||||
|
||||
_messageThread = new Thread(() => {
|
||||
_messageThread = new Thread(() =>
|
||||
{
|
||||
while (!_messageQueue.IsCompleted)
|
||||
{
|
||||
try
|
||||
|
@ -55,10 +56,11 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
// on the next iteration.
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_messageThread.Name = "Logger.MessageThread";
|
||||
_messageThread.IsBackground = true;
|
||||
})
|
||||
{
|
||||
Name = "Logger.MessageThread",
|
||||
IsBackground = true,
|
||||
};
|
||||
_messageThread.Start();
|
||||
}
|
||||
|
||||
|
@ -72,6 +74,7 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
_messageQueue.CompleteAdding();
|
||||
_messageThread.Join();
|
||||
}
|
||||
|
|
|
@ -11,20 +11,21 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
|
||||
string ILogTarget.Name { get => _name; }
|
||||
|
||||
private static ConsoleColor GetLogColor(LogLevel level) => level switch {
|
||||
LogLevel.Info => ConsoleColor.White,
|
||||
private static ConsoleColor GetLogColor(LogLevel level) => level switch
|
||||
{
|
||||
LogLevel.Info => ConsoleColor.White,
|
||||
LogLevel.Warning => ConsoleColor.Yellow,
|
||||
LogLevel.Error => ConsoleColor.Red,
|
||||
LogLevel.Stub => ConsoleColor.DarkGray,
|
||||
LogLevel.Notice => ConsoleColor.Cyan,
|
||||
LogLevel.Trace => ConsoleColor.DarkCyan,
|
||||
_ => ConsoleColor.Gray,
|
||||
LogLevel.Error => ConsoleColor.Red,
|
||||
LogLevel.Stub => ConsoleColor.DarkGray,
|
||||
LogLevel.Notice => ConsoleColor.Cyan,
|
||||
LogLevel.Trace => ConsoleColor.DarkCyan,
|
||||
_ => ConsoleColor.Gray,
|
||||
};
|
||||
|
||||
public ConsoleLogTarget(string name)
|
||||
{
|
||||
_formatter = new DefaultLogFormatter();
|
||||
_name = name;
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public void Log(object sender, LogEventArgs args)
|
||||
|
@ -36,6 +37,7 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
Console.ResetColor();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
{
|
||||
public class FileLogTarget : ILogTarget
|
||||
{
|
||||
private readonly StreamWriter _logWriter;
|
||||
private readonly StreamWriter _logWriter;
|
||||
private readonly ILogFormatter _formatter;
|
||||
private readonly string _name;
|
||||
private readonly string _name;
|
||||
|
||||
string ILogTarget.Name { get => _name; }
|
||||
|
||||
|
@ -20,7 +20,7 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
public FileLogTarget(string path, string name, FileShare fileShare, FileMode fileMode)
|
||||
{
|
||||
// Ensure directory is present
|
||||
DirectoryInfo logDir = new DirectoryInfo(Path.Combine(path, "Logs"));
|
||||
DirectoryInfo logDir = new(Path.Combine(path, "Logs"));
|
||||
logDir.Create();
|
||||
|
||||
// Clean up old logs, should only keep 3
|
||||
|
@ -33,9 +33,9 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
string version = ReleaseInformation.GetVersion();
|
||||
|
||||
// Get path for the current time
|
||||
path = Path.Combine(logDir.FullName, $"Ryujinx_{version}_{DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss")}.log");
|
||||
path = Path.Combine(logDir.FullName, $"Ryujinx_{version}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log");
|
||||
|
||||
_name = name;
|
||||
_name = name;
|
||||
_logWriter = new StreamWriter(File.Open(path, fileMode, FileAccess.Write, fileShare));
|
||||
_formatter = new DefaultLogFormatter();
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
_logWriter.WriteLine("---- End of Log ----");
|
||||
_logWriter.Flush();
|
||||
_logWriter.Dispose();
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.Common.Logging.Targets
|
||||
{
|
||||
public class JsonLogTarget : ILogTarget
|
||||
{
|
||||
private Stream _stream;
|
||||
private bool _leaveOpen;
|
||||
private string _name;
|
||||
private readonly Stream _stream;
|
||||
private readonly bool _leaveOpen;
|
||||
private readonly string _name;
|
||||
|
||||
string ILogTarget.Name { get => _name; }
|
||||
|
||||
public JsonLogTarget(Stream stream, string name)
|
||||
{
|
||||
_stream = stream;
|
||||
_name = name;
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public JsonLogTarget(Stream stream, bool leaveOpen)
|
||||
{
|
||||
_stream = stream;
|
||||
_stream = stream;
|
||||
_leaveOpen = leaveOpen;
|
||||
}
|
||||
|
||||
|
@ -31,6 +32,7 @@ namespace Ryujinx.Common.Logging.Targets
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
if (!_leaveOpen)
|
||||
{
|
||||
_stream.Dispose();
|
||||
|
|
|
@ -16,12 +16,12 @@ namespace Ryujinx.Common.Memory
|
|||
/// <summary>
|
||||
/// Null pointer.
|
||||
/// </summary>
|
||||
public static ArrayPtr<T> Null => new ArrayPtr<T>() { _ptr = IntPtr.Zero };
|
||||
public static ArrayPtr<T> Null => new() { _ptr = IntPtr.Zero };
|
||||
|
||||
/// <summary>
|
||||
/// True if the pointer is null, false otherwise.
|
||||
/// </summary>
|
||||
public bool IsNull => _ptr == IntPtr.Zero;
|
||||
public readonly bool IsNull => _ptr == IntPtr.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Number of elements on the array.
|
||||
|
@ -37,7 +37,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// </remarks>
|
||||
/// <param name="index">Index of the element</param>
|
||||
/// <returns>Reference to the element at the given index</returns>
|
||||
public ref T this[int index] => ref Unsafe.AsRef<T>((T*)_ptr + index);
|
||||
public readonly ref T this[int index] => ref Unsafe.AsRef<T>((T*)_ptr + index);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new array from a given reference.
|
||||
|
@ -81,7 +81,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// </summary>
|
||||
/// <param name="start">Index where the new array should start</param>
|
||||
/// <returns>New array starting at the specified position</returns>
|
||||
public ArrayPtr<T> Slice(int start) => new ArrayPtr<T>(ref this[start], Length - start);
|
||||
public ArrayPtr<T> Slice(int start) => new(ref this[start], Length - start);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a span from the array.
|
||||
|
@ -93,19 +93,19 @@ namespace Ryujinx.Common.Memory
|
|||
/// Gets the array base pointer.
|
||||
/// </summary>
|
||||
/// <returns>Base pointer</returns>
|
||||
public T* ToPointer() => (T*)_ptr;
|
||||
public readonly T* ToPointer() => (T*)_ptr;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public readonly override bool Equals(object obj)
|
||||
{
|
||||
return obj is ArrayPtr<T> other && Equals(other);
|
||||
}
|
||||
|
||||
public bool Equals([AllowNull] ArrayPtr<T> other)
|
||||
public readonly bool Equals([AllowNull] ArrayPtr<T> other)
|
||||
{
|
||||
return _ptr == other._ptr && Length == other.Length;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
public readonly override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(_ptr, Length);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// </summary>
|
||||
public sealed partial class ByteMemoryPool
|
||||
{
|
||||
private static readonly ByteMemoryPool _shared = new ByteMemoryPool();
|
||||
private static readonly ByteMemoryPool _shared = new();
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a <see cref="ByteMemoryPool"/> instance. Private to force access through
|
||||
|
@ -27,7 +27,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// <summary>
|
||||
/// Returns the maximum buffer size supported by this pool.
|
||||
/// </summary>
|
||||
public int MaxBufferSize => Array.MaxLength;
|
||||
public static int MaxBufferSize => Array.MaxLength;
|
||||
|
||||
/// <summary>
|
||||
/// Rents a byte memory buffer from <see cref="ArrayPool{Byte}.Shared"/>.
|
||||
|
@ -36,7 +36,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public IMemoryOwner<byte> Rent(long length)
|
||||
public static IMemoryOwner<byte> Rent(long length)
|
||||
=> RentImpl(checked((int)length));
|
||||
|
||||
/// <summary>
|
||||
|
@ -46,7 +46,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public IMemoryOwner<byte> Rent(ulong length)
|
||||
public static IMemoryOwner<byte> Rent(ulong length)
|
||||
=> RentImpl(checked((int)length));
|
||||
|
||||
/// <summary>
|
||||
|
@ -56,7 +56,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public IMemoryOwner<byte> Rent(int length)
|
||||
public static IMemoryOwner<byte> Rent(int length)
|
||||
=> RentImpl(length);
|
||||
|
||||
/// <summary>
|
||||
|
@ -66,7 +66,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public IMemoryOwner<byte> RentCleared(long length)
|
||||
public static IMemoryOwner<byte> RentCleared(long length)
|
||||
=> RentCleared(checked((int)length));
|
||||
|
||||
/// <summary>
|
||||
|
@ -76,7 +76,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public IMemoryOwner<byte> RentCleared(ulong length)
|
||||
public static IMemoryOwner<byte> RentCleared(ulong length)
|
||||
=> RentCleared(checked((int)length));
|
||||
|
||||
/// <summary>
|
||||
|
@ -86,7 +86,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// <param name="length">The buffer's required length in bytes</param>
|
||||
/// <returns>A <see cref="IMemoryOwner{Byte}"/> wrapping the rented memory</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public IMemoryOwner<byte> RentCleared(int length)
|
||||
public static IMemoryOwner<byte> RentCleared(int length)
|
||||
{
|
||||
var buffer = RentImpl(length);
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace Ryujinx.Common.Memory
|
|||
{
|
||||
public static class MemoryStreamManager
|
||||
{
|
||||
private static readonly RecyclableMemoryStreamManager _shared = new RecyclableMemoryStreamManager();
|
||||
private static readonly RecyclableMemoryStreamManager _shared = new();
|
||||
|
||||
/// <summary>
|
||||
/// We don't expose the <c>RecyclableMemoryStreamManager</c> directly because version 2.x
|
||||
|
@ -19,7 +19,7 @@ namespace Ryujinx.Common.Memory
|
|||
/// </summary>
|
||||
/// <returns>A <c>RecyclableMemoryStream</c></returns>
|
||||
public static RecyclableMemoryStream GetStream()
|
||||
=> new RecyclableMemoryStream(_shared);
|
||||
=> new(_shared);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a new <c>MemoryStream</c> object with the contents copied from the provided
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
|
||||
|
||||
namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
|
@ -14,15 +13,15 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||
public int WriteLock;
|
||||
public int ReaderCount;
|
||||
|
||||
public static int WriteLockOffset;
|
||||
public static int ReaderCountOffset;
|
||||
public static readonly int WriteLockOffset;
|
||||
public static readonly int ReaderCountOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Populates the field offsets for use when emitting native code.
|
||||
/// </summary>
|
||||
static NativeReaderWriterLock()
|
||||
{
|
||||
NativeReaderWriterLock instance = new NativeReaderWriterLock();
|
||||
NativeReaderWriterLock instance = new();
|
||||
|
||||
WriteLockOffset = OffsetOf(ref instance, ref instance.WriteLock);
|
||||
ReaderCountOffset = OffsetOf(ref instance, ref instance.ReaderCount);
|
||||
|
@ -35,7 +34,9 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||
{
|
||||
// Must take write lock for a very short time to become a reader.
|
||||
|
||||
while (Interlocked.CompareExchange(ref WriteLock, 1, 0) != 0) { }
|
||||
while (Interlocked.CompareExchange(ref WriteLock, 1, 0) != 0)
|
||||
{
|
||||
}
|
||||
|
||||
Interlocked.Increment(ref ReaderCount);
|
||||
|
||||
|
@ -60,11 +61,15 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||
|
||||
Interlocked.Decrement(ref ReaderCount);
|
||||
|
||||
while (Interlocked.CompareExchange(ref WriteLock, 1, 0) != 0) { }
|
||||
while (Interlocked.CompareExchange(ref WriteLock, 1, 0) != 0)
|
||||
{
|
||||
}
|
||||
|
||||
// Wait for reader count to drop to 0, then take the lock again as the only reader.
|
||||
|
||||
while (Interlocked.CompareExchange(ref ReaderCount, 1, 0) != 0) { }
|
||||
while (Interlocked.CompareExchange(ref ReaderCount, 1, 0) != 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.Marshalling;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
|
||||
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
|
||||
|
||||
namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
|
@ -35,7 +33,7 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||
|
||||
[SupportedOSPlatform("windows")]
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs (UnmanagedType.Bool)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static partial bool CloseHandle(IntPtr hObject);
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
|
@ -48,7 +46,7 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||
/// </summary>
|
||||
static unsafe PartialUnmapState()
|
||||
{
|
||||
PartialUnmapState instance = new PartialUnmapState();
|
||||
PartialUnmapState instance = new();
|
||||
|
||||
PartialUnmapLockOffset = OffsetOf(ref instance, ref instance.PartialUnmapLock);
|
||||
PartialUnmapsCountOffset = OffsetOf(ref instance, ref instance.PartialUnmapsCount);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
using static Ryujinx.Common.Memory.PartialUnmaps.PartialUnmapHelpers;
|
||||
|
||||
namespace Ryujinx.Common.Memory.PartialUnmaps
|
||||
|
@ -18,15 +17,15 @@ namespace Ryujinx.Common.Memory.PartialUnmaps
|
|||
public Array20<int> ThreadIds;
|
||||
public Array20<T> Structs;
|
||||
|
||||
public static int ThreadIdsOffset;
|
||||
public static int StructsOffset;
|
||||
public static readonly int ThreadIdsOffset;
|
||||
public static readonly int StructsOffset;
|
||||
|
||||
/// <summary>
|
||||
/// Populates the field offsets for use when emitting native code.
|
||||
/// </summary>
|
||||
static ThreadLocalMap()
|
||||
{
|
||||
ThreadLocalMap<T> instance = new ThreadLocalMap<T>();
|
||||
ThreadLocalMap<T> instance = new();
|
||||
|
||||
ThreadIdsOffset = OffsetOf(ref instance, ref instance.ThreadIds);
|
||||
StructsOffset = OffsetOf(ref instance, ref instance.Structs);
|
||||
|
|
|
@ -15,17 +15,17 @@ namespace Ryujinx.Common.Memory
|
|||
/// <summary>
|
||||
/// Null pointer.
|
||||
/// </summary>
|
||||
public static Ptr<T> Null => new Ptr<T>() { _ptr = IntPtr.Zero };
|
||||
public static Ptr<T> Null => new() { _ptr = IntPtr.Zero };
|
||||
|
||||
/// <summary>
|
||||
/// True if the pointer is null, false otherwise.
|
||||
/// </summary>
|
||||
public bool IsNull => _ptr == IntPtr.Zero;
|
||||
public readonly bool IsNull => _ptr == IntPtr.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a reference to the value.
|
||||
/// </summary>
|
||||
public ref T Value => ref Unsafe.AsRef<T>((void*)_ptr);
|
||||
public readonly ref T Value => ref Unsafe.AsRef<T>((void*)_ptr);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new pointer to an unmanaged resource.
|
||||
|
@ -40,17 +40,17 @@ namespace Ryujinx.Common.Memory
|
|||
_ptr = (IntPtr)Unsafe.AsPointer(ref value);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public readonly override bool Equals(object obj)
|
||||
{
|
||||
return obj is Ptr<T> other && Equals(other);
|
||||
}
|
||||
|
||||
public bool Equals([AllowNull] Ptr<T> other)
|
||||
public readonly bool Equals([AllowNull] Ptr<T> other)
|
||||
{
|
||||
return _ptr == other._ptr;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
public readonly override int GetHashCode()
|
||||
{
|
||||
return _ptr.GetHashCode();
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.Common.Memory
|
|||
{
|
||||
private ReadOnlySpan<byte> _input;
|
||||
|
||||
public int Length => _input.Length;
|
||||
public readonly int Length => _input.Length;
|
||||
|
||||
public SpanReader(ReadOnlySpan<byte> input)
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ namespace Ryujinx.Common.Memory
|
|||
{
|
||||
T value = MemoryMarshal.Cast<byte, T>(_input)[0];
|
||||
|
||||
_input = _input.Slice(Unsafe.SizeOf<T>());
|
||||
_input = _input[Unsafe.SizeOf<T>()..];
|
||||
|
||||
return value;
|
||||
}
|
||||
|
@ -37,16 +37,16 @@ namespace Ryujinx.Common.Memory
|
|||
|
||||
value = MemoryMarshal.Cast<byte, T>(_input)[0];
|
||||
|
||||
_input = _input.Slice(valueSize);
|
||||
_input = _input[valueSize..];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> GetSpan(int size)
|
||||
{
|
||||
ReadOnlySpan<byte> data = _input.Slice(0, size);
|
||||
ReadOnlySpan<byte> data = _input[..size];
|
||||
|
||||
_input = _input.Slice(size);
|
||||
_input = _input[size..];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -56,19 +56,19 @@ namespace Ryujinx.Common.Memory
|
|||
return GetSpan((int)Math.Min((uint)_input.Length, (uint)size));
|
||||
}
|
||||
|
||||
public T ReadAt<T>(int offset) where T : unmanaged
|
||||
public readonly T ReadAt<T>(int offset) where T : unmanaged
|
||||
{
|
||||
return MemoryMarshal.Cast<byte, T>(_input.Slice(offset))[0];
|
||||
return MemoryMarshal.Cast<byte, T>(_input[offset..])[0];
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> GetSpanAt(int offset, int size)
|
||||
public readonly ReadOnlySpan<byte> GetSpanAt(int offset, int size)
|
||||
{
|
||||
return _input.Slice(offset, size);
|
||||
}
|
||||
|
||||
public void Skip(int size)
|
||||
{
|
||||
_input = _input.Slice(size);
|
||||
_input = _input[size..];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ namespace Ryujinx.Common.Memory
|
|||
{
|
||||
private Span<byte> _output;
|
||||
|
||||
public int Length => _output.Length;
|
||||
public readonly int Length => _output.Length;
|
||||
|
||||
public SpanWriter(Span<byte> output)
|
||||
{
|
||||
|
@ -18,28 +18,28 @@ namespace Ryujinx.Common.Memory
|
|||
public void Write<T>(T value) where T : unmanaged
|
||||
{
|
||||
MemoryMarshal.Cast<byte, T>(_output)[0] = value;
|
||||
_output = _output.Slice(Unsafe.SizeOf<T>());
|
||||
_output = _output[Unsafe.SizeOf<T>()..];
|
||||
}
|
||||
|
||||
public void Write(ReadOnlySpan<byte> data)
|
||||
{
|
||||
data.CopyTo(_output.Slice(0, data.Length));
|
||||
_output = _output.Slice(data.Length);
|
||||
data.CopyTo(_output[..data.Length]);
|
||||
_output = _output[data.Length..];
|
||||
}
|
||||
|
||||
public void WriteAt<T>(int offset, T value) where T : unmanaged
|
||||
public readonly void WriteAt<T>(int offset, T value) where T : unmanaged
|
||||
{
|
||||
MemoryMarshal.Cast<byte, T>(_output.Slice(offset))[0] = value;
|
||||
MemoryMarshal.Cast<byte, T>(_output[offset..])[0] = value;
|
||||
}
|
||||
|
||||
public void WriteAt(int offset, ReadOnlySpan<byte> data)
|
||||
public readonly void WriteAt(int offset, ReadOnlySpan<byte> data)
|
||||
{
|
||||
data.CopyTo(_output.Slice(offset, data.Length));
|
||||
}
|
||||
|
||||
public void Skip(int size)
|
||||
{
|
||||
_output = _output.Slice(size);
|
||||
_output = _output[size..];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,654 +1,658 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#pragma warning disable CS0169, IDE0051 // Remove unused private member
|
||||
namespace Ryujinx.Common.Memory
|
||||
{
|
||||
public struct Array1<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
T _e0;
|
||||
public int Length => 1;
|
||||
public readonly int Length => 1;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 1);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array2<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array1<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 2;
|
||||
public readonly int Length => 2;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 2);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array3<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array2<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 3;
|
||||
public readonly int Length => 3;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 3);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array4<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array3<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 4;
|
||||
public readonly int Length => 4;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 4);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array5<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array4<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 5;
|
||||
public readonly int Length => 5;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 5);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array6<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array5<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 6;
|
||||
public readonly int Length => 6;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 6);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array7<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array6<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 7;
|
||||
public readonly int Length => 7;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 7);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array8<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array7<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 8;
|
||||
public readonly int Length => 8;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 8);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array9<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array8<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 9;
|
||||
public readonly int Length => 9;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 9);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array10<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array9<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 10;
|
||||
public readonly int Length => 10;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 10);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array11<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array10<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 11;
|
||||
public readonly int Length => 11;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 11);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array12<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array11<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 12;
|
||||
public readonly int Length => 12;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 12);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array13<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array12<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 13;
|
||||
public readonly int Length => 13;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 13);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array14<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array13<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 14;
|
||||
public readonly int Length => 14;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 14);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array15<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array14<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 15;
|
||||
public readonly int Length => 15;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 15);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array16<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array15<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 16;
|
||||
public readonly int Length => 16;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 16);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array17<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array16<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 17;
|
||||
public readonly int Length => 17;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 17);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array18<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array17<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 18;
|
||||
public readonly int Length => 18;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 18);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array19<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array18<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 19;
|
||||
public readonly int Length => 19;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 19);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array20<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array19<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 20;
|
||||
public readonly int Length => 20;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 20);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array21<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array20<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 21;
|
||||
public readonly int Length => 21;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 21);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array22<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array21<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 22;
|
||||
public readonly int Length => 22;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 22);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array23<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array22<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 23;
|
||||
public readonly int Length => 23;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 23);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array24<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array23<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 24;
|
||||
|
||||
public readonly int Length => 24;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 24);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array25<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array24<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 25;
|
||||
|
||||
public readonly int Length => 25;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 25);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array26<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array25<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 26;
|
||||
|
||||
public readonly int Length => 26;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 26);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array27<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array26<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 27;
|
||||
|
||||
public readonly int Length => 27;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 27);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array28<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array27<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 28;
|
||||
|
||||
public readonly int Length => 28;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 28);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array29<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array28<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 29;
|
||||
|
||||
public readonly int Length => 29;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 29);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array30<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array29<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 30;
|
||||
|
||||
public readonly int Length => 30;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 30);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array31<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array30<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 31;
|
||||
|
||||
public readonly int Length => 31;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 31);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array32<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array31<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 32;
|
||||
|
||||
public readonly int Length => 32;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 32);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array33<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array32<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 33;
|
||||
|
||||
public readonly int Length => 33;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 33);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array34<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array33<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 34;
|
||||
|
||||
public readonly int Length => 34;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 34);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array35<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array34<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 35;
|
||||
|
||||
public readonly int Length => 35;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 35);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array36<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array35<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 36;
|
||||
|
||||
public readonly int Length => 36;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 36);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array37<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array36<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 37;
|
||||
|
||||
public readonly int Length => 37;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 37);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array38<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array37<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 38;
|
||||
|
||||
public readonly int Length => 38;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 38);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array39<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array38<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 39;
|
||||
|
||||
public readonly int Length => 39;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 39);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array40<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array39<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 40;
|
||||
|
||||
public readonly int Length => 40;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 40);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array41<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array40<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 41;
|
||||
|
||||
public readonly int Length => 41;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 41);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array42<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array41<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 42;
|
||||
|
||||
public readonly int Length => 42;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 42);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array43<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array42<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 43;
|
||||
|
||||
public readonly int Length => 43;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 43);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array44<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array43<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 44;
|
||||
|
||||
public readonly int Length => 44;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 44);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array45<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array44<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 45;
|
||||
|
||||
public readonly int Length => 45;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 45);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array46<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array45<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 46;
|
||||
|
||||
public readonly int Length => 46;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 46);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array47<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array46<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 47;
|
||||
|
||||
public readonly int Length => 47;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 47);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array48<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array47<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 48;
|
||||
|
||||
public readonly int Length => 48;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 48);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array49<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array48<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 49;
|
||||
|
||||
public readonly int Length => 49;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 49);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array50<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array49<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 50;
|
||||
|
||||
public readonly int Length => 50;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 50);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array51<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array50<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 51;
|
||||
|
||||
public readonly int Length => 51;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 51);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array52<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array51<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 52;
|
||||
|
||||
public readonly int Length => 52;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 52);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array53<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array52<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 53;
|
||||
|
||||
public readonly int Length => 53;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 53);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array54<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array53<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 54;
|
||||
|
||||
public readonly int Length => 54;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 54);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array55<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array54<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 55;
|
||||
|
||||
public readonly int Length => 55;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 55);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array56<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array55<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 56;
|
||||
|
||||
public readonly int Length => 56;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 56);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array57<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array56<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 57;
|
||||
|
||||
public readonly int Length => 57;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 57);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array58<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array57<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 58;
|
||||
|
||||
public readonly int Length => 58;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 58);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array59<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array58<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 59;
|
||||
|
||||
public readonly int Length => 59;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 59);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array60<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array59<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 60;
|
||||
public readonly int Length => 60;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 60);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array61<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array60<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 61;
|
||||
public readonly int Length => 61;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 61);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array62<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array61<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 62;
|
||||
public readonly int Length => 62;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 62);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array63<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array62<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 63;
|
||||
public readonly int Length => 63;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 63);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array64<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array63<T> _other;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 64;
|
||||
public readonly int Length => 64;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 64);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array73<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
#pragma warning disable CS0169
|
||||
T _e0;
|
||||
Array64<T> _other;
|
||||
Array8<T> _other2;
|
||||
#pragma warning restore CS0169
|
||||
public int Length => 73;
|
||||
public readonly int Length => 73;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, 73);
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array127<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
T _e0;
|
||||
Array64<T> _other;
|
||||
Array62<T> _other2;
|
||||
public readonly int Length => 127;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array128<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
T _e0;
|
||||
Array64<T> _other;
|
||||
Array63<T> _other2;
|
||||
public readonly int Length => 128;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
|
||||
public struct Array256<T> : IArray<T> where T : unmanaged
|
||||
{
|
||||
T _e0;
|
||||
Array128<T> _other;
|
||||
Array127<T> _other2;
|
||||
public readonly int Length => 256;
|
||||
public ref T this[int index] => ref AsSpan()[index];
|
||||
public Span<T> AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length);
|
||||
}
|
||||
}
|
||||
#pragma warning restore CS0169, IDE0051
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Ryujinx.Common.Memory
|
|||
|
||||
byte _element;
|
||||
|
||||
public int Length => Size;
|
||||
public readonly int Length => Size;
|
||||
public ref byte this[int index] => ref AsSpan()[index];
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ namespace Ryujinx.Common.Memory
|
|||
|
||||
byte _element;
|
||||
|
||||
public int Length => Size;
|
||||
public readonly int Length => Size;
|
||||
public ref byte this[int index] => ref AsSpan()[index];
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ namespace Ryujinx.Common.Memory
|
|||
|
||||
byte _element;
|
||||
|
||||
public int Length => Size;
|
||||
public readonly int Length => Size;
|
||||
public ref byte this[int index] => ref AsSpan()[index];
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ namespace Ryujinx.Common.Memory
|
|||
|
||||
byte _element;
|
||||
|
||||
public int Length => Size;
|
||||
public readonly int Length => Size;
|
||||
public ref byte this[int index] => ref AsSpan()[index];
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ namespace Ryujinx.Common.Memory
|
|||
|
||||
byte _element;
|
||||
|
||||
public int Length => Size;
|
||||
public readonly int Length => Size;
|
||||
public ref byte this[int index] => ref AsSpan()[index];
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ namespace Ryujinx.Common.Memory
|
|||
|
||||
byte _element;
|
||||
|
||||
public int Length => Size;
|
||||
public readonly int Length => Size;
|
||||
public ref byte this[int index] => ref AsSpan()[index];
|
||||
public Span<byte> AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using System.Diagnostics;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
public static class PerformanceCounter
|
||||
{
|
||||
private static double _ticksToNs;
|
||||
private static readonly double _ticksToNs;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the number of ticks in 1 day.
|
||||
|
@ -71,10 +71,10 @@ namespace Ryujinx.Common
|
|||
static PerformanceCounter()
|
||||
{
|
||||
TicksPerMillisecond = Stopwatch.Frequency / 1000;
|
||||
TicksPerSecond = Stopwatch.Frequency;
|
||||
TicksPerMinute = TicksPerSecond * 60;
|
||||
TicksPerHour = TicksPerMinute * 60;
|
||||
TicksPerDay = TicksPerHour * 24;
|
||||
TicksPerSecond = Stopwatch.Frequency;
|
||||
TicksPerMinute = TicksPerSecond * 60;
|
||||
TicksPerHour = TicksPerMinute * 60;
|
||||
TicksPerDay = TicksPerHour * 24;
|
||||
|
||||
_ticksToNs = 1000000000.0 / Stopwatch.Frequency;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Common
|
|||
|
||||
public ObjectPool(Func<T> factory, int size)
|
||||
{
|
||||
_items = new T[size - 1];
|
||||
_items = new T[size - 1];
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
private static class DefaultPool<T>
|
||||
where T : class, new()
|
||||
{
|
||||
public static readonly ObjectPool<T> Instance = new ObjectPool<T>(() => new T(), 20);
|
||||
public static readonly ObjectPool<T> Instance = new(() => new T(), 20);
|
||||
}
|
||||
|
||||
public static ObjectPool<T> Default<T>()
|
||||
|
|
|
@ -9,10 +9,7 @@ namespace Ryujinx.Common.Pools
|
|||
|
||||
public static ref T[] Get()
|
||||
{
|
||||
if (_array == null)
|
||||
{
|
||||
_array = new T[1];
|
||||
}
|
||||
_array ??= new T[1];
|
||||
|
||||
return ref _array;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ namespace Ryujinx.Common
|
|||
{
|
||||
public class ReactiveObject<T>
|
||||
{
|
||||
private ReaderWriterLock _readerWriterLock = new ReaderWriterLock();
|
||||
private bool _isInitialized = false;
|
||||
private readonly ReaderWriterLock _readerWriterLock = new();
|
||||
private bool _isInitialized;
|
||||
private T _value;
|
||||
|
||||
public event EventHandler<ReactiveEventArgs<T>> Event;
|
||||
|
@ -30,7 +30,7 @@ namespace Ryujinx.Common
|
|||
bool oldIsInitialized = _isInitialized;
|
||||
|
||||
_isInitialized = true;
|
||||
_value = value;
|
||||
_value = value;
|
||||
|
||||
_readerWriterLock.ReleaseWriterLock();
|
||||
|
||||
|
|
|
@ -9,11 +9,11 @@ namespace Ryujinx.Common
|
|||
{
|
||||
private const string FlatHubChannelOwner = "flathub";
|
||||
|
||||
public static string BuildVersion = "%%RYUJINX_BUILD_VERSION%%";
|
||||
public static string BuildGitHash = "%%RYUJINX_BUILD_GIT_HASH%%";
|
||||
public static string ReleaseChannelName = "%%RYUJINX_TARGET_RELEASE_CHANNEL_NAME%%";
|
||||
public static string ReleaseChannelOwner = "%%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER%%";
|
||||
public static string ReleaseChannelRepo = "%%RYUJINX_TARGET_RELEASE_CHANNEL_REPO%%";
|
||||
public const string BuildVersion = "%%RYUJINX_BUILD_VERSION%%";
|
||||
public const string BuildGitHash = "%%RYUJINX_BUILD_GIT_HASH%%";
|
||||
public const string ReleaseChannelName = "%%RYUJINX_TARGET_RELEASE_CHANNEL_NAME%%";
|
||||
public const string ReleaseChannelOwner = "%%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER%%";
|
||||
public const string ReleaseChannelRepo = "%%RYUJINX_TARGET_RELEASE_CHANNEL_REPO%%";
|
||||
|
||||
public static bool IsValid()
|
||||
{
|
||||
|
@ -34,10 +34,8 @@ namespace Ryujinx.Common
|
|||
{
|
||||
return BuildVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
||||
}
|
||||
|
||||
return Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
|
||||
}
|
||||
|
||||
#if FORCE_EXTERNAL_BASE_DIR
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace Ryujinx.Common.SystemInfo
|
|||
{
|
||||
["model name"] = null,
|
||||
["Processor"] = null,
|
||||
["Hardware"] = null
|
||||
["Hardware"] = null,
|
||||
};
|
||||
|
||||
ParseKeyValues("/proc/cpuinfo", cpuDict);
|
||||
|
@ -31,7 +31,7 @@ namespace Ryujinx.Common.SystemInfo
|
|||
var memDict = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
{
|
||||
["MemTotal"] = null,
|
||||
["MemAvailable"] = null
|
||||
["MemAvailable"] = null,
|
||||
};
|
||||
|
||||
ParseKeyValues("/proc/meminfo", memDict);
|
||||
|
@ -56,22 +56,27 @@ namespace Ryujinx.Common.SystemInfo
|
|||
|
||||
int count = itemDict.Count;
|
||||
|
||||
using (StreamReader file = new StreamReader(filePath))
|
||||
using StreamReader file = new(filePath);
|
||||
|
||||
string line;
|
||||
while ((line = file.ReadLine()) != null)
|
||||
{
|
||||
string line;
|
||||
while ((line = file.ReadLine()) != null)
|
||||
string[] kvPair = line.Split(':', 2, StringSplitOptions.TrimEntries);
|
||||
|
||||
if (kvPair.Length < 2)
|
||||
{
|
||||
string[] kvPair = line.Split(':', 2, StringSplitOptions.TrimEntries);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (kvPair.Length < 2) continue;
|
||||
string key = kvPair[0];
|
||||
|
||||
string key = kvPair[0];
|
||||
if (itemDict.TryGetValue(key, out string value) && value == null)
|
||||
{
|
||||
itemDict[key] = kvPair[1];
|
||||
|
||||
if (itemDict.TryGetValue(key, out string value) && value == null)
|
||||
if (--count <= 0)
|
||||
{
|
||||
itemDict[key] = kvPair[1];
|
||||
|
||||
if (--count <= 0) break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,14 +14,14 @@ namespace Ryujinx.Common.SystemInfo
|
|||
{
|
||||
string cpuName = GetCpuidCpuName();
|
||||
|
||||
if (cpuName == null && sysctlbyname("machdep.cpu.brand_string", out cpuName) != 0)
|
||||
if (cpuName == null && SysctlByName("machdep.cpu.brand_string", out cpuName) != 0)
|
||||
{
|
||||
cpuName = "Unknown";
|
||||
}
|
||||
|
||||
ulong totalRAM = 0;
|
||||
|
||||
if (sysctlbyname("hw.memsize", ref totalRAM) != 0) // Bytes
|
||||
if (SysctlByName("hw.memsize", ref totalRAM) != 0) // Bytes
|
||||
{
|
||||
totalRAM = 0;
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ namespace Ryujinx.Common.SystemInfo
|
|||
[LibraryImport(SystemLibraryName, SetLastError = true)]
|
||||
private static partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, IntPtr oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
|
||||
|
||||
private static int sysctlbyname(string name, IntPtr oldValue, ref ulong oldSize)
|
||||
private static int SysctlByName(string name, IntPtr oldValue, ref ulong oldSize)
|
||||
{
|
||||
if (sysctlbyname(name, oldValue, ref oldSize, IntPtr.Zero, 0) == -1)
|
||||
{
|
||||
|
@ -77,23 +77,23 @@ namespace Ryujinx.Common.SystemInfo
|
|||
return 0;
|
||||
}
|
||||
|
||||
private static int sysctlbyname<T>(string name, ref T oldValue)
|
||||
private static int SysctlByName<T>(string name, ref T oldValue)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
ulong oldValueSize = (ulong)Unsafe.SizeOf<T>();
|
||||
|
||||
return sysctlbyname(name, (IntPtr)Unsafe.AsPointer(ref oldValue), ref oldValueSize);
|
||||
return SysctlByName(name, (IntPtr)Unsafe.AsPointer(ref oldValue), ref oldValueSize);
|
||||
}
|
||||
}
|
||||
|
||||
private static int sysctlbyname(string name, out string oldValue)
|
||||
private static int SysctlByName(string name, out string oldValue)
|
||||
{
|
||||
oldValue = default;
|
||||
|
||||
ulong strSize = 0;
|
||||
|
||||
int res = sysctlbyname(name, IntPtr.Zero, ref strSize);
|
||||
int res = SysctlByName(name, IntPtr.Zero, ref strSize);
|
||||
|
||||
if (res == 0)
|
||||
{
|
||||
|
@ -103,7 +103,7 @@ namespace Ryujinx.Common.SystemInfo
|
|||
{
|
||||
fixed (byte* rawDataPtr = rawData)
|
||||
{
|
||||
res = sysctlbyname(name, (IntPtr)rawDataPtr, ref strSize);
|
||||
res = SysctlByName(name, (IntPtr)rawDataPtr, ref strSize);
|
||||
}
|
||||
|
||||
if (res == 0)
|
||||
|
@ -152,6 +152,6 @@ namespace Ryujinx.Common.SystemInfo
|
|||
}
|
||||
|
||||
[LibraryImport(SystemLibraryName, SetLastError = true)]
|
||||
private static partial int host_statistics64(uint host_priv, int host_flavor, ref VMStatistics64 host_info64_out, ref uint host_info64_outCnt);
|
||||
private static partial int host_statistics64(uint hostPriv, int hostFlavor, ref VMStatistics64 hostInfo64Out, ref uint hostInfo64OutCnt);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,12 +43,10 @@ namespace Ryujinx.Common.SystemInfo
|
|||
{
|
||||
return new MacOSSystemInfo();
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, "SystemInfo unsupported on this platform");
|
||||
|
||||
return new SystemInfo();
|
||||
}
|
||||
Logger.Error?.Print(LogClass.Application, "SystemInfo unsupported on this platform");
|
||||
|
||||
return new SystemInfo();
|
||||
}
|
||||
|
||||
// x86 exposes a 48 byte ASCII "CPU brand" string via CPUID leaves 0x80000002-0x80000004.
|
||||
|
|
|
@ -17,15 +17,13 @@ namespace Ryujinx.Common.SystemInfo
|
|||
|
||||
private static (ulong Total, ulong Available) GetMemoryStats()
|
||||
{
|
||||
MemoryStatusEx memStatus = new MemoryStatusEx();
|
||||
MemoryStatusEx memStatus = new();
|
||||
if (GlobalMemoryStatusEx(ref memStatus))
|
||||
{
|
||||
return (memStatus.TotalPhys, memStatus.AvailPhys); // Bytes
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, $"GlobalMemoryStatusEx failed. Error {Marshal.GetLastWin32Error():X}");
|
||||
}
|
||||
|
||||
Logger.Error?.Print(LogClass.Application, $"GlobalMemoryStatusEx failed. Error {Marshal.GetLastWin32Error():X}");
|
||||
|
||||
return (0, 0);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Ryujinx.Common.SystemInterop
|
|||
{
|
||||
ES_CONTINUOUS = 0x80000000,
|
||||
ES_DISPLAY_REQUIRED = 0x00000002,
|
||||
ES_SYSTEM_REQUIRED = 0x00000001
|
||||
ES_SYSTEM_REQUIRED = 0x00000001,
|
||||
}
|
||||
|
||||
[LibraryImport("kernel32.dll", SetLastError = true)]
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace Ryujinx.Common.SystemInterop
|
|||
private static partial int XCloseDisplay(IntPtr display);
|
||||
|
||||
private static readonly double _standardDpiScale = 96.0;
|
||||
private static readonly double _maxScaleFactor = 1.25;
|
||||
private static readonly double _maxScaleFactor = 1.25;
|
||||
|
||||
/// <summary>
|
||||
/// Marks the application as DPI-Aware when running on the Windows operating system.
|
||||
|
@ -63,14 +63,14 @@ namespace Ryujinx.Common.SystemInterop
|
|||
string dpiString = Marshal.PtrToStringAnsi(XGetDefault(display, "Xft", "dpi"));
|
||||
if (dpiString == null || !double.TryParse(dpiString, NumberStyles.Any, CultureInfo.InvariantCulture, out userDpiScale))
|
||||
{
|
||||
userDpiScale = (double)XDisplayWidth(display, 0) * 25.4 / (double)XDisplayWidthMM(display, 0);
|
||||
userDpiScale = XDisplayWidth(display, 0) * 25.4 / XDisplayWidthMM(display, 0);
|
||||
}
|
||||
XCloseDisplay(display);
|
||||
_ = XCloseDisplay(display);
|
||||
}
|
||||
else if (xdgSessionType == "wayland")
|
||||
{
|
||||
// TODO
|
||||
Logger.Warning?.Print(LogClass.Application, $"Couldn't determine monitor DPI: Wayland not yet supported");
|
||||
Logger.Warning?.Print(LogClass.Application, "Couldn't determine monitor DPI: Wayland not yet supported");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -28,14 +28,14 @@ namespace Ryujinx.Common.SystemInterop
|
|||
{
|
||||
public int GdiplusVersion;
|
||||
|
||||
#pragma warning disable CS0649
|
||||
#pragma warning disable CS0649 // Field is never assigned to
|
||||
public IntPtr DebugEventCallback;
|
||||
public int SuppressBackgroundThread;
|
||||
public int SuppressExternalCodecs;
|
||||
public int StartupParameters;
|
||||
#pragma warning restore CS0649
|
||||
|
||||
public static StartupInputEx Default => new StartupInputEx
|
||||
public static StartupInputEx Default => new()
|
||||
{
|
||||
// We assume Windows 8 and upper
|
||||
GdiplusVersion = 2,
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Ryujinx.Common.SystemInterop
|
|||
{
|
||||
public partial class StdErrAdapter : IDisposable
|
||||
{
|
||||
private bool _disposable = false;
|
||||
private bool _disposable;
|
||||
private Stream _pipeReader;
|
||||
private Stream _pipeWriter;
|
||||
private CancellationTokenSource _cancellationTokenSource;
|
||||
|
@ -54,8 +54,10 @@ namespace Ryujinx.Common.SystemInterop
|
|||
}
|
||||
}
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
if (_disposable)
|
||||
{
|
||||
_disposable = false;
|
||||
|
@ -70,11 +72,6 @@ namespace Ryujinx.Common.SystemInterop
|
|||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
[LibraryImport("libc", SetLastError = true)]
|
||||
private static partial int dup2(int fd, int fd2);
|
||||
|
||||
|
@ -89,10 +86,8 @@ namespace Ryujinx.Common.SystemInterop
|
|||
{
|
||||
return (pipefd[0], pipefd[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new();
|
||||
}
|
||||
|
||||
throw new();
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("linux")]
|
||||
|
@ -100,7 +95,7 @@ namespace Ryujinx.Common.SystemInterop
|
|||
private static Stream CreateFileDescriptorStream(int fd)
|
||||
{
|
||||
return new FileStream(
|
||||
new SafeFileHandle((IntPtr)fd, ownsHandle: true),
|
||||
new SafeFileHandle(fd, ownsHandle: true),
|
||||
FileAccess.ReadWrite
|
||||
);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Ryujinx.Common.SystemInterop
|
|||
{
|
||||
public uint wPeriodMin;
|
||||
public uint wPeriodMax;
|
||||
};
|
||||
}
|
||||
|
||||
[LibraryImport("winmm.dll", EntryPoint = "timeGetDevCaps", SetLastError = true)]
|
||||
private static partial uint TimeGetDevCaps(ref TimeCaps timeCaps, uint sizeTimeCaps);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
|
@ -27,10 +26,10 @@ namespace Ryujinx.Common
|
|||
{
|
||||
value--;
|
||||
|
||||
value |= (value >> 1);
|
||||
value |= (value >> 2);
|
||||
value |= (value >> 4);
|
||||
value |= (value >> 8);
|
||||
value |= (value >> 1);
|
||||
value |= (value >> 2);
|
||||
value |= (value >> 4);
|
||||
value |= (value >> 8);
|
||||
value |= (value >> 16);
|
||||
|
||||
return ++value;
|
||||
|
@ -48,10 +47,10 @@ namespace Ryujinx.Common
|
|||
|
||||
private static ulong ReverseBits64(ulong value)
|
||||
{
|
||||
value = ((value & 0xaaaaaaaaaaaaaaaa) >> 1 ) | ((value & 0x5555555555555555) << 1 );
|
||||
value = ((value & 0xcccccccccccccccc) >> 2 ) | ((value & 0x3333333333333333) << 2 );
|
||||
value = ((value & 0xf0f0f0f0f0f0f0f0) >> 4 ) | ((value & 0x0f0f0f0f0f0f0f0f) << 4 );
|
||||
value = ((value & 0xff00ff00ff00ff00) >> 8 ) | ((value & 0x00ff00ff00ff00ff) << 8 );
|
||||
value = ((value & 0xaaaaaaaaaaaaaaaa) >> 1) | ((value & 0x5555555555555555) << 1);
|
||||
value = ((value & 0xcccccccccccccccc) >> 2) | ((value & 0x3333333333333333) << 2);
|
||||
value = ((value & 0xf0f0f0f0f0f0f0f0) >> 4) | ((value & 0x0f0f0f0f0f0f0f0f) << 4);
|
||||
value = ((value & 0xff00ff00ff00ff00) >> 8) | ((value & 0x00ff00ff00ff00ff) << 8);
|
||||
value = ((value & 0xffff0000ffff0000) >> 16) | ((value & 0x0000ffff0000ffff) << 16);
|
||||
|
||||
return (value >> 32) | (value << 32);
|
||||
|
|
|
@ -9,8 +9,8 @@ namespace Ryujinx.Common.Utilities
|
|||
[StructLayout(LayoutKind.Sequential, Size = 16)]
|
||||
public struct Buffer16
|
||||
{
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy0;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private ulong _dummy1;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong _dummy0;
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly ulong _dummy1;
|
||||
|
||||
public byte this[int i]
|
||||
{
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
@ -10,11 +9,11 @@ namespace Ryujinx.Common
|
|||
{
|
||||
public static class EmbeddedResources
|
||||
{
|
||||
private readonly static Assembly ResourceAssembly;
|
||||
private readonly static Assembly _resourceAssembly;
|
||||
|
||||
static EmbeddedResources()
|
||||
{
|
||||
ResourceAssembly = Assembly.GetAssembly(typeof(EmbeddedResources));
|
||||
_resourceAssembly = Assembly.GetAssembly(typeof(EmbeddedResources));
|
||||
}
|
||||
|
||||
public static byte[] Read(string filename)
|
||||
|
@ -33,28 +32,24 @@ namespace Ryujinx.Common
|
|||
|
||||
public static byte[] Read(Assembly assembly, string filename)
|
||||
{
|
||||
using (var stream = GetStream(assembly, filename))
|
||||
using var stream = GetStream(assembly, filename);
|
||||
if (stream == null)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return StreamUtils.StreamToBytes(stream);
|
||||
return null;
|
||||
}
|
||||
|
||||
return StreamUtils.StreamToBytes(stream);
|
||||
}
|
||||
|
||||
public async static Task<byte[]> ReadAsync(Assembly assembly, string filename)
|
||||
{
|
||||
using (var stream = GetStream(assembly, filename))
|
||||
using var stream = GetStream(assembly, filename);
|
||||
if (stream == null)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return await StreamUtils.StreamToBytesAsync(stream);
|
||||
return null;
|
||||
}
|
||||
|
||||
return await StreamUtils.StreamToBytesAsync(stream);
|
||||
}
|
||||
|
||||
public static string ReadAllText(string filename)
|
||||
|
@ -73,34 +68,26 @@ namespace Ryujinx.Common
|
|||
|
||||
public static string ReadAllText(Assembly assembly, string filename)
|
||||
{
|
||||
using (var stream = GetStream(assembly, filename))
|
||||
using var stream = GetStream(assembly, filename);
|
||||
if (stream == null)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
using var reader = new StreamReader(stream);
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
|
||||
public async static Task<string> ReadAllTextAsync(Assembly assembly, string filename)
|
||||
{
|
||||
using (var stream = GetStream(assembly, filename))
|
||||
using var stream = GetStream(assembly, filename);
|
||||
if (stream == null)
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using (var reader = new StreamReader(stream))
|
||||
{
|
||||
return await reader.ReadToEndAsync();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
using var reader = new StreamReader(stream);
|
||||
return await reader.ReadToEndAsync();
|
||||
}
|
||||
|
||||
public static Stream GetStream(string filename)
|
||||
|
@ -112,8 +99,8 @@ namespace Ryujinx.Common
|
|||
|
||||
public static Stream GetStream(Assembly assembly, string filename)
|
||||
{
|
||||
var namespace_ = assembly.GetName().Name;
|
||||
var manifestUri = namespace_ + "." + filename.Replace('/', '.');
|
||||
var @namespace = assembly.GetName().Name;
|
||||
var manifestUri = @namespace + "." + filename.Replace('/', '.');
|
||||
|
||||
var stream = assembly.GetManifestResourceStream(manifestUri);
|
||||
|
||||
|
@ -142,7 +129,7 @@ namespace Ryujinx.Common
|
|||
}
|
||||
}
|
||||
|
||||
return (ResourceAssembly, filename);
|
||||
return (_resourceAssembly, filename);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@ namespace Ryujinx.Common
|
|||
{
|
||||
public static class HexUtils
|
||||
{
|
||||
private static readonly char[] HexChars = "0123456789ABCDEF".ToCharArray();
|
||||
private static readonly char[] _hexChars = "0123456789ABCDEF".ToCharArray();
|
||||
|
||||
private const int HexTableColumnWidth = 8;
|
||||
private const int HexTableColumnSpace = 3;
|
||||
|
@ -39,20 +39,20 @@ namespace Ryujinx.Common
|
|||
|
||||
int expectedLines = (bytesLength + bytesPerLine - 1) / bytesPerLine;
|
||||
|
||||
StringBuilder result = new StringBuilder(expectedLines * lineLength);
|
||||
StringBuilder result = new(expectedLines * lineLength);
|
||||
|
||||
for (int i = 0; i < bytesLength; i += bytesPerLine)
|
||||
{
|
||||
line[0] = HexChars[(i >> 28) & 0xF];
|
||||
line[1] = HexChars[(i >> 24) & 0xF];
|
||||
line[2] = HexChars[(i >> 20) & 0xF];
|
||||
line[3] = HexChars[(i >> 16) & 0xF];
|
||||
line[4] = HexChars[(i >> 12) & 0xF];
|
||||
line[5] = HexChars[(i >> 8) & 0xF];
|
||||
line[6] = HexChars[(i >> 4) & 0xF];
|
||||
line[7] = HexChars[(i >> 0) & 0xF];
|
||||
line[0] = _hexChars[(i >> 28) & 0xF];
|
||||
line[1] = _hexChars[(i >> 24) & 0xF];
|
||||
line[2] = _hexChars[(i >> 20) & 0xF];
|
||||
line[3] = _hexChars[(i >> 16) & 0xF];
|
||||
line[4] = _hexChars[(i >> 12) & 0xF];
|
||||
line[5] = _hexChars[(i >> 8) & 0xF];
|
||||
line[6] = _hexChars[(i >> 4) & 0xF];
|
||||
line[7] = _hexChars[(i >> 0) & 0xF];
|
||||
|
||||
int hexColumn = firstHexColumn;
|
||||
int hexColumn = firstHexColumn;
|
||||
int charColumn = firstCharColumn;
|
||||
|
||||
for (int j = 0; j < bytesPerLine; j++)
|
||||
|
@ -64,17 +64,17 @@ namespace Ryujinx.Common
|
|||
|
||||
if (i + j >= bytesLength)
|
||||
{
|
||||
line[hexColumn] = ' ';
|
||||
line[hexColumn] = ' ';
|
||||
line[hexColumn + 1] = ' ';
|
||||
line[charColumn] = ' ';
|
||||
line[charColumn] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
byte b = bytes[i + j];
|
||||
|
||||
line[hexColumn] = HexChars[(b >> 4) & 0xF];
|
||||
line[hexColumn + 1] = HexChars[b & 0xF];
|
||||
line[charColumn] = (b < 32 ? '·' : (char)b);
|
||||
line[hexColumn] = _hexChars[(b >> 4) & 0xF];
|
||||
line[hexColumn + 1] = _hexChars[b & 0xF];
|
||||
line[charColumn] = (b < 32 ? '·' : (char)b);
|
||||
}
|
||||
|
||||
hexColumn += 3;
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.Common.Utilities
|
|||
{
|
||||
public class JsonHelper
|
||||
{
|
||||
private static readonly JsonNamingPolicy SnakeCasePolicy = new SnakeCaseNamingPolicy();
|
||||
private static readonly JsonNamingPolicy _snakeCasePolicy = new SnakeCaseNamingPolicy();
|
||||
private const int DefaultFileWriteBufferSize = 4096;
|
||||
|
||||
/// <summary>
|
||||
|
@ -21,11 +21,11 @@ namespace Ryujinx.Common.Utilities
|
|||
{
|
||||
JsonSerializerOptions options = new()
|
||||
{
|
||||
DictionaryKeyPolicy = SnakeCasePolicy,
|
||||
PropertyNamingPolicy = SnakeCasePolicy,
|
||||
WriteIndented = indented,
|
||||
AllowTrailingCommas = true,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip
|
||||
DictionaryKeyPolicy = _snakeCasePolicy,
|
||||
PropertyNamingPolicy = _snakeCasePolicy,
|
||||
WriteIndented = indented,
|
||||
AllowTrailingCommas = true,
|
||||
ReadCommentHandling = JsonCommentHandling.Skip,
|
||||
};
|
||||
|
||||
return options;
|
||||
|
|
|
@ -12,10 +12,8 @@ namespace Ryujinx.Common.Utilities
|
|||
{
|
||||
return Format(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
return obj.ToString();
|
||||
}
|
||||
|
||||
return obj.ToString();
|
||||
}
|
||||
|
||||
public static string Format(MessagePackObject obj)
|
||||
|
@ -179,19 +177,17 @@ namespace Ryujinx.Common.Utilities
|
|||
{
|
||||
return unchecked((char)('0' + b));
|
||||
}
|
||||
else
|
||||
{
|
||||
return unchecked((char)('A' + (b - 10)));
|
||||
}
|
||||
|
||||
return unchecked((char)('A' + (b - 10)));
|
||||
}
|
||||
|
||||
internal class IndentedStringBuilder
|
||||
{
|
||||
const string DefaultIndent = " ";
|
||||
|
||||
private int _indentCount = 0;
|
||||
private int _newLineIndex = 0;
|
||||
private StringBuilder _builder;
|
||||
private int _indentCount;
|
||||
private int _newLineIndex;
|
||||
private readonly StringBuilder _builder;
|
||||
|
||||
public string IndentString { get; set; } = DefaultIndent;
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace Ryujinx.Common.Utilities
|
|||
return (null, null);
|
||||
}
|
||||
|
||||
IPInterfaceProperties targetProperties = null;
|
||||
IPInterfaceProperties targetProperties = null;
|
||||
UnicastIPAddressInformation targetAddressInfo = null;
|
||||
|
||||
NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using Microsoft.IO;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -10,22 +9,21 @@ namespace Ryujinx.Common.Utilities
|
|||
{
|
||||
public static byte[] StreamToBytes(Stream input)
|
||||
{
|
||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
||||
{
|
||||
input.CopyTo(stream);
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
input.CopyTo(stream);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
public static async Task<byte[]> StreamToBytesAsync(Stream input, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
|
||||
{
|
||||
await input.CopyToAsync(stream, cancellationToken);
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
await input.CopyToAsync(stream, cancellationToken);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,8 +31,7 @@ namespace Ryujinx.Common
|
|||
private const ulong Prime64_4 = 0x85EBCA77C2B2AE63UL;
|
||||
private const ulong Prime64_5 = 0x27D4EB2F165667C5UL;
|
||||
|
||||
private static readonly ulong[] Xxh3InitAcc = new ulong[]
|
||||
{
|
||||
private static readonly ulong[] _xxh3InitAcc = {
|
||||
Prime32_3,
|
||||
Prime64_1,
|
||||
Prime64_2,
|
||||
|
@ -40,7 +39,7 @@ namespace Ryujinx.Common
|
|||
Prime64_4,
|
||||
Prime32_2,
|
||||
Prime64_5,
|
||||
Prime32_1
|
||||
Prime32_1,
|
||||
};
|
||||
|
||||
private static ReadOnlySpan<byte> Xxh3KSecret => new byte[]
|
||||
|
@ -56,23 +55,24 @@ namespace Ryujinx.Common
|
|||
0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb,
|
||||
0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e,
|
||||
0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce,
|
||||
0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e
|
||||
0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
|
||||
};
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong Mult32To64(ulong x, ulong y)
|
||||
{
|
||||
return (ulong)(uint)x * (ulong)(uint)y;
|
||||
return (uint)x * (ulong)(uint)y;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static Hash128 Mult64To128(ulong lhs, ulong rhs)
|
||||
{
|
||||
ulong high = Math.BigMul(lhs, rhs, out ulong low);
|
||||
|
||||
return new Hash128
|
||||
{
|
||||
Low = low,
|
||||
High = high
|
||||
High = high,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,7 @@ namespace Ryujinx.Common
|
|||
private static ulong Mul128Fold64(ulong lhs, ulong rhs)
|
||||
{
|
||||
Hash128 product = Mult64To128(lhs, rhs);
|
||||
|
||||
return product.Low ^ product.High;
|
||||
}
|
||||
|
||||
|
@ -87,6 +88,7 @@ namespace Ryujinx.Common
|
|||
private static ulong XorShift64(ulong v64, int shift)
|
||||
{
|
||||
Debug.Assert(0 <= shift && shift < 64);
|
||||
|
||||
return v64 ^ (v64 >> shift);
|
||||
}
|
||||
|
||||
|
@ -96,6 +98,7 @@ namespace Ryujinx.Common
|
|||
h64 = XorShift64(h64, 37);
|
||||
h64 *= 0x165667919E3779F9UL;
|
||||
h64 = XorShift64(h64, 32);
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
|
@ -107,6 +110,7 @@ namespace Ryujinx.Common
|
|||
h64 ^= h64 >> 29;
|
||||
h64 *= Prime64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
|
@ -165,8 +169,8 @@ namespace Ryujinx.Common
|
|||
{
|
||||
for (int i = 0; i < AccNb; i++)
|
||||
{
|
||||
ulong dataVal = BinaryPrimitives.ReadUInt64LittleEndian(input.Slice(i * sizeof(ulong)));
|
||||
ulong dataKey = dataVal ^ BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(i * sizeof(ulong)));
|
||||
ulong dataVal = BinaryPrimitives.ReadUInt64LittleEndian(input[(i * sizeof(ulong))..]);
|
||||
ulong dataKey = dataVal ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[(i * sizeof(ulong))..]);
|
||||
acc[i ^ 1] += dataVal;
|
||||
acc[i] += Mult32To64((uint)dataKey, dataKey >> 32);
|
||||
}
|
||||
|
@ -236,7 +240,7 @@ namespace Ryujinx.Common
|
|||
{
|
||||
for (int i = 0; i < AccNb; i++)
|
||||
{
|
||||
ulong key64 = BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(i * sizeof(ulong)));
|
||||
ulong key64 = BinaryPrimitives.ReadUInt64LittleEndian(secret[(i * sizeof(ulong))..]);
|
||||
ulong acc64 = acc[i];
|
||||
acc64 = XorShift64(acc64, 47);
|
||||
acc64 ^= key64;
|
||||
|
@ -251,8 +255,8 @@ namespace Ryujinx.Common
|
|||
{
|
||||
for (int n = 0; n < nbStripes; n++)
|
||||
{
|
||||
ReadOnlySpan<byte> inData = input.Slice(n * StripeLen);
|
||||
Xxh3Accumulate512(acc, inData, secret.Slice(n * SecretConsumeRate));
|
||||
ReadOnlySpan<byte> inData = input[(n * StripeLen)..];
|
||||
Xxh3Accumulate512(acc, inData, secret[(n * SecretConsumeRate)..]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,18 +270,18 @@ namespace Ryujinx.Common
|
|||
|
||||
for (int n = 0; n < nbBlocks; n++)
|
||||
{
|
||||
Xxh3Accumulate(acc, input.Slice(n * blockLen), secret, nbStripesPerBlock);
|
||||
Xxh3ScrambleAcc(acc, secret.Slice(secret.Length - StripeLen));
|
||||
Xxh3Accumulate(acc, input[(n * blockLen)..], secret, nbStripesPerBlock);
|
||||
Xxh3ScrambleAcc(acc, secret[^StripeLen..]);
|
||||
}
|
||||
|
||||
Debug.Assert(input.Length > StripeLen);
|
||||
|
||||
int nbStripes = (input.Length - 1 - (blockLen * nbBlocks)) / StripeLen;
|
||||
Debug.Assert(nbStripes <= (secret.Length / SecretConsumeRate));
|
||||
Xxh3Accumulate(acc, input.Slice(nbBlocks * blockLen), secret, nbStripes);
|
||||
Xxh3Accumulate(acc, input[(nbBlocks * blockLen)..], secret, nbStripes);
|
||||
|
||||
ReadOnlySpan<byte> p = input.Slice(input.Length - StripeLen);
|
||||
Xxh3Accumulate512(acc, p, secret.Slice(secret.Length - StripeLen - SecretLastAccStart));
|
||||
ReadOnlySpan<byte> p = input[^StripeLen..];
|
||||
Xxh3Accumulate512(acc, p, secret[(secret.Length - StripeLen - SecretLastAccStart)..]);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
@ -285,7 +289,7 @@ namespace Ryujinx.Common
|
|||
{
|
||||
return Mul128Fold64(
|
||||
acc[0] ^ BinaryPrimitives.ReadUInt64LittleEndian(secret),
|
||||
acc[1] ^ BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(8)));
|
||||
acc[1] ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[8..]));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
@ -295,7 +299,7 @@ namespace Ryujinx.Common
|
|||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
result64 += Xxh3Mix2Accs(acc.Slice(2 * i), secret.Slice(16 * i));
|
||||
result64 += Xxh3Mix2Accs(acc[(2 * i)..], secret[(16 * i)..]);
|
||||
}
|
||||
|
||||
return Xxh3Avalanche(result64);
|
||||
|
@ -305,7 +309,7 @@ namespace Ryujinx.Common
|
|||
private static Hash128 Xxh3HashLong128bInternal(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret)
|
||||
{
|
||||
Span<ulong> acc = stackalloc ulong[AccNb];
|
||||
Xxh3InitAcc.CopyTo(acc);
|
||||
_xxh3InitAcc.CopyTo(acc);
|
||||
|
||||
Xxh3HashLongInternalLoop(acc, input, secret);
|
||||
|
||||
|
@ -314,11 +318,11 @@ namespace Ryujinx.Common
|
|||
|
||||
return new Hash128
|
||||
{
|
||||
Low = Xxh3MergeAccs(acc, secret.Slice(SecretMergeAccsStart), (ulong)input.Length * Prime64_1),
|
||||
Low = Xxh3MergeAccs(acc, secret[SecretMergeAccsStart..], (ulong)input.Length * Prime64_1),
|
||||
High = Xxh3MergeAccs(
|
||||
acc,
|
||||
secret.Slice(secret.Length - acc.Length * sizeof(ulong) - SecretMergeAccsStart),
|
||||
~((ulong)input.Length * Prime64_2))
|
||||
secret[(secret.Length - acc.Length * sizeof(ulong) - SecretMergeAccsStart)..],
|
||||
~((ulong)input.Length * Prime64_2)),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -332,15 +336,15 @@ namespace Ryujinx.Common
|
|||
|
||||
uint combinedL = ((uint)c1 << 16) | ((uint)c2 << 24) | c3 | ((uint)input.Length << 8);
|
||||
uint combinedH = BitOperations.RotateLeft(BinaryPrimitives.ReverseEndianness(combinedL), 13);
|
||||
ulong bitFlipL = (BinaryPrimitives.ReadUInt32LittleEndian(secret) ^ BinaryPrimitives.ReadUInt32LittleEndian(secret.Slice(4))) + seed;
|
||||
ulong bitFlipH = (BinaryPrimitives.ReadUInt32LittleEndian(secret.Slice(8)) ^ BinaryPrimitives.ReadUInt32LittleEndian(secret.Slice(12))) - seed;
|
||||
ulong bitFlipL = (BinaryPrimitives.ReadUInt32LittleEndian(secret) ^ BinaryPrimitives.ReadUInt32LittleEndian(secret[4..])) + seed;
|
||||
ulong bitFlipH = (BinaryPrimitives.ReadUInt32LittleEndian(secret[8..]) ^ BinaryPrimitives.ReadUInt32LittleEndian(secret[12..])) - seed;
|
||||
ulong keyedLo = combinedL ^ bitFlipL;
|
||||
ulong keyedHi = combinedH ^ bitFlipH;
|
||||
|
||||
return new Hash128
|
||||
{
|
||||
Low = Xxh64Avalanche(keyedLo),
|
||||
High = Xxh64Avalanche(keyedHi)
|
||||
High = Xxh64Avalanche(keyedHi),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -351,9 +355,9 @@ namespace Ryujinx.Common
|
|||
seed ^= BinaryPrimitives.ReverseEndianness((uint)seed) << 32;
|
||||
|
||||
uint inputLo = BinaryPrimitives.ReadUInt32LittleEndian(input);
|
||||
uint inputHi = BinaryPrimitives.ReadUInt32LittleEndian(input.Slice(input.Length - 4));
|
||||
uint inputHi = BinaryPrimitives.ReadUInt32LittleEndian(input[^4..]);
|
||||
ulong input64 = inputLo + ((ulong)inputHi << 32);
|
||||
ulong bitFlip = (BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(16)) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(24))) + seed;
|
||||
ulong bitFlip = (BinaryPrimitives.ReadUInt64LittleEndian(secret[16..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[24..])) + seed;
|
||||
ulong keyed = input64 ^ bitFlip;
|
||||
|
||||
Hash128 m128 = Mult64To128(keyed, Prime64_1 + ((ulong)input.Length << 2));
|
||||
|
@ -365,6 +369,7 @@ namespace Ryujinx.Common
|
|||
m128.Low *= 0x9FB21C651E98DF25UL;
|
||||
m128.Low = XorShift64(m128.Low, 28);
|
||||
m128.High = Xxh3Avalanche(m128.High);
|
||||
|
||||
return m128;
|
||||
}
|
||||
|
||||
|
@ -372,10 +377,10 @@ namespace Ryujinx.Common
|
|||
{
|
||||
Debug.Assert(9 <= input.Length && input.Length <= 16);
|
||||
|
||||
ulong bitFlipL = (BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(32)) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(40))) - seed;
|
||||
ulong bitFlipH = (BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(48)) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(56))) + seed;
|
||||
ulong bitFlipL = (BinaryPrimitives.ReadUInt64LittleEndian(secret[32..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[40..])) - seed;
|
||||
ulong bitFlipH = (BinaryPrimitives.ReadUInt64LittleEndian(secret[48..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[56..])) + seed;
|
||||
ulong inputLo = BinaryPrimitives.ReadUInt64LittleEndian(input);
|
||||
ulong inputHi = BinaryPrimitives.ReadUInt64LittleEndian(input.Slice(input.Length - 8));
|
||||
ulong inputHi = BinaryPrimitives.ReadUInt64LittleEndian(input[^8..]);
|
||||
|
||||
Hash128 m128 = Mult64To128(inputLo ^ inputHi ^ bitFlipL, Prime64_1);
|
||||
m128.Low += ((ulong)input.Length - 1) << 54;
|
||||
|
@ -387,6 +392,7 @@ namespace Ryujinx.Common
|
|||
h128.High += m128.High * Prime64_2;
|
||||
h128.Low = Xxh3Avalanche(h128.Low);
|
||||
h128.High = Xxh3Avalanche(h128.High);
|
||||
|
||||
return h128;
|
||||
}
|
||||
|
||||
|
@ -398,40 +404,43 @@ namespace Ryujinx.Common
|
|||
{
|
||||
return Xxh3Len9To16128b(input, secret, seed);
|
||||
}
|
||||
else if (input.Length >= 4)
|
||||
|
||||
if (input.Length >= 4)
|
||||
{
|
||||
return Xxh3Len4To8128b(input, secret, seed);
|
||||
}
|
||||
else if (input.Length != 0)
|
||||
|
||||
if (input.Length != 0)
|
||||
{
|
||||
return Xxh3Len1To3128b(input, secret, seed);
|
||||
}
|
||||
else
|
||||
{
|
||||
Hash128 h128 = new Hash128();
|
||||
ulong bitFlipL = BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(64)) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(72));
|
||||
ulong bitFlipH = BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(80)) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(88));
|
||||
h128.Low = Xxh64Avalanche(seed ^ bitFlipL);
|
||||
h128.High = Xxh64Avalanche(seed ^ bitFlipH);
|
||||
return h128;
|
||||
}
|
||||
|
||||
Hash128 h128 = new();
|
||||
ulong bitFlipL = BinaryPrimitives.ReadUInt64LittleEndian(secret[64..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[72..]);
|
||||
ulong bitFlipH = BinaryPrimitives.ReadUInt64LittleEndian(secret[80..]) ^ BinaryPrimitives.ReadUInt64LittleEndian(secret[88..]);
|
||||
h128.Low = Xxh64Avalanche(seed ^ bitFlipL);
|
||||
h128.High = Xxh64Avalanche(seed ^ bitFlipH);
|
||||
|
||||
return h128;
|
||||
}
|
||||
|
||||
private static ulong Xxh3Mix16b(ReadOnlySpan<byte> input, ReadOnlySpan<byte> secret, ulong seed)
|
||||
{
|
||||
ulong inputLo = BinaryPrimitives.ReadUInt64LittleEndian(input);
|
||||
ulong inputHi = BinaryPrimitives.ReadUInt64LittleEndian(input.Slice(8));
|
||||
ulong inputHi = BinaryPrimitives.ReadUInt64LittleEndian(input[8..]);
|
||||
|
||||
return Mul128Fold64(
|
||||
inputLo ^ (BinaryPrimitives.ReadUInt64LittleEndian(secret) + seed),
|
||||
inputHi ^ (BinaryPrimitives.ReadUInt64LittleEndian(secret.Slice(8)) - seed));
|
||||
inputHi ^ (BinaryPrimitives.ReadUInt64LittleEndian(secret[8..]) - seed));
|
||||
}
|
||||
|
||||
private static Hash128 Xxh128Mix32b(Hash128 acc, ReadOnlySpan<byte> input, ReadOnlySpan<byte> input2, ReadOnlySpan<byte> secret, ulong seed)
|
||||
{
|
||||
acc.Low += Xxh3Mix16b(input, secret, seed);
|
||||
acc.Low ^= BinaryPrimitives.ReadUInt64LittleEndian(input2) + BinaryPrimitives.ReadUInt64LittleEndian(input2.Slice(8));
|
||||
acc.High += Xxh3Mix16b(input2, secret.Slice(16), seed);
|
||||
acc.High ^= BinaryPrimitives.ReadUInt64LittleEndian(input) + BinaryPrimitives.ReadUInt64LittleEndian(input.Slice(8));
|
||||
acc.Low ^= BinaryPrimitives.ReadUInt64LittleEndian(input2) + BinaryPrimitives.ReadUInt64LittleEndian(input2[8..]);
|
||||
acc.High += Xxh3Mix16b(input2, secret[16..], seed);
|
||||
acc.High ^= BinaryPrimitives.ReadUInt64LittleEndian(input) + BinaryPrimitives.ReadUInt64LittleEndian(input[8..]);
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
|
@ -440,10 +449,10 @@ namespace Ryujinx.Common
|
|||
Debug.Assert(secret.Length >= SecretSizeMin);
|
||||
Debug.Assert(16 < input.Length && input.Length <= 128);
|
||||
|
||||
Hash128 acc = new Hash128
|
||||
Hash128 acc = new()
|
||||
{
|
||||
Low = (ulong)input.Length * Prime64_1,
|
||||
High = 0
|
||||
High = 0,
|
||||
};
|
||||
|
||||
if (input.Length > 32)
|
||||
|
@ -452,21 +461,22 @@ namespace Ryujinx.Common
|
|||
{
|
||||
if (input.Length > 96)
|
||||
{
|
||||
acc = Xxh128Mix32b(acc, input.Slice(48), input.Slice(input.Length - 64), secret.Slice(96), seed);
|
||||
acc = Xxh128Mix32b(acc, input[48..], input[^64..], secret[96..], seed);
|
||||
}
|
||||
acc = Xxh128Mix32b(acc, input.Slice(32), input.Slice(input.Length - 48), secret.Slice(64), seed);
|
||||
acc = Xxh128Mix32b(acc, input[32..], input[^48..], secret[64..], seed);
|
||||
}
|
||||
acc = Xxh128Mix32b(acc, input.Slice(16), input.Slice(input.Length - 32), secret.Slice(32), seed);
|
||||
acc = Xxh128Mix32b(acc, input[16..], input[^32..], secret[32..], seed);
|
||||
}
|
||||
acc = Xxh128Mix32b(acc, input, input.Slice(input.Length - 16), secret, seed);
|
||||
acc = Xxh128Mix32b(acc, input, input[^16..], secret, seed);
|
||||
|
||||
Hash128 h128 = new Hash128
|
||||
Hash128 h128 = new()
|
||||
{
|
||||
Low = acc.Low + acc.High,
|
||||
High = acc.Low * Prime64_1 + acc.High * Prime64_4 + ((ulong)input.Length - seed) * Prime64_2
|
||||
High = acc.Low * Prime64_1 + acc.High * Prime64_4 + ((ulong)input.Length - seed) * Prime64_2,
|
||||
};
|
||||
h128.Low = Xxh3Avalanche(h128.Low);
|
||||
h128.High = 0UL - Xxh3Avalanche(h128.High);
|
||||
|
||||
return h128;
|
||||
}
|
||||
|
||||
|
@ -475,7 +485,7 @@ namespace Ryujinx.Common
|
|||
Debug.Assert(secret.Length >= SecretSizeMin);
|
||||
Debug.Assert(128 < input.Length && input.Length <= 240);
|
||||
|
||||
Hash128 acc = new Hash128();
|
||||
Hash128 acc = new();
|
||||
|
||||
int nbRounds = input.Length / 32;
|
||||
acc.Low = (ulong)input.Length * Prime64_1;
|
||||
|
@ -483,7 +493,7 @@ namespace Ryujinx.Common
|
|||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
acc = Xxh128Mix32b(acc, input.Slice(32 * i), input.Slice(32 * i + 16), secret.Slice(32 * i), seed);
|
||||
acc = Xxh128Mix32b(acc, input[(32 * i)..], input[(32 * i + 16)..], secret[(32 * i)..], seed);
|
||||
}
|
||||
|
||||
acc.Low = Xxh3Avalanche(acc.Low);
|
||||
|
@ -492,18 +502,19 @@ namespace Ryujinx.Common
|
|||
|
||||
for (int i = 4; i < nbRounds; i++)
|
||||
{
|
||||
acc = Xxh128Mix32b(acc, input.Slice(32 * i), input.Slice(32 * i + 16), secret.Slice(MidSizeStartOffset + 32 * (i - 4)), seed);
|
||||
acc = Xxh128Mix32b(acc, input[(32 * i)..], input[(32 * i + 16)..], secret[(MidSizeStartOffset + 32 * (i - 4))..], seed);
|
||||
}
|
||||
|
||||
acc = Xxh128Mix32b(acc, input.Slice(input.Length - 16), input.Slice(input.Length - 32), secret.Slice(SecretSizeMin - MidSizeLastOffset - 16), 0UL - seed);
|
||||
acc = Xxh128Mix32b(acc, input[^16..], input[^32..], secret[(SecretSizeMin - MidSizeLastOffset - 16)..], 0UL - seed);
|
||||
|
||||
Hash128 h128 = new Hash128
|
||||
Hash128 h128 = new()
|
||||
{
|
||||
Low = acc.Low + acc.High,
|
||||
High = acc.Low * Prime64_1 + acc.High * Prime64_4 + ((ulong)input.Length - seed) * Prime64_2
|
||||
High = acc.Low * Prime64_1 + acc.High * Prime64_4 + ((ulong)input.Length - seed) * Prime64_2,
|
||||
};
|
||||
h128.Low = Xxh3Avalanche(h128.Low);
|
||||
h128.High = 0UL - Xxh3Avalanche(h128.High);
|
||||
|
||||
return h128;
|
||||
}
|
||||
|
||||
|
@ -515,18 +526,18 @@ namespace Ryujinx.Common
|
|||
{
|
||||
return Xxh3Len0To16128b(input, secret, seed);
|
||||
}
|
||||
else if (input.Length <= 128)
|
||||
|
||||
if (input.Length <= 128)
|
||||
{
|
||||
return Xxh3Len17To128128b(input, secret, seed);
|
||||
}
|
||||
else if (input.Length <= 240)
|
||||
|
||||
if (input.Length <= 240)
|
||||
{
|
||||
return Xxh3Len129To240128b(input, secret, seed);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Xxh3HashLong128bInternal(input, secret);
|
||||
}
|
||||
|
||||
return Xxh3HashLong128bInternal(input, secret);
|
||||
}
|
||||
|
||||
public static Hash128 ComputeHash(ReadOnlySpan<byte> input)
|
||||
|
|
|
@ -69,8 +69,8 @@ namespace Ryujinx.HLE.HOS.Services.Audio.AudioRenderer
|
|||
|
||||
ReadOnlyMemory<byte> input = context.Memory.GetSpan(inputPosition, (int)inputSize).ToArray();
|
||||
|
||||
using (IMemoryOwner<byte> outputOwner = ByteMemoryPool.Shared.RentCleared(outputSize))
|
||||
using (IMemoryOwner<byte> performanceOutputOwner = ByteMemoryPool.Shared.RentCleared(performanceOutputSize))
|
||||
using (IMemoryOwner<byte> outputOwner = ByteMemoryPool.RentCleared(outputSize))
|
||||
using (IMemoryOwner<byte> performanceOutputOwner = ByteMemoryPool.RentCleared(performanceOutputSize))
|
||||
{
|
||||
Memory<byte> output = outputOwner.Memory;
|
||||
Memory<byte> performanceOutput = performanceOutputOwner.Memory;
|
||||
|
|
|
@ -439,7 +439,7 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
{
|
||||
const int messageSize = 0x100;
|
||||
|
||||
using IMemoryOwner<byte> reqDataOwner = ByteMemoryPool.Shared.Rent(messageSize);
|
||||
using IMemoryOwner<byte> reqDataOwner = ByteMemoryPool.Rent(messageSize);
|
||||
|
||||
Span<byte> reqDataSpan = reqDataOwner.Memory.Span;
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||
|
||||
ReadOnlySpan<byte> inputParcel = context.Memory.GetSpan(dataPos, (int)dataSize);
|
||||
|
||||
using (IMemoryOwner<byte> outputParcelOwner = ByteMemoryPool.Shared.RentCleared(replySize))
|
||||
using (IMemoryOwner<byte> outputParcelOwner = ByteMemoryPool.RentCleared(replySize))
|
||||
{
|
||||
Span<byte> outputParcel = outputParcelOwner.Memory.Span;
|
||||
|
||||
|
|
Loading…
Reference in a new issue