Skip to content

Commit

Permalink
Use a binary search to convert string -> enum for HeaderId (and other…
Browse files Browse the repository at this point in the history
… enums)

This helps with jstedfast/MailKit#1844
  • Loading branch information
jstedfast committed Nov 17, 2024
1 parent ed6fbed commit d73b8a2
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 96 deletions.
97 changes: 41 additions & 56 deletions MimeKit/HeaderId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
// THE SOFTWARE.
//

using System;
using System.Collections.Generic;

using MimeKit.Utils;

namespace MimeKit {
Expand Down Expand Up @@ -98,6 +95,14 @@ public enum HeaderId {
/// </summary>
AuthenticationResults,

/// <summary>
/// The Auto-Submitted header field.
/// </summary>
/// <remarks>
/// The header as defined in <a href="https://www.rfc-editor.org/rfc/rfc3834">RFC3834</a>.
/// </remarks>
AutoSubmitted,

/// <summary>
/// The Autocrypt header field.
/// </summary>
Expand All @@ -118,14 +123,6 @@ public enum HeaderId {
/// </summary>
Autoforwarded,

/// <summary>
/// The Auto-Submitted header field.
/// </summary>
/// <remarks>
/// The header as defined in <a href="https://www.rfc-editor.org/rfc/rfc3834">RFC3834</a>.
/// </remarks>
AutoSubmitted,

/// <summary>
/// The Autosubmitted header field.
/// </summary>
Expand Down Expand Up @@ -357,6 +354,11 @@ public enum HeaderId {
/// </summary>
Importance,

/// <summary>
/// The In-Reply-To header field.
/// </summary>
InReplyTo,

/// <summary>
/// The Injection-Date header field.
/// </summary>
Expand All @@ -367,11 +369,6 @@ public enum HeaderId {
/// </summary>
InjectionInfo,

/// <summary>
/// The In-Reply-To header field.
/// </summary>
InReplyTo,

/// <summary>
/// The Keywords header field.
/// </summary>
Expand Down Expand Up @@ -642,6 +639,26 @@ public enum HeaderId {
/// </summary>
UserAgent,

/// <summary>
/// The X-Mailer header field.
/// </summary>
XMailer,

/// <summary>
/// The X-MSMail-Priority header field.
/// </summary>
XMSMailPriority,

/// <summary>
/// The X-Priority header field.
/// </summary>
XPriority,

/// <summary>
/// The X-Status header field.
/// </summary>
XStatus,

/// <summary>
/// The X400-Content-Identifier header field.
/// </summary>
Expand Down Expand Up @@ -682,26 +699,6 @@ public enum HeaderId {
/// </summary>
X400Trace,

/// <summary>
/// The X-Mailer header field.
/// </summary>
XMailer,

/// <summary>
/// The X-MSMail-Priority header field.
/// </summary>
XMSMailPriority,

/// <summary>
/// The X-Priority header field.
/// </summary>
XPriority,

/// <summary>
/// The X-Status header field.
/// </summary>
XStatus,

/// <summary>
/// An unknown header field.
/// </summary>
Expand Down Expand Up @@ -729,11 +726,11 @@ public static class HeaderIdExtensions
"Archived-At",
"Article",
"Authentication-Results",
"Auto-Submitted",
"Autocrypt",
"Autocrypt-Gossip",
"Autocrypt-Setup-Message",
"Autoforwarded",
"Auto-Submitted",
"Autosubmitted",
"Base",
"Bcc",
Expand Down Expand Up @@ -779,9 +776,9 @@ public static class HeaderIdExtensions
"From",
"Generate-Delivery-Report",
"Importance",
"In-Reply-To",
"Injection-Date",
"Injection-Info",
"In-Reply-To",
"Keywords",
"Language",
"Latest-Delivery-Time",
Expand Down Expand Up @@ -836,6 +833,10 @@ public static class HeaderIdExtensions
"TLS-Required",
"To",
"User-Agent",
"X-Mailer",
"X-MSMail-Priority",
"X-Priority",
"X-Status",
"X400-Content-Identifier",
"X400-Content-Return",
"X400-Content-Type",
Expand All @@ -844,22 +845,7 @@ public static class HeaderIdExtensions
"X400-Received",
"X400-Recipients",
"X400-Trace",
"X-Mailer",
"X-MSMail-Priority",
"X-Priority",
"X-Status",
};
static readonly Dictionary<string, HeaderId> IdMapping;

static HeaderIdExtensions ()
{
var values = (HeaderId[]) Enum.GetValues (typeof (HeaderId));

IdMapping = new Dictionary<string, HeaderId> (values.Length - 1, MimeUtils.OrdinalIgnoreCase);

for (int i = 0; i < values.Length - 1; i++)
IdMapping.Add (HeaderNames[i], values[i]);
}

/// <summary>
/// Converts the enum value into the equivalent header field name.
Expand All @@ -881,10 +867,9 @@ public static string ToHeaderName (this HeaderId value)

internal static HeaderId ToHeaderId (this string name)
{
if (!IdMapping.TryGetValue (name, out var value))
return HeaderId.Unknown;
int index = MimeUtils.BinarySearch (HeaderNames, name);

return value;
return index >= 0 ? (HeaderId) index : HeaderId.Unknown;
}
}
}
19 changes: 2 additions & 17 deletions MimeKit/Text/HtmlAttributeId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
// THE SOFTWARE.
//

using System;
using System.Collections.Generic;

using MimeKit.Utils;

namespace MimeKit.Text {
Expand Down Expand Up @@ -689,17 +686,6 @@ public static class HtmlAttributeIdExtensions
"width",
"xmlns",
};
static readonly Dictionary<string, HtmlAttributeId> IdMapping;

static HtmlAttributeIdExtensions ()
{
var values = (HtmlAttributeId[]) Enum.GetValues (typeof (HtmlAttributeId));

IdMapping = new Dictionary<string, HtmlAttributeId> (values.Length - 1, MimeUtils.OrdinalIgnoreCase);

for (int i = 1; i < values.Length; i++)
IdMapping.Add (values[i].ToAttributeName (), values[i]);
}

/// <summary>
/// Converts the enum value into the equivalent attribute name.
Expand Down Expand Up @@ -729,10 +715,9 @@ public static string ToAttributeName (this HtmlAttributeId value)
/// <param name="name">The attribute name.</param>
internal static HtmlAttributeId ToHtmlAttributeId (this string name)
{
if (!IdMapping.TryGetValue (name, out HtmlAttributeId value))
return HtmlAttributeId.Unknown;
int index = MimeUtils.BinarySearch (AttributeNames, name);

return value;
return (HtmlAttributeId) (index + 1);
}
}
}
31 changes: 8 additions & 23 deletions MimeKit/Text/HtmlTagId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
// THE SOFTWARE.
//

using System;
using System.Collections.Generic;

using MimeKit.Utils;

namespace MimeKit.Text {
Expand All @@ -45,6 +42,11 @@ public enum HtmlTagId {
/// </summary>
Unknown,

/// <summary>
/// The HTML comment tag.
/// </summary>
Comment,

/// <summary>
/// The HTML &lt;a&gt; tag.
/// </summary>
Expand Down Expand Up @@ -190,11 +192,6 @@ public enum HtmlTagId {
/// </summary>
Command,

/// <summary>
/// The HTML comment tag.
/// </summary>
Comment,

/// <summary>
/// The HTML &lt;datalist&gt; tag.
/// </summary>
Expand Down Expand Up @@ -725,6 +722,7 @@ public enum HtmlTagId {
public static class HtmlTagIdExtensions
{
static readonly string[] TagNames = new string[] {
"!",
"a",
"abbr",
"acronym",
Expand Down Expand Up @@ -754,7 +752,6 @@ public static class HtmlTagIdExtensions
"col",
"colgroup",
"command",
"!",
"datalist",
"dd",
"del",
Expand Down Expand Up @@ -860,17 +857,6 @@ public static class HtmlTagIdExtensions
"xml",
"xmp",
};
static readonly Dictionary<string, HtmlTagId> IdMapping;

static HtmlTagIdExtensions ()
{
var values = (HtmlTagId[]) Enum.GetValues (typeof (HtmlTagId));

IdMapping = new Dictionary<string, HtmlTagId> (values.Length - 1, MimeUtils.OrdinalIgnoreCase);

for (int i = 1; i < values.Length; i++)
IdMapping.Add (values[i].ToHtmlTagName (), values[i]);
}

/// <summary>
/// Converts the enum value into the equivalent tag name.
Expand Down Expand Up @@ -906,10 +892,9 @@ internal static HtmlTagId ToHtmlTagId (this string name)
if (name[0] == '!')
return HtmlTagId.Comment;

if (!IdMapping.TryGetValue (name, out HtmlTagId value))
return HtmlTagId.Unknown;
int index = MimeUtils.BinarySearch (TagNames, name);

return value;
return (HtmlTagId) (index + 1);
}

/// <summary>
Expand Down
22 changes: 22 additions & 0 deletions MimeKit/Utils/MimeUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -614,5 +614,27 @@ internal static byte[] Unquote (byte[] text, int startIndex, int length, bool co

return builder.ToArray ();
}

internal static int BinarySearch (string[] names, string name)
{
int max = names.Length - 1;
int min = 0;

while (min <= max) {
int i = min + ((max - min) / 2);

int cmp = string.Compare (names[i], name, StringComparison.OrdinalIgnoreCase);

if (cmp == 0)
return i;

if (cmp < 0)
min = i + 1;
else
max = i - 1;
}

return -1;
}
}
}

0 comments on commit d73b8a2

Please sign in to comment.