Skip to content

Commit

Permalink
Consolidate MetadataRange types into a single readonly struct.
Browse files Browse the repository at this point in the history
  • Loading branch information
Washi1337 committed Sep 17, 2022
1 parent 16367c1 commit 3bb6b6a
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 197 deletions.

This file was deleted.

11 changes: 10 additions & 1 deletion src/AsmResolver.PE/DotNet/Metadata/Tables/IMetadataTable.cs
Expand Up @@ -53,12 +53,21 @@ bool IsSorted
/// <returns>The row.</returns>
IMetadataRow GetByRid(uint rid);

/// <summary>
/// Attempts to get the contents of a cell in the table by its row identifier and column index.
/// </summary>
/// <param name="rid">The row identifier.</param>
/// <param name="column">The column index.</param>
/// <param name="value">When successful, the contents of the cell, converted to an unsigned integer.</param>
/// <returns><c>true</c> if the cell existed and was obtained successfully, <c>false</c> otherwise.</returns>
bool TryGetCell(uint rid, int column, out uint value);

/// <summary>
/// Attempts to get the contents of a row by its row identifier.
/// </summary>
/// <param name="rid">The row identifier.</param>
/// <param name="row">When successful, the read row.</param>
/// <returns><c>true</c> if the RID existed an the row was obtained successfully, <c>false</c> otherwise.</returns>
/// <returns><c>true</c> if the RID existed and the row was obtained successfully, <c>false</c> otherwise.</returns>
bool TryGetByRid(uint rid, out IMetadataRow row);

/// <summary>
Expand Down
129 changes: 117 additions & 12 deletions src/AsmResolver.PE/DotNet/Metadata/Tables/MetadataRange.cs
@@ -1,39 +1,56 @@
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace AsmResolver.PE.DotNet.Metadata.Tables
{
/// <summary>
/// Represents a range of metadata tokens, indicated by a starting and ending row identifier within a metadata table.
/// </summary>
public abstract class MetadataRange : IEnumerable<MetadataToken>
public readonly struct MetadataRange : IEnumerable<MetadataToken>
{
/// <summary>
/// Represents the empty metadata range.
/// </summary>
public static readonly MetadataRange Empty = new ContinuousMetadataRange(TableIndex.Module, 1, 1);
public static readonly MetadataRange Empty = new(TableIndex.Module, 1, 1);

/// <summary>
/// Initializes the range.
/// </summary>
/// <param name="table">The table.</param>
/// <param name="startRid">The starting row identifier.</param>
/// <param name="endRid">The ending row identifier. This identifier is exclusive.</param>
protected MetadataRange(TableIndex table, uint startRid, uint endRid)
public MetadataRange(TableIndex table, uint startRid, uint endRid)
{
Table = table;
StartRid = startRid;
EndRid = endRid;
RedirectionTable = null;
}

/// <summary>
/// Gets the index of the metadata table this range is targeting.
/// Initializes the range.
/// </summary>
/// <param name="redirectionTable">The table that is used for translating raw indices.</param>
/// <param name="table">The table.</param>
/// <param name="startRid">The starting row identifier.</param>
/// <param name="endRid">The ending row identifier. This identifier is exclusive.</param>
public MetadataRange(IMetadataTable redirectionTable, TableIndex table, uint startRid, uint endRid)
{
Table = table;
StartRid = startRid;
EndRid = endRid;
RedirectionTable = redirectionTable;
}

/// <summary>
/// Gets the index of the metadata table this range is targeting.
/// </summary>
public TableIndex Table
{
get;
}

/// <summary>
/// Gets the first row identifier that this range includes.
/// </summary>
Expand All @@ -43,24 +60,112 @@ public uint StartRid
}

/// <summary>
/// Gets the row identifier indicating the end of the range. The range excludes this row identifier.
/// Gets the row identifier indicating the end of the range. The range excludes this row identifier.
/// </summary>
public uint EndRid
{
get;
}

/// <summary>
/// Gets a value indicating whether the range is empty or not.
/// </summary>
public bool IsEmpty => EndRid == StartRid;

/// <summary>
/// Gets the table that is used for translating raw indices.
/// </summary>
public IMetadataTable? RedirectionTable
{
get;
}

/// <summary>
/// Gets a value indicating whether the range is associated to a redirection table.
/// </summary>
[MemberNotNullWhen(true, nameof(RedirectionTable))]
public bool IsRedirected => RedirectionTable is not null;

/// <summary>
/// Gets the number of metadata rows this range spans.
/// </summary>
public int Count => (int) (EndRid - StartRid);

/// <summary>
/// Obtains an enumerator that enumerates all metadata tokens within the range.
/// </summary>
/// <returns></returns>
public Enumerator GetEnumerator() => new(this);

/// <inheritdoc />
public abstract IEnumerator<MetadataToken> GetEnumerator();
IEnumerator<MetadataToken> IEnumerable<MetadataToken>.GetEnumerator() => GetEnumerator();

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

IEnumerator IEnumerable.GetEnumerator()
/// <inheritdoc />
public override string ToString()
{
return GetEnumerator();
var start = new MetadataToken(Table, StartRid);
var end = new MetadataToken(Table, EndRid);
return $"[0x{start.ToString()}..0x{end.ToString()})";
}

/// <summary>
/// Represents an enumerator that enumerates all metadata tokens within a token range.
/// </summary>
public struct Enumerator : IEnumerator<MetadataToken>
{
private readonly MetadataRange _range;
private uint _currentRid;

/// <summary>
/// Initializes a new token enumerator.
/// </summary>
/// <param name="range">The range to enumerate from.</param>
public Enumerator(MetadataRange range)
{
_range = range;
_currentRid = range.StartRid - 1;
}

/// <inheritdoc />
public MetadataToken Current
{
get
{
uint actualRid;

if (!_range.IsRedirected)
actualRid = _currentRid;
else
_range.RedirectionTable.TryGetCell(_currentRid, 0, out actualRid);

return new MetadataToken(_range.Table, actualRid);
}
}

/// <inheritdoc />
object IEnumerator.Current => Current;

/// <inheritdoc />
public bool MoveNext()
{
if (_currentRid < _range.EndRid - 1)
{
_currentRid++;
return true;
}

return false;
}

/// <inheritdoc />
public void Reset() => _currentRid = 0;

/// <inheritdoc />
public void Dispose()
{
}
}
}
}
}
13 changes: 13 additions & 0 deletions src/AsmResolver.PE/DotNet/Metadata/Tables/MetadataTable.cs
Expand Up @@ -180,6 +180,19 @@ public int Capacity
/// <returns>The row.</returns>
public TRow GetByRid(uint rid) => this[(int) (rid - 1)];

/// <inheritdoc />
public bool TryGetCell(uint rid, int column, out uint value)
{
if (column >= 0 && column < Layout.Columns.Count && TryGetByRid(rid, out var row))
{
value = row[column];
return true;
}

value = 0;
return false;
}

IMetadataRow IMetadataTable.GetByRid(uint rid) => GetByRid(rid);

/// <summary>
Expand Down

This file was deleted.

0 comments on commit 3bb6b6a

Please sign in to comment.