cs-midi/AH/Containers/ArrayHelpers.hpp

168 lines
4.8 KiB
C++

#pragma once
#include "Array.hpp"
#include <AH/STL/algorithm>
#if __cplusplus >= 201400L
#define USE_CONSTEXPR_ARRAY_HELPERS constexpr
#else
#define USE_CONSTEXPR_ARRAY_HELPERS
#endif
BEGIN_AH_NAMESPACE
namespace detail {
template <class T, class V>
class Incrementor {
public:
USE_CONSTEXPR_ARRAY_HELPERS Incrementor(T start = 0, V increment = 1)
: value(start), increment(increment) {}
USE_CONSTEXPR_ARRAY_HELPERS T operator()() {
T temp = value;
value += increment;
return temp;
}
private:
T value;
const V increment;
};
} // namespace detail
template <class T, size_t N, class G>
USE_CONSTEXPR_ARRAY_HELPERS Array<T, N> generateArray(G generator) {
Array<T, N> array{{}};
std::generate(array.begin(), array.end(), generator);
return array;
}
template <size_t N, class G>
USE_CONSTEXPR_ARRAY_HELPERS auto generateArray(G generator)
-> Array<decltype(generator()), N> {
Array<decltype(generator()), N> array{{}};
std::generate(array.begin(), array.end(), generator);
return array;
}
template <class T, size_t N, class U>
USE_CONSTEXPR_ARRAY_HELPERS Array<T, N> copyAs(const Array<U, N> &src) {
Array<T, N> dest{{}};
std::transform(std::begin(src), std::end(src), std::begin(dest),
[](const U &src) { return T(src); });
return dest;
}
template <class F, class U, size_t N>
USE_CONSTEXPR_ARRAY_HELPERS Array<decltype(F{}(U{})), N>
apply(const Array<U, N> &src, F f) {
Array<decltype(F{}(U{})), N> dest{{}};
std::transform(std::begin(src), std::end(src), std::begin(dest), f);
return dest;
}
template <class T, size_t N, class... Args>
USE_CONSTEXPR_ARRAY_HELPERS Array<T, N> fillArray(Args... args) {
return generateArray<N>([&]() { return T{args...}; });
}
template <class T, size_t N, class U, class V = U>
USE_CONSTEXPR_ARRAY_HELPERS Array<T, N>
generateIncrementalArray(U start = 0, V increment = V(1)) {
detail::Incrementor<U, V> g(start, increment);
return generateArray<T, N>(g);
}
template <class T, size_t M, size_t N>
USE_CONSTEXPR_ARRAY_HELPERS Array<T, M + N> cat(const Array<T, M> &a,
const Array<T, N> &b) {
Array<T, M + N> result{{}};
size_t r = 0;
for (size_t i = 0; i < M; ++i, ++r)
result[r] = a[i];
for (size_t i = 0; i < N; ++i, ++r)
result[r] = b[i];
return result;
}
template <class T1, class T2, size_t N1, size_t N2, bool Reverse1,
bool Reverse2, bool Const1, bool Const2>
USE_CONSTEXPR_ARRAY_HELPERS Array<decltype(T1() * T2()), N1 + N2 - 1>
distribute(const ArraySlice<T1, N1, Reverse1, Const1> &a,
const ArraySlice<T2, N2, Reverse2, Const2> &b) {
Array<decltype(T1() * T2()), N1 + N2 - 1> result = {{}};
for (size_t i = 0; i < N1; ++i)
for (size_t j = 0; j < N2; ++j)
result[i + j] += a[i] * b[j];
return result;
}
template <class T1, class T2, size_t N1, size_t N2, bool Reverse1, bool Const1>
USE_CONSTEXPR_ARRAY_HELPERS Array<decltype(T1() * T2()), N1 + N2 - 1>
distribute(const ArraySlice<T1, N1, Reverse1, Const1> &a,
const Array<T2, N2> &b) {
return distribute(a, b.slice());
}
template <class T1, class T2, size_t N1, size_t N2, bool Reverse2, bool Const2>
USE_CONSTEXPR_ARRAY_HELPERS Array<decltype(T1() * T2()), N1 + N2 - 1>
distribute(const Array<T1, N1> &a,
const ArraySlice<T2, N2, Reverse2, Const2> &b) {
return distribute(a.slice(), b);
}
template <class T1, class T2, size_t N1, size_t N2>
USE_CONSTEXPR_ARRAY_HELPERS Array<decltype(T1() * T2()), N1 + N2 - 1>
distribute(const Array<T1, N1> &a, const Array<T2, N2> &b) {
return distribute(a.slice(), b.slice());
}
END_AH_NAMESPACE
#ifndef ARDUINO
#include <ostream>
BEGIN_AH_NAMESPACE
template <class T, size_t N, bool Reverse, bool Const>
std::enable_if_t<std::is_arithmetic<T>::value, std::ostream &>
operator<<(std::ostream &os, const AH::ArraySlice<T, N, Reverse, Const> &a) {
for (const T &el : a.template slice<0, N - 2>())
os << el << ", ";
os << a[N - 1];
return os;
}
template <class T, size_t N>
std::enable_if_t<std::is_arithmetic<T>::value, std::ostream &>
operator<<(std::ostream &os, const AH::Array<T, N> &a) {
return os << a.slice();
}
END_AH_NAMESPACE
#endif
#include <AH/PrintStream/PrintStream.hpp>
BEGIN_AH_NAMESPACE
template <class T, size_t N, bool Reverse, bool Const>
std::enable_if_t<std::is_arithmetic<T>::value, Print &>
operator<<(Print &os, const AH::ArraySlice<T, N, Reverse, Const> &a) {
for (const T &el : a.template slice<0, N - 2>())
os << el << ", ";
os << a[N - 1];
return os;
}
template <class T, size_t N>
std::enable_if_t<std::is_arithmetic<T>::value, Print &>
operator<<(Print &os, const AH::Array<T, N> &a) {
return os << a.slice();
}
END_AH_NAMESPACE