Skip to content

Commit

Permalink
Replace Marshal.SizeOf with Unsafe.SizeOf for component registration (#…
Browse files Browse the repository at this point in the history
…112)

* Replace Marshal.SizeOf with Unsafe.SizeOf for component registration

* Merge codepaths

* Fix doc comments
  • Loading branch information
DrSmugleaf committed May 16, 2023
1 parent 292ece0 commit 33013b9
Showing 1 changed file with 82 additions and 35 deletions.
117 changes: 82 additions & 35 deletions src/Arch/Core/Utils/CompileTimeStatics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,23 +109,36 @@ public static ComponentType[] TypesArray
/// <remarks>You should only be using this when you exactly know what you are doing.</remarks>
/// </summary>
/// <param name="type">Its <see cref="Type"/>.</param>
/// <param name="typeSize">The size in bytes of <see cref="type"/>.</param>
/// <returns>Its <see cref="ComponentType"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ComponentType Add(ComponentType type)
private static ComponentType Add(Type type, int typeSize)
{
if (TryGet(type, out var meta))
{
return meta;
}

// Register and assign component id
meta = type;
meta = new ComponentType(Size + 1, type, typeSize, type.GetFields().Length == 0);
_types.Add(type, meta);

Size++;
return meta;
}

/// <summary>
/// Adds a new <see cref="ComponentType"/> manually and registers it.
/// <remarks>You should only be using this when you exactly know what you are doing.</remarks>
/// </summary>
/// <param name="type">Its <see cref="Type"/>.</param>
/// <returns>Its <see cref="ComponentType"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ComponentType Add(ComponentType type)
{
return Add(type.Type, type.ByteSize);
}

/// <summary>
/// Adds a new component and registers it.
/// </summary>
Expand All @@ -134,7 +147,7 @@ public static ComponentType Add(ComponentType type)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ComponentType Add<T>()
{
return Add(typeof(T));
return Add(typeof(T), SizeOf<T>());
}

/// <summary>
Expand All @@ -145,26 +158,15 @@ public static ComponentType Add<T>()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ComponentType Add(Type type)
{
if (TryGet(type, out var meta))
{
return meta;
}

// Register and assign component id
var size = type.IsValueType ? Marshal.SizeOf(type) : IntPtr.Size;
meta = new ComponentType(Size + 1, type, size, type.GetFields().Length == 0);
_types.Add(type, meta);

Size++;
return meta;
return Add(type, SizeOf(type));
}

// NOTE: Should this be `Contains` to follow other existing .NET APIs (ICollection<T>.Contains(T))?
/// <summary>
/// Checks if a component is registered.
/// </summary>
/// <typeparam name="T">Its generic type.</typeparam>
/// <returns>True if it is, otherwhise false.</returns>
/// <returns>True if it is, otherwise false.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Has<T>()
{
Expand All @@ -176,7 +178,7 @@ public static bool Has<T>()
/// Checks if a component is registered.
/// </summary>
/// <param name="type">Its <see cref="Type"/>.</param>
/// <returns>True if it is, otherwhise false.</returns>
/// <returns>True if it is, otherwise false.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Has(Type type)
{
Expand All @@ -187,7 +189,7 @@ public static bool Has(Type type)
/// Removes a registered component by its <see cref="Type"/> from the <see cref="ComponentRegistry"/>.
/// </summary>
/// <typeparam name="T">The component to remove.</typeparam>
/// <returns>True if it was sucessfull, false if not.</returns>
/// <returns>True if it was successful, false if not.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Remove<T>()
{
Expand All @@ -198,26 +200,23 @@ public static bool Remove<T>()
/// Removes a registered component by its <see cref="Type"/> from the <see cref="ComponentRegistry"/>.
/// </summary>
/// <param name="type">The component <see cref="Type"/> to remove.</param>
/// <returns>True if it was sucessfull, false if not.</returns>
/// <returns>True if it was successful, false if not.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Remove(Type type)
{
return _types.Remove(type);
}

/// <summary>
/// Replaces a registered component by its <see cref="Type"/> with another one.
/// The new <see cref="Type"/> will receive the id from the old one.
/// <remarks>Use with caution, might cause undefined behaviour if you do not know what exactly you are doing.</remarks>
/// Removes a registered component by its <see cref="Type"/> from the <see cref="ComponentRegistry"/>.
/// </summary>
/// <typeparam name="T0">The old component to be replaced.</typeparam>
/// <typeparam name="T1">The new component that replaced the old one.</typeparam>
/// <param name="type">The component <see cref="Type"/> to remove.</param>
/// <param name="compType">The removed <see cref="ComponentType"/>, if it existed.</param>
/// <returns>True if it was successful, false if not.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Replace<T0,T1>()
public static bool Remove(Type type, out ComponentType compType)
{
var oldType = typeof(T0);
var newType = typeof(T1);
Replace(oldType, newType);
return _types.Remove(type, out compType);
}

/// <summary>
Expand All @@ -227,30 +226,55 @@ public static bool Remove(Type type)
/// </summary>
/// <param name="oldType">The old component <see cref="Type"/> to be replaced.</param>
/// <param name="newType">The new component <see cref="Type"/> that replaced the old one.</param>
/// <param name="newTypeSize">The size in bytes of <see cref="newType"/>.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Replace(Type oldType, Type newType)
public static void Replace(Type oldType, Type newType, int newTypeSize)
{
var id = 0;
if (TryGet(oldType, out var oldComponentType))
if (Remove(oldType, out var oldComponentType))
{
id = oldComponentType.Id;
_types.Remove(oldType);
}
else
{
id = ++Size;
}

var size = newType.IsValueType ? Marshal.SizeOf(newType) : IntPtr.Size;
_types.Add(newType, new ComponentType(id, newType, size, newType.GetFields().Length == 0));
_types.Add(newType, new ComponentType(id, newType, newTypeSize, newType.GetFields().Length == 0));
}

/// <summary>
/// Replaces a registered component by its <see cref="Type"/> with another one.
/// The new <see cref="Type"/> will receive the id from the old one.
/// <remarks>Use with caution, might cause undefined behaviour if you do not know what exactly you are doing.</remarks>
/// </summary>
/// <typeparam name="T0">The old component to be replaced.</typeparam>
/// <typeparam name="T1">The new component that replaced the old one.</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Replace<T0, T1>()
{
Replace(typeof(T0), typeof(T1), SizeOf<T1>());
}

/// <summary>
/// Replaces a registered component by its <see cref="Type"/> with another one.
/// The new <see cref="Type"/> will receive the id from the old one.
/// <remarks>Use with caution, might cause undefined behaviour if you do not know what exactly you are doing.</remarks>
/// </summary>
/// <param name="oldType">The old component <see cref="Type"/> to be replaced.</param>
/// <param name="newType">The new component <see cref="Type"/> that replaced the old one.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Replace(Type oldType, Type newType)
{
Replace(oldType, newType, SizeOf(newType));
}

/// <summary>
/// Trys to get a component if it is registered.
/// </summary>
/// <typeparam name="T">Its generic type.</typeparam>
/// <param name="componentType">Its <see cref="ComponentType"/>, if it is registered.</param>
/// <returns>True if it registered, otherwhise false.</returns>
/// <returns>True if it registered, otherwise false.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryGet<T>(out ComponentType componentType)
{
Expand All @@ -262,12 +286,35 @@ public static bool TryGet<T>(out ComponentType componentType)
/// </summary>
/// <param name="type">Its <see cref="Type"/>.</param>
/// <param name="componentType">Its <see cref="ComponentType"/>, if it is registered.</param>
/// <returns>True if it registered, otherwhise false.</returns>
/// <returns>True if it registered, otherwise false.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryGet(Type type, out ComponentType componentType)
{
return _types.TryGetValue(type, out componentType);
}

private static int SizeOf<T>()
{
if (typeof(T).IsValueType)
{
return Unsafe.SizeOf<T>();
}

return IntPtr.Size;
}

private static int SizeOf(Type type)
{
if (type.IsValueType)
{
return (int) typeof(Unsafe)
.GetMethod(nameof(Unsafe.SizeOf))!
.MakeGenericMethod(type)
.Invoke(null, null)!;
}

return IntPtr.Size;
}
}

/// <summary>
Expand Down

0 comments on commit 33013b9

Please sign in to comment.