Ejemplo n.º 1
0
        /// <summary>
        /// Constructs a count dictionary, staying mindful of the known number of elements
        /// so that we bail early (returning null) if we detect a count mismatch
        /// </summary>
        private static CountingSet <TKey> TryBuildElementCountsWithKnownCount <TKey>(
            IEnumerator <TKey> elements,
            int remaining,
            IEqualityComparer <TKey> comparer)
        {
            if (remaining == 0)
            {
                // don't build the dictionary at all if nothing should be in it
                return(null);
            }

            const int MaxInitialElementCountsCapacity = 1024;
            var       elementCounts = new CountingSet <TKey>(capacity: Math.Min(remaining, MaxInitialElementCountsCapacity), comparer: comparer);

            elementCounts.Increment(elements.Current);
            while (elements.MoveNext())
            {
                if (--remaining < 0)
                {
                    // too many elements
                    return(null);
                }
                elementCounts.Increment(elements.Current);
            }

            if (remaining > 0)
            {
                // too few elements
                return(null);
            }

            return(elementCounts);
        }
Ejemplo n.º 2
0
        public void RemoveItem_TheSameItemWasAddedTwice_CollectionStillContainsItem()
        {
            CountingSet <object> coll = new CountingSet <object>();

            object item = new object();

            coll.Add(item);
            coll.Add(item);

            coll.Remove(item);

            Assert.IsTrue(coll.Contains(item));
        }
Ejemplo n.º 3
0
        public void RemoveItemTwice_TheSameItemWasAddedTwice_CollectionDoesntContainItem()
        {
            CountingSet <object> coll = new CountingSet <object>();

            object item = new object();

            coll.Add(item);
            coll.Add(item);

            coll.Remove(item);
            coll.Remove(item);

            Assert.IsFalse(coll.Contains(item));
        }
        private static IUnsafeMarshaller <CountingSet <string> > CreateMarshaller()
        {
            return(new UniversalMarshaller <CountingSet <string> >(reader =>
            {
                var count = reader.ReadInt32();
                var set = new CountingSet <string>(count);
                for (int i = 0; i < count; i++)
                {
                    set.Add(reader.ReadString(), reader.ReadInt32());
                }

                return set;
            },
                                                                   (writer, value) =>
            {
                writer.Write(value.Count);
                foreach (var(item, count) in value)
                {
                    writer.Write(item);
                    writer.Write(count);
                }
            }));
Ejemplo n.º 5
0
        /// <summary>
        /// Determines whether <paramref name="this"/> and <paramref name="that"/> are equal in the sense of having the exact same
        /// elements. Unlike <see cref="Enumerable.SequenceEqual{TSource}(IEnumerable{TSource}, IEnumerable{TSource})"/>,
        /// this method disregards order. Unlike <see cref="ISet{T}.SetEquals(IEnumerable{T})"/>, this method does not disregard duplicates.
        /// An optional <paramref name="comparer"/> allows the equality semantics for the elements to be specified
        /// </summary>
        public static bool CollectionEquals <TElement>(this IEnumerable <TElement> @this, IEnumerable <TElement> that, IEqualityComparer <TElement> comparer = null)
        {
            if (@this == null)
            {
                throw new ArgumentNullException(nameof(@this));
            }
            if (that == null)
            {
                throw new ArgumentNullException(nameof(that));
            }

            // FastCount optimization: If both of the collections are materialized and have counts,
            // we can exit very quickly if those counts differ
            int  thisCount, thatCount;
            var  hasThisCount = TryFastCount(@this, out thisCount);
            bool hasThatCount;

            if (hasThisCount)
            {
                hasThatCount = TryFastCount(that, out thatCount);
                if (hasThatCount)
                {
                    if (thisCount != thatCount)
                    {
                        return(false);
                    }
                    if (thisCount == 0)
                    {
                        return(true);
                    }
                }
            }
            else
            {
                hasThatCount = false;
            }

            var cmp = comparer ?? EqualityComparer <TElement> .Default;

            var itemsEnumerated = 0;

            // SequenceEqual optimization: we reduce/avoid hashing
            // the collections have common prefixes, at the cost of only one
            // extra Equals() call in the case where the prefixes are not common
            using (var thisEnumerator = @this.GetEnumerator())
                using (var thatEnumerator = that.GetEnumerator())
                {
                    while (true)
                    {
                        var thisFinished = !thisEnumerator.MoveNext();
                        var thatFinished = !thatEnumerator.MoveNext();

                        if (thisFinished)
                        {
                            // either this shorter than that, or the two were sequence-equal
                            return(thatFinished);
                        }
                        if (thatFinished)
                        {
                            // that shorter than this
                            return(false);
                        }

                        // keep track of this so that we can factor it into count-based
                        // logic below
                        ++itemsEnumerated;

                        if (!cmp.Equals(thisEnumerator.Current, thatEnumerator.Current))
                        {
                            break; // prefixes were not equal
                        }
                    }

                    // now, build a dictionary of item => count out of one collection and then
                    // probe it with the other collection to look for mismatches

                    // Build/Probe Choice optimization: if we know the count of one collection, we should
                    // use the other collection to build the dictionary. That way we can bail immediately if
                    // we see too few or too many items
                    CountingSet <TElement> elementCounts;
                    IEnumerator <TElement> probeSide;
                    if (hasThisCount)
                    {
                        // we know this's count => use that as the build side
                        probeSide = thisEnumerator;
                        var remaining = thisCount - itemsEnumerated;
                        if (hasThatCount)
                        {
                            // if we have both counts, that means they must be equal or we would have already
                            // exited. However, in this case, we know exactly the capacity needed for the dictionary
                            // so we can avoid resizing
                            elementCounts = new CountingSet <TElement>(capacity: remaining, comparer: cmp);
                            do
                            {
                                elementCounts.Increment(thatEnumerator.Current);
                            }while (thatEnumerator.MoveNext());
                        }
                        else
                        {
                            elementCounts = TryBuildElementCountsWithKnownCount(thatEnumerator, remaining, cmp);
                        }
                    }
                    else if (TryFastCount(that, out thatCount))
                    {
                        // we know that's count => use this as the build side
                        probeSide = thatEnumerator;
                        var remaining = thatCount - itemsEnumerated;
                        elementCounts = TryBuildElementCountsWithKnownCount(thisEnumerator, remaining, cmp);
                    }
                    else
                    {
                        // when we don't know either count, just use that as the build side arbitrarily
                        probeSide     = thisEnumerator;
                        elementCounts = new CountingSet <TElement>(cmp);
                        do
                        {
                            elementCounts.Increment(thatEnumerator.Current);
                        }while (thatEnumerator.MoveNext());
                    }

                    // check whether we failed to construct a dictionary. This happens when we know
                    // one of the counts and we detect, during construction, that the counts are unequal
                    if (elementCounts == null)
                    {
                        return(false);
                    }

                    // probe the dictionary with the probe side enumerator
                    do
                    {
                        if (!elementCounts.TryDecrement(probeSide.Current))
                        {
                            // element in probe not in build => not equal
                            return(false);
                        }
                    }while (probeSide.MoveNext());

                    // we are equal only if the loop above completely cleared out the dictionary
                    return(elementCounts.IsEmpty);
                }
        }