Skip to content

Commit a09ba60

Browse files
jhonabreulclaude
andcommitted
Move suggestion caches to the class field block; simplify candidate collection
Move the _candidateNameCache and _suggestionCache declarations up to the class field block with the other fields. In GetCandidateMemberNames, collect the snake_case names into a single HashSet (named names) instead of a HashSet plus a List, and return the set directly; deduplication and storage are the same collection. Candidate iteration order no longer matters -- suggestions are ordered by edit distance and then by name. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 4c682fc commit a09ba60

1 file changed

Lines changed: 16 additions & 21 deletions

File tree

src/runtime/Types/ClassBase.cs

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ internal class ClassBase : ManagedType, IDeserializationCallback
2929
internal readonly Dictionary<int, MethodObject> richcompare = new();
3030
internal MaybeType type;
3131

32+
// Reflecting over a managed type's full member set (with FlattenHierarchy) plus the
33+
// snake_case conversion is expensive, and the result never changes for a given type.
34+
// Compute it once per type.
35+
private static readonly ConcurrentDictionary<Type, HashSet<string>> _candidateNameCache = new();
36+
37+
// A miss-heavy workload probes the same missing names over and over (e.g. a per-bar
38+
// getattr(self, "_optional", None) on a .NET-derived object). Memoize the fully-built
39+
// " Did you mean: ...?" hint (empty when there is nothing to suggest) per
40+
// (type, missing-name) so repeats are a dictionary lookup instead of an O(members)
41+
// reflection + Levenshtein scan on every miss.
42+
private static readonly ConcurrentDictionary<(Type Type, string Name), string> _suggestionCache = new();
43+
3244
internal ClassBase(Type tp)
3345
{
3446
if (tp is null) throw new ArgumentNullException(nameof(type));
@@ -730,26 +742,13 @@ private static string GetErrorMessage(BorrowedReference value, string fallbackNa
730742
return $"object has no attribute '{fallbackName}'";
731743
}
732744

733-
// Reflecting over a managed type's full member set (with FlattenHierarchy) plus the
734-
// snake_case conversion is expensive, and the result never changes for a given type.
735-
// Compute it once per type.
736-
private static readonly ConcurrentDictionary<Type, string[]> _candidateNameCache = new();
737-
738-
// A miss-heavy workload probes the same missing names over and over (e.g. a per-bar
739-
// getattr(self, "_optional", None) on a .NET-derived object). Memoize the fully-built
740-
// " Did you mean: ...?" hint (empty when there is nothing to suggest) per
741-
// (type, missing-name) so repeats are a dictionary lookup instead of an O(members)
742-
// reflection + Levenshtein scan on every miss.
743-
private static readonly ConcurrentDictionary<(Type Type, string Name), string> _suggestionCache = new();
744-
745745
// The deduplicated snake_case member names of a type, cached so the reflection and
746746
// string conversion happen at most once per type rather than on every attribute miss.
747-
private static string[] GetCandidateMemberNames(Type type)
747+
private static HashSet<string> GetCandidateMemberNames(Type type)
748748
{
749749
return _candidateNameCache.GetOrAdd(type, static t =>
750750
{
751-
var seen = new HashSet<string>(StringComparer.Ordinal);
752-
var names = new List<string>();
751+
var names = new HashSet<string>(StringComparer.Ordinal);
753752

754753
var members = t.GetMembers(BindingFlags.Public | BindingFlags.Instance
755754
| BindingFlags.Static | BindingFlags.FlattenHierarchy);
@@ -769,14 +768,10 @@ private static string[] GetCandidateMemberNames(Type type)
769768

770769
// Suggest the snake_case alias, since that is the fork's PEP8-style
771770
// public API surface (members are exposed in both Pascal and snake case).
772-
var candidate = ToSnakeCaseMemberName(member);
773-
if (seen.Add(candidate))
774-
{
775-
names.Add(candidate);
776-
}
771+
names.Add(ToSnakeCaseMemberName(member));
777772
}
778773

779-
return names.ToArray();
774+
return names;
780775
});
781776
}
782777

0 commit comments

Comments
 (0)