From 5282fdde4636016314befe7110a7d4573c597c7c Mon Sep 17 00:00:00 2001 From: BlackMark Date: Fri, 27 May 2022 20:39:17 +0200 Subject: [PATCH] Add constexpr C++ array wrapper --- array.hpp | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ type.hpp | 12 +-- 2 files changed, 245 insertions(+), 5 deletions(-) create mode 100644 array.hpp diff --git a/array.hpp b/array.hpp new file mode 100644 index 0000000..388878a --- /dev/null +++ b/array.hpp @@ -0,0 +1,238 @@ +#pragma once + +#include + +#include "type.hpp" +#include "util.hpp" + +namespace util { + +template +struct array { + using value_type = T; + using size_type = size_t; + using difference_type = ptrdiff_t; + using reference = value_type &; + using const_reference = const value_type &; + using pointer = value_type *; + using const_pointer = const value_type *; + using iterator = pointer; + using const_iterator = const_pointer; + // using reverse_iterator = ; + // using const_reverse_iterator = ; + + constexpr reference at(size_type pos) + { + if (pos >= N) { + return *static_cast(nullptr); + } + + return m_data[pos]; + } + + constexpr const_reference at(size_type pos) const + { + if (pos >= N) { + return *static_cast(nullptr); + } + + return m_data[pos]; + } + + constexpr reference operator[](size_type pos) + { + return m_data[pos]; + } + + constexpr const_reference operator[](size_type pos) const + { + return m_data[pos]; + } + + constexpr reference front() + { + return m_data[0]; + } + + constexpr const_reference front() const + { + return m_data[0]; + } + + constexpr reference back() + { + return m_data[N - 1]; + } + + constexpr const_reference back() const + { + return m_data[N - 1]; + } + + constexpr pointer data() noexcept + { + return m_data; + } + + constexpr const_pointer data() const noexcept + { + return m_data; + } + + constexpr iterator begin() noexcept + { + return &m_data[0]; + } + + constexpr const_iterator begin() const noexcept + { + return &m_data[0]; + } + + constexpr const_iterator cbegin() const noexcept + { + return &m_data[0]; + } + + constexpr iterator end() noexcept + { + return &m_data[N]; + } + + constexpr const_iterator end() const noexcept + { + return &m_data[N]; + } + + constexpr const_iterator cend() const noexcept + { + return &m_data[N]; + } + + // reverse_iterator rbegin() noexcept; + // const_reverse_iterator rbegin() const noexcept; + // const_reverse_iterator crbegin() const noexcept; + + // reverse_iterator rend() noexcept; + // const_reverse_iterator rend() const noexcept; + // const_reverse_iterator crend() const noexcept; + + constexpr bool empty() const noexcept + { + return N == 0; + } + + constexpr size_type size() const noexcept + { + return N; + } + + constexpr size_type max_size() const noexcept + { + return N; + } + + constexpr void fill(const T &value) + { + for (size_t i = 0; i < N; ++i) { + m_data[i] = value; + } + } + + constexpr void swap(array &other) noexcept(noexcept(swap(declval(), declval()))) + { + for (size_t i = 0; i < N; ++i) { + T tmp = m_data[i]; + m_data[i] = other.m_data[i]; + other.m_data[i] = tmp; + } + } + + ////////////////////////////////////////////////////////////////////////// + + friend constexpr bool operator==(const array &lhs, const array &rhs) + { + for (size_t i = 0; i < N; ++i) { + if (!(lhs[i] == rhs[i])) { + return false; + } + } + + return true; + } + + friend constexpr bool operator!=(const array &lhs, const array &rhs) + { + return !(lhs == rhs); + } + + friend constexpr bool operator<(const array &lhs, const array &rhs) + { + for (size_t i = 0; i < N; ++i) { + if (rhs[i] < lhs[i]) { + return false; + } else if (lhs[i] < rhs[i]) { + return true; + } + } + + return false; + } + + friend constexpr bool operator<=(const array &lhs, const array &rhs) + { + return !(rhs < lhs); + } + + friend constexpr bool operator>(const array &lhs, const array &rhs) + { + return (rhs < lhs); + } + + friend constexpr bool operator>=(const array &lhs, const array &rhs) + { + return !(lhs < rhs); + } + + ////////////////////////////////////////////////////////////////////////// + + T m_data[N]; +}; + +////////////////////////////////////////////////////////////////////////// + +namespace detail { + +template +constexpr array, N> to_array_impl(T (&a)[N], index_sequence) +{ + return {{a[I]...}}; +} + +template +constexpr array, N> to_array_impl(T(&&a)[N], index_sequence) +{ + return {{move(a[I])...}}; +} + +} // namespace detail + +template +constexpr array, N> to_array(T (&a)[N]) +{ + return detail::to_array_impl(a, make_index_sequence{}); +} + +template +constexpr array, N> to_array(T(&&a)[N]) +{ + return detail::to_array_impl(move(a), make_index_sequence{}); +} + +////////////////////////////////////////////////////////////////////////// +// deduction guides + +template +array(T, U...)->array; + +} // namespace util diff --git a/type.hpp b/type.hpp index f92d265..4474ca1 100644 --- a/type.hpp +++ b/type.hpp @@ -33,6 +33,10 @@ template using bool_constant = integral_constant; using false_type = bool_constant; using true_type = bool_constant; +// Not part of , but very useful +template struct always_false : false_type {}; +template inline constexpr auto always_false_v = always_false::value; + template struct is_const : false_type {}; template struct is_const : true_type {}; template inline constexpr bool is_const_v = is_const::value; @@ -247,7 +251,9 @@ namespace util { template struct reference_wrapper; template inline constexpr T &&forward(util::remove_reference_t &t) noexcept; -template util::add_rvalue_reference_t declval() noexcept; +template util::add_rvalue_reference_t declval() noexcept { + static_assert(always_false_v, "declval not allowed in an evaluated context"); +} } // namespace util @@ -307,10 +313,6 @@ struct invoke_result(), util::declval struct invoke_result : detail::invoke_result {}; template using invoke_result_t = typename invoke_result::type; -// Not part of , but very useful -template struct always_false : false_type {}; -template inline constexpr auto always_false_v = always_false::value; - // template struct numeric_limits {};