From 4804b206f943dca32aed8971ff1b2505a8ec36c0 Mon Sep 17 00:00:00 2001 From: "Ryan M. Richard" Date: Mon, 14 Oct 2024 15:58:02 -0500 Subject: [PATCH 1/4] almost works [skip ci] --- include/tensorwrapper/shape/shape_base.hpp | 15 ++-- include/tensorwrapper/shape/shape_fwd.hpp | 18 +++++ include/tensorwrapper/shape/shape_traits.hpp | 51 +++++++++++++ include/tensorwrapper/shape/smooth_view.hpp | 57 ++++++++++++++ .../shape/detail_/smooth_view_pimpl.hpp | 43 +++++++++++ src/tensorwrapper/shape/smooth_view.cpp | 74 +++++++++++++++++++ .../shape/detail_/smooth_view_pimpl.cpp | 22 ++++++ 7 files changed, 275 insertions(+), 5 deletions(-) create mode 100644 include/tensorwrapper/shape/shape_fwd.hpp create mode 100644 include/tensorwrapper/shape/shape_traits.hpp create mode 100644 include/tensorwrapper/shape/smooth_view.hpp create mode 100644 src/tensorwrapper/shape/detail_/smooth_view_pimpl.hpp create mode 100644 src/tensorwrapper/shape/smooth_view.cpp create mode 100644 tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_view_pimpl.cpp diff --git a/include/tensorwrapper/shape/shape_base.hpp b/include/tensorwrapper/shape/shape_base.hpp index 3c62e16d..d9044851 100644 --- a/include/tensorwrapper/shape/shape_base.hpp +++ b/include/tensorwrapper/shape/shape_base.hpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace tensorwrapper::shape { /** @brief Code factorization for the various types of shapes. @@ -34,19 +35,23 @@ namespace tensorwrapper::shape { * - get_rank_() * - get_size_() */ -class ShapeBase : public detail_::PolymorphicBase { +class ShapeBase : public tensorwrapper::detail_::PolymorphicBase { +private: + /// Type implementing the traits of this + using traits_type = ShapeTraits; + public: /// Type all shapes inherit from - using shape_base = ShapeBase; + using shape_base = typename traits_type::shape_base; /// Type of a pointer to the base of a shape object - using base_pointer = std::unique_ptr; + using base_pointer = typename traits_type::base_pointer; /// Type used to hold the rank of a tensor - using rank_type = unsigned short; + using rank_type = typename traits_type::rank_type; /// Type used to specify the number of elements in the shape - using size_type = std::size_t; + using size_type = typename traits_type::size_type; /// No-op for ShapeBase because ShapeBase has no state ShapeBase() noexcept = default; diff --git a/include/tensorwrapper/shape/shape_fwd.hpp b/include/tensorwrapper/shape/shape_fwd.hpp new file mode 100644 index 00000000..8a84008c --- /dev/null +++ b/include/tensorwrapper/shape/shape_fwd.hpp @@ -0,0 +1,18 @@ +#pragma once + +namespace tensorwrapper::shape { +namespace detail_ { + +template +class SmoothViewPIMPL; + +} + +class ShapeBase; + +class Smooth; + +template +class SmoothView; + +} // namespace tensorwrapper::shape \ No newline at end of file diff --git a/include/tensorwrapper/shape/shape_traits.hpp b/include/tensorwrapper/shape/shape_traits.hpp new file mode 100644 index 00000000..775c4000 --- /dev/null +++ b/include/tensorwrapper/shape/shape_traits.hpp @@ -0,0 +1,51 @@ +#pragma once +#include +#include + +namespace tensorwrapper::shape { + +template +struct ShapeTraits; + +template<> +struct ShapeTraits { + using shape_base = ShapeBase; + using base_pointer = std::unique_ptr; + using rank_type = unsigned short; + using size_type = std::size_t; +}; + +template<> +struct ShapeTraits { + using shape_base = ShapeBase; + using base_pointer = std::unique_ptr; + using rank_type = unsigned short; + using size_type = std::size_t; +}; + +template<> +struct ShapeTraits : public ShapeTraits { + using value_type = Smooth; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; +}; + +template<> +struct ShapeTraits : public ShapeTraits { + using value_type = Smooth; + using reference = const value_type&; + using const_reference = const value_type&; + using pointer = const value_type*; + using const_pointer = const value_type*; +}; + +template +struct ShapeTraits> { + using smooth_traits = ShapeTraits; + using pimpl_type = detail_::SmoothViewPIMPL; + using pimpl_pointer = std::unique_ptr; +}; + +} // namespace tensorwrapper::shape \ No newline at end of file diff --git a/include/tensorwrapper/shape/smooth_view.hpp b/include/tensorwrapper/shape/smooth_view.hpp new file mode 100644 index 00000000..dc037c43 --- /dev/null +++ b/include/tensorwrapper/shape/smooth_view.hpp @@ -0,0 +1,57 @@ +#pragma once +#include +#include + +namespace tensorwrapper::shape { + +template +class SmoothView { +private: + /// Type of *this + using my_type = SmoothView; + + /// Type defining the traits for *this + using traits_type = ShapeTraits; + +public: + /// Types needed to implement Smooth's interface + ///@{ + using smooth_traits = typename traits_type::smooth_traits; + using smooth_type = typename smooth_traits::value_type; + using smooth_reference = typename smooth_traits::reference; + using const_smooth_reference = typename smooth_traits::const_reference; + using rank_type = typename smooth_traits::rank_type; + using size_type = typename smooth_traits::size_type; + ///@} + + using pimpl_pointer = typename traits_type::pimpl_pointer; + + SmoothView(smooth_reference smooth); + + SmoothView(const SmoothView& other); + SmoothView(SmoothView&& other) noexcept; + SmoothView& operator=(const SmoothView& rhs); + SmoothView& operator=(SmoothView&& rhs) noexcept; + ~SmoothView() noexcept; + + rank_type extent(size_type i) const; + rank_type rank() const noexcept; + size_type size() const noexcept; + + void swap(SmoothView& rhs) noexcept; + + bool operator==(const SmoothView& rhs) const noexcept; + bool operator!=(const SmoothView& rhs) const noexcept { + return !((*this) == rhs); + } + +private: + bool has_pimpl_() const noexcept; + pimpl_pointer clone_() const; + pimpl_pointer m_pimpl_; +}; + +extern template class SmoothView; +extern template class SmoothView; + +} // namespace tensorwrapper::shape \ No newline at end of file diff --git a/src/tensorwrapper/shape/detail_/smooth_view_pimpl.hpp b/src/tensorwrapper/shape/detail_/smooth_view_pimpl.hpp new file mode 100644 index 00000000..2df00f81 --- /dev/null +++ b/src/tensorwrapper/shape/detail_/smooth_view_pimpl.hpp @@ -0,0 +1,43 @@ +#include + +namespace tensorwrapper::shape::detail_ { + +// Eventually this should be turned into a base class and the current +// implementation moved into a derived class that wraps an existing Smooth +// object +template +class SmoothViewPIMPL { +public: + /// Type of the class *this is implementing + using parent_type = SmoothView; + + /// Pull in parent's types + ///@{ + using smooth_pointer = typename parent_type::smooth_traits::pointer; + using smooth_reference = typename parent_type::smooth_reference; + using pimpl_pointer = typename parent_type::pimpl_pointer; + using rank_type = typename parent_type::rank_type; + using size_type = typename parent_type::size_type; + ///@} + + explicit SmoothViewPIMPL(smooth_reference shape) : m_pshape_(&shape) {} + + pimpl_pointer clone() const { + return std::make_unique(*this); + } + + rank_type extent(size_type i) const { return m_pshape_->extent(i); } + + rank_type rank() const noexcept { return m_pshape_->rank(); } + + size_type size() const noexcept { return m_pshape_->size(); } + + bool operator==(const SmoothViewPIMPL& rhs) const noexcept { + return (*m_pshape_) == (*rhs.m_pshape_); + } + +private: + smooth_pointer m_pshape_; +}; + +} // namespace tensorwrapper::shape::detail_ \ No newline at end of file diff --git a/src/tensorwrapper/shape/smooth_view.cpp b/src/tensorwrapper/shape/smooth_view.cpp new file mode 100644 index 00000000..881f7bb4 --- /dev/null +++ b/src/tensorwrapper/shape/smooth_view.cpp @@ -0,0 +1,74 @@ +#include "detail_/smooth_view_pimpl.hpp" +#include + +namespace tensorwrapper::shape { + +#define TPARAMS template +#define SMOOTH_VIEW SmoothView + +TPARAMS +SMOOTH_VIEW::SmoothView(smooth_reference smooth) : + m_pimpl_(std::make_unique(smooth)) {} + +TPARAMS +SMOOTH_VIEW::SmoothView(const SmoothView& other) : m_pimpl_(other.clone_()) {} + +TPARAMS +SMOOTH_VIEW::SmoothView(SmoothView&& other) noexcept = default; + +TPARAMS +SMOOTH_VIEW& SMOOTH_VIEW::operator=(const SmoothView& rhs) { + if(this != &rhs) SmoothView(rhs).swap(*this); + return *this; +} + +TPARAMS +SMOOTH_VIEW& SMOOTH_VIEW::operator=(SmoothView&& rhs) noexcept = default; + +TPARAMS +SMOOTH_VIEW::~SmoothView() noexcept = default; + +TPARAMS +typename SMOOTH_VIEW::rank_type SMOOTH_VIEW::extent(size_type i) const { + return m_pimpl_->extent(i); +} + +TPARAMS +typename SMOOTH_VIEW::rank_type SMOOTH_VIEW::rank() const noexcept { + return m_pimpl_->rank(); +} + +TPARAMS +typename SMOOTH_VIEW::size_type SMOOTH_VIEW::size() const noexcept { + return m_pimpl_->size(); +} + +TPARAMS +void SMOOTH_VIEW::swap(SmoothView& rhs) noexcept { + m_pimpl_.swap(rhs.m_pimpl_); +} + +TPARAMS +bool SMOOTH_VIEW::operator==(const SmoothView& rhs) const noexcept { + if(has_pimpl_() != rhs.has_pimpl_()) return false; + if(!has_pimpl_()) return true; + return (*m_pimpl_) == (*rhs.m_pimpl_); +} + +TPARAMS +bool SMOOTH_VIEW::has_pimpl_() const noexcept { + return static_cast(m_pimpl_); +} + +TPARAMS +typename SMOOTH_VIEW::pimpl_pointer SMOOTH_VIEW::clone_() const { + return has_pimpl_() ? m_pimpl_->clone() : nullptr; +} + +#undef SMOOTH_VIEW +#undef TPARAMS + +template class SmoothView; +template class SmoothView; + +} // namespace tensorwrapper::shape \ No newline at end of file diff --git a/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_view_pimpl.cpp b/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_view_pimpl.cpp new file mode 100644 index 00000000..033186b2 --- /dev/null +++ b/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_view_pimpl.cpp @@ -0,0 +1,22 @@ +#include "../../helpers.hpp" +#include + +using namespace tensorwrapper::shape; + +using types2test = std::pair; + +TEMPLATE_LIST_TEST_CASE("SmoothViewPIMPL", "", types2test) { + using pimpl_type = detail_::SmoothViewPIMPL; + std::decay_t defaulted_shape, shape{1, 2, 3}; + + pimpl_type defaulted(defaulted_shape); + pimpl_type value(shape); + + SECTION("CTor") { + REQUIRE(defaulted.rank() == defaulted_shape.rank()); + REQUIRE(defaulted.size() == defaulted_shape.size()); + + REQUIRE(value.rank() == shape.rank()); + REQUIRE(value.size() == shape.size()); + } +} \ No newline at end of file From 6afe1c2fa09b952b6e681570e997e0e1d6a9a882 Mon Sep 17 00:00:00 2001 From: "Ryan M. Richard" Date: Tue, 15 Oct 2024 13:51:52 -0500 Subject: [PATCH 2/4] back up [skip ci] --- .../detail_/polymorphic_base.hpp | 7 +- include/tensorwrapper/detail_/view_traits.hpp | 45 ++++++ include/tensorwrapper/shape/shape_traits.hpp | 27 ++-- include/tensorwrapper/shape/smooth_view.hpp | 88 +++++++++++- .../shape/detail_/smooth_alias.hpp | 69 ++++++++++ .../shape/detail_/smooth_view_pimpl.hpp | 74 +++++++--- src/tensorwrapper/shape/smooth_view.cpp | 15 +- .../tensorwrapper/detail_/view_traits.cpp | 22 +++ .../shape/detail_/smooth_alias.cpp | 44 ++++++ .../shape/detail_/smooth_view_pimpl.cpp | 36 +++-- .../tensorwrapper/shape/smooth_view.cpp | 128 ++++++++++++++++++ 11 files changed, 505 insertions(+), 50 deletions(-) create mode 100644 include/tensorwrapper/detail_/view_traits.hpp create mode 100644 src/tensorwrapper/shape/detail_/smooth_alias.hpp create mode 100644 tests/cxx/unit_tests/tensorwrapper/detail_/view_traits.cpp create mode 100644 tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_alias.cpp create mode 100644 tests/cxx/unit_tests/tensorwrapper/shape/smooth_view.cpp diff --git a/include/tensorwrapper/detail_/polymorphic_base.hpp b/include/tensorwrapper/detail_/polymorphic_base.hpp index a0e90b28..15e0ae0c 100644 --- a/include/tensorwrapper/detail_/polymorphic_base.hpp +++ b/include/tensorwrapper/detail_/polymorphic_base.hpp @@ -103,8 +103,13 @@ class PolymorphicBase { * @throw None No throw guarantee. */ bool are_equal(const_base_reference rhs) const noexcept { + // Downcast *this so it can be passed to are_equal_ const_base_reference plhs = static_cast(*this); - return are_equal_(rhs) && rhs.are_equal_(plhs); + + // This line is necessary if are_equal_ is overriden in BaseType + const PolymorphicBase& rhs_upcast = rhs; + + return are_equal_(rhs) && rhs_upcast.are_equal_(plhs); } /** @brief Determines if *this and @p rhs are polymorphically different. diff --git a/include/tensorwrapper/detail_/view_traits.hpp b/include/tensorwrapper/detail_/view_traits.hpp new file mode 100644 index 00000000..db347f1b --- /dev/null +++ b/include/tensorwrapper/detail_/view_traits.hpp @@ -0,0 +1,45 @@ +#pragma once +#include + +namespace tensorwrapper::detail_ { + +/** @brief Is the cast from @p FromType to @p ToType just adding const? + * + * A common TMP pattern in implementing views is needing to convert mutable + * views to read-only views. This trait can be used to compare the template + * type parameters of two views (assuming the views are templated on what + * object they are acting like) in order to determine if they represent a + * conversion from @p FromType to @p ToType such that @p ToType is + * `const FromType`. If @p ToType is `const FromType` this template variable + * will be set to true, otherwise it will be set to false. + * + * @tparam FromType The type we are converting from. + * @tparam ToType The type we are converting to. + */ +template +constexpr bool is_mutable_to_immutable_cast_v = + !std::is_const_v && // FromType is NOT read-only + std::is_const_v && // ToType is read-only + std::is_same_v; // They differ by const-ness + +/** @brief Disables a templated function except when + * `is_mutable_to_immutable_cast_v` evaluates to true. + * + * If `View` is a template class with template parameter type `T`, we want the + * implicit conversion from `View` to `View` to exist. In practice, + * this leaves us with two options: partial specialization of `View` for + * const-qualified types or use of SFINAE to disable the conversion. We prefer + * the latter as the former requires us to duplicate the entirety of the + * class. This template type will disable the accompanying function via SFINAE + * if @p ToType is not `const FromType`. + * + * @tparam FromType The type we are converting from. Expected to be the + * template type parameter of the view we are casting from. + * @tparam ToType The type we are converting to. Expected to be the template + * type parameter of the view we are casting to. + */ +template +using enable_if_mutable_to_immutable_cast_t = + std::enable_if_t>; + +} // namespace tensorwrapper::detail_ \ No newline at end of file diff --git a/include/tensorwrapper/shape/shape_traits.hpp b/include/tensorwrapper/shape/shape_traits.hpp index 775c4000..6cdf9d86 100644 --- a/include/tensorwrapper/shape/shape_traits.hpp +++ b/include/tensorwrapper/shape/shape_traits.hpp @@ -25,27 +25,32 @@ struct ShapeTraits { template<> struct ShapeTraits : public ShapeTraits { - using value_type = Smooth; - using reference = value_type&; - using const_reference = const value_type&; - using pointer = value_type*; - using const_pointer = const value_type*; + using value_type = Smooth; + using const_value_type = const value_type; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = value_type*; + using const_pointer = const value_type*; }; template<> struct ShapeTraits : public ShapeTraits { - using value_type = Smooth; - using reference = const value_type&; - using const_reference = const value_type&; - using pointer = const value_type*; - using const_pointer = const value_type*; + using value_type = Smooth; + using const_value_type = const value_type; + using reference = const value_type&; + using const_reference = const value_type&; + using pointer = const value_type*; + using const_pointer = const value_type*; }; template struct ShapeTraits> { using smooth_traits = ShapeTraits; using pimpl_type = detail_::SmoothViewPIMPL; - using pimpl_pointer = std::unique_ptr; + using const_pimpl_type = + detail_::SmoothViewPIMPL; + using pimpl_pointer = std::unique_ptr; + using const_pimpl_pointer = std::unique_ptr; }; } // namespace tensorwrapper::shape \ No newline at end of file diff --git a/include/tensorwrapper/shape/smooth_view.hpp b/include/tensorwrapper/shape/smooth_view.hpp index dc037c43..314dd62a 100644 --- a/include/tensorwrapper/shape/smooth_view.hpp +++ b/include/tensorwrapper/shape/smooth_view.hpp @@ -1,9 +1,19 @@ #pragma once +#include #include #include namespace tensorwrapper::shape { +/** @brief Wraps existing state in an API compatible with SmoothView. + * + * @tparam SmoothType Type of Smooth object *this is acting as. Expected to be + * either Smooth or const Smooth. + * + * Sometimes we have state which may not actually be in a Smooth object, but + * is capable of being used as a Smooth object. This class maps the Smooth + * API to the existing state. + */ template class SmoothView { private: @@ -13,6 +23,12 @@ class SmoothView { /// Type defining the traits for *this using traits_type = ShapeTraits; + /// Bind SmoothType for + template + using enable_if_mutable_to_immutable_cast_t = + tensorwrapper::detail_::enable_if_mutable_to_immutable_cast_t; + public: /// Types needed to implement Smooth's interface ///@{ @@ -24,30 +40,94 @@ class SmoothView { using size_type = typename smooth_traits::size_type; ///@} - using pimpl_pointer = typename traits_type::pimpl_pointer; - + /** @brief Creates a view of an existing Smooth object. + * + * In order to treat SmoothView objects on the same footing as Smooth + * objects it must be possible to implicitly convert between the two. + * This ctor will implicitly convert @p smooth into a SmoothView object. + * + * @param[in] smooth The object to convert. + * + * @throw std::bad_alloc if there is a problem allocating the PIMPL. + * Strong throw guarantee. + */ SmoothView(smooth_reference smooth); + /** @brief Implicitly converts mutable views into read-only views. + * + * @tparam SmoothType2 The type @p other is a view of. This method will + * only participate in overload resolution if + * SmoothType2 is `const Smooth`. + * @tparam Type parameter used to disable this method when + * SmoothType2 is not `const Smooth` and/or when + * SmoothType is not `Smooth`. + * + * Views act like references to an object. Views of mutable objects should + * be usable wherever views to read-only objects are used. This ctor + * enables the implicit conversion from mutable view to read-only view in + * order to make that possible. + * + * @param[in] other The view to convert to a read-only view. + * + * @throw std::bad_alloc if there is a problem allocating the PIMPL. Strong + * throw guarantee. + */ + template> + SmoothView(const SmoothView& other); + SmoothView(const SmoothView& other); SmoothView(SmoothView&& other) noexcept; SmoothView& operator=(const SmoothView& rhs); SmoothView& operator=(SmoothView&& rhs) noexcept; + + /// Nothrow defaulted dtor ~SmoothView() noexcept; rank_type extent(size_type i) const; rank_type rank() const noexcept; size_type size() const noexcept; + /// Swaps the state of *this with that of @p rhs void swap(SmoothView& rhs) noexcept; - bool operator==(const SmoothView& rhs) const noexcept; - bool operator!=(const SmoothView& rhs) const noexcept { + bool operator==(const SmoothView& rhs) const noexcept; + + /** @brief Is *this different from @p rhs? + * + * @tparam SmoothType2 The type @p rhs is a view of. Expected to be Smooth + * or const Smooth. + * + * This method defines "different" as not value equal. See operator== for + * the definition of value equal. + * + * @param[in] rhs The view to compare to. + * + * @return False if *this is value equal to @p rhs and true otherwise. + * + * @throw None No throw guarantee. + */ + template + bool operator!=(const SmoothView& rhs) const noexcept { return !((*this) == rhs); } +protected: + /// Lets the class access PIMPLs regardless of template type parameter + template + friend class SmoothView; + private: + /// Type of a pointer to the PIMPL + using pimpl_pointer = typename traits_type::pimpl_pointer; + + /// Does *this have a PIMPL? bool has_pimpl_() const noexcept; + + /// Makes a deep copy of the PIMPL pimpl_pointer clone_() const; + + /// The object implementing *this pimpl_pointer m_pimpl_; }; diff --git a/src/tensorwrapper/shape/detail_/smooth_alias.hpp b/src/tensorwrapper/shape/detail_/smooth_alias.hpp new file mode 100644 index 00000000..257b18dc --- /dev/null +++ b/src/tensorwrapper/shape/detail_/smooth_alias.hpp @@ -0,0 +1,69 @@ +#pragma once +#include "smooth_view_pimpl.hpp" + +namespace tensorwrapper::shape::detail_ { + +/** @brief Implements SmoothView by wrapping a Smooth object. + * + * A common scenario that occurs is that we need to use an actual Smooth + * object as if it were a SmoothView object. This class implements a SmoothView + * by wrapping a pointer to an actual Smooth object. All member functions of + * the Smooth object are simply forwarded through the SmoothView API. + * + * @tparam SmoothType the type of Smooth object *this is acting like a view of. + */ +template +class SmoothAlias : public SmoothViewPIMPL { +private: + /// Actual type *this inherits from + using my_base = SmoothViewPIMPL; + + /// Template type parameter with const-qualifier removed + using value_type = std::decay_t; + + /// Type of a SmoothAlias aliasing a read-only Smooth object. + using const_my_type = SmoothAlias; + +public: + /// Pull in bases's types + ///@{ + using base_type = typename my_base::base_type; + using base_pointer = typename my_base::base_pointer; + using parent_type = typename my_base::parent_type; + using smooth_pointer = typename parent_type::smooth_traits::pointer; + using smooth_reference = typename parent_type::smooth_reference; + using rank_type = typename my_base::rank_type; + using size_type = typename my_base::size_type; + using typename my_base::const_smooth_view_pimpl_pointer; + ///@} + + /// Aliases @p shape + explicit SmoothAlias(smooth_reference shape) : m_pshape_(&shape) {} + +protected: + /// Implemented by calling deep copy ctor + base_pointer clone_() const override { + return std::make_unique(*this); + } + + /// These just call shape's member function with the same name + ///@{ + rank_type extent_(size_type i) const override { return shape_().extent(i); } + rank_type rank_() const noexcept override { return shape_().rank(); } + size_type size_() const noexcept override { return shape_().size(); } + ///@} + + /// Implemented by by passing const reference of the shape *this aliases + const_smooth_view_pimpl_pointer as_const_() const override { + return std::make_unique(*m_pshape_); + } + +private: + /// Shortens the keystrokes for dereferencing m_pshape_ + decltype(auto) shape_() const { return *m_pshape_; } + + /// The Smooth object we are aliasing. + smooth_pointer m_pshape_; +}; + +} // namespace tensorwrapper::shape::detail_ \ No newline at end of file diff --git a/src/tensorwrapper/shape/detail_/smooth_view_pimpl.hpp b/src/tensorwrapper/shape/detail_/smooth_view_pimpl.hpp index 2df00f81..60850922 100644 --- a/src/tensorwrapper/shape/detail_/smooth_view_pimpl.hpp +++ b/src/tensorwrapper/shape/detail_/smooth_view_pimpl.hpp @@ -1,43 +1,75 @@ +#pragma once +#include #include namespace tensorwrapper::shape::detail_ { -// Eventually this should be turned into a base class and the current -// implementation moved into a derived class that wraps an existing Smooth -// object +/** @brief Defines the API for all SmoothView PIMPLs. + * + * The data for a SmoothView can be laid out in a number of different ways. + * This class defines the API for accessing it. + * + * @tparam SmoothType The type *this will be a view of. + */ template -class SmoothViewPIMPL { +class SmoothViewPIMPL : public tensorwrapper::detail_::PolymorphicBase< + SmoothViewPIMPL> { +private: + /// Type of *this + using my_type = SmoothViewPIMPL; + + /// Type *this actually inherits from. + using my_base = tensorwrapper::detail_::PolymorphicBase; + public: /// Type of the class *this is implementing using parent_type = SmoothView; /// Pull in parent's types ///@{ - using smooth_pointer = typename parent_type::smooth_traits::pointer; - using smooth_reference = typename parent_type::smooth_reference; - using pimpl_pointer = typename parent_type::pimpl_pointer; - using rank_type = typename parent_type::rank_type; - using size_type = typename parent_type::size_type; + using rank_type = typename parent_type::rank_type; + using size_type = typename parent_type::size_type; ///@} - explicit SmoothViewPIMPL(smooth_reference shape) : m_pshape_(&shape) {} + /// Pull in base's types + using const_base_reference = typename my_base::const_base_reference; - pimpl_pointer clone() const { - return std::make_unique(*this); - } + /// Type of a SmoothViewPIMPL if it aliases a const Smooth + using const_smooth_view_pimpl_pointer = + typename ShapeTraits::const_pimpl_pointer; - rank_type extent(size_type i) const { return m_pshape_->extent(i); } + /// Derived class implements by overriding extent_ + rank_type extent(size_type i) const { return extent_(i); } - rank_type rank() const noexcept { return m_pshape_->rank(); } + /// Derived class implements by overriding rank_ + rank_type rank() const noexcept { return rank_(); } - size_type size() const noexcept { return m_pshape_->size(); } + /// Derived class implements by overriding size_ + size_type size() const noexcept { return size_(); } - bool operator==(const SmoothViewPIMPL& rhs) const noexcept { - return (*m_pshape_) == (*rhs.m_pshape_); - } + /// Derived class implements by overriding as_const_() + const_smooth_view_pimpl_pointer as_const() const { return as_const_(); } -private: - smooth_pointer m_pshape_; +protected: + /// Derived class should implement to be consistent with SmoothView::extent + virtual rank_type extent_(size_type i) const = 0; + + /// Derived class should implement to be consistent with SmoothView::rank + virtual rank_type rank_() const noexcept = 0; + + /// Derived class should implement to be consistent with SmoothView::size + virtual size_type size_() const noexcept = 0; + + /// Used to create a PIMPL for SmoothView + virtual const_smooth_view_pimpl_pointer as_const_() const = 0; + + /// Compares state through common API of this class + bool are_equal_(const_base_reference rhs) const noexcept override { + if(rank() != rhs.rank()) return false; + for(size_type i = 0; i < rank(); ++i) + if(extent(i) != rhs.extent(i)) return false; + return true; + } }; } // namespace tensorwrapper::shape::detail_ \ No newline at end of file diff --git a/src/tensorwrapper/shape/smooth_view.cpp b/src/tensorwrapper/shape/smooth_view.cpp index 881f7bb4..0fc38027 100644 --- a/src/tensorwrapper/shape/smooth_view.cpp +++ b/src/tensorwrapper/shape/smooth_view.cpp @@ -1,4 +1,4 @@ -#include "detail_/smooth_view_pimpl.hpp" +#include "detail_/smooth_alias.hpp" #include namespace tensorwrapper::shape { @@ -8,7 +8,12 @@ namespace tensorwrapper::shape { TPARAMS SMOOTH_VIEW::SmoothView(smooth_reference smooth) : - m_pimpl_(std::make_unique(smooth)) {} + m_pimpl_(std::make_unique>(smooth)) {} + +TPARAMS +template +SMOOTH_VIEW::SmoothView(const SmoothView& other) : + m_pimpl_(other.m_pimpl_->as_const()) {} TPARAMS SMOOTH_VIEW::SmoothView(const SmoothView& other) : m_pimpl_(other.clone_()) {} @@ -49,10 +54,11 @@ void SMOOTH_VIEW::swap(SmoothView& rhs) noexcept { } TPARAMS -bool SMOOTH_VIEW::operator==(const SmoothView& rhs) const noexcept { +bool SMOOTH_VIEW::operator==( + const SmoothView& rhs) const noexcept { if(has_pimpl_() != rhs.has_pimpl_()) return false; if(!has_pimpl_()) return true; - return (*m_pimpl_) == (*rhs.m_pimpl_); + return m_pimpl_->as_const()->are_equal(*rhs.m_pimpl_); } TPARAMS @@ -68,6 +74,7 @@ typename SMOOTH_VIEW::pimpl_pointer SMOOTH_VIEW::clone_() const { #undef SMOOTH_VIEW #undef TPARAMS +template SmoothView::SmoothView(const SmoothView&); template class SmoothView; template class SmoothView; diff --git a/tests/cxx/unit_tests/tensorwrapper/detail_/view_traits.cpp b/tests/cxx/unit_tests/tensorwrapper/detail_/view_traits.cpp new file mode 100644 index 00000000..dd3ac539 --- /dev/null +++ b/tests/cxx/unit_tests/tensorwrapper/detail_/view_traits.cpp @@ -0,0 +1,22 @@ +#include "../helpers.hpp" +#include + +using namespace tensorwrapper::detail_; + +TEST_CASE("is_mutable_to_immutable_cast_v") { + // N.B. Only the const-ness of the types and whether they differ by + // const-ness should matter + STATIC_REQUIRE(is_mutable_to_immutable_cast_v); + + STATIC_REQUIRE_FALSE(is_mutable_to_immutable_cast_v); + STATIC_REQUIRE_FALSE(is_mutable_to_immutable_cast_v); + STATIC_REQUIRE_FALSE(is_mutable_to_immutable_cast_v); + STATIC_REQUIRE_FALSE( + is_mutable_to_immutable_cast_v); +} + +TEST_CASE("enable_if_mutable_to_immutable_cast_t") { + STATIC_REQUIRE( + std::is_same_v< + enable_if_mutable_to_immutable_cast_t, void>); +} \ No newline at end of file diff --git a/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_alias.cpp b/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_alias.cpp new file mode 100644 index 00000000..5fdbcd31 --- /dev/null +++ b/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_alias.cpp @@ -0,0 +1,44 @@ +#include "../../helpers.hpp" +#include + +using namespace tensorwrapper::shape; + +using types2test = std::pair; + +TEMPLATE_LIST_TEST_CASE("SmoothAlias", "", types2test) { + using pimpl_type = detail_::SmoothAlias; + std::decay_t scalar_shape{}, shape{1, 2, 3}; + + pimpl_type scalar(scalar_shape); + pimpl_type value(shape); + + SECTION("CTor") { + REQUIRE(scalar.rank() == scalar_shape.rank()); + REQUIRE(scalar.size() == scalar_shape.size()); + + REQUIRE(value.rank() == shape.rank()); + REQUIRE(value.size() == shape.size()); + } + + SECTION("clone") { + REQUIRE(scalar.clone()->are_equal(scalar)); + REQUIRE(value.clone()->are_equal(value)); + } + + SECTION("extent") { + REQUIRE_THROWS_AS(scalar.extent(0), std::out_of_range); + REQUIRE(value.extent(0) == 1); + REQUIRE(value.extent(1) == 2); + REQUIRE(value.extent(2) == 3); + } + + SECTION("rank") { + REQUIRE(scalar.rank() == 0); + REQUIRE(value.rank() == 3); + } + + SECTION("size") { + REQUIRE(scalar.size() == 1); + REQUIRE(value.size() == 6); + } +} \ No newline at end of file diff --git a/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_view_pimpl.cpp b/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_view_pimpl.cpp index 033186b2..34e01812 100644 --- a/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_view_pimpl.cpp +++ b/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_view_pimpl.cpp @@ -1,22 +1,40 @@ #include "../../helpers.hpp" -#include +#include + +/* Testing Strategy. + * + * At present the only thing actually implemented in SmoothViewPIMPL is + * are_equal so that's all this test case tests. + */ using namespace tensorwrapper::shape; using types2test = std::pair; TEMPLATE_LIST_TEST_CASE("SmoothViewPIMPL", "", types2test) { - using pimpl_type = detail_::SmoothViewPIMPL; - std::decay_t defaulted_shape, shape{1, 2, 3}; + using pimpl_type = detail_::SmoothAlias; + using shape_type = std::decay_t; + shape_type scalar_shape{}, shape{1, 2, 3}; - pimpl_type defaulted(defaulted_shape); + pimpl_type scalar(scalar_shape); pimpl_type value(shape); - SECTION("CTor") { - REQUIRE(defaulted.rank() == defaulted_shape.rank()); - REQUIRE(defaulted.size() == defaulted_shape.size()); + SECTION("are_equal") { + SECTION("Same") { + REQUIRE(scalar.are_equal(pimpl_type(scalar_shape))); + REQUIRE(value.are_equal(pimpl_type(shape))); + } + + SECTION("Different rank") { + shape_type rhs_shape{1}; + pimpl_type rhs(rhs_shape); + REQUIRE_FALSE(scalar.are_equal(rhs)); + } - REQUIRE(value.rank() == shape.rank()); - REQUIRE(value.size() == shape.size()); + SECTION("Different extents") { + shape_type rhs_shape{2, 1, 3}; + pimpl_type rhs(rhs_shape); + REQUIRE_FALSE(value.are_equal(rhs)); + } } } \ No newline at end of file diff --git a/tests/cxx/unit_tests/tensorwrapper/shape/smooth_view.cpp b/tests/cxx/unit_tests/tensorwrapper/shape/smooth_view.cpp new file mode 100644 index 00000000..a97991cf --- /dev/null +++ b/tests/cxx/unit_tests/tensorwrapper/shape/smooth_view.cpp @@ -0,0 +1,128 @@ +/* + * Copyright 2024 NWChemEx Community + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../helpers.hpp" +#include +#include + +using namespace tensorwrapper::testing; +using namespace tensorwrapper::shape; + +using rank_type = typename Smooth::rank_type; +using size_type = typename Smooth::size_type; + +using types2test = std::pair; +TEMPLATE_LIST_TEST_CASE("SmoothView", "", types2test) { + using view_type = SmoothView; + using const_view_type = SmoothView>; + using smooth_type = typename view_type::smooth_type; + + smooth_type scalar{}; + smooth_type vector{3}; + + view_type alias_scalar(scalar); + view_type alias_vector(vector); + + SECTION("Ctors and assignment") { + SECTION("alias Smooth object") { + REQUIRE(alias_scalar.rank() == rank_type(0)); + REQUIRE(alias_scalar.size() == size_type(1)); + + REQUIRE(alias_vector.rank() == rank_type(1)); + REQUIRE(alias_vector.size() == size_type(3)); + } + + SECTION("Assign to const") { + // if TestType is non-const this tests mutable to const conversion, + // otherwise this duplicates the copy ctor test. + const_view_type const_scalar(alias_scalar); + REQUIRE(const_scalar.rank() == rank_type(0)); + REQUIRE(const_scalar.size() == size_type(1)); + } + + test_copy_and_move_ctors(alias_scalar, alias_vector); + + SECTION("copy assignment") { + view_type copy_scalar(alias_scalar); + auto pcopy_scalar = &(copy_scalar = alias_vector); + REQUIRE(copy_scalar == alias_vector); + REQUIRE(pcopy_scalar == ©_scalar); + } + + SECTION("move assignment") { + view_type copy_scalar(alias_scalar); + view_type copy_vector(alias_vector); + auto pcopy_scalar = &(copy_scalar = std::move(alias_vector)); + REQUIRE(copy_scalar == copy_vector); + REQUIRE(pcopy_scalar == ©_scalar); + } + } + + SECTION("extent") { + REQUIRE_THROWS_AS(alias_scalar.extent(0), std::out_of_range); + + REQUIRE(alias_vector.extent(0) == 3); + REQUIRE_THROWS_AS(alias_vector.extent(1), std::out_of_range); + } + + SECTION("rank") { + REQUIRE(alias_scalar.rank() == rank_type(0)); + REQUIRE(alias_vector.rank() == rank_type(1)); + } + + SECTION("size") { + REQUIRE(alias_scalar.size() == size_type(1)); + REQUIRE(alias_vector.size() == size_type(3)); + } + + SECTION("Utility methods") { + SECTION("swap") { + view_type scalar_copy(alias_scalar); + view_type vector_copy(alias_vector); + + alias_vector.swap(alias_scalar); + REQUIRE(alias_vector == scalar_copy); + REQUIRE(alias_scalar == vector_copy); + } + + SECTION("operator==") { + // Same shapes + REQUIRE(alias_scalar == view_type(scalar)); + REQUIRE(alias_vector == view_type(vector)); + + // (Possibly) different const-ness (if same const-ness duplicates + // the above check). Also check for symmetry. + REQUIRE(alias_scalar == const_view_type(alias_scalar)); + REQUIRE(const_view_type(alias_scalar) == alias_scalar); + + // Can compare aliases with objects + REQUIRE(alias_scalar == scalar); + + // Different ranks + REQUIRE_FALSE(alias_scalar == alias_vector); + + // Different extents + smooth_type vector2{2}; + REQUIRE_FALSE(alias_vector == view_type(vector2)); + } + + SECTION("operator!=") { + // Implemented by negating operator==, so just spot check + REQUIRE_FALSE(alias_scalar != view_type(scalar)); + REQUIRE(alias_scalar != alias_vector); + } + } +} From 82cea9e81936ecb4ea279c048b5d759884f5407d Mon Sep 17 00:00:00 2001 From: "Ryan M. Richard" Date: Tue, 15 Oct 2024 15:53:05 -0500 Subject: [PATCH 3/4] r2g --- include/tensorwrapper/shape/shape_base.hpp | 42 +++++++++ include/tensorwrapper/shape/smooth.hpp | 6 ++ include/tensorwrapper/shape/smooth_view.hpp | 93 ++++++++++++++++++- .../shape/detail_/smooth_alias.hpp | 1 + .../unit_tests/tensorwrapper/shape/smooth.cpp | 10 ++ .../tensorwrapper/shape/smooth_view.cpp | 2 + 6 files changed, 153 insertions(+), 1 deletion(-) diff --git a/include/tensorwrapper/shape/shape_base.hpp b/include/tensorwrapper/shape/shape_base.hpp index d9044851..ce352e61 100644 --- a/include/tensorwrapper/shape/shape_base.hpp +++ b/include/tensorwrapper/shape/shape_base.hpp @@ -19,6 +19,8 @@ #include #include #include +#include + namespace tensorwrapper::shape { /** @brief Code factorization for the various types of shapes. @@ -53,6 +55,12 @@ class ShapeBase : public tensorwrapper::detail_::PolymorphicBase { /// Type used to specify the number of elements in the shape using size_type = typename traits_type::size_type; + /// Type of an object acting like a mutable reference to a Smooth shape + using smooth_reference = SmoothView; + + /// Type of an object acting like a read-only reference to a Smooth shape + using const_smooth_reference = SmoothView; + /// No-op for ShapeBase because ShapeBase has no state ShapeBase() noexcept = default; @@ -88,6 +96,34 @@ class ShapeBase : public tensorwrapper::detail_::PolymorphicBase { */ size_type size() const noexcept { return get_size_(); } + /** @brief Returns a view of *this as a Smooth object. + * + * It is possible to view any shape as a smooth shape. For more exotic + * shapes this may require flattening nestings and padding dimensions. + * This method ultimately dispatches to the as_smooth_ overload of the + * derived class to control how to smooth the shape out. + * + * @return A view of *this consistent with thinking of *this as a Smooth + * object. + * + * @throw std::bad_alloc if there is a problem allocating the view. Strong + * throw guarantee. + */ + smooth_reference as_smooth() { return as_smooth_(); } + + /** @brief Returns a read-only view of *this as a Smooth object. + * + * This method works the same as the non-const version except that the + * resulting view is read-only. + * + * @return A read-only view of *this consistent with thinking of *this as + * a Smooth object. + * + * @throw std::bad_alloc if there is a problem allocating the view. Strong + * throw guarantee. + */ + const_smooth_reference as_smooth() const { return as_smooth_(); } + protected: /** @brief Used to implement rank(). * @@ -113,6 +149,12 @@ class ShapeBase : public tensorwrapper::detail_::PolymorphicBase { * subject to a no-throw guarantee. */ virtual size_type get_size_() const noexcept = 0; + + /// Derived class should override to be consistent with as_smooth() + virtual smooth_reference as_smooth_() = 0; + + /// Derived class should override to be consistent with as_smooth() const + virtual const_smooth_reference as_smooth_() const = 0; }; } // namespace tensorwrapper::shape diff --git a/include/tensorwrapper/shape/smooth.hpp b/include/tensorwrapper/shape/smooth.hpp index fb4b8ad9..95315f2e 100644 --- a/include/tensorwrapper/shape/smooth.hpp +++ b/include/tensorwrapper/shape/smooth.hpp @@ -166,6 +166,12 @@ class Smooth : public ShapeBase { size_type(1), std::multiplies()); } + smooth_reference as_smooth_() override { return smooth_reference(*this); } + + virtual const_smooth_reference as_smooth_() const override { + return const_smooth_reference(*this); + } + /// Implements are_equal by calling ShapeBase::are_equal_impl_ bool are_equal_(const ShapeBase& rhs) const noexcept override { return are_equal_impl_(rhs); diff --git a/include/tensorwrapper/shape/smooth_view.hpp b/include/tensorwrapper/shape/smooth_view.hpp index 314dd62a..1acc3df6 100644 --- a/include/tensorwrapper/shape/smooth_view.hpp +++ b/include/tensorwrapper/shape/smooth_view.hpp @@ -1,7 +1,6 @@ #pragma once #include #include -#include namespace tensorwrapper::shape { @@ -76,21 +75,113 @@ class SmoothView { typename = enable_if_mutable_to_immutable_cast_t> SmoothView(const SmoothView& other); + /** @brief Creates a new view aliasing the same Smooth object as @p other. + * + * Views alias their state. The view constructed by this copy ctor will + * alias the same state that is aliased by @p other. In this sense it is + * a shallow copy of the aliased state and a deep copy of @p other. + * + * @param[in] other The view to copy. + * + * @throw std::bad_alloc if there is a problem allocating the copy. Strong + * throw guarantee. + */ SmoothView(const SmoothView& other); + + /** @brief Creates a new view by taking the state of @p other. + * + * This ctor initializes *this by taking the state from @p other. After + * construction *this will alias the same object @p other did. It is worth + * noting the aliased object is untouched after this operation. + * + * @param[in,out] other The object to take the state from. After this + * operation @p other will be in a valid, but + * otherwise undefined state. + * + * @throw None No throw guarantee. + */ SmoothView(SmoothView&& other) noexcept; + + /** @brief Overwrites *this to alias the same Smooth object as @p other. + * + * This operator causes the state in *this to instead alias the Smooth + * object in @p other. This does not release the state associated with the + * aliased object. + * + * @param[in] other The view to copy. + * + * @return *this after making it alias the state in @p other. + * + * @throw std::bad_alloc if there is a problem allocating the copy. Strong + * throw guarantee. + */ SmoothView& operator=(const SmoothView& rhs); + + /** @brief Overrides the state of *this with the state of @p other. + * + * This operator causes the state to be replaced by the state in @p other. + * This does not release the state associated with the aliased object nor + * does it take state from the aliased object. + * + * @param[in,out] other The object to take the state from. After this + * operation @p other will be in a valid, but + * otherwise undefined state. + * + * @return *this after taking the state of @p other. + * + * @throw None No throw guarantee. + */ SmoothView& operator=(SmoothView&& rhs) noexcept; /// Nothrow defaulted dtor ~SmoothView() noexcept; + /** @brief What is the extent of the i-th mode of the tensor with the + * aliased shape? + * + * @param[in] i The offset of the requested mode. @p i must be in the + * range [0, size()). + * + * @return The length of the @p i-th mode in a tensor with the aliased + * shape. + * + * @throw std::out_of_range if @p i is not in the range [0, size()). Strong + * throw guarantee. + */ rank_type extent(size_type i) const; + + /** @brief What is the rank of the tensor the aliased shape describes? + * + * @return The rank of the tensor with the aliased shape. + * + * @throw None No throw guarantee. + */ rank_type rank() const noexcept; + + /** @brief How many elements are in the tensor the aliased shape describes? + * + * @return The number of elements in a tensor with the aliased shape. + * + * @throw None No throw guarantee. + */ size_type size() const noexcept; /// Swaps the state of *this with that of @p rhs void swap(SmoothView& rhs) noexcept; + /** @brief Is the Smooth shape aliased by *this the same as that aliased by + * @p rhs? + * + * Two SmoothView objects are value equal if the Smooth objects they alias + * compare value equal. + * + * @param[in] rhs The view aliasing the shape to compare to. + * + * @return True if *this aliases a Smooth object which is value equal to + * that aliased by @p rhs and false otherwise. + * + * @throw None No throw guarantee. + */ bool operator==(const SmoothView& rhs) const noexcept; /** @brief Is *this different from @p rhs? diff --git a/src/tensorwrapper/shape/detail_/smooth_alias.hpp b/src/tensorwrapper/shape/detail_/smooth_alias.hpp index 257b18dc..023e535c 100644 --- a/src/tensorwrapper/shape/detail_/smooth_alias.hpp +++ b/src/tensorwrapper/shape/detail_/smooth_alias.hpp @@ -1,5 +1,6 @@ #pragma once #include "smooth_view_pimpl.hpp" +#include namespace tensorwrapper::shape::detail_ { diff --git a/tests/cxx/unit_tests/tensorwrapper/shape/smooth.cpp b/tests/cxx/unit_tests/tensorwrapper/shape/smooth.cpp index 3ff31d25..9bdff9bd 100644 --- a/tests/cxx/unit_tests/tensorwrapper/shape/smooth.cpp +++ b/tests/cxx/unit_tests/tensorwrapper/shape/smooth.cpp @@ -94,6 +94,16 @@ TEST_CASE("Smooth") { REQUIRE(tensor.size() == size_type(60)); } + SECTION("as_smooth()") { + REQUIRE(scalar.as_smooth() == scalar); + REQUIRE(vector.as_smooth() == vector); + } + + SECTION("as_smooth() const") { + REQUIRE(std::as_const(scalar).as_smooth() == scalar); + REQUIRE(std::as_const(vector).as_smooth() == vector); + } + SECTION("are_equal_") { // Relies on operator==, which is tested below. So just spot check. REQUIRE(scalar.are_equal(Smooth{})); diff --git a/tests/cxx/unit_tests/tensorwrapper/shape/smooth_view.cpp b/tests/cxx/unit_tests/tensorwrapper/shape/smooth_view.cpp index a97991cf..48587b86 100644 --- a/tests/cxx/unit_tests/tensorwrapper/shape/smooth_view.cpp +++ b/tests/cxx/unit_tests/tensorwrapper/shape/smooth_view.cpp @@ -16,6 +16,7 @@ #include "../helpers.hpp" #include +#include #include using namespace tensorwrapper::testing; @@ -25,6 +26,7 @@ using rank_type = typename Smooth::rank_type; using size_type = typename Smooth::size_type; using types2test = std::pair; + TEMPLATE_LIST_TEST_CASE("SmoothView", "", types2test) { using view_type = SmoothView; using const_view_type = SmoothView>; From 441d389d1bcdcae7cfac5e320ef820a026762d71 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 15 Oct 2024 20:53:50 +0000 Subject: [PATCH 4/4] Committing clang-format changes --- include/tensorwrapper/detail_/view_traits.hpp | 16 ++++++++++++++++ include/tensorwrapper/shape/shape_fwd.hpp | 16 ++++++++++++++++ include/tensorwrapper/shape/shape_traits.hpp | 16 ++++++++++++++++ include/tensorwrapper/shape/smooth_view.hpp | 16 ++++++++++++++++ src/tensorwrapper/shape/detail_/smooth_alias.hpp | 16 ++++++++++++++++ .../shape/detail_/smooth_view_pimpl.hpp | 16 ++++++++++++++++ src/tensorwrapper/shape/smooth_view.cpp | 16 ++++++++++++++++ .../tensorwrapper/detail_/view_traits.cpp | 16 ++++++++++++++++ .../tensorwrapper/shape/detail_/smooth_alias.cpp | 16 ++++++++++++++++ .../shape/detail_/smooth_view_pimpl.cpp | 16 ++++++++++++++++ 10 files changed, 160 insertions(+) diff --git a/include/tensorwrapper/detail_/view_traits.hpp b/include/tensorwrapper/detail_/view_traits.hpp index db347f1b..9deab3ac 100644 --- a/include/tensorwrapper/detail_/view_traits.hpp +++ b/include/tensorwrapper/detail_/view_traits.hpp @@ -1,3 +1,19 @@ +/* + * Copyright 2024 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #pragma once #include diff --git a/include/tensorwrapper/shape/shape_fwd.hpp b/include/tensorwrapper/shape/shape_fwd.hpp index 8a84008c..cc2657c5 100644 --- a/include/tensorwrapper/shape/shape_fwd.hpp +++ b/include/tensorwrapper/shape/shape_fwd.hpp @@ -1,3 +1,19 @@ +/* + * Copyright 2024 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #pragma once namespace tensorwrapper::shape { diff --git a/include/tensorwrapper/shape/shape_traits.hpp b/include/tensorwrapper/shape/shape_traits.hpp index 6cdf9d86..07dbc7a1 100644 --- a/include/tensorwrapper/shape/shape_traits.hpp +++ b/include/tensorwrapper/shape/shape_traits.hpp @@ -1,3 +1,19 @@ +/* + * Copyright 2024 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #pragma once #include #include diff --git a/include/tensorwrapper/shape/smooth_view.hpp b/include/tensorwrapper/shape/smooth_view.hpp index 1acc3df6..253efe08 100644 --- a/include/tensorwrapper/shape/smooth_view.hpp +++ b/include/tensorwrapper/shape/smooth_view.hpp @@ -1,3 +1,19 @@ +/* + * Copyright 2024 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #pragma once #include #include diff --git a/src/tensorwrapper/shape/detail_/smooth_alias.hpp b/src/tensorwrapper/shape/detail_/smooth_alias.hpp index 023e535c..0bfc6f4a 100644 --- a/src/tensorwrapper/shape/detail_/smooth_alias.hpp +++ b/src/tensorwrapper/shape/detail_/smooth_alias.hpp @@ -1,3 +1,19 @@ +/* + * Copyright 2024 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #pragma once #include "smooth_view_pimpl.hpp" #include diff --git a/src/tensorwrapper/shape/detail_/smooth_view_pimpl.hpp b/src/tensorwrapper/shape/detail_/smooth_view_pimpl.hpp index 60850922..56a2b1e1 100644 --- a/src/tensorwrapper/shape/detail_/smooth_view_pimpl.hpp +++ b/src/tensorwrapper/shape/detail_/smooth_view_pimpl.hpp @@ -1,3 +1,19 @@ +/* + * Copyright 2024 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #pragma once #include #include diff --git a/src/tensorwrapper/shape/smooth_view.cpp b/src/tensorwrapper/shape/smooth_view.cpp index 0fc38027..fba74d12 100644 --- a/src/tensorwrapper/shape/smooth_view.cpp +++ b/src/tensorwrapper/shape/smooth_view.cpp @@ -1,3 +1,19 @@ +/* + * Copyright 2024 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "detail_/smooth_alias.hpp" #include diff --git a/tests/cxx/unit_tests/tensorwrapper/detail_/view_traits.cpp b/tests/cxx/unit_tests/tensorwrapper/detail_/view_traits.cpp index dd3ac539..22699691 100644 --- a/tests/cxx/unit_tests/tensorwrapper/detail_/view_traits.cpp +++ b/tests/cxx/unit_tests/tensorwrapper/detail_/view_traits.cpp @@ -1,3 +1,19 @@ +/* + * Copyright 2024 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "../helpers.hpp" #include diff --git a/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_alias.cpp b/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_alias.cpp index 5fdbcd31..224c4812 100644 --- a/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_alias.cpp +++ b/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_alias.cpp @@ -1,3 +1,19 @@ +/* + * Copyright 2024 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "../../helpers.hpp" #include diff --git a/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_view_pimpl.cpp b/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_view_pimpl.cpp index 34e01812..5c07e15b 100644 --- a/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_view_pimpl.cpp +++ b/tests/cxx/unit_tests/tensorwrapper/shape/detail_/smooth_view_pimpl.cpp @@ -1,3 +1,19 @@ +/* + * Copyright 2024 NWChemEx-Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "../../helpers.hpp" #include