geode/loader/include/Geode/utils/vector.hpp

246 lines
7.6 KiB
C++

#pragma once
#include <Geode/DefaultInclude.hpp>
#include <string>
#include <vector>
#include <functional>
#include <algorithm>
namespace geode::utils::vector {
/**
* Check if a vector contains an element by value.
* @param vec The vector to check.
* @param elem The element to find.
* @returns True if element is in `vec`, false if not.
*/
template<class T>
bool contains(gd::vector<T> const& vec, T const& elem) {
return std::find(vec.begin(), vec.end(), elem) != vec.end();
}
/**
* Get the index of an element in a vector by value.
* @param vec The vector to check.
* @param elem The element to get the index of.
* @returns Iterator to the index of element, or
* gd::vector::end if the item is not in the vector.
*/
template<class T>
typename gd::vector<T>::const_iterator indexOf(gd::vector<T> const& vec, T const& elem) {
return std::find(vec.begin(), vec.end(), elem);
}
/**
* Check if a vector contains an element via a function.
* @param vec The vector to check.
* @param containFunc A function that returns bool if the
* element parameter is what is looked for.
* @returns True if an element matching `containFunc` is
* in `vec`, false if not.
*/
template<class T>
bool contains(gd::vector<T> const& vec, std::function<bool(T)> containFunc) {
for (auto const& item : vec) {
if (containFunc(item))
return true;
}
return false;
}
/**
* Add a vector to the end of another vector.
* @param vec The vector to add to.
* @param subVec The vector to add.
*/
template<class T>
void push(gd::vector<T> & vec, gd::vector<T> const& subVec) {
vec.insert(vec.begin(), subVec.begin(), subVec.end());
}
/**
* Turn a vector into a string. T must be either a string,
* or convertible via `std::to_string`.
* @param vec The vector to add to.
* @param sep Separator string.
* @returns Joined string.
*/
template<class T>
std::string join(gd::vector<T> const& vec, std::string const& sep) {
std::string res = "";
for (auto p : vec) {
if constexpr (std::is_same_v<T, std::string>) {
res += p + sep;
} else {
res += std::to_string(p) + sep;
}
}
res = res.substr(0, res.length() - sep.length());
return res;
}
/**
* Map a vector of items type T to a new vector of items
* type T2.
* @param vec The vector to map.
* @param mapFunc Function that converts an element from T to T2.
* @returns Mapped vector.
*/
template<class T, class T2>
gd::vector<T2> map(gd::vector<T> const& vec, std::function<T2(T)> mapFunc) {
gd::vector<T2> res;
std::transform(vec.begin(), vec.end(), res.end(), mapFunc);
return res;
}
/**
* Remove items from a vector that don't match the filter
* predicate.
* @param vec The vector to filter.
* @param filterFunc Predicate function that returns true
* if element should be kept in vector.
* @returns Filtered vector.
*/
template<class T>
gd::vector<T>& filterIP(gd::vector<T> & vec, std::function<bool(T)> filterFunc) {
gd::vector<T> res;
for (auto m : vec) {
if (filterFunc(m)) {
res.push_back(m);
}
}
vec = res;
return vec;
}
/**
* Return a copy of the vector that has items not
* matching `filterFunc` removed.
* @param vec The vector to filter.
* @param filterFunc Predicate function that returns true
* if element should be kept in vector.
* @returns Filtered vector.
*/
template<class T>
gd::vector<T> filter(gd::vector<T> const& vec, std::function<bool(T)> filterFunc) {
gd::vector<T> res;
for (auto m : vec) {
if (filterFunc(m)) {
res.push_back(m);
}
}
return res;
}
/**
* See if an item in the vector matching the predicate
* `selectFunc` exists, and return it if it does.
* @param vec The vector to select from.
* @param selectFunc Predicate function to see if a
* given item is what is looked for.
* @returns Found item, or the default of T if it was
* not found. If T is pointer type and item was not
* found, the return type is nullptr.
*/
template<class T>
T select(gd::vector<T> const& vec, std::function<bool(T)> selectFunc) {
for (auto const& v : vec) {
if (selectFunc(v)) {
return v;
}
}
if (std::is_pointer<T>::value) {
return nullptr;
}
return T();
}
/**
* Alias for `filter`.
* @param vec The vector to filter.
* @param selectFunc Predicate function that returns true
* if element should be kept in vector.
* @returns Filtered vector.
*/
template<class T>
gd::vector<T> selectAll(gd::vector<T> const& vec, std::function<bool(T)> selectFunc) {
return filter<T>(vec, selectFunc);
}
/**
* Remove elements from a vector by value.
* @param vec The vector to remove from.
* @param element Elements to remove.
* @returns Reference to vector.
*/
template<class T>
gd::vector<T>& erase(gd::vector<T>& vec, T const& element) {
vec.erase(std::remove(vec.begin(), vec.end(), element), vec.end());
return vec;
}
/**
* Remove elements from a vector via a function.
* @param vec The vector to remove from.
* @param eraseFunc Predicate function to decide whether
* to remove an element or not.
* @returns Reference to vector.
*/
template<class T>
gd::vector<T>& erase(gd::vector<T>& vec, std::function<bool(T)> eraseFunc) {
vec.erase(std::remove_if(vec.begin(), vec.end(), eraseFunc), vec.end());
return vec;
}
/**
* Reduce vector of elements to single value.
* @param vec The vector to reduce.
* @param reduceFunc Function to handle the
* creation of the reduced value. First parameter
* is a reference to the accumulator and second
* is the current item. Modify the value in the
* accumulator, for example with R += T, to
* compute the reduced value.
* @example ```cpp
* gd::vector<int> numbers = { 1, 3, 7, 8, };
* int total = reduce<int, int>(numbers, [](int& acc, int val) -> void {
* acc += val;
* }); // 19
* ```
* @returns Reduced value.
*/
template<class R, class T>
R reduce(gd::vector<T> const& vec, std::function<void(R&, T)> reduceFunc) {
R res = R();
for (auto const& item : vec) {
reduceFunc(res, item);
}
return res;
}
/**
* Insert an element in a vector before another
* element.
* @param vec Vector to insert into.
* @param item Element to insert.
* @param after Element to insert before.
*/
template<class T>
void insertBefore(gd::vector<T> & vec, T const& item, T const& before) {
vec.insert(utils::vector::indexOf(vec, before), item);
}
/**
* Insert an element in a vector after another
* element.
* @param vec Vector to insert into.
* @param item Element to insert.
* @param after Element to insert after.
*/
template<class T>
void insertAfter(gd::vector<T> & vec, T const& item, T const& after) {
vec.insert(utils::vector::indexOf(vec, after) + 1, item);
}
}