Skip to content
This repository was archived by the owner on Aug 2, 2023. It is now read-only.
This repository was archived by the owner on Aug 2, 2023. It is now read-only.

Add a StringKeyedDictionary<T> type #2438

@TylerBrinkley

Description

@TylerBrinkley

Motivation

As part of the #2406 initiative I would like a StringKeyedDictionary<T> type added in order to allow using a ReadOnlySpan<char> value for dictionary lookups without having to allocate a string.

Proposed API

 namespace System.Collections.Specialized {
+    public class StringKeyedDictionary<T> : Dictionary<string, T> {
+        public StringKeyedDictionary();
+        public StringKeyedDictionary(IStringEqualityComparer comparer);
+        public StringKeyedDictionary(int capacity);
+        public StringKeyedDictionary(int capacity, IStringEqualityComparer comparer);
+        public StringKeyedDictionary(IDictionary<string, T> dictionary);
+        public StringKeyedDictionary(IDictionary<string, T> dictionary, IStringEqualityComparer comparer);
+        public StringKeyedDictionary(IEnumerable<KeyValuePair<string, T>> collection);
+        public StringKeyedDictionary(IEnumerable<KeyValuePair<string, T>> collection, IStringEqualityComparer comparer);
+        public new IStringEqualityComparer Comparer { get; }
+        public T this[ReadOnlySpan<char> key] { get; }
+        public bool ContainsKey(ReadOnlySpan<char> key);
+        public bool Remove(ReadOnlySpan<char> key);
+        public bool TryGetValue(ReadOnlySpan<char> key, out T value);
+    }
+    public interface IStringEqualityComparer : IEqualityComparer<string> {
+        bool Equals(ReadOnlySpan<char> x, ReadOnlySpan<char> y);
+        int GetHashCode(ReadOnlySpan<char> obj);
+    }
 }
 namespace System {
-     public abstract class StringComparer : IComparer<string>, IEqualityComparer<string>, IComparer, IEqualityComparer {
+     public abstract class StringComparer : IComparer<string>, IEqualityComparer<string>, IComparer, IEqualityComparer, IStringEqualityComparer {
+        public virtual bool Equals(ReadOnlySpan<char> x, ReadOnlySpan<char> y);
+        public virtual int GetHashCode(ReadOnlySpan<char> obj);
      }
     public sealed class CultureAwareComparer : StringComparer {
+        public override bool Equals(ReadOnlySpan<char> x, ReadOnlySpan<char> y);
+        public override int GetHashCode(ReadOnlySpan<char> obj);
     }
     public class OrdinalComparer : StringComparer {
+        public override bool Equals(ReadOnlySpan<char> x, ReadOnlySpan<char> y);
+        public override int GetHashCode(ReadOnlySpan<char> obj);
     }
 }

Implementation Details

  • The default implementation of the new virtual methods on StringComparer would convert the span to a string and use the string methods instead.
  • Internal details of Dictionary<TKey, TValue> would be needed to implement the ReadOnlySpan<char> overloads.
  • A null comparer passed to the constructor would default to StringComparer.Ordinal.
  • Would need to be implemented in corefx to access internal Dictionary<TKey, TValue> details as well as update StringComparer.

Possible Addition

While not specifically needed for this request an IStringComparer interface should probably be added as well like so since we're updating StringComparer. It could then be used in a specialized StringKeyedSortedDictionary or StringSortedSet.

 namespace System.Collections.Specialized {
+    public interface IStringComparer : IComparer<string> {
+        int Compare(ReadOnlySpan<char> x, ReadOnlySpan<char> y);
+    }
 }
 namespace System {
-    public abstract class StringComparer : IComparer, IEqualityComparer, IComparer<string>, IEqualityComparer<string>, IStringEqualityComparer {
+    public abstract class StringComparer : IComparer, IEqualityComparer, IComparer<string>, IEqualityComparer<string>, IStringEqualityComparer, IStringComparer {
+        public virtual int Compare(ReadOnlySpan<char> x, ReadOnlySpan<char> y);
     }
     public sealed class CultureAwareComparer : StringComparer {
+        public override int Compare(ReadOnlySpan<char> x, ReadOnlySpan<char> y);
     }
     public class OrdinalComparer : StringComparer {
+        public override int Compare(ReadOnlySpan<char> x, ReadOnlySpan<char> y);
     }
 }

Open Questions

  • Should the additional IStringComparer interface also be implemented?

Updates

  • Switched to proposing implementation that derives from Dictionary<string, T> due to the massive code duplication of re-implementing Dictionary<TKey, TValue>'s logic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions