Skip to content

Commit

Permalink
Merge pull request #492 from gregsdennis/pointer/allocations
Browse files Browse the repository at this point in the history
Pointer/allocations
  • Loading branch information
gregsdennis committed Jul 23, 2023
2 parents 580ac56 + 9bb2bc3 commit 091d170
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 28 deletions.
33 changes: 21 additions & 12 deletions JsonPointer/JsonPointer.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
Expand Down Expand Up @@ -30,7 +31,9 @@ public class JsonPointer : IEquatable<JsonPointer>
/// </summary>
public PointerSegment[] Segments { get; private set; } = null!;

#pragma warning disable CS8618
private JsonPointer() { }
#pragma warning restore CS8618

/// <summary>
/// Parses a JSON Pointer from a string.
Expand Down Expand Up @@ -129,7 +132,7 @@ public static JsonPointer Create(params PointerSegment[] segments)
{
return new JsonPointer
{
Segments = segments.ToArray()
Segments = segments
};
}

Expand Down Expand Up @@ -334,17 +337,20 @@ public bool TryEvaluate(JsonNode? root, out JsonNode? result)
/// <returns>The string representation.</returns>
public string ToString(JsonPointerStyle pointerStyle)
{
var sb = new StringBuilder();
if (pointerStyle == JsonPointerStyle.UriEncoded)
sb.Append("#");

foreach (var segment in Segments)
string BuildString(StringBuilder sb)
{
sb.Append("/");
sb.Append(segment.ToString(pointerStyle));
foreach (var segment in Segments)
{
sb.Append("/");
sb.Append(segment.ToString(pointerStyle));
}

return sb.ToString();
}

return sb.ToString();
return BuildString(pointerStyle != JsonPointerStyle.UriEncoded
? new StringBuilder()
: new StringBuilder("#"));
}

/// <summary>Returns the string representation of this instance.</summary>
Expand All @@ -357,17 +363,20 @@ public override string ToString()
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns>true if the current object is equal to the <paramref name="other">other</paramref> parameter; otherwise, false.</returns>
public bool Equals(JsonPointer other)
public bool Equals(JsonPointer? other)
{
if (other is null) return false;
if (ReferenceEquals(this, other)) return true;

return Segments.SequenceEqual(other.Segments);
}

/// <summary>Indicates whether this instance and a specified object are equal.</summary>
/// <param name="obj">The object to compare with the current instance.</param>
/// <returns>true if <paramref name="obj">obj</paramref> and this instance are the same type and represent the same value; otherwise, false.</returns>
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is JsonPointer other && Equals(other);
return Equals(obj as JsonPointer);
}

/// <summary>Returns the hash code for this instance.</summary>
Expand Down
4 changes: 2 additions & 2 deletions JsonPointer/JsonPointer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>latest</LangVersion>
<RootNamespace>Json.Pointer</RootNamespace>
<Version>3.0.1</Version>
<Version>3.0.2</Version>
<AssemblyVersion>3.0.0.0</AssemblyVersion>
<FileVersion>3.0.1.0</FileVersion>
<FileVersion>3.0.2.0</FileVersion>
<PackageId>JsonPointer.Net</PackageId>
<Authors>Greg Dennis</Authors>
<Product>JsonPointer.Net</Product>
Expand Down
39 changes: 25 additions & 14 deletions JsonPointer/PointerSegment.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Text;
using System.Web;

Expand All @@ -9,13 +10,15 @@ namespace Json.Pointer;
/// </summary>
public class PointerSegment : IEquatable<PointerSegment>
{
private string? _source;

/// <summary>
/// Gets the segment value.
/// </summary>
public string Value { get; private set; }

#pragma warning disable CS8618
private PointerSegment() { }
private PointerSegment(){}
#pragma warning restore CS8618

/// <summary>
Expand All @@ -31,6 +34,7 @@ public static PointerSegment Parse(string? source)

return new PointerSegment
{
_source = source,
Value = Decode(source)
};
}
Expand All @@ -53,6 +57,7 @@ public static bool TryParse(string? source, out PointerSegment? segment)
{
segment = new PointerSegment
{
_source = source,
Value = Decode(source)
};
return true;
Expand Down Expand Up @@ -81,9 +86,10 @@ public static PointerSegment Create(string value)

private static string Encode(string value)
{
if (value.All(c => c is not ('~' or '/'))) return value;

var builder = new StringBuilder();
var chars = value.AsSpan();
foreach (var ch in chars)
foreach (var ch in value)
{
switch (ch)
{
Expand All @@ -104,15 +110,16 @@ private static string Encode(string value)

private static string Decode(string source)
{
if (source.All(c => c is not '~')) return source;

var builder = new StringBuilder();
var span = source.AsSpan();
for (int i = 0; i < span.Length; i++)
for (int i = 0; i < source.Length; i++)
{
if (span[i] == '~')
if (source[i] == '~')
{
if (i >= span.Length - 1) throw new PointerParseException("Segment cannot end with `~`");
if (i >= source.Length - 1) throw new PointerParseException("Segment cannot end with `~`");

switch (span[i + 1])
switch (source[i + 1])
{
case '0':
builder.Append('~');
Expand All @@ -123,13 +130,13 @@ private static string Decode(string source)
i++;
break;
default:
throw new PointerParseException($"Invalid escape sequence: `~{span[i + 1]}`");
throw new PointerParseException($"Invalid escape sequence: `~{source[i + 1]}`");
}

continue;
}

builder.Append(span[i]);
builder.Append(source[i]);
}

return builder.ToString();
Expand All @@ -140,7 +147,8 @@ private static string Decode(string source)
/// <returns>The string representation.</returns>
public string ToString(JsonPointerStyle pointerStyle)
{
var str = Encode(Value);
_source ??= Encode(Value);
var str = _source;

if (pointerStyle == JsonPointerStyle.UriEncoded)
str = HttpUtility.UrlEncode(str);
Expand All @@ -153,15 +161,18 @@ public string ToString(JsonPointerStyle pointerStyle)
/// <returns>true if the current object is equal to the <paramref name="other">other</paramref> parameter; otherwise, false.</returns>
public bool Equals(PointerSegment? other)
{
return string.Equals(Value, other?.Value, StringComparison.InvariantCulture);
if (other is null) return false;
if (ReferenceEquals(this, other)) return true;

return string.Equals(Value, other.Value, StringComparison.InvariantCulture);
}

/// <summary>Indicates whether this instance and a specified object are equal.</summary>
/// <param name="obj">The object to compare with the current instance.</param>
/// <returns>true if <paramref name="obj">obj</paramref> and this instance are the same type and represent the same value; otherwise, false.</returns>
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is PointerSegment other && Equals(other);
return Equals(obj as PointerSegment);
}

/// <summary>Returns the hash code for this instance.</summary>
Expand Down
4 changes: 4 additions & 0 deletions tools/ApiDocsGenerator/release-notes/rn-json-pointer.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ title: JsonPointer.Net
icon: fas fa-tag
order: "8.09"
---
# [3.0.2](https://github.com/gregsdennis/json-everything/pull/492) {#release-pointer-3.0.2}

Memory and performance improvements.

# [3.0.1](https://github.com/gregsdennis/json-everything/pull/425) {#release-pointer-3.0.1}

[#408](https://github.com/gregsdennis/json-everything/issues/408) - Fixed an issue where an empty string segment fails for array values. Thanks to [@mbj2011](https://github.com/mbj2011) for finding and reporting this.
Expand Down

0 comments on commit 091d170

Please sign in to comment.