private IEnumerable <LoggedBinaryReaderRegion> Merge([NotNull] IEnumerable <LoggedBinaryReaderRegion> regions)
        {
            using (IEnumerator <LoggedBinaryReaderRegion> e = regions.GetEnumerator())
            {
                if (!e.MoveNext())
                {
                    yield break;
                }

                long origin = e.Current.Position;
                long ending = e.Current.Position + e.Current.Length;

                while (e.MoveNext())
                {
                    LoggedBinaryReaderRegion current = e.Current;
                    long currentPos = current.Position;
                    long currentLen = current.Length;

                    if (currentPos > ending)
                    {
                        yield return(new LoggedBinaryReaderRegion(origin, ending - origin));

                        origin = currentPos;
                        ending = currentPos + currentLen;
                    }
                    else
                    {
                        ending = Math.Max(currentPos + currentLen, ending);
                    }
                }

                yield return(new LoggedBinaryReaderRegion(origin, ending - origin));
            }
        }
        internal void EndGroupInternal()
        {
            if (Group == -1)
            {
                throw new InvalidOperationException($"A previous call to {nameof(BeginGroup)} has not been disposed.");
            }

            LoggedBinaryReaderRegion[] regions1 = Journal.Skip(Group).ToArray();
            LoggedBinaryReaderRegion[] regions2 = Merge(regions1).ToArray();

            if (regions2.Length > 1)
            {
                throw new NotSupportedException("Region grouping only supports consecutive regions.");
            }

            int count = Journal.Count - Group;

            for (int i = 0; i < count; i++)
            {
                Journal.RemoveAt(Journal.Count - 1);
            }

            LoggedBinaryReaderRegion region = regions2.First();

            Journal.Add(region);

            Group = -1;
        }
        /// <summary>
        ///     Gets the regions that haven't been read.
        /// </summary>
        /// <returns>
        ///     The unread regions.
        /// </returns>
        public IEnumerable <LoggedBinaryReaderRegion> GetUnreadRegions()
        {
            IEnumerable <LoggedBinaryReaderRegion> regions = Journal.GetOrderedRegions();

            using (IEnumerator <LoggedBinaryReaderRegion> e = regions.GetEnumerator())
            {
                // nothing at all
                if (!e.MoveNext())
                {
                    yield return(new LoggedBinaryReaderRegion(0, BaseStream.Length));

                    yield break;
                }

                LoggedBinaryReaderRegion first = e.Current;

                // beginning of file
                if (first.Position > 0)
                {
                    yield return(new LoggedBinaryReaderRegion(0, first.Position));
                }

                // middle of file
                while (e.MoveNext())
                {
                    LoggedBinaryReaderRegion second = e.Current;
                    long secondPos = first.Position + first.Length;
                    long secondLen = second.Position - secondPos;

                    if (secondLen > 0)
                    {
                        yield return(new LoggedBinaryReaderRegion(secondPos, secondLen));
                    }

                    first = second;
                }

                // end of file
                long thirdPos = first.Position + first.Length;
                long thirdLen = BaseStream.Length - thirdPos;
                if (thirdPos < BaseStream.Length)
                {
                    yield return(new LoggedBinaryReaderRegion(thirdPos, thirdLen));
                }
            }
        }