#pragma once #include #include #include #include #include #include namespace waybar::util { /// Joins a sequence of strings, separating them using `js` template // Models InputIterator std::string join_strings(StrIterator b, StrIterator e, std::string_view js = ", ") { std::string result; std::for_each(b, e, [&](auto&& s) { if (!result.empty()) { result.append(js); } result.append(s); }); return result; } inline const char* nonull(const char* str) { if (str == nullptr) return ""; return str; }; inline bool iequals(std::string_view a, std::string_view b) { return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { return tolower(a) == tolower(b); }); } inline bool starts_with(std::string_view prefix, std::string_view a) { return a.compare(0, prefix.size(), prefix) == 0; } inline bool ends_with(std::string_view prefix, std::string_view a) { return a.compare(a.size() - prefix.size(), prefix.size(), prefix) == 0; } /// Return a closure which compares the adress any reference to T to the address of t template constexpr auto addr_eq(T&& t) { return [&t] (auto&& t2) { return &t == &t2; }; } template bool erase_this(std::vector& cont, T* el) { if (el < cont.data() && el >= cont.data() + cont.size()) return false; cont.erase(cont.begin() + (el - cont.data())); return true; } template bool erase_this(std::vector& cont, T& el) { return erase_this(cont, &el); } namespace detail { template constexpr auto generate_array_impl(std::integer_sequence&&, Func&& gen) { return std::array()))>, sizeof...(ns)>{{std::invoke(gen, ns)...}}; } } // namespace detail template constexpr auto generate_array(Func&& gen) { auto intseq = std::make_integer_sequence(); return detail::generate_array_impl(std::move(intseq), std::forward(gen)); } namespace view { namespace detail { template using store_or_ref_t = std::conditional_t, std::decay_t, T&>; } template struct reverse { reverse(Cont&& cont) noexcept : _container(std::forward(cont)) {} auto begin() { return std::rbegin(_container); } auto end() { return std::rend(_container); } auto begin() const { return std::rbegin(_container); } auto end() const { return std::rend(_container); } auto cbegin() const { return std::crbegin(_container); } auto cend() const { return std::crend(_container); } detail::store_or_ref_t _container; }; template reverse(ContRef&& cont) -> reverse; template struct constant { constant(Cont&& cont) noexcept : _container(std::forward(cont)){}; auto begin() const { return std::cbegin(_container); } auto end() const { return std::cend(_container); } auto cbegin() const { return std::cbegin(_container); } auto cend() const { return std::cend(_container); } detail::store_or_ref_t _container; }; template constant(ContRef&& cont) -> constant; } // namespace view /* * Range algorithms */ template constexpr InputIt for_each_n(InputIt&& first, Size n, F&& f) { for (Size i = 0; i < n; ++first, ++i) { std::invoke(f, *first); } return first; } /// `for_each` with access to an index value. Function called as `f(*it, i)` /// /// For each item in range `[first, last)`, invoke `f` with args /// `*iter, i` where `iter` is the current iterator, and `i` is /// an incrementing value, starting at zero. Use this instead of /// raw indexed loops wherever possible. /// /// \param first Input iterator to the begining of the range /// \param last Input iterator to the end of the range /// \param f Must be invocable with arguments `value_type`, `std::size_t` /// \returns The number of iterations performed template constexpr std::size_t indexed_for(InputIt&& first, InputIt&& last, F&& f) { std::size_t i = 0; std::for_each(std::forward(first), std::forward(last), [&](auto&& a) { std::invoke(f, a, i); i++; }); return i; } template constexpr std::size_t indexed_for(Rng&& rng, F&& f) { return indexed_for(std::begin(rng), std::end(rng), std::forward(f)); } /// `for_each_n` with access to an index value. Function called as `f(*it, i)` /// /// for `n` iterations, invoke `f` with args `*iter, i` /// where `iter` is the current iterator starting with `first`, /// and `i` is an incrementing value, starting at zero. /// Use this instead of raw indexed loops wherever possible. /// /// \param first Input iterator to the begining of the range /// \param n Number of iterations to go through /// \param f Must be invocable with arguments `value_type`, `std::size_t` /// \returns An iterator one past the last one visited template constexpr InputIt indexed_for_n(InputIt first, Size n, F&& f) { for (Size i = 0; i < n; ++first, ++i) { std::invoke(f, *first, i); } return first; } template constexpr std::size_t indexed_for_n(Rng&& rng, Size n, F&& f) { return indexed_for_n(std::begin(rng), std::end(rng), n, std::forward(f)); } template constexpr void for_both(Iter1&& f1, Iter1&& l1, Iter2&& f2, Iter2&& l2, F&& f) { Iter1 i1 = std::forward(f1); Iter2 i2 = std::forward(f2); for (; i1 != l1 && i2 != l2; i1++, i2++) { std::invoke(f, *i1, *i2); } } template constexpr void for_both(Rng1&& r1, Rng2&& r2, F&& f) { for_both(std::begin(r1), std::end(r1), std::begin(r2), std::end(r2), std::forward(f)); } /* * Range based standard algorithms * * Thanks, chris from SO! */ template constexpr auto accumulate(Cont&& cont, T&& init) { // TODO C++20: std::accumulate is constexpr using std::begin, std::end; auto first = begin(cont); auto last = end(cont); for (; first != last; ++first) init = init + *first; return init; } template constexpr auto accumulate(Cont&& cont, T&& init, BinaryOperation&& op) { // TODO C++20: std::accumulate is constexpr using std::begin, std::end; auto first = begin(cont); auto last = end(cont); for (; first != last; ++first) init = op(init, *first); return init; } template decltype(auto) adjacent_difference(Cont&& cont, OutputIterator&& first) { using std::begin; using std::end; return std::adjacent_difference(begin(cont), end(cont), std::forward(first)); } template decltype(auto) prev_permutation(Cont&& cont) { using std::begin; using std::end; return std::prev_permutation(begin(cont), end(cont)); } template decltype(auto) prev_permutation(Cont&& cont, Compare&& comp) { using std::begin; using std::end; return std::prev_permutation(begin(cont), end(cont), std::forward(comp)); } template decltype(auto) push_heap(Cont&& cont) { using std::begin; using std::end; return std::push_heap(begin(cont), end(cont)); } template decltype(auto) push_heap(Cont&& cont, Compare&& comp) { using std::begin; using std::end; return std::push_heap(begin(cont), end(cont), std::forward(comp)); } template decltype(auto) remove(Cont&& cont, T&& value) { using std::begin; using std::end; return std::remove(begin(cont), end(cont), std::forward(value)); } template decltype(auto) remove_copy(Cont&& cont, OutputIterator&& first, T&& value) { using std::begin; using std::end; return std::remove_copy(begin(cont), end(cont), std::forward(first), std::forward(value)); } template decltype(auto) remove_copy_if(Cont&& cont, OutputIterator&& first, UnaryPredicate&& p) { using std::begin; using std::end; return std::remove_copy_if(begin(cont), end(cont), std::forward(first), std::forward(p)); } template decltype(auto) remove_if(Cont&& cont, UnaryPredicate&& p) { using std::begin; using std::end; return std::remove_if(begin(cont), end(cont), std::forward(p)); } template decltype(auto) replace(Cont&& cont, T&& old_value, T2&& new_value) { using std::begin; using std::end; return std::replace(begin(cont), end(cont), std::forward(old_value), std::forward(new_value)); } template decltype(auto) replace_copy(Cont&& cont, OutputIterator&& first, T&& old_value, T2&& new_value) { using std::begin; using std::end; return std::replace_copy(begin(cont), end(cont), std::forward(first), std::forward(old_value), std::forward(old_value)); } template decltype(auto) replace_copy_if(Cont&& cont, OutputIterator&& first, UnaryPredicate&& p, T&& new_value) { using std::begin; using std::end; return std::replace_copy(begin(cont), end(cont), std::forward(first), std::forward(p), std::forward(new_value)); } template decltype(auto) replace_if(Cont&& cont, UnaryPredicate&& p, T&& new_value) { using std::begin; using std::end; return std::replace_if(begin(cont), end(cont), std::forward(p), std::forward(new_value)); } template decltype(auto) reverse(Cont&& cont) { using std::begin; using std::end; return std::reverse(begin(cont), end(cont)); } template decltype(auto) reverse_copy(Cont&& cont, OutputIterator&& first) { using std::begin; using std::end; return std::reverse_copy(begin(cont), end(cont), std::forward(first)); } template decltype(auto) rotate(Cont&& cont, ForwardIterator&& new_first) { using std::begin; using std::end; return std::rotate(begin(cont), std::forward(new_first), end(cont)); } template decltype(auto) rotate_copy(Cont&& cont, ForwardIterator&& new_first, OutputIterator&& first) { using std::begin; using std::end; return std::rotate_copy(begin(cont), std::forward(new_first), end(cont), std::forward(first)); } template decltype(auto) search(Cont&& cont, Cont2&& cont2) { using std::begin; using std::end; return std::search(begin(cont), end(cont), begin(cont2), end(cont2)); } template decltype(auto) search(Cont&& cont, Cont2&& cont2, BinaryPredicate&& p) { using std::begin; using std::end; return std::search(begin(cont), end(cont), begin(cont2), end(cont2), std::forward(p)); } template decltype(auto) search_n(Cont&& cont, Size count, T&& value) { using std::begin; using std::end; return std::search_n(begin(cont), end(cont), count, std::forward(value)); } template decltype(auto) search_n(Cont&& cont, Size count, T&& value, BinaryPredicate&& p) { using std::begin; using std::end; return std::search_n(begin(cont), end(cont), count, std::forward(value), std::forward(p)); } template decltype(auto) set_difference(Cont&& cont, Cont2&& cont2, OutputIterator&& first) { using std::begin; using std::end; return std::set_difference(begin(cont), end(cont), begin(cont2), end(cont2), std::forward(first)); } template decltype(auto) set_difference(Cont&& cont, Cont2&& cont2, OutputIterator&& first, Compare&& comp) { using std::begin; using std::end; return std::set_difference(begin(cont), end(cont), begin(cont2), end(cont2), std::forward(first), std::forward(comp)); } template decltype(auto) set_intersection(Cont&& cont, Cont2&& cont2, OutputIterator&& first) { using std::begin; using std::end; return std::set_intersection(begin(cont), end(cont), begin(cont2), end(cont2), std::forward(first)); } template decltype(auto) set_intersection(Cont&& cont, Cont2&& cont2, OutputIterator&& first, Compare&& comp) { using std::begin; using std::end; return std::set_intersection(begin(cont), end(cont), begin(cont2), end(cont2), std::forward(first), std::forward(comp)); } template decltype(auto) set_symmetric_difference(Cont&& cont, Cont2&& cont2, OutputIterator&& first) { using std::begin; using std::end; return std::set_symmetric_difference(begin(cont), end(cont), begin(cont2), end(cont2), std::forward(first)); } template decltype(auto) set_symmetric_difference(Cont&& cont, Cont2&& cont2, OutputIterator&& first, Compare&& comp) { using std::begin; using std::end; return std::set_symmetric_difference(begin(cont), end(cont), begin(cont2), end(cont2), std::forward(first), std::forward(comp)); } template decltype(auto) set_union(Cont&& cont, Cont2&& cont2, OutputIterator&& first) { using std::begin; using std::end; return std::set_union(begin(cont), end(cont), begin(cont2), end(cont2), std::forward(first)); } template decltype(auto) set_union(Cont&& cont, Cont2&& cont2, OutputIterator&& first, Compare&& comp) { using std::begin; using std::end; return std::set_union(begin(cont), end(cont), begin(cont2), end(cont2), std::forward(first), std::forward(comp)); } template decltype(auto) shuffle(Cont&& cont, UniformRandomNumberGenerator&& g) { using std::begin; using std::end; return std::shuffle(begin(cont), end(cont), std::forward(g)); } template decltype(auto) sort(Cont&& cont) { using std::begin; using std::end; return std::sort(begin(cont), end(cont)); } template decltype(auto) sort(Cont&& cont, Compare&& comp) { using std::begin; using std::end; return std::sort(begin(cont), end(cont), std::forward(comp)); } template decltype(auto) sort_heap(Cont&& cont) { using std::begin; using std::end; return std::sort_heap(begin(cont), end(cont)); } template decltype(auto) sort_heap(Cont&& cont, Compare&& comp) { using std::begin; using std::end; return std::sort_heap(begin(cont), end(cont), std::forward(comp)); } template decltype(auto) stable_partition(Cont&& cont, UnaryPredicate&& p) { using std::begin; using std::end; return std::stable_partition(begin(cont), end(cont), std::forward(p)); } template decltype(auto) stable_sort(Cont&& cont) { using std::begin; using std::end; return std::stable_sort(begin(cont), end(cont)); } template decltype(auto) stable_sort(Cont&& cont, Compare&& comp) { using std::begin; using std::end; return std::stable_sort(begin(cont), end(cont), std::forward(comp)); } template decltype(auto) swap_ranges(Cont&& cont, ForwardIterator&& first) { using std::begin; using std::end; return std::swap_ranges(begin(cont), end(cont), std::forward(first)); } template auto transform(Cont&& cont, Cont2&& cont2, F&& f) -> decltype(begin(cont2)) { using std::begin; using std::end; return std::transform(begin(cont), end(cont), begin(cont2), std::forward(f)); } template decltype(auto) transform(Cont&& cont, Iter&& iter, F&& f) { using std::begin; using std::end; return std::transform(begin(cont), end(cont), std::forward(iter), std::forward(f)); } template auto transform(Cont&& cont, Cont2&& cont2, Cont3&& cont3, BinaryPredicate&& f) -> decltype(begin(cont2), begin(cont3)) { using std::begin; using std::end; return std::transform(begin(cont), end(cont), begin(cont2), begin(cont3), std::forward(f)); } template auto transform(Cont&& cont, InputIterator&& iter, Cont3&& cont3, BinaryPredicate&& f) -> decltype(begin(cont), begin(cont3)) { using std::begin; using std::end; return std::transform(begin(cont), end(cont), std::forward(iter), begin(cont3), std::forward(f)); } template auto transform(Cont&& cont, Cont2&& cont2, InputIterator&& iter, BinaryPredicate&& f) -> decltype(begin(cont), begin(cont2), iter) { using std::begin; using std::end; return std::transform(begin(cont), end(cont), begin(cont2), std::forward(iter), std::forward(f)); } template decltype(auto) transform(Cont&& cont, InputIterator&& firstIn, OutputIterator&& firstOut, BinaryOperation&& op) { using std::begin; using std::end; return std::transform(begin(cont), end(cont), std::forward(firstIn), std::forward(firstOut), std::forward(op)); } template decltype(auto) unique(Cont&& cont) { using std::begin; using std::end; return std::unique(begin(cont), end(cont)); } template decltype(auto) unique(Cont&& cont, BinaryPredicate&& p) { using std::begin; using std::end; return std::unique(begin(cont), end(cont), std::forward(p)); } template decltype(auto) unique_copy(Cont&& cont, OutputIterator&& first) { using std::begin; using std::end; return std::unique_copy(begin(cont), end(cont), std::forward(first)); } template decltype(auto) unique_copy(Cont&& cont, OutputIterator&& first, BinaryPredicate&& p) { using std::begin; using std::end; return std::unique_copy(begin(cont), end(cont), std::forward(first), std::forward(p)); } template decltype(auto) upper_bound(Cont&& cont, T&& value) { using std::begin; using std::end; return std::upper_bound(begin(cont), end(cont), std::forward(value)); } template decltype(auto) upper_bound(Cont&& cont, T&& value, Compare&& comp) { using std::begin; using std::end; return std::upper_bound(begin(cont), end(cont), std::forward(value), std::forward(comp)); } template decltype(auto) copy(Cont&& cont, OutputIterator&& first) { using std::begin; using std::end; return std::copy(begin(cont), end(cont), std::forward(first)); } template decltype(auto) copy_if(Cont&& cont, OutputIterator&& first, UnaryPredicate&& p) { using std::begin; using std::end; return std::copy_if(begin(cont), end(cont), std::forward(first), std::forward(p)); } template decltype(auto) fill(Cont&& cont, T&& value) { using std::begin; using std::end; return std::fill(begin(cont), end(cont), std::forward(value)); } template decltype(auto) fill_n(Cont&& cont, std::size_t n, T&& value) { using std::begin; using std::end; return std::fill_n(begin(cont), n, std::forward(value)); } template decltype(auto) any_of(Cont&& cont, UnaryPredicate&& p) { using std::begin; using std::end; return std::any_of(begin(cont), end(cont), std::forward(p)); } template decltype(auto) all_of(Cont&& cont, UnaryPredicate&& p) { using std::begin; using std::end; return std::all_of(begin(cont), end(cont), std::forward(p)); } template decltype(auto) none_of(Cont&& cont, UnaryPredicate&& p) { using std::begin; using std::end; return std::none_of(begin(cont), end(cont), std::forward(p)); } template decltype(auto) max_element(Cont&& cont) { using std::begin; using std::end; return std::max_element(begin(cont), end(cont)); } template decltype(auto) min_element(Cont&& cont) { using std::begin; using std::end; return std::min_element(begin(cont), end(cont)); } template decltype(auto) min_element(Cont&& cont, Compare&& f) { using std::begin; using std::end; return std::min_element(begin(cont), end(cont), std::forward(f)); } template decltype(auto) max_element(Cont&& cont, Compare&& f) { using std::begin; using std::end; return std::max_element(begin(cont), end(cont), std::forward(f)); } template decltype(auto) find(Cont&& cont, T&& t) { using std::begin; using std::end; return std::find(begin(cont), end(cont), std::forward(t)); } template decltype(auto) find_if(Cont&& cont, UnaryPredicate&& f) { using std::begin; using std::end; return std::find_if(begin(cont), end(cont), std::forward(f)); } } // namespace waybar::util