Skip to content

Commit

Permalink
Avoid Hashtable-related allocations in DataBindEngine (#6501)
Browse files Browse the repository at this point in the history
The _valueConverterTable is a Hashtable that uses a struct-based key.  It's boxing every time a lookup is performed or an add is performed.
  • Loading branch information
stephentoub authored Aug 12, 2022
1 parent 8853b34 commit 5717fc2
Showing 1 changed file with 21 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -368,13 +368,14 @@ internal IValueConverter GetDefaultValueConverter(Type sourceType,
Type targetType,
bool targetToSource)
{
IValueConverter result = _valueConverterTable[sourceType, targetType, targetToSource];

if (result == null)
ValueConverterTableKey key = new ValueConverterTableKey(sourceType, targetType, targetToSource);
if (!_valueConverterTable.TryGetValue(key, out IValueConverter result))
{
result = DefaultValueConverter.Create(sourceType, targetType, targetToSource, this);
if (result != null)
_valueConverterTable.Add(sourceType, targetType, targetToSource, result);
{
_valueConverterTable.Add(key, result);
}
}

return result;
Expand Down Expand Up @@ -657,63 +658,26 @@ private void OnLayoutUpdated(object sender, EventArgs e)
//
//------------------------------------------------------

// cache of default value converters (so that all uses of string-to-int can
// share the same converter)
class ValueConverterTable : Hashtable
private readonly struct ValueConverterTableKey : IEquatable<ValueConverterTableKey>
{
struct Key
{
Type _sourceType, _targetType;
bool _targetToSource;

public Key(Type sourceType, Type targetType, bool targetToSource)
{
_sourceType = sourceType;
_targetType = targetType;
_targetToSource = targetToSource;
}
private readonly Type _sourceType, _targetType;
private readonly bool _targetToSource;

public override int GetHashCode()
{
return _sourceType.GetHashCode() + _targetType.GetHashCode();
}

public override bool Equals(object o)
{
if (o is Key)
{
return (this == (Key)o);
}
return false;
}

public static bool operator ==(Key k1, Key k2)
{
return k1._sourceType == k2._sourceType &&
k1._targetType == k2._targetType &&
k1._targetToSource == k2._targetToSource;
}

public static bool operator !=(Key k1, Key k2)
{
return !(k1 == k2);
}
}

public IValueConverter this[Type sourceType, Type targetType, bool targetToSource]
public ValueConverterTableKey(Type sourceType, Type targetType, bool targetToSource)
{
get
{
Key key = new Key(sourceType, targetType, targetToSource);
object value = base[key];
return (IValueConverter)value;
}
_sourceType = sourceType;
_targetType = targetType;
_targetToSource = targetToSource;
}

public void Add(Type sourceType, Type targetType, bool targetToSource, IValueConverter value)
{
base.Add(new Key(sourceType, targetType, targetToSource), value);
}
public override int GetHashCode() => _sourceType.GetHashCode() + _targetType.GetHashCode();

public override bool Equals(object o) => o is ValueConverterTableKey other && Equals(other);

public bool Equals(ValueConverterTableKey other) =>
_sourceType == other._sourceType &&
_targetType == other._targetType &&
_targetToSource == other._targetToSource;
}

private sealed class DataBindEngineShutDownListener : ShutDownListener
Expand Down Expand Up @@ -741,7 +705,7 @@ internal override void OnShutDown(object target, object sender, EventArgs e)
private UIElement _layoutElement;
private ViewManager _viewManager = new ViewManager();
private CommitManager _commitManager = new CommitManager();
private ValueConverterTable _valueConverterTable = new ValueConverterTable();
private Dictionary<ValueConverterTableKey, IValueConverter> _valueConverterTable = new Dictionary<ValueConverterTableKey, IValueConverter>();
private PathParser _pathParser = new PathParser();
private IAsyncDataDispatcher _defaultAsyncDataDispatcher;
private HybridDictionary _asyncDispatchers;
Expand Down

0 comments on commit 5717fc2

Please sign in to comment.