Last active
January 28, 2018 01:53
-
-
Save Ostoic/854b5f6ec3ec0abe71bb9dbc2802a6b8 to your computer and use it in GitHub Desktop.
A few constexpr algorithms for use with std::array
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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