summaryrefslogtreecommitdiff
path: root/lib/collections.h
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2023-04-29 19:07:11 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2023-04-29 19:07:11 +0100
commit5a0b3927a33807cca4c77c40eb873f8a3b51b0b0 (patch)
tree4af0585ee8f8f468ab10c0a4fe9994fb30b79599 /lib/collections.h
parentDunno how, but some DOS new lines got in here! (diff)
downloadilt-5a0b3927a33807cca4c77c40eb873f8a3b51b0b0.tar.bz2
ilt-5a0b3927a33807cca4c77c40eb873f8a3b51b0b0.tar.xz
ilt-5a0b3927a33807cca4c77c40eb873f8a3b51b0b0.zip
Drop .hpp for header only things
Half of them acquired a .cpp part anyway
Diffstat (limited to 'lib/collections.h')
-rw-r--r--lib/collections.h159
1 files changed, 159 insertions, 0 deletions
diff --git a/lib/collections.h b/lib/collections.h
new file mode 100644
index 0000000..8f5a43d
--- /dev/null
+++ b/lib/collections.h
@@ -0,0 +1,159 @@
+#pragma once
+
+#include <algorithm>
+#include <array>
+#include <span>
+#include <utility>
+#include <vector>
+
+template<typename T, typename E>
+concept SequentialCollection = requires(T c) {
+ {
+ c.size()
+ } -> std::integral;
+ {
+ c.data()
+ } -> std::same_as<const E *>;
+ };
+template<typename T>
+concept IterableCollection = std::is_same_v<decltype(std::declval<T>().begin()), decltype(std::declval<T>().end())>;
+
+template<typename T, std::size_t first, std::size_t second>
+[[nodiscard]] constexpr std::array<T, first + second>
+operator+(const std::array<T, first> & a, const std::array<T, second> & b)
+{
+ std::array<T, first + second> r;
+ auto out = r.begin();
+ out = std::copy(a.begin(), a.end(), out);
+ std::copy(b.begin(), b.end(), out);
+ return r;
+}
+
+template<typename T, typename V, std::size_t first, std::size_t second>
+[[nodiscard]] constexpr std::array<std::pair<T, V>, first * second>
+operator*(const std::array<T, first> & a, const std::array<V, second> & b)
+{
+ std::array<std::pair<T, V>, first * second> r;
+ auto out = r.begin();
+ for (const auto & ae : a) {
+ for (const auto & be : b) {
+ *out++ = {ae, be};
+ }
+ }
+ return r;
+}
+
+template<typename T, std::size_t N>
+[[nodiscard]] constexpr auto
+operator*(const std::array<T, N> & in, auto && f)
+{
+ std::array<decltype(f(in[0])), N> out;
+
+ for (auto outitr = out.begin(); const auto & v : in) {
+ *outitr++ = f(v);
+ }
+ return out;
+}
+
+constexpr auto &
+operator*=(IterableCollection auto & in, auto && f)
+{
+ for (auto & v : in) {
+ f(v);
+ }
+ return in;
+}
+
+template<template<typename...> typename C, typename... T>
+ requires IterableCollection<C<T...>>
+[[nodiscard]] constexpr auto
+operator*(const C<T...> & in, auto && f)
+{
+ C<decltype(f(*in.begin()))> out;
+ if constexpr (requires { out.reserve(in.size()); }) {
+ out.reserve(in.size());
+ }
+
+ std::transform(in.begin(), in.end(), std::inserter(out, out.end()), f);
+ return out;
+}
+
+template<typename T, std::size_t N>
+[[nodiscard]] constexpr auto
+operator*(const std::span<T, N> in, auto && f)
+{
+ std::array<decltype(f(std::declval<T>())), N> out;
+
+ std::transform(in.begin(), in.end(), out.begin(), f);
+ return out;
+}
+
+template<typename T>
+[[nodiscard]] constexpr auto
+operator*(const std::span<T, std::dynamic_extent> in, auto && f)
+{
+ std::vector<decltype(f(std::declval<T>()))> out;
+
+ out.reserve(in.size());
+ std::transform(in.begin(), in.end(), std::inserter(out, out.end()), f);
+ return out;
+}
+
+template<typename... T>
+constexpr auto &
+operator+=(std::vector<T...> & in, std::vector<T...> && src)
+{
+ in.reserve(in.size() + src.size());
+ std::move(src.begin(), src.end(), std::back_inserter(in));
+ return in;
+}
+
+template<typename... T, typename Vn>
+[[nodiscard]] constexpr auto
+operator+(const std::vector<T...> & in, Vn && vn)
+{
+ auto out(in);
+ out.emplace_back(std::forward<Vn>(vn));
+ return out;
+}
+
+template<template<typename> typename Direction = std::plus, typename T = unsigned int>
+[[nodiscard]] static auto
+vectorOfN(std::integral auto N, T start = {}, T step = 1)
+{
+ std::vector<T> v;
+ v.resize(N);
+ std::generate_n(v.begin(), N, [&start, step, adj = Direction {}]() {
+ return std::exchange(start, adj(start, step));
+ });
+ return v;
+}
+
+template<template<typename...> typename Rtn = std::vector, IterableCollection In>
+[[nodiscard]] auto
+materializeRange(In && in)
+{
+ return Rtn(in.begin(), in.end());
+}
+
+template<template<typename...> typename Rtn = std::vector, typename In>
+[[nodiscard]] auto
+materializeRange(const std::pair<In, In> & in)
+{
+ return Rtn(in.first, in.second);
+}
+
+template<typename T> struct pair_range {
+ constexpr auto &
+ begin() const noexcept
+ {
+ return pair.first;
+ }
+ constexpr auto &
+ end() const noexcept
+ {
+ return pair.second;
+ }
+ const std::pair<T, T> & pair;
+};
+template<typename T> pair_range(std::pair<T, T>) -> pair_range<T>;