/// <summary>
 /// Initializes a new instance of the
 /// <see cref="PersistentDictionaryReverseEnumerator{TKey,TValue,TReturn}"/> class.
 /// </summary>
 /// <param name="dictionary">The dictionary to enumerate.</param>
 /// <param name="range">The range to enumerate.</param>
 /// <param name="getter">A function that gets the value from a cursor.</param>
 /// <param name="predicate">The predicate to filter items with.</param>
 public PersistentDictionaryReverseEnumerator(
     PersistentDictionary <TKey, TValue> dictionary,
     KeyRange <TKey> range,
     Func <PersistentDictionaryCursor <TKey, TValue>, TReturn> getter,
     Predicate <TReturn> predicate)
 {
     this.dictionary = dictionary;
     this.range      = range;
     this.getter     = getter;
     this.predicate  = predicate;
 }
        /// <summary>
        /// Determine if the MethodCallExpression is a key comparison method, and
        /// return the index range if it is.
        /// </summary>
        /// <param name="methodCall">The method call expression.</param>
        /// <param name="keyMemberInfo">The name of the parameter member that is the key.</param>
        /// <param name="keyRange">Returns the key range if this is a key comparison method.</param>
        /// <returns>True if the method is a key comparison method.</returns>
        private static bool IsComparisonMethod(MethodCallExpression methodCall, MemberInfo keyMemberInfo, out KeyRange <TKey> keyRange)
        {
            if (null != methodCall.Object && IsKeyAccess(methodCall.Object, keyMemberInfo))
            {
                TKey value;

                // TKey.Equals
                if ((equalsMethod == methodCall.Method) &&
                    ConstantExpressionEvaluator <TKey> .TryGetConstantExpression(methodCall.Arguments[0], out value))
                {
                    keyRange = new KeyRange <TKey>(Key <TKey> .CreateKey(value, true), Key <TKey> .CreateKey(value, true));
                    return(true);
                }
            }

            if (typeof(TKey) == typeof(string))
            {
                if (null != methodCall.Object &&
                    IsKeyAccess(methodCall.Object, keyMemberInfo))
                {
                    TKey value;

                    // String.StartsWith
                    if (StringExpressionEvaluatorHelper.StringStartWithMethod == methodCall.Method &&
                        ConstantExpressionEvaluator <TKey> .TryGetConstantExpression(methodCall.Arguments[0], out value))
                    {
                        // Lower range is just the string, upper range is the prefix
                        keyRange = new KeyRange <TKey>(Key <TKey> .CreateKey(value, true), Key <TKey> .CreatePrefixKey(value));
                        return(true);
                    }
                }
                else if (null == methodCall.Object)
                {
                    // Static String.Equals
                    if (StringExpressionEvaluatorHelper.StringStaticEqualsMethod == methodCall.Method)
                    {
                        TKey value;
                        if ((IsKeyAccess(methodCall.Arguments[0], keyMemberInfo) &&
                             ConstantExpressionEvaluator <TKey> .TryGetConstantExpression(methodCall.Arguments[1], out value)) ||
                            (IsKeyAccess(methodCall.Arguments[1], keyMemberInfo) &&
                             ConstantExpressionEvaluator <TKey> .TryGetConstantExpression(methodCall.Arguments[0], out value)))
                        {
                            keyRange = new KeyRange <TKey>(Key <TKey> .CreateKey(value, true), Key <TKey> .CreateKey(value, true));
                            return(true);
                        }
                    }
                }
            }

            keyRange = null;
            return(false);
        }
        /// <summary>
        /// Create an index range on the cursor, controlling which records will be enumerated.
        /// After this call the cursor will be positioned on range.Max and can be enumerated
        /// backwards to range.Min with TryMovePrevious.
        /// </summary>
        /// <param name="range">The range to set.</param>
        /// <returns>False if the range is empty.</returns>
        public bool SetReverseIndexRange(KeyRange <TKey> range)
        {
            if (range.IsEmpty)
            {
                return(false);
            }

            if (null != range.Max)
            {
                // The possibilities we have here are:
                //   1. Key = 'k', exclusive: seek for < 'k'
                //   2. Key = 'k', inclusive: seek for <= 'k'
                //   3. Key = 'k', prefix: make a prefix key and seek LE
                if (range.Max.IsPrefix)
                {
                    this.MakePrefixKey(range.Max.Value);
                }
                else
                {
                    this.MakeKey(range.Max.Value);
                }

                SeekGrbit grbit = range.Max.IsInclusive ? SeekGrbit.SeekLE : SeekGrbit.SeekLT;
                if (!Api.TrySeek(this.sesid, this.dataTable, grbit))
                {
                    return(false);
                }
            }
            else
            {
                Api.MoveAfterLast(this.sesid, this.dataTable);
                if (!Api.TryMovePrevious(this.sesid, this.dataTable))
                {
                    return(false);
                }
            }

            if (null != range.Min)
            {
                this.MakeKey(range.Min.Value);
                SetIndexRangeGrbit grbit = range.Min.IsInclusive ? SetIndexRangeGrbit.RangeInclusive : SetIndexRangeGrbit.None;
                return(Api.TrySetIndexRange(this.sesid, this.dataTable, grbit));
            }

            return(true);
        }
        /// <summary>
        /// Returns an enumerator that iterates through the collection.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
        /// </returns>
        public IEnumerator <TKey> GetEnumerator()
        {
            // Consider: we could get the enumeration of key ranges, sort them and union overlapping ranges.
            // Enumerating the data as several different ranges would be more efficient when the expression
            // specifies an OR and the ranges are highly disjoint.
            KeyRange <TKey> range = KeyExpressionEvaluator <TKey> .GetKeyRange(this.expression);

            this.dictionary.TraceWhere(range, this.isReversed);
            if (this.isReversed)
            {
                return(new PersistentDictionaryReverseEnumerator <TKey, TValue, TKey>(
                           this.dictionary, range, c => c.RetrieveCurrentKey(), this.predicate));
            }

            return(new PersistentDictionaryEnumerator <TKey, TValue, TKey>(
                       this.dictionary, range, c => c.RetrieveCurrentKey(), this.predicate));
        }
Example #5
0
        /// <summary>
        /// Return the intersection of two ranges.
        /// </summary>
        /// <param name="a">The first range.</param>
        /// <param name="b">The second range.</param>
        /// <returns>The intersection of the two ranges.</returns>
        public static KeyRange <T> operator &(KeyRange <T> a, KeyRange <T> b)
        {
            // Intersecting anything with an empty range returns the empty range.
            if (a.IsEmpty || b.IsEmpty)
            {
                return(EmptyRange);
            }

            var intersected = new KeyRange <T>(LowerIntersection(a.Min, b.Min), UpperIntersection(a.Max, b.Max));

            if (intersected.IsEmpty)
            {
                intersected = EmptyRange;
            }

            return(intersected);
        }
        /// <summary>
        /// Create an index range on the cursor, controlling which records will be enumerated.
        /// </summary>
        /// <param name="range">The range to set.</param>
        /// <returns>False if the range is empty.</returns>
        public bool SetIndexRange(KeyRange <TKey> range)
        {
            if (range.IsEmpty)
            {
                return(false);
            }

            if (null != range.Min)
            {
                this.MakeKey(range.Min.Value);
                SeekGrbit grbit = range.Min.IsInclusive ? SeekGrbit.SeekGE : SeekGrbit.SeekGT;
                if (!Api.TrySeek(this.sesid, this.dataTable, grbit))
                {
                    return(false);
                }
            }
            else
            {
                Api.MoveBeforeFirst(this.sesid, this.dataTable);
                if (!Api.TryMoveNext(this.sesid, this.dataTable))
                {
                    return(false);
                }
            }

            if (null != range.Max)
            {
                if (range.Max.IsPrefix)
                {
                    this.MakePrefixKey(range.Max.Value);
                }
                else
                {
                    this.MakeKey(range.Max.Value);
                }

                SetIndexRangeGrbit grbit = SetIndexRangeGrbit.RangeUpperLimit | (range.Max.IsInclusive
                                                                                     ? SetIndexRangeGrbit.RangeInclusive
                                                                                     : SetIndexRangeGrbit.None);
                return(Api.TrySetIndexRange(this.sesid, this.dataTable, grbit));
            }

            return(true);
        }
Example #7
0
        /// <summary>
        /// Compare two key ranges to see if they are equal.
        /// </summary>
        /// <param name="other">The key range to compare against.</param>
        /// <returns>True if they are equal, false otherwise.</returns>
        public bool Equals(KeyRange <T> other)
        {
            if (null == other)
            {
                return(false);
            }

            // All empty ranges are equal
            if (this.IsEmpty && other.IsEmpty)
            {
                return(true);
            }

            bool minIsEqual = (null == this.Min && null == other.Min) ||
                              (null != this.Min && this.Min.Equals(other.Min));
            bool maxIsEqual = (null == this.Max && null == other.Max) ||
                              (null != this.Max && this.Max.Equals(other.Max));

            return(minIsEqual && maxIsEqual);
        }
 internal void TraceWhere(KeyRange <TKey> range, bool isReversed)
 {
     Trace.WriteLineIf(this.traceSwitch.TraceVerbose, string.Format(CultureInfo.InvariantCulture, "WHERE: {0} {1}", range, isReversed ? "(reversed)" : string.Empty));
 }