mirror of
https://github.com/boostorg/openmethod.git
synced 2026-01-27 19:12:11 +00:00
Compare commits
13 Commits
boost-1.90
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e2454d841 | ||
|
|
3dfaf30264 | ||
|
|
f4860bbac3 | ||
|
|
6c48df7a03 | ||
|
|
f0a8656744 | ||
|
|
c465260fe7 | ||
|
|
f53122eae8 | ||
|
|
41eaec5bef | ||
|
|
5796d3c3ea | ||
|
|
a6337d2f55 | ||
|
|
02cffffe4f | ||
|
|
ef48e48235 | ||
|
|
e0ead3bf71 |
@@ -37,10 +37,35 @@ set(__ignore__ ${CMAKE_C_COMPILER})
|
|||||||
# Options
|
# Options
|
||||||
#
|
#
|
||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
option(BOOST_OPENMETHOD_BUILD_TESTS "Build boost::openmethod tests even if BUILD_TESTING is OFF" OFF)
|
|
||||||
option(BOOST_OPENMETHOD_BUILD_EXAMPLES "Build boost::openmethod examples" ${BOOST_OPENMETHOD_IS_ROOT})
|
option(
|
||||||
option(BOOST_OPENMETHOD_MRDOCS_BUILD "Build the target for MrDocs: see mrdocs.yml" OFF)
|
BOOST_OPENMETHOD_BUILD_TESTS
|
||||||
option(BOOST_OPENMETHOD_WARNINGS_AS_ERRORS "Treat warnings as errors" OFF)
|
"Build boost::openmethod tests even if BUILD_TESTING is OFF"
|
||||||
|
${BOOST_OPENMETHOD_IS_ROOT})
|
||||||
|
|
||||||
|
if (BUILD_TESTING)
|
||||||
|
set(BOOST_OPENMETHOD_BUILD_TESTS ON)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
option(
|
||||||
|
BOOST_OPENMETHOD_BUILD_EXAMPLES
|
||||||
|
"Build boost::openmethod examples"
|
||||||
|
${BOOST_OPENMETHOD_IS_ROOT})
|
||||||
|
option(
|
||||||
|
BOOST_OPENMETHOD_MRDOCS_BUILD
|
||||||
|
"Build the target for MrDocs: see mrdocs.yml"
|
||||||
|
OFF)
|
||||||
|
option(
|
||||||
|
BOOST_OPENMETHOD_WARNINGS_AS_ERRORS
|
||||||
|
"Treat warnings as errors"
|
||||||
|
OFF)
|
||||||
|
|
||||||
|
if (BOOST_OPENMETHOD_BUILD_EXAMPLES AND NOT BOOST_OPENMETHOD_BUILD_TESTS)
|
||||||
|
message(
|
||||||
|
WARNING
|
||||||
|
"BOOST_OPENMETHOD_BUILD_EXAMPLES requires BOOST_OPENMETHOD_BUILD_TESTS. Examples will not be built.")
|
||||||
|
set(BOOST_OPENMETHOD_BUILD_EXAMPLES OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Check if environment variable BOOST_SRC_DIR is set
|
# Check if environment variable BOOST_SRC_DIR is set
|
||||||
if (NOT DEFINED BOOST_SRC_DIR AND DEFINED ENV{BOOST_SRC_DIR})
|
if (NOT DEFINED BOOST_SRC_DIR AND DEFINED ENV{BOOST_SRC_DIR})
|
||||||
@@ -67,21 +92,30 @@ set(
|
|||||||
Boost::preprocessor
|
Boost::preprocessor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (BOOST_OPENMETHOD_BUILD_TESTS OR BOOST_OPENMETHOD_MRDOCS_BUILD)
|
||||||
|
list(APPEND BOOST_OPENMETHOD_DEPENDENCIES Boost::smart_ptr)
|
||||||
|
endif()
|
||||||
|
|
||||||
foreach (BOOST_OPENMETHOD_DEPENDENCY ${BOOST_OPENMETHOD_DEPENDENCIES})
|
foreach (BOOST_OPENMETHOD_DEPENDENCY ${BOOST_OPENMETHOD_DEPENDENCIES})
|
||||||
if (BOOST_OPENMETHOD_DEPENDENCY MATCHES "^[ ]*Boost::([A-Za-z0-9_]+)[ ]*$")
|
if (BOOST_OPENMETHOD_DEPENDENCY MATCHES "^[ ]*Boost::([A-Za-z0-9_]+)[ ]*$")
|
||||||
list(APPEND BOOST_OPENMETHOD_INCLUDE_LIBRARIES ${CMAKE_MATCH_1})
|
list(APPEND BOOST_OPENMETHOD_INCLUDE_LIBRARIES ${CMAKE_MATCH_1})
|
||||||
endif ()
|
endif ()
|
||||||
endforeach ()
|
endforeach ()
|
||||||
|
|
||||||
# Conditional dependencies
|
# Conditional dependencies
|
||||||
|
if (BOOST_OPENMETHOD_MRDOCS_BUILD)
|
||||||
|
list(APPEND BOOST_OPENMETHOD_INCLUDE_LIBRARIES smart_ptr)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (NOT BOOST_OPENMETHOD_MRDOCS_BUILD)
|
if (NOT BOOST_OPENMETHOD_MRDOCS_BUILD)
|
||||||
if (BUILD_TESTING OR BOOST_OPENMETHOD_BUILD_TESTS)
|
if (BOOST_OPENMETHOD_BUILD_TESTS)
|
||||||
set(BOOST_OPENMETHOD_UNIT_TEST_LIBRARIES test)
|
set(BOOST_OPENMETHOD_UNIT_TEST_LIBRARIES test)
|
||||||
endif()
|
|
||||||
if (BOOST_OPENMETHOD_BUILD_EXAMPLES)
|
if (BOOST_OPENMETHOD_BUILD_EXAMPLES)
|
||||||
set(BOOST_OPENMETHOD_EXAMPLE_LIBRARIES dll)
|
set(BOOST_OPENMETHOD_EXAMPLE_LIBRARIES dll)
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Complete dependency list
|
# Complete dependency list
|
||||||
set(BOOST_INCLUDE_LIBRARIES ${BOOST_OPENMETHOD_INCLUDE_LIBRARIES} ${BOOST_OPENMETHOD_UNIT_TEST_LIBRARIES} ${BOOST_OPENMETHOD_EXAMPLE_LIBRARIES})
|
set(BOOST_INCLUDE_LIBRARIES ${BOOST_OPENMETHOD_INCLUDE_LIBRARIES} ${BOOST_OPENMETHOD_UNIT_TEST_LIBRARIES} ${BOOST_OPENMETHOD_EXAMPLE_LIBRARIES})
|
||||||
set(BOOST_EXCLUDE_LIBRARIES openmethod)
|
set(BOOST_EXCLUDE_LIBRARIES openmethod)
|
||||||
@@ -175,20 +209,15 @@ endif()
|
|||||||
# Tests
|
# Tests
|
||||||
#
|
#
|
||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
if (BUILD_TESTING OR BOOST_OPENMETHOD_BUILD_TESTS)
|
if (BOOST_OPENMETHOD_BUILD_TESTS)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
if (BOOST_OPENMETHOD_IS_ROOT)
|
if (BOOST_OPENMETHOD_IS_ROOT)
|
||||||
add_custom_target(all_with_tests ALL DEPENDS tests)
|
add_custom_target(all_with_tests ALL DEPENDS tests)
|
||||||
endif()
|
endif()
|
||||||
endif ()
|
|
||||||
|
|
||||||
#-------------------------------------------------
|
# Examples
|
||||||
#
|
if (BOOST_OPENMETHOD_BUILD_EXAMPLES)
|
||||||
# Examples
|
|
||||||
#
|
|
||||||
#-------------------------------------------------
|
|
||||||
if (BOOST_OPENMETHOD_BUILD_EXAMPLES)
|
|
||||||
enable_testing()
|
|
||||||
add_subdirectory(doc/modules/ROOT/examples)
|
add_subdirectory(doc/modules/ROOT/examples)
|
||||||
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ antora:
|
|||||||
tag: 'develop'
|
tag: 'develop'
|
||||||
variable: 'BOOST_SRC_DIR'
|
variable: 'BOOST_SRC_DIR'
|
||||||
system-env: 'BOOST_SRC_DIR'
|
system-env: 'BOOST_SRC_DIR'
|
||||||
|
- require: '@cppalliance/antora-downloads-extension'
|
||||||
|
|
||||||
asciidoc:
|
asciidoc:
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ struct Plus : Node {
|
|||||||
Plus(
|
Plus(
|
||||||
shared_virtual_ptr<const Node> left,
|
shared_virtual_ptr<const Node> left,
|
||||||
shared_virtual_ptr<const Node> right)
|
shared_virtual_ptr<const Node> right)
|
||||||
: left(left), right(right) {
|
: left(std::move(left)), right(std::move(right)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_virtual_ptr<const Node> left, right;
|
shared_virtual_ptr<const Node> left, right;
|
||||||
@@ -35,7 +35,7 @@ struct Times : Node {
|
|||||||
Times(
|
Times(
|
||||||
shared_virtual_ptr<const Node> left,
|
shared_virtual_ptr<const Node> left,
|
||||||
shared_virtual_ptr<const Node> right)
|
shared_virtual_ptr<const Node> right)
|
||||||
: left(left), right(right) {
|
: left(std::move(left)), right(std::move(right)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_virtual_ptr<const Node> left, right;
|
shared_virtual_ptr<const Node> left, right;
|
||||||
|
|||||||
@@ -3,146 +3,153 @@
|
|||||||
// See accompanying file LICENSE_1_0.txt
|
// See accompanying file LICENSE_1_0.txt
|
||||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
// https://godbolt.org/z/r6o4f171r
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
|
|
||||||
#include <boost/openmethod.hpp>
|
#include <boost/openmethod.hpp>
|
||||||
|
#include <boost/openmethod/policies/static_rtti.hpp>
|
||||||
#include <boost/openmethod/initialize.hpp>
|
#include <boost/openmethod/initialize.hpp>
|
||||||
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
|
||||||
|
|
||||||
using std::make_shared;
|
|
||||||
using std::shared_ptr;
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
using boost::openmethod::make_shared_virtual;
|
using namespace boost::openmethod::aliases;
|
||||||
using boost::openmethod::shared_virtual_ptr;
|
|
||||||
using boost::openmethod::virtual_ptr;
|
|
||||||
|
|
||||||
struct matrix {
|
struct abstract {
|
||||||
virtual ~matrix() {
|
int ref_count = 0;
|
||||||
}
|
|
||||||
virtual auto at(int row, int col) const -> double = 0;
|
|
||||||
// ...
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dense_matrix : matrix {
|
struct registry
|
||||||
virtual auto at(int /*row*/, int /*col*/) const -> double {
|
: boost::openmethod::registry<boost::openmethod::policies::static_rtti> {};
|
||||||
return 0;
|
|
||||||
|
template<class Rep>
|
||||||
|
using matrix_ptr = boost::openmethod::virtual_ptr<Rep, registry>;
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD(destroy, (matrix_ptr<abstract>), void, registry);
|
||||||
|
|
||||||
|
class matrix {
|
||||||
|
matrix_ptr<abstract> rep_;
|
||||||
|
|
||||||
|
explicit matrix(matrix_ptr<abstract> 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<abstract> {
|
||||||
|
return rep_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Rep, class... Args>
|
||||||
|
static matrix make(Args&&... args) {
|
||||||
|
return matrix(
|
||||||
|
boost::openmethod::final_virtual_ptr<registry>(
|
||||||
|
*new Rep(std::forward<Args>(args)...)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct diagonal_matrix : matrix {
|
struct dense : abstract {
|
||||||
virtual auto at(int /*row*/, int /*col*/) const -> double {
|
static constexpr const char* type = "dense";
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BOOST_OPENMETHOD_CLASSES(matrix, dense_matrix, diagonal_matrix);
|
BOOST_OPENMETHOD_OVERRIDE(destroy, (matrix_ptr<dense> rep), void) {
|
||||||
|
delete rep.get();
|
||||||
BOOST_OPENMETHOD(to_json, (virtual_ptr<const matrix>), string);
|
|
||||||
|
|
||||||
BOOST_OPENMETHOD_OVERRIDE(to_json, (virtual_ptr<const dense_matrix>), string) {
|
|
||||||
return "json for dense matrix...";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_OPENMETHOD_OVERRIDE(
|
struct diagonal : abstract {
|
||||||
to_json, (virtual_ptr<const diagonal_matrix>), string) {
|
static constexpr const char* type = "diagonal";
|
||||||
return "json for diagonal matrix...";
|
};
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(destroy, (matrix_ptr<diagonal> rep), void) {
|
||||||
|
delete rep.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_CLASSES(abstract, dense, diagonal, registry);
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// matrix * matrix
|
// matrix * matrix
|
||||||
|
|
||||||
BOOST_OPENMETHOD(
|
BOOST_OPENMETHOD(
|
||||||
times, (shared_virtual_ptr<const matrix>, shared_virtual_ptr<const matrix>),
|
times, (matrix_ptr<abstract>, matrix_ptr<abstract>), matrix, registry);
|
||||||
shared_virtual_ptr<const matrix>);
|
|
||||||
|
|
||||||
// catch-all matrix * matrix -> dense_matrix
|
// catch-all matrix * matrix -> dense
|
||||||
BOOST_OPENMETHOD_OVERRIDE(
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
times,
|
times, (matrix_ptr<abstract> /*a*/, matrix_ptr<abstract> /*b*/), matrix) {
|
||||||
(shared_virtual_ptr<const matrix> /*a*/,
|
return matrix::make<dense>();
|
||||||
shared_virtual_ptr<const matrix> /*b*/),
|
|
||||||
shared_virtual_ptr<const dense_matrix>) {
|
|
||||||
return make_shared<const dense_matrix>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// diagonal_matrix * diagonal_matrix -> diagonal_matrix
|
// diagonal * diagonal -> diagonal
|
||||||
BOOST_OPENMETHOD_OVERRIDE(
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
times,
|
times, (matrix_ptr<diagonal> /*a*/, matrix_ptr<diagonal> /*b*/), matrix) {
|
||||||
(shared_virtual_ptr<const diagonal_matrix> /*a*/,
|
return matrix::make<diagonal>();
|
||||||
shared_virtual_ptr<const diagonal_matrix> /*b*/),
|
|
||||||
shared_virtual_ptr<const diagonal_matrix>) {
|
|
||||||
return make_shared_virtual<diagonal_matrix>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto operator*(shared_ptr<const matrix> a, shared_ptr<const matrix> b)
|
inline auto operator*(matrix a, matrix b) -> matrix {
|
||||||
-> shared_virtual_ptr<const matrix> {
|
return times(a.rep(), b.rep());
|
||||||
return times(a, b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// scalar * matrix
|
// scalar * matrix
|
||||||
|
|
||||||
BOOST_OPENMETHOD(
|
BOOST_OPENMETHOD(times, (double, matrix_ptr<abstract>), matrix, registry);
|
||||||
times, (double, shared_virtual_ptr<const matrix>),
|
|
||||||
shared_virtual_ptr<const matrix>);
|
|
||||||
|
|
||||||
// catch-all matrix * scalar -> dense_matrix
|
// catch-all matrix * scalar -> dense
|
||||||
BOOST_OPENMETHOD_OVERRIDE(
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
times, (double /*a*/, shared_virtual_ptr<const matrix> /*b*/),
|
times, (double /*a*/, matrix_ptr<abstract> /*b*/), matrix) {
|
||||||
shared_virtual_ptr<const dense_matrix>) {
|
return matrix::make<dense>();
|
||||||
return make_shared_virtual<dense_matrix>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_OPENMETHOD_OVERRIDE(
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
times, (double /*a*/, shared_virtual_ptr<const diagonal_matrix> /*b*/),
|
times, (double /*a*/, matrix_ptr<diagonal> /*b*/), matrix) {
|
||||||
shared_virtual_ptr<const diagonal_matrix>) {
|
return matrix::make<diagonal>();
|
||||||
return make_shared_virtual<diagonal_matrix>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// matrix * scalar
|
// matrix * scalar
|
||||||
|
|
||||||
// just swap
|
// just swap
|
||||||
inline auto times(shared_virtual_ptr<const matrix> a, double b)
|
inline auto times(matrix_ptr<abstract> a, double b) -> matrix {
|
||||||
-> shared_virtual_ptr<const matrix> {
|
|
||||||
return times(b, a);
|
return times(b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// main
|
// main
|
||||||
|
|
||||||
#define check(expr) \
|
BOOST_OPENMETHOD(write, (matrix_ptr<abstract>), string, registry);
|
||||||
{ \
|
|
||||||
if (!(expr)) { \
|
inline auto operator<<(std::ostream& os, matrix a) -> std::ostream& {
|
||||||
cerr << #expr << " failed\n"; \
|
return os << write(a.rep());
|
||||||
} \
|
}
|
||||||
}
|
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(write, (matrix_ptr<dense>), string) {
|
||||||
|
return "a dense matrix";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(write, (matrix_ptr<diagonal>), string) {
|
||||||
|
return "a diagonal matrix";
|
||||||
|
}
|
||||||
|
|
||||||
auto main() -> int {
|
auto main() -> int {
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::cout;
|
using std::cout;
|
||||||
|
|
||||||
boost::openmethod::initialize();
|
boost::openmethod::initialize<registry>();
|
||||||
|
|
||||||
shared_ptr<const matrix> a = make_shared<dense_matrix>();
|
matrix a = matrix::make<dense>();
|
||||||
shared_ptr<const matrix> b = make_shared<diagonal_matrix>();
|
matrix b = matrix::make<diagonal>();
|
||||||
double s = 1;
|
double s = 1;
|
||||||
|
|
||||||
#ifdef BOOST_CLANG
|
cout << a << "\n";
|
||||||
#pragma clang diagnostic ignored "-Wpotentially-evaluated-expression"
|
cout << b << "\n";
|
||||||
#endif
|
|
||||||
|
|
||||||
check(typeid(*times(a, a)) == typeid(dense_matrix));
|
|
||||||
check(typeid(*times(a, b)) == typeid(dense_matrix));
|
|
||||||
check(typeid(*times(b, b)) == typeid(diagonal_matrix));
|
|
||||||
check(typeid(*times(s, a)) == typeid(dense_matrix));
|
|
||||||
check(typeid(*times(s, b)) == typeid(diagonal_matrix));
|
|
||||||
|
|
||||||
cout << to_json(*a) << "\n"; // json for dense matrix
|
|
||||||
cout << to_json(*b) << "\n"; // json for diagonal matrix
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
150
doc/modules/ROOT/examples/matrix_intrusive_vptr.cpp
Normal file
150
doc/modules/ROOT/examples/matrix_intrusive_vptr.cpp
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
// 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)
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <typeinfo>
|
||||||
|
|
||||||
|
#include <boost/openmethod.hpp>
|
||||||
|
#include <boost/openmethod/initialize.hpp>
|
||||||
|
#include <boost/openmethod/interop/boost_intrusive_ptr.hpp>
|
||||||
|
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
using namespace boost::openmethod::aliases;
|
||||||
|
|
||||||
|
struct abstract {
|
||||||
|
virtual ~abstract() {
|
||||||
|
}
|
||||||
|
|
||||||
|
int ref_count = 0;
|
||||||
|
|
||||||
|
friend void intrusive_ptr_add_ref(abstract* p) {
|
||||||
|
++p->ref_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend void intrusive_ptr_release(abstract* p) {
|
||||||
|
if (--p->ref_count == 0) {
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Rep>
|
||||||
|
using matrix_ptr = boost::openmethod::boost_intrusive_virtual_ptr<Rep>;
|
||||||
|
|
||||||
|
class matrix {
|
||||||
|
matrix_ptr<abstract> rep_;
|
||||||
|
|
||||||
|
explicit matrix(matrix_ptr<abstract> rep) : rep_(rep) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
matrix(const matrix&) = default;
|
||||||
|
matrix& operator=(const matrix&) = default;
|
||||||
|
|
||||||
|
auto rep() const -> matrix_ptr<abstract> {
|
||||||
|
return rep_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Rep>
|
||||||
|
static matrix make() {
|
||||||
|
return matrix(boost::openmethod::make_boost_intrusive_virtual<Rep>());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dense : abstract {};
|
||||||
|
|
||||||
|
struct diagonal : abstract {};
|
||||||
|
|
||||||
|
using namespace boost::openmethod::aliases;
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_CLASSES(abstract, dense, diagonal);
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD(to_str, (matrix_ptr<abstract>), string);
|
||||||
|
|
||||||
|
inline auto operator<<(std::ostream& os, matrix a) -> std::ostream& {
|
||||||
|
return os << to_str(a.rep());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(to_str, (matrix_ptr<dense>), string) {
|
||||||
|
return "a dense matrix";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(to_str, (matrix_ptr<diagonal>), string) {
|
||||||
|
return "a diagonal matrix";
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// matrix * matrix
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD(times, (matrix_ptr<abstract>, matrix_ptr<abstract>), matrix);
|
||||||
|
|
||||||
|
// catch-all matrix * matrix -> dense
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
|
times, (matrix_ptr<abstract> /*a*/, matrix_ptr<abstract> /*b*/), matrix) {
|
||||||
|
return matrix::make<dense>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// diagonal * diagonal -> diagonal
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
|
times, (matrix_ptr<diagonal> /*a*/, matrix_ptr<diagonal> /*b*/), matrix) {
|
||||||
|
return matrix::make<diagonal>();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto operator*(matrix a, matrix b) -> matrix {
|
||||||
|
return times(a.rep(), b.rep());
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// scalar * matrix
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD(times, (double, matrix_ptr<abstract>), matrix);
|
||||||
|
|
||||||
|
// catch-all matrix * scalar -> dense
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
|
times, (double /*a*/, matrix_ptr<abstract> /*b*/), matrix) {
|
||||||
|
return matrix::make<dense>();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
|
times, (double /*a*/, matrix_ptr<diagonal> /*b*/), matrix) {
|
||||||
|
return matrix::make<diagonal>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// matrix * scalar
|
||||||
|
|
||||||
|
// just swap
|
||||||
|
inline auto times(matrix_ptr<abstract> a, double b) -> matrix {
|
||||||
|
return times(b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// main
|
||||||
|
|
||||||
|
#define check(expr) \
|
||||||
|
{ \
|
||||||
|
if (!(expr)) { \
|
||||||
|
cerr << #expr << " failed\n"; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
auto main() -> int {
|
||||||
|
using std::cerr;
|
||||||
|
using std::cout;
|
||||||
|
|
||||||
|
boost::openmethod::initialize();
|
||||||
|
|
||||||
|
matrix a = matrix::make<dense>();
|
||||||
|
matrix b = matrix::make<diagonal>();
|
||||||
|
double s = 1;
|
||||||
|
|
||||||
|
cout << a << "\n";
|
||||||
|
cout << b << "\n";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -14,5 +14,5 @@ BOOST_OPENMETHOD_OVERRIDE(
|
|||||||
return 5000.0;
|
return 5000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_OPENMETHOD_CLASSES(Employee)
|
BOOST_OPENMETHOD_CLASSES(Employee);
|
||||||
// end::content[]
|
// end::content[]
|
||||||
|
|||||||
@@ -14,6 +14,6 @@ BOOST_OPENMETHOD_OVERRIDE(
|
|||||||
return next(emp) + emp->sales * 0.05; // base + commission
|
return next(emp) + emp->sales * 0.05; // base + commission
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)
|
BOOST_OPENMETHOD_CLASSES(Employee, Salesman);
|
||||||
|
|
||||||
// end::content[]
|
// end::content[]
|
||||||
|
|||||||
@@ -12,5 +12,5 @@ BOOST_OPENMETHOD_DEFINE_OVERRIDER(
|
|||||||
return 5000.0;
|
return 5000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_OPENMETHOD_CLASSES(Employee)
|
BOOST_OPENMETHOD_CLASSES(Employee);
|
||||||
// end::content[]
|
// end::content[]
|
||||||
|
|||||||
@@ -16,4 +16,4 @@ BOOST_OPENMETHOD_OVERRIDE(
|
|||||||
}
|
}
|
||||||
// end::content[]
|
// end::content[]
|
||||||
|
|
||||||
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)
|
BOOST_OPENMETHOD_CLASSES(Employee, Salesman);
|
||||||
|
|||||||
@@ -7,5 +7,5 @@
|
|||||||
#include "roles.hpp"
|
#include "roles.hpp"
|
||||||
#include <boost/openmethod.hpp>
|
#include <boost/openmethod.hpp>
|
||||||
|
|
||||||
BOOST_OPENMETHOD_CLASSES(Employee)
|
BOOST_OPENMETHOD_CLASSES(Employee);
|
||||||
// end::content[]
|
// end::content[]
|
||||||
|
|||||||
@@ -16,4 +16,4 @@ BOOST_OPENMETHOD_OVERRIDE(
|
|||||||
}
|
}
|
||||||
// end::content[]
|
// end::content[]
|
||||||
|
|
||||||
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)
|
BOOST_OPENMETHOD_CLASSES(Employee, Salesman);
|
||||||
|
|||||||
@@ -7,5 +7,5 @@
|
|||||||
#include "roles.hpp"
|
#include "roles.hpp"
|
||||||
#include <boost/openmethod.hpp>
|
#include <boost/openmethod.hpp>
|
||||||
|
|
||||||
BOOST_OPENMETHOD_CLASSES(employees::Employee)
|
BOOST_OPENMETHOD_CLASSES(employees::Employee);
|
||||||
// end::content[]
|
// end::content[]
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ BOOST_OPENMETHOD_OVERRIDE(
|
|||||||
emp->sales * 0.05; // base + commission
|
emp->sales * 0.05; // base + commission
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_OPENMETHOD_CLASSES(employees::Employee, Salesman)
|
BOOST_OPENMETHOD_CLASSES(employees::Employee, Salesman);
|
||||||
|
|
||||||
} // namespace sales
|
} // namespace sales
|
||||||
// end::content[]
|
// end::content[]
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ BOOST_OPENMETHOD_OVERRIDE(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ...and let's not forget to register the classes
|
// ...and let's not forget to register the classes
|
||||||
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)
|
BOOST_OPENMETHOD_CLASSES(Employee, Salesman);
|
||||||
// end::overriders[]
|
// end::overriders[]
|
||||||
|
|
||||||
// tag::main[]
|
// tag::main[]
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ BOOST_OPENMETHOD_OVERRIDE(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ...and let's not forget to register the classes
|
// ...and let's not forget to register the classes
|
||||||
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)
|
BOOST_OPENMETHOD_CLASSES(Employee, Salesman);
|
||||||
// end::overriders[]
|
// end::overriders[]
|
||||||
|
|
||||||
// tag::main[]
|
// tag::main[]
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ add_compile_definitions(BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS)
|
|||||||
|
|
||||||
add_library(boost_openmethod-shared SHARED extensions.cpp)
|
add_library(boost_openmethod-shared SHARED extensions.cpp)
|
||||||
target_link_libraries(boost_openmethod-shared Boost::openmethod)
|
target_link_libraries(boost_openmethod-shared Boost::openmethod)
|
||||||
set_target_properties(boost_openmethod-shared PROPERTIES ENABLE_EXPORTS ON)
|
set_target_properties(boost_openmethod-shared PROPERTIES
|
||||||
|
ENABLE_EXPORTS ON
|
||||||
|
OUTPUT_NAME shared
|
||||||
|
)
|
||||||
|
|
||||||
add_executable(boost_openmethod-static static_main.cpp)
|
add_executable(boost_openmethod-static static_main.cpp)
|
||||||
target_link_libraries(boost_openmethod-static Boost::openmethod Boost::dll boost_openmethod-shared)
|
target_link_libraries(boost_openmethod-static Boost::openmethod Boost::dll boost_openmethod-shared)
|
||||||
@@ -36,7 +39,10 @@ add_library(boost_openmethod-indirect_shared SHARED indirect_extensions.cpp)
|
|||||||
target_compile_definitions(
|
target_compile_definitions(
|
||||||
boost_openmethod-indirect_shared PUBLIC BOOST_OPENMETHOD_DEFAULT_REGISTRY=indirect_registry)
|
boost_openmethod-indirect_shared PUBLIC BOOST_OPENMETHOD_DEFAULT_REGISTRY=indirect_registry)
|
||||||
target_link_libraries(boost_openmethod-indirect_shared PRIVATE Boost::openmethod Boost::dll)
|
target_link_libraries(boost_openmethod-indirect_shared PRIVATE Boost::openmethod Boost::dll)
|
||||||
set_target_properties(boost_openmethod-indirect_shared PROPERTIES ENABLE_EXPORTS ON)
|
set_target_properties(boost_openmethod-indirect_shared PROPERTIES
|
||||||
|
ENABLE_EXPORTS ON
|
||||||
|
OUTPUT_NAME indirect_shared
|
||||||
|
)
|
||||||
|
|
||||||
add_executable(boost_openmethod-indirect indirect_main.cpp)
|
add_executable(boost_openmethod-indirect indirect_main.cpp)
|
||||||
target_compile_definitions(
|
target_compile_definitions(
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ An _open-method_ is a free-standing function that has one or more _virtual_
|
|||||||
_parameters_. When it is called, it forwards to an _overrider_ selected from a
|
_parameters_. When it is called, it forwards to an _overrider_ selected from a
|
||||||
set by examining the dynamic types of the virtual parameters.
|
set by examining the dynamic types of the virtual parameters.
|
||||||
|
|
||||||
If this sounds like a virtual function, that's because because an open-method
|
If this sounds like a virtual function, that's because an open-method
|
||||||
with one virtual parameter is equivalent to a virtual function - with one big
|
with one virtual parameter is equivalent to a virtual function - with one big
|
||||||
difference: it exists outside of classes.
|
difference: it exists outside of classes.
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,12 @@ Provides a `virtual_traits` specialization that makes it possible to use a
|
|||||||
Provides a `virtual_traits` specialization that makes it possible to use a
|
Provides a `virtual_traits` specialization that makes it possible to use a
|
||||||
`std::unique_ptr` in place of a raw pointer or reference in virtual parameters.
|
`std::unique_ptr` in place of a raw pointer or reference in virtual parameters.
|
||||||
|
|
||||||
|
[#boost_intrusive_ptr]
|
||||||
|
### link:{{BASE_URL}}/include/boost/openmethod/interop/boost_intrusive_ptr.hpp[<boost/openmethod/interop/boost_intrusive_ptr.hpp>]
|
||||||
|
|
||||||
|
Provides a `virtual_traits` specialization that makes it possible to use a
|
||||||
|
`boost::intrusive_ptr` in place of a raw pointer or reference in virtual parameters.
|
||||||
|
|
||||||
*The headers below are for advanced use*.
|
*The headers below are for advanced use*.
|
||||||
|
|
||||||
## Pre-Core Headers
|
## Pre-Core Headers
|
||||||
|
|||||||
7
doc/package-lock.json
generated
7
doc/package-lock.json
generated
@@ -10,6 +10,7 @@
|
|||||||
"@asciidoctor/tabs": "^1.0.0-beta.6",
|
"@asciidoctor/tabs": "^1.0.0-beta.6",
|
||||||
"@cppalliance/antora-cpp-reference-extension": "^0.1.0",
|
"@cppalliance/antora-cpp-reference-extension": "^0.1.0",
|
||||||
"@cppalliance/antora-cpp-tagfiles-extension": "^0.1.0",
|
"@cppalliance/antora-cpp-tagfiles-extension": "^0.1.0",
|
||||||
|
"@cppalliance/antora-downloads-extension": "^0.0.2",
|
||||||
"@cppalliance/asciidoctor-boost-links": "^0.0.2"
|
"@cppalliance/asciidoctor-boost-links": "^0.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -420,6 +421,12 @@
|
|||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@cppalliance/antora-downloads-extension": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@cppalliance/antora-downloads-extension/-/antora-downloads-extension-0.0.2.tgz",
|
||||||
|
"integrity": "sha512-2wXahlvRz9J75ZSfzDeP4XpIZiqIm+w/YjmCWJxFPp6oWgP7e8f6ps7HqdtHNGxnK5mG38OjiCFdHjmHYfgbDA==",
|
||||||
|
"license": "BSL-1.0"
|
||||||
|
},
|
||||||
"node_modules/@cppalliance/asciidoctor-boost-links": {
|
"node_modules/@cppalliance/asciidoctor-boost-links": {
|
||||||
"version": "0.0.2",
|
"version": "0.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@cppalliance/asciidoctor-boost-links/-/asciidoctor-boost-links-0.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@cppalliance/asciidoctor-boost-links/-/asciidoctor-boost-links-0.0.2.tgz",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
"@asciidoctor/tabs": "^1.0.0-beta.6",
|
"@asciidoctor/tabs": "^1.0.0-beta.6",
|
||||||
"@cppalliance/antora-cpp-reference-extension": "^0.1.0",
|
"@cppalliance/antora-cpp-reference-extension": "^0.1.0",
|
||||||
"@cppalliance/antora-cpp-tagfiles-extension": "^0.1.0",
|
"@cppalliance/antora-cpp-tagfiles-extension": "^0.1.0",
|
||||||
|
"@cppalliance/antora-downloads-extension": "^0.0.2",
|
||||||
"@cppalliance/asciidoctor-boost-links": "^0.0.2"
|
"@cppalliance/asciidoctor-boost-links": "^0.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -359,6 +359,7 @@ struct use_class_aux<Registry, mp11::mp_list<Class, Bases...>>
|
|||||||
resolve_type_ids();
|
resolve_type_ids();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// coverity[uninit] - zero-initialized static storage
|
||||||
Registry::classes.push_back(*this);
|
Registry::classes.push_back(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2403,6 +2404,8 @@ method<Id, ReturnType(Parameters...), Registry>::method() {
|
|||||||
this->not_implemented = reinterpret_cast<void (*)()>(fn_not_implemented);
|
this->not_implemented = reinterpret_cast<void (*)()>(fn_not_implemented);
|
||||||
this->ambiguous = reinterpret_cast<void (*)()>(fn_ambiguous);
|
this->ambiguous = reinterpret_cast<void (*)()>(fn_ambiguous);
|
||||||
|
|
||||||
|
// zero-initalized static variable
|
||||||
|
// coverity[uninit_use]
|
||||||
Registry::methods.push_back(*this);
|
Registry::methods.push_back(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2746,7 +2749,7 @@ method<Id, ReturnType(Parameters...), Registry>::override_impl<
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// zero-initalized static variable
|
// zero-initalized static variable
|
||||||
// coverity[uninit_use:FALSE]
|
// coverity[uninit_use]
|
||||||
if (overrider_info::method) {
|
if (overrider_info::method) {
|
||||||
BOOST_ASSERT(overrider_info::method == &fn);
|
BOOST_ASSERT(overrider_info::method == &fn);
|
||||||
return;
|
return;
|
||||||
@@ -2844,14 +2847,21 @@ struct VirtualTraits {
|
|||||||
|
|
||||||
//! Casts a virtual argument.
|
//! Casts a virtual argument.
|
||||||
//!
|
//!
|
||||||
//! Casts a virtual argument to the type expected by the overrider.
|
//! `cast` is responsible for passing virtual arguments from method to
|
||||||
|
//! overrider. In general, this requires some form of adjustment, because a
|
||||||
|
//! virtual parameter in the overrider usually has a different type than the
|
||||||
|
//! corresponding parameter in the method. Typically, the adjustment
|
||||||
|
//! consists of a cast, performed via `static_cast`, `dynamic_cast`, or
|
||||||
|
//! other means, depending on the type of the argument and the rtti policy
|
||||||
|
//! of the method. `cast` may return the adjusted argument by reference or
|
||||||
|
//! as a temporary value.
|
||||||
//!
|
//!
|
||||||
//! @tparam T The type of a virtual parameter of a method.
|
//! @tparam T The type of the virtual parameter in the method.
|
||||||
//! @tparam U The type of a virtual parameter of an overrider.
|
//! @tparam U The type of the virtual parameter in the overrider.
|
||||||
//! @param arg The argument passed to a method call.
|
//! @param arg The argument passed to the method call.
|
||||||
//! @return A reference to the argument, cast to `U`.
|
//! @return A value that can be passed as a U.
|
||||||
template<typename U>
|
template<typename U>
|
||||||
static auto cast(T arg) -> U;
|
static auto cast(T arg) -> detail::unspecified;
|
||||||
|
|
||||||
//! Rebind to a another class (smart pointers only).
|
//! Rebind to a another class (smart pointers only).
|
||||||
//!
|
//!
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
namespace boost::openmethod {
|
namespace boost::openmethod {
|
||||||
|
|
||||||
|
|||||||
@@ -127,10 +127,11 @@ class static_list {
|
|||||||
|
|
||||||
friend auto operator==(const iterator& a, const iterator& b) -> bool {
|
friend auto operator==(const iterator& a, const iterator& b) -> bool {
|
||||||
return a.ptr == b.ptr;
|
return a.ptr == b.ptr;
|
||||||
};
|
}
|
||||||
|
|
||||||
friend auto operator!=(const iterator& a, const iterator& b) -> bool {
|
friend auto operator!=(const iterator& a, const iterator& b) -> bool {
|
||||||
return a.ptr != b.ptr;
|
return a.ptr != b.ptr;
|
||||||
};
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T* ptr;
|
T* ptr;
|
||||||
@@ -179,11 +180,12 @@ class static_list {
|
|||||||
friend auto
|
friend auto
|
||||||
operator==(const const_iterator& a, const const_iterator& b) -> bool {
|
operator==(const const_iterator& a, const const_iterator& b) -> bool {
|
||||||
return a.ptr == b.ptr;
|
return a.ptr == b.ptr;
|
||||||
};
|
}
|
||||||
|
|
||||||
friend auto
|
friend auto
|
||||||
operator!=(const const_iterator& a, const const_iterator& b) -> bool {
|
operator!=(const const_iterator& a, const const_iterator& b) -> bool {
|
||||||
return a.ptr != b.ptr;
|
return a.ptr != b.ptr;
|
||||||
};
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T* ptr;
|
T* ptr;
|
||||||
|
|||||||
150
include/boost/openmethod/interop/boost_intrusive_ptr.hpp
Normal file
150
include/boost/openmethod/interop/boost_intrusive_ptr.hpp
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
// 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)
|
||||||
|
|
||||||
|
#ifndef BOOST_OPENMETHOD_INTEROP_BOOST_INTRUSIVE_PTR_HPP
|
||||||
|
#define BOOST_OPENMETHOD_INTEROP_BOOST_INTRUSIVE_PTR_HPP
|
||||||
|
|
||||||
|
#include <boost/openmethod/core.hpp>
|
||||||
|
#include <boost/smart_ptr/intrusive_ptr.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace boost::openmethod {
|
||||||
|
|
||||||
|
//! Specialize virtual_traits for boost::intrusive_ptr.
|
||||||
|
//!
|
||||||
|
//! @tparam Class A class type, possibly cv-qualified.
|
||||||
|
//! @tparam Registry A @ref registry.
|
||||||
|
template<typename Class, class Registry>
|
||||||
|
struct virtual_traits<boost::intrusive_ptr<Class>, Registry> {
|
||||||
|
//! Rebind to a different element type.
|
||||||
|
//!
|
||||||
|
//! @tparam Other The new element type.
|
||||||
|
template<class Other>
|
||||||
|
using rebind = boost::intrusive_ptr<Other>;
|
||||||
|
|
||||||
|
//! `Class`, stripped from cv-qualifiers.
|
||||||
|
using virtual_type = std::remove_cv_t<Class>;
|
||||||
|
|
||||||
|
//! Return a reference to a non-modifiable `Class` object.
|
||||||
|
//! @param arg A reference to a `boost::intrusive_ptr<Class>`.
|
||||||
|
//! @return A reference to the object pointed to.
|
||||||
|
static auto peek(const boost::intrusive_ptr<Class>& arg) -> const Class& {
|
||||||
|
return *arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Cast method argument to overrider argument.
|
||||||
|
//!
|
||||||
|
//! Cast a `boost::intrusive_ptr` to a `boost::intrusive_ptr` to a derived
|
||||||
|
//! class, using a static cast if possible, and a dynamic cast otherwise.
|
||||||
|
//!
|
||||||
|
//! @tparam OverriderType The type required by the overrider (a
|
||||||
|
//! `boost::intrusive_ptr`).
|
||||||
|
//! @param obj The method's argument..
|
||||||
|
//! @return A `boost::intrusive_ptr` _value_.
|
||||||
|
template<class OverriderType>
|
||||||
|
static auto cast(const boost::intrusive_ptr<Class>& obj) {
|
||||||
|
using element_type = typename OverriderType::element_type;
|
||||||
|
|
||||||
|
if constexpr (detail::requires_dynamic_cast<Class*, element_type*>) {
|
||||||
|
// make it work with custom RTTI
|
||||||
|
return OverriderType(
|
||||||
|
&Registry::rtti::template dynamic_cast_ref<element_type&>(
|
||||||
|
*obj));
|
||||||
|
} else {
|
||||||
|
return boost::static_pointer_cast<element_type>(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Specialize virtual_traits for const boost::intrusive_ptr&.
|
||||||
|
//!
|
||||||
|
//! @tparam Class A class type, possibly cv-qualified.
|
||||||
|
//! @tparam Registry A @ref registry.
|
||||||
|
template<class Class, class Registry>
|
||||||
|
struct virtual_traits<const boost::intrusive_ptr<Class>&, Registry> {
|
||||||
|
public:
|
||||||
|
//! Rebind to a different element type.
|
||||||
|
//!
|
||||||
|
//! @tparam Other The new element type.
|
||||||
|
template<class Other>
|
||||||
|
using rebind = boost::intrusive_ptr<Other>;
|
||||||
|
|
||||||
|
//! `Class`, stripped from cv-qualifiers.
|
||||||
|
using virtual_type = std::remove_cv_t<Class>;
|
||||||
|
|
||||||
|
//! Return a reference to a non-modifiable `Class` object.
|
||||||
|
//! @param arg A reference to a `boost::intrusive_ptr<Class>`.
|
||||||
|
//! @return A reference to the object pointed to.
|
||||||
|
static auto peek(const boost::intrusive_ptr<Class>& arg) -> const Class& {
|
||||||
|
return *arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Cast method argument to overrider argument.
|
||||||
|
//!
|
||||||
|
//! Cast a `boost::intrusive_ptr` to a `boost::intrusive_ptr` to a derived
|
||||||
|
//! class, using a static cast if possible, and a dynamic cast otherwise.
|
||||||
|
//!
|
||||||
|
//! @tparam OverriderType The type required by the overrider (a `const
|
||||||
|
//! boost::intrusive_ptr&`).
|
||||||
|
//! @param obj The method's argument..
|
||||||
|
//! @return A `boost::intrusive_ptr` _value_.
|
||||||
|
template<class OverriderType>
|
||||||
|
static decltype(auto) cast(const boost::intrusive_ptr<Class>& obj) {
|
||||||
|
if constexpr (std::is_same_v<
|
||||||
|
OverriderType, const boost::intrusive_ptr<Class>&>) {
|
||||||
|
return obj;
|
||||||
|
} else {
|
||||||
|
using element_type =
|
||||||
|
typename std::remove_reference_t<OverriderType>::element_type;
|
||||||
|
|
||||||
|
if constexpr (detail::requires_dynamic_cast<
|
||||||
|
Class*, element_type*>) {
|
||||||
|
// make it work with custom RTTI
|
||||||
|
return std::remove_const_t<
|
||||||
|
std::remove_reference_t<OverriderType>>(
|
||||||
|
&Registry::rtti::template dynamic_cast_ref<element_type&>(
|
||||||
|
*obj));
|
||||||
|
} else {
|
||||||
|
return boost::static_pointer_cast<element_type>(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Alias for a `virtual_ptr<boost::intrusive_ptr<T>>`.
|
||||||
|
template<class Class, class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
|
||||||
|
using boost_intrusive_virtual_ptr =
|
||||||
|
virtual_ptr<boost::intrusive_ptr<Class>, Registry>;
|
||||||
|
|
||||||
|
//! Create a new object and return a `boost_intrusive_virtual_ptr` to it.
|
||||||
|
//!
|
||||||
|
//! Create an object using `std::make_shared`, and return a @ref
|
||||||
|
//! boost_intrusive_virtual_ptr pointing to it. Since the exact class of the
|
||||||
|
//! object is known, the `virtual_ptr` is created using @ref final_virtual_ptr.
|
||||||
|
//!
|
||||||
|
//! `Class` is _not_ required to be a polymorphic class.
|
||||||
|
//!
|
||||||
|
//! @tparam Class The class of the object to create.
|
||||||
|
//! @tparam Registry A @ref registry.
|
||||||
|
//! @tparam T Types of the arguments to pass to the constructor of `Class`.
|
||||||
|
//! @param args Arguments to pass to the constructor of `Class`.
|
||||||
|
//! @return A `boost_intrusive_virtual_ptr<Class, Registry>` pointing to a newly
|
||||||
|
//! created object of type `Class`.
|
||||||
|
template<
|
||||||
|
class Class, class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY,
|
||||||
|
typename... T>
|
||||||
|
inline auto make_boost_intrusive_virtual(T&&... args) {
|
||||||
|
return final_virtual_ptr<Registry>(intrusive_ptr<Class>(
|
||||||
|
new std::remove_cv_t<Class>(std::forward<T>(args)...)));
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace aliases {
|
||||||
|
using boost::openmethod::boost_intrusive_virtual_ptr;
|
||||||
|
using boost::openmethod::make_boost_intrusive_virtual;
|
||||||
|
} // namespace aliases
|
||||||
|
|
||||||
|
} // namespace boost::openmethod
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -167,7 +167,11 @@ struct virtual_traits<const std::shared_ptr<Class>&, Registry> {
|
|||||||
//! @return A `std::shared_ptr` to the same object, cast to
|
//! @return A `std::shared_ptr` to the same object, cast to
|
||||||
//! `Derived::element_type`.
|
//! `Derived::element_type`.
|
||||||
template<class Other>
|
template<class Other>
|
||||||
static auto cast(const std::shared_ptr<Class>& obj) {
|
static decltype(auto) cast(const std::shared_ptr<Class>& obj) {
|
||||||
|
if constexpr (std::is_same_v<Other, const std::shared_ptr<Class>&>) {
|
||||||
|
// avoid unnecessary copy
|
||||||
|
return obj;
|
||||||
|
} else {
|
||||||
using namespace boost::openmethod::detail;
|
using namespace boost::openmethod::detail;
|
||||||
|
|
||||||
if constexpr (requires_dynamic_cast<Class*, Other>) {
|
if constexpr (requires_dynamic_cast<Class*, Other>) {
|
||||||
@@ -178,6 +182,7 @@ struct virtual_traits<const std::shared_ptr<Class>&, Registry> {
|
|||||||
typename shared_ptr_cast_traits<Other>::virtual_type>(obj);
|
typename shared_ptr_cast_traits<Other>::virtual_type>(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Alias for a `virtual_ptr<std::shared_ptr<T>>`.
|
//! Alias for a `virtual_ptr<std::shared_ptr<T>>`.
|
||||||
|
|||||||
@@ -43,10 +43,12 @@ struct virtual_traits<std::unique_ptr<Class>, Registry> {
|
|||||||
if constexpr (detail::requires_dynamic_cast<Class&, Derived&>) {
|
if constexpr (detail::requires_dynamic_cast<Class&, Derived&>) {
|
||||||
auto p = &Registry::rtti::template dynamic_cast_ref<
|
auto p = &Registry::rtti::template dynamic_cast_ref<
|
||||||
typename Derived::element_type&>(*ptr);
|
typename Derived::element_type&>(*ptr);
|
||||||
|
// coverity[alloc_fn]
|
||||||
ptr.release();
|
ptr.release();
|
||||||
return Derived(p);
|
return Derived(p);
|
||||||
} else {
|
} else {
|
||||||
auto p = &static_cast<typename Derived::element_type&>(*ptr);
|
auto p = &static_cast<typename Derived::element_type&>(*ptr);
|
||||||
|
// coverity[alloc_fn]
|
||||||
ptr.release();
|
ptr.release();
|
||||||
return Derived(p);
|
return Derived(p);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,8 +62,6 @@ struct va_args<ReturnType> {
|
|||||||
::boost::openmethod::detail::va_args<__VA_ARGS__>::registry>
|
::boost::openmethod::detail::va_args<__VA_ARGS__>::registry>
|
||||||
|
|
||||||
#define BOOST_OPENMETHOD(NAME, ARGS, ...) \
|
#define BOOST_OPENMETHOD(NAME, ARGS, ...) \
|
||||||
template<typename...> \
|
|
||||||
struct BOOST_OPENMETHOD_OVERRIDERS(NAME); \
|
|
||||||
struct BOOST_OPENMETHOD_ID(NAME); \
|
struct BOOST_OPENMETHOD_ID(NAME); \
|
||||||
template<typename... ForwarderParameters> \
|
template<typename... ForwarderParameters> \
|
||||||
typename ::boost::openmethod::detail::enable_forwarder< \
|
typename ::boost::openmethod::detail::enable_forwarder< \
|
||||||
@@ -79,7 +77,9 @@ struct va_args<ReturnType> {
|
|||||||
ForwarderParameters...>::type { \
|
ForwarderParameters...>::type { \
|
||||||
return BOOST_OPENMETHOD_TYPE(NAME, ARGS, __VA_ARGS__)::fn( \
|
return BOOST_OPENMETHOD_TYPE(NAME, ARGS, __VA_ARGS__)::fn( \
|
||||||
std::forward<ForwarderParameters>(args)...); \
|
std::forward<ForwarderParameters>(args)...); \
|
||||||
}
|
} \
|
||||||
|
template<typename...> \
|
||||||
|
struct BOOST_OPENMETHOD_OVERRIDERS(NAME)
|
||||||
|
|
||||||
#define BOOST_OPENMETHOD_DETAIL_LOCATE_METHOD(NAME, ARGS) \
|
#define BOOST_OPENMETHOD_DETAIL_LOCATE_METHOD(NAME, ARGS) \
|
||||||
template<typename T> \
|
template<typename T> \
|
||||||
@@ -88,7 +88,7 @@ struct va_args<ReturnType> {
|
|||||||
struct boost_openmethod_detail_locate_method_aux<void(A...)> { \
|
struct boost_openmethod_detail_locate_method_aux<void(A...)> { \
|
||||||
using type = \
|
using type = \
|
||||||
decltype(BOOST_OPENMETHOD_GUIDE(NAME)(std::declval<A>()...)); \
|
decltype(BOOST_OPENMETHOD_GUIDE(NAME)(std::declval<A>()...)); \
|
||||||
};
|
}
|
||||||
|
|
||||||
#define BOOST_OPENMETHOD_DECLARE_OVERRIDER(NAME, ARGS, ...) \
|
#define BOOST_OPENMETHOD_DECLARE_OVERRIDER(NAME, ARGS, ...) \
|
||||||
template<typename...> \
|
template<typename...> \
|
||||||
@@ -136,6 +136,6 @@ struct va_args<ReturnType> {
|
|||||||
-> boost::mp11::mp_back<boost::mp11::mp_list<__VA_ARGS__>>
|
-> boost::mp11::mp_back<boost::mp11::mp_list<__VA_ARGS__>>
|
||||||
|
|
||||||
#define BOOST_OPENMETHOD_CLASSES(...) \
|
#define BOOST_OPENMETHOD_CLASSES(...) \
|
||||||
BOOST_OPENMETHOD_REGISTER(::boost::openmethod::use_classes<__VA_ARGS__>);
|
BOOST_OPENMETHOD_REGISTER(::boost::openmethod::use_classes<__VA_ARGS__>)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -94,11 +94,9 @@ struct default_error_handler : error_handler {
|
|||||||
//!
|
//!
|
||||||
//! @param new_handler the new function.
|
//! @param new_handler the new function.
|
||||||
//! @return The previous function.
|
//! @return The previous function.
|
||||||
|
// coverity[auto_causes_copy]
|
||||||
static auto set(function_type new_handler) -> function_type {
|
static auto set(function_type new_handler) -> function_type {
|
||||||
auto prev = handler;
|
return std::exchange(handler, std::move(new_handler));
|
||||||
handler = std::move(new_handler);
|
|
||||||
|
|
||||||
return prev;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! The default error handler function.
|
//! The default error handler function.
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ struct vptr_vector : vptr {
|
|||||||
} else {
|
} else {
|
||||||
detail::vptr_vector_vptrs<Registry>.clear();
|
detail::vptr_vector_vptrs<Registry>.clear();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="refresh" content="0; URL=doc/html/index.html">
|
<meta http-equiv="refresh" content="0; URL=doc/html/openmethod/index.html">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
Automatic redirection failed, please go to
|
Automatic redirection failed, please go to
|
||||||
<a href="doc/html/index.html">doc/html/index.html</a>
|
<a href="doc/html/openmethod/index.html">doc/html/openmethod/index.html</a>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"maintainers": [
|
"maintainers": [
|
||||||
"Jean-Louis Leroy"
|
"Jean-Louis Leroy"
|
||||||
],
|
],
|
||||||
"description": "Open-methods for C++17 and above.",
|
"description": "Open-methods are free-standing functions that work like virtual functions: they select the best overrider from a set, depending on the dynamic type of their arguments. This makes it possible to add polymorphic operations to existing classes, without modifying them. They make patterns like Visitor unnecessary.",
|
||||||
"category": [
|
"category": [
|
||||||
"Emulation", "Programming"
|
"Emulation", "Programming"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ template<typename... Ts>
|
|||||||
auto sstr(Ts... args) {
|
auto sstr(Ts... args) {
|
||||||
std::vector<class_*> vec{args...};
|
std::vector<class_*> vec{args...};
|
||||||
std::sort(vec.begin(), vec.end());
|
std::sort(vec.begin(), vec.end());
|
||||||
|
|
||||||
return str(vec);
|
return str(vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
168
test/test_dispatch_intrusive_ptr.cpp
Normal file
168
test/test_dispatch_intrusive_ptr.cpp
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
// 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)
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <any>
|
||||||
|
|
||||||
|
#include <boost/openmethod.hpp>
|
||||||
|
#include <boost/openmethod/interop/boost_intrusive_ptr.hpp>
|
||||||
|
#include <boost/openmethod/initialize.hpp>
|
||||||
|
#include <boost/smart_ptr/intrusive_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/intrusive_ref_counter.hpp>
|
||||||
|
|
||||||
|
#define BOOST_TEST_MODULE openmethod
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
using namespace boost::openmethod;
|
||||||
|
|
||||||
|
#define MAKE_CLASSES() \
|
||||||
|
struct Animal : boost::intrusive_ref_counter<Animal> { \
|
||||||
|
explicit Animal(std::string str) { \
|
||||||
|
name = std::move(str); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
Animal(const Animal&) = delete; \
|
||||||
|
Animal(Animal&&) = default; \
|
||||||
|
virtual ~Animal() = default; \
|
||||||
|
\
|
||||||
|
std::string name; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
struct Dog : Animal { \
|
||||||
|
using Animal::Animal; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
struct Cat : virtual Animal { \
|
||||||
|
using Animal::Animal; \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat);
|
||||||
|
|
||||||
|
namespace BOOST_OPENMETHOD_GENSYM {
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// pass virtual args by shared_ptr by value
|
||||||
|
|
||||||
|
MAKE_CLASSES();
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD(
|
||||||
|
name, (virtual_<boost::intrusive_ptr<const Animal>>), std::string);
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
|
name, (boost::intrusive_ptr<const Cat> cat), std::string) {
|
||||||
|
return cat->name + " the cat";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
|
name, (boost::intrusive_ptr<const Dog> dog), std::string) {
|
||||||
|
return dog->name + " the dog";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(intrusive_ptr_by_value) {
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
auto spot = boost::intrusive_ptr<const Dog>(new Dog("Spot"));
|
||||||
|
BOOST_TEST(name(spot) == "Spot the dog");
|
||||||
|
|
||||||
|
auto felix = boost::intrusive_ptr<const Cat>(new Cat("Felix"));
|
||||||
|
BOOST_TEST(name(felix) == "Felix the cat");
|
||||||
|
}
|
||||||
|
} // namespace BOOST_OPENMETHOD_GENSYM
|
||||||
|
|
||||||
|
namespace BOOST_OPENMETHOD_GENSYM {
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// pass virtual args by shared_ptr by const&
|
||||||
|
|
||||||
|
MAKE_CLASSES();
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD(
|
||||||
|
name, (virtual_<const boost::intrusive_ptr<const Animal>&>), std::string);
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
|
name, (const boost::intrusive_ptr<const Cat>& cat), std::string) {
|
||||||
|
return cat->name + " the cat";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
|
name, (const boost::intrusive_ptr<const Dog>& dog), std::string) {
|
||||||
|
return dog->name + " the dog";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(intrusive_ptr_by_const_ref) {
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
auto spot = boost::intrusive_ptr<const Dog>(new Dog("Spot"));
|
||||||
|
BOOST_TEST(name(spot) == "Spot the dog");
|
||||||
|
|
||||||
|
auto felix = boost::intrusive_ptr<const Cat>(new Cat("Felix"));
|
||||||
|
BOOST_TEST(name(felix) == "Felix the cat");
|
||||||
|
}
|
||||||
|
} // namespace BOOST_OPENMETHOD_GENSYM
|
||||||
|
|
||||||
|
namespace BOOST_OPENMETHOD_GENSYM {
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// virtual_ptr<intrusive_ptr> by value
|
||||||
|
|
||||||
|
MAKE_CLASSES();
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD(
|
||||||
|
name, (boost_intrusive_virtual_ptr<const Animal>), std::string);
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
|
name, (boost_intrusive_virtual_ptr<const Cat> cat), std::string) {
|
||||||
|
return cat->name + " the cat";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
|
name, (boost_intrusive_virtual_ptr<const Dog> dog), std::string) {
|
||||||
|
return dog->name + " the dog";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(intrusive_virtual_ptr_by_value) {
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
auto spot = make_boost_intrusive_virtual<const Dog>("Spot");
|
||||||
|
BOOST_TEST(name(spot) == "Spot the dog");
|
||||||
|
|
||||||
|
auto felix = make_boost_intrusive_virtual<const Cat>("Felix");
|
||||||
|
BOOST_TEST(name(felix) == "Felix the cat");
|
||||||
|
}
|
||||||
|
} // namespace BOOST_OPENMETHOD_GENSYM
|
||||||
|
|
||||||
|
namespace BOOST_OPENMETHOD_GENSYM {
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// virtual_ptr<intrusive_ptr> by const&
|
||||||
|
|
||||||
|
MAKE_CLASSES();
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD(
|
||||||
|
name, (const boost_intrusive_virtual_ptr<const Animal>&), std::string);
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
|
name, (const boost_intrusive_virtual_ptr<const Cat>& cat), std::string) {
|
||||||
|
return cat->name + " the cat";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_OVERRIDE(
|
||||||
|
name, (const boost_intrusive_virtual_ptr<const Dog>& dog), std::string) {
|
||||||
|
return dog->name + " the dog";
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(intrusive_virtual_ptr_by_const_ref) {
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
auto spot = make_boost_intrusive_virtual<const Dog>("Spot");
|
||||||
|
BOOST_TEST(name(spot) == "Spot the dog");
|
||||||
|
|
||||||
|
auto felix = make_boost_intrusive_virtual<const Cat>("Felix");
|
||||||
|
BOOST_TEST(name(felix) == "Felix the cat");
|
||||||
|
}
|
||||||
|
} // namespace BOOST_OPENMETHOD_GENSYM
|
||||||
@@ -194,6 +194,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(
|
|||||||
shared_virtual_ptr<Dog, Registry> q(std::move(p));
|
shared_virtual_ptr<Dog, Registry> q(std::move(p));
|
||||||
BOOST_TEST(q.get() == snoopy.get());
|
BOOST_TEST(q.get() == snoopy.get());
|
||||||
BOOST_TEST(q.vptr() == Registry::template static_vptr<Dog>);
|
BOOST_TEST(q.vptr() == Registry::template static_vptr<Dog>);
|
||||||
|
// coverity[use_after_move]
|
||||||
BOOST_TEST(p.get() == nullptr);
|
BOOST_TEST(p.get() == nullptr);
|
||||||
BOOST_TEST(p.vptr() == nullptr);
|
BOOST_TEST(p.vptr() == nullptr);
|
||||||
}
|
}
|
||||||
|
|||||||
445
test/test_smart_virtual_ptr_value_semantics.cpp
Normal file
445
test/test_smart_virtual_ptr_value_semantics.cpp
Normal file
@@ -0,0 +1,445 @@
|
|||||||
|
// Copyright (c) 2018-2025 Jean-Louis Leroy
|
||||||
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
|
// See accompanying file LICENSE_1_0.txt
|
||||||
|
// or q at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||||
|
#include <boost/openmethod/interop/boost_intrusive_ptr.hpp>
|
||||||
|
|
||||||
|
#define BOOST_TEST_MODULE openmethod
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
#include <boost/utility/identity_type.hpp>
|
||||||
|
|
||||||
|
#include "test_virtual_ptr_value_semantics.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#ifdef BOOST_GCC
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic ignored "-Wunused-local-typedefs"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct using_shared_ptr {
|
||||||
|
template<class Class>
|
||||||
|
using ptr = std::shared_ptr<Class>;
|
||||||
|
|
||||||
|
template<class Class>
|
||||||
|
using virtual_ptr = shared_virtual_ptr<Class>;
|
||||||
|
|
||||||
|
template<class Class, class... Args>
|
||||||
|
static decltype(auto) make(Args&&... args) {
|
||||||
|
return std::make_shared<Class>(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Class, class... Args>
|
||||||
|
static decltype(auto) make_virtual(Args&&... args) {
|
||||||
|
return make_shared_virtual<Class>(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cast_moves() {
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
ptr<Animal> animal = make<Dog>();
|
||||||
|
(void)std::static_pointer_cast<Dog>(animal);
|
||||||
|
|
||||||
|
return animal.get() == nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct using_boost_intrusive_ptr {
|
||||||
|
template<class Class>
|
||||||
|
using ptr = boost::intrusive_ptr<Class>;
|
||||||
|
|
||||||
|
template<class Class>
|
||||||
|
using virtual_ptr = boost_intrusive_virtual_ptr<Class>;
|
||||||
|
|
||||||
|
template<class Class, class... Args>
|
||||||
|
static auto make(Args&&... args) {
|
||||||
|
return boost::intrusive_ptr<Class>(
|
||||||
|
new Class(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Class, class... Args>
|
||||||
|
static auto make_virtual(Args&&... args) {
|
||||||
|
return make_boost_intrusive_virtual<Class>(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cast_moves() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using smart_pointers =
|
||||||
|
boost::mp11::mp_list<using_shared_ptr, using_boost_intrusive_ptr>;
|
||||||
|
|
||||||
|
#define USING_DECLARATIONS \
|
||||||
|
using animal_ptr = typename smart::template ptr<Animal>; \
|
||||||
|
using const_animal_ptr = typename smart::template ptr<const Animal>; \
|
||||||
|
using animal_virtual_ptr = typename smart::template virtual_ptr<Animal>; \
|
||||||
|
using const_animal_virtual_ptr = \
|
||||||
|
typename smart::template virtual_ptr<const Animal>; \
|
||||||
|
using dog_ptr = typename smart::template ptr<Dog>; \
|
||||||
|
using const_dog_ptr = typename smart::template ptr<const Dog>; \
|
||||||
|
using dog_virtual_ptr = typename smart::template virtual_ptr<Dog>; \
|
||||||
|
using const_dog_virtual_ptr = \
|
||||||
|
typename smart::template virtual_ptr<const Dog>; \
|
||||||
|
using cat_ptr = typename smart::template ptr<Cat>; \
|
||||||
|
using const_cat_ptr = typename smart::template ptr<const Cat>; \
|
||||||
|
using cat_virtual_ptr = typename smart::template virtual_ptr<Cat>; \
|
||||||
|
using const_cat_virtual_ptr = \
|
||||||
|
typename smart::template virtual_ptr<const Cat>;
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||||
|
smart_pointer_value_semantics, smart, smart_pointers) {
|
||||||
|
USING_DECLARATIONS;
|
||||||
|
|
||||||
|
static_assert(SameSmartPtr<animal_ptr, dog_ptr, default_registry>);
|
||||||
|
static_assert(
|
||||||
|
!SameSmartPtr<animal_ptr, std::unique_ptr<Dog>, default_registry>);
|
||||||
|
static_assert(
|
||||||
|
std::is_same_v<typename animal_virtual_ptr::element_type, Animal>);
|
||||||
|
static_assert(std::is_same_v<
|
||||||
|
decltype(std::declval<animal_virtual_ptr>().get()), Animal*>);
|
||||||
|
static_assert(IsSmartPtr<animal_ptr, default_registry>);
|
||||||
|
static_assert(IsSmartPtr<const_animal_ptr, default_registry>);
|
||||||
|
static_assert(
|
||||||
|
std::is_same_v<decltype(*std::declval<animal_virtual_ptr>()), Animal&>);
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
// construction and assignment from a plain pointer or reference is not
|
||||||
|
// allowed
|
||||||
|
|
||||||
|
static_assert(!construct_assign_ok<dog_virtual_ptr, Dog>);
|
||||||
|
static_assert(!construct_assign_ok<dog_virtual_ptr, Dog&&>);
|
||||||
|
static_assert(!construct_assign_ok<dog_virtual_ptr, const Dog&>);
|
||||||
|
static_assert(!construct_assign_ok<dog_virtual_ptr, const Dog*>);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// construction and assignment from plain references and pointers
|
||||||
|
|
||||||
|
{
|
||||||
|
dog_virtual_ptr p{nullptr};
|
||||||
|
BOOST_TEST(p.get() == nullptr);
|
||||||
|
BOOST_TEST(p.vptr() == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto snoopy = smart::template make<Dog>();
|
||||||
|
dog_virtual_ptr p(snoopy);
|
||||||
|
BOOST_TEST(p.get() == snoopy.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
|
||||||
|
p = *&p;
|
||||||
|
BOOST_TEST(p.get() == snoopy.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
|
||||||
|
auto hector = smart::template make<Dog>();
|
||||||
|
p = hector;
|
||||||
|
BOOST_TEST(p.get() == hector.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto snoopy = smart::template make<Dog>();
|
||||||
|
animal_virtual_ptr p(snoopy);
|
||||||
|
BOOST_TEST(p.get() == snoopy.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
|
||||||
|
auto felix = smart::template make<Cat>();
|
||||||
|
p = felix;
|
||||||
|
BOOST_TEST(p.get() == felix.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Cat>);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto snoopy = smart::template make<const Dog>();
|
||||||
|
const_dog_virtual_ptr p(snoopy);
|
||||||
|
BOOST_TEST(p.get() == snoopy.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
|
||||||
|
auto hector = smart::template make<const Dog>();
|
||||||
|
p = hector;
|
||||||
|
BOOST_TEST(p.get() == hector.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto snoopy = smart::template make<const Dog>();
|
||||||
|
const_animal_virtual_ptr p(snoopy);
|
||||||
|
BOOST_TEST(p.get() == snoopy.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
|
||||||
|
auto felix = smart::template make<const Cat>();
|
||||||
|
p = felix;
|
||||||
|
BOOST_TEST(p.get() == felix.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Cat>);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto snoopy = smart::template make<Dog>();
|
||||||
|
dog_virtual_ptr p(snoopy);
|
||||||
|
BOOST_TEST(p.get() == snoopy.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
|
||||||
|
auto hector = smart::template make<Dog>();
|
||||||
|
p = hector;
|
||||||
|
BOOST_TEST(p.get() == hector.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto snoopy = smart::template make<Dog>();
|
||||||
|
animal_virtual_ptr p(snoopy);
|
||||||
|
BOOST_TEST(p.get() == snoopy.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
|
||||||
|
auto felix = smart::template make<Cat>();
|
||||||
|
p = felix;
|
||||||
|
BOOST_TEST(p.get() == felix.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Cat>);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto snoopy = smart::template make<const Dog>();
|
||||||
|
const_dog_virtual_ptr p(snoopy);
|
||||||
|
BOOST_TEST(p.get() == snoopy.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
|
||||||
|
auto hector = smart::template make<const Dog>();
|
||||||
|
p = hector;
|
||||||
|
BOOST_TEST(p.get() == hector.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto snoopy = smart::template make<const Dog>();
|
||||||
|
const_animal_virtual_ptr p(snoopy);
|
||||||
|
BOOST_TEST(p.get() == snoopy.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
|
||||||
|
auto felix = smart::template make<const Cat>();
|
||||||
|
p = felix;
|
||||||
|
BOOST_TEST(p.get() == felix.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Cat>);
|
||||||
|
}
|
||||||
|
|
||||||
|
// dog_virtual_ptr p{Dog()};
|
||||||
|
static_assert(!construct_assign_ok<dog_virtual_ptr, Dog&&>);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// construction and assignment from other shared_virtual_ptr
|
||||||
|
|
||||||
|
{
|
||||||
|
// dog_virtual_ptr(const dog_virtual_ptr&)
|
||||||
|
auto snoopy = smart::template make<Dog>();
|
||||||
|
const dog_virtual_ptr p(snoopy);
|
||||||
|
dog_virtual_ptr q(p);
|
||||||
|
BOOST_TEST(q.get() == snoopy.get());
|
||||||
|
BOOST_TEST(q.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// dog_virtual_ptr(dog_virtual_ptr&)
|
||||||
|
auto snoopy = smart::template make<Dog>();
|
||||||
|
dog_virtual_ptr p(snoopy);
|
||||||
|
dog_virtual_ptr q(p);
|
||||||
|
BOOST_TEST(q.get() == snoopy.get());
|
||||||
|
BOOST_TEST(q.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// dog_virtual_ptr(dog_virtual_ptr&&)
|
||||||
|
auto snoopy = smart::template make<Dog>();
|
||||||
|
dog_virtual_ptr p(snoopy);
|
||||||
|
dog_virtual_ptr q(std::move(p));
|
||||||
|
BOOST_TEST(q.get() == snoopy.get());
|
||||||
|
BOOST_TEST(q.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
// coverity[use_after_move]
|
||||||
|
BOOST_TEST(p.get() == nullptr);
|
||||||
|
BOOST_TEST(p.vptr() == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// animal_virtual_ptr(const dog_virtual_ptr&)
|
||||||
|
auto snoopy = smart::template make<Dog>();
|
||||||
|
const dog_virtual_ptr p(snoopy);
|
||||||
|
animal_virtual_ptr base(p);
|
||||||
|
BOOST_TEST(base.get() == snoopy.get());
|
||||||
|
BOOST_TEST(base.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// shared_virtual_ptr<const Dog>(const dog_virtual_ptr&)
|
||||||
|
auto snoopy = smart::template make<Dog>();
|
||||||
|
const dog_virtual_ptr p(snoopy);
|
||||||
|
const_dog_virtual_ptr const_q(p);
|
||||||
|
BOOST_TEST(const_q.get() == snoopy.get());
|
||||||
|
BOOST_TEST(
|
||||||
|
const_q.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// shared_virtual_ptr<const Animal>(const dog_virtual_ptr&)
|
||||||
|
auto snoopy = smart::template make<Dog>();
|
||||||
|
const dog_virtual_ptr p(snoopy);
|
||||||
|
const_animal_virtual_ptr const_base_q(p);
|
||||||
|
BOOST_TEST(const_base_q.get() == snoopy.get());
|
||||||
|
BOOST_TEST(
|
||||||
|
const_base_q.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// dog_virtual_ptr()
|
||||||
|
dog_virtual_ptr p{nullptr};
|
||||||
|
BOOST_TEST(p.get() == nullptr);
|
||||||
|
BOOST_TEST(p.vptr() == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
dog_virtual_ptr p{dog_ptr()};
|
||||||
|
BOOST_TEST(p.get() == nullptr);
|
||||||
|
BOOST_TEST(p.vptr() == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// assignment
|
||||||
|
|
||||||
|
{
|
||||||
|
dog_virtual_ptr p;
|
||||||
|
auto snoopy = smart::template make<Dog>();
|
||||||
|
p = snoopy;
|
||||||
|
BOOST_TEST(p.get() == snoopy.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
dog_virtual_ptr p;
|
||||||
|
auto snoopy = smart::template make<Dog>();
|
||||||
|
p = snoopy;
|
||||||
|
BOOST_TEST(p.get() == snoopy.get());
|
||||||
|
BOOST_TEST(p.vptr() == default_registry::template static_vptr<Dog>);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto p = smart::template make_virtual<Dog>();
|
||||||
|
p = nullptr;
|
||||||
|
BOOST_TEST(p.get() == nullptr);
|
||||||
|
BOOST_TEST(p.vptr() == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto p = smart::template make_virtual<Dog>();
|
||||||
|
p = dog_ptr();
|
||||||
|
BOOST_TEST(p.get() == nullptr);
|
||||||
|
BOOST_TEST(p.vptr() == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(!construct_assign_ok<dog_virtual_ptr, const Dog&>);
|
||||||
|
static_assert(!construct_assign_ok<dog_virtual_ptr, const Dog*>);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE_TEMPLATE(cast_smart_pointer_value, smart, smart_pointers) {
|
||||||
|
USING_DECLARATIONS;
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
animal_ptr animal = smart::template make<Dog>();
|
||||||
|
dog_ptr dog =
|
||||||
|
virtual_traits<animal_ptr, default_registry>::template cast<dog_ptr>(
|
||||||
|
animal);
|
||||||
|
BOOST_TEST(dog.get() == animal.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||||
|
cast_smart_ptr_lvalue_reference, smart, smart_pointers) {
|
||||||
|
USING_DECLARATIONS;
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
animal_ptr animal = smart::template make<Dog>();
|
||||||
|
dog_ptr dog =
|
||||||
|
virtual_traits<const animal_ptr&, default_registry>::template cast<
|
||||||
|
const dog_ptr&>(animal);
|
||||||
|
BOOST_TEST(dog.get() == animal.get());
|
||||||
|
|
||||||
|
dog_ptr dog2 = virtual_traits<
|
||||||
|
const dog_ptr&, default_registry>::template cast<const dog_ptr&>(dog);
|
||||||
|
BOOST_TEST(dog2.get() == dog.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||||
|
cast_smart_ptr_xvalue_reference, smart, smart_pointers) {
|
||||||
|
USING_DECLARATIONS;
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
animal_ptr animal = smart::template make<Dog>();
|
||||||
|
auto p = animal.get();
|
||||||
|
auto dog =
|
||||||
|
virtual_traits<animal_ptr, default_registry>::template cast<dog_ptr>(
|
||||||
|
std::move(animal));
|
||||||
|
BOOST_TEST(dog.get() == p);
|
||||||
|
|
||||||
|
if (smart::cast_moves()) {
|
||||||
|
// coverity[use_after_move]
|
||||||
|
BOOST_TEST(animal.get() == nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||||
|
cast_shared_virtual_ptr_value, smart, smart_pointers) {
|
||||||
|
USING_DECLARATIONS;
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
animal_virtual_ptr base = smart::template make<Dog>();
|
||||||
|
auto derived = virtual_traits<
|
||||||
|
animal_virtual_ptr, default_registry>::template cast<dog_ptr>(base);
|
||||||
|
BOOST_TEST(derived.get() == base.get());
|
||||||
|
BOOST_TEST(base.vptr() == default_registry::static_vptr<Dog>);
|
||||||
|
BOOST_TEST(derived.vptr() == default_registry::static_vptr<Dog>);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||||
|
cast_shared_virtual_ptr_lvalue_reference, smart, smart_pointers) {
|
||||||
|
USING_DECLARATIONS;
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
animal_virtual_ptr base = smart::template make<Dog>();
|
||||||
|
auto derived = virtual_traits<const animal_virtual_ptr&, default_registry>::
|
||||||
|
template cast<const dog_virtual_ptr&>(base);
|
||||||
|
BOOST_TEST(derived.get() == base.get());
|
||||||
|
BOOST_TEST(base.vptr() == default_registry::static_vptr<Dog>);
|
||||||
|
BOOST_TEST(derived.vptr() == default_registry::static_vptr<Dog>);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||||
|
cast_shared_virtual_ptr_xvalue_reference, smart, smart_pointers) {
|
||||||
|
USING_DECLARATIONS;
|
||||||
|
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
animal_virtual_ptr base = smart::template make<Dog>();
|
||||||
|
auto p = base.get();
|
||||||
|
auto derived =
|
||||||
|
virtual_traits<animal_virtual_ptr, default_registry>::template cast<
|
||||||
|
dog_virtual_ptr>(std::move(base));
|
||||||
|
BOOST_TEST(derived.get() == p);
|
||||||
|
BOOST_TEST(derived.vptr() == default_registry::static_vptr<Dog>);
|
||||||
|
|
||||||
|
if (smart::cast_moves()) {
|
||||||
|
BOOST_TEST(base.get() == nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template struct check_illegal_smart_ops<
|
||||||
|
std::shared_ptr, std::unique_ptr, direct_vector>;
|
||||||
|
|
||||||
|
template struct check_illegal_smart_ops<
|
||||||
|
boost::intrusive_ptr, std::unique_ptr, direct_vector>;
|
||||||
@@ -101,6 +101,8 @@ BOOST_AUTO_TEST_CASE(test_list) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct static_value : static_list<static_value>::static_link {
|
struct static_value : static_list<static_value>::static_link {
|
||||||
|
// coverity[uninit_in_ctor]
|
||||||
|
// coverity[uninit_use_in_call]
|
||||||
explicit static_value(static_list<static_value>& reg) {
|
explicit static_value(static_list<static_value>& reg) {
|
||||||
reg.push_back(*this);
|
reg.push_back(*this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(
|
|||||||
unique_virtual_ptr<Dog, Registry> q(std::move(p));
|
unique_virtual_ptr<Dog, Registry> q(std::move(p));
|
||||||
BOOST_TEST(q.get() == dog);
|
BOOST_TEST(q.get() == dog);
|
||||||
BOOST_TEST(q.vptr() == Registry::template static_vptr<Dog>);
|
BOOST_TEST(q.vptr() == Registry::template static_vptr<Dog>);
|
||||||
|
// coverity[use_after_move]
|
||||||
BOOST_TEST(p.get() == nullptr);
|
BOOST_TEST(p.get() == nullptr);
|
||||||
BOOST_TEST(p.vptr() == nullptr);
|
BOOST_TEST(p.vptr() == nullptr);
|
||||||
}
|
}
|
||||||
@@ -129,6 +130,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(
|
|||||||
unique_virtual_ptr<Animal, Registry> q(std::move(p));
|
unique_virtual_ptr<Animal, Registry> q(std::move(p));
|
||||||
BOOST_TEST(q.get() == dog);
|
BOOST_TEST(q.get() == dog);
|
||||||
BOOST_TEST(q.vptr() == Registry::template static_vptr<Dog>);
|
BOOST_TEST(q.vptr() == Registry::template static_vptr<Dog>);
|
||||||
|
// coverity[use_after_move]
|
||||||
BOOST_TEST(p.get() == nullptr);
|
BOOST_TEST(p.get() == nullptr);
|
||||||
BOOST_TEST(p.vptr() == nullptr);
|
BOOST_TEST(p.vptr() == nullptr);
|
||||||
}
|
}
|
||||||
@@ -269,6 +271,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(
|
|||||||
unique_virtual_ptr<Class>>(std::move(base));
|
unique_virtual_ptr<Class>>(std::move(base));
|
||||||
BOOST_TEST(derived.get() == p);
|
BOOST_TEST(derived.get() == p);
|
||||||
BOOST_TEST(derived.vptr() == default_registry::static_vptr<Class>);
|
BOOST_TEST(derived.vptr() == default_registry::static_vptr<Class>);
|
||||||
|
// coverity[use_after_move]
|
||||||
BOOST_TEST(base.get() == nullptr);
|
BOOST_TEST(base.get() == nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ BOOST_AUTO_TEST_CASE(smart_virtual_ptr_examples) {
|
|||||||
|
|
||||||
virtual_ptr<std::shared_ptr<Animal>> p = std::move(snoopy);
|
virtual_ptr<std::shared_ptr<Animal>> p = std::move(snoopy);
|
||||||
|
|
||||||
|
// coverity[use_after_move]
|
||||||
BOOST_TEST(p.get() == moving);
|
BOOST_TEST(p.get() == moving);
|
||||||
BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
|
BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
|
||||||
BOOST_TEST(snoopy.get() == nullptr);
|
BOOST_TEST(snoopy.get() == nullptr);
|
||||||
@@ -126,6 +127,7 @@ BOOST_AUTO_TEST_CASE(smart_virtual_ptr_examples) {
|
|||||||
make_shared_virtual<Dog>();
|
make_shared_virtual<Dog>();
|
||||||
virtual_ptr<std::shared_ptr<Animal>> p = std::move(snoopy);
|
virtual_ptr<std::shared_ptr<Animal>> p = std::move(snoopy);
|
||||||
|
|
||||||
|
// coverity[use_after_move]
|
||||||
BOOST_TEST(snoopy.get() != nullptr);
|
BOOST_TEST(snoopy.get() != nullptr);
|
||||||
BOOST_TEST(p.get() == snoopy.get());
|
BOOST_TEST(p.get() == snoopy.get());
|
||||||
BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
|
BOOST_TEST(p.vptr() == default_registry::static_vptr<Dog>);
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(
|
|||||||
Dog snoopy;
|
Dog snoopy;
|
||||||
virtual_ptr<Dog, Registry> p(snoopy);
|
virtual_ptr<Dog, Registry> p(snoopy);
|
||||||
virtual_ptr<Dog, Registry> q(std::move(p));
|
virtual_ptr<Dog, Registry> q(std::move(p));
|
||||||
|
// coverity[use_after_move]
|
||||||
BOOST_TEST(q.get() == &snoopy);
|
BOOST_TEST(q.get() == &snoopy);
|
||||||
BOOST_TEST(q.vptr() == Registry::template static_vptr<Dog>);
|
BOOST_TEST(q.vptr() == Registry::template static_vptr<Dog>);
|
||||||
BOOST_TEST(p.get() == &snoopy);
|
BOOST_TEST(p.get() == &snoopy);
|
||||||
|
|||||||
@@ -6,10 +6,16 @@
|
|||||||
#ifndef TEST_VIRTUAL_PTR_VALUE_SEMANTICS_HPP
|
#ifndef TEST_VIRTUAL_PTR_VALUE_SEMANTICS_HPP
|
||||||
#define TEST_VIRTUAL_PTR_VALUE_SEMANTICS_HPP
|
#define TEST_VIRTUAL_PTR_VALUE_SEMANTICS_HPP
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <boost/mp11.hpp>
|
||||||
#include <boost/openmethod.hpp>
|
#include <boost/openmethod.hpp>
|
||||||
#include <boost/openmethod/policies/vptr_map.hpp>
|
|
||||||
#include <boost/openmethod/initialize.hpp>
|
#include <boost/openmethod/initialize.hpp>
|
||||||
|
#include <boost/openmethod/policies/vptr_map.hpp>
|
||||||
|
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||||
|
#include <boost/openmethod/interop/boost_intrusive_ptr.hpp>
|
||||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/intrusive_ptr.hpp>
|
||||||
|
#include <boost/smart_ptr/intrusive_ref_counter.hpp>
|
||||||
|
|
||||||
#include "test_util.hpp"
|
#include "test_util.hpp"
|
||||||
|
|
||||||
@@ -19,7 +25,7 @@ using namespace boost::openmethod;
|
|||||||
using namespace policies;
|
using namespace policies;
|
||||||
using namespace detail;
|
using namespace detail;
|
||||||
|
|
||||||
struct Animal {
|
struct Animal : boost::intrusive_ref_counter<Animal> {
|
||||||
virtual ~Animal() {
|
virtual ~Animal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +37,12 @@ struct Cat : virtual Animal {};
|
|||||||
|
|
||||||
struct Dog : Animal {};
|
struct Dog : Animal {};
|
||||||
|
|
||||||
|
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog);
|
||||||
|
|
||||||
|
struct id;
|
||||||
|
// without following line, no methods, no v-tables
|
||||||
|
auto instantiate_a_method = &method<id, auto(virtual_ptr<Animal>)->void>::fn;
|
||||||
|
|
||||||
template<class Left, class Right>
|
template<class Left, class Right>
|
||||||
constexpr bool construct_assign_ok =
|
constexpr bool construct_assign_ok =
|
||||||
std::is_constructible_v<Left, Right> && std::is_assignable_v<Left, Right>;
|
std::is_constructible_v<Left, Right> && std::is_assignable_v<Left, Right>;
|
||||||
|
|||||||
Reference in New Issue
Block a user