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); }
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); }
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); }
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); }
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); }