-
Notifications
You must be signed in to change notification settings - Fork 149
fix(lifetime): extending the lifetime of temporary objects #160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
amitsingh19975
wants to merge
18
commits into
develop
Choose a base branch
from
bugfix/lifetime
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 3 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
15c4476
fix(lifetime): extending the lifetime of temporary objects
amitsingh19975 8f5a5d1
fix(comparision): use `same_exp` instead of `std::is_same`
amitsingh19975 8178c6c
refactor(comparision): decoupled `if constexpr` and cleaned-up compare.
amitsingh19975 9b8c4e1
test(enable): enable tests for expression templates
amitsingh19975 d70a701
fix(test): bind the prvalue (=3) to a variable
amitsingh19975 8ec747c
refactor(expression): add function cast_tensor_expression for casting
amitsingh19975 7a936dd
chore(expression): add `nodiscard`
amitsingh19975 b6a3dd8
refactor(comparision): remove the construction of a whole new tensor
amitsingh19975 3a013d0
fix(compare): get the value type after `cast_tensor_expression`
amitsingh19975 7b23092
refactor(expression): validate predicate and add noexcept
amitsingh19975 a90573c
refactor(eval): clean the implementation
amitsingh19975 2abe215
fix(expression): disable the move constructor for public use to avoid…
amitsingh19975 51674d5
refactor(expression): clean unnecessary code and fix the comparision …
amitsingh19975 b7de038
refactor(expression): use `std::invoke` and add types to functional o…
amitsingh19975 bc0afbd
refactor(expression): add `noexcept`, rearrange constructors, and rem…
amitsingh19975 00357a0
fix(test): remove the undefined behaviour if the type is not FP
amitsingh19975 549f8a0
refactor(expression): improve error message and simplified if-else.
amitsingh19975 23ba8fc
refactor(compare): combine two compare function into one for easier m…
amitsingh19975 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| // | ||
| // Copyright (c) 2018-2019, Cem Bassoy, [email protected] | ||
| // Copyright (c) 2022, Amit Singh, [email protected] | ||
| // | ||
| // Distributed under the Boost Software License, Version 1.0. (See | ||
| // accompanying file LICENSE_1_0.txt or copy at | ||
|
|
@@ -13,13 +14,68 @@ | |
| #define BOOST_UBLAS_TENSOR_EXPRESSIONS_HPP | ||
|
|
||
| #include <cstddef> | ||
| #include <type_traits> | ||
| #include <boost/numeric/ublas/expression_types.hpp> | ||
|
|
||
| #include "tags.hpp" | ||
|
|
||
| namespace boost::numeric::ublas::detail | ||
| { | ||
|
|
||
| template<class T, class E> | ||
| struct tensor_expression; | ||
|
|
||
| template<class T, class EL, class ER, class OP> | ||
| struct binary_tensor_expression; | ||
|
|
||
| template<class T, class E, class OP> | ||
| struct unary_tensor_expression; | ||
|
|
||
| template<typename E1, typename E2> | ||
| concept same_exp = std::is_same_v< std::decay_t<E1>, std::decay_t<E2> >; | ||
|
|
||
| template<typename T> | ||
| struct does_exp_need_cast : std::false_type{}; | ||
|
|
||
| template<typename T> | ||
| static constexpr bool does_exp_need_cast_v = does_exp_need_cast< std::decay_t<T> >::value; | ||
|
|
||
| template<typename E, typename T> | ||
| struct does_exp_need_cast< tensor_expression<T,E> > : std::true_type{}; | ||
|
|
||
| template<typename E, typename T> | ||
| constexpr auto is_tensor_expression_impl(tensor_expression<T,E> const*) -> std::true_type; | ||
|
|
||
| constexpr auto is_tensor_expression_impl(void const*) -> std::false_type; | ||
|
|
||
| template<typename E> | ||
| constexpr auto is_matrix_expression_impl(matrix_expression<E> const*) -> std::true_type; | ||
|
|
||
| constexpr auto is_matrix_expression_impl(void const*) -> std::false_type; | ||
|
|
||
| template<typename E> | ||
| constexpr auto is_vector_expression_impl(vector_expression<E> const*) -> std::true_type; | ||
|
|
||
| constexpr auto is_vector_expression_impl(void const*) -> std::false_type; | ||
|
|
||
| template<typename E> | ||
| concept TensorExpression = decltype(is_tensor_expression_impl(static_cast<std::decay_t<E> const*>(nullptr)))::value; | ||
|
|
||
| // TODO: Remove this concept in the future when we have our own implementation of matrices. | ||
| template<typename E> | ||
| concept MatrixExpression = decltype(is_matrix_expression_impl(static_cast<std::decay_t<E> const*>(nullptr)))::value; | ||
|
|
||
| // TODO: Remove this concept in the future when we have our own implementation of vectors. | ||
| template<typename E> | ||
| concept VectorExpression = decltype(is_vector_expression_impl(static_cast<std::decay_t<E> const*>(nullptr)))::value; | ||
|
|
||
| template<typename Exp> | ||
| using expression_operand_t = std::conditional_t< | ||
| !std::is_lvalue_reference_v<Exp>, | ||
| std::decay_t<Exp>, | ||
| std::add_lvalue_reference_t< std::add_const_t< std::decay_t<Exp> > > | ||
| >; | ||
|
|
||
| /** @\brief base class for tensor expressions | ||
| * | ||
| * \note implements crtp - no use of virtual function calls | ||
|
|
@@ -30,7 +86,7 @@ namespace boost::numeric::ublas::detail | |
| **/ | ||
| template<class T, class E> | ||
| struct tensor_expression | ||
| : public ublas_expression<E> | ||
| : public ublas_expression<E> // DISCUSS: Do we really need to do derive from ublas_expression? | ||
| { | ||
| // static const unsigned complexity = 0; | ||
| using expression_type = E; | ||
|
|
@@ -40,11 +96,12 @@ struct tensor_expression | |
| inline | ||
| constexpr auto const& operator()() const noexcept { return *static_cast<const expression_type*> (this); } | ||
|
|
||
| ~tensor_expression() = default; | ||
| constexpr tensor_expression(tensor_expression&&) noexcept = default; | ||
| constexpr tensor_expression& operator=(tensor_expression&&) noexcept = default; | ||
| constexpr ~tensor_expression() = default; | ||
|
|
||
| tensor_expression(const tensor_expression&) = delete; | ||
| tensor_expression(tensor_expression&&) noexcept = delete; | ||
| tensor_expression& operator=(const tensor_expression&) = delete; | ||
| tensor_expression& operator=(tensor_expression&&) noexcept = delete; | ||
|
|
||
|
|
||
| protected : | ||
|
|
@@ -58,72 +115,76 @@ struct binary_tensor_expression | |
| { | ||
| using self_type = binary_tensor_expression<T,EL,ER,OP>; | ||
| using tensor_type = T; | ||
| using binary_operation = OP; | ||
| using expression_type_left = EL; | ||
| using expression_type_right = ER; | ||
| using binary_operation = std::decay_t<OP>; | ||
| using expression_type_left = expression_operand_t<EL>; | ||
| using expression_type_right = expression_operand_t<ER>; | ||
| using derived_type = tensor_expression <tensor_type,self_type>; | ||
|
|
||
| using size_type = typename tensor_type::size_type; | ||
|
|
||
| explicit constexpr binary_tensor_expression(expression_type_left const& l, expression_type_right const& r, binary_operation o) : el(l) , er(r) , op(std::move(o)) {} | ||
| constexpr binary_tensor_expression(binary_tensor_expression&& l) noexcept = delete; | ||
| constexpr binary_tensor_expression& operator=(binary_tensor_expression&& l) noexcept = delete; | ||
| ~binary_tensor_expression() = default; | ||
|
|
||
| binary_tensor_expression() = delete; | ||
|
|
||
| template<same_exp<EL> LeftExp, same_exp<ER> RightExp, typename OPType> | ||
| explicit constexpr binary_tensor_expression(LeftExp&& l, RightExp&& r, OPType&& o) | ||
| : el(std::forward<LeftExp>(l)) | ||
| , er(std::forward<RightExp>(r)) | ||
| , op(std::forward<OPType>(o)) | ||
| {} | ||
| constexpr binary_tensor_expression(binary_tensor_expression&& l) noexcept = default; | ||
| constexpr binary_tensor_expression& operator=(binary_tensor_expression&& l) noexcept = default; | ||
| constexpr ~binary_tensor_expression() = default; | ||
|
|
||
| binary_tensor_expression(const binary_tensor_expression& l) = delete; | ||
| binary_tensor_expression& operator=(binary_tensor_expression const& l) noexcept = delete; | ||
|
|
||
|
|
||
| [[nodiscard]] inline | ||
| constexpr decltype(auto) operator()(size_type i) const | ||
| requires (does_exp_need_cast_v<expression_type_left> && does_exp_need_cast_v<expression_type_right>) | ||
| { | ||
| return op(el()(i), er()(i)); | ||
| } | ||
|
|
||
| [[nodiscard]] inline | ||
| constexpr decltype(auto) operator()(size_type i) const | ||
| requires (does_exp_need_cast_v<expression_type_left> && !does_exp_need_cast_v<expression_type_right>) | ||
| { | ||
| return op(el()(i), er(i)); | ||
| } | ||
|
|
||
| [[nodiscard]] inline | ||
| constexpr decltype(auto) operator()(size_type i) const | ||
| requires (!does_exp_need_cast_v<expression_type_left> && does_exp_need_cast_v<expression_type_right>) | ||
| { | ||
| return op(el(i), er()(i)); | ||
| } | ||
|
|
||
| [[nodiscard]] inline | ||
| constexpr decltype(auto) operator()(size_type i) const { return op(el(i), er(i)); } | ||
| constexpr decltype(auto) operator()(size_type i) const { | ||
| return op(el(i), er(i)); | ||
| } | ||
|
|
||
| expression_type_left const& el; | ||
| expression_type_right const& er; | ||
| expression_type_left el; | ||
| expression_type_right er; | ||
| binary_operation op; | ||
| }; | ||
|
|
||
| /// @brief helper function to simply instantiation of lambda proxy class | ||
| template<class T1, class T2, class EL, class ER, class OP> | ||
| template<typename T, typename EL, typename ER, typename OP> | ||
| requires ( | ||
| ( MatrixExpression<EL> || VectorExpression<EL> || TensorExpression<EL> ) && | ||
| ( MatrixExpression<ER> || VectorExpression<ER> || TensorExpression<ER> ) | ||
| ) | ||
| [[nodiscard]] inline | ||
| constexpr auto make_binary_tensor_expression( tensor_expression<T1,EL> const& el, tensor_expression<T2,ER> const& er, OP op) noexcept | ||
| constexpr auto make_binary_tensor_expression( EL&& el, ER&& er, OP&& op) noexcept | ||
| { | ||
| static_assert( std::is_same_v< typename T1::value_type, typename T2::value_type>, | ||
| "boost::numeric::ublas::make_binary_tensor_expression(T1,T2) : LHS tensor and RHS tensor should have same value type" | ||
| return binary_tensor_expression<T,EL,ER,OP>( | ||
| std::forward<EL>(el), | ||
| std::forward<ER>(er), | ||
| std::forward<OP>(op) | ||
| ); | ||
| return binary_tensor_expression<T1,EL,ER,OP>( el(), er(), op) ; | ||
| } | ||
|
|
||
| template<class T, class EL, class ER, class OP> | ||
| [[nodiscard]] inline | ||
| constexpr auto make_binary_tensor_expression( matrix_expression<EL> const& el, tensor_expression<T,ER> const& er, OP op) noexcept | ||
| { | ||
| return binary_tensor_expression<T,EL,ER,OP>( el(), er(), op) ; | ||
| } | ||
|
|
||
| template<class T, class EL, class ER, class OP> | ||
| [[nodiscard]] inline | ||
| constexpr auto make_binary_tensor_expression( tensor_expression<T,EL> const& el, matrix_expression<ER> const& er, OP op) noexcept | ||
| { | ||
| return binary_tensor_expression<T,EL,ER,OP>( el(), er(), op) ; | ||
| } | ||
|
|
||
| template<class T, class EL, class ER, class OP> | ||
| [[nodiscard]] inline | ||
| constexpr auto make_binary_tensor_expression( vector_expression<EL> const& el, tensor_expression<T,ER> const& er, OP op) noexcept | ||
| { | ||
| return binary_tensor_expression<T,EL,ER,OP>( el(), er(), op) ; | ||
| } | ||
|
|
||
| template<class T, class EL, class ER, class OP> | ||
| [[nodiscard]] inline | ||
| constexpr auto make_binary_tensor_expression( tensor_expression<T,EL> const& el, vector_expression<ER> const& er, OP op) noexcept | ||
| { | ||
| return binary_tensor_expression<T,EL,ER,OP>( el(), er(), op) ; | ||
| } | ||
|
|
||
|
|
||
|
|
||
| template<class T, class E, class OP> | ||
| struct unary_tensor_expression | ||
|
|
@@ -132,51 +193,53 @@ struct unary_tensor_expression | |
|
|
||
| using self_type = unary_tensor_expression<T,E,OP>; | ||
| using tensor_type = T; | ||
| using expression_type = E; | ||
| using unary_operation = OP; | ||
| using expression_type = expression_operand_t<E>; | ||
| using unary_operation = std::decay_t<OP>; | ||
| using derived_type = tensor_expression <T, unary_tensor_expression<T,E,OP>>; | ||
|
|
||
| using size_type = typename tensor_type::size_type; | ||
|
|
||
| explicit constexpr unary_tensor_expression(expression_type const& ee, unary_operation o) : e(ee) , op(std::move(o)) {} | ||
| constexpr unary_tensor_expression(unary_tensor_expression&& l) noexcept = delete; | ||
| constexpr unary_tensor_expression& operator=(unary_tensor_expression&& l) noexcept = delete; | ||
| template<same_exp<E> Exp, typename OPType> | ||
| explicit constexpr unary_tensor_expression(Exp&& ee, OPType&& o) | ||
| : e(std::forward<Exp>(ee)) | ||
| , op(std::forward<OPType>(o)) | ||
| {} | ||
| constexpr unary_tensor_expression(unary_tensor_expression&& l) noexcept = default; | ||
| constexpr unary_tensor_expression& operator=(unary_tensor_expression&& l) noexcept = default; | ||
| constexpr ~unary_tensor_expression() = default; | ||
|
|
||
| constexpr unary_tensor_expression() = delete; | ||
| unary_tensor_expression(unary_tensor_expression const& l) = delete; | ||
| unary_tensor_expression& operator=(unary_tensor_expression const& l) noexcept = delete; | ||
| ~unary_tensor_expression() = default; | ||
|
|
||
| [[nodiscard]] inline constexpr | ||
| decltype(auto) operator()(size_type i) const { return op(e(i)); } | ||
| decltype(auto) operator()(size_type i) const | ||
| requires does_exp_need_cast_v<expression_type> | ||
| { | ||
| return op(e()(i)); | ||
| } | ||
|
|
||
| [[nodiscard]] inline constexpr | ||
| decltype(auto) operator()(size_type i) const { | ||
| return op(e(i)); | ||
| } | ||
|
|
||
| E const& e; | ||
| OP op; | ||
| expression_type e; | ||
| unary_operation op; | ||
| }; | ||
|
|
||
| // \brief helper function to simply instantiation of lambda proxy class | ||
| template<class T, class E, class OP> | ||
| [[nodiscard]] inline | ||
| constexpr auto make_unary_tensor_expression( tensor_expression<T,E> const& e, OP op) noexcept | ||
| { | ||
| return unary_tensor_expression<T,E,OP>( e() , op); | ||
| } | ||
|
|
||
| template<class T, class E, class OP> | ||
| [[nodiscard]] inline | ||
| constexpr auto make_unary_tensor_expression( matrix_expression<E> const& e, OP op) noexcept | ||
| { | ||
| return unary_tensor_expression<T,E,OP>( e() , op); | ||
| } | ||
|
|
||
| template<class T, class E, class OP> | ||
| template<typename T, typename E, typename OP> | ||
| requires ( MatrixExpression<E> || VectorExpression<E> || TensorExpression<E> ) | ||
| [[nodiscard]] inline | ||
| constexpr auto make_unary_tensor_expression( vector_expression<E> const& e, OP op) noexcept | ||
| constexpr auto make_unary_tensor_expression( E&& e, OP&& op) noexcept | ||
| { | ||
| return unary_tensor_expression<T,E,OP>( e() , op); | ||
| return unary_tensor_expression<T, E, OP>( | ||
| std::forward<E>(e), | ||
| std::forward<OP>(op) | ||
| ); | ||
| } | ||
|
|
||
|
|
||
| } // namespace boost::numeric::ublas::detail | ||
|
|
||
| #endif // BOOST_UBLAS_TENSOR_EXPRESSIONS_HPP | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.