public void ContainsSpeedTest()
        {
            // on my PC you can run 400000 contains lookups in 10ms with lots of other things running at the same time
            int l = chars.Length;
            TestUtility.AssertExecutionTimeIsLessThan(() => { for (int i = 0; i < 400000; i++) cache.Contains(chars[i % l]);  }, 10);

            l = 1000;
            var c2 = new FastLookupCache<int>(l);
            for (int i = 0; i < c2.MaxCapacity; i++)
                c2.Enqueue(i);

            // for a much larger cache we should get approx. the same timing
            TestUtility.AssertExecutionTimeIsLessThan(() => { for (int i = 0; i < 400000; i++) c2.Contains(i % l); }, 10);
        }
        public void Parse(Stream stream, Action <BracketPipeTextFragment> callback)
        {
            bool skip = false;

            if (Distinct)
            {
                cache = new FastLookupCache <string>(CacheSize);
            }
            else
            {
                cache = null;
            }

            var filter = GetFilter(Filter);

            if (filter == null)
            {
                throw new FetchoException("{0} is an invalid filter type", Filter);
            }

            var tag = new Stack <string>();

            using (var reader = new HtmlReader(stream))
            {
                foreach (var c in reader)
                {
                    switch (c.Type)
                    {
                    case HtmlTokenType.StartTag:
                        if (c.Value == ScriptHtmlTag)
                        {
                            skip = true;
                        }
                        if (c.Value == StyleHtmlTag)
                        {
                            skip = true;
                        }
                        tag.Push(c.Value);
                        break;

                    case HtmlTokenType.EndTag:
                        if (c.Value == ScriptHtmlTag)
                        {
                            skip = false;
                        }
                        if (c.Value == StyleHtmlTag)
                        {
                            skip = false;
                        }
                        if (tag.Count > 0)
                        {
                            tag.Pop();
                        }
                        break;

                    default:
                        break;
                    }

                    if (!skip && c.Type == HtmlTokenType.Text)
                    {
                        if (c.Value.Length.IsBetween(MinimumLength, MaximumLength))
                        {
                            if (cache == null || !cache.Contains(c.Value))
                            {
                                cache?.Enqueue(c.Value);
                                string tagvalue = string.Empty;
                                if (tag.Count > 0)
                                {
                                    tagvalue = tag.Peek();
                                }
                                var fragment = new BracketPipeTextFragment(tagvalue, c.Value);
                                if (filter(fragment))
                                {
                                    callback(fragment);
                                }
                            }
                        }
                    }
                }
            }
        }
 public void Setup()
 {
     cache = new FastLookupCache<char>(10);
     for (int i = 0; i < 10; i++)
         cache.Enqueue(chars[i]);
 }