Skip to content

Instantly share code, notes, and snippets.

@Ostoic
Last active January 28, 2018 01:53
Show Gist options
  • Save Ostoic/854b5f6ec3ec0abe71bb9dbc2802a6b8 to your computer and use it in GitHub Desktop.
Save Ostoic/854b5f6ec3ec0abe71bb9dbc2802a6b8 to your computer and use it in GitHub Desktop.
A few constexpr algorithms for use with std::array
#include <array>
#include <iostream>
#include <type_traits>
#include <vector>
// Array factory for type deduction
template <typename... Ts>
constexpr auto make_array(Ts&&... ts) noexcept
{
return std::array<std::common_type_t<Ts...>, sizeof...(Ts)>{std::forward<Ts>(ts)...};
}
namespace detail
{
//
template <typename T, std::size_t Size, std::size_t... Is>
constexpr auto array_from_subsequence(const std::array<T, Size>& array, std::index_sequence<Is...> sequence) noexcept
{
return make_array(std::get<Is>(array)...);
}
// Create a new std::array of size Size1+Size2, whose elements are {a1[0], ...., a1[Size1-1], a2[0], ..., a2[Size2-1]}.
template <typename T, std::size_t Size1, std::size_t Size2,
std::size_t... I1s,
std::size_t... I2s
>
constexpr std::array<T, Size1 + Size2> append_impl(
const std::array<T, Size1>& array1,
const std::array<T, Size2>& array2,
std::index_sequence<I1s...>, std::index_sequence<I2s...>) noexcept
{
// Expand the first and second sequences according to the pattern std::get<index>(array).
return make_array(std::get<I1s>(array1)..., std::get<I2s>(array2)...);
}
}
// Push the given element to the end of the array.
// Returns the array {a1[0], ..., a1[Size1-1], value}
template <typename T, std::size_t Size>
constexpr std::array<T, Size + 1> push_back(const std::array<T, Size>& array, const T& value) noexcept
{
// Call append for the arrays array, {value}, such that value is lifted into an array object.
return append(array, make_array(value));
}
// Append the second array to the end of the first array.
// Result is the array {a1[0], ..., a1[Size1-1], a2[0], ..., a2[Size2-1]}
template <typename T, std::size_t Size1, std::size_t Size2>
constexpr std::array<T, Size1 + Size2> append(const std::array<T, Size1>& array1, const std::array<T, Size2>& array2) noexcept
{
return detail::append_impl(array1, array2, std::make_index_sequence<Size1>{}, std::make_index_sequence<Size2>{});
}
// Returns the array {array[0], array[1], array[2], ..., array[Size - 1]}.
// Similar to std::vector's pop_back.
template <typename T, std::size_t Size>
constexpr auto pop_back(const std::array<T, Size>& array) noexcept
{
// Creates array with index sequence {0, 1, 2, ..., Size - 1}.
return detail::array_from_subsequence(array, std::make_index_sequence<Size - 1>{});
}
// Pop_back "Length" times
template <std::size_t Length, typename T, std::size_t Size>
constexpr auto truncate(const std::array<T, Size>& array) noexcept
{
// Creates array with index sequence {0, 1, 2, ..., Size - 1}.
return detail::array_from_subsequence(array, std::make_index_sequence<Size - Length>{});
}
// Overload stream operator for arrays.
template <typename T, std::size_t Size>
std::ostream& operator<<(std::ostream& stream, const std::array<T, Size>& array)
{
for (const auto& each : array)
stream << each << ' ';
return stream;
}
int main()
{
constexpr auto array1 = make_array(1, 2, 3);
constexpr auto array2 = make_array(4, 5, 6);
constexpr auto appended = append(array1, array2);
constexpr auto popped = pop_back(appended);
std::cout << appended << '\n';
std::cout << popped << '\n';
std::cout << truncate<2>(appended) << '\n';
std::cout << truncate<3>(appended) << '\n';
std::cout << truncate<4>(appended) << '\n';
std::cout << truncate<5>(appended) << '\n';
return 0;
}
/*
Running this file outputs:
1 2 3 4 5 6
1 2 3 4 5
1 2 3 4
1 2 3
1 2
1
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment