query.h
Go to the documentation of this file.
1 
25 #ifndef FCPP_QUERY_H
26 #define FCPP_QUERY_H
27 
28 #include <algorithm>
29 #include <functional>
30 #include <iterator>
31 #include <map>
32 #include <optional>
33 #include <random>
34 #include <set>
35 #include <tuple>
36 #include <type_traits>
37 #include <utility>
38 #include <valarray>
39 #include <variant>
40 #include <vector>
41 
42 #include "asserts.h"
43 #include "traits.h"
44 #include "transforms.h"
45 
46 // DO NOT USE
47 //
48 // Internal overloads of [CR_]EXPR.
50 #define __EXPR1__(type, var, expr) [](type var) { return expr; }
51 #define __EXPR2__(type, var1, var2, expr) \
52  [](type var1, type var2) { return expr; }
53 #define __GET_MACRO__(_1, _2, _3, NAME, ...) NAME
54 
67 #define EXPR(...) \
68  __GET_MACRO__(__VA_ARGS__, __EXPR2__, __EXPR1__)(auto, __VA_ARGS__)
69 
82 #define CR_EXPR(...) \
83  __GET_MACRO__(__VA_ARGS__, __EXPR2__, __EXPR1__)(const auto &, __VA_ARGS__)
84 
85 namespace fcpp {
86 // Forward declaration. See actual definition below.
87 template <typename T>
88 class Queryable;
89 
95 template <typename T>
96 class WhenTrue;
97 
104 template <typename WhenTrueQueried, typename T>
105 class WhenFalse;
106 
114 template <typename TrueT, typename FalseT>
115 class Merge;
116 
124 template <typename T>
125 Queryable<T> query(std::vector<T> items);
126 
161 template <typename T>
162 class Queryable final {
163 public:
169  explicit Queryable(std::vector<T> items);
174  Queryable() = delete;
175  virtual ~Queryable() = default;
181  Queryable(Queryable &&) = default;
187  Queryable(const Queryable &) = delete;
194  Queryable &operator=(const Queryable &) = delete;
201  operator const std::vector<T> &&() const { return std::move(items_); }
202 
215  friend bool operator==(const Queryable<T> &lhs, const std::vector<T> &rhs) {
216  return std::equal(lhs.items_.begin(), lhs.items_.end(), rhs.begin());
217  }
226  friend bool operator==(const Queryable<T> &lhs, const Queryable<T> &rhs) {
227  return std::equal(lhs.items_.begin(), lhs.items_.end(), rhs.items_.begin());
228  }
229 
233  typedef T item_type;
234 
244  template <typename U, typename AccumulateFn>
245  U accumulate(U initial, AccumulateFn accumulate_func) const;
246 
253  template <typename ActionFn>
254  Queryable<T> action(ActionFn action_func);
255 
263  template <typename Predicate>
264  bool all(Predicate predicate) const;
265 
273  template <typename Predicate>
274  bool any(Predicate predicate) const;
275 
282  template <typename Predicate>
283  WhenTrue<T> branch(Predicate predicate);
284 
291  Queryable<T> difference(std::vector<T> rhs_items);
292 
299 
306  bool empty() const;
307 
316  template <typename Predicate>
317  std::optional<T> first_or_default(Predicate predicate);
318 
325  auto flatten();
326 
334  template <typename KeySelector>
335  Queryable<std::vector<T>> group_by(KeySelector key_selector);
336 
343  Queryable<T> intersect(const std::vector<T> &rhs_items);
344 
358  template <typename U, typename LhsKeySelector, typename RhsKeySelector>
360  std::vector<U> rhs_items, LhsKeySelector lhs_key_selector,
361  RhsKeySelector rhs_key_selector);
362 
371  template <typename KeySelector>
372  auto keyed_group_by(KeySelector key_selector);
373 
379  T max();
380 
388  template <typename ValueSelector>
389  T max(ValueSelector value_selector);
390 
396  T min();
397 
405  template <typename ValueSelector>
406  T min(ValueSelector value_selector);
407 
417  template <typename ValueSelector>
418  Queryable<T> order_by(ValueSelector value_selector, bool descending = false);
419 
426 
434  template <typename Selector>
435  auto select(Selector selector);
436 
443 
449  size_t size() const;
450 
458  Queryable<T> skip(size_t value);
459 
476  Queryable<T> slice(size_t start_index, size_t size, size_t stride = 1);
477 
483  Queryable<T> sort();
484 
492  Queryable<T> take(size_t value);
493 
501  Queryable<T> take_random(size_t value);
502 
509  Queryable<T> trim(size_t size);
510 
518  template <typename KeySelector>
519  auto to_multi_value_map(KeySelector key_selector);
520 
529  template <typename KeySelector /* = std::function<K(T)>*/>
530  auto to_single_value_map(KeySelector key_selector);
531 
537  std::set<T> to_set();
538 
544  std::vector<T> to_vector();
545 
552  Queryable<T> unionize(std::vector<T> rhs_items);
553 
561  template <typename Predicate>
562  Queryable<T> where(Predicate predicate);
563 
575  template <typename U>
577  zip(std::vector<U> rhs_items, bool truncate = false);
578 
590  template <typename U>
592  zip(std::initializer_list<U> rhs_items, bool truncate);
593 
594 private:
598  std::vector<T> items_;
599 };
600 
601 } // namespace fcpp
602 
603 /******************************************************************************
604  *
605  * @brief Keep definitions separate to allow the declarations to stay clean and
606  * compact.
607  *
608  *****************************************************************************/
609 
610 namespace fcpp {
611 
612 template <typename T>
613 Queryable<T> query(std::vector<T> items) {
614  return Queryable<T>(std::move(items));
615 }
616 
617 template <typename T>
618 Queryable<T>::Queryable(std::vector<T> items) : items_(std::move(items)) {}
619 
620 template <typename T>
621 bool operator==(const Queryable<T> &lhs, const std::vector<T> &rhs) {
622  return std::equal(lhs.items_.begin(), lhs.items_.end(), rhs.begin());
623 }
624 
625 template <typename T>
626 bool operator==(const Queryable<T> &lhs, const Queryable<T> &rhs) {
627  return std::equal(lhs.items_.begin(), lhs.items_.end(), rhs.items_.begin());
628 }
629 
630 template <typename T>
631 template <typename U, typename AccumulateFn>
632 U Queryable<T>::accumulate(U initial, AccumulateFn accumulate_func) const {
633  static_assert(
634  traits::is_additive<U>::value, "Initial value type must be additive.");
635  // @todo Check that AccumulateFn is a binary operation.
636  return std::accumulate(
637  std::make_move_iterator(items_.begin()),
638  std::make_move_iterator(items_.end()), initial, accumulate_func);
639 }
640 
641 template <typename T>
642 template <typename ActionFn>
643 Queryable<T> Queryable<T>::action(ActionFn action_func) {
644  // @todo Check that ActionFn is a unary operation.
645  std::for_each(items_.begin(), items_.end(), [&action_func](auto item) {
646  action_func(item);
647  });
648  return Queryable<T>(std::move(items_));
649 }
650 
651 template <typename T>
652 template <typename Predicate>
653 bool Queryable<T>::all(Predicate predicate) const {
654  return std::all_of(items_.begin(), items_.end(), predicate);
655 }
656 
657 template <typename T>
658 template <typename Predicate>
659 bool Queryable<T>::any(Predicate predicate) const {
660  return std::any_of(items_.begin(), items_.end(), predicate);
661 }
662 
663 template <typename T>
664 Queryable<T> Queryable<T>::difference(std::vector<T> rhs_items) {
665  static_assert(
667  "T must be equality comparable.");
668  // @todo Bubble up concepts for comparisons.
669  std::vector<T> difference;
670  std::set_difference(
671  std::make_move_iterator(items_.begin()),
672  std::make_move_iterator(items_.end()),
673  std::make_move_iterator(rhs_items.begin()),
674  std::make_move_iterator(rhs_items.end()), std::back_inserter(difference));
675  return Queryable<T>(std::move(difference));
676 }
677 
678 template <typename T>
680  static_assert(
682  "T must be equality comparable.");
683  // @todo Reduce the number of transforms.
684  std::set<T> distinguished(
685  std::make_move_iterator(items_.begin()),
686  std::make_move_iterator(items_.end()));
687  return Queryable<T>(transforms::to_vector(std::move(distinguished)));
688 }
689 
690 template <typename T>
691 bool Queryable<T>::empty() const {
692  return items_.empty();
693 }
694 
695 template <typename T>
696 template <typename Predicate>
697 std::optional<T> Queryable<T>::first_or_default(Predicate predicate) {
698  // @todo Require predicate to be a unary operation.
699  auto end = std::make_move_iterator(items_.end());
700  auto it =
701  std::find_if(std::make_move_iterator(items_.begin()), end, predicate);
702  return it != end ? std::make_optional(*it) : std::nullopt;
703 }
704 
705 template <typename T>
706 auto Queryable<T>::flatten() {
707  // @todo asserts::invariant T is a vector.
708  using U = T::value_type;
709  std::vector<U> flattened;
710  for (T &item : items_) {
711  for (U &sub_item : item) {
712  flattened.push_back(std::move(sub_item));
713  }
714  }
715  return Queryable<U>(std::move(flattened));
716 }
717 
718 template <typename T>
719 template <typename KeySelector>
720 Queryable<std::vector<T>> Queryable<T>::group_by(KeySelector key_selector) {
721  using K = decltype(key_selector(*items_.begin()));
722  static_assert(
723  traits::is_less_than_comparable<K>::value,
724  "Key selector must produce a value that is less-than comparable.");
725 
726  std::map<K, std::vector<T>> keyed_groups;
727  std::for_each(
728  std::make_move_iterator(items_.begin()),
729  std::make_move_iterator(items_.end()), [&](auto item) {
730  keyed_groups[key_selector(item)].push_back(std::move(item));
731  });
732 
733  std::vector<std::vector<T>> groups;
734  groups.resize(keyed_groups.size());
735  std::transform(
736  std::make_move_iterator(keyed_groups.begin()),
737  std::make_move_iterator(keyed_groups.end()), groups.begin(),
738  [this](std::pair<K, std::vector<T>> pair) {
739  return std::move(pair.second);
740  });
741 
742  return Queryable<std::vector<T>>(std::move(groups));
743 }
744 
745 template <typename T>
746 Queryable<T> Queryable<T>::intersect(const std::vector<T> &rhs_items) {
747  // @todo Investigate potential copies of rhs_items when set_intersection
748  // called.
749  std::vector<T> intersection;
750  std::set_intersection(
751  std::make_move_iterator(items_.begin()),
752  std::make_move_iterator(items_.end()), rhs_items.begin(), rhs_items.end(),
753  std::back_inserter(intersection));
754  return Queryable<T>(std::move(intersection));
755 }
756 
757 template <typename T>
758 template <typename U, typename LhsKeySelector, typename RhsKeySelector>
760  std::vector<U> rhs_items, LhsKeySelector lhs_key_selector,
761  RhsKeySelector rhs_key_selector) {
762  using KU = decltype(rhs_key_selector(*rhs_items.begin()));
763  using KT = decltype(rhs_key_selector(*items_.begin()));
764  static_assert(
765  std::is_same<KU, KT>::value,
766  "Left and right hand key selectors must produce the same type.");
767 
768  using K = KT;
769  static_assert(
771  "Key selectors must produce a type that is less-than compareable.");
772 
773  std::map<K, std::vector<U>> rhs_mapped;
774  std::for_each(
775  std::make_move_iterator(rhs_items.begin()),
776  std::make_move_iterator(rhs_items.end()), [&, this](U rhs_item) {
777  rhs_mapped[rhs_key_selector(rhs_item)].push_back(std::move(rhs_item));
778  });
779 
780  std::vector<std::tuple<T, U>> joined;
781  std::for_each(
782  std::make_move_iterator(items_.begin()),
783  std::make_move_iterator(items_.end()), [&, this](auto lhs_item) {
784  auto lhs_key = lhs_key_selector(lhs_item);
785  auto rhs_it = rhs_mapped.find(lhs_key);
786  if (rhs_it != rhs_mapped.end()) {
787  for (U &rhs_item : rhs_it->second) {
788  joined.push_back({std::move(lhs_item), std::move(rhs_item)});
789  }
790  }
791  });
792 
793  return Queryable<std::tuple<T, U>>(std::move(joined));
794 }
795 
796 template <typename T>
797 template <typename KeySelector>
798 auto Queryable<T>::keyed_group_by(KeySelector key_selector) {
799  using K = decltype(key_selector(*items_.begin()));
800 
801  std::map<K, std::vector<T>> mapped;
802  for (int i = 0; i < items_.size(); i++) {
803  // @todo Avoid a copy of items_[i] on key_selector call for large objects.
804  mapped[key_selector(items_[i])].push_back(std::move(items_[i]));
805  }
807  {std::make_move_iterator(mapped.begin()),
808  std::make_move_iterator(mapped.end())});
809 }
810 
811 template <typename T>
812 T Queryable<T>::max() {
813  static_assert(
814  traits::is_less_than_comparable<T>::value,
815  "T must be less-than compareable.");
816  asserts::invariant::eval(!items_.empty()) << "Sequence cannot be empty.";
817 
818  // @todo Investigate performance for large objects.
819  return *std::max_element(
820  std::make_move_iterator(items_.begin()),
821  std::make_move_iterator(items_.end()));
822 }
823 
824 template <typename T>
825 template <typename ValueSelector>
826 T Queryable<T>::max(ValueSelector value_selector) {
827  static_assert(
828  traits::is_less_than_comparable<decltype(value_selector(
829  *items_.begin()))>::value,
830  "ValueSelector return type must be less-than compareable.");
831  asserts::invariant::eval(!items_.empty()) << "Sequence cannot be empty.";
832  // @todo Require unary operation.
833 
834  return *std::max_element(
835  std::make_move_iterator(items_.begin()),
836  std::make_move_iterator(items_.end()),
837  [&value_selector](const auto &lhs, const auto &rhs) {
838  return value_selector(lhs) < value_selector(rhs);
839  });
840 }
841 
842 template <typename T>
843 T Queryable<T>::min() {
844  static_assert(
846  "T must be less-than compareable.");
847  asserts::invariant::eval(!items_.empty()) << "Sequence cannot be empty.";
848 
849  // @todo Guard with concepts as seen in min_element.
850  return *std::min_element(
851  std::make_move_iterator(items_.begin()),
852  std::make_move_iterator(items_.end()));
853 }
854 
855 template <typename T>
856 template <typename ValueSelector /* = std::function<K(T)>*/>
857 T Queryable<T>::min(ValueSelector value_selector) {
858  static_assert(
859  traits::is_less_than_comparable<decltype(value_selector(
860  *items_.begin()))>::value,
861  "ValueSelector return type must be less-than compareable.");
862  asserts::invariant::eval(!items_.empty()) << "Sequence cannot be empty.";
863  // @todo Require unary operation.
864 
865  return *std::min_element(
866  std::make_move_iterator(items_.begin()),
867  std::make_move_iterator(items_.end()),
868  [&value_selector](const auto &lhs, const auto &rhs) {
869  return value_selector(lhs) < value_selector(rhs);
870  });
871 }
872 
873 template <typename T>
874 template <typename ValueSelector>
876 Queryable<T>::order_by(ValueSelector value_selector, bool descending) {
877  static_assert(
878  std::is_copy_assignable_v<T> ||
879  (std::is_move_assignable_v<T> && std::is_move_constructible_v<T>),
880  "T must either be copy assignable, or move assignable and "
881  "constructible.");
882  static_assert(
883  traits::is_less_than_comparable<decltype(value_selector(
884  *items_.begin()))>::value,
885  "ValueSelector return type must be less-than compareable.");
886 
887  using K = decltype(value_selector(*items_.begin()));
888  std::sort(
889  items_.begin(), items_.end(),
890  [&value_selector, descending](const auto &lhs, const auto &rhs) -> bool {
891  const K &lhs_value = value_selector(lhs);
892  const K &rhs_value = value_selector(rhs);
893  return descending ? lhs_value > rhs_value : lhs_value < rhs_value;
894  });
895 
896  return Queryable<T>(std::move(items_));
897 }
898 
899 template <typename T>
901  std::reverse(items_.begin(), items_.end());
902  return Queryable<T>(std::move(items_));
903 }
904 
905 template <typename T>
906 template <typename Selector /* = std::function<U(T)>*/>
907 auto Queryable<T>::select(Selector selector) {
908  using U = decltype(selector(*items_.begin()));
909  std::vector<U> selected;
910  selected.reserve(items_.size());
911  std::transform(
912  std::make_move_iterator(items_.begin()),
913  std::make_move_iterator(items_.end()), std::back_inserter(selected),
914  selector);
915 
916  return Queryable<U>(std::move(selected));
917 }
918 
919 template <typename T>
921  std::shuffle(
922  items_.begin(), items_.end(), std::mt19937(std::random_device()()));
923  return Queryable<T>(std::move(items_));
924 }
925 
926 template <typename T>
927 size_t Queryable<T>::size() const {
928  return items_.size();
929 }
930 
931 template <typename T>
933  asserts::invariant::eval(value <= size())
934  << "Skip value " << value
935  << " must be less than or equal to sequence size of " << size() << ".";
936 
937  return Queryable<T>(
938  {std::make_move_iterator(items_.begin() + value),
939  std::make_move_iterator(items_.end())});
940 }
941 
942 template <typename T>
943 Queryable<T>
944 Queryable<T>::slice(size_t start_index, size_t size, size_t stride) {
945  asserts::invariant::eval(start_index < this->size())
946  << "Slice start index " << start_index
947  << " must be less than sequence size of " << this->size() << ".";
948 
949  size_t slice_length = (start_index - 1) + (size * stride);
950  asserts::invariant::eval(stride == 0 || slice_length <= this->size())
951  << "Slice length " << slice_length
952  << " must be less than or equal to the sequence size of " << this->size()
953  << ".";
954 
955  std::vector<T> sliced;
956  sliced.reserve(size);
957 
958  int i = start_index;
959  for (size_t current_size = 0; current_size < size; current_size++) {
960  sliced.push_back(std::move(items_[i]));
961  i += stride;
962  }
963 
964  return Queryable<T>(std::move(sliced));
965 }
966 
967 template <typename T>
968 Queryable<T> Queryable<T>::sort() {
969  std::sort(items_.begin(), items_.end());
970  return this;
971 }
972 
973 template <typename T>
974 Queryable<T> Queryable<T>::take(size_t value) {
975  asserts::invariant::eval(value <= size())
976  << "Take value " << value
977  << " must be less than or equal to sequence size of " << size() << ".";
978 
979  return Queryable<T>(
980  {std::make_move_iterator(items_.begin()),
981  std::make_move_iterator(items_.begin() + value)});
982 }
983 
984 template <typename T>
985 Queryable<T> Queryable<T>::take_random(size_t value) {
986  asserts::invariant::eval(value <= size())
987  << "Take random value " << value
988  << " must be less than or equal to sequence size of " << size() << ".";
989 
990  std::vector<int> indices;
991  indices.reserve(items_.size());
992  for (int i = 0; i < items_.size(); i++) {
993  indices.push_back(i);
994  }
995  std::shuffle(
996  indices.begin(), indices.end(), std::mt19937(std::random_device()()));
997  indices.resize(value);
998 
999  std::vector<T> random_items;
1000  random_items.reserve(std::min(items_.size(), value));
1001  std::transform(
1002  indices.begin(), indices.end(), std::back_inserter(random_items),
1003  [this](int i) { return std::move(items_[i]); });
1004 
1005  return Queryable<T>(std::move(random_items));
1006 }
1007 
1008 template <typename T>
1009 template <typename KeySelector /* = std::function<K(T)>*/>
1010 auto Queryable<T>::to_multi_value_map(KeySelector key_selector) {
1011  using K = decltype(key_selector(*items_.begin()));
1012  std::map<K, std::vector<T>> mapped;
1013  std::for_each(items_.begin(), items_.end(), [&, this](auto &item) {
1014  mapped[key_selector(item)].push_back(std::move(item));
1015  });
1016  return mapped;
1017 }
1018 
1019 template <typename T>
1020 template <typename KeySelector /* = std::function<K(T)>*/>
1021 auto Queryable<T>::to_single_value_map(KeySelector key_selector) {
1022  using K = decltype(key_selector(*items_.begin()));
1023  static_assert(
1025  "KeySelector return type must be less-than compareable.");
1027  std::map<K, T> mapped;
1028  std::for_each(
1029  std::make_move_iterator(items_.begin()),
1030  std::make_move_iterator(items_.end()), [&, this](auto item) {
1031  K key = key_selector(item);
1032  auto it = mapped.find(key);
1033  if (it == mapped.end()) {
1034  mapped.insert({std::move(key), std::move(item)});
1035  }
1036  });
1037  return mapped;
1038 }
1039 
1040 template <typename T>
1041 std::set<T> Queryable<T>::to_set() {
1042  static_assert(
1043  traits::is_less_than_comparable<T>::value,
1044  "T must be less-than compareable.");
1045  return std::set<T>(
1046  std::make_move_iterator(items_.begin()),
1047  std::make_move_iterator(items_.end()));
1048 }
1049 
1050 template <typename T>
1051 std::vector<T> Queryable<T>::to_vector() {
1052  return std::move(items_);
1053 }
1054 
1055 template <typename T>
1057  asserts::invariant(items_.size() <= size)
1058  << "Size " << size << " must be less than or equal to sequence size of "
1059  << this->size() << ".";
1060 
1061  items_.resize(items_.size() - size);
1062  return Queryable<T>(std::move(items_));
1063 }
1064 
1065 template <typename T>
1066 Queryable<T> Queryable<T>::unionize(std::vector<T> rhs_items) {
1067  static_assert(
1069  "T must be less-than compareable.");
1070 
1071  std::set<T> unionized(
1072  std::make_move_iterator(items_.begin()),
1073  std::make_move_iterator(items_.end()));
1074  std::move(
1075  rhs_items.begin(), rhs_items.end(),
1076  std::inserter(unionized, unionized.end()));
1077 
1078  return Queryable<T>(transforms::to_vector(std::move(unionized)));
1079 }
1080 
1081 template <typename T>
1082 template <typename Predicate>
1083 Queryable<T> Queryable<T>::where(Predicate predicate) {
1084  std::vector<T> filtered;
1085  std::copy_if(
1086  std::make_move_iterator(items_.begin()),
1087  std::make_move_iterator(items_.end()), std::back_inserter(filtered),
1088  predicate);
1089  return Queryable<T>(std::move(filtered));
1090 }
1091 
1092 template <typename T>
1093 template <typename U>
1095 Queryable<T>::zip(std::vector<U> rhs_items, bool truncate) {
1096  if (!truncate) {
1097  static_assert(
1098  std::is_default_constructible_v<T>,
1099  "T must have a default constructor so default values can "
1100  "populate the tuple.");
1101  static_assert(
1102  std::is_default_constructible_v<U>,
1103  "U must have a default constructor so default values can "
1104  "populate the tuple.");
1105  }
1106 
1107  std::vector<std::tuple<T, U>> zipped;
1108  zipped.reserve(
1109  truncate ? std::min({items_.size(), rhs_items.size()})
1110  : std::max({items_.size(), rhs_items.size()}));
1111 
1112  int i = 0;
1113  for (; i < std::min({items_.size(), rhs_items.size()}); i++) {
1114  zipped.push_back({std::move(items_[i]), std::move(rhs_items[i])});
1115  }
1116 
1117  if (truncate) {
1118  return Queryable<std::tuple<T, U>>(std::move(zipped));
1119  }
1120 
1121  if (items_.size() > rhs_items.size()) {
1122  for (; i < items_.size(); i++) {
1123  zipped.push_back({std::move(items_[i]), U()});
1124  }
1125  } else {
1126  for (; i < rhs_items.size(); i++) {
1127  zipped.push_back({T(), std::move(rhs_items[i])});
1128  }
1129  }
1130  return Queryable<std::tuple<T, U>>(std::move(zipped));
1131 }
1132 
1133 template <typename T>
1134 template <typename U>
1135 Queryable<std::tuple<T, U>>
1136 Queryable<T>::zip(std::initializer_list<U> rhs_items, bool truncate) {
1137  return zip(std::vector<U>(std::move(rhs_items)), truncate);
1138 }
1139 
1140 template <typename TrueT, typename FalseT>
1141 class Merge {
1142 public:
1143  explicit Merge(Queryable<TrueT> true_queried, Queryable<FalseT> false_queried)
1144  : true_queried_(std::move(true_queried)),
1145  false_queried_(std::move(false_queried)) {}
1146  Merge() = delete;
1147  virtual ~Merge() = default;
1148  Merge(const Merge &) = delete;
1149  Merge &operator=(const Merge &) = delete;
1150 
1151  // Merges the true and false branches as a zip.
1152  Queryable<std::tuple<TrueT, FalseT>> merge(bool truncate = false) {
1153  return true_queried_.zip(std::move(false_queried_.to_vector()), truncate);
1154  }
1155 
1156 private:
1157  Queryable<TrueT> true_queried_;
1158  Queryable<FalseT> false_queried_;
1159 };
1160 
1161 template <typename WhenTrueQueriedT, typename T>
1162 class WhenFalse {
1163 public:
1164  explicit WhenFalse(
1165  Queryable<WhenTrueQueriedT> when_true_queried,
1166  std::vector<T> when_false_items)
1167  : when_true_queried_(std::move(when_true_queried)),
1168  when_false_items_(std::move(when_false_items)) {}
1169  WhenFalse() = delete;
1170  virtual ~WhenFalse() = default;
1171  WhenFalse(const WhenFalse &) = delete;
1172  WhenFalse &operator=(const WhenFalse &) = delete;
1173 
1174  // Queries the false branched items from the Queryable<T>::branch predicate.
1175  template <
1176  typename WhenFalseQuery /* =
1177  std::function<Queryable<WhenFalseQueriedT>(Queryable<T>&)>
1178  */
1179  ,
1180  typename WhenFalseQueriedT =
1181  std::invoke_result_t<WhenFalseQuery, Queryable<T>>::item_type>
1182  Merge<WhenTrueQueriedT, WhenFalseQueriedT>
1183  when_false(WhenFalseQuery when_false_query) {
1184  return Merge<WhenTrueQueriedT, WhenFalseQueriedT>(
1185  Queryable<WhenTrueQueriedT>(when_true_queried_.to_vector()),
1186  when_false_query(Queryable<T>(std::move(when_false_items_))));
1187  }
1188 
1189 private:
1190  Queryable<WhenTrueQueriedT> when_true_queried_;
1191  std::vector<T> when_false_items_;
1192 };
1193 
1194 // True branch from the Queryable<T>::branch predicate.
1195 template <typename T>
1196 class WhenTrue {
1197 public:
1198  explicit WhenTrue(
1199  std::vector<T> when_true_items, std::vector<T> when_false_items)
1200  : when_true_items_(std::move(when_true_items)),
1201  when_false_items_(std::move(when_false_items)) {}
1202  WhenTrue() = delete;
1203  virtual ~WhenTrue() = default;
1204  WhenTrue(const WhenTrue &) = delete;
1205  WhenTrue &operator=(const WhenTrue &) = delete;
1206 
1207  // Queries the true branched items from the Queryable<T>::branch predicate.
1208  template <
1209  typename WhenTrueQuery /* =
1210  std::function<Queryable<WhenTrueQueriedT>(Queryable<T>)>
1211  */
1212  ,
1213  typename WhenTrueQueriedT =
1214  std::invoke_result_t<WhenTrueQuery, Queryable<T>>::item_type>
1215  WhenFalse<WhenTrueQueriedT, T> when_true(WhenTrueQuery when_true_query) {
1216  return WhenFalse<WhenTrueQueriedT, T>(
1217  std::move(when_true_query(Queryable<T>(std::move(when_true_items_)))),
1218  std::move(when_false_items_));
1219  }
1220 
1221 private:
1222  std::vector<T> when_true_items_;
1223  std::vector<T> when_false_items_;
1224 };
1225 
1226 template <typename T>
1227 template <typename Predicate>
1228 WhenTrue<T> Queryable<T>::branch(Predicate predicate) {
1229  std::vector<T> when_true_items;
1230  std::vector<T> when_false_items;
1231  std::for_each(
1232  std::make_move_iterator(items_.begin()),
1233  std::make_move_iterator(items_.end()), [&](auto item) {
1234  if (predicate(item)) {
1235  when_true_items.push_back(std::move(item));
1236  } else {
1237  when_false_items.push_back(std::move(item));
1238  }
1239  });
1240 
1241  return WhenTrue<T>(std::move(when_true_items), std::move(when_false_items));
1242 }
1243 
1244 } // namespace fcpp
1245 
1246 #endif // FCPP_QUERY_H
Queryable< std::tuple< T, U > > join(std::vector< U > rhs_items, LhsKeySelector lhs_key_selector, RhsKeySelector rhs_key_selector)
Correlates the items of two sequences based on matching keys.
Definition: query.h:764
size_t size() const
Gets the size of the sequence.
Definition: query.h:932
Queryable()=delete
Empty constructor.
bool all(Predicate predicate) const
Determines whether all items of a sequence satisfy a condition.
Definition: query.h:658
False / else block query of Queryable<T>::branch method.
Definition: query.h:105
std::vector< T > to_vector()
Gets the sequence as a vector.
Definition: query.h:1056
Definition: traits.h:32
Queryable< T > shuffle()
Randomizes / shuffles all the item's order in the sequence.
Definition: query.h:925
Queryable & operator=(const Queryable &)=delete
Copy assignment operator.
auto to_single_value_map(KeySelector key_selector)
Groups items by selected key value, takes the first item of every group, and puts them into a hash ma...
Definition: query.h:1026
Queryable< T > order_by(ValueSelector value_selector, bool descending=false)
Orders the sequence by the selected value.
Definition: query.h:881
friend bool operator==(const Queryable< T > &lhs, const std::vector< T > &rhs)
Equals overload operator for Queryable<T> against a std::vector<T>.
Definition: query.h:215
auto select(Selector selector)
Projects each item of a sequence into a new form.
Definition: query.h:912
Queryable< T > difference(std::vector< T > rhs_items)
Produces the set difference of two sequences.
Definition: query.h:669
WhenTrue< T > branch(Predicate predicate)
Branches the sequence into two based on a condition.
Definition: query.h:1233
Definition: traits.h:41
std::optional< T > first_or_default(Predicate predicate)
Gets the first item of a sequence, or a default value if no item is found.
Definition: query.h:702
Runtime validation of object states.
Queryable< std::vector< T > > group_by(KeySelector key_selector)
Groups the items of a sequence.
Definition: query.h:725
Queryable< T > skip(size_t value)
Bypasses a specified number of items in the sequence and then returns the remaining items.
Definition: query.h:937
auto keyed_group_by(KeySelector key_selector)
Groups the items of a sequence by key and produces as a key-group pair sequence.
Definition: query.h:803
auto flatten()
Projects each item in the sequence-of-sequences and flattens the resulting sequences into one (i....
Definition: query.h:711
Enforce assertions that a condition will never change during the running lifetime of that code.
Definition: asserts.h:37
Queryable< T > slice(size_t start_index, size_t size, size_t stride=1)
Gets a slice of the sequence.
Definition: query.h:949
True / if block query of Queryable<T>::branch method.
Definition: query.h:96
std::set< T > to_set()
Gets the sequence as a set.
Definition: query.h:1046
auto to_multi_value_map(KeySelector key_selector)
Groups items by a selected key value and puts them into a hash map.
Definition: query.h:1015
Merge result of both if and else block queries from Queryable<T>::branch method.
Definition: query.h:115
Queryable< T > sort()
Sorts the items in the sequence.
Definition: query.h:973
Queryable< T > intersect(const std::vector< T > &rhs_items)
Produces the set intersection of two sequences.
Definition: query.h:751
Queryable< T > query(std::vector< T > items)
Queries the sequence of items using a vector.
Definition: query.h:618
Queryable< T > trim(size_t size)
Trim from the back of the sequence.
Definition: query.h:1061
Queryable< T > distinct()
Gets distinct items from a sequence.
Definition: query.h:684
Queryable< std::tuple< T, U > > zip(std::vector< U > rhs_items, bool truncate=false)
Produces a sequence of tuples with items from the two specified sequences.
Definition: query.h:1100
Queryable< T > action(ActionFn action_func)
Executes a void action to create side effects.
Definition: query.h:648
T item_type
Type of items to query over. Used for type deduction.
Definition: query.h:233
bool empty() const
Indicates of the sequence is empty.
Definition: query.h:696
Queryable< T > reverse()
Inverts the order of the items in the sequence.
Definition: query.h:905
U accumulate(U initial, AccumulateFn accumulate_func) const
Sums all the projected values of the sequence into a single value.
Definition: query.h:637
bool operator==(const Queryable< T > &lhs, const std::vector< T > &rhs)
Definition: query.h:626
Queryable< T > unionize(std::vector< T > rhs_items)
Unions the left hand and right hand side sequences.
Definition: query.h:1071
Queryable< T > take(size_t value)
Takes a specified number of contiguous items from the start of a sequence.
Definition: query.h:979
Definition: traits.h:51
Queryable< T > where(Predicate predicate)
Selects items in the sequence that satisfy the predicate / conditional.
Definition: query.h:1088
Traits for asserting object features.
friend bool operator==(const Queryable< T > &lhs, const Queryable< T > &rhs)
Equals overload operator.
Definition: query.h:226
Core object used to query items and hold the sequence state.
Definition: query.h:88
T max()
Gets the maximum item from the sequence.
Definition: query.h:817
T min()
Gets the minimum item from the sequence.
Definition: query.h:848
bool any(Predicate predicate) const
Determines whether a sequence contains any items.
Definition: query.h:664
Queryable< T > take_random(size_t value)
Takes the specified number of items from the sequence at random places.
Definition: query.h:990