#pragma once #include #include #include #include #include namespace geode::vector_utils { /** * 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 bool contains(std::vector 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 * std::vector::end if the item is not in the vector. */ template typename std::vector::const_iterator indexOf(std::vector 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 bool contains(std::vector const& vec, std::function 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 void push(std::vector & vec, std::vector 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 std::string join(std::vector const& vec, std::string const& sep) { std::string res = ""; for (auto p : vec) { if constexpr (std::is_same_v) { 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 std::vector map(std::vector const& vec, std::function mapFunc) { std::vector 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 std::vector& filterIP(std::vector & vec, std::function filterFunc) { std::vector 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 std::vector filter(std::vector const& vec, std::function filterFunc) { std::vector 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 T select(std::vector const& vec, std::function selectFunc) { for (auto const& v : vec) { if (selectFunc(v)) { return v; } } if (std::is_pointer::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 std::vector selectAll(std::vector const& vec, std::function selectFunc) { return filter(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 std::vector& erase(std::vector& vec, T 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 std::vector& erase(std::vector& vec, std::function 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 * std::vector numbers = { 1, 3, 7, 8, }; * int total = reduce(numbers, [](int& acc, int val) -> void { * acc += val; * }); // 19 * ``` * @returns Reduced value. */ template R reduce(std::vector const& vec, std::function 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 void insertBefore(std::vector & vec, T const& item, T const& before) { vec.insert(vector_utils::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 void insertAfter(std::vector & vec, T const& item, T const& after) { vec.insert(vector_utils::indexOf(vec, after) + 1, item); } }