Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Remove default collection initialization for perf reasons #2284

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e0f3773
feat: use lazy get for collection initialization to reduce resource a…
MaggieKimani1 Mar 24, 2025
3b370e5
chore: use Lazy<T> pattern; preserve null values
MaggieKimani1 Mar 25, 2025
ef7a150
chore: replicate for collections in other components
MaggieKimani1 Mar 25, 2025
205e6a1
chore: remove unnecessary usings
MaggieKimani1 Mar 25, 2025
915e747
fix: revert lazy initialization; remove collection initialization
MaggieKimani1 Mar 26, 2025
0a65a54
chore: initialize collections to prevent NREs
MaggieKimani1 Mar 26, 2025
00e0913
chore: fix failing tests
MaggieKimani1 Mar 26, 2025
0921b0d
chore: merge remote-tracking branch 'origin/feat/memory-perf-improvem…
MaggieKimani1 Mar 26, 2025
796d49c
chore: revert changes
MaggieKimani1 Mar 26, 2025
08cc754
chore: merge main into current branch
MaggieKimani1 Apr 1, 2025
6fff3c5
chore: remove default collection initialization across all models; cl…
MaggieKimani1 Apr 1, 2025
1fa4647
chore: merge main into current branch
MaggieKimani1 Apr 2, 2025
4e97803
chore: clean up code; initialize collections where applicable
MaggieKimani1 Apr 3, 2025
eabd01d
chore: more cleanup
MaggieKimani1 Apr 3, 2025
c035940
chore: move assignment within the condition
MaggieKimani1 Apr 3, 2025
a28aa21
chore: replace interface with concrete type
MaggieKimani1 Apr 6, 2025
5686de4
chore: simplify collection initialization
MaggieKimani1 Apr 7, 2025
ccfeab1
Update src/Microsoft.OpenApi/Models/OpenApiPathItem.cs
MaggieKimani1 Apr 7, 2025
ad46bdb
chore: implement PR feedback
MaggieKimani1 Apr 7, 2025
d12efaf
chore: pull changes in remote branch
MaggieKimani1 Apr 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ var document = new OpenApiDocument
{
["/pets"] = new OpenApiPathItem
{
Operations = new Dictionary<HttpMethod, OpenApiOperation>
Operations = new()
{
[HttpMethod.Get] = new OpenApiOperation
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ internal static class OpenApiExtensibleExtensions
/// <param name="extensions">A dictionary of <see cref="IOpenApiExtension"/>.</param>
/// <param name="extensionKey">The key corresponding to the <see cref="IOpenApiExtension"/>.</param>
/// <returns>A <see cref="string"/> value matching the provided extensionKey. Return null when extensionKey is not found. </returns>
internal static string GetExtension(this IDictionary<string, IOpenApiExtension> extensions, string extensionKey)
internal static string GetExtension(this Dictionary<string, IOpenApiExtension> extensions, string extensionKey)
{
if (extensions.TryGetValue(extensionKey, out var value) && value is OpenApiAny { Node: JsonValue castValue } && castValue.TryGetValue<string>(out var stringValue))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static bool IsEquals(this string? target, string? searchValue, StringComp
/// <param name="target">The target string to split by char. </param>
/// <param name="separator">The char separator.</param>
/// <returns>An <see cref="IList{String}"/> containing substrings.</returns>
public static IList<string> SplitByChar(this string target, char separator)
public static List<string> SplitByChar(this string target, char separator)
{
if (string.IsNullOrWhiteSpace(target))
{
Expand Down
10 changes: 5 additions & 5 deletions src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public override void Visit(OpenApiOperation operation)
// Order matters. Resolve operationId.
operationId = RemoveHashSuffix(operationId);
if (operationTypeExtension.IsEquals("action") || operationTypeExtension.IsEquals("function"))
operationId = RemoveKeyTypeSegment(operationId, operation.Parameters ?? new List<IOpenApiParameter>());
operationId = RemoveKeyTypeSegment(operationId, operation.Parameters ?? []);
operationId = SingularizeAndDeduplicateOperationId(operationId.SplitByChar('.'));
operationId = ResolveODataCastOperationId(operationId);
operationId = ResolveByRefOperationId(operationId);
Expand Down Expand Up @@ -119,7 +119,7 @@ private static string ResolveODataCastOperationId(string operationId)
return match.Success ? $"{match.Groups[1]}{match.Groups[2]}" : operationId;
}

private static string SingularizeAndDeduplicateOperationId(IList<string> operationIdSegments)
private static string SingularizeAndDeduplicateOperationId(List<string> operationIdSegments)
{
var segmentsCount = operationIdSegments.Count;
var lastSegmentIndex = segmentsCount - 1;
Expand All @@ -145,7 +145,7 @@ private static string RemoveHashSuffix(string operationId)
return s_hashSuffixRegex.Match(operationId).Value;
}

private static string RemoveKeyTypeSegment(string operationId, IList<IOpenApiParameter> parameters)
private static string RemoveKeyTypeSegment(string operationId, List<IOpenApiParameter> parameters)
{
var segments = operationId.SplitByChar('.');
foreach (var parameter in parameters)
Expand All @@ -159,9 +159,9 @@ private static string RemoveKeyTypeSegment(string operationId, IList<IOpenApiPar
return string.Join('.', segments);
}

private static void ResolveFunctionParameters(IList<IOpenApiParameter> parameters)
private static void ResolveFunctionParameters(List<IOpenApiParameter> parameters)
{
foreach (var parameter in parameters.OfType<OpenApiParameter>().Where(static p => p.Content?.Any() ?? false))
foreach (var parameter in parameters.OfType<OpenApiParameter>().Where(static p => p.Content?.Count > 0))
{
// Replace content with a schema object of type array
// for structured or collection-valued function parameters
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi.Hidi/StatsVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public override void Visit(IOpenApiSchema schema)

public int HeaderCount { get; set; }

public override void Visit(IDictionary<string, IOpenApiHeader> headers)
public override void Visit(Dictionary<string, IOpenApiHeader> headers)
{
HeaderCount++;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi.Workbench/StatsVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public override void Visit(IOpenApiSchema schema)

public int HeaderCount { get; set; }

public override void Visit(IDictionary<string, IOpenApiHeader> headers)
public override void Visit(Dictionary<string, IOpenApiHeader> headers)
{
HeaderCount++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT license.

using System;
using System.Collections.Generic;
using Microsoft.OpenApi.Exceptions;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
Expand Down Expand Up @@ -32,10 +33,8 @@ public static void AddExtension<T>(this T element, string name, IOpenApiExtensio
throw new OpenApiException(string.Format(SRResource.ExtensionFieldNameMustBeginWithXDash, name));
}

if (element.Extensions is not null)
{
element.Extensions[name] = Utils.CheckArgumentNull(any);
}
element.Extensions ??= [];
element.Extensions[name] = Utils.CheckArgumentNull(any);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public static class OpenApiServerExtensions
/// 1. A substitution has no valid value in both the supplied dictionary and the default
/// 2. A substitution's value is not available in the enum provided
/// </exception>
public static string? ReplaceServerUrlVariables(this OpenApiServer server, IDictionary<string, string>? values = null)
public static string? ReplaceServerUrlVariables(this OpenApiServer server, Dictionary<string, string>? values = null)
{
var parsedUrl = server.Url;
if (server.Variables is not null && parsedUrl is not null)
Expand Down
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi/Interfaces/IMetadataContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ public interface IMetadataContainer
/// <summary>
/// A collection of properties associated with the current OpenAPI element.
/// </summary>
IDictionary<string, object>? Metadata { get; set; }
Dictionary<string, object>? Metadata { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi/Interfaces/IOpenApiExtensible.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ public interface IOpenApiExtensible : IOpenApiElement
/// <summary>
/// Specification extensions.
/// </summary>
IDictionary<string, IOpenApiExtension>? Extensions { get; set; }
Dictionary<string, IOpenApiExtension>? Extensions { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ public interface IOpenApiReadOnlyExtensible
/// <summary>
/// Specification extensions.
/// </summary>
IDictionary<string, IOpenApiExtension>? Extensions { get; }
Dictionary<string, IOpenApiExtension>? Extensions { get; }

}
4 changes: 2 additions & 2 deletions src/Microsoft.OpenApi/Models/Interfaces/IOpenApiHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ public interface IOpenApiHeader : IOpenApiDescribedElement, IOpenApiReadOnlyExte
/// <summary>
/// Examples of the media type.
/// </summary>
public IDictionary<string, IOpenApiExample>? Examples { get; }
public Dictionary<string, IOpenApiExample>? Examples { get; }

/// <summary>
/// A map containing the representations for the header.
/// </summary>
public IDictionary<string, OpenApiMediaType>? Content { get; }
public Dictionary<string, OpenApiMediaType>? Content { get; }

}
2 changes: 1 addition & 1 deletion src/Microsoft.OpenApi/Models/Interfaces/IOpenApiLink.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public interface IOpenApiLink : IOpenApiDescribedElement, IOpenApiReadOnlyExtens
/// <summary>
/// A map representing parameters to pass to an operation as specified with operationId or identified via operationRef.
/// </summary>
public IDictionary<string, RuntimeExpressionAnyWrapper>? Parameters { get; }
public Dictionary<string, RuntimeExpressionAnyWrapper>? Parameters { get; }

/// <summary>
/// A literal value or {expression} to use as a request body when calling the target operation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public interface IOpenApiParameter : IOpenApiDescribedElement, IOpenApiReadOnlyE
/// Furthermore, if referencing a schema which contains an example,
/// the examples value SHALL override the example provided by the schema.
/// </summary>
public IDictionary<string, IOpenApiExample>? Examples { get; }
public Dictionary<string, IOpenApiExample>? Examples { get; }

/// <summary>
/// Example of the media type. The example SHOULD match the specified schema and encoding properties
Expand All @@ -102,5 +102,5 @@ public interface IOpenApiParameter : IOpenApiDescribedElement, IOpenApiReadOnlyE
/// When example or examples are provided in conjunction with the schema object,
/// the example MUST follow the prescribed serialization strategy for the parameter.
/// </summary>
public IDictionary<string, OpenApiMediaType>? Content { get; }
public Dictionary<string, OpenApiMediaType>? Content { get; }
}
6 changes: 3 additions & 3 deletions src/Microsoft.OpenApi/Models/Interfaces/IOpenApiPathItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ public interface IOpenApiPathItem : IOpenApiDescribedElement, IOpenApiSummarized
/// <summary>
/// Gets the definition of operations on this path.
/// </summary>
public IDictionary<HttpMethod, OpenApiOperation>? Operations { get; }
public Dictionary<HttpMethod, OpenApiOperation>? Operations { get; }

/// <summary>
/// An alternative server array to service all operations in this path.
/// </summary>
public IList<OpenApiServer>? Servers { get; }
public List<OpenApiServer>? Servers { get; }

/// <summary>
/// A list of parameters that are applicable for all the operations described under this path.
/// These parameters can be overridden at the operation level, but cannot be removed there.
/// </summary>
public IList<IOpenApiParameter>? Parameters { get; }
public List<IOpenApiParameter>? Parameters { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public interface IOpenApiRequestBody : IOpenApiDescribedElement, IOpenApiReadOnl
/// REQUIRED. The content of the request body. The key is a media type or media type range and the value describes it.
/// For requests that match multiple keys, only the most specific key is applicable. e.g. text/plain overrides text/*
/// </summary>
public IDictionary<string, OpenApiMediaType>? Content { get; }
public Dictionary<string, OpenApiMediaType>? Content { get; }
/// <summary>
/// Converts the request body to a body parameter in preparation for a v2 serialization.
/// </summary>
Expand Down
6 changes: 3 additions & 3 deletions src/Microsoft.OpenApi/Models/Interfaces/IOpenApiResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ public interface IOpenApiResponse : IOpenApiDescribedElement, IOpenApiReadOnlyEx
/// <summary>
/// Maps a header name to its definition.
/// </summary>
public IDictionary<string, IOpenApiHeader>? Headers { get; }
public Dictionary<string, IOpenApiHeader>? Headers { get; }

/// <summary>
/// A map containing descriptions of potential response payloads.
/// The key is a media type or media type range and the value describes it.
/// </summary>
public IDictionary<string, OpenApiMediaType>? Content { get; }
public Dictionary<string, OpenApiMediaType>? Content { get; }

/// <summary>
/// A map of operations links that can be followed from the response.
/// The key of the map is a short name for the link,
/// following the naming constraints of the names for Component Objects.
/// </summary>
public IDictionary<string, IOpenApiLink>? Links { get; }
public Dictionary<string, IOpenApiLink>? Links { get; }
}
26 changes: 13 additions & 13 deletions src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
/// <summary>
/// $vocabulary- used in meta-schemas to identify the vocabularies available for use in schemas described by that meta-schema.
/// </summary>
public IDictionary<string, bool>? Vocabulary { get; }
public Dictionary<string, bool>? Vocabulary { get; }

/// <summary>
/// $dynamicRef - an applicator that allows for deferring the full resolution until runtime, at which point it is resolved each time it is encountered while evaluating an instance
Expand All @@ -51,7 +51,7 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
/// $defs - reserves a location for schema authors to inline re-usable JSON Schemas into a more general schema.
/// The keyword does not directly affect the validation result
/// </summary>
public IDictionary<string, IOpenApiSchema>? Definitions { get; }
public Dictionary<string, IOpenApiSchema>? Definitions { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
Expand Down Expand Up @@ -144,19 +144,19 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
/// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema.
/// </summary>
public IList<IOpenApiSchema>? AllOf { get; }
public List<IOpenApiSchema>? AllOf { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
/// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema.
/// </summary>
public IList<IOpenApiSchema>? OneOf { get; }
public List<IOpenApiSchema>? OneOf { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
/// Inline or referenced schema MUST be of a Schema Object and not a standard JSON Schema.
/// </summary>
public IList<IOpenApiSchema>? AnyOf { get; }
public List<IOpenApiSchema>? AnyOf { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
Expand All @@ -167,7 +167,7 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
/// </summary>
public ISet<string>? Required { get; }
public HashSet<string>? Required { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
Expand Down Expand Up @@ -195,7 +195,7 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
/// Property definitions MUST be a Schema Object and not a standard JSON Schema (inline or referenced).
/// </summary>
public IDictionary<string, IOpenApiSchema>? Properties { get; }
public Dictionary<string, IOpenApiSchema>? Properties { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
Expand All @@ -204,7 +204,7 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
/// egular expression dialect. Each property value of this object MUST be an object, and each object MUST
/// be a valid Schema Object not a standard JSON Schema.
/// </summary>
public IDictionary<string, IOpenApiSchema>? PatternProperties { get; }
public Dictionary<string, IOpenApiSchema>? PatternProperties { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
Expand Down Expand Up @@ -246,12 +246,12 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
/// To represent examples that cannot be naturally represented in JSON or YAML,
/// a list of values can be used to contain the examples with escaping where necessary.
/// </summary>
public IList<JsonNode>? Examples { get; }
public List<JsonNode>? Examples { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
/// </summary>
public IList<JsonNode>? Enum { get; }
public List<JsonNode>? Enum { get; }

/// <summary>
/// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00
Expand All @@ -278,16 +278,16 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiReadOnlyExte
/// <summary>
/// This object stores any unrecognized keywords found in the schema.
/// </summary>
public IDictionary<string, JsonNode>? UnrecognizedKeywords { get; }
public Dictionary<string, JsonNode>? UnrecognizedKeywords { get; }

/// <summary>
/// Any annotation to attach to the schema to be used by the application.
/// Annotations are NOT (de)serialized with the schema and can be used for custom properties.
/// </summary>
public IDictionary<string, object>? Annotations { get; }
public Dictionary<string, object>? Annotations { get; }

/// <summary>
/// Follow JSON Schema definition:https://json-schema.org/draft/2020-12/json-schema-validation#section-6.5.4
/// </summary>
public IDictionary<string, ISet<string>>? DependentRequired { get; }
public Dictionary<string, HashSet<string>>? DependentRequired { get; }
}
5 changes: 2 additions & 3 deletions src/Microsoft.OpenApi/Models/OpenApiCallback.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,16 @@ namespace Microsoft.OpenApi.Models
/// <summary>
/// Callback Object: A map of possible out-of band callbacks related to the parent operation.
/// </summary>
public class OpenApiCallback : IOpenApiReferenceable, IOpenApiExtensible, IOpenApiCallback
public class OpenApiCallback : IOpenApiExtensible, IOpenApiCallback
{
/// <inheritdoc/>
public Dictionary<RuntimeExpression, IOpenApiPathItem>? PathItems { get; set; }
= [];


/// <summary>
/// This object MAY be extended with Specification Extensions.
/// </summary>
public IDictionary<string, IOpenApiExtension>? Extensions { get; set; } = new Dictionary<string, IOpenApiExtension>();
public Dictionary<string, IOpenApiExtension>? Extensions { get; set; }

/// <summary>
/// Parameter-less constructor
Expand Down
Loading