Skip to content

Commit 9148e12

Browse files
Further reduce allocations
1 parent ec0d104 commit 9148e12

File tree

6 files changed

+237
-172
lines changed

6 files changed

+237
-172
lines changed

API/Routing/RoutingTarget.cs

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Linq;
34

45
namespace GenHTTP.Api.Routing
@@ -13,6 +14,8 @@ namespace GenHTTP.Api.Routing
1314
/// </remarks>
1415
public sealed class RoutingTarget
1516
{
17+
private static readonly List<WebPathPart> EMPTY_LIST = new();
18+
1619
private int _Index = 0;
1720

1821
#region Get-/Setters
@@ -72,7 +75,19 @@ public void Advance()
7275
/// Retrieves the part of the path that still needs to be routed.
7376
/// </summary>
7477
/// <returns>The remaining part of the path</returns>
75-
public WebPath GetRemaining() => new(Path.Parts.Skip(_Index).ToList(), Path.TrailingSlash);
78+
public WebPath GetRemaining()
79+
{
80+
var remaining = Path.Parts.Count - _Index;
81+
82+
var resultList = (remaining > 0) ? new List<WebPathPart>(remaining) : EMPTY_LIST;
83+
84+
for (int i = _Index; i < Path.Parts.Count; i++)
85+
{
86+
resultList.Add(Path.Parts[i]);
87+
}
88+
89+
return new(resultList, Path.TrailingSlash);
90+
}
7691

7792
#endregion
7893

Engine/Protocol/Parser/Conversion/MethodConverter.cs

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Buffers;
2+
using System.Collections.Generic;
23

34
using GenHTTP.Api.Protocol;
45

@@ -7,10 +8,26 @@ namespace GenHTTP.Engine.Protocol.Parser.Conversion
78

89
internal static class MethodConverter
910
{
11+
private static readonly Dictionary<string, RequestMethod> KNOWN_METHODS = new(7)
12+
{
13+
{ "GET", RequestMethod.GET },
14+
{ "HEAD", RequestMethod.HEAD },
15+
{ "POST", RequestMethod.POST },
16+
{ "PUT", RequestMethod.PUT },
17+
{ "PATCH", RequestMethod.PATCH },
18+
{ "DELETE", RequestMethod.DELETE },
19+
{ "OPTIONS", RequestMethod.OPTIONS }
20+
};
1021

1122
internal static FlexibleRequestMethod ToRequestMethod(ReadOnlySequence<byte> value)
1223
{
13-
if (ValueConverter.CompareTo(value, "GET")) return FlexibleRequestMethod.Get(RequestMethod.GET);
24+
foreach (var kv in KNOWN_METHODS)
25+
{
26+
if (ValueConverter.CompareTo(value, kv.Key))
27+
{
28+
return FlexibleRequestMethod.Get(kv.Value);
29+
}
30+
}
1431

1532
return FlexibleRequestMethod.Get(ValueConverter.GetString(value));
1633
}
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,71 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
5-
namespace GenHTTP.Modules.Conversion.Formatters
6-
{
7-
8-
public sealed class FormatterRegistry
9-
{
10-
11-
#region Get-/Setters
12-
13-
public IReadOnlyList<IFormatter> Formatters { get; private set; }
14-
15-
#endregion
16-
17-
#region Initialization
18-
19-
public FormatterRegistry(List<IFormatter> formatters)
20-
{
21-
Formatters = formatters;
22-
}
23-
24-
#endregion
25-
26-
#region Functionality
27-
28-
public bool CanHandle(Type type) => Formatters.Any(f => f.CanHandle(type));
29-
30-
public object? Read(string value, Type type) => Formatters.First(f => f.CanHandle(type)).Read(value, type);
31-
32-
public string? Write(object value, Type type) => Formatters.First(f => f.CanHandle(type)).Write(value, type);
33-
34-
#endregion
35-
36-
}
37-
38-
}
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace GenHTTP.Modules.Conversion.Formatters
5+
{
6+
7+
public sealed class FormatterRegistry
8+
{
9+
10+
#region Get-/Setters
11+
12+
public IReadOnlyList<IFormatter> Formatters { get; private set; }
13+
14+
#endregion
15+
16+
#region Initialization
17+
18+
public FormatterRegistry(List<IFormatter> formatters)
19+
{
20+
Formatters = formatters;
21+
}
22+
23+
#endregion
24+
25+
#region Functionality
26+
27+
public bool CanHandle(Type type)
28+
{
29+
for (int i = 0; i < Formatters.Count; i++)
30+
{
31+
if (Formatters[i].CanHandle(type))
32+
{
33+
return true;
34+
}
35+
}
36+
37+
return false;
38+
}
39+
40+
public object? Read(string value, Type type)
41+
{
42+
for (int i = 0; i < Formatters.Count; i++)
43+
{
44+
if (Formatters[i].CanHandle(type))
45+
{
46+
return Formatters[i].Read(value, type);
47+
}
48+
}
49+
50+
return null;
51+
}
52+
53+
54+
public string? Write(object value, Type type)
55+
{
56+
for (int i = 0; i < Formatters.Count; i++)
57+
{
58+
if (Formatters[i].CanHandle(type))
59+
{
60+
return Formatters[i].Write(value, type);
61+
}
62+
}
63+
64+
return null;
65+
}
66+
67+
#endregion
68+
69+
}
70+
71+
}

Modules/IO/Streaming/StreamExtensions.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public static class StreamExtensions
1515

1616
private static readonly Encoding UTF8 = Encoding.UTF8;
1717

18+
private static readonly Encoder ENCODER = UTF8.GetEncoder();
19+
1820
public static async ValueTask CopyPooledAsync(this Stream source, Stream target, uint bufferSize)
1921
{
2022
if (source.CanSeek && source.Position != 0)
@@ -56,15 +58,13 @@ public static async ValueTask RenderToStream<T>(this IRenderer<T> renderer, T mo
5658

5759
public static async ValueTask WriteAsync(this string content, Stream target)
5860
{
59-
var encoder = UTF8.GetEncoder();
60-
61-
var bytes = encoder.GetByteCount(content, false);
61+
var bytes = ENCODER.GetByteCount(content, false);
6262

6363
var buffer = POOL.Rent(bytes);
6464

6565
try
6666
{
67-
encoder.GetBytes(content.AsSpan(), buffer.AsSpan(), true);
67+
ENCODER.GetBytes(content.AsSpan(), buffer.AsSpan(), true);
6868

6969
await target.WriteAsync(buffer.AsMemory(0, bytes));
7070
}

Playground/Program.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
Host.Create()
77
.Handler(Content.From(Resource.FromString("Hello World")))
8-
//.Defaults()
9-
//.Development()
10-
//.Console()
8+
.Defaults()
9+
.Development()
10+
.Console()
1111
.Run();
1212

0 commit comments

Comments
 (0)