|
3 | 3 | // See accompanying file LICENSE_1_0.txt |
4 | 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) |
5 | 5 |
|
| 6 | +// https://godbolt.org/z/r6o4f171r |
| 7 | + |
6 | 8 | #include <iostream> |
7 | 9 | #include <memory> |
8 | 10 | #include <string> |
9 | 11 | #include <typeinfo> |
10 | 12 |
|
11 | 13 | #include <boost/openmethod.hpp> |
| 14 | +#include <boost/openmethod/policies/static_rtti.hpp> |
12 | 15 | #include <boost/openmethod/initialize.hpp> |
13 | | -#include <boost/openmethod/interop/std_shared_ptr.hpp> |
14 | 16 |
|
15 | | -using std::make_shared; |
16 | | -using std::shared_ptr; |
17 | 17 | using std::string; |
18 | 18 |
|
19 | | -using boost::openmethod::make_shared_virtual; |
20 | | -using boost::openmethod::shared_virtual_ptr; |
21 | | -using boost::openmethod::virtual_ptr; |
| 19 | +using namespace boost::openmethod::aliases; |
22 | 20 |
|
23 | | -struct matrix { |
24 | | - virtual ~matrix() { |
25 | | - } |
26 | | - virtual auto at(int row, int col) const -> double = 0; |
27 | | - // ... |
| 21 | +struct abstract { |
| 22 | + int ref_count = 0; |
28 | 23 | }; |
29 | 24 |
|
30 | | -struct dense_matrix : matrix { |
31 | | - virtual auto at(int /*row*/, int /*col*/) const -> double { |
32 | | - return 0; |
| 25 | +struct registry |
| 26 | + : boost::openmethod::registry<boost::openmethod::policies::static_rtti> {}; |
| 27 | + |
| 28 | +template<class Rep> |
| 29 | +using matrix_ptr = boost::openmethod::virtual_ptr<Rep, registry>; |
| 30 | + |
| 31 | +BOOST_OPENMETHOD(destroy, (matrix_ptr<abstract>), void, registry); |
| 32 | + |
| 33 | +class matrix { |
| 34 | + matrix_ptr<abstract> rep_; |
| 35 | + |
| 36 | + explicit matrix(matrix_ptr<abstract> rep) : rep_(rep) { |
| 37 | + ++rep_->ref_count; |
| 38 | + |
| 39 | + if (--rep->ref_count == 0) { |
| 40 | + destroy(rep); |
| 41 | + } |
33 | 42 | } |
34 | | -}; |
35 | 43 |
|
36 | | -struct diagonal_matrix : matrix { |
37 | | - virtual auto at(int /*row*/, int /*col*/) const -> double { |
38 | | - return 0; |
| 44 | + public: |
| 45 | + matrix(const matrix&) = default; |
| 46 | + matrix& operator=(const matrix&) = default; |
| 47 | + |
| 48 | + auto rep() const -> matrix_ptr<abstract> { |
| 49 | + return rep_; |
39 | 50 | } |
40 | | -}; |
41 | 51 |
|
42 | | -BOOST_OPENMETHOD_CLASSES(matrix, dense_matrix, diagonal_matrix); |
| 52 | + template<class Rep, class... Args> |
| 53 | + static matrix make(Args&&... args) { |
| 54 | + return matrix( |
| 55 | + boost::openmethod::final_virtual_ptr<registry>( |
| 56 | + *new Rep(std::forward<Args>(args)...))); |
| 57 | + } |
| 58 | +}; |
43 | 59 |
|
44 | | -BOOST_OPENMETHOD(to_json, (virtual_ptr<const matrix>), string); |
| 60 | +struct dense : abstract { |
| 61 | + static constexpr const char* type = "dense"; |
| 62 | +}; |
45 | 63 |
|
46 | | -BOOST_OPENMETHOD_OVERRIDE(to_json, (virtual_ptr<const dense_matrix>), string) { |
47 | | - return "json for dense matrix..."; |
| 64 | +BOOST_OPENMETHOD_OVERRIDE(destroy, (matrix_ptr<dense> rep), void) { |
| 65 | + delete rep.get(); |
48 | 66 | } |
49 | 67 |
|
50 | | -BOOST_OPENMETHOD_OVERRIDE( |
51 | | - to_json, (virtual_ptr<const diagonal_matrix>), string) { |
52 | | - return "json for diagonal matrix..."; |
| 68 | +struct diagonal : abstract { |
| 69 | + static constexpr const char* type = "diagonal"; |
| 70 | +}; |
| 71 | + |
| 72 | +BOOST_OPENMETHOD_OVERRIDE(destroy, (matrix_ptr<diagonal> rep), void) { |
| 73 | + delete rep.get(); |
53 | 74 | } |
54 | 75 |
|
| 76 | +BOOST_OPENMETHOD_CLASSES(abstract, dense, diagonal, registry); |
| 77 | + |
55 | 78 | // ----------------------------------------------------------------------------- |
56 | 79 | // matrix * matrix |
57 | 80 |
|
58 | 81 | BOOST_OPENMETHOD( |
59 | | - times, (shared_virtual_ptr<const matrix>, shared_virtual_ptr<const matrix>), |
60 | | - shared_virtual_ptr<const matrix>); |
| 82 | + times, (matrix_ptr<abstract>, matrix_ptr<abstract>), matrix, registry); |
61 | 83 |
|
62 | | -// catch-all matrix * matrix -> dense_matrix |
| 84 | +// catch-all matrix * matrix -> dense |
63 | 85 | BOOST_OPENMETHOD_OVERRIDE( |
64 | | - times, |
65 | | - (shared_virtual_ptr<const matrix> /*a*/, |
66 | | - shared_virtual_ptr<const matrix> /*b*/), |
67 | | - shared_virtual_ptr<const dense_matrix>) { |
68 | | - return make_shared<const dense_matrix>(); |
| 86 | + times, (matrix_ptr<abstract> /*a*/, matrix_ptr<abstract> /*b*/), matrix) { |
| 87 | + return matrix::make<dense>(); |
69 | 88 | } |
70 | 89 |
|
71 | | -// diagonal_matrix * diagonal_matrix -> diagonal_matrix |
| 90 | +// diagonal * diagonal -> diagonal |
72 | 91 | BOOST_OPENMETHOD_OVERRIDE( |
73 | | - times, |
74 | | - (shared_virtual_ptr<const diagonal_matrix> /*a*/, |
75 | | - shared_virtual_ptr<const diagonal_matrix> /*b*/), |
76 | | - shared_virtual_ptr<const diagonal_matrix>) { |
77 | | - return make_shared_virtual<diagonal_matrix>(); |
| 92 | + times, (matrix_ptr<diagonal> /*a*/, matrix_ptr<diagonal> /*b*/), matrix) { |
| 93 | + return matrix::make<diagonal>(); |
78 | 94 | } |
79 | 95 |
|
80 | | -inline auto operator*(shared_ptr<const matrix> a, shared_ptr<const matrix> b) |
81 | | - -> shared_virtual_ptr<const matrix> { |
82 | | - return times(a, b); |
| 96 | +inline auto operator*(matrix a, matrix b) -> matrix { |
| 97 | + return times(a.rep(), b.rep()); |
83 | 98 | } |
84 | 99 |
|
85 | 100 | // ----------------------------------------------------------------------------- |
86 | 101 | // scalar * matrix |
87 | 102 |
|
88 | | -BOOST_OPENMETHOD( |
89 | | - times, (double, shared_virtual_ptr<const matrix>), |
90 | | - shared_virtual_ptr<const matrix>); |
| 103 | +BOOST_OPENMETHOD(times, (double, matrix_ptr<abstract>), matrix, registry); |
91 | 104 |
|
92 | | -// catch-all matrix * scalar -> dense_matrix |
| 105 | +// catch-all matrix * scalar -> dense |
93 | 106 | BOOST_OPENMETHOD_OVERRIDE( |
94 | | - times, (double /*a*/, shared_virtual_ptr<const matrix> /*b*/), |
95 | | - shared_virtual_ptr<const dense_matrix>) { |
96 | | - return make_shared_virtual<dense_matrix>(); |
| 107 | + times, (double /*a*/, matrix_ptr<abstract> /*b*/), matrix) { |
| 108 | + return matrix::make<dense>(); |
97 | 109 | } |
98 | 110 |
|
99 | 111 | BOOST_OPENMETHOD_OVERRIDE( |
100 | | - times, (double /*a*/, shared_virtual_ptr<const diagonal_matrix> /*b*/), |
101 | | - shared_virtual_ptr<const diagonal_matrix>) { |
102 | | - return make_shared_virtual<diagonal_matrix>(); |
| 112 | + times, (double /*a*/, matrix_ptr<diagonal> /*b*/), matrix) { |
| 113 | + return matrix::make<diagonal>(); |
103 | 114 | } |
104 | 115 |
|
105 | 116 | // ----------------------------------------------------------------------------- |
106 | 117 | // matrix * scalar |
107 | 118 |
|
108 | 119 | // just swap |
109 | | -inline auto times(shared_virtual_ptr<const matrix> a, double b) |
110 | | - -> shared_virtual_ptr<const matrix> { |
| 120 | +inline auto times(matrix_ptr<abstract> a, double b) -> matrix { |
111 | 121 | return times(b, a); |
112 | 122 | } |
113 | 123 |
|
114 | 124 | // ----------------------------------------------------------------------------- |
115 | 125 | // main |
116 | 126 |
|
117 | | -#define check(expr) \ |
118 | | - { \ |
119 | | - if (!(expr)) { \ |
120 | | - cerr << #expr << " failed\n"; \ |
121 | | - } \ |
122 | | - } |
| 127 | +BOOST_OPENMETHOD(write, (matrix_ptr<abstract>), string, registry); |
| 128 | + |
| 129 | +inline auto operator<<(std::ostream& os, matrix a) -> std::ostream& { |
| 130 | + return os << write(a.rep()); |
| 131 | +} |
| 132 | + |
| 133 | +BOOST_OPENMETHOD_OVERRIDE(write, (matrix_ptr<dense>), string) { |
| 134 | + return "a dense matrix"; |
| 135 | +} |
| 136 | + |
| 137 | +BOOST_OPENMETHOD_OVERRIDE(write, (matrix_ptr<diagonal>), string) { |
| 138 | + return "a diagonal matrix"; |
| 139 | +} |
123 | 140 |
|
124 | 141 | auto main() -> int { |
125 | 142 | using std::cerr; |
126 | 143 | using std::cout; |
127 | 144 |
|
128 | | - boost::openmethod::initialize(); |
| 145 | + boost::openmethod::initialize<registry>(); |
129 | 146 |
|
130 | | - shared_ptr<const matrix> a = make_shared<dense_matrix>(); |
131 | | - shared_ptr<const matrix> b = make_shared<diagonal_matrix>(); |
| 147 | + matrix a = matrix::make<dense>(); |
| 148 | + matrix b = matrix::make<diagonal>(); |
132 | 149 | double s = 1; |
133 | 150 |
|
134 | | -#ifdef BOOST_CLANG |
135 | | -#pragma clang diagnostic ignored "-Wpotentially-evaluated-expression" |
136 | | -#endif |
137 | | - |
138 | | - check(typeid(*times(a, a)) == typeid(dense_matrix)); |
139 | | - check(typeid(*times(a, b)) == typeid(dense_matrix)); |
140 | | - check(typeid(*times(b, b)) == typeid(diagonal_matrix)); |
141 | | - check(typeid(*times(s, a)) == typeid(dense_matrix)); |
142 | | - check(typeid(*times(s, b)) == typeid(diagonal_matrix)); |
143 | | - |
144 | | - cout << to_json(*a) << "\n"; // json for dense matrix |
145 | | - cout << to_json(*b) << "\n"; // json for diagonal matrix |
| 151 | + cout << a << "\n"; |
| 152 | + cout << b << "\n"; |
146 | 153 |
|
147 | 154 | return 0; |
148 | 155 | } |
0 commit comments