54#define __EXPR1__(type, var, expr) [](type var) { return expr; }
55#define __EXPR2__(type, var1, var2, expr) \
56 [](type var1, type var2) { return expr; }
57#define __GET_MACRO__(_1, _2, _3, NAME, ...) NAME
72 __GET_MACRO__(__VA_ARGS__, __EXPR2__, __EXPR1__)(auto, __VA_ARGS__)
87 __GET_MACRO__(__VA_ARGS__, __EXPR2__, __EXPR1__)(const auto &, __VA_ARGS__)
95inline std::mt19937 &random_engine() {
96 thread_local std::mt19937 engine(std::random_device{}());
102T copy_or_throw(
const T &item,
const char *operation) {
103 if constexpr (std::is_copy_constructible_v<T>) {
106 throw std::invalid_argument(
107 std::string(operation) +
" requires copying a non-copyable item.");
132template <
typename WhenTrueQueried,
typename T>
142template <
typename TrueT,
typename FalseT>
153Queryable<T> query(std::vector<T> items);
229 operator std::vector<T>() && {
return std::move(items_); }
235 operator std::vector<T>() const & {
return items_; }
250 return lhs.items_ == rhs;
261 return lhs.items_ == rhs.items_;
278 template <
typename U,
typename AccumulateFn>
287 template <
typename ActionFn>
297 template <
typename Predicate>
298 bool all(Predicate predicate)
const;
307 template <
typename Predicate>
308 bool any(Predicate predicate)
const;
316 template <
typename Predicate>
354 template <
typename Predicate>
372 template <
typename KeySelector>
403 template <
typename U,
typename LhsKeySelector,
typename RhsKeySelector>
405 std::vector<U> rhs_items, LhsKeySelector lhs_key_selector,
406 RhsKeySelector rhs_key_selector);
416 template <
typename KeySelector>
433 template <
typename ValueSelector>
434 T
max(ValueSelector value_selector);
450 template <
typename ValueSelector>
451 T
min(ValueSelector value_selector);
464 template <
typename ValueSelector>
481 template <
typename Selector>
496 [[nodiscard]]
size_t size()
const;
566 template <
typename KeySelector>
577 template <
typename KeySelector >
609 template <
typename Predicate>
624 template <
typename U>
626 zip(std::vector<U> rhs_items,
bool truncate =
false);
640 template <
typename U>
642 zip(std::initializer_list<U> rhs_items,
bool truncate =
false);
648 std::vector<T> items_;
671template <
typename U,
typename AccumulateFn>
676 return std::accumulate(
677 items_.begin(), items_.end(), initial, accumulate_func);
681template <
typename ActionFn>
686 std::for_each(items_.begin(), items_.end(), [&action_func](
const auto &item) {
693template <
typename Predicate>
695 return std::all_of(items_.begin(), items_.end(), predicate);
699template <
typename Predicate>
701 return std::any_of(items_.begin(), items_.end(), predicate);
708 "T must be less-than comparable.");
709 std::sort(rhs_items.begin(), rhs_items.end());
712 std::vector<size_t> consumed(rhs_items.size(), 0);
713 std::erase_if(items_, [&](
const T &item) {
714 auto [lo, hi] = std::equal_range(rhs_items.begin(), rhs_items.end(), item);
715 size_t &used = consumed[lo - rhs_items.begin()];
716 if (lo + used < hi) {
729 "T must be less-than comparable.");
730 std::sort(items_.begin(), items_.end());
734 items_.begin(), items_.end(),
735 [](
const T &lhs,
const T &rhs) { return !(lhs < rhs); }),
742 return items_.empty();
746template <
typename Predicate>
750 std::find_if(items_.begin(), items_.end(), [&predicate](
const T &item) {
751 return predicate(item);
753 if (it == items_.end()) {
756 return std::optional<T>(std::move(*it));
762 using U =
typename T::value_type;
766 for (T &item : items_) {
767 total += item.size();
769 std::vector<U> flattened;
770 flattened.reserve(total);
771 for (T &item : items_) {
772 for (U &sub_item : item) {
773 flattened.push_back(std::move(sub_item));
780template <
typename KeySelector>
782 using K =
decltype(key_selector(*items_.begin()));
785 "Key selector must produce a value that is less-than comparable.");
787 std::map<K, std::vector<T>> keyed_groups;
788 for (T &item : items_) {
789 keyed_groups[key_selector(std::as_const(item))].push_back(std::move(item));
792 std::vector<std::vector<T>> groups;
793 groups.reserve(keyed_groups.size());
794 for (
auto &[key, group] : keyed_groups) {
795 groups.push_back(std::move(group));
804 "T must be less-than comparable.");
805 std::sort(rhs_items.begin(), rhs_items.end());
808 std::vector<size_t> consumed(rhs_items.size(), 0);
809 std::erase_if(items_, [&](
const T &item) {
810 auto [lo, hi] = std::equal_range(rhs_items.begin(), rhs_items.end(), item);
811 size_t &used = consumed[lo - rhs_items.begin()];
812 if (lo + used < hi) {
822template <
typename U,
typename LhsKeySelector,
typename RhsKeySelector>
824 std::vector<U> rhs_items, LhsKeySelector lhs_key_selector,
825 RhsKeySelector rhs_key_selector) {
826 using KU =
decltype(rhs_key_selector(*rhs_items.begin()));
827 using KT =
decltype(lhs_key_selector(*items_.begin()));
829 std::is_same<KU, KT>::value,
830 "Left and right hand key selectors must produce the same type.");
835 "Key selectors must produce a type that is less-than compareable.");
837 std::map<K, std::vector<U>> rhs_mapped;
838 for (U &rhs_item : rhs_items) {
839 rhs_mapped[rhs_key_selector(std::as_const(rhs_item))].push_back(
840 std::move(rhs_item));
844 std::vector<K> lhs_keys;
845 lhs_keys.reserve(items_.size());
846 std::map<K, size_t> uses_left;
847 for (T &lhs_item : items_) {
848 lhs_keys.push_back(lhs_key_selector(std::as_const(lhs_item)));
849 if (rhs_mapped.count(lhs_keys.back())) {
850 uses_left[lhs_keys.back()]++;
854 std::vector<std::tuple<T, U>> joined;
855 for (
size_t i = 0; i < items_.size(); i++) {
856 auto rhs_it = rhs_mapped.find(lhs_keys[i]);
857 if (rhs_it == rhs_mapped.end()) {
860 bool last_lhs_use = --uses_left[lhs_keys[i]] == 0;
861 std::vector<U> &rhs_group = rhs_it->second;
862 for (
size_t j = 0; j < rhs_group.size(); j++) {
863 bool last_rhs_use = j + 1 == rhs_group.size();
865 last_rhs_use ? std::move(items_[i])
866 : detail::copy_or_throw(items_[i],
"join"),
867 last_lhs_use ? std::move(rhs_group[j])
868 : detail::copy_or_throw(rhs_group[j],
"join"));
876template <
typename KeySelector>
878 using K =
decltype(key_selector(*items_.begin()));
880 std::map<K, std::vector<T>> mapped;
881 for (T &item : items_) {
882 mapped[key_selector(std::as_const(item))].push_back(std::move(item));
885 {std::make_move_iterator(mapped.begin()),
886 std::make_move_iterator(mapped.end())});
893 "T must be less-than compareable.");
897 return std::move(*std::max_element(items_.begin(), items_.end()));
901template <
typename ValueSelector>
905 *items_.begin()))>::value,
906 "ValueSelector return type must be less-than compareable.");
910 return std::move(*std::max_element(
911 items_.begin(), items_.end(),
912 [&value_selector](
const auto &lhs,
const auto &rhs) {
913 return value_selector(lhs) < value_selector(rhs);
921 "T must be less-than compareable.");
925 return std::move(*std::min_element(items_.begin(), items_.end()));
929template <
typename ValueSelector >
933 *items_.begin()))>::value,
934 "ValueSelector return type must be less-than compareable.");
938 return std::move(*std::min_element(
939 items_.begin(), items_.end(),
940 [&value_selector](
const auto &lhs,
const auto &rhs) {
941 return value_selector(lhs) < value_selector(rhs);
946template <
typename ValueSelector>
950 std::is_copy_assignable_v<T> ||
951 (std::is_move_assignable_v<T> && std::is_move_constructible_v<T>),
952 "T must either be copy assignable, or move assignable and "
956 *items_.begin()))>::value,
957 "ValueSelector return type must be less-than compareable.");
959 using K = std::decay_t<
decltype(value_selector(*items_.begin()))>;
961 std::vector<K> values;
962 values.reserve(items_.size());
963 for (T &item : items_) {
964 values.push_back(value_selector(std::as_const(item)));
966 std::vector<size_t> order(items_.size());
967 std::iota(order.begin(), order.end(), 0);
969 order.begin(), order.end(),
970 [&values, descending](
size_t lhs,
size_t rhs) {
971 return descending ? values[rhs] < values[lhs]
972 : values[lhs] < values[rhs];
975 std::vector<T> ordered;
976 ordered.reserve(items_.size());
977 for (
size_t i : order) {
978 ordered.push_back(std::move(items_[i]));
985 std::reverse(items_.begin(), items_.end());
990template <
typename Selector >
992 using U =
decltype(selector(*items_.begin()));
993 std::vector<U> selected;
994 selected.reserve(items_.size());
996 std::make_move_iterator(items_.begin()),
997 std::make_move_iterator(items_.end()), std::back_inserter(selected),
1003template <
typename T>
1005 std::shuffle(items_.begin(), items_.end(), detail::random_engine());
1009template <
typename T>
1011 return items_.size();
1014template <
typename T>
1017 <<
"Skip value " << value
1018 <<
" must be less than or equal to sequence size of " <<
size() <<
".";
1020 items_.erase(items_.begin(), items_.begin() + value);
1024template <
typename T>
1031 <<
"Slice start index " << start_index
1032 <<
" must be less than sequence size of " << this->size() <<
".";
1034 size_t last_index = start_index + (
size - 1) * stride;
1036 <<
"Slice last index " << last_index
1037 <<
" must be less than the sequence size of " << this->size() <<
".";
1039 std::vector<T> sliced;
1040 sliced.reserve(
size);
1043 for (
size_t i = 0; i + 1 <
size; i++) {
1044 sliced.push_back(detail::copy_or_throw(items_[start_index],
"slice"));
1046 sliced.push_back(std::move(items_[start_index]));
1048 for (
size_t i = start_index; sliced.size() <
size; i += stride) {
1049 sliced.push_back(std::move(items_[i]));
1056template <
typename T>
1058 std::sort(items_.begin(), items_.end());
1062template <
typename T>
1065 <<
"Take value " << value
1066 <<
" must be less than or equal to sequence size of " <<
size() <<
".";
1068 items_.erase(items_.begin() + value, items_.end());
1072template <
typename T>
1075 <<
"Take random value " << value
1076 <<
" must be less than or equal to sequence size of " <<
size() <<
".";
1079 auto &engine = detail::random_engine();
1080 for (
size_t i = 0; i < value; i++) {
1081 std::uniform_int_distribution<size_t> dist(i, items_.size() - 1);
1082 std::swap(items_[i], items_[dist(engine)]);
1084 items_.erase(items_.begin() + value, items_.end());
1088template <
typename T>
1089template <
typename KeySelector >
1091 using K =
decltype(key_selector(*items_.begin()));
1092 std::map<K, std::vector<T>> mapped;
1093 for (T &item : items_) {
1094 mapped[key_selector(std::as_const(item))].push_back(std::move(item));
1099template <
typename T>
1100template <
typename KeySelector >
1102 using K =
decltype(key_selector(*items_.begin()));
1105 "KeySelector return type must be less-than compareable.");
1107 std::map<K, T> mapped;
1108 for (T &item : items_) {
1110 mapped.try_emplace(key_selector(std::as_const(item)), std::move(item));
1115template <
typename T>
1119 "T must be less-than compareable.");
1121 std::make_move_iterator(items_.begin()),
1122 std::make_move_iterator(items_.end()));
1125template <
typename T>
1127 return std::move(items_);
1130template <
typename T>
1133 <<
"Size " <<
size <<
" must be less than or equal to sequence size of "
1134 << this->size() <<
".";
1136 items_.erase(items_.end() -
size, items_.end());
1140template <
typename T>
1144 "T must be less-than compareable.");
1147 items_.end(), std::make_move_iterator(rhs_items.begin()),
1148 std::make_move_iterator(rhs_items.end()));
1152template <
typename T>
1153template <
typename Predicate>
1157 items_, [&predicate](
const T &item) {
return !predicate(item); });
1161template <
typename T>
1162template <
typename U>
1165 size_t common = std::min(items_.size(), rhs_items.size());
1166 size_t total = truncate ? common : std::max(items_.size(), rhs_items.size());
1168 std::vector<std::tuple<T, U>> zipped;
1169 zipped.reserve(total);
1170 for (
size_t i = 0; i < common; i++) {
1171 zipped.emplace_back(std::move(items_[i]), std::move(rhs_items[i]));
1173 if (total == common) {
1178 if (items_.size() > rhs_items.size()) {
1179 if constexpr (std::is_default_constructible_v<U>) {
1180 for (
size_t i = common; i < total; i++) {
1181 zipped.emplace_back(std::move(items_[i]), U());
1184 throw std::invalid_argument(
1185 "zip padding requires a default constructible right hand type.");
1188 if constexpr (std::is_default_constructible_v<T>) {
1189 for (
size_t i = common; i < total; i++) {
1190 zipped.emplace_back(T(), std::move(rhs_items[i]));
1193 throw std::invalid_argument(
1194 "zip padding requires a default constructible left hand type.");
1200template <
typename T>
1201template <
typename U>
1204 return zip(std::vector<U>(std::move(rhs_items)), truncate);
1214template <
typename TrueT,
typename FalseT>
1227 : true_queried_(std::move(true_queried)),
1228 false_queried_(std::move(false_queried)) {}
1243 return true_queried_.zip(false_queried_.to_vector(), truncate);
1257template <
typename WhenTrueQueriedT,
typename T>
1272 std::vector<T> when_false_items)
1273 : when_true_queried_(std::move(when_true_queried)),
1274 when_false_items_(std::move(when_false_items)) {}
1291 typename WhenFalseQuery
1295 typename WhenFalseQueriedT =
typename std::invoke_result_t<
1300 std::move(when_true_queried_),
1301 when_false_query(
Queryable<T>(std::move(when_false_items_))));
1306 std::vector<T> when_false_items_;
1314template <
typename T>
1327 std::vector<T> when_true_items, std::vector<T> when_false_items)
1328 : when_true_items_(std::move(when_true_items)),
1329 when_false_items_(std::move(when_false_items)) {}
1346 typename WhenTrueQuery
1350 typename WhenTrueQueriedT =
1351 typename std::invoke_result_t<WhenTrueQuery, Queryable<T>>::item_type>
1354 when_true_query(
Queryable<T>(std::move(when_true_items_))),
1355 std::move(when_false_items_));
1359 std::vector<T> when_true_items_;
1360 std::vector<T> when_false_items_;
1363template <
typename T>
1364template <
typename Predicate>
1366 std::vector<T> when_true_items;
1367 std::vector<T> when_false_items;
1368 for (T &item : items_) {
1369 if (predicate(std::as_const(item))) {
1370 when_true_items.push_back(std::move(item));
1372 when_false_items.push_back(std::move(item));
1376 return WhenTrue<T>(std::move(when_true_items), std::move(when_false_items));
Runtime validation of object states.
Merge result of both if and else block queries from Queryable<T>::branch method.
Definition query.h:1215
Merge(Queryable< TrueT > true_queried, Queryable< FalseT > false_queried)
Construct a new Merge object from the transformed true and false branches of the predicate.
Definition query.h:1226
Queryable< std::tuple< TrueT, FalseT > > merge(bool truncate=false)
Merges the true and false branch sequences as a zip.
Definition query.h:1242
Core object used to query items and hold the sequence state.
Definition query.h:190
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:1101
std::set< T > to_set()
Gets the sequence as a set.
Definition query.h:1116
bool all(Predicate predicate) const
Determines whether all items of a sequence satisfy a condition.
Definition query.h:694
Queryable< T > shuffle()
Randomizes / shuffles all the item's order in the sequence.
Definition query.h:1004
bool any(Predicate predicate) const
Determines whether a sequence contains any items.
Definition query.h:700
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:823
auto flatten()
Projects each item in the sequence-of-sequences and flattens the resulting sequences into one (i....
Definition query.h:760
T item_type
Type of items to query over. Used for type deduction.
Definition query.h:267
Queryable< T > where(Predicate predicate)
Selects items in the sequence that satisfy the predicate / conditional.
Definition query.h:1154
Queryable< T > skip(size_t value)
Bypasses a specified number of items in the sequence and then returns the remaining items.
Definition query.h:1015
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:1164
Queryable< T > sort()
Sorts the items in the sequence.
Definition query.h:1057
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:249
Queryable< T > unionize(std::vector< T > rhs_items)
Unions the left hand and right hand side sequences.
Definition query.h:1141
Queryable< T > order_by(ValueSelector value_selector, bool descending=false)
Orders the sequence by the selected value.
Definition query.h:948
Queryable< T > reverse()
Inverts the order of the items in the sequence.
Definition query.h:984
T min()
Gets the minimum item from the sequence.
Definition query.h:918
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:747
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:1090
Queryable< T > difference(std::vector< T > rhs_items)
Produces the multiset difference of two sequences.
Definition query.h:705
Queryable< T > take_random(size_t value)
Takes the specified number of items from the sequence at random places.
Definition query.h:1073
Queryable(Queryable &&) noexcept=default
Move assignment operator.
Queryable< T > distinct()
Gets distinct items from a sequence.
Definition query.h:726
Queryable< T > take(size_t value)
Takes a specified number of contiguous items from the start of a sequence.
Definition query.h:1063
std::vector< T > to_vector()
Gets the sequence as a vector.
Definition query.h:1126
Queryable< T > slice(size_t start_index, size_t size, size_t stride=1)
Gets a slice of the sequence.
Definition query.h:1026
Queryable()=delete
Empty constructor.
size_t size() const
Gets the size of the sequence.
Definition query.h:1010
bool empty() const
Indicates of the sequence is empty.
Definition query.h:741
Queryable(std::vector< T > items)
Construct a new Queryable object from a sequence of items.
Definition query.h:668
U accumulate(U initial, AccumulateFn accumulate_func) const
Sums all the projected values of the sequence into a single value.
Definition query.h:672
Queryable< T > intersect(std::vector< T > rhs_items)
Produces the multiset intersection of two sequences.
Definition query.h:801
T max()
Gets the maximum item from the sequence.
Definition query.h:890
auto select(Selector selector)
Projects each item of a sequence into a new form.
Definition query.h:991
friend bool operator==(const Queryable< T > &lhs, const Queryable< T > &rhs)
Equals overload operator.
Definition query.h:260
Queryable< T > trim(size_t size)
Trim from the back of the sequence.
Definition query.h:1131
Queryable< std::vector< T > > group_by(KeySelector key_selector)
Groups the items of a sequence.
Definition query.h:781
Queryable< T > action(ActionFn action_func)
Executes a void action to create side effects.
Definition query.h:682
WhenTrue< T > branch(Predicate predicate)
Branches the sequence into two based on a condition.
Definition query.h:1365
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:877
False / else block query of Queryable<T>::branch method.
Definition query.h:1258
Merge< WhenTrueQueriedT, WhenFalseQueriedT > when_false(WhenFalseQuery when_false_query)
Projects each item of the false branched sequence into a new form from the Queryable<T>::branch of th...
Definition query.h:1298
WhenFalse(Queryable< WhenTrueQueriedT > when_true_queried, std::vector< T > when_false_items)
Construct a new WhereFalse object from a sequence of transformed items from the true branch of the pr...
Definition query.h:1270
True / if block query of Queryable<T>::branch method.
Definition query.h:1315
WhenTrue(std::vector< T > when_true_items, std::vector< T > when_false_items)
Construct a new WhereTrue object from a sequence of true and false branched items of the predicate th...
Definition query.h:1326
WhenFalse< WhenTrueQueriedT, T > when_true(WhenTrueQuery when_true_query)
Projects each item of the true branched sequence into a new form from the Queryable<T>::branch of the...
Definition query.h:1352
static invariant eval(bool condition)
Evaluate the invariant and throw std::invalid_argument if violated.
Definition asserts.h:100
Queryable< T > query(std::vector< T > items)
Queries the sequence of items using a vector.
Definition query.h:663
Traits for asserting object features.