<commit_before>﻿using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace JotunShard.Extensions
{
    public static class Enumerables
    {
        private const uint
            FNV_OFFSET_BASIS = 2166136261u,
            FNV_PRIME = 16777619u;

        // TryFind

        public static bool HasCount<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            int count)
        {
            source.CheckArgumentNull(nameof(source));
            count.CheckArgumentIsGreaterOrEqual(nameof(count), 0);
            if (source is ICollection<TElem> coll)
                return coll.Count == count;
            var index = 0;
            foreach (var item in source)
                if (index++ >= count)
                    break;
            return index == count;
        }

        public static IEnumerable<IReadOnlyCollection<TElem>> PartitionIf<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            [NotNull] Func<int, TElem, bool> partitioner,
            Func<IList<TElem>, IReadOnlyCollection<TElem>> partitionProvider = null)
        {
            IReadOnlyCollection<TElem> Iterator(
                IEnumerator<TElem> enmrtr)
            {
                var partition = new List<TElem>();
                var index = 0;
                TElem item;
                do
                {
                    partition.Add(item = enmrtr.Current);
                } while (partitioner(++index, item) && enmrtr.MoveNext());
                return partitionProvider(partition);
            }

            source.CheckArgumentNull(nameof(source));
            partitioner.CheckArgumentNull(nameof(partitioner));
            partitionProvider = partitionProvider
                ?? (list => new ReadOnlyCollection<TElem>(list));
            using (var enmrtr = source.GetEnumerator())
                while (enmrtr.MoveNext())
                    yield return Iterator(enmrtr);
        }

        public static IEnumerable<IReadOnlyCollection<TElem>> PartitionBy<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            int count,
            Func<IList<TElem>, IReadOnlyCollection<TElem>> partitionProvider = null)
        {
            source.CheckArgumentNull(nameof(source));
            count.CheckArgumentIsGreater(nameof(count), 0);
            return source.PartitionIf(
                (index, item) => index < count,
                partitionProvider);
        }

        public static IEnumerable<TElem> Flatten<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            [NotNull] Func<TElem, IEnumerable<TElem>> provider,
            TreeTraversalMode mode = TreeTraversalMode.Depth)
        {
            source.CheckArgumentNull(nameof(source));
            provider.CheckArgumentNull(nameof(provider));
            switch (mode)
            {
                case TreeTraversalMode.Depth:
                    foreach (var item in source)
                    {
                        yield return item;
                        foreach (var subItem in provider(item)
                            .Flatten(provider, mode))
                            yield return subItem;
                    }
                    break;

                case TreeTraversalMode.Breadth:
                    foreach (var item in source)
                        yield return item;
                    foreach (var item in source)
                        foreach (var subItem in provider(item)
                            .Flatten(provider, mode))
                            yield return subItem;
                    break;
            }
        }

        public static IEnumerable<TElem> Flatten<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            TreeTraversalMode mode = TreeTraversalMode.Depth)
            where TElem : IEnumerable<TElem>
        => source.Flatten(c => c, mode);

        public static IEnumerable<TElem> Cycle<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            int? repeat = null)
        {
            source.CheckArgumentNull(nameof(source));
            repeat?.CheckArgumentIsGreaterOrEqual(nameof(repeat), 0);
            if (!source.Any() || repeat == 0)
                yield break;
            var index = 0;
            while (!repeat.HasValue || index++ < repeat)
                foreach (var item in source)
                    yield return item;
        }

        public static IEnumerable<TElem> ToShuffled<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            Func<int, int, int> randomSource = null,
            Func<IList<TElem>, IEnumerable<TElem>> resultProvider = null)
        {
            source.CheckArgumentNull(nameof(source));
            randomSource = randomSource ?? new Random().Next;
            resultProvider = resultProvider
                ?? (list => new ReadOnlyCollection<TElem>(list));
            var result = new List<TElem>();
            foreach (var item in source)
            {
                var index = randomSource(0, result.Count + 1);
                if (index == result.Count)
                    result.Add(item);
                else
                {
                    result.Add(result[index]);
                    result[index] = item;
                }
            }
            return resultProvider(result);
        }

        public static TElem GetRandom<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            Func<int, int> randomSource = null)
        {
            source.CheckArgumentNull(nameof(source));
            randomSource = randomSource ?? new Random().Next;
            return source.ElementAt(randomSource(source.Count()));
        }

        public static bool TryGetFirst<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            [NotNull] Func<TElem, bool> predicate,
            out TElem firstItem)
        {
            source.CheckArgumentNull(nameof(source));<commit_msg>* Renaming of PartionIf's Iterator to PartitionBuilder to be more sensible * Removal of overall System.Collections.ObjectModel import<commit_after>﻿using JetBrains.Annotations;
using System;
using System.Collections.Generic;

using System.Linq;

namespace JotunShard.Extensions
{
    public static class Enumerables
    {
        private const uint
            FNV_OFFSET_BASIS = 2166136261u,
            FNV_PRIME = 16777619u;

        // TryFind

        public static bool HasCount<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            int count)
        {
            source.CheckArgumentNull(nameof(source));
            count.CheckArgumentIsGreaterOrEqual(nameof(count), 0);
            if (source is ICollection<TElem> coll)
                return coll.Count == count;
            var index = 0;
            foreach (var item in source)
                if (index++ >= count)
                    break;
            return index == count;
        }

        public static IEnumerable<IReadOnlyCollection<TElem>> PartitionIf<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            [NotNull] Func<int, TElem, bool> partitioner,
            Func<IList<TElem>, IReadOnlyCollection<TElem>> partitionProvider = null)
        {
            IReadOnlyCollection<TElem> PartitionBuilder(
                IEnumerator<TElem> enmrtr)
            {
                var partition = new List<TElem>();
                var index = 0;
                TElem item;
                do
                {
                    partition.Add(item = enmrtr.Current);
                } while (partitioner(++index, item) && enmrtr.MoveNext());
                return partitionProvider(partition);
            }

            source.CheckArgumentNull(nameof(source));
            partitioner.CheckArgumentNull(nameof(partitioner));
            partitionProvider = partitionProvider
                ?? (list => new System.Collections.ObjectModel.ReadOnlyCollection<TElem>(list));
            using (var enmrtr = source.GetEnumerator())
                while (enmrtr.MoveNext())
                    yield return PartitionBuilder(enmrtr);
        }

        public static IEnumerable<IReadOnlyCollection<TElem>> PartitionBy<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            int count,
            Func<IList<TElem>, IReadOnlyCollection<TElem>> partitionProvider = null)
        {
            source.CheckArgumentNull(nameof(source));
            count.CheckArgumentIsGreater(nameof(count), 0);
            return source.PartitionIf(
                (index, item) => index < count,
                partitionProvider);
        }

        public static IEnumerable<TElem> Flatten<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            [NotNull] Func<TElem, IEnumerable<TElem>> provider,
            TreeTraversalMode mode = TreeTraversalMode.Depth)
        {
            source.CheckArgumentNull(nameof(source));
            provider.CheckArgumentNull(nameof(provider));
            switch (mode)
            {
                case TreeTraversalMode.Depth:
                    foreach (var item in source)
                    {
                        yield return item;
                        foreach (var subItem in provider(item)
                            .Flatten(provider, mode))
                            yield return subItem;
                    }
                    break;

                case TreeTraversalMode.Breadth:
                    foreach (var item in source)
                        yield return item;
                    foreach (var item in source)
                        foreach (var subItem in provider(item)
                            .Flatten(provider, mode))
                            yield return subItem;
                    break;
            }
        }

        public static IEnumerable<TElem> Flatten<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            TreeTraversalMode mode = TreeTraversalMode.Depth)
            where TElem : IEnumerable<TElem>
        => source.Flatten(c => c, mode);

        public static IEnumerable<TElem> Cycle<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            int? repeat = null)
        {
            source.CheckArgumentNull(nameof(source));
            repeat?.CheckArgumentIsGreaterOrEqual(nameof(repeat), 0);
            if (!source.Any() || repeat == 0)
                yield break;
            var index = 0;
            while (!repeat.HasValue || index++ < repeat)
                foreach (var item in source)
                    yield return item;
        }

        public static IEnumerable<TElem> ToShuffled<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            Func<int, int, int> randomSource = null,
            Func<IList<TElem>, IEnumerable<TElem>> resultProvider = null)
        {
            source.CheckArgumentNull(nameof(source));
            randomSource = randomSource ?? new Random().Next;
            resultProvider = resultProvider
                ?? (list => new System.Collections.ObjectModel.ReadOnlyCollection<TElem>(list));
            var result = new List<TElem>();
            foreach (var item in source)
            {
                var index = randomSource(0, result.Count + 1);
                if (index == result.Count)
                    result.Add(item);
                else
                {
                    result.Add(result[index]);
                    result[index] = item;
                }
            }
            return resultProvider(result);
        }

        public static TElem GetRandom<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            Func<int, int> randomSource = null)
        {
            source.CheckArgumentNull(nameof(source));
            randomSource = randomSource ?? new Random().Next;
            return source.ElementAt(randomSource(source.Count()));
        }

        public static bool TryGetFirst<TElem>(
            [NotNull] this IEnumerable<TElem> source,
            [NotNull] Func<TElem, bool> predicate,
            out TElem firstItem)
        {
            source.CheckArgumentNull(nameof(source));
{'fraction_non_alphanumeric': 0.08743973196044783, 'fraction_numerical': 0.004412846285854376, 'mean_word_length': 1.6038297872340426, 'pattern_counts': {'":': 0, '<': 105, '<?xml version=': 0, '>': 113, 'https://': 0, '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': '1339036', 'n_tokens_mistral': 3101, 'n_tokens_neox': 2941, 'n_words': 698}