Skip to content

Commit 8e2c9d6

Browse files
committed
Added text formatting and io utillities.
1 parent daac623 commit 8e2c9d6

File tree

17 files changed

+3567
-7
lines changed

17 files changed

+3567
-7
lines changed

.github/workflows/tests.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Build and Test
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
branches:
9+
- master
10+
11+
jobs:
12+
build-and-test:
13+
runs-on: ${{ matrix.os }}
14+
strategy:
15+
matrix:
16+
os: [ubuntu-latest, windows-latest, macos-latest]
17+
18+
steps:
19+
- name: Checkout code
20+
uses: actions/checkout@v4
21+
22+
- name: Setup .NET
23+
uses: actions/setup-dotnet@v4
24+
with:
25+
dotnet-version: '9.x'
26+
27+
- name: Restore dependencies
28+
run: dotnet restore
29+
30+
- name: Build
31+
run: dotnet build
32+
33+
- name: Run tests
34+
run: dotnet test
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
namespace Hexa.NET.Utilities.Tests
2+
{
3+
using Hexa.NET.Utilities.IO;
4+
5+
[TestFixture]
6+
public unsafe class FileUtilitiesTests
7+
{
8+
[Test]
9+
[Platform(Include = "MacOsX", Reason = "This test is only applicable on macOS.")]
10+
public void EnumerateEntriesOSXTest()
11+
{
12+
// Arrange
13+
string testDirectory = AppDomain.CurrentDomain.BaseDirectory;
14+
15+
foreach (var entry in FileUtils.OSX.EnumerateEntries(testDirectory, "*", SearchOption.TopDirectoryOnly))
16+
{
17+
var path = entry.Path.ToString();
18+
string fileName = Path.GetFileName(path);
19+
Assert.Multiple(() =>
20+
{
21+
Assert.That(string.IsNullOrEmpty(path), Is.False, "Path should not be empty");
22+
Assert.That(string.IsNullOrEmpty(fileName), Is.False, "File name should not be empty");
23+
});
24+
25+
// Optional: Print the path and file name for verification
26+
Console.WriteLine($"Path: {entry.Path}, File Name: {fileName}, {entry.Attributes}");
27+
}
28+
}
29+
30+
[Test]
31+
[Platform(Include = "Win", Reason = "This test is only applicable on Windows.")]
32+
public void EnumerateEntriesWinTest()
33+
{
34+
// Arrange
35+
string testDirectory = AppDomain.CurrentDomain.BaseDirectory;
36+
37+
foreach (var entry in FileUtils.Win.EnumerateEntries(testDirectory, "*", SearchOption.TopDirectoryOnly))
38+
{
39+
var path = entry.Path.ToString();
40+
string fileName = Path.GetFileName(path);
41+
Assert.Multiple(() =>
42+
{
43+
Assert.That(string.IsNullOrEmpty(path), Is.False, "Path should not be empty");
44+
Assert.That(string.IsNullOrEmpty(fileName), Is.False, "File name should not be empty");
45+
});
46+
47+
// Optional: Print the path and file name for verification
48+
Console.WriteLine($"Path: {entry.Path}, File Name: {fileName}, {entry.Attributes}");
49+
}
50+
}
51+
}
52+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
namespace Hexa.NET.Utilities.Extensions
2+
{
3+
using System.Runtime.CompilerServices;
4+
5+
/// <summary>
6+
/// Provides extension methods for enumerations to cast them to integral types.
7+
/// </summary>
8+
public static class EnumExtension
9+
{
10+
/// <summary>
11+
/// Casts an enumeration value to the specified integral type, with type size checking.
12+
/// </summary>
13+
/// <typeparam name="TEnum">The enumeration type.</typeparam>
14+
/// <typeparam name="TInt">The integral type to cast to.</typeparam>
15+
/// <param name="enumValue">The enumeration value to cast.</param>
16+
/// <returns>The casted value of the specified integral type.</returns>
17+
/// <exception cref="Exception">Thrown when the size of the enumeration does not match the size of the target integral type.</exception>
18+
public static TInt AsInteger<TEnum, TInt>(this TEnum enumValue)
19+
where TEnum : unmanaged, Enum
20+
where TInt : unmanaged
21+
{
22+
if (Unsafe.SizeOf<TEnum>() != Unsafe.SizeOf<TInt>()) throw new Exception("type mismatch");
23+
TInt value = Unsafe.As<TEnum, TInt>(ref enumValue);
24+
return value;
25+
}
26+
27+
/// <summary>
28+
/// Casts an enumeration value to a long integral type with size checking.
29+
/// </summary>
30+
/// <typeparam name="TEnum">The enumeration type.</typeparam>
31+
/// <param name="enumValue">The enumeration value to cast.</param>
32+
/// <returns>The casted value of type long.</returns>
33+
/// <exception cref="Exception">Thrown when the size of the enumeration does not match supported integral types.</exception>
34+
public static long AsInteger<TEnum>(this TEnum enumValue)
35+
where TEnum : unmanaged, Enum
36+
{
37+
long value;
38+
if (Unsafe.SizeOf<TEnum>() != Unsafe.SizeOf<byte>()) value = Unsafe.As<TEnum, byte>(ref enumValue);
39+
else if (Unsafe.SizeOf<TEnum>() != Unsafe.SizeOf<short>()) value = Unsafe.As<TEnum, short>(ref enumValue);
40+
else if (Unsafe.SizeOf<TEnum>() != Unsafe.SizeOf<int>()) value = Unsafe.As<TEnum, int>(ref enumValue);
41+
else if (Unsafe.SizeOf<TEnum>() != Unsafe.SizeOf<long>()) value = Unsafe.As<TEnum, long>(ref enumValue);
42+
else throw new Exception("type mismatch");
43+
return value;
44+
}
45+
}
46+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
namespace Hexa.NET.Utilities.Extensions
2+
{
3+
using System;
4+
using System.Runtime.InteropServices;
5+
using System.Text;
6+
7+
public static unsafe class SpanHelper
8+
{
9+
public static ReadOnlySpan<char> CreateReadOnlySpanFromNullTerminated(char* pointer)
10+
{
11+
int len = StrLen(pointer);
12+
return new ReadOnlySpan<char>(pointer, len);
13+
}
14+
15+
public static ReadOnlySpan<byte> CreateReadOnlySpanFromNullTerminated(byte* pointer)
16+
{
17+
int len = StrLen(pointer);
18+
return new ReadOnlySpan<byte>(pointer, len);
19+
}
20+
21+
#if NETSTANDARD2_0
22+
public static bool StartsWith(this ReadOnlySpan<char> span, char c)
23+
{
24+
return span.Length > 0 && span[0] == c;
25+
}
26+
27+
public static bool StartsWith(this string span, char c)
28+
{
29+
return span.Length > 0 && span[0] == c;
30+
}
31+
32+
public static void Append(this StringBuilder sb, ReadOnlySpan<char> span)
33+
{
34+
if (span.IsEmpty)
35+
return;
36+
37+
// Ensure the StringBuilder has enough capacity to avoid resizing during append
38+
sb.EnsureCapacity(sb.Length + span.Length);
39+
40+
// Manually append each character from the span to the StringBuilder
41+
foreach (char c in span)
42+
{
43+
sb.Append(c);
44+
}
45+
}
46+
47+
public static int GetBytes(this Encoding encoding, ReadOnlySpan<char> chars, Span<byte> bytes)
48+
{
49+
fixed (char* pChars = chars)
50+
{
51+
fixed (byte* pBytes = bytes)
52+
{
53+
return encoding.GetBytes(pChars, chars.Length, pBytes, bytes.Length);
54+
}
55+
}
56+
}
57+
58+
public static int GetChars(this Encoding encoding, ReadOnlySpan<byte> bytes, Span<char> chars)
59+
{
60+
fixed (byte* pBytes = bytes)
61+
{
62+
fixed (char* pChars = chars)
63+
{
64+
return encoding.GetChars(pBytes, bytes.Length, pChars, chars.Length);
65+
}
66+
}
67+
}
68+
69+
public static int GetCharCount(this Encoding encoding, ReadOnlySpan<byte> bytes)
70+
{
71+
fixed (byte* pBytes = bytes)
72+
{
73+
return encoding.GetCharCount(pBytes, bytes.Length);
74+
}
75+
}
76+
77+
public static int GetByteCount(this Encoding encoding, ReadOnlySpan<char> chars)
78+
{
79+
fixed (char* pChars = chars)
80+
{
81+
return encoding.GetByteCount(pChars, chars.Length);
82+
}
83+
}
84+
85+
#endif
86+
}
87+
88+
public static unsafe class CollectionsExtensions
89+
{
90+
public static void AddRange<T>(this IList<T> list, Span<T> values)
91+
{
92+
for (int i = 0; i < values.Length; i++)
93+
{
94+
list.Add(values[i]);
95+
}
96+
}
97+
}
98+
}

Hexa.NET.Utilities/Hexa.NET.Utilities.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<PropertyGroup>
2020
<PackageId>Hexa.NET.Utilities</PackageId>
2121
<AssemblyVersion>1.0.0</AssemblyVersion>
22-
<PackageVersion>2.1.14</PackageVersion>
22+
<PackageVersion>2.2.0</PackageVersion>
2323
<Authors>Juna</Authors>
2424
<AssemblyName>Hexa.NET.Utilities</AssemblyName>
2525
<PackageProjectUrl>https://github.com/HexaEngine/Hexa.NET.Utilities</PackageProjectUrl>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace Hexa.NET.Utilities.IO
2+
{
3+
using Hexa.NET.Utilities;
4+
using System;
5+
using System.IO;
6+
7+
public struct FileMetadata
8+
{
9+
public StdWString Path;
10+
public long Size;
11+
public DateTime CreationTime;
12+
public DateTime LastAccessTime;
13+
public DateTime LastWriteTime;
14+
public FileAttributes Attributes;
15+
}
16+
}

0 commit comments

Comments
 (0)