Perf - enumerate with struct
Conflicts: src/Microsoft.AspNet.Server.Kestrel/project.json
This commit is contained in:
parent
ad089be477
commit
96b03ee212
|
|
@ -10,9 +10,9 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
|
|||
// To enable this option, right-click on the project and select the Properties menu item. In the Build tab select "Produce outputs on build".
|
||||
public class KnownHeaders : ICompileModule
|
||||
{
|
||||
string Each<T>(IEnumerable<T> values, Func<T, string> formatter)
|
||||
static string Each<T>(IEnumerable<T> values, Func<T, string> formatter)
|
||||
{
|
||||
return values.Select(formatter).Aggregate((a, b) => a + b + "\r\n");
|
||||
return values.Select(formatter).Aggregate((a, b) => a + b);
|
||||
}
|
||||
|
||||
class KnownHeader
|
||||
|
|
@ -26,6 +26,12 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
|
|||
}
|
||||
|
||||
public virtual void BeforeCompile(BeforeCompileContext context)
|
||||
{
|
||||
var syntaxTree = Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText(GeneratedFile());
|
||||
context.Compilation = context.Compilation.AddSyntaxTrees(syntaxTree);
|
||||
}
|
||||
|
||||
public static string GeneratedFile()
|
||||
{
|
||||
var commonHeaders = new[]
|
||||
{
|
||||
|
|
@ -71,7 +77,7 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
|
|||
"Referer",
|
||||
"Range",
|
||||
"TE",
|
||||
"Translage",
|
||||
"Translate",
|
||||
"User-Agent",
|
||||
}).Select((header, index) => new KnownHeader
|
||||
{
|
||||
|
|
@ -113,7 +119,7 @@ namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
|
|||
}
|
||||
};
|
||||
|
||||
var syntaxTree = Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree.ParseText($@"
|
||||
return $@"
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
|
@ -122,11 +128,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
public partial class {loop.ClassName}
|
||||
{{
|
||||
long _bits = 0;
|
||||
{Each(loop.Headers, header => "string[] _" + header.Identifier + ";")}
|
||||
{Each(loop.Headers, header => @"
|
||||
string[] _" + header.Identifier + ";")}
|
||||
|
||||
protected override int GetCountFast()
|
||||
{{
|
||||
var count = Unknown.Count;
|
||||
var count = MaybeUnknown?.Count ?? 0;
|
||||
{Each(loop.Headers, header => $@"
|
||||
if ({header.TestBit()})
|
||||
{{
|
||||
|
|
@ -142,7 +149,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
{{{Each(loop.HeadersByLength, byLength => $@"
|
||||
case {byLength.Key}:
|
||||
{{{Each(byLength, header => $@"
|
||||
if (0 == StringComparer.OrdinalIgnoreCase.Compare(key, ""{header.Name}""))
|
||||
if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
|
||||
{{
|
||||
if ({header.TestBit()})
|
||||
{{
|
||||
|
|
@ -156,7 +163,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
")}}}
|
||||
break;
|
||||
")}}}
|
||||
return Unknown[key];
|
||||
if (MaybeUnknown == null)
|
||||
{{
|
||||
throw new System.Collections.Generic.KeyNotFoundException();
|
||||
}}
|
||||
return MaybeUnknown[key];
|
||||
}}
|
||||
|
||||
protected override bool TryGetValueFast(string key, out string[] value)
|
||||
|
|
@ -165,7 +176,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
{{{Each(loop.HeadersByLength, byLength => $@"
|
||||
case {byLength.Key}:
|
||||
{{{Each(byLength, header => $@"
|
||||
if (0 == StringComparer.OrdinalIgnoreCase.Compare(key, ""{header.Name}""))
|
||||
if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
|
||||
{{
|
||||
if ({header.TestBit()})
|
||||
{{
|
||||
|
|
@ -181,7 +192,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
")}}}
|
||||
break;
|
||||
")}}}
|
||||
return Unknown.TryGetValue(key, out value);
|
||||
value = null;
|
||||
return MaybeUnknown?.TryGetValue(key, out value) ?? false;
|
||||
}}
|
||||
|
||||
protected override void SetValueFast(string key, string[] value)
|
||||
|
|
@ -190,7 +202,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
{{{Each(loop.HeadersByLength, byLength => $@"
|
||||
case {byLength.Key}:
|
||||
{{{Each(byLength, header => $@"
|
||||
if (0 == StringComparer.OrdinalIgnoreCase.Compare(key, ""{header.Name}""))
|
||||
if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
|
||||
{{
|
||||
{header.SetBit()};
|
||||
_{header.Identifier} = value;
|
||||
|
|
@ -208,7 +220,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
{{{Each(loop.HeadersByLength, byLength => $@"
|
||||
case {byLength.Key}:
|
||||
{{{Each(byLength, header => $@"
|
||||
if (0 == StringComparer.OrdinalIgnoreCase.Compare(key, ""{header.Name}""))
|
||||
if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
|
||||
{{
|
||||
if ({header.TestBit()})
|
||||
{{
|
||||
|
|
@ -230,7 +242,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
{{{Each(loop.HeadersByLength, byLength => $@"
|
||||
case {byLength.Key}:
|
||||
{{{Each(byLength, header => $@"
|
||||
if (0 == StringComparer.OrdinalIgnoreCase.Compare(key, ""{header.Name}""))
|
||||
if (""{header.Name}"".Equals(key, StringComparison.OrdinalIgnoreCase))
|
||||
{{
|
||||
if ({header.TestBit()})
|
||||
{{
|
||||
|
|
@ -245,13 +257,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
")}}}
|
||||
break;
|
||||
")}}}
|
||||
return Unknown.Remove(key);
|
||||
return MaybeUnknown?.Remove(key) ?? false;
|
||||
}}
|
||||
|
||||
protected override void ClearFast()
|
||||
{{
|
||||
_bits = 0;
|
||||
Unknown.Clear();
|
||||
MaybeUnknown?.Clear();
|
||||
}}
|
||||
|
||||
protected override void CopyToFast(KeyValuePair<string, string[]>[] array, int arrayIndex)
|
||||
|
|
@ -273,27 +285,44 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
++arrayIndex;
|
||||
}}
|
||||
")}
|
||||
((ICollection<KeyValuePair<string, string[]>>)Unknown).CopyTo(array, arrayIndex);
|
||||
((ICollection<KeyValuePair<string, string[]>>)MaybeUnknown)?.CopyTo(array, arrayIndex);
|
||||
}}
|
||||
|
||||
protected override IEnumerable<KeyValuePair<string, string[]>> EnumerateFast()
|
||||
public partial struct Enumerator
|
||||
{{
|
||||
{Each(loop.Headers, header => $@"
|
||||
if ({header.TestBit()})
|
||||
{{
|
||||
yield return new KeyValuePair<string, string[]>(""{header.Name}"", _{header.Identifier});
|
||||
}}
|
||||
")}
|
||||
foreach(var kv in Unknown)
|
||||
public bool MoveNext()
|
||||
{{
|
||||
yield return kv;
|
||||
switch (_state)
|
||||
{{
|
||||
{Each(loop.Headers, header => $@"
|
||||
case {header.Index}:
|
||||
goto state{header.Index};
|
||||
")}
|
||||
default:
|
||||
goto state_default;
|
||||
}}
|
||||
{Each(loop.Headers, header => $@"
|
||||
state{header.Index}:
|
||||
if ({header.TestBit()})
|
||||
{{
|
||||
_current = new KeyValuePair<string, string[]>(""{header.Name}"", _collection._{header.Identifier});
|
||||
_state = {header.Index + 1};
|
||||
return true;
|
||||
}}
|
||||
")}
|
||||
state_default:
|
||||
if (!_hasUnknown || !_unknownEnumerator.MoveNext())
|
||||
{{
|
||||
_current = default(KeyValuePair<string, string[]>);
|
||||
return false;
|
||||
}}
|
||||
_current = _unknownEnumerator.Current;
|
||||
return true;
|
||||
}}
|
||||
}}
|
||||
}}
|
||||
")}}}
|
||||
");
|
||||
|
||||
context.Compilation = context.Compilation.AddSyntaxTrees(syntaxTree);
|
||||
";
|
||||
}
|
||||
|
||||
public virtual void AfterCompile(AfterCompileContext context)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Server.Kestrel.GeneratedCode
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public int Main(string[] args)
|
||||
{
|
||||
var text = KnownHeaders.GeneratedFile();
|
||||
|
||||
if (args.Length == 1)
|
||||
{
|
||||
var existing = File.Exists(args[0]) ? File.ReadAllText(args[0]) : "";
|
||||
if (!string.Equals(text, existing))
|
||||
{
|
||||
File.WriteAllText(args[0], text);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine(text);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
private bool _resultStarted;
|
||||
private bool _responseStarted;
|
||||
private bool _keepAlive;
|
||||
private readonly FrameRequestHeaders _requestHeaders = new FrameRequestHeaders();
|
||||
private readonly FrameResponseHeaders _responseHeaders = new FrameResponseHeaders();
|
||||
|
||||
/*
|
||||
//IDictionary<string, object> _environment;
|
||||
|
|
@ -43,8 +45,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
{
|
||||
FrameControl = this;
|
||||
StatusCode = 200;
|
||||
RequestHeaders = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);
|
||||
ResponseHeaders = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);
|
||||
RequestHeaders = _requestHeaders;
|
||||
ResponseHeaders = _responseHeaders;
|
||||
}
|
||||
|
||||
public string Method { get; set; }
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -5,17 +5,11 @@ using System.Linq;
|
|||
|
||||
namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||
{
|
||||
public partial class FrameRequestHeaders : FrameHeaders
|
||||
{
|
||||
}
|
||||
|
||||
public partial class FrameResponseHeaders : FrameHeaders
|
||||
{
|
||||
}
|
||||
|
||||
public abstract class FrameHeaders : IDictionary<string, string[]>
|
||||
{
|
||||
protected Dictionary<string, string[]> Unknown = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);
|
||||
protected Dictionary<string, string[]> MaybeUnknown;
|
||||
|
||||
protected Dictionary<string, string[]> Unknown => MaybeUnknown ?? (MaybeUnknown = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase));
|
||||
|
||||
protected virtual int GetCountFast()
|
||||
{ throw new NotImplementedException(); }
|
||||
|
|
@ -41,7 +35,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
protected virtual void CopyToFast(KeyValuePair<string, string[]>[] array, int arrayIndex)
|
||||
{ throw new NotImplementedException(); }
|
||||
|
||||
protected virtual IEnumerable<KeyValuePair<string, string[]>> EnumerateFast()
|
||||
protected virtual IEnumerator<KeyValuePair<string, string[]>> GetEnumeratorFast()
|
||||
{ throw new NotImplementedException(); }
|
||||
|
||||
|
||||
|
|
@ -62,9 +56,9 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
|
||||
bool ICollection<KeyValuePair<string, string[]>>.IsReadOnly => false;
|
||||
|
||||
ICollection<string> IDictionary<string, string[]>.Keys => EnumerateFast().Select(x => x.Key).ToList();
|
||||
ICollection<string> IDictionary<string, string[]>.Keys => ((IDictionary<string,string[]>)this).Select(x => x.Key).ToList();
|
||||
|
||||
ICollection<string[]> IDictionary<string, string[]>.Values => EnumerateFast().Select(x => x.Value).ToList();
|
||||
ICollection<string[]> IDictionary<string, string[]>.Values => ((IDictionary<string, string[]>)this).Select(x => x.Value).ToList();
|
||||
|
||||
void ICollection<KeyValuePair<string, string[]>>.Add(KeyValuePair<string, string[]> item)
|
||||
{
|
||||
|
|
@ -102,12 +96,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return EnumerateFast().GetEnumerator();
|
||||
return GetEnumeratorFast();
|
||||
}
|
||||
|
||||
IEnumerator<KeyValuePair<string, string[]>> IEnumerable<KeyValuePair<string, string[]>>.GetEnumerator()
|
||||
{
|
||||
return EnumerateFast().GetEnumerator();
|
||||
return GetEnumeratorFast();
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<string, string[]>>.Remove(KeyValuePair<string, string[]> item)
|
||||
|
|
@ -129,4 +123,100 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
|||
return TryGetValueFast(key, out value);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class FrameRequestHeaders : FrameHeaders
|
||||
{
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
protected override IEnumerator<KeyValuePair<string, string[]>> GetEnumeratorFast()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public partial struct Enumerator : IEnumerator<KeyValuePair<string, string[]>>
|
||||
{
|
||||
FrameRequestHeaders _collection;
|
||||
long _bits;
|
||||
int _state;
|
||||
KeyValuePair<string, string[]> _current;
|
||||
bool _hasUnknown;
|
||||
Dictionary<string, string[]>.Enumerator _unknownEnumerator;
|
||||
|
||||
internal Enumerator(FrameRequestHeaders collection)
|
||||
{
|
||||
_collection = collection;
|
||||
_bits = collection._bits;
|
||||
_state = 0;
|
||||
_current = default(KeyValuePair<string, string[]>);
|
||||
_hasUnknown = collection.MaybeUnknown != null;
|
||||
_unknownEnumerator = _hasUnknown
|
||||
? collection.MaybeUnknown.GetEnumerator()
|
||||
: default(Dictionary<string, string[]>.Enumerator);
|
||||
}
|
||||
|
||||
public KeyValuePair<string, string[]> Current => _current;
|
||||
|
||||
object IEnumerator.Current => _current;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class FrameResponseHeaders : FrameHeaders
|
||||
{
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return new Enumerator(this);
|
||||
}
|
||||
|
||||
protected override IEnumerator<KeyValuePair<string, string[]>> GetEnumeratorFast()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public partial struct Enumerator : IEnumerator<KeyValuePair<string, string[]>>
|
||||
{
|
||||
FrameResponseHeaders _collection;
|
||||
long _bits;
|
||||
int _state;
|
||||
KeyValuePair<string, string[]> _current;
|
||||
bool _hasUnknown;
|
||||
Dictionary<string, string[]>.Enumerator _unknownEnumerator;
|
||||
|
||||
internal Enumerator(FrameResponseHeaders collection)
|
||||
{
|
||||
_collection = collection;
|
||||
_bits = collection._bits;
|
||||
_state = 0;
|
||||
_current = default(KeyValuePair<string, string[]>);
|
||||
_hasUnknown = collection.MaybeUnknown != null;
|
||||
_unknownEnumerator = _hasUnknown
|
||||
? collection.MaybeUnknown.GetEnumerator()
|
||||
: default(Dictionary<string, string[]>.Enumerator);
|
||||
}
|
||||
|
||||
public KeyValuePair<string, string[]> Current => _current;
|
||||
|
||||
object IEnumerator.Current => _current;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNet.Server.Kestrel
|
||||
{
|
||||
public class KnownHeaders : Microsoft.AspNet.Server.Kestrel.GeneratedCode.KnownHeaders
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -6,8 +6,7 @@
|
|||
"url": "git://github.com/aspnet/kestrelhttpserver"
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.Dnx.Runtime.Abstractions": "1.0.0-beta7-*",
|
||||
"Microsoft.AspNet.Server.Kestrel.GeneratedCode": { "version": "1.0.0-*", "type": "build" }
|
||||
"Microsoft.Dnx.Runtime.Abstractions": "1.0.0-beta7-*"
|
||||
},
|
||||
"frameworks": {
|
||||
"dnx451": { },
|
||||
|
|
@ -33,5 +32,8 @@
|
|||
},
|
||||
"compilationOptions": {
|
||||
"allowUnsafe": true
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "dnx ../Microsoft.AspNet.Server.Kestrel.GeneratedCode run Http/FrameHeaders.Generated.cs"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue