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
        }
示例#3
0
        /// <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);
        }
示例#10
0
        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);
        }
示例#11
0
        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;
            });
        }
示例#13
0
 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
            }
示例#15
0
 public int GetHashCode(CachedTuple <T1, T2> obj)
 {
     return(obj._cachedHashCode);
 }
示例#16
0
 public bool Equals(CachedTuple <T1, T2> x, CachedTuple <T1, T2> y)
 {
     return(InternalEquals(x, y));
 }