Example #1
0
        private JsonPropertyInfo GetPropertyThatHasAttribute(Type attributeType)
        {
            Debug.Assert(_propertyRefs != null);

            JsonPropertyInfo property = null;

            for (int iProperty = 0; iProperty < _propertyRefs.Count; iProperty++)
            {
                PropertyRef      propertyRef      = _propertyRefs[iProperty];
                JsonPropertyInfo jsonPropertyInfo = propertyRef.Info;
                Attribute        attribute        = jsonPropertyInfo.PropertyInfo.GetCustomAttribute(attributeType);
                if (attribute != null)
                {
                    if (property != null)
                    {
                        ThrowHelper.ThrowInvalidOperationException_SerializationDuplicateTypeAttribute(Type, attributeType);
                    }

                    property = jsonPropertyInfo;
                }
            }

            return(property);
        }
Example #2
0
        public JsonPropertyInfo GetProperty(ReadOnlySpan <byte> propertyName, ref ReadStackFrame frame)
        {
            JsonPropertyInfo info = null;

            // Keep a local copy of the cache in case it changes by another thread.
            PropertyRef[] localPropertyRefsSorted = _propertyRefsSorted;

            ulong key = GetKey(propertyName);

            // If there is an existing cache, then use it.
            if (localPropertyRefsSorted != null)
            {
                // Start with the current property index, and then go forwards\backwards.
                int propertyIndex = frame.PropertyIndex;

                int count     = localPropertyRefsSorted.Length;
                int iForward  = Math.Min(propertyIndex, count);
                int iBackward = iForward - 1;

                while (true)
                {
                    if (iForward < count)
                    {
                        PropertyRef propertyRef = localPropertyRefsSorted[iForward];
                        if (TryIsPropertyRefEqual(propertyRef, propertyName, key, ref info))
                        {
                            return(info);
                        }

                        ++iForward;

                        if (iBackward >= 0)
                        {
                            propertyRef = localPropertyRefsSorted[iBackward];
                            if (TryIsPropertyRefEqual(propertyRef, propertyName, key, ref info))
                            {
                                return(info);
                            }

                            --iBackward;
                        }
                    }
                    else if (iBackward >= 0)
                    {
                        PropertyRef propertyRef = localPropertyRefsSorted[iBackward];
                        if (TryIsPropertyRefEqual(propertyRef, propertyName, key, ref info))
                        {
                            return(info);
                        }

                        --iBackward;
                    }
                    else
                    {
                        // Property was not found.
                        break;
                    }
                }
            }

            // No cached item was found. Try the main list which has all of the properties.

            string stringPropertyName = JsonHelpers.Utf8GetString(propertyName);

            if (!PropertyCache.TryGetValue(stringPropertyName, out info))
            {
                info = JsonPropertyInfo.s_missingProperty;
            }

            Debug.Assert(info != null);

            // Three code paths to get here:
            // 1) info == s_missingProperty. Property not found.
            // 2) key == info.PropertyNameKey. Exact match found.
            // 3) key != info.PropertyNameKey. Match found due to case insensitivity.
            Debug.Assert(info == JsonPropertyInfo.s_missingProperty || key == info.PropertyNameKey || Options.PropertyNameCaseInsensitive);

            // Check if we should add this to the cache.
            // Only cache up to a threshold length and then just use the dictionary when an item is not found in the cache.
            int cacheCount = 0;

            if (localPropertyRefsSorted != null)
            {
                cacheCount = localPropertyRefsSorted.Length;
            }

            // Do a quick check for the stable (after warm-up) case.
            if (cacheCount < PropertyNameCountCacheThreshold)
            {
                // Do a slower check for the warm-up case.
                if (frame.PropertyRefCache != null)
                {
                    cacheCount += frame.PropertyRefCache.Count;
                }

                // Check again to append the cache up to the threshold.
                if (cacheCount < PropertyNameCountCacheThreshold)
                {
                    if (frame.PropertyRefCache == null)
                    {
                        frame.PropertyRefCache = new List <PropertyRef>();
                    }

                    PropertyRef propertyRef = new PropertyRef(key, info);
                    frame.PropertyRefCache.Add(propertyRef);
                }
            }

            return(info);
        }
        public JsonPropertyInfo GetProperty(
            ReadOnlySpan <byte> propertyName,
            ref ReadStackFrame frame,
            out byte[] utf8PropertyName)
        {
            PropertyRef propertyRef;

            ulong key = GetKey(propertyName);

            // Keep a local copy of the cache in case it changes by another thread.
            PropertyRef[]? localPropertyRefsSorted = _propertyRefsSorted;

            // If there is an existing cache, then use it.
            if (localPropertyRefsSorted != null)
            {
                // Start with the current property index, and then go forwards\backwards.
                int propertyIndex = frame.PropertyIndex;

                int count     = localPropertyRefsSorted.Length;
                int iForward  = Math.Min(propertyIndex, count);
                int iBackward = iForward - 1;

                while (true)
                {
                    if (iForward < count)
                    {
                        propertyRef = localPropertyRefsSorted[iForward];
                        if (IsPropertyRefEqual(propertyRef, propertyName, key))
                        {
                            utf8PropertyName = propertyRef.NameFromJson;
                            return(propertyRef.Info);
                        }

                        ++iForward;

                        if (iBackward >= 0)
                        {
                            propertyRef = localPropertyRefsSorted[iBackward];
                            if (IsPropertyRefEqual(propertyRef, propertyName, key))
                            {
                                utf8PropertyName = propertyRef.NameFromJson;
                                return(propertyRef.Info);
                            }

                            --iBackward;
                        }
                    }
                    else if (iBackward >= 0)
                    {
                        propertyRef = localPropertyRefsSorted[iBackward];
                        if (IsPropertyRefEqual(propertyRef, propertyName, key))
                        {
                            utf8PropertyName = propertyRef.NameFromJson;
                            return(propertyRef.Info);
                        }

                        --iBackward;
                    }
                    else
                    {
                        // Property was not found.
                        break;
                    }
                }
            }

            // No cached item was found. Try the main dictionary which has all of the properties.
            Debug.Assert(PropertyCache != null);

            if (PropertyCache.TryGetValue(JsonHelpers.Utf8GetString(propertyName), out JsonPropertyInfo? info))
            {
                if (Options.PropertyNameCaseInsensitive)
                {
                    if (propertyName.SequenceEqual(info.NameAsUtf8Bytes))
                    {
                        Debug.Assert(key == GetKey(info.NameAsUtf8Bytes.AsSpan()));

                        // Use the existing byte[] reference instead of creating another one.
                        utf8PropertyName = info.NameAsUtf8Bytes !;
                    }
                    else
                    {
                        // Make a copy of the original Span.
                        utf8PropertyName = propertyName.ToArray();
                    }
                }
                else
                {
                    Debug.Assert(key == GetKey(info.NameAsUtf8Bytes !.AsSpan()));
                    utf8PropertyName = info.NameAsUtf8Bytes !;
                }
            }
            else
            {
                info = JsonPropertyInfo.s_missingProperty;

                // Make a copy of the original Span.
                utf8PropertyName = propertyName.ToArray();
            }

            // Check if we should add this to the cache.
            // Only cache up to a threshold length and then just use the dictionary when an item is not found in the cache.
            int cacheCount = 0;

            if (localPropertyRefsSorted != null)
            {
                cacheCount = localPropertyRefsSorted.Length;
            }

            // Do a quick check for the stable (after warm-up) case.
            if (cacheCount < PropertyNameCountCacheThreshold)
            {
                // Do a slower check for the warm-up case.
                if (frame.PropertyRefCache != null)
                {
                    cacheCount += frame.PropertyRefCache.Count;
                }

                // Check again to append the cache up to the threshold.
                if (cacheCount < PropertyNameCountCacheThreshold)
                {
                    if (frame.PropertyRefCache == null)
                    {
                        frame.PropertyRefCache = new List <PropertyRef>();
                    }

                    Debug.Assert(info != null);

                    propertyRef = new PropertyRef(key, info, utf8PropertyName);
                    frame.PropertyRefCache.Add(propertyRef);
                }
            }

            return(info);
        }
Example #4
0
        internal JsonPropertyInfo GetProperty(ReadOnlySpan <byte> propertyName, ref ReadStackFrame frame)
        {
            JsonPropertyInfo info = null;

            // If we're not trying to build the cache locally, and there is an existing cache, then use it.
            if (_propertyRefsSorted != null)
            {
                ulong key = GetKey(propertyName);

                // First try sorted lookup.
                int propertyIndex = frame.PropertyIndex;

                // This .Length is consistent no matter what json data intialized _propertyRefsSorted.
                int count = _propertyRefsSorted.Length;
                if (count != 0)
                {
                    int iForward  = Math.Min(propertyIndex, count);
                    int iBackward = iForward - 1;
                    while (iForward < count || iBackward >= 0)
                    {
                        if (iForward < count)
                        {
                            if (TryIsPropertyRefEqual(_propertyRefsSorted[iForward], propertyName, key, ref info))
                            {
                                return(info);
                            }
                            ++iForward;
                        }

                        if (iBackward >= 0)
                        {
                            if (TryIsPropertyRefEqual(_propertyRefsSorted[iBackward], propertyName, key, ref info))
                            {
                                return(info);
                            }
                            --iBackward;
                        }
                    }
                }
            }

            // Try the main list which has all of the properties in a consistent order.
            // We could get here even when hasPropertyCache==true if there is a race condition with different json
            // property ordering and _propertyRefsSorted is re-assigned while in the loop above.

            string stringPropertyName = JsonHelpers.Utf8GetString(propertyName);

            if (PropertyCache.TryGetValue(stringPropertyName, out info))
            {
                // For performance, only add to cache up to a threshold and then just use the dictionary.
                int count;
                if (_propertyRefsSorted != null)
                {
                    count = _propertyRefsSorted.Length;
                }
                else
                {
                    count = 0;
                }

                // Do a quick check for the stable (after warm-up) case.
                if (count < PropertyNameCountCacheThreshold)
                {
                    if (frame.PropertyRefCache != null)
                    {
                        count += frame.PropertyRefCache.Count;
                    }

                    // Check again to fill up to the limit.
                    if (count < PropertyNameCountCacheThreshold)
                    {
                        if (frame.PropertyRefCache == null)
                        {
                            frame.PropertyRefCache = new List <PropertyRef>();
                        }

                        ulong       key         = info.PropertyNameKey;
                        PropertyRef propertyRef = new PropertyRef(key, info);
                        frame.PropertyRefCache.Add(propertyRef);
                    }
                }
            }

            return(info);
        }
Example #5
0
        public JsonPropertyInfo GetProperty(ReadOnlySpan <byte> propertyName, ref ReadStackFrame frame)
        {
            JsonPropertyInfo info = null;

            // Keep a local copy of the cache in case it changes by another thread.
            PropertyRef[] localPropertyRefsSorted = _propertyRefsSorted;

            // If there is an existing cache, then use it.
            if (localPropertyRefsSorted != null)
            {
                ulong key = GetKey(propertyName);

                // Start with the current property index, and then go forwards\backwards.
                int propertyIndex = frame.PropertyIndex;

                int count     = localPropertyRefsSorted.Length;
                int iForward  = Math.Min(propertyIndex, count);
                int iBackward = iForward - 1;

                while (iForward < count || iBackward >= 0)
                {
                    if (iForward < count)
                    {
                        if (TryIsPropertyRefEqual(localPropertyRefsSorted[iForward], propertyName, key, ref info))
                        {
                            return(info);
                        }
                        ++iForward;
                    }

                    if (iBackward >= 0)
                    {
                        if (TryIsPropertyRefEqual(localPropertyRefsSorted[iBackward], propertyName, key, ref info))
                        {
                            return(info);
                        }
                        --iBackward;
                    }
                }
            }

            // No cached item was found. Try the main list which has all of the properties.

            string stringPropertyName = JsonHelpers.Utf8GetString(propertyName);

            if (PropertyCache.TryGetValue(stringPropertyName, out info))
            {
                // Check if we should add this to the cache.
                // Only cache up to a threshold length and then just use the dictionary when an item is not found in the cache.
                int count;
                if (localPropertyRefsSorted != null)
                {
                    count = localPropertyRefsSorted.Length;
                }
                else
                {
                    count = 0;
                }

                // Do a quick check for the stable (after warm-up) case.
                if (count < PropertyNameCountCacheThreshold)
                {
                    // Do a slower check for the warm-up case.
                    if (frame.PropertyRefCache != null)
                    {
                        count += frame.PropertyRefCache.Count;
                    }

                    // Check again to append the cache up to the threshold.
                    if (count < PropertyNameCountCacheThreshold)
                    {
                        if (frame.PropertyRefCache == null)
                        {
                            frame.PropertyRefCache = new List <PropertyRef>();
                        }

                        ulong       key         = info.PropertyNameKey;
                        PropertyRef propertyRef = new PropertyRef(key, info);
                        frame.PropertyRefCache.Add(propertyRef);
                    }
                }
            }

            return(info);
        }
Example #6
0
        internal JsonPropertyInfo GetProperty(JsonSerializerOptions options, ReadOnlySpan <byte> propertyName, ref ReadStackFrame frame)
        {
            // If we should compare with case-insensitive, normalize to an uppercase format since that is what is cached on the propertyInfo.
            if (options.PropertyNameCaseInsensitive)
            {
                string utf16PropertyName = JsonHelpers.Utf8GetString(propertyName);
                string upper             = utf16PropertyName.ToUpperInvariant();
                propertyName = Encoding.UTF8.GetBytes(upper);
            }

            ulong            key  = GetKey(propertyName);
            JsonPropertyInfo info = null;

            // First try sorted lookup.
            int propertyIndex = frame.PropertyIndex;

            // If we're not trying to build the cache locally, and there is an existing cache, then use it.
            bool hasPropertyCache = frame.PropertyRefCache == null && _propertyRefsSorted != null;

            if (hasPropertyCache)
            {
                // This .Length is consistent no matter what json data intialized _propertyRefsSorted.
                int count = _propertyRefsSorted.Length;
                if (count != 0)
                {
                    int iForward  = propertyIndex;
                    int iBackward = propertyIndex - 1;
                    while (iForward < count || iBackward >= 0)
                    {
                        if (iForward < count)
                        {
                            if (TryIsPropertyRefEqual(ref _propertyRefsSorted[iForward], propertyName, key, ref info))
                            {
                                return(info);
                            }
                            ++iForward;
                        }

                        if (iBackward >= 0)
                        {
                            if (TryIsPropertyRefEqual(ref _propertyRefsSorted[iBackward], propertyName, key, ref info))
                            {
                                return(info);
                            }
                            --iBackward;
                        }
                    }
                }
            }

            // Try the main list which has all of the properties in a consistent order.
            // We could get here even when hasPropertyCache==true if there is a race condition with different json
            // property ordering and _propertyRefsSorted is re-assigned while in the loop above.
            for (int i = 0; i < _propertyRefs.Count; i++)
            {
                PropertyRef propertyRef = _propertyRefs[i];
                if (TryIsPropertyRefEqual(ref propertyRef, propertyName, key, ref info))
                {
                    break;
                }
            }

            if (!hasPropertyCache)
            {
                if (propertyIndex == 0 && frame.PropertyRefCache == null)
                {
                    // Create the temporary list on first property access to prevent a partially filled List.
                    frame.PropertyRefCache = new List <PropertyRef>();
                }

                if (info != null)
                {
                    Debug.Assert(frame.PropertyRefCache != null);
                    frame.PropertyRefCache.Add(new PropertyRef(key, info));
                }
            }

            return(info);
        }