diff --git a/ref_app/src/math/functions/math_functions_hypergeometric.h b/ref_app/src/math/functions/math_functions_hypergeometric.h index f5a057515..95ceaa850 100644 --- a/ref_app/src/math/functions/math_functions_hypergeometric.h +++ b/ref_app/src/math/functions/math_functions_hypergeometric.h @@ -160,11 +160,13 @@ T x_pow_n_div_n_fact(x); + constexpr std::size_t local_buffer_size { std::size_t { UINT8_C(64) } }; + // Define an allocator type for use in the containers below. - using allocator_type = util::ring_allocator; + using allocator_type = util::ring_allocator; // Define a container type for the upcoming calculation. - using container_type = util::dynamic_array; + using container_type = util::fixed_dynamic_array; // The pochhammer symbols for the multiplications in the series expansion // will be stored in non-constant STL vectors. diff --git a/ref_app/src/math/wide_integer/uintwide_t.h b/ref_app/src/math/wide_integer/uintwide_t.h index 0469fd22a..40f7466ed 100644 --- a/ref_app/src/math/wide_integer/uintwide_t.h +++ b/ref_app/src/math/wide_integer/uintwide_t.h @@ -114,6 +114,14 @@ namespace math { namespace wide_integer { namespace detail { // NOLINT(modernize-concat-nested-namespaces) #endif + using size_t = std::uint32_t; + using ptrdiff_t = std::int32_t; + #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) + using uint_defaultlimb_t = std::uint64_t; + #else + using uint_defaultlimb_t = std::uint32_t; + #endif + namespace iterator_detail { class input_iterator_tag { }; @@ -374,7 +382,7 @@ template constexpr auto lexicographical_compare_unsafe(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) -> bool { - for( ; (first1 != last1) && (first2 != last2); static_cast(++first1), static_cast(++first2)) + for( ; (first1 != last1) && (first2 != last2); ++first1, static_cast(++first2)) { if(*first1 < *first2) { @@ -504,13 +512,25 @@ namespace array_detail { - template + + template class array { public: // Standard container-local type definitions. - using size_type = ::std::size_t; - using difference_type = ::std::ptrdiff_t; + #if defined(WIDE_INTEGER_NAMESPACE) + using size_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::size_t; + using difference_type = WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::ptrdiff_t; + #else + using size_type = ::math::wide_integer::detail::size_t; + using difference_type = ::math::wide_integer::detail::ptrdiff_t; + #endif using value_type = T; using pointer = T*; using const_pointer = const T*; @@ -605,26 +625,25 @@ friend constexpr auto operator> (const array& left, const array& right) -> bool { return (right < left); } friend constexpr auto operator>=(const array& left, const array& right) -> bool { return (!(left < right)); } friend constexpr auto operator<=(const array& left, const array& right) -> bool { return (!(right < left)); } - }; - template - constexpr auto swap(array& x, array& y) noexcept -> void - { - swap_ranges_unsafe(x.begin(), x.end(), y.begin()); - } + friend constexpr auto swap(array& x, array& y) noexcept -> void + { + swap_ranges_unsafe(x.begin(), x.end(), y.begin()); + } + }; template class tuple_size; - template - class tuple_size> : public std::integral_constant { }; + template + class tuple_size> : public std::integral_constant { }; - template + template class tuple_element; - template + template class tuple_element > { static_assert(I < N, "Sorry, tuple_element index is out of bounds."); @@ -675,19 +694,17 @@ using size_type = SizeType; using difference_type = DiffType; #if defined(WIDE_INTEGER_NAMESPACE) - using reverse_iterator = WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::iterator_detail::reverse_iterator< value_type*>; - using const_reverse_iterator = WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::iterator_detail::reverse_iterator; + using reverse_iterator = WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::iterator_detail::reverse_iterator; + using const_reverse_iterator = WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::iterator_detail::reverse_iterator; #else - using reverse_iterator = ::math::wide_integer::detail::iterator_detail::reverse_iterator< value_type*>; - using const_reverse_iterator = ::math::wide_integer::detail::iterator_detail::reverse_iterator; + using reverse_iterator = ::math::wide_integer::detail::iterator_detail::reverse_iterator; + using const_reverse_iterator = ::math::wide_integer::detail::iterator_detail::reverse_iterator; #endif static_assert(std::is_integral::value, "Error: the value_type of dynamic_array must be a built-in integral"); // Constructors. - constexpr dynamic_array() = delete; - - explicit constexpr dynamic_array(size_type count_in, + explicit constexpr dynamic_array(size_type count_in = size_type(), const_reference value_in = value_type(), const allocator_type& alloc_in = allocator_type()) : elem_count(count_in), @@ -722,9 +739,9 @@ } } - template - constexpr dynamic_array(input_iterator first, - input_iterator last, + template + constexpr dynamic_array(InputIterator first, + InputIterator last, const allocator_type& alloc_in = allocator_type()) : elem_count(static_cast(last - first)), my_alloc(alloc_in) @@ -761,7 +778,7 @@ // Move constructor. constexpr dynamic_array(dynamic_array&& other) noexcept : elem_count(other.elem_count), elems (other.elems), - my_alloc (std::move(other.my_alloc)) + my_alloc (std::move(static_cast(other.my_alloc))) { other.elem_count = static_cast(UINT8_C(0)); other.elems = nullptr; @@ -772,9 +789,16 @@ { if(!empty()) { + // The destructors of the elements are called (in unspecified order) + // and the dynamically allocated storage (if any) is deallocated. + + for(auto* itr { begin() }; itr != end(); ++itr) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + { + itr->~value_type(); + } + using local_allocator_traits_type = std::allocator_traits; - // Deallocate the range of *this. local_allocator_traits_type::deallocate(my_alloc, elems, elem_count); elem_count = static_cast(UINT8_C(0)); @@ -799,9 +823,9 @@ #else other.elems + ::math::wide_integer::detail::min_unsafe #endif - ( - elem_count, other.elem_count - ), + ( + elem_count, other.elem_count + ), elems ); } @@ -900,63 +924,46 @@ allocator_type my_alloc; // NOLINT(readability-identifier-naming) friend constexpr auto operator==(const dynamic_array& lhs, const dynamic_array& rhs) -> bool - { - return - ( - (lhs.size() == rhs.size()) - && ( - lhs.empty() - #if defined(WIDE_INTEGER_NAMESPACE) - || WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::equal_unsafe(lhs.cbegin(), lhs.cend(), rhs.cbegin()) - #else - || ::math::wide_integer::detail::equal_unsafe(lhs.cbegin(), lhs.cend(), rhs.cbegin()) - #endif - ) - ); - } - - friend constexpr auto operator<(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { bool b_result { }; if(lhs.empty()) { - b_result = (!rhs.empty()); + b_result = rhs.empty(); } - else + else if(lhs.size() == rhs.size()) { - // Note: Use lexicographical_compare here. If the dynamic arrays - // have unequal sizes, then simply ignore the size differences. - - b_result = - #if defined(WIDE_INTEGER_NAMESPACE) - WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::lexicographical_compare_unsafe - #else - ::math::wide_integer::detail::lexicographical_compare_unsafe - #endif - ( - lhs.cbegin(), - lhs.cend(), - rhs.cbegin(), - rhs.cend() - ); + #if defined(WIDE_INTEGER_NAMESPACE) + b_result = WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::equal_unsafe(lhs.cbegin(), lhs.cend(), rhs.cbegin()); + #else + b_result = ::math::wide_integer::detail::equal_unsafe(lhs.cbegin(), lhs.cend(), rhs.cbegin()); + #endif } + // else b_result remains false return b_result; } + friend constexpr auto operator<(const dynamic_array& lhs, const dynamic_array& rhs) -> bool + { + return + #if defined(WIDE_INTEGER_NAMESPACE) + WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::lexicographical_compare_unsafe + #else + ::math::wide_integer::detail::lexicographical_compare_unsafe + #endif + ( + lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend() + ); + } + friend constexpr auto operator!=(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (!(lhs == rhs)); } friend constexpr auto operator> (const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (rhs < lhs); } friend constexpr auto operator>=(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (!(lhs < rhs)); } friend constexpr auto operator<=(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (!(rhs < lhs)); } - }; - template - constexpr auto swap(dynamic_array& x, - dynamic_array& y) noexcept -> void - { - x.swap(y); - } + friend constexpr auto swap(dynamic_array& x, dynamic_array& y) noexcept -> void { x.swap(y); } + }; } // namespace util @@ -1018,14 +1025,6 @@ namespace detail { - using size_t = std::uint32_t; - using ptrdiff_t = std::int32_t; - #if defined(WIDE_INTEGER_HAS_LIMB_TYPE_UINT64) - using uint_defaultlimb_t = std::uint64_t; - #else - using uint_defaultlimb_t = std::uint32_t; - #endif - static_assert(( (std::numeric_limits::digits >= std::numeric_limits::digits) && (std::numeric_limits::digits + 1 >= std::numeric_limits::digits)), "Error: size type and pointer difference type must be at least 16 bits in width (or wider)"); @@ -1588,22 +1587,42 @@ namespace math { namespace wide_integer { namespace detail { // NOLINT(modernize-concat-nested-namespaces) #endif - template> + class fixed_dynamic_array; + + template - class fixed_dynamic_array final : public detail::dynamic_array // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) + typename AllocatorType> + class fixed_dynamic_array final : public detail::dynamic_array // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) { private: - using base_class_type = detail::dynamic_array; + using base_class_type = detail::dynamic_array; public: - static constexpr auto static_size() -> typename base_class_type::size_type { return MySize; } + // Type definitions. + using typename base_class_type::allocator_type; + using typename base_class_type::value_type; + using typename base_class_type::reference; + using typename base_class_type::const_reference; + using typename base_class_type::iterator; + using typename base_class_type::const_iterator; + using typename base_class_type::pointer; + using typename base_class_type::const_pointer; + using typename base_class_type::size_type; + using typename base_class_type::difference_type; + using typename base_class_type::reverse_iterator; + using typename base_class_type::const_reverse_iterator; + + static constexpr auto static_size() -> size_type { return MySize; } - explicit constexpr fixed_dynamic_array(const typename base_class_type::size_type size_in = MySize, - const typename base_class_type::value_type& value_in = typename base_class_type::value_type(), - const typename base_class_type::allocator_type& alloc_in = typename base_class_type::allocator_type()) - : base_class_type(MySize, value_in, alloc_in) + explicit constexpr fixed_dynamic_array(const size_type size_in = static_size(), + const value_type& value_in = value_type(), + const allocator_type& alloc_in = allocator_type()) + : base_class_type(static_size(), value_in, alloc_in) { + // This parameter is explicitly and purposely ignored. static_cast(size_in); } @@ -1611,24 +1630,47 @@ constexpr fixed_dynamic_array(fixed_dynamic_array&&) noexcept = default; - constexpr fixed_dynamic_array(std::initializer_list lst) - : base_class_type(lst.begin(), - lst.begin() + (detail::min_unsafe)(static_cast(lst.size()), MySize)) { } + constexpr fixed_dynamic_array(std::initializer_list lst, const allocator_type& alloc_in = allocator_type()) + : base_class_type(static_size(), size_type(), alloc_in) + { + #if defined(WIDE_INTEGER_NAMESPACE) + WIDE_INTEGER_NAMESPACE::math::wide_integer::detail::copy_unsafe + #else + ::math::wide_integer::detail::copy_unsafe + #endif + ( + lst.begin(), + lst.begin() + (detail::min_unsafe)(static_cast(lst.size()), static_size()), + base_class_type::data() + ); + } - //constexpt ~fixed_dynamic_array() override = default; constexpr auto operator=(const fixed_dynamic_array&) -> fixed_dynamic_array& = default; - constexpr auto operator=(fixed_dynamic_array&&) noexcept -> fixed_dynamic_array& = default; + constexpr auto operator=(fixed_dynamic_array&& other) noexcept -> fixed_dynamic_array& + { + base_class_type::operator=(static_cast(other)); + + return *this; + } }; - template + class tuple_size; + + template + class tuple_size> : public ::std::integral_constant { }; + + template - class fixed_static_array final : public detail::array_detail::array(MySize)> + class fixed_static_array final : public detail::array_detail::array { private: - using base_class_type = detail::array_detail::array(MySize)>; + using base_class_type = detail::array_detail::array; struct allocator_dummy_unsafe { @@ -1636,15 +1678,26 @@ }; public: - using size_type = size_t; - using value_type = typename base_class_type::value_type; + // Standard container-local type definitions. using allocator_type = allocator_dummy_unsafe; - static constexpr auto static_size() -> size_type { return MySize; } + using typename base_class_type::size_type; + using typename base_class_type::difference_type; + using typename base_class_type::value_type; + using typename base_class_type::pointer; + using typename base_class_type::const_pointer; + using typename base_class_type::reference; + using typename base_class_type::const_reference; + using typename base_class_type::iterator; + using typename base_class_type::const_iterator; + using typename base_class_type::reverse_iterator; + using typename base_class_type::const_reverse_iterator; - constexpr fixed_static_array() = default; + static_assert(::std::is_integral::value, "Error the template value_type must be a built-in integral type."); - explicit constexpr fixed_static_array(const size_type size_in, + static constexpr auto static_size() -> size_type { return MySize; } + + explicit constexpr fixed_static_array(const size_type size_in = size_type(), const value_type& value_in = value_type(), allocator_type alloc_in = allocator_type()) { @@ -1652,8 +1705,8 @@ if(size_in < static_size()) { - detail::fill_unsafe(base_class_type::begin(), base_class_type::begin() + size_in, value_in); - detail::fill_unsafe(base_class_type::begin() + size_in, base_class_type::end(), value_type()); + detail::fill_unsafe(base_class_type::begin(), base_class_type::begin() + size_in, value_in); + detail::fill_unsafe(base_class_type::begin() + size_in, base_class_type::end(), value_type()); } else { @@ -1690,16 +1743,16 @@ } } - //constexpr ~fixed_static_array() = default; constexpr auto operator=(const fixed_static_array& other_array) -> fixed_static_array& = default; constexpr auto operator=(fixed_static_array&& other_array) noexcept -> fixed_static_array& = default; - - constexpr auto operator[](const size_type i) -> typename base_class_type::reference { return base_class_type::operator[](static_cast(i)); } - constexpr auto operator[](const size_type i) const -> typename base_class_type::const_reference { return base_class_type::operator[](static_cast(i)); } }; + template + class tuple_size> : public ::std::integral_constant { }; + template struct verify_power_of_two_times_granularity_one_sixty_fourth // NOLINT(altera-struct-pack-align) { // List of numbers used to identify the form 2^n times 1...63. diff --git a/ref_app/src/util/memory/util_ring_allocator.h b/ref_app/src/util/memory/util_ring_allocator.h index b44dab8ea..77985d4da 100644 --- a/ref_app/src/util/memory/util_ring_allocator.h +++ b/ref_app/src/util/memory/util_ring_allocator.h @@ -88,10 +88,23 @@ { // The buffer has overflowed. + #if (defined(__GNUC__) && !defined(__clang__)) + #if(__GNUC__ >= 12) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Warray-bounds" + #endif + #endif + // Reset the allocated pointer to the bottom of the buffer // and increment the next get-pointer. p = &buffer.data[std::size_t { UINT8_C(0) }]; get_ptr = &buffer.data[chunk_size]; + + #if (defined(__GNUC__) && !defined(__clang__)) + #if(__GNUC__ >= 12) + #pragma GCC diagnostic pop + #endif + #endif } return static_cast(p); diff --git a/ref_app/src/util/utility/util_dynamic_array.h b/ref_app/src/util/utility/util_dynamic_array.h index 624461ebd..94ee34f1a 100644 --- a/ref_app/src/util/utility/util_dynamic_array.h +++ b/ref_app/src/util/utility/util_dynamic_array.h @@ -19,9 +19,9 @@ namespace util { template, - typename SizeType = std::size_t, - typename DiffType = std::ptrdiff_t> + typename AllocatorType = ::std::allocator, + typename SizeType = ::std::size_t, + typename DiffType = ::std::ptrdiff_t> class dynamic_array; template; // Constructors. - constexpr dynamic_array() = delete; - - explicit constexpr dynamic_array(size_type count_in, + explicit constexpr dynamic_array(size_type count_in = size_type(), const_reference value_in = value_type(), const allocator_type& alloc_in = allocator_type()) : elem_count(count_in), @@ -79,9 +77,9 @@ } } - template - constexpr dynamic_array(input_iterator first, - input_iterator last, + template + constexpr dynamic_array(InputIterator first, + InputIterator last, const allocator_type& alloc_in = allocator_type()) : elem_count(static_cast(std::distance(first, last))), my_alloc(alloc_in) @@ -110,20 +108,27 @@ // Move constructor. constexpr dynamic_array(dynamic_array&& other) noexcept : elem_count(other.elem_count), elems (other.elems), - my_alloc (std::move(other.my_alloc)) + my_alloc (std::move(static_cast(other.my_alloc))) { other.elem_count = static_cast(UINT8_C(0)); other.elems = nullptr; } // Destructor. - virtual ~dynamic_array() // LCOV_EXCL_LINE + virtual ~dynamic_array() { if(!empty()) { + // The destructors of the elements are called (in unspecified order) + // and the dynamically allocated storage (if any) is deallocated. + + for(auto* itr { begin() }; itr != end(); ++itr) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + { + itr->~value_type(); + } + using local_allocator_traits_type = std::allocator_traits; - // Deallocate the range of *this. local_allocator_traits_type::deallocate(my_alloc, elems, elem_count); elem_count = static_cast(UINT8_C(0)); @@ -136,9 +141,15 @@ { if(this != &other) { - std::copy(other.elems, - other.elems + (std::min)(elem_count, other.elem_count), - elems); + std::copy + ( + other.elems, + other.elems + (std::min) + ( + elem_count, other.elem_count + ), + elems + ); } return *this; @@ -147,60 +158,75 @@ // Move assignment operator. constexpr auto operator=(dynamic_array&& other) noexcept -> dynamic_array& { - std::swap(elem_count, other.elem_count); - std::swap(elems, other.elems); + if(this != &other) + { + if(!empty()) + { + using local_allocator_traits_type = std::allocator_traits; + + // Deallocate the range of *this. + local_allocator_traits_type::deallocate(my_alloc, elems, elem_count); + } + + elem_count = other.elem_count; + elems = other.elems; + + other.elem_count = static_cast(UINT8_C(0)); + other.elems = nullptr; + } return *this; } // Iterator members: - constexpr auto begin () noexcept -> iterator { return elems; } - constexpr auto end () noexcept -> iterator { return elems + elem_count; } - constexpr auto begin () const noexcept -> const_iterator { return elems; } - constexpr auto end () const noexcept -> const_iterator { return elems + elem_count; } - constexpr auto cbegin () const noexcept -> const_iterator { return elems; } - constexpr auto cend () const noexcept -> const_iterator { return elems + elem_count; } - constexpr auto rbegin () noexcept -> reverse_iterator { return reverse_iterator(elems + elem_count); } - constexpr auto rend () noexcept -> reverse_iterator { return reverse_iterator(elems); } - constexpr auto rbegin () const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems + elem_count); } - constexpr auto rend () const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems); } - constexpr auto crbegin() const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems + elem_count); } - constexpr auto crend () const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems); } + [[nodiscard]] constexpr auto begin () noexcept -> iterator { return elems; } + [[nodiscard]] constexpr auto end () noexcept -> iterator { return elems + elem_count; } + [[nodiscard]] constexpr auto begin () const noexcept -> const_iterator { return elems; } + [[nodiscard]] constexpr auto end () const noexcept -> const_iterator { return elems + elem_count; } + [[nodiscard]] constexpr auto cbegin () const noexcept -> const_iterator { return elems; } + [[nodiscard]] constexpr auto cend () const noexcept -> const_iterator { return elems + elem_count; } + [[nodiscard]] constexpr auto rbegin () noexcept -> reverse_iterator { return reverse_iterator(elems + elem_count); } + [[nodiscard]] constexpr auto rend () noexcept -> reverse_iterator { return reverse_iterator(elems); } + [[nodiscard]] constexpr auto rbegin () const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems + elem_count); } + [[nodiscard]] constexpr auto rend () const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems); } + [[nodiscard]] constexpr auto crbegin() const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems + elem_count); } + [[nodiscard]] constexpr auto crend () const noexcept -> const_reverse_iterator { return const_reverse_iterator(elems); } // Raw pointer access. - constexpr auto data() noexcept -> pointer { return elems; } - constexpr auto data() const noexcept -> const_pointer { return elems; } + [[nodiscard]] constexpr auto data() noexcept -> pointer { return elems; } + [[nodiscard]] constexpr auto data() const noexcept -> const_pointer { return elems; } // Size and capacity. - constexpr auto size () const noexcept -> size_type { return elem_count; } - constexpr auto max_size() const noexcept -> size_type { return elem_count; } - constexpr auto empty () const noexcept -> bool { return (elem_count == static_cast(UINT8_C(0))); } + [[nodiscard]] constexpr auto size () const noexcept -> size_type { return elem_count; } + [[nodiscard]] constexpr auto max_size() const noexcept -> size_type { return elem_count; } + [[nodiscard]] constexpr auto empty () const noexcept -> bool { return (elem_count == static_cast(UINT8_C(0))); } // Element access members. - constexpr auto operator[](const size_type i) noexcept -> reference { return elems[i]; } - constexpr auto operator[](const size_type i) const noexcept -> const_reference { return elems[i]; } + [[nodiscard]] constexpr auto operator[](const size_type i) noexcept -> reference { return elems[i]; } + [[nodiscard]] constexpr auto operator[](const size_type i) const noexcept -> const_reference { return elems[i]; } - constexpr auto front() noexcept -> reference { return elems[static_cast(UINT8_C(0))]; } - constexpr auto front() const noexcept -> const_reference { return elems[static_cast(UINT8_C(0))]; } + [[nodiscard]] constexpr auto front() noexcept -> reference { return elems[static_cast(UINT8_C(0))]; } + [[nodiscard]] constexpr auto front() const noexcept -> const_reference { return elems[static_cast(UINT8_C(0))]; } - constexpr auto back() noexcept -> reference { return ((elem_count > static_cast(UINT8_C(0))) ? elems[static_cast(elem_count - static_cast(UINT8_C(1)))] : elems[static_cast(UINT8_C(0))]); } - constexpr auto back() const noexcept -> const_reference { return ((elem_count > static_cast(UINT8_C(0))) ? elems[static_cast(elem_count - static_cast(UINT8_C(1)))] : elems[static_cast(UINT8_C(0))]); } + [[nodiscard]] constexpr auto back() noexcept -> reference { return ((elem_count > static_cast(UINT8_C(0))) ? elems[static_cast(elem_count - static_cast(UINT8_C(1)))] : elems[static_cast(UINT8_C(0))]); } + [[nodiscard]] constexpr auto back() const noexcept -> const_reference { return ((elem_count > static_cast(UINT8_C(0))) ? elems[static_cast(elem_count - static_cast(UINT8_C(1)))] : elems[static_cast(UINT8_C(0))]); } - constexpr auto at(const size_type i) noexcept -> reference { return ((i < elem_count) ? elems[i] : elems[static_cast(UINT8_C(0))]); } - constexpr auto at(const size_type i) const noexcept -> const_reference { return ((i < elem_count) ? elems[i] : elems[static_cast(UINT8_C(0))]); } + [[nodiscard]] constexpr auto at(const size_type i) noexcept -> reference { return ((i < elem_count) ? elems[i] : elems[static_cast(UINT8_C(0))]); } + [[nodiscard]] constexpr auto at(const size_type i) const noexcept -> const_reference { return ((i < elem_count) ? elems[i] : elems[static_cast(UINT8_C(0))]); } // Element manipulation members. - constexpr auto fill(const value_type& v) -> void + constexpr auto fill(const value_type& value_in) -> void { - std::fill(begin(), begin() + elem_count, v); + std::fill(begin(), begin() + elem_count, value_in); } constexpr auto swap(dynamic_array& other) noexcept -> void { if(this != &other) { - std::swap(elems, other.elems); + std::swap(elems, other.elems); std::swap(elem_count, other.elem_count); + std::swap(my_alloc, other.my_alloc); } } @@ -211,69 +237,117 @@ friend constexpr auto operator==(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { - bool left_and_right_are_equal = false; + bool b_result { }; - if(lhs.size() == rhs.size()) + if(lhs.empty()) { - using size_type = typename dynamic_array::size_type; - - const auto size_of_left_is_zero = (lhs.size() == static_cast(UINT8_C(0))); - - left_and_right_are_equal = - (size_of_left_is_zero || std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin())); - - return left_and_right_are_equal; + b_result = rhs.empty(); + } + else if(lhs.size() == rhs.size()) + { + b_result = std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin()); } + // else b_result remains false + + return b_result; } friend constexpr auto operator<(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { - using size_type = typename dynamic_array::size_type; + return + std::lexicographical_compare + ( + lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend() + ); + } - const auto size_of_left_is_zero = (lhs.size() == static_cast(UINT8_C(0))); + friend constexpr auto operator!=(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (!(lhs == rhs)); } + friend constexpr auto operator> (const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (rhs < lhs); } + friend constexpr auto operator>=(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (!(lhs < rhs)); } + friend constexpr auto operator<=(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (!(rhs < lhs)); } - bool b_result { }; + friend constexpr auto swap(dynamic_array& x, dynamic_array& y) noexcept -> void { x.swap(y); } + }; - if(size_of_left_is_zero) - { - const auto size_of_right_is_zero = (rhs.size() == static_cast(UINT8_C(0))); + template> + class fixed_dynamic_array; - b_result = (!size_of_right_is_zero); - } - else - { - if(size_of_left_is_zero) - { - const auto size_of_right_is_zero = (rhs.size() == static_cast(UINT8_C(0))); + template + class fixed_dynamic_array final : public dynamic_array // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) + { + private: + using base_class_type = dynamic_array; - b_result = (!size_of_right_is_zero); - } - else - { - const size_type count = (std::min)(lhs.size(), rhs.size()); + public: + // Type definitions. + using typename base_class_type::allocator_type; + using typename base_class_type::value_type; + using typename base_class_type::reference; + using typename base_class_type::const_reference; + using typename base_class_type::iterator; + using typename base_class_type::const_iterator; + using typename base_class_type::pointer; + using typename base_class_type::const_pointer; + using typename base_class_type::size_type; + using typename base_class_type::difference_type; + using typename base_class_type::reverse_iterator; + using typename base_class_type::const_reverse_iterator; + + static constexpr auto static_size() -> size_type { return MySize; } + + explicit constexpr fixed_dynamic_array(const size_type size_in = static_size(), + const value_type& value_in = value_type(), + const allocator_type& alloc_in = allocator_type()) + : base_class_type(static_size(), value_in, alloc_in) + { + // This parameter is explicitly and purposely ignored. + static_cast(size_in); + } - b_result= std::lexicographical_compare(lhs.cbegin(), - lhs.cbegin() + count, - rhs.cbegin(), - rhs.cbegin() + count); - } - } + constexpr fixed_dynamic_array(const fixed_dynamic_array&) = default; - return b_result; + constexpr fixed_dynamic_array(fixed_dynamic_array&&) noexcept = default; + + constexpr fixed_dynamic_array(std::initializer_list lst, const allocator_type& alloc_in = allocator_type()) + : base_class_type(static_size(), size_type(), alloc_in) + { + std::copy + ( + lst.begin(), + lst.begin() + (std::min)(static_cast(lst.size()), static_size()), + base_class_type::data() + ); } - friend constexpr auto operator!=(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (!(lhs == rhs)); } - friend constexpr auto operator> (const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (rhs < lhs); } - friend constexpr auto operator>=(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (!(lhs < rhs)); } - friend constexpr auto operator<=(const dynamic_array& lhs, const dynamic_array& rhs) -> bool { return (!(rhs < lhs)); } + template + constexpr fixed_dynamic_array(InputIterator first, + InputIterator last, + const allocator_type& alloc_in = allocator_type()) + : base_class_type(first, last, alloc_in) { } + + ~fixed_dynamic_array() override = default; + + constexpr auto operator=(const fixed_dynamic_array&) -> fixed_dynamic_array& = default; + + constexpr auto operator=(fixed_dynamic_array&& other) noexcept -> fixed_dynamic_array& + { + base_class_type::operator=(static_cast(other)); + + return *this; + } }; - template - constexpr auto swap(dynamic_array& x, - dynamic_array& y) noexcept -> void - { - x.swap(y); - } + template + class tuple_size; + + template + class tuple_size> : public ::std::integral_constant { }; } // namespace util