internal void CacheMeasure(Size desiredSize, Size measuredSize) { Scavenge(); var key = CachedTuple.Create(desiredSize.Width, desiredSize.Height); var node = _queue.AddLast(key); _sizes[key] = new MeasureSizeEntry(measuredSize, node); }
/// <summary> /// Memoizer with two parameters, used to perform a lazy-cached evaluation. (see http://en.wikipedia.org/wiki/Memoization) /// </summary> /// <typeparam name="T">The return type to memoize</typeparam> /// <param name="func">the function to evaluate</param> /// <returns>A memoized value</returns> public static Func <TArg1, TArg2, TResult> AsLockedMemoized <TArg1, TArg2, TResult>(this Func <TArg1, TArg2, TResult> func) { #if XAMARIN // On Xamarin.iOS, the SynchronizedDictionary type costs a lot in terms of // generic delegates, where trampolines are used a lot. As simple lock will not create that // much contention for now. var values = new Dictionary <CachedTuple <TArg1, TArg2>, TResult>(CachedTuple <TArg1, TArg2> .Comparer); return((arg1, arg2) => { var tuple = CachedTuple.Create(arg1, arg2); lock (values) { return values.FindOrCreate( tuple, () => func(tuple.Item1, tuple.Item2) ); } }); #elif !HAS_NO_CONCURRENT_DICT var values = new ConcurrentDictionary <CachedTuple <TArg1, TArg2>, TResult>(CachedTuple <TArg1, TArg2> .Comparer); return((arg1, arg2) => { var tuple = CachedTuple.Create(arg1, arg2); return values.GetOrAdd( tuple, // Use the parameter to avoid closure heap allocation k => func(k.Item1, k.Item2) ); }); #else var values = new SynchronizedDictionary <Tuple <TArg1, TArg2>, TResult>(); return((arg1, arg2) => { TResult value = default(TResult); var tuple = Tuple.Create(arg1, arg2); values.Lock.Write( v => v.TryGetValue(tuple, out value), v => value = values[tuple] = func(arg1, arg2) ); return value; }); #endif }
/// <summary> /// Gets the dependencies properties for the specified type with specific Framework metadata options /// </summary> /// <param name="type">A dependency object</param> /// <param name="options">A set of flags that must be set</param> /// <returns>An array of Dependency Properties.</returns> internal static DependencyProperty[] GetFrameworkPropertiesForType(Type type, FrameworkPropertyMetadataOptions options) { DependencyProperty[] result = null; var key = CachedTuple.Create(type, options); if (!_getFrameworkPropertiesForType.TryGetValue(key, out result)) { _getFrameworkPropertiesForType.Add(key, result = InternalGetFrameworkPropertiesForType(type, options)); } return(result); }
/// <summary> /// Provides a NSIndexPath for the current ListViewSource. /// </summary> /// <remarks> /// Use this method instead of NSIndexPath.FromRowSection, as the interop call /// is quite costly. /// </remarks> protected NSIndexPath GetNSIndexPathFromRowSection(int row, int section) { NSIndexPath indexPath; var key = CachedTuple.Create(row, section); if (!_indexPaths.TryGetValue(key, out indexPath)) { _indexPaths.Add(key, indexPath = NSIndexPath.FromRowSection(row, section)); } return(indexPath); }
/// <summary> /// Provides a UICollectionViewLayoutAttributes for the current ListViewSource. /// </summary> /// <remarks> /// Use this method instead of UICollectionViewLayoutAttributes.CreateForCell, as the interop call /// is quite costly. /// </remarks> protected UICollectionViewLayoutAttributes GetLayoutAttributesForIndexPath(int row, int section) { var key = CachedTuple.Create(row, section); UICollectionViewLayoutAttributes attributes; if (!_layoutAttributesForIndexPaths.TryGetValue(key, out attributes)) { var indexPath = GetNSIndexPathFromRowSection(row, section); _layoutAttributesForIndexPaths.Add(key, attributes = UICollectionViewLayoutAttributes.CreateForCell <UICollectionViewLayoutAttributes>(indexPath)); } return(attributes); }
/// <summary> /// Memoizer with four parameters, used to perform a lazy-cached evaluation. (see http://en.wikipedia.org/wiki/Memoization) /// </summary> /// <typeparam name="T">The return type to memoize</typeparam> /// <param name="func">the function to evaluate</param> /// <returns>A memoized value</returns> public static Func <TArg1, TArg2, TArg3, TArg4, TResult> AsLockedMemoized <TArg1, TArg2, TArg3, TArg4, TResult>(this Func <TArg1, TArg2, TArg3, TArg4, TResult> func) { #if XAMARIN var values = new Dictionary <CachedTuple <TArg1, TArg2, TArg3, TArg4>, TResult>(CachedTuple <TArg1, TArg2, TArg3, TArg4> .Comparer); return((arg1, arg2, arg3, arg4) => { var tuple = CachedTuple.Create(arg1, arg2, arg3, arg4); lock (values) { return values.FindOrCreate( tuple, // Use the parameter to avoid closure heap allocation () => func(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4) ); } }); #elif !HAS_NO_CONCURRENT_DICT var values = new ConcurrentDictionary <CachedTuple <TArg1, TArg2, TArg3, TArg4>, TResult>(CachedTuple <TArg1, TArg2, TArg3, TArg4> .Comparer); return((arg1, arg2, arg3, arg4) => { var tuple = CachedTuple.Create(arg1, arg2, arg3, arg4); return values.GetOrAdd( tuple, // Use the parameter to avoid closure heap allocation k => func(k.Item1, k.Item2, k.Item3, k.Item4) ); }); #else var values = new SynchronizedDictionary <Tuple <TArg1, TArg2, TArg3, TArg4>, TResult>(); return((arg1, arg2, arg3, arg4) => { TResult value = default(TResult); var tuple = new Tuple <TArg1, TArg2, TArg3, TArg4>(arg1, arg2, arg3, arg4); values.Lock.Write( v => v.TryGetValue(tuple, out value), v => value = values[tuple] = func(arg1, arg2, arg3, arg4) ); return value; }); #endif }
public static bool IsEvent(Type type, string property) { var key = CachedTuple.Create(type, property); bool result; lock (_isEvent) { if (!_isEvent.TryGetValue(key, out result)) { _isEvent.Add(key, result = InternalIsEvent(type, property)); } } return(result); }
internal static ValueUnsetterHandler GetValueUnsetter(Type type, string property, DependencyPropertyValuePrecedences precedence) { var key = CachedTuple.Create(type, property, precedence); ValueUnsetterHandler result; lock (_getValueUnsetter) { if (!_getValueUnsetter.TryGetValue(key, out result)) { _getValueUnsetter.Add(key, result = InternalGetValueUnsetter(type, property, precedence)); } } return(result); }
public static Type GetPropertyType(Type type, string property) { var key = CachedTuple.Create(type, property); Type result; lock (_getPropertyType) { if (!_getPropertyType.TryGetValue(key, out result)) { _getPropertyType.Add(key, result = InternalGetPropertyType(type, property)); } } return(result); }
internal static ValueGetterHandler GetValueGetter(Type type, string property, DependencyPropertyValuePrecedences?precedence, bool allowPrivateMembers) { var key = CachedTuple.Create(type, property, precedence, allowPrivateMembers); ValueGetterHandler?result; lock (_getValueGetter) { if (!_getValueGetter.TryGetValue(key, out result)) { _getValueGetter.Add(key, result = InternalGetValueGetter(type, property, precedence, allowPrivateMembers)); } } return(result); }
public static Type?GetPropertyType(Type type, string property, bool allowPrivateMembers) { var key = CachedTuple.Create(type, property, allowPrivateMembers); Type?result; lock (_getPropertyType) { if (!_getPropertyType.TryGetValue(key, out result)) { _getPropertyType.Add(key, result = InternalGetPropertyType(type, property, allowPrivateMembers)); } } return(result); }
/// <summary> /// Memoizer with two parameters, used to perform a lazy-cached evaluation. (see http://en.wikipedia.org/wiki/Memoization) /// </summary> /// <typeparam name="TParam1">The first parameter type to memoize</typeparam> /// <typeparam name="TParam2">The second parameter type to memoize</typeparam> /// <param name="func">the function to evaluate</param> /// <returns>A memoized value</returns> public static Func <TParam1, TParam2, TResult> AsMemoized <TParam1, TParam2, TResult>(this Func <TParam1, TParam2, TResult> func) { Dictionary <CachedTuple <TParam1, TParam2>, TResult> values = new Dictionary <CachedTuple <TParam1, TParam2>, TResult>(CachedTuple <TParam1, TParam2> .Comparer); return((arg1, arg2) => { var tuple = CachedTuple.Create(arg1, arg2); TResult value; if (!values.TryGetValue(tuple, out value)) { value = values[tuple] = func(arg1, arg2); } return value; }); }
public Size?FindMeasuredSize(MeasureKey key, Size availableSize) { if (_sizes.TryGetValue(CachedTuple.Create(availableSize.Width, availableSize.Height), out var sizeEntry)) { return(sizeEntry.MeasuredSize); } else { if (key.TextWrapping == TextWrapping.NoWrap) { // No wrap, assume any measured width below the asked available size // is valid, if the available size is greater. foreach (var keySize in _sizes) { if (keySize.Key.Item1 >= availableSize.Width && keySize.Value.MeasuredSize.Width <= availableSize.Width) { MoveToLast(keySize.Key, keySize.Value); return(keySize.Value.MeasuredSize); } } } else { foreach (var keySize in _sizes) { // If text wraps and the available width is the same, any height below the // available size is valid. if ( keySize.Key.Item1 == availableSize.Width && keySize.Value.MeasuredSize.Height <= availableSize.Height ) { MoveToLast(keySize.Key, keySize.Value); return(keySize.Value.MeasuredSize); } } } } return(null); }
public Size?FindMeasuredSize(MeasureKey key, Size availableSize) { var currentAvailableWidth = availableSize.Width; var currentAvailableHeight = availableSize.Height; if (_sizes.TryGetValue(CachedTuple.Create(currentAvailableWidth, currentAvailableHeight), out var sizeEntry)) { return(sizeEntry.MeasuredSize); } var isWrapping = key.IsWrapping; var isClipping = key.IsClipping; foreach (var kvp in _sizes) { var size = kvp.Key; var measureSizeEntry = kvp.Value; var measurementCachedWidth = measureSizeEntry.MeasuredSize.Width; var measurementCachedHeight = measureSizeEntry.MeasuredSize.Height; var measurementAvailableWidth = size.Item1; var measurementAvailableHeight = size.Item2; if (isWrapping || isClipping) { if (measurementCachedWidth <= currentAvailableWidth && currentAvailableWidth <= measurementAvailableWidth) { // Ok we can reuse it } else { continue; // Check for another cached measurement } } else { // Non-wrapping text if (double.IsInfinity(measurementAvailableWidth)) { // Previous measurement was unconstrained // horizontally: we can definitely reuse it. } else { if (Math.Abs(measurementCachedWidth - measurementAvailableWidth) < 0.5d) { // This measure was constrained, we can reuse only if the width is the same. if (Math.Abs(measurementCachedWidth - currentAvailableWidth) < 0.5d) { // Yep, that's good } else { continue; // Check for another cached measurement } } } } // We need to make sure the height is ok if (double.IsInfinity(measurementAvailableHeight)) { // Previous measurement was unconstrained // vertically: we can definitely reuse it. } else { // A max-height was specified in the cached measurement: // We must check if we can reuse it. if (Math.Abs(measurementCachedHeight - measurementAvailableHeight) < 0.5d) { // This measure was constrained, we can reuse only if the available height // is same or higher than current available height if (measurementCachedHeight >= currentAvailableHeight) { // Yep, that's good } else { continue; // Check for another cached measurement } } } // Got it, this cached measurement fits MoveToLast(size, measureSizeEntry); return(measureSizeEntry.MeasuredSize); } return(null); // No valid cache entry found }
public int GetHashCode(CachedTuple <T1, T2> obj) { return(obj._cachedHashCode); }
public bool Equals(CachedTuple <T1, T2> x, CachedTuple <T1, T2> y) { return(InternalEquals(x, y)); }