< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 43
Coverable lines: 43
Total lines: 95
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 47
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%110%
Equals(...)100%110%
Equals(...)0%220%
GetHashCode()100%110%
Equals(...)0%660%
GetKey(...)0%39390%

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/PropertyRef.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Diagnostics;
 5using System.Runtime.CompilerServices;
 6using System.Runtime.InteropServices;
 7
 8namespace System.Text.Json.Serialization.Metadata
 9{
 10    /// <summary>
 11    /// Represents a UTF-8 encoded JSON property name and its associated <see cref="JsonPropertyInfo"/>, if available.
 12    /// PropertyRefs use byte sequence equality, so equal JSON strings with alternate encodings or casings are not equal
 13    /// Used as a first-level cache for property lookups before falling back to UTF decoding and string comparison.
 14    /// </summary>
 15    internal readonly struct PropertyRef(ulong key, JsonPropertyInfo? info, byte[] utf8PropertyName) : IEquatable<Proper
 16    {
 17        // The length of the property name embedded in the key (in bytes).
 18        // The key is a ulong (8 bytes) containing the first 7 bytes of the property name
 19        // followed by a byte representing the length.
 20        private const int PropertyNameKeyLength = 7;
 21
 22        /// <summary>
 23        /// A custom hashcode produced from the UTF-8 encoded property name.
 24        /// </summary>
 025        public readonly ulong Key = key;
 26
 27        /// <summary>
 28        /// The <see cref="JsonPropertyInfo"/> associated with the property name, if available.
 29        /// </summary>
 030        public readonly JsonPropertyInfo? Info = info;
 31
 32        /// <summary>
 33        /// Caches a heap allocated copy of the UTF-8 encoded property name.
 34        /// </summary>
 035        public readonly byte[] Utf8PropertyName = utf8PropertyName;
 36
 037        public bool Equals(PropertyRef other) => Equals(other.Utf8PropertyName, other.Key);
 038        public override bool Equals(object? obj) => obj is PropertyRef other && Equals(other);
 039        public override int GetHashCode() => Key.GetHashCode();
 40
 41        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 42        public bool Equals(ReadOnlySpan<byte> propertyName, ulong key)
 043        {
 44            // If both property names are less than 8 bytes, they are embedded in the key so no further comparison is ne
 045            return key == Key &&
 046                ((propertyName.Length <= PropertyNameKeyLength && Utf8PropertyName.Length <= PropertyNameKeyLength)
 047                    || propertyName.SequenceEqual(Utf8PropertyName));
 048        }
 49
 50        /// <summary>
 51        /// Get a key from the property name.
 52        /// The key consists of the first 7 bytes of the property name and then the least significant bits of the length
 53        /// </summary>
 54        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 55        public static ulong GetKey(ReadOnlySpan<byte> name)
 056        {
 057            int length = name.Length;
 058            ulong key = (ulong)(byte)length << 56;
 059            key |= length switch
 060            {
 061                0 => 0,
 062                1 => name[0],
 063                2 => BitConverter.ToUInt16(name),
 064                3 => BitConverter.ToUInt16(name) | ((ulong)name[2] << 16),
 065                4 => BitConverter.ToUInt32(name),
 066                5 => BitConverter.ToUInt32(name) | ((ulong)name[4] << 32),
 067                6 => BitConverter.ToUInt32(name) | ((ulong)BitConverter.ToUInt16(name.Slice(4, 2)) << 32),
 068                7 => BitConverter.ToUInt32(name) | ((ulong)BitConverter.ToUInt16(name.Slice(4, 2)) << 32) | ((ulong)name
 069                _ => BitConverter.ToUInt64(name) & 0x00ffffffffffffffUL
 070            };
 71#if DEBUG
 72            // Verify key contains the embedded bytes as expected.
 73            // Note: the expected properties do not hold true on big-endian platforms
 074            if (BitConverter.IsLittleEndian)
 075            {
 76                const int BitsInByte = 8;
 077                Debug.Assert(
 078                    // Verify embedded property name.
 079                    (name.Length < 1 || name[0] == ((key & ((ulong)0xFF << BitsInByte * 0)) >> BitsInByte * 0)) &&
 080                    (name.Length < 2 || name[1] == ((key & ((ulong)0xFF << BitsInByte * 1)) >> BitsInByte * 1)) &&
 081                    (name.Length < 3 || name[2] == ((key & ((ulong)0xFF << BitsInByte * 2)) >> BitsInByte * 2)) &&
 082                    (name.Length < 4 || name[3] == ((key & ((ulong)0xFF << BitsInByte * 3)) >> BitsInByte * 3)) &&
 083                    (name.Length < 5 || name[4] == ((key & ((ulong)0xFF << BitsInByte * 4)) >> BitsInByte * 4)) &&
 084                    (name.Length < 6 || name[5] == ((key & ((ulong)0xFF << BitsInByte * 5)) >> BitsInByte * 5)) &&
 085                    (name.Length < 7 || name[6] == ((key & ((ulong)0xFF << BitsInByte * 6)) >> BitsInByte * 6)) &&
 086                    // Verify embedded length.
 087                    (key & ((ulong)0xFF << BitsInByte * 7)) >> BitsInByte * 7 == (byte)name.Length,
 088                    "Embedded bytes not as expected");
 089            }
 90#endif
 091            return key;
 092        }
 93    }
 94}
 95