4#include <system/collections/ienumerable.h>
5#include <system/linq/iordered_enumerable.h>
6#include <system/collections/list.h>
7#include <system/collections/dictionary.h>
8#include <system/array.h>
9#include <system/constraints.h>
10#include <system/object_ext.h>
11#include <system/exceptions.h>
12#include <system/details/equality_helper.h>
13#include <system/details/cast_rules.h>
14#include <system/default.h>
17namespace System {
namespace Linq {
31 throw InvalidOperationException(u
"Collection is empty");
43 System::Details::VirtualizedIteratorBase<T>*
CloneIterator()
const override
59 static const auto enumerator = MakeObject<EmptyEnumerator<T>>();
67template<
typename TItem>
73 template<
typename TEnumeratorItem>
79 return cachedEnumerable->items->data()[position];
82 CachedEnumerator(
System::SharedPtr<CachedEnumerable<TEnumeratorItem>> cachedEnumerable) : position(-1)
84 this->cachedEnumerable = cachedEnumerable;
87 void Dispose()
override
92 bool MoveNext()
override
95 return cachedEnumerable->items->get_Count() > position || cachedEnumerable->requestNext();
103 System::Details::VirtualizedIteratorBase<TEnumeratorItem>* CloneIterator()
const override
105 return new CachedEnumerator(*
this);
118 items = System::MakeObject<System::Collections::Generic::List<TItem>>();
143 template <
typename T>
146 static const auto enumerable = MakeObject<Details::EmptyEnumerable<T>>();
159namespace System {
namespace Collections {
namespace Generic {
171T TryGetFirst(IEnumerable<T>& enumerable,
bool& found)
175 const auto count = list->get_Count();
179 return list->idx_get(0);
184 const auto enumerator = enumerable.GetEnumerator();
185 if (enumerator->MoveNext())
188 return enumerator->get_Current();
204T TryGetFirst(IEnumerable<T>& enumerable,
const Func<T, bool>& predicate,
bool& found)
206 if (predicate ==
nullptr)
207 throw ArgumentNullException(u
"predicate");
209 const auto enumerator = enumerable.GetEnumerator();
210 while (enumerator->MoveNext())
212 T value = enumerator->get_Current();
213 if (predicate(value))
231T TryGetLast(IEnumerable<T>& enumerable,
bool& found)
233 if (IList<T>* list =
dynamic_cast<IList<T>*
>(&enumerable))
235 const auto count = list->get_Count();
239 return list->idx_get(count - 1);
244 const auto enumerator = enumerable.GetEnumerator();
245 if (enumerator->MoveNext())
250 value = enumerator->get_Current();
251 }
while (enumerator->MoveNext());
264template <
typename Source,
typename Result>
265class EnumeratorCastAdapter final :
public IEnumerator<Result>
268 EnumeratorCastAdapter(
SharedPtr<IEnumerator<Source>> sourceEnumerator)
269 : m_sourceEnumerator(sourceEnumerator)
272 MakeConstRef_t<Result>
get_Current()
const override
274 m_current = CastRules::Cast<Source, Result>(m_sourceEnumerator->get_Current());
280 return m_sourceEnumerator->MoveNext();
283 void Reset()
override
285 m_sourceEnumerator->Reset();
288 System::Details::VirtualizedIteratorBase<Result>*
CloneIterator()
const override
290 return new EnumeratorCastAdapter(*
this);
294 SharedPtr<IEnumerator<Source>> m_sourceEnumerator;
295 mutable Result m_current;
301template <
typename Source,
typename Result>
302class EnumeratorOfTypeAdapter final :
public IEnumerator<Result>
305 EnumeratorOfTypeAdapter(
SharedPtr<IEnumerator<Source>> sourceEnumerator)
306 : m_sourceEnumerator(sourceEnumerator)
309 MakeConstRef_t<Result>
get_Current()
const override
311 m_current = CastRules::Cast<Source, Result>(m_sourceEnumerator->get_Current());
317 while (m_sourceEnumerator->MoveNext())
319 if (CastRules::CanCast<Source, Result>(m_sourceEnumerator->get_Current()))
323 m_current = System::Default<Result>();
327 void Reset()
override
329 m_sourceEnumerator->Reset();
332 System::Details::VirtualizedIteratorBase<Result>*
CloneIterator()
const override
334 return new EnumeratorOfTypeAdapter(*
this);
338 SharedPtr<IEnumerator<Source>> m_sourceEnumerator;
339 mutable Result m_current;
345template <
typename Source,
typename Result>
346class EnumeratorSelectAdapter final :
public IEnumerator<Result>
349 EnumeratorSelectAdapter(
SharedPtr<IEnumerator<Source>> sourceEnumerator,
const Func<Source, Result>& selector)
350 : m_sourceEnumerator(sourceEnumerator)
351 , m_selector(selector)
354 MakeConstRef_t<Result>
get_Current()
const override
356 m_current = m_selector(m_sourceEnumerator->get_Current());
362 return m_sourceEnumerator->MoveNext();
365 void Reset()
override
367 m_sourceEnumerator->Reset();
370 System::Details::VirtualizedIteratorBase<Result>*
CloneIterator()
const override
372 return new EnumeratorSelectAdapter(*
this);
376 SharedPtr<IEnumerator<Source>> m_sourceEnumerator;
377 Func<Source, Result> m_selector;
378 mutable Result m_current;
381template <
typename Source,
typename Result>
382class EnumeratorSelectIndexAdapter final :
public IEnumerator<Result>
385 EnumeratorSelectIndexAdapter(
SharedPtr<IEnumerator<Source>> sourceEnumerator,
const Func<Source, int32_t, Result>& selector)
386 : m_sourceEnumerator(sourceEnumerator), m_selector(selector), index(-1)
389 MakeConstRef_t<Result>
get_Current()
const override
391 m_current = m_selector(m_sourceEnumerator->get_Current(), index);
398 return m_sourceEnumerator->MoveNext();
401 void Reset()
override
404 m_sourceEnumerator->Reset();
407 System::Details::VirtualizedIteratorBase<Result>*
CloneIterator()
const override
409 return new EnumeratorSelectIndexAdapter(*
this);
413 SharedPtr<IEnumerator<Source>> m_sourceEnumerator;
414 Func<Source, int32_t, Result> m_selector;
416 mutable Result m_current;
424template <
typename Source,
typename Result,
typename EnumeratorAdapter>
425class EnumerableAdapter final :
public IEnumerable<Result>
428 EnumerableAdapter(
SharedPtr<IEnumerable<Source>> sourceEnumerable)
429 : m_sourceEnumerable(sourceEnumerable)
434 return MakeObject<EnumeratorAdapter>(m_sourceEnumerable->GetEnumerator());
438 SharedPtr<IEnumerable<Source>> m_sourceEnumerable;
444template <
typename Source,
typename Result>
445class EnumerableSelectAdapter final :
public IEnumerable<Result>
448 EnumerableSelectAdapter(
SharedPtr<IEnumerable<Source>> sourceEnumerable,
const Func<Source, Result>& selector)
449 : m_sourceEnumerable(sourceEnumerable)
450 , m_selector(selector)
455 return MakeObject<EnumeratorSelectAdapter<Source, Result>>(m_sourceEnumerable->GetEnumerator(), m_selector);
459 SharedPtr<IEnumerable<Source>> m_sourceEnumerable;
460 Func<Source, Result> m_selector;
463template <
typename Source,
typename Result>
464class EnumerableSelectIndexAdapter final :
public IEnumerable<Result>
467 EnumerableSelectIndexAdapter(
SharedPtr<IEnumerable<Source>> sourceEnumerable,
const Func<Source, int32_t, Result>& selector)
468 : m_sourceEnumerable(sourceEnumerable), m_selector(selector)
473 return MakeObject<EnumeratorSelectIndexAdapter<Source, Result>>(m_sourceEnumerable->GetEnumerator(), m_selector);
477 SharedPtr<IEnumerable<Source>> m_sourceEnumerable;
478 Func<Source, int32_t, Result> m_selector;
481template <
typename Source,
typename Result>
482class EnumeratorSelectManyAdapter final :
public IEnumerator<Result>
485 EnumeratorSelectManyAdapter(
SharedPtr<IEnumerator<Source>> baseEnumerator,
486 const Func<Source,
SharedPtr<IEnumerable<Result>>>& selector)
487 : m_baseEnumerator(baseEnumerator), m_selector(selector)
490 MakeConstRef_t<Result>
get_Current()
const override
492 return m_nestedEnumerator->get_Current();
497 if (m_nestedEnumerator !=
nullptr)
499 if (m_nestedEnumerator->MoveNext())
505 while (m_baseEnumerator->MoveNext())
507 Source currentSource = m_baseEnumerator->get_Current();
509 m_nestedEnumerator = m_selector(currentSource)->GetEnumerator();
511 if (m_nestedEnumerator->MoveNext())
520 void Reset()
override
522 m_baseEnumerator->Reset();
523 DisposeNestedEnumerator();
526 System::Details::VirtualizedIteratorBase<Result>*
CloneIterator()
const override
528 return new EnumeratorSelectManyAdapter(*
this);
533 void DisposeNestedEnumerator()
535 if (m_nestedEnumerator ==
nullptr)
537 m_nestedEnumerator->Dispose();
538 m_nestedEnumerator =
nullptr;
541 SharedPtr<IEnumerator<Source>> m_baseEnumerator;
542 SharedPtr<IEnumerator<Result>> m_nestedEnumerator;
543 Func<Source, SharedPtr<IEnumerable<Result>>> m_selector;
547template <
typename Source,
typename Result>
548class EnumerableSelectManyAdapter final :
public IEnumerable<Result>
551 EnumerableSelectManyAdapter(
SharedPtr<IEnumerable<Source>> sourceEnumerable,
552 const Func<Source,
SharedPtr<IEnumerable<Result>>>& selector)
553 : m_sourceEnumerable(sourceEnumerable), m_selector(selector)
558 return MakeObject<EnumeratorSelectManyAdapter<Source, Result>>(m_sourceEnumerable->GetEnumerator(),
563 SharedPtr<IEnumerable<Source>> m_sourceEnumerable;
564 Func<Source, SharedPtr<IEnumerable<Result>>> m_selector;
568template <
typename Key,
typename Source>
574 groupCachedEnumerable = System::MakeObject<System::Linq::Details::CachedEnumerable<Source>>(hasNext);
584 return groupCachedEnumerable->GetEnumerator();
587 void Add(Source item)
589 groupCachedEnumerable->Add(item);
598template <
typename Source,
typename Key>
599class GroupEnumerable final :
public IEnumerable<SharedPtr<System::Linq::IGrouping<Key, Source>>>
602 GroupEnumerable(
SharedPtr<IEnumerable<Source>> sourceEnumerable,
const Func<Source, Key>& keyPredicate)
603 : m_sourceEnumerable(sourceEnumerable)
604 , m_keyPredicate(keyPredicate)
606 groups = System::MakeObject<System::Collections::Generic::Dictionary<Key, System::SharedPtr<Grouping<Key, Source>>>>();
607 m_sourceEnumerator = m_sourceEnumerable->GetEnumerator();
610 groupsCachedEnumerable = System::MakeObject<System::Linq::Details::CachedEnumerable<System::SharedPtr<System::Linq::IGrouping<Key, Source>>>>(hasNext);
613 SharedPtr<IEnumerator<SharedPtr<System::Linq::IGrouping<Key, Source>>>>
GetEnumerator()
override
615 return groupsCachedEnumerable->GetEnumerator();
624 if (!m_sourceEnumerator->MoveNext())
628 auto current = m_sourceEnumerator->get_Current();
629 auto key = m_keyPredicate(current);
630 bool isNewGroup = !groups->ContainsKey(key);
631 group = isNewGroup ? System::MakeObject<Grouping<Key, Source>>(key, [
this, key]() {
return FindNextForKey(key); }) : groups->idx_get(key);
635 groups->Add(key, group);
636 groupsCachedEnumerable->Add(group);
647 bool FindNextForKey(Key groupKey)
651 if (!m_sourceEnumerator->MoveNext())
655 auto current = m_sourceEnumerator->get_Current();
656 auto key = m_keyPredicate(current);
657 bool isNewGroup = !groups->ContainsKey(key);
658 group = isNewGroup ? System::MakeObject<Grouping<Key, Source>>(key, [
this, key]() {
return FindNextForKey(key); }) : groups->idx_get(key);
662 groups->Add(key, group);
663 groupsCachedEnumerable->Add(group);
666 if (
Equals(groupKey, key))
678 SharedPtr<IEnumerable<Source>> m_sourceEnumerable;
679 SharedPtr<IEnumerator<Source>> m_sourceEnumerator;
680 Func<Source, Key> m_keyPredicate;
689 auto enumerator = GetEnumerator();
690 if (!enumerator->MoveNext())
692 throw InvalidOperationException(u
"The source sequence is empty");
694 auto result = enumerator->Current();
695 while (enumerator->MoveNext())
697 result = func(result, enumerator->Current());
708 auto enumerator = GetEnumerator();
709 while (enumerator->MoveNext())
713 return enumerator->Current();
719 throw ArgumentOutOfRangeException(u
"index");
727 auto enumerator = GetEnumerator();
728 while (enumerator->MoveNext())
732 return enumerator->Current();
738 return System::Default<T>();
745 T first = Details::TryGetFirst(*
this, found);
747 throw InvalidOperationException(u
"The source sequence is empty");
756 T first = Details::TryGetFirst(*
this, predicate, found);
758 throw InvalidOperationException(u
"No element satisfies the specified condition");
767 return Details::TryGetFirst(*
this, found);
774 T last = Details::TryGetLast(*
this, found);
776 throw InvalidOperationException(u
"The source sequence is empty.");
785 return Details::TryGetLast(*
this, found);
792 auto list = System::MakeObject<Collections::Generic::List<T>>();
793 auto enumerator = GetEnumerator();
794 while (enumerator->MoveNext())
796 list->Add(enumerator->Current());
805 auto enumerator = GetEnumerator();
806 while (enumerator->MoveNext())
816 if (predicate ==
nullptr)
817 throw ArgumentNullException(u
"predicate");
820 auto enumerator = GetEnumerator();
821 while (enumerator->MoveNext())
823 if (predicate(enumerator->get_Current()))
834 return LINQ_ToList()->ToArray();
841 throw ArgumentNullException(u
"predicate");
843 auto enumerator = GetEnumerator();
844 while (enumerator->MoveNext())
845 if (!predicate(enumerator->Current()))
853 auto enumerator = GetEnumerator();
854 if (enumerator->MoveNext())
863 throw ArgumentNullException(u
"predicate");
865 auto enumerator = GetEnumerator();
866 while (enumerator->MoveNext())
867 if (predicate(enumerator->Current()))
876 throw ArgumentNullException(u
"predicate");
878 auto enumerator = GetEnumerator();
879 while (enumerator->MoveNext())
881 T val = enumerator->Current();
892 throw ArgumentNullException(u
"predicate");
894 auto list = System::MakeObject<Collections::Generic::List<T>>();
895 auto enumerator = GetEnumerator();
896 while (enumerator->MoveNext())
898 T val = enumerator->Current();
908 const auto enumerator = GetEnumerator();
909 while (enumerator->MoveNext())
911 if (System::Details::AreEqual(value, enumerator->get_Current()))
917template <
typename Source>
918template <
typename Result>
921 using EnumeratorAdapter = Details::EnumeratorCastAdapter<Source, Result>;
922 using EnumerableAdapter = Details::EnumerableAdapter<Source, Result, EnumeratorAdapter>;
926template <
typename Source>
927template <
typename Result>
930 using EnumeratorAdapter = Details::EnumeratorOfTypeAdapter<Source, Result>;
931 using EnumerableAdapter = Details::EnumerableAdapter<Source, Result, EnumeratorAdapter>;
935template <
typename Source>
936template <
typename Result>
939 if (selector ==
nullptr)
940 throw ArgumentNullException(u
"selector");
942 using EnumerableAdapter = Details::EnumerableSelectAdapter<Source, Result>;
943 return MakeObject<EnumerableAdapter>(
MakeSharedPtr(
this), selector);
946template <
typename Source>
947template <
typename Result>
950 if (selector ==
nullptr)
951 throw ArgumentNullException(u
"selector");
953 using EnumerableAdapter = Details::EnumerableSelectIndexAdapter<Source, Result>;
954 return MakeObject<EnumerableAdapter>(
MakeSharedPtr(
this), selector);
958template <
typename Source>
959template <
typename Key>
963 auto items = LINQ_ToArray();
964 items->Sort(keys, items);
965 return System::MakeObject<Linq::IOrderedEnumerable<Source>>(
967 [keySelector](
const Source& left,
const Source& right) {
return keySelector(left) == keySelector(right); });
970template <
typename Source>
971template <
typename Key>
975 auto items = LINQ_ToArray();
976 items->Sort(keys, items);
977 std::reverse(items->begin(), items->end());
978 return System::MakeObject<Linq::IOrderedEnumerable<Source>>(
980 [keySelector](
const Source& left,
const Source& right) {
return keySelector(left) == keySelector(right); });
983template <
typename Source>
986 auto first = LINQ_ToList();
987 auto second = sequence->LINQ_ToList();
989 first->AddRange(second);
994template <
typename Source>
997 auto items = LINQ_ToArray();
998 std::reverse(items->begin(), items->end());
1002template <
typename Source>
1003template <
typename Key>
1007 if (keyPredicate ==
nullptr)
1008 throw ArgumentNullException(u
"keyPredicate");
1010 using EnumerableAdapter = Details::GroupEnumerable<Source, Key>;
1011 return MakeObject<EnumerableAdapter>(
MakeSharedPtr(
this), keyPredicate);
1014template <
typename Source>
1015template <
typename Result>
1019 if (selector ==
nullptr)
1020 throw ArgumentNullException(u
"selector");
1022 using EnumerableAdapter = Details::EnumerableSelectManyAdapter<Source, Result>;
1023 return MakeObject<EnumerableAdapter>(
MakeSharedPtr(
this), selector);
1026template <
typename Source>
1029 auto result = LINQ_ToList();
1030 auto currentCount = result->get_Count();
1031 if (currentCount > count)
1033 result->RemoveRange(count, currentCount - count);
1038template <
typename Source>
1039template <
typename ResultType>
1042 auto enumerator = GetEnumerator();
1043 if (!enumerator->MoveNext())
1044 throw InvalidOperationException(u
"Collection is empty");
1046 auto result = selector(enumerator->get_Current());
1047 while (enumerator->MoveNext())
1049 auto candidate = selector(enumerator->get_Current());
1050 if (candidate < result)
1057template <
typename Source>
1058template <
typename ResultType>
1061 auto enumerator = GetEnumerator();
1062 if (!enumerator->MoveNext())
1063 throw InvalidOperationException(u
"Collection is empty");
1065 auto result = selector(enumerator->get_Current());
1066 while (enumerator->MoveNext())
1068 auto candidate = selector(enumerator->get_Current());
1069 if (candidate > result)
1078namespace System {
namespace Linq {
1080template <
typename Source>
1081template <
typename Key>
1084 auto items = m_root->LINQ_ToArray();
1086 auto begin = items->begin();
1087 while (begin != items->end())
1089 auto end = std::next(begin);
1090 while (end != items->end() && m_comparator(*begin, *end))
1095 std::stable_sort(begin, end, [&](
const Source& left,
const Source& right){
return keySelector(left) < keySelector(right);});
1100 return System::MakeObject<IOrderedEnumerable<Source>>(
1102 [comp = m_comparator, keySelector](
const Source& left,
const Source& right)
1104 return comp(left, right) && keySelector(left) == keySelector(right);
Interface of object providing enumerator on contained elements.
Definition: ienumerable.h:25
bool LINQ_Contains(T value)
Determines if a sequence contains a specified value.
Definition: enumerable.h:906
T LINQ_ElementAtOrDefault(int index)
Returns the element at a specified index in a sequence.
Definition: enumerable.h:723
bool LINQ_All(std::function< bool(T)> predicate)
Determines whether all elements of a sequence satisfy a condition.
Definition: enumerable.h:838
SharedPtr< IEnumerable< T > > LINQ_Where(std::function< bool(T)> predicate)
Filters a sequence based on the specified predicate.
Definition: enumerable.h:889
T LINQ_LastOrDefault()
Returns the last element of a sequence, or a default value if the sequence is empty.
Definition: enumerable.h:782
bool LINQ_Any()
Determines whether a sequence contains any elements.
Definition: enumerable.h:851
System::ArrayPtr< T > LINQ_ToArray()
Creates an array from a sequence.
Definition: enumerable.h:832
T LINQ_ElementAt(int index)
Returns the element at a specified index in a sequence.
Definition: enumerable.h:704
T LINQ_Aggregate(const Func< T, T, T > &func)
Applies an accumulator function over a sequence.
Definition: enumerable.h:687
T LINQ_FirstOrDefault()
Returns the first element of a sequence, or a default value if the sequence is empty.
Definition: enumerable.h:764
SharedPtr< IEnumerable< ResultType > > LINQ_Cast()
Casts the elements to the specified type.
T LINQ_First()
Returns the first element of a sequence.
Definition: enumerable.h:742
SharedPtr< List< T > > LINQ_ToList()
Creates a List<T> from a sequence.
Definition: enumerable.h:789
virtual SharedPtr< IEnumerator< Result > > GetEnumerator()=0
Gets enumerator.
T LINQ_Last()
Returns the last element of a sequence.
Definition: enumerable.h:771
int LINQ_Count()
Returns the number of elements in the sequence (calculated via direct counting).
Definition: enumerable.h:802
Interface of enumerator which can be used to iterate through some elements. Objects of this class sho...
Definition: ienumerator.h:63
virtual MakeConstRef_t< Result > get_Current() const=0
Gets current element.
virtual bool MoveNext()=0
Moves enumerator to the next element. If no element was referenced before, sets reference to the firs...
System::Details::VirtualizedIteratorBase< Result > * CloneIterator() const override
Clones current iterator.
Definition: ienumerator.h:129
virtual void Reset()
Resets enumerator to position before first element.
Definition: ienumerator.h:97
Interface of indexed container of elements. Objects of this class should only be allocated using Syst...
Definition: ilist.h:19
Internal utility class Implements IEnumerable over queue of items.
Definition: enumerable.h:69
void Add(TItem item)
Definition: enumerable.h:126
System::SharedPtr< System::Collections::Generic::IEnumerator< TItem > > GetEnumerator() override
Gets enumerator.
Definition: enumerable.h:121
CachedEnumerable(System::Func< bool > requestNext)
Definition: enumerable.h:116
Implements the IEnumerable interface for an empty generic collection.
Definition: enumerable.h:53
EmptyEnumerable()=default
SharedPtr< Collections::Generic::IEnumerator< T > > GetEnumerator() override
Gets enumerator.
Definition: enumerable.h:57
Implements the IEnumerator interface for an empty generic collection.
Definition: enumerable.h:25
bool MoveNext() override
Moves enumerator to the next element. If no element was referenced before, sets reference to the firs...
Definition: enumerable.h:34
MakeConstRef_t< T > get_Current() const override
Gets current element.
Definition: enumerable.h:29
void Reset() override
Resets enumerator to position before first element.
Definition: enumerable.h:39
EmptyEnumerator()=default
System::Details::VirtualizedIteratorBase< T > * CloneIterator() const override
Definition: enumerable.h:43
Provides static LINQ methods.
Definition: enumerable.h:140
static SharedPtr< Collections::Generic::IEnumerable< int32_t > > Range(int32_t start, int32_t count)
Generates a sequence of integral numbers within a specified range.
static SharedPtr< Collections::Generic::IEnumerable< T > > Empty()
Returns an empty IEnumerable object.
Definition: enumerable.h:144
Definition: igrouping.h:11
SharedPtr< IOrderedEnumerable< T > > LINQ_ThenBy(const Func< T, Key > &keySelector)
Performs a subsequent ordering of the elements in a sequence in ascending order according to a key.
Pointer class to wrap types being allocated on heap. Use it to manage memory for classes inheriting O...
Definition: smart_ptr.h:180
Definition: db_command.h:9
bool Equals(const TA &a, const TB &b)
Determines the equality of two values applying operator==() to them.
Definition: primitive_types.h:77
SmartPtr< X > MakeSharedPtr(X *p)
Converts raw pointer to smart pointer.
Definition: smart_ptr.h:1650
SmartPtr< T > SharedPtr
Alias for smart pointer widely used in the library.
Definition: smart_ptr.h:1779
typename MakeConstRef< T >::type MakeConstRef_t
Helper type for MakeConstRef modifier.
Definition: make_const_ref.h:20