diff --git a/README.md b/README.md
index c31882025b..fc2a0e6ac4 100644
--- a/README.md
+++ b/README.md
@@ -303,7 +303,7 @@ We are grateful to the following sponsors, who provide the team with a no-cost l
-
+
Do you like this project? Consider to [sponsor](https://github.com/sponsors/json-api-dotnet), or just reward us by
giving our repository a star.
diff --git a/src/JsonApiDotNetCore/Queries/Parsing/QueryExpressionParser.cs b/src/JsonApiDotNetCore/Queries/Parsing/QueryExpressionParser.cs
index d324ffc11b..46fa2c8273 100644
--- a/src/JsonApiDotNetCore/Queries/Parsing/QueryExpressionParser.cs
+++ b/src/JsonApiDotNetCore/Queries/Parsing/QueryExpressionParser.cs
@@ -53,7 +53,20 @@ protected virtual void Tokenize(string source)
Source = source;
var tokenizer = new QueryTokenizer(source);
- TokenStack = new Stack(tokenizer.EnumerateTokens().Reverse());
+ Token[] tokens = tokenizer.EnumerateTokens().ToArray();
+ TokenStack = TokensToStack(tokens);
+ }
+
+ private static Stack TokensToStack(Token[] tokens)
+ {
+ var stack = new Stack(tokens.Length);
+
+ for (int index = tokens.Length - 1; index >= 0; index--)
+ {
+ stack.Push(tokens[index]);
+ }
+
+ return stack;
}
///
@@ -143,7 +156,11 @@ protected virtual void EatSingleCharacterToken(TokenKind kind)
{
if (!TokenStack.TryPop(out Token? token) || token.Kind != kind)
{
- char ch = QueryTokenizer.SingleCharacterToTokenKinds.Single(pair => pair.Value == kind).Key;
+ if (!QueryTokenizer.TokenKindToSingleCharacterLookup.TryGetValue(kind, out char ch))
+ {
+ throw new InvalidOperationException($"Token kind '{kind}' is not a single-character token.");
+ }
+
int position = token?.Position ?? GetNextTokenPositionOrEnd();
throw new QueryParseException($"{ch} expected.", position);
}
diff --git a/src/JsonApiDotNetCore/Queries/Parsing/QueryTokenizer.cs b/src/JsonApiDotNetCore/Queries/Parsing/QueryTokenizer.cs
index 0e1e7660a2..bf7b714e96 100644
--- a/src/JsonApiDotNetCore/Queries/Parsing/QueryTokenizer.cs
+++ b/src/JsonApiDotNetCore/Queries/Parsing/QueryTokenizer.cs
@@ -1,4 +1,3 @@
-using System.Collections.ObjectModel;
using System.Text;
using JetBrains.Annotations;
@@ -7,18 +6,20 @@ namespace JsonApiDotNetCore.Queries.Parsing;
[PublicAPI]
public sealed class QueryTokenizer
{
- public static readonly IReadOnlyDictionary SingleCharacterToTokenKinds = new ReadOnlyDictionary(
- new Dictionary
- {
- ['('] = TokenKind.OpenParen,
- [')'] = TokenKind.CloseParen,
- ['['] = TokenKind.OpenBracket,
- [']'] = TokenKind.CloseBracket,
- ['.'] = TokenKind.Period,
- [','] = TokenKind.Comma,
- [':'] = TokenKind.Colon,
- ['-'] = TokenKind.Minus
- });
+ public static readonly IReadOnlyDictionary SingleCharacterToTokenKinds = new Dictionary
+ {
+ ['('] = TokenKind.OpenParen,
+ [')'] = TokenKind.CloseParen,
+ ['['] = TokenKind.OpenBracket,
+ [']'] = TokenKind.CloseBracket,
+ ['.'] = TokenKind.Period,
+ [','] = TokenKind.Comma,
+ [':'] = TokenKind.Colon,
+ ['-'] = TokenKind.Minus
+ }.AsReadOnly();
+
+ internal static readonly IReadOnlyDictionary TokenKindToSingleCharacterLookup =
+ SingleCharacterToTokenKinds.ToDictionary(pair => pair.Value, pair => pair.Key).AsReadOnly();
private readonly string _source;
private readonly StringBuilder _textBuffer = new();
diff --git a/src/JsonApiDotNetCore/Serialization/Response/FingerprintGenerator.cs b/src/JsonApiDotNetCore/Serialization/Response/FingerprintGenerator.cs
index 61f3349df3..4a0650b035 100644
--- a/src/JsonApiDotNetCore/Serialization/Response/FingerprintGenerator.cs
+++ b/src/JsonApiDotNetCore/Serialization/Response/FingerprintGenerator.cs
@@ -7,13 +7,6 @@ namespace JsonApiDotNetCore.Serialization.Response;
internal sealed class FingerprintGenerator : IFingerprintGenerator
{
private static readonly byte[] Separator = "|"u8.ToArray();
- private static readonly uint[] LookupTable = Enumerable.Range(0, 256).Select(ToLookupEntry).ToArray();
-
- private static uint ToLookupEntry(int index)
- {
- string hex = index.ToString("X2");
- return hex[0] + ((uint)hex[1] << 16);
- }
///
public string Generate(IEnumerable elements)
@@ -30,22 +23,6 @@ public string Generate(IEnumerable elements)
}
byte[] hash = hasher.GetHashAndReset();
- return ByteArrayToHex(hash);
- }
-
- private static string ByteArrayToHex(byte[] bytes)
- {
- // https://stackoverflow.com/questions/311165/how-do-you-convert-a-byte-array-to-a-hexadecimal-string-and-vice-versa
-
- char[] buffer = new char[bytes.Length * 2];
-
- for (int index = 0; index < bytes.Length; index++)
- {
- uint value = LookupTable[bytes[index]];
- buffer[2 * index] = (char)value;
- buffer[2 * index + 1] = (char)(value >> 16);
- }
-
- return new string(buffer);
+ return Convert.ToHexString(hash);
}
}
diff --git a/src/JsonApiDotNetCore/Serialization/Response/JsonApiWriter.cs b/src/JsonApiDotNetCore/Serialization/Response/JsonApiWriter.cs
index 67bb61213b..66dcaedf29 100644
--- a/src/JsonApiDotNetCore/Serialization/Response/JsonApiWriter.cs
+++ b/src/JsonApiDotNetCore/Serialization/Response/JsonApiWriter.cs
@@ -118,7 +118,7 @@ private static bool CanWriteBody(HttpStatusCode statusCode)
private static bool IsSuccessStatusCode(HttpStatusCode statusCode)
{
- return new HttpResponseMessage(statusCode).IsSuccessStatusCode;
+ return (int)statusCode is >= 200 and <= 299;
}
private string RenderModel(object? model)
diff --git a/src/JsonApiDotNetCore/Serialization/Response/ResourceObjectTreeNode.cs b/src/JsonApiDotNetCore/Serialization/Response/ResourceObjectTreeNode.cs
index 7417adc6ff..c18eecd8b7 100644
--- a/src/JsonApiDotNetCore/Serialization/Response/ResourceObjectTreeNode.cs
+++ b/src/JsonApiDotNetCore/Serialization/Response/ResourceObjectTreeNode.cs
@@ -184,11 +184,11 @@ public IList GetResponseIncluded()
HashSet primaryResourceObjectSet = GetDirectChildren().Select(node => node.ResourceObject).ToHashSet(ResourceObjectComparer.Instance);
List includes = [];
- foreach (ResourceObject include in visited.Select(node => node.ResourceObject))
+ foreach (ResourceObjectTreeNode include in visited)
{
- if (!primaryResourceObjectSet.Contains(include))
+ if (!primaryResourceObjectSet.Contains(include.ResourceObject))
{
- includes.Add(include);
+ includes.Add(include.ResourceObject);
}
}