Ryujinx/Ryujinx.Common/Utilities/EmbeddedResources.cs
jhorv 5131b71437
Reducing memory allocations (#4537)
* add RecyclableMemoryStream dependency and MemoryStreamManager

* organize BinaryReader/BinaryWriter extensions

* add StreamExtensions to reduce need for BinaryWriter

* simple replacments of MemoryStream with RecyclableMemoryStream

* add write ReadOnlySequence<byte> support to IVirtualMemoryManager

* avoid 0-length array creation

* rework IpcMessage and related types to greatly reduce memory allocation by using RecylableMemoryStream, keeping streams around longer, avoiding their creation when possible, and avoiding creation of BinaryReader and BinaryWriter when possible

* reduce LINQ-induced memory allocations with custom methods to query KPriorityQueue

* use RecyclableMemoryStream in StreamUtils, and use StreamUtils in EmbeddedResources

* add constants for nanosecond/millisecond conversions

* code formatting

* XML doc adjustments

* fix: StreamExtension.WriteByte not writing non-zero values for lengths <= 16

* XML Doc improvements. Implement StreamExtensions.WriteByte() block writes for large-enough count values.

* add copyless path for StreamExtension.Write(ReadOnlySpan<int>)

* add default implementation of IVirtualMemoryManager.Write(ulong, ReadOnlySequence<byte>); remove previous explicit implementations

* code style fixes

* remove LINQ completely from KScheduler/KPriorityQueue by implementing a custom struct-based enumerator
2023-03-17 13:14:50 +01:00

148 lines
4.1 KiB
C#

using Ryujinx.Common.Memory;
using Ryujinx.Common.Utilities;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
namespace Ryujinx.Common
{
public static class EmbeddedResources
{
private readonly static Assembly ResourceAssembly;
static EmbeddedResources()
{
ResourceAssembly = Assembly.GetAssembly(typeof(EmbeddedResources));
}
public static byte[] Read(string filename)
{
var (assembly, path) = ResolveManifestPath(filename);
return Read(assembly, path);
}
public static Task<byte[]> ReadAsync(string filename)
{
var (assembly, path) = ResolveManifestPath(filename);
return ReadAsync(assembly, path);
}
public static byte[] Read(Assembly assembly, string filename)
{
using (var stream = GetStream(assembly, filename))
{
if (stream == null)
{
return null;
}
return StreamUtils.StreamToBytes(stream);
}
}
public async static Task<byte[]> ReadAsync(Assembly assembly, string filename)
{
using (var stream = GetStream(assembly, filename))
{
if (stream == null)
{
return null;
}
return await StreamUtils.StreamToBytesAsync(stream);
}
}
public static string ReadAllText(string filename)
{
var (assembly, path) = ResolveManifestPath(filename);
return ReadAllText(assembly, path);
}
public static Task<string> ReadAllTextAsync(string filename)
{
var (assembly, path) = ResolveManifestPath(filename);
return ReadAllTextAsync(assembly, path);
}
public static string ReadAllText(Assembly assembly, string filename)
{
using (var stream = GetStream(assembly, filename))
{
if (stream == null)
{
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))
{
if (stream == null)
{
return null;
}
using (var reader = new StreamReader(stream))
{
return await reader.ReadToEndAsync();
}
}
}
public static Stream GetStream(string filename)
{
var (assembly, path) = ResolveManifestPath(filename);
return GetStream(assembly, path);
}
public static Stream GetStream(Assembly assembly, string filename)
{
var namespace_ = assembly.GetName().Name;
var manifestUri = namespace_ + "." + filename.Replace('/', '.');
var stream = assembly.GetManifestResourceStream(manifestUri);
return stream;
}
public static string[] GetAllAvailableResources(string path, string ext = "")
{
return ResolveManifestPath(path).Item1.GetManifestResourceNames()
.Where(r => r.EndsWith(ext))
.ToArray();
}
private static (Assembly, string) ResolveManifestPath(string filename)
{
var segments = filename.Split('/', 2, StringSplitOptions.RemoveEmptyEntries);
if (segments.Length >= 2)
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
if (assembly.GetName().Name == segments[0])
{
return (assembly, segments[1]);
}
}
}
return (ResourceAssembly, filename);
}
}
}