// Copyright (c) 2018-2025 Jean-Louis Leroy // Distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) // https://godbolt.org/z/r6o4f171r #include #include #include #include #include #include #include using std::string; using namespace boost::openmethod::aliases; struct abstract { int ref_count = 0; }; struct registry : boost::openmethod::registry {}; template using matrix_ptr = boost::openmethod::virtual_ptr; BOOST_OPENMETHOD(destroy, (matrix_ptr), void, registry); class matrix { matrix_ptr rep_; explicit matrix(matrix_ptr rep) : rep_(rep) { ++rep_->ref_count; if (--rep->ref_count == 0) { destroy(rep); } } public: matrix(const matrix&) = default; matrix& operator=(const matrix&) = default; auto rep() const -> matrix_ptr { return rep_; } template static matrix make(Args&&... args) { return matrix( boost::openmethod::final_virtual_ptr( *new Rep(std::forward(args)...))); } }; struct dense : abstract { static constexpr const char* type = "dense"; }; BOOST_OPENMETHOD_OVERRIDE(destroy, (matrix_ptr rep), void) { delete rep.get(); } struct diagonal : abstract { static constexpr const char* type = "diagonal"; }; BOOST_OPENMETHOD_OVERRIDE(destroy, (matrix_ptr rep), void) { delete rep.get(); } BOOST_OPENMETHOD_CLASSES(abstract, dense, diagonal, registry); // ----------------------------------------------------------------------------- // matrix * matrix BOOST_OPENMETHOD( times, (matrix_ptr, matrix_ptr), matrix, registry); // catch-all matrix * matrix -> dense BOOST_OPENMETHOD_OVERRIDE( times, (matrix_ptr /*a*/, matrix_ptr /*b*/), matrix) { return matrix::make(); } // diagonal * diagonal -> diagonal BOOST_OPENMETHOD_OVERRIDE( times, (matrix_ptr /*a*/, matrix_ptr /*b*/), matrix) { return matrix::make(); } inline auto operator*(matrix a, matrix b) -> matrix { return times(a.rep(), b.rep()); } // ----------------------------------------------------------------------------- // scalar * matrix BOOST_OPENMETHOD(times, (double, matrix_ptr), matrix, registry); // catch-all matrix * scalar -> dense BOOST_OPENMETHOD_OVERRIDE( times, (double /*a*/, matrix_ptr /*b*/), matrix) { return matrix::make(); } BOOST_OPENMETHOD_OVERRIDE( times, (double /*a*/, matrix_ptr /*b*/), matrix) { return matrix::make(); } // ----------------------------------------------------------------------------- // matrix * scalar // just swap inline auto times(matrix_ptr a, double b) -> matrix { return times(b, a); } // ----------------------------------------------------------------------------- // main BOOST_OPENMETHOD(write, (matrix_ptr), string, registry); inline auto operator<<(std::ostream& os, matrix a) -> std::ostream& { return os << write(a.rep()); } BOOST_OPENMETHOD_OVERRIDE(write, (matrix_ptr), string) { return "a dense matrix"; } BOOST_OPENMETHOD_OVERRIDE(write, (matrix_ptr), string) { return "a diagonal matrix"; } auto main() -> int { using std::cerr; using std::cout; boost::openmethod::initialize(); matrix a = matrix::make(); matrix b = matrix::make(); double s = 1; cout << a << "\n"; cout << b << "\n"; return 0; }