Skip to content

Commit

Permalink
Revert "make factory struct"
Browse files Browse the repository at this point in the history
This reverts commit 37c39894c115ed73a69d9ef222e81974d948e9b8.
  • Loading branch information
twsouthwick committed Nov 27, 2024
1 parent d6e48cc commit be53c40
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,29 @@
using System;
using System.Diagnostics;

namespace DocumentFormat.OpenXml.Framework.Metadata;

[DebuggerDisplay("{QName,nq}")]
internal readonly struct ElementFactory(OpenXmlSchemaType type, Func<OpenXmlElement> factory)
namespace DocumentFormat.OpenXml.Framework.Metadata
{
public OpenXmlSchemaType Type => type;
[DebuggerDisplay("{QName,nq}")]
internal sealed class ElementFactory
{
private readonly Func<OpenXmlElement> _factory;

public ElementFactory(in OpenXmlSchemaType type, Func<OpenXmlElement> factory)
{
Type = type;
_factory = factory;
}

public OpenXmlSchemaType Type { get; }

public OpenXmlElement Create() => _factory();

public static ElementFactory Create<T>()
where T : OpenXmlElement, new()
{
var instance = new T();

public OpenXmlElement Create() => factory();
return new ElementFactory(instance.Metadata.Type, static () => new T());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,49 +1,81 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Linq;

namespace DocumentFormat.OpenXml.Framework.Metadata;

/// <summary>
/// A lookup that identifies properties on an <see cref="OpenXmlElement"/> and caches the schema information
/// from those elements.
/// </summary>
internal class ElementFactoryCollection
namespace DocumentFormat.OpenXml.Framework.Metadata
{
public static readonly ElementFactoryCollection Empty = new([]);

private readonly List<ElementFactory> _data;

public ElementFactoryCollection(List<ElementFactory> lookup)
/// <summary>
/// A lookup that identifies properties on an <see cref="OpenXmlElement"/> and caches the schema information
/// from those elements.
/// </summary>
internal class ElementFactoryCollection
{
lookup.Sort(ElementChildNameComparer.Instance);
_data = lookup;
}
public static readonly ElementFactoryCollection Empty = new(Enumerable.Empty<ElementFactory>());

public OpenXmlElement? Create(in OpenXmlQualifiedName qname)
{
if (_data.Count == 0)
private readonly ElementFactory[] _data;

public ElementFactoryCollection(IEnumerable<ElementFactory> lookup)
{
return null;
var array = lookup.ToArray();

Array.Sort(array, ElementChildNameComparer.Instance);

_data = array;
}

// This is on a hot-path and using a dictionary adds substantial time to the lookup. Most child lists are small, so using a sorted
// list to store them with a binary search improves overall performance.
var idx = _data.BinarySearch(new ElementFactory(new(qname, default), null!), ElementChildNameComparer.Instance);
public int Count => _data.Length;

if (idx < 0)
public IEnumerable<ElementFactory> Elements => _data;

public OpenXmlElement? Create(in OpenXmlQualifiedName qname)
{
return null;
if (_data.Length == 0)
{
return null;
}

// This is on a hot-path and using a dictionary adds substantial time to the lookup. Most child lists are small, so using a sorted
// list to store them with a binary search improves overall performance.
var idx = Array.BinarySearch(_data, new ElementFactory(new(qname, default), null!), ElementChildNameComparer.Instance);

if (idx < 0)
{
return null;
}

return _data[idx].Create();
}

return _data[idx].Create();
}
private class ElementChildNameComparer : IComparer<ElementFactory>
{
public static IComparer<ElementFactory> Instance { get; } = new ElementChildNameComparer();

private sealed class ElementChildNameComparer : IComparer<ElementFactory>
{
public static IComparer<ElementFactory> Instance { get; } = new ElementChildNameComparer();
private ElementChildNameComparer()
{
}

public int Compare(ElementFactory x, ElementFactory y) => x.Type.Name.CompareTo(y.Type.Name);
public int Compare(ElementFactory? x, ElementFactory? y)
{
if (x is null && y is null)
{
return 0;
}

if (x is null)
{
return -1;
}

if (y is null)
{
return 1;
}

return x.Type.Name.CompareTo(y.Type.Name);
}
}
}
}

0 comments on commit be53c40

Please sign in to comment.