35std::vector<barks> bark_log;
38 good_base() =
default;
39 virtual ~good_base() noexcept { bark_log.push_back(dgood_base); }
41 virtual auto bark() const ->
void { bark_log.push_back(vgood_base); }
43struct good_derived : good_base {
44 ~good_derived() noexcept
override { bark_log.push_back(dgood_derived); }
46 auto bark() const ->
void override { bark_log.push_back(vgood_derived); }
49struct bad_nocopy : good_base {
50 bad_nocopy(
const bad_nocopy&) =
delete;
54 virtual auto bark() const ->
void { bark_log.push_back(vbad_base1); }
56 ~bad_base1() noexcept { bark_log.push_back(dbad_base1); }
58struct bad_derived1 : bad_base1 {
59 auto bark() const ->
void override { bark_log.push_back(vbad_derived1); }
60 KBLIB_UNUSED ~bad_derived1() noexcept { bark_log.push_back(dbad_derived1); }
64 bad_base2() =
default;
65 virtual ~bad_base2() noexcept { bark_log.push_back(dbad_base2); }
66 virtual auto bark() const ->
void { bark_log.push_back(vbad_base2); }
68struct bad_derived2 :
protected bad_base2 {
69 auto bark() const ->
void override { bark_log.push_back(vbad_derived2); }
70 ~bad_derived2() noexcept
override { bark_log.push_back(dbad_derived2); }
73 small_base() =
default;
74 virtual ~small_base() noexcept = default;
75 virtual auto bark() const ->
void { bark_log.push_back(vsmall_base); }
76 virtual auto id() const ->
int {
return 0; }
78struct big_derived : small_base {
80 = (
static_cast<void>(x = 1),
81 kblib::FNVa_a<std::size_t>(
82 reinterpret_cast<const char (&)[sizeof(big_derived)]
>(*
this)));
83 auto bark() const ->
void override { bark_log.push_back(vbig_derived); }
84 ~big_derived() noexcept override = default;
85 auto
id() const ->
int override {
return 1; }
89 not_copyable() =
default;
90 not_copyable(
const not_copyable&) =
delete;
91 KBLIB_UNUSED not_copyable(not_copyable&&) noexcept = default;
92 virtual ~not_copyable() = default;
95struct copyable_derived : not_copyable {
97 copyable_derived(
const copyable_derived&) {}
98 copyable_derived(copyable_derived&&) noexcept = default;
101struct copyable_base {
102 virtual ~copyable_base() =
default;
105struct noncopyable_derived : copyable_base {
107 noncopyable_derived(
const noncopyable_derived&) =
delete;
108 KBLIB_UNUSED noncopyable_derived(noncopyable_derived&&) =
default;
112 constexpr static std::size_t max_derived_size =
sizeof(big_derived);
113 virtual ~hinted_base() =
default;
116struct hinted_derived : hinted_base {
127 std::vector<barks> expected;
132 REQUIRE(o2.has_value());
134 expected.push_back(vgood_base);
135 REQUIRE(bark_log == expected);
139 expected.push_back(dgood_derived);
140 expected.push_back(dgood_base);
141 REQUIRE(bark_log == expected);
145 expected.push_back(vgood_derived);
146 REQUIRE(bark_log == expected);
149 expected.push_back(dgood_base);
150 REQUIRE(bark_log == expected);
153 expected.push_back(vgood_derived);
154 REQUIRE(bark_log == expected);
157 expected.push_back(dgood_derived);
158 expected.push_back(dgood_base);
159 REQUIRE(bark_log == expected);
161 REQUIRE(o2.has_value());
166 expected.push_back(dgood_derived);
167 expected.push_back(dgood_base);
168 REQUIRE(bark_log == expected);
171 SECTION(
"non-virtual destructor") {
177 SECTION(
"private base") {
178 std::vector<barks> expected;
185 expected.push_back(dbad_base2);
186 REQUIRE(bark_log == expected);
189 SECTION(
"capacity") {
190 std::vector<barks> expected;
198 kblib::poly_obj<small_base,
sizeof(big_derived)> o7, o8{std::in_place};
200 expected.push_back(vsmall_base);
201 REQUIRE(bark_log == expected);
203 sizeof(big_derived)>::make<big_derived>();
204 REQUIRE(o7.has_value());
206 expected.push_back(vbig_derived);
207 REQUIRE(bark_log == expected);
210 SECTION(
"non-copyable type") {
223 SECTION(
"non-copyable derived") {
229 auto o2 =
decltype(o1)::make<noncopyable_derived>();
232 SECTION(
"mixed vector") {
233 auto r = [n = std::uint16_t{16127}]()
mutable {
236 return kblib::FNV32a({
reinterpret_cast<char*
>(&n),
sizeof(n)});
241 std::vector<obj> polyvec;
246 return obj::make<big_derived>();
249 return obj(std::in_place);
257 for (
const auto& o : polyvec) {
265 SECTION(
"free make function") {
268 auto o = kblib::make_poly_obj<small_base, big_derived>();
270 std::is_same_v<
decltype(o),
272 "make_poly_obj must return the correct type.");
276 == hinted_base::max_derived_size);
278 static_assert(
decltype(o)::capacity
279 ==
decltype(o)::base_type::max_derived_size);
280 o =
decltype(o)::make<hinted_derived>();
287 auto get_member() &
noexcept ->
int {
return member; }
288 auto cget_member() const& noexcept ->
int {
return member; }
289 auto rget_member() &&
noexcept ->
int {
return member; }
290 auto crget_member() const&& noexcept ->
int {
return member; }
292 auto get_member2() noexcept ->
int {
return member; }
293 auto cget_member2() const noexcept ->
int {
return member; }
295 virtual ~mem_ptr_test() =
default;
301 SECTION(
"member data") {
302 constexpr auto data_member = &mem_ptr_test::member;
303 REQUIRE(obj->*data_member == 42);
304 static_assert(std::is_same_v<
decltype(obj->*data_member),
int&>);
305 static_assert(std::is_same_v<
decltype(std::as_const(obj)->*data_member),
308 std::is_same_v<
decltype(std::move(obj)->*data_member),
int&&>);
310 std::is_same_v<
decltype(std::move(std::as_const(obj))->*data_member),
313 SECTION(
"member function") {
314 constexpr auto func_member = &mem_ptr_test::get_member;
315 constexpr auto cfunc_member = &mem_ptr_test::cget_member;
316 constexpr auto rfunc_member = &mem_ptr_test::rget_member;
317 constexpr auto crfunc_member = &mem_ptr_test::crget_member;
318 REQUIRE((obj->*func_member)() == 42);
319 static_assert(std::is_same_v<
decltype((obj->*func_member)()),
int>);
320 REQUIRE((obj->*cfunc_member)() == 42);
321 static_assert(std::is_same_v<
decltype((obj->*cfunc_member)()),
int>);
322 REQUIRE((std::as_const(obj)->*cfunc_member)() == 42);
324 std::is_same_v<
decltype((std::as_const(obj)->*cfunc_member)()),
int>);
325 REQUIRE((std::move(obj)->*rfunc_member)() == 42);
327 std::is_same_v<
decltype((std::move(obj)->*rfunc_member)()),
int>);
328 REQUIRE((std::move(obj)->*crfunc_member)() == 42);
330 std::is_same_v<
decltype((std::move(obj)->*crfunc_member)()),
int>);
331 REQUIRE((std::move(std::as_const(obj))->*crfunc_member)() == 42);
332 static_assert(std::is_same_v<
333 decltype((std::move(std::as_const(obj))->*crfunc_member)()),
336 constexpr auto func_member2 = &mem_ptr_test::get_member2;
337 constexpr auto cfunc_member2 = &mem_ptr_test::cget_member2;
339 REQUIRE((obj->*func_member2)() == 42);
340 static_assert(std::is_same_v<
decltype((obj->*func_member2)()),
int>);
341 REQUIRE((obj->*cfunc_member2)() == 42);
342 static_assert(std::is_same_v<
decltype((obj->*cfunc_member2)()),
int>);
343 REQUIRE((std::as_const(obj)->*cfunc_member2)() == 42);
345 std::is_same_v<
decltype((std::as_const(obj)->*cfunc_member2)()),
Inline polymorphic object. Generally mimics the interfaces of std::optional and std::variant.
auto has_value() const &noexcept -> bool
auto clear() noexcept -> void
Empties the poly_obj, reverting to a default-constructed state.
constexpr auto generate_n(OutputIt first, Size count, Generator g) noexcept(noexcept(*first++=g())) -> OutputIt
Like std::generate_n except that it is constexpr.
constexpr auto FNV32a(std::string_view s, std::uint32_t hval=fnv::fnv_offset< std::uint32_t >::value) noexcept -> std::uint32_t
A standard FNV32a hash function, for string_views.
Provides poly_obj, which enables polymorphism to be used without unnecessary per-object dynamic alloc...
poly_obj_traits is a traits class template which abstracts the allowed operations on a polymorphic ty...
#define KBLIB_UNUSED
This internal macro is used to provide a fallback for [[maybe_unused]] in C++14.