diff --git a/CHANGELOG.md b/CHANGELOG.md index b7b29f8..03bc8ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,6 @@ - Added `soagen::for_each_column()` - Added `row::for_each_column()` - Added generic names `first`, `second`, ..., `sixteenth` for unnamed columns 0-15 -- Added const propagation to `soagen::row` member functions - Binary size improvements - Documentation improvements diff --git a/src/soagen/hpp/iterator.hpp b/src/soagen/hpp/iterator.hpp index afad467..e4e3d85 100644 --- a/src/soagen/hpp/iterator.hpp +++ b/src/soagen/hpp/iterator.hpp @@ -222,8 +222,8 @@ namespace soagen SOAGEN_ASSUME(!!base::table); SOAGEN_ASSUME(base::offset >= 0); - return row_type{ { static_cast>( - base::table->template column()[base::offset]) }... }; + return row_type{ static_cast>( + base::table->template column()[base::offset])... }; } /// @brief Returns the row the iterator refers to. @@ -240,8 +240,8 @@ namespace soagen SOAGEN_ASSUME(!!base::table); SOAGEN_ASSUME(base::offset + offset >= 0); - return row_type{ { static_cast>( - base::table->template column()[base::offset + offset]) }... }; + return row_type{ static_cast>( + base::table->template column()[base::offset + offset])... }; } /// @} diff --git a/src/soagen/hpp/mixins/rows.hpp b/src/soagen/hpp/mixins/rows.hpp index 7248bea..9342baf 100644 --- a/src/soagen/hpp/mixins/rows.hpp +++ b/src/soagen/hpp/mixins/rows.hpp @@ -30,13 +30,13 @@ namespace soagen::mixins { if constexpr (sizeof...(Cols)) { - return { { static_cast>( - static_cast(*this).template column(Cols)>()[index]) }... }; + return { static_cast>( + static_cast(*this).template column(Cols)>()[index])... }; } else { - return { { static_cast>( - static_cast(*this).template column(Columns)>()[index]) }... }; + return { static_cast>( + static_cast(*this).template column(Columns)>()[index])... }; } } @@ -47,31 +47,31 @@ namespace soagen::mixins { if constexpr (sizeof...(Cols)) { - return { { static_cast>( - static_cast(*this).template column(Cols)>()[index]) }... }; + return { static_cast>( + static_cast(*this).template column(Cols)>()[index])... }; } else { - return { { static_cast>( - static_cast(*this).template column(Columns)>()[index]) }... }; + return { static_cast>( + static_cast(*this).template column(Columns)>()[index])... }; } } template SOAGEN_PURE_GETTER SOAGEN_CPP20_CONSTEXPR - soagen::row_type row(size_type index) const& noexcept + soagen::const_row_type row(size_type index) const& noexcept { if constexpr (sizeof...(Cols)) { - return { { static_cast>( - static_cast(*this).template column(Cols)>()[index]) }... }; + return { static_cast>( + static_cast(*this).template column(Cols)>()[index])... }; } else { - return { { static_cast>( + return { static_cast>( static_cast(*this) - .template column(Columns)>()[index]) }... }; + .template column(Columns)>()[index])... }; } } diff --git a/src/soagen/hpp/names.hpp b/src/soagen/hpp/names.hpp index 1f735a3..ef54cd8 100644 --- a/src/soagen/hpp/names.hpp +++ b/src/soagen/hpp/names.hpp @@ -27,15 +27,10 @@ \ protected: \ SOAGEN_PURE_INLINE_GETTER \ - constexpr T get_ref() noexcept \ + constexpr T get_ref() const noexcept \ { \ return static_cast(Name); \ } \ - SOAGEN_PURE_INLINE_GETTER \ - constexpr decltype(auto) get_ref() const noexcept \ - { \ - return static_cast>, T>>(Name); \ - } \ }; \ \ template \ @@ -113,17 +108,11 @@ namespace soagen::detail T val_; SOAGEN_PURE_INLINE_GETTER - constexpr T get_ref() noexcept + constexpr T get_ref() const noexcept { return static_cast(val_); } - SOAGEN_PURE_INLINE_GETTER - constexpr decltype(auto) get_ref() const noexcept - { - return static_cast>, T>>(val_); - } - public: template SOAGEN_NODISCARD_CTOR @@ -179,19 +168,20 @@ namespace soagen::detail //--- column references --------- - template - struct SOAGEN_EMPTY_BASES column_ref : named_ref, value_ref> + template + struct SOAGEN_EMPTY_BASES column_ref // + : named_ref, value_ref> { - static_assert(!std::is_lvalue_reference_v); + static_assert(!std::is_lvalue_reference_v); }; //--- column functions --------- - template + template struct SOAGEN_EMPTY_BASES column_func // - : named_func, Derived, Column> + : named_func, Soa, Column> { - static_assert(!is_cvref); + static_assert(!is_cvref); }; } /// @endcond diff --git a/src/soagen/hpp/row.hpp b/src/soagen/hpp/row.hpp index a0b7449..35880cf 100644 --- a/src/soagen/hpp/row.hpp +++ b/src/soagen/hpp/row.hpp @@ -145,23 +145,23 @@ namespace soagen "row_base specializations may not have data members"); static_assert(std::is_trivial_v>>, "row_base specializations must be trivial"); + /// @cond + + SOAGEN_NODISCARD_CTOR + constexpr row(value_ref... args) noexcept // + : detail::column_ref{ static_cast>(args) }... + {} + + SOAGEN_DEFAULT_RULE_OF_FIVE(row); + + /// @endcond + /// @name Columns /// @{ /// @brief Returns a reference to the specified column's value. template SOAGEN_PURE_INLINE_GETTER - constexpr decltype(auto) column() noexcept - { - static_assert(static_cast(Column) < table_traits_type::column_count, - "column index out of range"); - - return detail::column_ref(Column)>::get_ref(); - } - - /// @brief Returns a reference to the specified column's value (const overload). - template - SOAGEN_PURE_INLINE_GETTER constexpr decltype(auto) column() const noexcept { static_assert(static_cast(Column) < table_traits_type::column_count, @@ -174,16 +174,6 @@ namespace soagen /// @see soagen::for_each_column template SOAGEN_ALWAYS_INLINE - constexpr void for_each_column(Func&& func) // - noexcept(noexcept(soagen::for_each_column(std::declval(), std::declval()))) - { - soagen::for_each_column(*this, static_cast(func)); - } - - /// @brief Invokes a callable once for each column in the row (const overload). - /// @see soagen::for_each_column - template - SOAGEN_ALWAYS_INLINE constexpr void for_each_column(Func&& func) const // noexcept(noexcept(soagen::for_each_column(std::declval(), std::declval()))) { @@ -199,17 +189,6 @@ namespace soagen /// @note `Member` corresponds to the column at the specified position of the `Columns` template argument. template SOAGEN_PURE_INLINE_GETTER - constexpr decltype(auto) get() noexcept - { - static_assert(Member < sizeof...(Columns), "member index out of range"); - - return type_at_index(Member), detail::column_ref...>::get_ref(); - } - - /// @brief Returns a reference to the specified member's value (const overload). - /// @note `Member` corresponds to the column at the specified position of the `Columns` template argument. - template - SOAGEN_PURE_INLINE_GETTER constexpr decltype(auto) get() const noexcept { static_assert(Member < sizeof...(Columns), "member index out of range"); @@ -230,6 +209,11 @@ namespace soagen friend constexpr bool operator==(const row& lhs, const row& rhs) // noexcept(table_traits_type::all_nothrow_equality_comparable) { + if constexpr (std::is_same_v) + { + if (&lhs == &rhs) + return true; + } return ((lhs.template column() == rhs.template column()) && ...); } @@ -257,6 +241,12 @@ namespace soagen static constexpr int row_compare_impl(const row& lhs, const row& rhs) // noexcept(table_traits_type::all_nothrow_less_than_comparable) { + if constexpr (std::is_same_v) + { + if (&lhs == &rhs) + return 0; + } + if (lhs.template get() < rhs.template get()) return -1; @@ -341,8 +331,7 @@ namespace soagen SOAGEN_PURE_INLINE_GETTER constexpr operator row() const noexcept { - return row{ { static_cast>().template column())>( - this->template column()) }... }; + return row{ static_cast>(this->template column())... }; } /// @cond @@ -354,8 +343,7 @@ namespace soagen SOAGEN_PURE_INLINE_GETTER explicit constexpr operator row() const noexcept { - return row{ { static_cast>().template column())>( - this->template column()) }... }; + return row{ static_cast>(this->template column())... }; } /// @endcond diff --git a/src/soagen/hpp/single/soagen.hpp b/src/soagen/hpp/single/soagen.hpp index a4b6a64..e0b9bd9 100644 --- a/src/soagen/hpp/single/soagen.hpp +++ b/src/soagen/hpp/single/soagen.hpp @@ -3675,15 +3675,10 @@ namespace soagen::detail \ protected: \ SOAGEN_PURE_INLINE_GETTER \ - constexpr T get_ref() noexcept \ + constexpr T get_ref() const noexcept \ { \ return static_cast(Name); \ } \ - SOAGEN_PURE_INLINE_GETTER \ - constexpr decltype(auto) get_ref() const noexcept \ - { \ - return static_cast>, T>>(Name); \ - } \ }; \ \ template \ @@ -3760,17 +3755,11 @@ namespace soagen::detail T val_; SOAGEN_PURE_INLINE_GETTER - constexpr T get_ref() noexcept + constexpr T get_ref() const noexcept { return static_cast(val_); } - SOAGEN_PURE_INLINE_GETTER - constexpr decltype(auto) get_ref() const noexcept - { - return static_cast>, T>>(val_); - } - public: template SOAGEN_NODISCARD_CTOR @@ -3826,19 +3815,20 @@ namespace soagen::detail //--- column references --------- - template - struct SOAGEN_EMPTY_BASES column_ref : named_ref, value_ref> + template + struct SOAGEN_EMPTY_BASES column_ref // + : named_ref, value_ref> { - static_assert(!std::is_lvalue_reference_v); + static_assert(!std::is_lvalue_reference_v); }; //--- column functions --------- - template + template struct SOAGEN_EMPTY_BASES column_func // - : named_func, Derived, Column> + : named_func, Soa, Column> { - static_assert(!is_cvref); + static_assert(!is_cvref); }; } @@ -4033,15 +4023,12 @@ namespace soagen "row_base specializations may not have data members"); static_assert(std::is_trivial_v>>, "row_base specializations must be trivial"); - template - SOAGEN_PURE_INLINE_GETTER - constexpr decltype(auto) column() noexcept - { - static_assert(static_cast(Column) < table_traits_type::column_count, - "column index out of range"); + SOAGEN_NODISCARD_CTOR + constexpr row(value_ref... args) noexcept // + : detail::column_ref{ static_cast>(args) }... + {} - return detail::column_ref(Column)>::get_ref(); - } + SOAGEN_DEFAULT_RULE_OF_FIVE(row); template SOAGEN_PURE_INLINE_GETTER @@ -4053,14 +4040,6 @@ namespace soagen return detail::column_ref(Column)>::get_ref(); } - template - SOAGEN_ALWAYS_INLINE - constexpr void for_each_column(Func&& func) // - noexcept(noexcept(soagen::for_each_column(std::declval(), std::declval()))) - { - soagen::for_each_column(*this, static_cast(func)); - } - template SOAGEN_ALWAYS_INLINE constexpr void for_each_column(Func&& func) const // @@ -4069,15 +4048,6 @@ namespace soagen soagen::for_each_column(*this, static_cast(func)); } - template - SOAGEN_PURE_INLINE_GETTER - constexpr decltype(auto) get() noexcept - { - static_assert(Member < sizeof...(Columns), "member index out of range"); - - return type_at_index(Member), detail::column_ref...>::get_ref(); - } - template SOAGEN_PURE_INLINE_GETTER constexpr decltype(auto) get() const noexcept @@ -4093,6 +4063,11 @@ namespace soagen friend constexpr bool operator==(const row& lhs, const row& rhs) // noexcept(table_traits_type::all_nothrow_equality_comparable) { + if constexpr (std::is_same_v) + { + if (&lhs == &rhs) + return true; + } return ((lhs.template column() == rhs.template column()) && ...); } @@ -4112,6 +4087,12 @@ namespace soagen static constexpr int row_compare_impl(const row& lhs, const row& rhs) // noexcept(table_traits_type::all_nothrow_less_than_comparable) { + if constexpr (std::is_same_v) + { + if (&lhs == &rhs) + return 0; + } + if (lhs.template get() < rhs.template get()) return -1; @@ -4168,8 +4149,7 @@ namespace soagen SOAGEN_PURE_INLINE_GETTER constexpr operator row() const noexcept { - return row{ { static_cast>().template column())>( - this->template column()) }... }; + return row{ static_cast>(this->template column())... }; } SOAGEN_CONSTRAINED_TEMPLATE((!detail::row_implicit_conversion_ok> @@ -4179,8 +4159,7 @@ namespace soagen SOAGEN_PURE_INLINE_GETTER explicit constexpr operator row() const noexcept { - return row{ { static_cast>().template column())>( - this->template column()) }... }; + return row{ static_cast>(this->template column())... }; } }; } @@ -5301,8 +5280,8 @@ namespace soagen SOAGEN_ASSUME(!!base::table); SOAGEN_ASSUME(base::offset >= 0); - return row_type{ { static_cast>( - base::table->template column()[base::offset]) }... }; + return row_type{ static_cast>( + base::table->template column()[base::offset])... }; } SOAGEN_PURE_INLINE_GETTER @@ -5317,8 +5296,8 @@ namespace soagen SOAGEN_ASSUME(!!base::table); SOAGEN_ASSUME(base::offset + offset >= 0); - return row_type{ { static_cast>( - base::table->template column()[base::offset + offset]) }... }; + return row_type{ static_cast>( + base::table->template column()[base::offset + offset])... }; } SOAGEN_CONSTRAINED_TEMPLATE((same_table_type), typename T, size_t... Cols) @@ -5732,13 +5711,13 @@ namespace soagen::mixins { if constexpr (sizeof...(Cols)) { - return { { static_cast>( - static_cast(*this).template column(Cols)>()[index]) }... }; + return { static_cast>( + static_cast(*this).template column(Cols)>()[index])... }; } else { - return { { static_cast>( - static_cast(*this).template column(Columns)>()[index]) }... }; + return { static_cast>( + static_cast(*this).template column(Columns)>()[index])... }; } } @@ -5749,31 +5728,31 @@ namespace soagen::mixins { if constexpr (sizeof...(Cols)) { - return { { static_cast>( - static_cast(*this).template column(Cols)>()[index]) }... }; + return { static_cast>( + static_cast(*this).template column(Cols)>()[index])... }; } else { - return { { static_cast>( - static_cast(*this).template column(Columns)>()[index]) }... }; + return { static_cast>( + static_cast(*this).template column(Columns)>()[index])... }; } } template SOAGEN_PURE_GETTER SOAGEN_CPP20_CONSTEXPR - soagen::row_type row(size_type index) const& noexcept + soagen::const_row_type row(size_type index) const& noexcept { if constexpr (sizeof...(Cols)) { - return { { static_cast>( - static_cast(*this).template column(Cols)>()[index]) }... }; + return { static_cast>( + static_cast(*this).template column(Cols)>()[index])... }; } else { - return { { static_cast>( + return { static_cast>( static_cast(*this) - .template column(Columns)>()[index]) }... }; + .template column(Columns)>()[index])... }; } } diff --git a/tests/employees.cpp b/tests/employees.cpp index f447177..b73d6d8 100644 --- a/tests/employees.cpp +++ b/tests/employees.cpp @@ -196,7 +196,7 @@ TEST_CASE("employees - general use") CHECK(emp.tag()[0] == nullptr); CHECK(emp[0] == emp[0]); CHECK(emp[0] == std::as_const(emp)[0]); - CHECK(emp[0] == std::move(emp)[0]); + CHECK(emp[0] == static_cast(emp[0])); CHECK(emp[0] == std::move(std::as_const(emp))[0]); CHECK(emp[0] <= emp[0]); CHECK(emp[0] >= emp[0]); @@ -269,7 +269,7 @@ TEST_CASE("employees - general use") CHECK_ROW_EQ(emp.back(), "joe bloggs", 1, (1970, 1, 1), 50000, nullptr); CHECK(emp[1] == emp[1]); CHECK(emp[1] == std::as_const(emp)[1]); - CHECK(emp[1] == std::move(emp)[1]); + CHECK(emp[1] == static_cast(emp[1])); CHECK(emp[1] == std::move(std::as_const(emp))[1]); CHECK(emp[1] != emp[0]); CHECK(emp[1] != std::as_const(emp)[0]); @@ -1075,8 +1075,8 @@ TEST_CASE("employees - general use") static_assert(is_implicitly_convertible, row>); static_assert(is_implicitly_convertible, row>); { - using to = row; // salary, id, name - to dest = std::move(emp[1]); // rvalue -> const lvalue + using to = row; // salary, id, name + to dest = static_cast(emp[1]); // rvalue -> const lvalue CHECK(dest.column<3>() == 999999); CHECK(dest.column<1>() == 0); CHECK(dest.column<0>() == "mark gillard");