<commit_before>﻿// Copyright (c) Narvalo.Org. All rights reserved. See LICENSE.txt in the project root for license information.

namespace Narvalo.Fx
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;

    /// <summary>
    /// Provides extension methods for <see cref="IEnumerable{T}"/>.
    /// </summary>
    public static partial class EnumerableExtensions
    {
        // Useful when using built-in LINQ operators. Even if it is not publicly visible,
        // I believe that all LINQ operators never return a null but rather an empty sequence if needed.
        public static IEnumerable<TSource> EmptyIfNull<TSource>(this IEnumerable<TSource> @this)
        {
            Warrant.NotNull<IEnumerable<TSource>>();

            if (@this == null)
            {
                return Enumerable.Empty<TSource>();
            }

            return @this;
        }

        public static bool IsEmpty<TSource>(this IEnumerable<TSource> @this)
        {
            Expect.NotNull(@this);

            return !@this.Any();
        }

        #region Element Operators

        // Named <c>listToMaybe</c> in Haskell parlance.
        public static Maybe<TSource> FirstOrNone<TSource>(this IEnumerable<TSource> @this)
        {
            Expect.NotNull(@this);

            return FirstOrNone(@this, Stubs<TSource>.AlwaysTrue);
        }

        public static Maybe<TSource> FirstOrNone<TSource>(
            this IEnumerable<TSource> @this,
            Func<TSource, bool> predicate)
        {
            Require.NotNull(@this, nameof(@this));
            Require.NotNull(predicate, nameof(predicate));

            IEnumerable<Maybe<TSource>> seq
                = from t in @this where predicate.Invoke(t) select Maybe.Of(t);

            using (var iter = seq.EmptyIfNull().GetEnumerator())
            {
                var current = iter.Current;

                return iter.MoveNext() ? current : Maybe<TSource>.None;
            }
        }

        public static Maybe<TSource> LastOrNone<TSource>(this IEnumerable<TSource> @this)
        {
            Expect.NotNull(@this);

            return LastOrNone(@this, Stubs<TSource>.AlwaysTrue);
        }

        public static Maybe<TSource> LastOrNone<TSource>(this IEnumerable<TSource> @this, Func<TSource, bool> predicate)
        {
            Require.NotNull(@this, nameof(@this));
            Require.NotNull(predicate, nameof(predicate));

            return @this.Reverse().EmptyIfNull().FirstOrNone();
        }

        public static Maybe<TSource> SingleOrNone<TSource>(this IEnumerable<TSource> @this)
        {
            Expect.NotNull(@this);

            return SingleOrNone(@this, Stubs<TSource>.AlwaysTrue);
        }

        public static Maybe<TSource> SingleOrNone<TSource>(
            this IEnumerable<TSource> @this,
            Func<TSource, bool> predicate)
        {
            Require.NotNull(@this, nameof(@this));
            Require.NotNull(predicate, nameof(predicate));

            IEnumerable<Maybe<TSource>> seq
                = from t in @this where predicate.Invoke(t) select Maybe.Of(t);

            using (var iter = seq.EmptyIfNull().GetEnumerator())
            {
                var current = iter.Current;

                var result = iter.MoveNext() ? current : Maybe<TSource>.None;

                // Return Maybe.None if there is one more element.
                return iter.MoveNext() ? Maybe<TSource>.None : result;
            }
        }

        #endregion

        #region Concatenation Operators

        // There is a much better implementation coming soon (?).
        // https://github.com/dotnet/corefx/commits/master/src/System.Linq/src/System/Linq/AppendPrepend.cs
        // REVIEW: Since this method is a critical component of Collect(), we could import this
        // until it is publicly available.
        public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> @this, TSource element)
        {
            Expect.NotNull(@this);
            Warrant.NotNull<IEnumerable<TSource>>();

            return @this.Concat(Sequence.Pure(element)).EmptyIfNull();
        }

        // See remarks for Append.
        public static IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> @this, TSource element)
        {
            Expect.NotNull(@this);
            Warrant.NotNull<IEnumerable<TSource>>();

            return Sequence.Pure(element).Concat(@this).EmptyIfNull();
        }

        #endregion

        #region Conversion Operators

        public static ICollection<TSource> ToCollection<TSource>(this IEnumerable<TSource> @this)
        {
            Require.NotNull(@this, nameof(@this));
            Warrant.NotNull<ICollection<TSource>>();

            var retval = new Collection<TSource>();

            foreach (TSource item in @this)
            {
                retval.Add(item);
            }

            return retval;
        }

        #endregion

        #region Aggregate Operators

        public static TAccumulate AggregateBack<TSource, TAccumulate>(
            this IEnumerable<TSource> @this,
            TAccumulate seed,
            Func<TAccumulate, TSource, TAccumulate> accumulator)
        {
            Expect.NotNull(@this);
            Expect.NotNull(accumulator);<commit_msg>Disable ToCollection() + perf improvement.<commit_after>﻿// Copyright (c) Narvalo.Org. All rights reserved. See LICENSE.txt in the project root for license information.

namespace Narvalo.Fx
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;

    /// <summary>
    /// Provides extension methods for <see cref="IEnumerable{T}"/>.
    /// </summary>
    public static partial class EnumerableExtensions
    {
        // Useful when using built-in LINQ operators. Even if it is not publicly visible,
        // I believe that all LINQ operators never return a null but rather an empty sequence if needed.
        public static IEnumerable<TSource> EmptyIfNull<TSource>(this IEnumerable<TSource> @this)
        {
            Warrant.NotNull<IEnumerable<TSource>>();

            if (@this == null)
            {
                return Enumerable.Empty<TSource>();
            }

            return @this;
        }

        public static bool IsEmpty<TSource>(this IEnumerable<TSource> @this)
        {
            Expect.NotNull(@this);

            return !@this.Any();
        }

        #region Element Operators

        // Named <c>listToMaybe</c> in Haskell parlance.
        public static Maybe<TSource> FirstOrNone<TSource>(this IEnumerable<TSource> @this)
        {
            Expect.NotNull(@this);

            return FirstOrNone(@this, Stubs<TSource>.AlwaysTrue);
        }

        public static Maybe<TSource> FirstOrNone<TSource>(
            this IEnumerable<TSource> @this,
            Func<TSource, bool> predicate)
        {
            Require.NotNull(@this, nameof(@this));
            Require.NotNull(predicate, nameof(predicate));

            var seq = from t in @this where predicate.Invoke(t) select t;

            using (var iter = seq.EmptyIfNull().GetEnumerator())
            {
                var current = Maybe.Of(iter.Current);

                return iter.MoveNext() ? current : Maybe<TSource>.None;
            }
        }

        public static Maybe<TSource> LastOrNone<TSource>(this IEnumerable<TSource> @this)
        {
            Expect.NotNull(@this);

            return LastOrNone(@this, Stubs<TSource>.AlwaysTrue);
        }

        public static Maybe<TSource> LastOrNone<TSource>(this IEnumerable<TSource> @this, Func<TSource, bool> predicate)
        {
            Require.NotNull(@this, nameof(@this));
            Require.NotNull(predicate, nameof(predicate));

            return @this.Reverse().EmptyIfNull().FirstOrNone();
        }

        public static Maybe<TSource> SingleOrNone<TSource>(this IEnumerable<TSource> @this)
        {
            Expect.NotNull(@this);

            return SingleOrNone(@this, Stubs<TSource>.AlwaysTrue);
        }

        public static Maybe<TSource> SingleOrNone<TSource>(
            this IEnumerable<TSource> @this,
            Func<TSource, bool> predicate)
        {
            Require.NotNull(@this, nameof(@this));
            Require.NotNull(predicate, nameof(predicate));

            var seq = from t in @this where predicate.Invoke(t) select t;

            using (var iter = seq.EmptyIfNull().GetEnumerator())
            {
                var current = iter.Current;

                // Return None if the sequence is empty.
                var result = iter.MoveNext() ? Maybe.Of(current) : Maybe<TSource>.None;

                // Return None if there is one more element.
                return iter.MoveNext() ? Maybe<TSource>.None : result;
            }
        }

        #endregion

        #region Concatenation Operators

        // There is a much better implementation coming soon (?).
        // https://github.com/dotnet/corefx/commits/master/src/System.Linq/src/System/Linq/AppendPrepend.cs
        // REVIEW: Since this method is a critical component of Collect(), we could import this
        // until it is publicly available.
        public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> @this, TSource element)
        {
            Expect.NotNull(@this);
            Warrant.NotNull<IEnumerable<TSource>>();

            return @this.Concat(Sequence.Pure(element)).EmptyIfNull();
        }

        // See remarks for Append.
        public static IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> @this, TSource element)
        {
            Expect.NotNull(@this);
            Warrant.NotNull<IEnumerable<TSource>>();

            return Sequence.Pure(element).Concat(@this).EmptyIfNull();
        }

        #endregion

        //#region Conversion Operators

        //public static ICollection<TSource> ToCollection<TSource>(this IEnumerable<TSource> @this)
        //{
        //    Require.NotNull(@this, nameof(@this));
        //    Warrant.NotNull<ICollection<TSource>>();

        //    var retval = new Collection<TSource>();

        //    foreach (TSource item in @this)
        //    {
        //        retval.Add(item);
        //    }

        //    return retval;
        //}

        //#endregion

        #region Aggregate Operators

        public static TAccumulate AggregateBack<TSource, TAccumulate>(
            this IEnumerable<TSource> @this,
            TAccumulate seed,
            Func<TAccumulate, TSource, TAccumulate> accumulator)
        {
            Expect.NotNull(@this);
            Expect.NotNull(accumulator);
{'fraction_non_alphanumeric': 0.10701656430299647, 'fraction_numerical': 0.0, 'mean_word_length': 2.054860716316089, 'pattern_counts': {'":': 0, '<': 125, '<?xml version=': 0, '>': 125, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6486057', 'n_tokens_mistral': 2950, 'n_tokens_neox': 2807, 'n_words': 675}