Fixup ProgramIndexMapInfoManager

This commit is contained in:
Alex Barney 2022-01-12 16:29:42 -07:00
parent 9803634284
commit 814ae34642
4 changed files with 157 additions and 125 deletions

View file

@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using LibHac.Fs;
using LibHac.Ncm;
using LibHac.Os;
using LibHac.Util;
namespace LibHac.FsSrv.Impl;
/// <summary>
/// Keeps track of the program IDs and program indexes of each program in a multi-program application.
/// </summary>
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
public class ProgramIndexMapInfoManager : IDisposable
{
private LinkedList<ProgramIndexMapInfo> _mapEntries;
private SdkMutexType _mutex;
public ProgramIndexMapInfoManager()
{
_mapEntries = new LinkedList<ProgramIndexMapInfo>();
_mutex = new SdkMutexType();
}
public void Dispose()
{
Clear();
}
/// <summary>
/// Unregisters any previously registered program index map info and registers the provided map info.
/// </summary>
/// <param name="programIndexMapInfo">The program map info entries to register.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.</returns>
public Result Reset(ReadOnlySpan<ProgramIndexMapInfo> programIndexMapInfo)
{
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
ClearImpl();
for (int i = 0; i < programIndexMapInfo.Length; i++)
{
var entry = new ProgramIndexMapInfo
{
ProgramId = programIndexMapInfo[i].ProgramId,
MainProgramId = programIndexMapInfo[i].MainProgramId,
ProgramIndex = programIndexMapInfo[i].ProgramIndex
};
_mapEntries.AddLast(entry);
}
// We skip running ClearImpl() if the allocation failed because we don't need to worry about that in C#
return Result.Success;
}
/// <summary>
/// Unregisters all currently registered program index map info.
/// </summary>
public void Clear()
{
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
ClearImpl();
}
/// <summary>
/// Gets the <see cref="ProgramIndexMapInfo"/> associated with the specified program ID.
/// </summary>
/// <param name="programId">The program ID of the map info to get.</param>
/// <returns>If the program ID was found, the <see cref="ProgramIndexMapInfo"/> associated
/// with that ID; otherwise, <see langword="null"/>.</returns>
public Optional<ProgramIndexMapInfo> Get(ProgramId programId)
{
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
return GetImpl((in ProgramIndexMapInfo x) => x.ProgramId == programId);
}
/// <summary>
/// Gets the <see cref="ProgramId"/> of the program with index <paramref name="programIndex"/> in the
/// multi-program app <paramref name="programId"/> is part of.
/// </summary>
/// <param name="programId">A program ID in the multi-program app to query.</param>
/// <param name="programIndex">The index of the program to get.</param>
/// <returns>If the program exists, the ID of the program with the specified index,
/// otherwise <see cref="ProgramId.InvalidId"/></returns>
public ProgramId GetProgramId(ProgramId programId, byte programIndex)
{
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
Optional<ProgramIndexMapInfo> programIndexMapInfo =
GetImpl((in ProgramIndexMapInfo x) => x.ProgramId == programId);
if (!programIndexMapInfo.HasValue)
return ProgramId.InvalidId;
Optional<ProgramIndexMapInfo> targetProgramIndexMapInfo = GetImpl((in ProgramIndexMapInfo x) =>
x.MainProgramId == programIndexMapInfo.Value.MainProgramId && x.ProgramIndex == programIndex);
if (!targetProgramIndexMapInfo.HasValue)
return ProgramId.InvalidId;
return targetProgramIndexMapInfo.Value.ProgramId;
}
/// <summary>
/// Gets the number of currently registered programs,
/// </summary>
/// <returns>The number of registered programs.</returns>
public int GetProgramCount()
{
using ScopedLock<SdkMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
return _mapEntries.Count;
}
private delegate bool EntrySelector(in ProgramIndexMapInfo candidate);
private Optional<ProgramIndexMapInfo> GetImpl(EntrySelector selector)
{
var returnValue = new Optional<ProgramIndexMapInfo>();
foreach (ProgramIndexMapInfo entry in _mapEntries)
{
if (selector(in entry))
{
returnValue.Set(default);
returnValue.Value.ProgramId = entry.ProgramId;
returnValue.Value.MainProgramId = entry.MainProgramId;
returnValue.Value.ProgramIndex = entry.ProgramIndex;
break;
}
}
return returnValue;
}
private void ClearImpl()
{
_mapEntries.Clear();
}
}

View file

@ -1,121 +0,0 @@
using System;
using System.Collections.Generic;
using LibHac.Fs;
using LibHac.Ncm;
using LibHac.Util;
namespace LibHac.FsSrv;
/// <summary>
/// Keeps track of the program IDs and program indexes of each program in a multi-program application.
/// </summary>
/// <remarks>Based on FS 10.0.0 (nnSdk 10.4.0)</remarks>
public class ProgramIndexMapInfoManager
{
private LinkedList<ProgramIndexMapInfo> MapEntries { get; } = new LinkedList<ProgramIndexMapInfo>();
/// <summary>
/// Unregisters any previously registered program index map info and registers the provided map info.
/// </summary>
/// <param name="programIndexMapInfo">The program map info entries to register.</param>
/// <returns><see cref="Result.Success"/>: The operation was successful.</returns>
public Result Reset(ReadOnlySpan<ProgramIndexMapInfo> programIndexMapInfo)
{
lock (MapEntries)
{
ClearImpl();
for (int i = 0; i < programIndexMapInfo.Length; i++)
{
MapEntries.AddLast(programIndexMapInfo[i]);
}
return Result.Success;
}
}
/// <summary>
/// Unregisters all currently registered program index map info.
/// </summary>
public void Clear()
{
lock (MapEntries)
{
ClearImpl();
}
}
/// <summary>
/// Gets the <see cref="ProgramIndexMapInfo"/> associated with the specified program ID.
/// </summary>
/// <param name="programId">The program ID of the map info to get.</param>
/// <returns>If the program ID was found, the <see cref="ProgramIndexMapInfo"/> associated
/// with that ID; otherwise, <see langword="null"/>.</returns>
public Optional<ProgramIndexMapInfo> Get(ProgramId programId)
{
lock (MapEntries)
{
return GetImpl((in ProgramIndexMapInfo x) => x.ProgramId == programId);
}
}
/// <summary>
/// Gets the <see cref="ProgramId"/> of the program with index <paramref name="programIndex"/> in the
/// multi-program app <paramref name="programId"/> is part of.
/// </summary>
/// <param name="programId">A program ID in the multi-program app to query.</param>
/// <param name="programIndex">The index of the program to get.</param>
/// <returns>If the program exists, the ID of the program with the specified index,
/// otherwise <see cref="ProgramId.InvalidId"/></returns>
public ProgramId GetProgramId(ProgramId programId, byte programIndex)
{
lock (MapEntries)
{
Optional<ProgramIndexMapInfo> mainProgramMapInfo =
GetImpl((in ProgramIndexMapInfo x) => x.ProgramId == programId);
if (!mainProgramMapInfo.HasValue)
return ProgramId.InvalidId;
Optional<ProgramIndexMapInfo> requestedMapInfo = GetImpl((in ProgramIndexMapInfo x) =>
x.MainProgramId == mainProgramMapInfo.Value.MainProgramId && x.ProgramIndex == programIndex);
if (!requestedMapInfo.HasValue)
return ProgramId.InvalidId;
return requestedMapInfo.Value.ProgramId;
}
}
/// <summary>
/// Gets the number of currently registered programs,
/// </summary>
/// <returns>The number of registered programs.</returns>
public int GetProgramCount()
{
lock (MapEntries)
{
return MapEntries.Count;
}
}
private delegate bool EntrySelector(in ProgramIndexMapInfo candidate);
private Optional<ProgramIndexMapInfo> GetImpl(EntrySelector selector)
{
foreach (ProgramIndexMapInfo entry in MapEntries)
{
if (selector(in entry))
{
return new Optional<ProgramIndexMapInfo>(entry);
}
}
return new Optional<ProgramIndexMapInfo>();
}
private void ClearImpl()
{
MapEntries.Clear();
}
}

View file

@ -1,4 +1,5 @@
using System.Runtime.InteropServices;
using System;
using System.Runtime.InteropServices;
using LibHac.Common;
using LibHac.Diag;
@ -36,6 +37,12 @@ public struct Optional<T>
public static implicit operator Optional<T>(in T value) => new Optional<T>(in value);
public void Set(T value)
{
_value = value;
_hasValue = true;
}
public void Set(in T value)
{
_value = value;
@ -47,4 +54,4 @@ public struct Optional<T>
_hasValue = false;
_value = default;
}
}
}

View file

@ -2,7 +2,6 @@
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Shim;
using LibHac.FsSrv;
using LibHac.FsSrv.Impl;
using LibHac.Ncm;
using LibHac.Util;
@ -194,4 +193,4 @@ public class ProgramIndexMapInfoTests
Assert.False(manager.Get(new ProgramId(2)).HasValue);
}
}
}