Use generic math in Util.Alignment

This commit is contained in:
Alex Barney 2022-12-13 19:10:10 -07:00
parent 7fce26e899
commit df77de365c
23 changed files with 232 additions and 133 deletions

View file

@ -242,11 +242,11 @@ internal static class AssertImpl
public static bool IsAligned(long value, int alignment) public static bool IsAligned(long value, int alignment)
{ {
return Alignment.IsAlignedPow2(value, (uint)alignment); return Alignment.IsAligned(value, (uint)alignment);
} }
public static bool IsAligned(ulong value, int alignment) public static bool IsAligned(ulong value, int alignment)
{ {
return Alignment.IsAlignedPow2(value, (uint)alignment); return Alignment.IsAligned(value, (uint)alignment);
} }
} }

View file

@ -20,7 +20,7 @@ public static class ApplicationSaveDataManagement
private static long RoundUpOccupationSize(long size) private static long RoundUpOccupationSize(long size)
{ {
return Alignment.AlignUpPow2(size, SaveDataBlockSize); return Alignment.AlignUp(size, SaveDataBlockSize);
} }
private static long CalculateSaveDataExtensionContextFileSize(long saveDataSize, long saveDataJournalSize) private static long CalculateSaveDataExtensionContextFileSize(long saveDataSize, long saveDataJournalSize)
@ -48,10 +48,10 @@ public static class ApplicationSaveDataManagement
if (availableSize < saveDataSize || journalSize < saveDataJournalSize) if (availableSize < saveDataSize || journalSize < saveDataJournalSize)
{ {
// Make sure the new sizes are valid // Make sure the new sizes are valid
if (availableSize < saveDataSize && !Alignment.IsAlignedPow2(saveDataSize, SaveDataExtensionSizeAlignment)) if (availableSize < saveDataSize && !Alignment.IsAligned(saveDataSize, SaveDataExtensionSizeAlignment))
return ResultFs.ExtensionSizeInvalid.Log(); return ResultFs.ExtensionSizeInvalid.Log();
if (journalSize < saveDataJournalSize && !Alignment.IsAlignedPow2(saveDataJournalSize, SaveDataExtensionSizeAlignment)) if (journalSize < saveDataJournalSize && !Alignment.IsAligned(saveDataJournalSize, SaveDataExtensionSizeAlignment))
return ResultFs.ExtensionSizeInvalid.Log(); return ResultFs.ExtensionSizeInvalid.Log();
long newSaveDataSize = Math.Max(saveDataSize, availableSize); long newSaveDataSize = Math.Max(saveDataSize, availableSize);

View file

@ -171,7 +171,7 @@ public ref struct Path
if (_buffer is not null && _buffer.Length > length) if (_buffer is not null && _buffer.Length > length)
return Result.Success; return Result.Success;
int alignedLength = Alignment.AlignUpPow2(length, WriteBufferAlignmentLength); int alignedLength = Alignment.AlignUp(length, WriteBufferAlignmentLength);
byte[] buffer = ArrayPool<byte>.Shared.Rent(alignedLength); byte[] buffer = ArrayPool<byte>.Shared.Rent(alignedLength);
byte[] oldBuffer = _buffer; byte[] oldBuffer = _buffer;
@ -321,7 +321,7 @@ public ref struct Path
{ {
Assert.SdkRequiresNotNull(buffer); Assert.SdkRequiresNotNull(buffer);
Assert.SdkRequires(length > 0); Assert.SdkRequires(length > 0);
Assert.SdkRequires(Alignment.IsAlignedPow2(length, WriteBufferAlignmentLength)); Assert.SdkRequires(Alignment.IsAligned(length, WriteBufferAlignmentLength));
byte[] oldBuffer = _writeBuffer; byte[] oldBuffer = _writeBuffer;
_writeBuffer = buffer; _writeBuffer = buffer;
@ -359,7 +359,7 @@ public ref struct Path
if (_writeBufferLength > length) if (_writeBufferLength > length)
return Result.Success; return Result.Success;
int alignedLength = Alignment.AlignUpPow2(length, WriteBufferAlignmentLength); int alignedLength = Alignment.AlignUp(length, WriteBufferAlignmentLength);
byte[] buffer = ArrayPool<byte>.Shared.Rent(alignedLength); byte[] buffer = ArrayPool<byte>.Shared.Rent(alignedLength);
SetModifiableBuffer(buffer, alignedLength); SetModifiableBuffer(buffer, alignedLength);
@ -1134,7 +1134,7 @@ public ref struct Path
if (flags.IsWindowsPathAllowed() && WindowsPath.IsWindowsPath(_string, true)) if (flags.IsWindowsPathAllowed() && WindowsPath.IsWindowsPath(_string, true))
bufferLength += 1; bufferLength += 1;
int alignedBufferLength = Alignment.AlignUpPow2(bufferLength, WriteBufferAlignmentLength); int alignedBufferLength = Alignment.AlignUp(bufferLength, WriteBufferAlignmentLength);
byte[] rentedArray = null; byte[] rentedArray = null;
try try

View file

@ -39,8 +39,8 @@ public readonly struct FileRegion
public FileRegion ExpandAndAlign(uint alignment) public FileRegion ExpandAndAlign(uint alignment)
{ {
long alignedStartOffset = Alignment.AlignDownPow2(Offset, alignment); long alignedStartOffset = Alignment.AlignDown(Offset, alignment);
long alignedEndOffset = Alignment.AlignUpPow2(GetEndOffset(), alignment); long alignedEndOffset = Alignment.AlignUp(GetEndOffset(), alignment);
long alignedSize = alignedEndOffset - alignedStartOffset; long alignedSize = alignedEndOffset - alignedStartOffset;
return new FileRegion(alignedStartOffset, alignedSize); return new FileRegion(alignedStartOffset, alignedSize);
@ -48,8 +48,8 @@ public readonly struct FileRegion
public FileRegion ShrinkAndAlign(uint alignment) public FileRegion ShrinkAndAlign(uint alignment)
{ {
long alignedStartOffset = Alignment.AlignUpPow2(Offset, alignment); long alignedStartOffset = Alignment.AlignUp(Offset, alignment);
long alignedEndOffset = Alignment.AlignDownPow2(GetEndOffset(), alignment); long alignedEndOffset = Alignment.AlignDown(GetEndOffset(), alignment);
long alignedSize = alignedEndOffset - alignedStartOffset; long alignedSize = alignedEndOffset - alignedStartOffset;
return new FileRegion(alignedStartOffset, alignedSize); return new FileRegion(alignedStartOffset, alignedSize);

View file

@ -120,10 +120,10 @@ public static class SaveData
public static Result EnsureSaveDataImpl(this FileSystemClientImpl fs, UserId userId, long saveDataSize, public static Result EnsureSaveDataImpl(this FileSystemClientImpl fs, UserId userId, long saveDataSize,
long saveDataJournalSize, bool extendIfNeeded) long saveDataJournalSize, bool extendIfNeeded)
{ {
if (!Alignment.IsAlignedPow2(saveDataSize, SaveDataBlockSize)) if (!Alignment.IsAligned(saveDataSize, SaveDataBlockSize))
return ResultFs.InvalidSize.Log(); return ResultFs.InvalidSize.Log();
if (!Alignment.IsAlignedPow2(saveDataJournalSize, SaveDataBlockSize)) if (!Alignment.IsAligned(saveDataJournalSize, SaveDataBlockSize))
return ResultFs.InvalidSize.Log(); return ResultFs.InvalidSize.Log();
if (saveDataSize + saveDataJournalSize > SaveDataTotalSizeMax) if (saveDataSize + saveDataJournalSize > SaveDataTotalSizeMax)

View file

@ -146,7 +146,7 @@ public class AccessControl
accessControlData.Slice(data.SaveDataOwnerInfoOffset + sizeof(int), infoCount)); accessControlData.Slice(data.SaveDataOwnerInfoOffset + sizeof(int), infoCount));
// The ID list must be 4-byte aligned // The ID list must be 4-byte aligned
int idsOffset = Alignment.AlignUpPow2(data.SaveDataOwnerInfoOffset + sizeof(int) + infoCount, 4); int idsOffset = Alignment.AlignUp(data.SaveDataOwnerInfoOffset + sizeof(int) + infoCount, 4);
ReadOnlySpan<ulong> ids = MemoryMarshal.Cast<byte, ulong>( ReadOnlySpan<ulong> ids = MemoryMarshal.Cast<byte, ulong>(
accessControlData.Slice(idsOffset, infoCount * sizeof(ulong))); accessControlData.Slice(idsOffset, infoCount * sizeof(ulong)));

View file

@ -358,7 +358,7 @@ public class DeviceOperator : IDeviceOperator
// Changed: Removed the alignment check for the buffer address // Changed: Removed the alignment check for the buffer address
if (!Alignment.IsAlignedPow2(bufferSize, 0x1000)) if (!Alignment.IsAligned(bufferSize, 0x1000))
return ResultFs.InvalidAlignment.Log(); return ResultFs.InvalidAlignment.Log();
return _fsServer.Storage.WriteToGameCardDirectly(offset, GetSpan(buffer, bufferSize)).Ret(); return _fsServer.Storage.WriteToGameCardDirectly(offset, GetSpan(buffer, bufferSize)).Ret();

View file

@ -217,10 +217,10 @@ public class AesCtrCounterExtendedStorage : IStorage
return Result.Success; return Result.Success;
// Reads cannot contain any partial blocks. // Reads cannot contain any partial blocks.
if (!Alignment.IsAlignedPow2(offset, (uint)BlockSize)) if (!Alignment.IsAligned(offset, (uint)BlockSize))
return ResultFs.InvalidOffset.Log(); return ResultFs.InvalidOffset.Log();
if (!Alignment.IsAlignedPow2(destination.Length, (uint)BlockSize)) if (!Alignment.IsAligned(destination.Length, (uint)BlockSize))
return ResultFs.InvalidSize.Log(); return ResultFs.InvalidSize.Log();
// Ensure the the requested range is within the bounds of the table. // Ensure the the requested range is within the bounds of the table.
@ -244,7 +244,7 @@ public class AesCtrCounterExtendedStorage : IStorage
// Verify that the entry's offset is aligned to an AES block and within the bounds of the table. // Verify that the entry's offset is aligned to an AES block and within the bounds of the table.
long entryOffset = visitor.Get<Entry>().GetOffset(); long entryOffset = visitor.Get<Entry>().GetOffset();
if (!Alignment.IsAlignedPow2(entryOffset, (uint)BlockSize) || entryOffset < 0 || if (!Alignment.IsAligned(entryOffset, (uint)BlockSize) || entryOffset < 0 ||
!offsets.IsInclude(entryOffset)) !offsets.IsInclude(entryOffset))
{ {
return ResultFs.InvalidAesCtrCounterExtendedEntryOffset.Log(); return ResultFs.InvalidAesCtrCounterExtendedEntryOffset.Log();
@ -283,7 +283,7 @@ public class AesCtrCounterExtendedStorage : IStorage
entryEndOffset = offsets.EndOffset; entryEndOffset = offsets.EndOffset;
} }
if (!Alignment.IsAlignedPow2((ulong)entryEndOffset, (uint)BlockSize) || currentOffset >= entryEndOffset) if (!Alignment.IsAligned((ulong)entryEndOffset, (uint)BlockSize) || currentOffset >= entryEndOffset)
return ResultFs.InvalidAesCtrCounterExtendedEntryOffset.Log(); return ResultFs.InvalidAesCtrCounterExtendedEntryOffset.Log();
// Get the part of the entry that contains the data we read. // Get the part of the entry that contains the data we read.
@ -383,10 +383,10 @@ public class AesCtrCounterExtendedStorage : IStorage
return Result.Success; return Result.Success;
} }
if (!Alignment.IsAlignedPow2(offset, (uint)BlockSize)) if (!Alignment.IsAligned(offset, (uint)BlockSize))
return ResultFs.InvalidOffset.Log(); return ResultFs.InvalidOffset.Log();
if (!Alignment.IsAlignedPow2(size, (uint)BlockSize)) if (!Alignment.IsAligned(size, (uint)BlockSize))
return ResultFs.InvalidSize.Log(); return ResultFs.InvalidSize.Log();
// Ensure the storage contains the provided offset and size. // Ensure the storage contains the provided offset and size.

View file

@ -76,10 +76,10 @@ public class AesCtrStorage : IStorage
return Result.Success; return Result.Success;
// Reads cannot contain any partial blocks. // Reads cannot contain any partial blocks.
if (!Alignment.IsAlignedPow2(offset, (uint)BlockSize)) if (!Alignment.IsAligned(offset, (uint)BlockSize))
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
if (!Alignment.IsAlignedPow2(destination.Length, (uint)BlockSize)) if (!Alignment.IsAligned(destination.Length, (uint)BlockSize))
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
Result res = _baseStorage.Read(offset, destination); Result res = _baseStorage.Read(offset, destination);
@ -103,10 +103,10 @@ public class AesCtrStorage : IStorage
return Result.Success; return Result.Success;
// We can only write full, aligned blocks. // We can only write full, aligned blocks.
if (!Alignment.IsAlignedPow2(offset, (uint)BlockSize)) if (!Alignment.IsAligned(offset, (uint)BlockSize))
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
if (!Alignment.IsAlignedPow2(source.Length, (uint)BlockSize)) if (!Alignment.IsAligned(source.Length, (uint)BlockSize))
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
// Get a pooled buffer. // Get a pooled buffer.
@ -192,10 +192,10 @@ public class AesCtrStorage : IStorage
return Result.Success; return Result.Success;
} }
if (!Alignment.IsAlignedPow2(offset, (uint)BlockSize)) if (!Alignment.IsAligned(offset, (uint)BlockSize))
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
if (!Alignment.IsAlignedPow2(size, (uint)BlockSize)) if (!Alignment.IsAligned(size, (uint)BlockSize))
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
} }

View file

@ -78,10 +78,10 @@ public class AesXtsStorageExternal : IStorage
return ResultFs.NullptrArgument.Log(); return ResultFs.NullptrArgument.Log();
// We can only read at block aligned offsets. // We can only read at block aligned offsets.
if (!Alignment.IsAlignedPow2(offset, AesBlockSize)) if (!Alignment.IsAligned(offset, AesBlockSize))
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
if (!Alignment.IsAlignedPow2(destination.Length, AesBlockSize)) if (!Alignment.IsAligned(destination.Length, AesBlockSize))
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
// Read the encrypted data. // Read the encrypted data.
@ -102,7 +102,7 @@ public class AesXtsStorageExternal : IStorage
if (offset % _blockSize != 0) if (offset % _blockSize != 0)
{ {
// Determine the size of the pre-data read. // Determine the size of the pre-data read.
int skipSize = (int)(offset - Alignment.AlignDownPow2(offset, _blockSize)); int skipSize = (int)(offset - Alignment.AlignDown(offset, _blockSize));
int dataSize = (int)Math.Min(destination.Length, _blockSize - skipSize); int dataSize = (int)Math.Min(destination.Length, _blockSize - skipSize);
// Decrypt into a pooled buffer. // Decrypt into a pooled buffer.
@ -159,10 +159,10 @@ public class AesXtsStorageExternal : IStorage
return ResultFs.NullptrArgument.Log(); return ResultFs.NullptrArgument.Log();
// We can only write at block aligned offsets. // We can only write at block aligned offsets.
if (!Alignment.IsAlignedPow2(offset, AesBlockSize)) if (!Alignment.IsAligned(offset, AesBlockSize))
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
if (!Alignment.IsAlignedPow2(source.Length, AesBlockSize)) if (!Alignment.IsAligned(source.Length, AesBlockSize))
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
// Get a pooled buffer. // Get a pooled buffer.
@ -186,7 +186,7 @@ public class AesXtsStorageExternal : IStorage
if (offset % _blockSize != 0) if (offset % _blockSize != 0)
{ {
// Determine the size of the pre-data write. // Determine the size of the pre-data write.
int skipSize = (int)(offset - Alignment.AlignDownPow2(offset, _blockSize)); int skipSize = (int)(offset - Alignment.AlignDown(offset, _blockSize));
int dataSize = (int)Math.Min(source.Length, _blockSize - skipSize); int dataSize = (int)Math.Min(source.Length, _blockSize - skipSize);
// Encrypt into a pooled buffer. // Encrypt into a pooled buffer.
@ -289,10 +289,10 @@ public class AesXtsStorageExternal : IStorage
return Result.Success; return Result.Success;
// Ensure alignment. // Ensure alignment.
if (!Alignment.IsAlignedPow2(offset, AesBlockSize)) if (!Alignment.IsAligned(offset, AesBlockSize))
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
if (!Alignment.IsAlignedPow2(size, AesBlockSize)) if (!Alignment.IsAligned(size, AesBlockSize))
return ResultFs.InvalidArgument.Log(); return ResultFs.InvalidArgument.Log();
} }

View file

@ -109,7 +109,7 @@ public class AlignmentMatchingStorage<TDataAlignment, TBufferAlignment> : IStora
public override Result SetSize(long size) public override Result SetSize(long size)
{ {
Result res = _baseStorage.SetSize(Alignment.AlignUpPow2(size, DataAlign)); Result res = _baseStorage.SetSize(Alignment.AlignUp(size, DataAlign));
_isBaseStorageSizeDirty = true; _isBaseStorageSizeDirty = true;
return res; return res;
@ -150,8 +150,8 @@ public class AlignmentMatchingStorage<TDataAlignment, TBufferAlignment> : IStora
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
long validSize = Math.Min(size, baseStorageSize - offset); long validSize = Math.Min(size, baseStorageSize - offset);
long alignedOffset = Alignment.AlignDownPow2(offset, DataAlign); long alignedOffset = Alignment.AlignDown(offset, DataAlign);
long alignedOffsetEnd = Alignment.AlignUpPow2(offset + validSize, DataAlign); long alignedOffsetEnd = Alignment.AlignUp(offset + validSize, DataAlign);
long alignedSize = alignedOffsetEnd - alignedOffset; long alignedSize = alignedOffsetEnd - alignedOffset;
return _baseStorage.OperateRange(outBuffer, operationId, alignedOffset, alignedSize, inBuffer); return _baseStorage.OperateRange(outBuffer, operationId, alignedOffset, alignedSize, inBuffer);
@ -255,7 +255,7 @@ public class AlignmentMatchingStoragePooledBuffer<TBufferAlignment> : IStorage
public override Result SetSize(long size) public override Result SetSize(long size)
{ {
Result res = _baseStorage.SetSize(Alignment.AlignUpPow2(size, _dataAlignment)); Result res = _baseStorage.SetSize(Alignment.AlignUp(size, _dataAlignment));
_isBaseStorageSizeDirty = true; _isBaseStorageSizeDirty = true;
return res; return res;
@ -296,8 +296,8 @@ public class AlignmentMatchingStoragePooledBuffer<TBufferAlignment> : IStorage
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
long validSize = Math.Min(size, baseStorageSize - offset); long validSize = Math.Min(size, baseStorageSize - offset);
long alignedOffset = Alignment.AlignDownPow2(offset, _dataAlignment); long alignedOffset = Alignment.AlignDown(offset, _dataAlignment);
long alignedOffsetEnd = Alignment.AlignUpPow2(offset + validSize, _dataAlignment); long alignedOffsetEnd = Alignment.AlignUp(offset + validSize, _dataAlignment);
long alignedSize = alignedOffsetEnd - alignedOffset; long alignedSize = alignedOffsetEnd - alignedOffset;
return _baseStorage.OperateRange(outBuffer, operationId, alignedOffset, alignedSize, inBuffer); return _baseStorage.OperateRange(outBuffer, operationId, alignedOffset, alignedSize, inBuffer);
@ -367,8 +367,8 @@ public class AlignmentMatchingStorageInBulkRead<TBufferAlignment> : IStorage
// Calculate the aligned offsets of the requested region. // Calculate the aligned offsets of the requested region.
long offsetEnd = offset + destination.Length; long offsetEnd = offset + destination.Length;
long alignedOffset = Alignment.AlignDownPow2(offset, _dataAlignment); long alignedOffset = Alignment.AlignDown(offset, _dataAlignment);
long alignedOffsetEnd = Alignment.AlignUpPow2(offsetEnd, _dataAlignment); long alignedOffsetEnd = Alignment.AlignUp(offsetEnd, _dataAlignment);
long alignedSize = alignedOffsetEnd - alignedOffset; long alignedSize = alignedOffsetEnd - alignedOffset;
using var pooledBuffer = new PooledBuffer(); using var pooledBuffer = new PooledBuffer();
@ -406,8 +406,8 @@ public class AlignmentMatchingStorageInBulkRead<TBufferAlignment> : IStorage
} }
// Determine read extents for the aligned portion. // Determine read extents for the aligned portion.
long coreOffset = Alignment.AlignUpPow2(offset, _dataAlignment); long coreOffset = Alignment.AlignUp(offset, _dataAlignment);
long coreOffsetEnd = Alignment.AlignDownPow2(offsetEnd, _dataAlignment); long coreOffsetEnd = Alignment.AlignDown(offsetEnd, _dataAlignment);
// Handle any data before the aligned portion. // Handle any data before the aligned portion.
if (offset < coreOffset) if (offset < coreOffset)
@ -469,7 +469,7 @@ public class AlignmentMatchingStorageInBulkRead<TBufferAlignment> : IStorage
public override Result SetSize(long size) public override Result SetSize(long size)
{ {
Result res = _baseStorage.SetSize(Alignment.AlignUpPow2(size, _dataAlignment)); Result res = _baseStorage.SetSize(Alignment.AlignUp(size, _dataAlignment));
_baseStorageSize = -1; _baseStorageSize = -1;
return res; return res;
@ -509,8 +509,8 @@ public class AlignmentMatchingStorageInBulkRead<TBufferAlignment> : IStorage
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
long validSize = Math.Min(size, baseStorageSize - offset); long validSize = Math.Min(size, baseStorageSize - offset);
long alignedOffset = Alignment.AlignDownPow2(offset, _dataAlignment); long alignedOffset = Alignment.AlignDown(offset, _dataAlignment);
long alignedOffsetEnd = Alignment.AlignUpPow2(offset + validSize, _dataAlignment); long alignedOffsetEnd = Alignment.AlignUp(offset + validSize, _dataAlignment);
long alignedSize = alignedOffsetEnd - alignedOffset; long alignedSize = alignedOffsetEnd - alignedOffset;
return _baseStorage.OperateRange(outBuffer, operationId, alignedOffset, alignedSize, inBuffer); return _baseStorage.OperateRange(outBuffer, operationId, alignedOffset, alignedSize, inBuffer);

View file

@ -15,22 +15,22 @@ public static class AlignmentMatchingStorageImpl
{ {
public static uint GetRoundDownDifference(int value, uint alignment) public static uint GetRoundDownDifference(int value, uint alignment)
{ {
return (uint)(value - Alignment.AlignDownPow2(value, alignment)); return (uint)(value - Alignment.AlignDown(value, alignment));
} }
public static uint GetRoundDownDifference(long value, uint alignment) public static uint GetRoundDownDifference(long value, uint alignment)
{ {
return (uint)(value - Alignment.AlignDownPow2(value, alignment)); return (uint)(value - Alignment.AlignDown(value, alignment));
} }
public static uint GetRoundUpDifference(int value, uint alignment) public static uint GetRoundUpDifference(int value, uint alignment)
{ {
return (uint)(Alignment.AlignUpPow2(value, alignment) - value); return (uint)(Alignment.AlignUp(value, alignment) - value);
} }
private static uint GetRoundUpDifference(long value, uint alignment) private static uint GetRoundUpDifference(long value, uint alignment)
{ {
return (uint)(Alignment.AlignUpPow2(value, alignment) - value); return (uint)(Alignment.AlignUp(value, alignment) - value);
} }
public static Result Read(in SharedRef<IStorage> storage, Span<byte> workBuffer, uint dataAlignment, public static Result Read(in SharedRef<IStorage> storage, Span<byte> workBuffer, uint dataAlignment,
@ -60,10 +60,10 @@ public static class AlignmentMatchingStorageImpl
// Calculate the range that contains only full data blocks. // Calculate the range that contains only full data blocks.
uint offsetRoundUpDifference = GetRoundUpDifference(offset, dataAlignment); uint offsetRoundUpDifference = GetRoundUpDifference(offset, dataAlignment);
long coreOffset = Alignment.AlignUpPow2(offset, dataAlignment); long coreOffset = Alignment.AlignUp(offset, dataAlignment);
long coreSize = destination.Length < offsetRoundUpDifference long coreSize = destination.Length < offsetRoundUpDifference
? 0 ? 0
: Alignment.AlignDownPow2(destination.Length - offsetRoundUpDifference, dataAlignment); : Alignment.AlignDown(destination.Length - offsetRoundUpDifference, dataAlignment);
long coveredOffset = coreSize > 0 ? coreOffset : offset; long coveredOffset = coreSize > 0 ? coreOffset : offset;
@ -77,7 +77,7 @@ public static class AlignmentMatchingStorageImpl
// Read any partial block at the head of the requested range // Read any partial block at the head of the requested range
if (offset < coveredOffset) if (offset < coveredOffset)
{ {
long headOffset = Alignment.AlignDownPow2(offset, dataAlignment); long headOffset = Alignment.AlignDown(offset, dataAlignment);
int headSize = (int)(coveredOffset - offset); int headSize = (int)(coveredOffset - offset);
Assert.SdkAssert(GetRoundDownDifference(offset, dataAlignment) + headSize <= workBuffer.Length); Assert.SdkAssert(GetRoundDownDifference(offset, dataAlignment) + headSize <= workBuffer.Length);
@ -94,7 +94,7 @@ public static class AlignmentMatchingStorageImpl
// Read any partial block at the tail of the requested range // Read any partial block at the tail of the requested range
while (remainingTailSize > 0) while (remainingTailSize > 0)
{ {
long alignedTailOffset = Alignment.AlignDownPow2(tailOffset, dataAlignment); long alignedTailOffset = Alignment.AlignDown(tailOffset, dataAlignment);
long copySize = Math.Min(alignedTailOffset + dataAlignment - tailOffset, remainingTailSize); long copySize = Math.Min(alignedTailOffset + dataAlignment - tailOffset, remainingTailSize);
Result res = storage.Read(alignedTailOffset, workBuffer.Slice(0, (int)dataAlignment)); Result res = storage.Read(alignedTailOffset, workBuffer.Slice(0, (int)dataAlignment));
@ -127,10 +127,10 @@ public static class AlignmentMatchingStorageImpl
// Calculate the range that contains only full data blocks. // Calculate the range that contains only full data blocks.
uint offsetRoundUpDifference = GetRoundUpDifference(offset, dataAlignment); uint offsetRoundUpDifference = GetRoundUpDifference(offset, dataAlignment);
long coreOffset = Alignment.AlignUpPow2(offset, dataAlignment); long coreOffset = Alignment.AlignUp(offset, dataAlignment);
long coreSize = source.Length < offsetRoundUpDifference long coreSize = source.Length < offsetRoundUpDifference
? 0 ? 0
: Alignment.AlignDownPow2(source.Length - offsetRoundUpDifference, dataAlignment); : Alignment.AlignDown(source.Length - offsetRoundUpDifference, dataAlignment);
long coveredOffset = coreSize > 0 ? coreOffset : offset; long coveredOffset = coreSize > 0 ? coreOffset : offset;
@ -144,7 +144,7 @@ public static class AlignmentMatchingStorageImpl
// Write any partial block at the head of the specified range // Write any partial block at the head of the specified range
if (offset < coveredOffset) if (offset < coveredOffset)
{ {
long headOffset = Alignment.AlignDownPow2(offset, dataAlignment); long headOffset = Alignment.AlignDown(offset, dataAlignment);
int headSize = (int)(coveredOffset - offset); int headSize = (int)(coveredOffset - offset);
Assert.SdkAssert((offset - headOffset) + headSize <= workBuffer.Length); Assert.SdkAssert((offset - headOffset) + headSize <= workBuffer.Length);
@ -168,7 +168,7 @@ public static class AlignmentMatchingStorageImpl
{ {
Assert.SdkAssert(tailOffset - offset < source.Length); Assert.SdkAssert(tailOffset - offset < source.Length);
long alignedTailOffset = Alignment.AlignDownPow2(tailOffset, dataAlignment); long alignedTailOffset = Alignment.AlignDown(tailOffset, dataAlignment);
long copySize = Math.Min(alignedTailOffset + dataAlignment - tailOffset, remainingTailSize); long copySize = Math.Min(alignedTailOffset + dataAlignment - tailOffset, remainingTailSize);
// Read the existing block, copy the partial block to the appropriate portion, // Read the existing block, copy the partial block to the appropriate portion,

View file

@ -77,13 +77,13 @@ public class DefaultAsynchronousAccessSplitter : IAsynchronousAccessSplitter
public Result QueryAppropriateOffset(out long offsetAppropriate, long startOffset, long accessSize, long alignmentSize) public Result QueryAppropriateOffset(out long offsetAppropriate, long startOffset, long accessSize, long alignmentSize)
{ {
offsetAppropriate = Alignment.AlignDownPow2(startOffset + accessSize, alignmentSize); offsetAppropriate = Alignment.AlignDown(startOffset + accessSize, alignmentSize);
return Result.Success; return Result.Success;
} }
public Result QueryInvocationCount(out long count, long startOffset, long endOffset, long accessSize, long alignmentSize) public Result QueryInvocationCount(out long count, long startOffset, long endOffset, long accessSize, long alignmentSize)
{ {
long alignedStartOffset = Alignment.AlignDownPow2(startOffset, alignmentSize); long alignedStartOffset = Alignment.AlignDown(startOffset, alignmentSize);
count = BitUtil.DivideUp(endOffset - alignedStartOffset, accessSize); count = BitUtil.DivideUp(endOffset - alignedStartOffset, accessSize);
return Result.Success; return Result.Success;
} }

View file

@ -554,7 +554,7 @@ public class BufferedStorage : IStorage
private readonly void CalcFetchParameter(out FetchParameter fetchParam, long offset) private readonly void CalcFetchParameter(out FetchParameter fetchParam, long offset)
{ {
long blockSize = _bufferedStorage._blockSize; long blockSize = _bufferedStorage._blockSize;
long storageOffset = Alignment.AlignDownPow2(offset, (uint)_bufferedStorage._blockSize); long storageOffset = Alignment.AlignDown(offset, (uint)_bufferedStorage._blockSize);
long baseSize = _bufferedStorage._baseStorageSize; long baseSize = _bufferedStorage._baseStorageSize;
long remainingSize = baseSize - storageOffset; long remainingSize = baseSize - storageOffset;
long cacheSize = Math.Min(blockSize, remainingSize); long cacheSize = Math.Min(blockSize, remainingSize);
@ -1107,7 +1107,7 @@ public class BufferedStorage : IStorage
if (prevSize < size) if (prevSize < size)
{ {
// Prepare to expand. // Prepare to expand.
if (!Alignment.IsAlignedPow2(prevSize, (uint)_blockSize)) if (!Alignment.IsAligned(prevSize, (uint)_blockSize))
{ {
using var cache = new SharedCache(this); using var cache = new SharedCache(this);
long invalidateOffset = prevSize; long invalidateOffset = prevSize;
@ -1130,7 +1130,7 @@ public class BufferedStorage : IStorage
using var cache = new SharedCache(this); using var cache = new SharedCache(this);
long invalidateOffset = prevSize; long invalidateOffset = prevSize;
long invalidateSize = size - prevSize; long invalidateSize = size - prevSize;
bool isFragment = Alignment.IsAlignedPow2(size, (uint)_blockSize); bool isFragment = Alignment.IsAligned(size, (uint)_blockSize);
while (cache.AcquireNextOverlappedCache(invalidateOffset, invalidateSize)) while (cache.AcquireNextOverlappedCache(invalidateOffset, invalidateSize))
{ {
@ -1317,7 +1317,7 @@ public class BufferedStorage : IStorage
int currentSize; int currentSize;
// If the offset is in the middle of a block, read the remaining part of that block. // If the offset is in the middle of a block, read the remaining part of that block.
if (!Alignment.IsAlignedPow2(currentOffset, (uint)_blockSize)) if (!Alignment.IsAligned(currentOffset, (uint)_blockSize))
{ {
long alignedSize = _blockSize - (currentOffset & (_blockSize - 1)); long alignedSize = _blockSize - (currentOffset & (_blockSize - 1));
currentSize = (int)Math.Min(alignedSize, remainingSize); currentSize = (int)Math.Min(alignedSize, remainingSize);
@ -1330,7 +1330,7 @@ public class BufferedStorage : IStorage
// We have at least one full block to read. Read all the remaining full blocks at once. // We have at least one full block to read. Read all the remaining full blocks at once.
else else
{ {
currentSize = (int)Alignment.AlignDownPow2(remainingSize, (uint)_blockSize); currentSize = (int)Alignment.AlignDown(remainingSize, (uint)_blockSize);
} }
Span<byte> currentDestination = destination.Slice((int)bufferOffset, currentSize); Span<byte> currentDestination = destination.Slice((int)bufferOffset, currentSize);
@ -1421,15 +1421,15 @@ public class BufferedStorage : IStorage
/// Otherwise, <see langword="false"/>.</returns> /// Otherwise, <see langword="false"/>.</returns>
private bool ReadHeadCache(ref long offset, Span<byte> buffer, ref long size, ref long bufferOffset) private bool ReadHeadCache(ref long offset, Span<byte> buffer, ref long size, ref long bufferOffset)
{ {
bool isCacheNeeded = !Alignment.IsAlignedPow2(offset, (uint)_blockSize); bool isCacheNeeded = !Alignment.IsAligned(offset, (uint)_blockSize);
while (size > 0) while (size > 0)
{ {
long currentSize; long currentSize;
if (!Alignment.IsAlignedPow2(offset, (uint)_blockSize)) if (!Alignment.IsAligned(offset, (uint)_blockSize))
{ {
long alignedSize = Alignment.AlignUpPow2(offset, (uint)_blockSize) - offset; long alignedSize = Alignment.AlignUp(offset, (uint)_blockSize) - offset;
currentSize = Math.Min(alignedSize, size); currentSize = Math.Min(alignedSize, size);
} }
else if (size < _blockSize) else if (size < _blockSize)
@ -1458,16 +1458,16 @@ public class BufferedStorage : IStorage
private bool ReadTailCache(long offset, Span<byte> buffer, ref long size, long bufferOffset) private bool ReadTailCache(long offset, Span<byte> buffer, ref long size, long bufferOffset)
{ {
bool isCacheNeeded = !Alignment.IsAlignedPow2(offset + size, (uint)_blockSize); bool isCacheNeeded = !Alignment.IsAligned(offset + size, (uint)_blockSize);
while (size > 0) while (size > 0)
{ {
long currentOffsetEnd = offset + size; long currentOffsetEnd = offset + size;
long currentSize; long currentSize;
if (!Alignment.IsAlignedPow2(currentOffsetEnd, (uint)_blockSize)) if (!Alignment.IsAligned(currentOffsetEnd, (uint)_blockSize))
{ {
long alignedSize = currentOffsetEnd - Alignment.AlignDownPow2(currentOffsetEnd, (uint)_blockSize); long alignedSize = currentOffsetEnd - Alignment.AlignDown(currentOffsetEnd, (uint)_blockSize);
currentSize = Math.Min(alignedSize, size); currentSize = Math.Min(alignedSize, size);
} }
else if (size < _blockSize) else if (size < _blockSize)
@ -1511,8 +1511,8 @@ public class BufferedStorage : IStorage
Result res; Result res;
// Determine aligned extents. // Determine aligned extents.
long alignedOffset = Alignment.AlignDownPow2(offset, (uint)_blockSize); long alignedOffset = Alignment.AlignDown(offset, (uint)_blockSize);
long alignedOffsetEnd = Math.Min(Alignment.AlignUpPow2(offset + buffer.Length, (uint)_blockSize), long alignedOffsetEnd = Math.Min(Alignment.AlignUp(offset + buffer.Length, (uint)_blockSize),
_baseStorageSize); _baseStorageSize);
long alignedSize = alignedOffsetEnd - alignedOffset; long alignedSize = alignedOffsetEnd - alignedOffset;
@ -1606,7 +1606,7 @@ public class BufferedStorage : IStorage
if (upgradeResult.wasUpgradeSuccessful) if (upgradeResult.wasUpgradeSuccessful)
{ {
long tailCacheOffset = Alignment.AlignDownPow2(offset + buffer.Length, (uint)_blockSize); long tailCacheOffset = Alignment.AlignDown(offset + buffer.Length, (uint)_blockSize);
long tailCacheSize = alignedSize - tailCacheOffset + alignedOffset; long tailCacheSize = alignedSize - tailCacheOffset + alignedOffset;
res = fetchCache.FetchFromBuffer(tailCacheOffset, res = fetchCache.FetchFromBuffer(tailCacheOffset,
@ -1649,7 +1649,7 @@ public class BufferedStorage : IStorage
ReadOnlySpan<byte> currentSource = source.Slice(bufferOffset); ReadOnlySpan<byte> currentSource = source.Slice(bufferOffset);
int currentSize; int currentSize;
if (!Alignment.IsAlignedPow2(currentOffset, (uint)_blockSize)) if (!Alignment.IsAligned(currentOffset, (uint)_blockSize))
{ {
int alignedSize = (int)(_blockSize - (currentOffset & (_blockSize - 1))); int alignedSize = (int)(_blockSize - (currentOffset & (_blockSize - 1)));
currentSize = Math.Min(alignedSize, remainingSize); currentSize = Math.Min(alignedSize, remainingSize);
@ -1660,7 +1660,7 @@ public class BufferedStorage : IStorage
} }
else else
{ {
currentSize = Alignment.AlignDownPow2(remainingSize, (uint)_blockSize); currentSize = Alignment.AlignDown(remainingSize, (uint)_blockSize);
} }
Result res; Result res;

View file

@ -175,7 +175,7 @@ public unsafe class FileSystemBuddyHeap : IDisposable
uint pageListAlignment = (uint)Unsafe.SizeOf<nint>(); uint pageListAlignment = (uint)Unsafe.SizeOf<nint>();
const uint ulongAlignment = 8; const uint ulongAlignment = 8;
return (nuint)Alignment.AlignUpPow2(pageListSize * (orderMax + 1) + pageListAlignment, ulongAlignment); return (nuint)Alignment.AlignUp(pageListSize * (orderMax + 1) + pageListAlignment, ulongAlignment);
} }
public static int QueryOrderMax(nuint size, nuint blockSize) public static int QueryOrderMax(nuint size, nuint blockSize)
@ -184,7 +184,7 @@ public unsafe class FileSystemBuddyHeap : IDisposable
Assert.SdkRequiresGreaterEqual(blockSize, BlockSizeMin); Assert.SdkRequiresGreaterEqual(blockSize, BlockSizeMin);
Assert.SdkRequires(BitUtil.IsPowerOfTwo(blockSize)); Assert.SdkRequires(BitUtil.IsPowerOfTwo(blockSize));
int blockCount = (int)(Alignment.AlignUpPow2(size, (uint)blockSize) / blockSize); int blockCount = (int)(Alignment.AlignUp(size, (uint)blockSize) / blockSize);
for (int order = 1; ; order++) for (int order = 1; ; order++)
{ {
if (blockCount <= GetBlockCountFromOrder(order)) if (blockCount <= GetBlockCountFromOrder(order))
@ -203,7 +203,7 @@ public unsafe class FileSystemBuddyHeap : IDisposable
Assert.SdkRequiresGreaterEqual(workBufferSize, QueryWorkBufferSize(orderMax)); Assert.SdkRequiresGreaterEqual(workBufferSize, QueryWorkBufferSize(orderMax));
uint pageListAlignment = (uint)Unsafe.SizeOf<nint>(); uint pageListAlignment = (uint)Unsafe.SizeOf<nint>();
var alignedWork = (void*)Alignment.AlignUpPow2((ulong)workBuffer, pageListAlignment); var alignedWork = (void*)Alignment.AlignUp((ulong)workBuffer, pageListAlignment);
ExternalFreeLists = (PageList*)alignedWork; ExternalFreeLists = (PageList*)alignedWork;
// Note: The original code does not have a buffer size assert after adjusting for alignment. // Note: The original code does not have a buffer size assert after adjusting for alignment.
@ -531,7 +531,7 @@ public unsafe class FileSystemBuddyHeap : IDisposable
private int GetBlockCountFromSize(nuint size) private int GetBlockCountFromSize(nuint size)
{ {
nuint blockSize = GetBlockSize(); nuint blockSize = GetBlockSize();
return (int)(Alignment.AlignUpPow2(size, (uint)blockSize) / blockSize); return (int)(Alignment.AlignUp(size, (uint)blockSize) / blockSize);
} }
private UIntPtr GetAddressFromPageEntry(PageEntry* pageEntry) private UIntPtr GetAddressFromPageEntry(PageEntry* pageEntry)
@ -551,7 +551,7 @@ public unsafe class FileSystemBuddyHeap : IDisposable
Assert.SdkRequiresLess((nuint)address, HeapStart + HeapSize); Assert.SdkRequiresLess((nuint)address, HeapStart + HeapSize);
ulong blockStart = (ulong)HeapStart + ulong blockStart = (ulong)HeapStart +
Alignment.AlignDownPow2((nuint)address - HeapStart, (uint)GetBlockSize()); Alignment.AlignDown((nuint)address - HeapStart, (uint)GetBlockSize());
return (PageEntry*)blockStart; return (PageEntry*)blockStart;
} }
@ -568,7 +568,7 @@ public unsafe class FileSystemBuddyHeap : IDisposable
private bool IsAlignedToOrder(PageEntry* pageEntry, int order) private bool IsAlignedToOrder(PageEntry* pageEntry, int order)
{ {
return Alignment.IsAlignedPow2(GetIndexFromPageEntry(pageEntry), (uint)GetBlockCountFromOrder(order)); return Alignment.IsAligned(GetIndexFromPageEntry(pageEntry), (uint)GetBlockCountFromOrder(order));
} }
// Addition: The below fields and methods allow using Memory<byte> with the class instead // Addition: The below fields and methods allow using Memory<byte> with the class instead

View file

@ -98,7 +98,7 @@ public class FileSystemBufferManager : IBufferManager
int entrySize = Unsafe.SizeOf<Entry>() * maxCacheCount; int entrySize = Unsafe.SizeOf<Entry>() * maxCacheCount;
int attrListSize = Unsafe.SizeOf<AttrInfo>() * 0x100; int attrListSize = Unsafe.SizeOf<AttrInfo>() * 0x100;
return (int)Alignment.AlignUpPow2( return (int)Alignment.AlignUp(
(ulong)(entrySize + attrListSize + entryAlignment + attrInfoAlignment), 8); (ulong)(entrySize + attrListSize + entryAlignment + attrInfoAlignment), 8);
} }

View file

@ -137,14 +137,14 @@ public class HierarchicalIntegrityVerificationStorageControlArea : IDisposable
Span<long> levelSize = stackalloc long[IntegrityMaxLayerCount]; Span<long> levelSize = stackalloc long[IntegrityMaxLayerCount];
int level = layerCount - 1; int level = layerCount - 1;
levelSize[level] = Alignment.AlignUpPow2(dataSize, (uint)inputParam.LevelBlockSizes[level - 1]); levelSize[level] = Alignment.AlignUp(dataSize, (uint)inputParam.LevelBlockSizes[level - 1]);
level--; level--;
for (; level > 0; level--) for (; level > 0; level--)
{ {
// Calculate how much space is needed to store the hashes of the above level, rounding up to the next block size. // Calculate how much space is needed to store the hashes of the above level, rounding up to the next block size.
levelSize[level] = levelSize[level] =
Alignment.AlignUpPow2(levelSize[level + 1] / inputParam.LevelBlockSizes[level] * HashSize, Alignment.AlignUp(levelSize[level + 1] / inputParam.LevelBlockSizes[level] * HashSize,
(uint)inputParam.LevelBlockSizes[level - 1]); (uint)inputParam.LevelBlockSizes[level - 1]);
} }

View file

@ -170,7 +170,7 @@ public class IntegrityVerificationStorage : IStorage
if (dataSize < offset) if (dataSize < offset)
return ResultFs.InvalidOffset.Log(); return ResultFs.InvalidOffset.Log();
long alignedDataSize = Alignment.AlignUpPow2(dataSize, (uint)_verificationBlockSize); long alignedDataSize = Alignment.AlignUp(dataSize, (uint)_verificationBlockSize);
res = CheckAccessRange(offset, destination.Length, alignedDataSize); res = CheckAccessRange(offset, destination.Length, alignedDataSize);
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
@ -268,7 +268,7 @@ public class IntegrityVerificationStorage : IStorage
if (offset >= dataSize) if (offset >= dataSize)
return ResultFs.InvalidOffset.Log(); return ResultFs.InvalidOffset.Log();
res = CheckAccessRange(offset, source.Length, Alignment.AlignUpPow2(dataSize, (uint)_verificationBlockSize)); res = CheckAccessRange(offset, source.Length, Alignment.AlignUp(dataSize, (uint)_verificationBlockSize));
if (res.IsFailure()) return res.Miss(); if (res.IsFailure()) return res.Miss();
Assert.SdkRequiresAligned(offset, _verificationBlockSize); Assert.SdkRequiresAligned(offset, _verificationBlockSize);
@ -292,7 +292,7 @@ public class IntegrityVerificationStorage : IStorage
return Result.Success; return Result.Success;
} }
int alignedWriteSize = Alignment.AlignUpPow2(writeSize, (uint)_verificationBlockSize); int alignedWriteSize = Alignment.AlignUp(writeSize, (uint)_verificationBlockSize);
Result updateResult = Result.Success; Result updateResult = Result.Success;
int updatedSignatureCount = 0; int updatedSignatureCount = 0;

View file

@ -168,7 +168,7 @@ public class UnionStorage : IStorage
// Get the start offset of the block containing the requested offset // Get the start offset of the block containing the requested offset
long offsetBuffer = 0; long offsetBuffer = 0;
long offsetOriginal = Alignment.AlignDownPow2(offset, _blockSize); long offsetOriginal = Alignment.AlignDown(offset, _blockSize);
long sizeSkipBlock = offset - offsetOriginal; long sizeSkipBlock = offset - offsetOriginal;
while (offsetBuffer < destination.Length) while (offsetBuffer < destination.Length)
@ -214,7 +214,7 @@ public class UnionStorage : IStorage
// Get the start offset of the block containing the requested offset // Get the start offset of the block containing the requested offset
long offsetBuffer = 0; long offsetBuffer = 0;
long offsetOriginal = Alignment.AlignDownPow2(offset, _blockSize); long offsetOriginal = Alignment.AlignDown(offset, _blockSize);
long sizeSkipBlock = offset - offsetOriginal; long sizeSkipBlock = offset - offsetOriginal;
while (offsetBuffer < source.Length) while (offsetBuffer < source.Length)
@ -302,7 +302,7 @@ public class UnionStorage : IStorage
public override Result OperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size, public override Result OperateRange(Span<byte> outBuffer, OperationId operationId, long offset, long size,
ReadOnlySpan<byte> inBuffer) ReadOnlySpan<byte> inBuffer)
{ {
for (long currentOffset = Alignment.AlignDownPow2(offset, _blockSize); for (long currentOffset = Alignment.AlignDown(offset, _blockSize);
currentOffset < offset + size; currentOffset < offset + size;
currentOffset += _blockSize) currentOffset += _blockSize)
{ {

View file

@ -126,7 +126,7 @@ public class PartitionFileSystemBuilder
size += entry.NameLength + 1; size += entry.NameLength + 1;
} }
int endOffset = Alignment.AlignUpPow2(startOffset + size, GetMetaDataAlignment(type)); int endOffset = Alignment.AlignUp(startOffset + size, GetMetaDataAlignment(type));
return endOffset - startOffset; return endOffset - startOffset;
} }

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using LibHac.Diag; using LibHac.Diag;
@ -7,58 +8,53 @@ namespace LibHac.Util;
public static class Alignment public static class Alignment
{ {
// The alignment functions in this class come from C++ templates that always cast to unsigned types public static T AlignUp<T>(T value, ulong alignment) where T : IBinaryNumber<T>
public static ulong AlignUpPow2(ulong value, uint alignment)
{ {
Assert.SdkRequires(BitUtil.IsPowerOfTwo(alignment)); Assert.SdkRequires(BitUtil.IsPowerOfTwo(alignment) || alignment == 0);
ulong invMask = alignment - 1; unchecked
return ((value + invMask) & ~invMask); {
ulong invMask = alignment - 1;
return T.CreateTruncating((ulong.CreateTruncating(value) + invMask) & ~invMask);
}
} }
public static ulong AlignDownPow2(ulong value, uint alignment) public static T AlignDown<T>(T value, ulong alignment) where T : IBinaryNumber<T>
{ {
Assert.SdkRequires(BitUtil.IsPowerOfTwo(alignment)); Assert.SdkRequires(BitUtil.IsPowerOfTwo(alignment) || alignment == 0);
ulong invMask = alignment - 1; unchecked
return (value & ~invMask); {
ulong invMask = alignment - 1;
return T.CreateTruncating(ulong.CreateTruncating(value) & ~invMask);
}
} }
public static bool IsAlignedPow2(ulong value, uint alignment) public static T AlignDown<T>(T value, long alignment) where T : IBinaryNumber<T> => AlignDown(value, (ulong)alignment);
{
Assert.SdkRequires(BitUtil.IsPowerOfTwo(alignment));
ulong invMask = alignment - 1; public static bool IsAligned<T>(T value, ulong alignment) where T : IBinaryNumber<T>
return (value & invMask) == 0; {
Assert.SdkRequires(BitUtil.IsPowerOfTwo(alignment) || alignment == 0);
unchecked
{
ulong invMask = alignment - 1;
return (ulong.CreateTruncating(value) & invMask) == 0;
}
} }
public static bool IsAlignedPow2<T>(ReadOnlySpan<T> buffer, uint alignment) public static bool IsAligned<T>(ReadOnlySpan<T> buffer, ulong alignment)
{ {
return IsAlignedPow2(ref MemoryMarshal.GetReference(buffer), alignment); return IsAligned(ref MemoryMarshal.GetReference(buffer), alignment);
} }
public static unsafe bool IsAlignedPow2<T>(ref T pointer, uint alignment) public static unsafe bool IsAligned<T>(ref T pointer, ulong alignment)
{ {
return IsAlignedPow2((ulong)Unsafe.AsPointer(ref pointer), alignment); return IsAligned((ulong)Unsafe.AsPointer(ref pointer), alignment);
} }
public static int AlignUpPow2(int value, uint alignment) => (int)AlignUpPow2((ulong)value, alignment); public static T GetAlignment<T>(T value) where T : IUnsignedNumber<T>, IBinaryInteger<T>
public static long AlignUpPow2(long value, uint alignment) => (long)AlignUpPow2((ulong)value, alignment); {
public static int AlignDownPow2(int value, uint alignment) => (int)AlignDownPow2((ulong)value, alignment); return unchecked(value & -value);
public static long AlignDownPow2(long value, uint alignment) => (long)AlignDownPow2((ulong)value, alignment); }
public static long AlignDownPow2(long value, long alignment) => (long)AlignDownPow2((ulong)value, (uint)alignment);
public static bool IsAlignedPow2(int value, uint alignment) => IsAlignedPow2((ulong)value, alignment);
public static bool IsAlignedPow2(long value, uint alignment) => IsAlignedPow2((ulong)value, alignment);
public static ulong AlignUp(ulong value, uint alignment) => AlignDown(value + alignment - 1, alignment);
public static ulong AlignDown(ulong value, uint alignment) => value - value % alignment;
public static bool IsAligned(ulong value, uint alignment) => value % alignment == 0;
public static int AlignUp(int value, uint alignment) => (int)AlignUp((ulong)value, alignment);
public static long AlignUp(long value, uint alignment) => (long)AlignUp((ulong)value, alignment);
public static int AlignDown(int value, uint alignment) => (int)AlignDown((ulong)value, alignment);
public static long AlignDown(long value, uint alignment) => (long)AlignDown((ulong)value, alignment);
public static bool IsAligned(int value, uint alignment) => IsAligned((ulong)value, alignment);
public static bool IsAligned(long value, uint alignment) => IsAligned((ulong)value, alignment);
} }

View file

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>

View file

@ -0,0 +1,102 @@
using LibHac.Util;
using Xunit;
namespace LibHac.Tests.Util
{
public class AlignmentTests
{
[Theory]
[InlineData(0, 0x40, 0)]
[InlineData(0x3F, 0x40, 0x40)]
[InlineData(0x40, 0x40, 0x40)]
[InlineData(0x41, 0x40, 0x80)]
public void AlignUp_Byte(byte value, uint alignment, byte expectedValue)
{
var actualValue = Alignment.AlignUp(value, alignment);
Assert.Equal(expectedValue, actualValue);
}
[Theory]
[InlineData(0, 0x40, 0)]
[InlineData(-0x3F, 0x40, 0)]
[InlineData(-0x40, 0x40, -0x40)]
[InlineData(-0x41, 0x40, -0x40)]
[InlineData(-0x41, 0, 0)]
[InlineData(int.MaxValue, 0x40, int.MinValue)]
public void AlignUp_Int(int value, uint alignment, int expectedValue)
{
var actualValue = Alignment.AlignUp(value, alignment);
Assert.Equal(expectedValue, actualValue);
}
[Theory]
[InlineData(0, 0x40, 0)]
[InlineData(0x3F, 0x40, 0x40)]
[InlineData(0x40, 0x40, 0x40)]
[InlineData(0x41, 0x40, 0x80)]
[InlineData(0xFFF_FFFF_8000, 0x10000, 0x1000_0000_0000)]
public void AlignUp_Ulong(ulong value, uint alignment, ulong expectedValue)
{
var actualValue = Alignment.AlignUp(value, alignment);
Assert.Equal(expectedValue, actualValue);
}
[Theory]
[InlineData(0, 0x40, 0)]
[InlineData(0x3F, 0x40, 0)]
[InlineData(0x40, 0x40, 0x40)]
[InlineData(0x41, 0x40, 0x40)]
public void AlignDown_Byte(byte value, uint alignment, byte expectedValue)
{
var actualValue = Alignment.AlignDown(value, alignment);
Assert.Equal(expectedValue, actualValue);
}
[Theory]
[InlineData(0, 0x40, 0)]
[InlineData(0x3F, 0x40, 0)]
[InlineData(0x40, 0x40, 0x40)]
[InlineData(0x41, 0x40, 0x40)]
public void AlignDown_Long(long value, uint alignment, long expectedValue)
{
var actualValue = Alignment.AlignDown(value, alignment);
Assert.Equal(expectedValue, actualValue);
}
[Theory]
[InlineData(0, 0x40, true)]
[InlineData(0x3F, 0x40, false)]
[InlineData(0x40, 0x40, true)]
[InlineData(0x41, 0x40, false)]
public void IsAligned_Byte(byte value, uint alignment, bool expectedValue)
{
var actualValue = Alignment.IsAligned(value, alignment);
Assert.Equal(expectedValue, actualValue);
}
[Theory]
[InlineData(0, 0x40, true)]
[InlineData(0x3F, 0x40, false)]
[InlineData(0x40, 0x40, true)]
[InlineData(0x41, 0x40, false)]
[InlineData(0xFFF_FFFF_8000, 0x400, true)]
public void IsAligned_Long(long value, uint alignment, bool expectedValue)
{
var actualValue = Alignment.IsAligned(value, alignment);
Assert.Equal(expectedValue, actualValue);
}
[Theory]
[InlineData(0, 0)]
[InlineData(0x3F, 1)]
[InlineData(0x40, 0x40)]
[InlineData(0x41, 1)]
[InlineData(0x42, 2)]
[InlineData(0xFF900000, 0x100000)]
public void GetAlignment_Uint(uint value, long expectedValue)
{
var actualValue = Alignment.GetAlignment(value);
Assert.Equal(expectedValue, actualValue);
}
}
}