62 return r ? l : construct_type::none;
70namespace detail_poly {
74 return (type & construct_type::copy_only) != construct_type::none;
78 return (type & construct_type::move) != construct_type::none;
82 return (type & construct_type::move) != construct_type::none
83 and (type & construct_type::throw_move) == construct_type::none;
91 return construct_type::copy_only;
93 return construct_type::both;
95 return construct_type::both_throw;
98 return construct_type::move;
100 return construct_type::none;
104 template <construct_type traits>
175 template <
typename T>
177 = construct_type::copy_only* std::is_copy_constructible<T>::value
178 | construct_type::move* std::is_move_constructible<T>::value
179 | construct_type::throw_move*(
180 std::is_move_constructible<T>::value
181 & not std::is_nothrow_move_constructible<T>::value);
183 template <
typename T,
typename hash =
void>
186 template <
typename T>
189 return std::hash<T>()(*
static_cast<const T*
>(obj));
192 alias<std::size_t (*)(
void*)> hash = &default_hash;
195 template <
typename T,
typename hash =
void>
198 template <
typename T>
205 alias<std::size_t (*)(
void*)> hash = &default_hash;
208 template <
typename Traits>
212 , Traits::destroy_t {
214 using Traits::move_t::move;
216 using Traits::destroy_t::destroy;
219 template <
typename T,
typename Traits>
222 std::is_copy_constructible<T>::value>::value,
223 "T must be copy constructible if Traits is.");
226 std::is_nothrow_move_constructible<T>::value>::value,
227 "T must be nothrow move constructible if Traits is.");
230 "T must be move constructible if Traits is.");
231 return {{
typename Traits::copy_t{
static_cast<T*
>(
nullptr)}},
232 {
typename Traits::move_t{
static_cast<T*
>(
nullptr)}},
233 {
typename Traits::destroy_t{
static_cast<T*
>(
nullptr)}}};
236 template <
typename T,
typename =
void>
238 : std::integral_constant<std::size_t, sizeof(T)> {};
239 template <
typename T>
241 : std::integral_constant<std::size_t, T::max_derived_size> {};
247inline auto noop(
void*,
const T*) -> T* {
251template <
typename T,
bool nothrow>
252inline auto noop(
void*, T*)
noexcept(nothrow) -> T* {
256template <
typename Obj,
bool copyable>
259 template <
typename T>
260 static auto do_copy(
void* dest,
const Obj* from) -> Obj* {
261 return static_cast<Obj*
>(
new (dest) T(*
static_cast<const T*
>(from)));
264 auto (*p_copy)(
void* dest,
const Obj* from) -> Obj* = &noop<Obj>;
270 template <typename T>
272 : p_copy(&do_copy<T>) {}
276 return p_copy(dest, from);
279template <
typename Obj>
282 template <typename T>
284 auto copy(
void* dest,
const Obj* from) -> Obj* =
delete;
290template <
typename Obj,
auto (Obj::*clone)(
void*)
const->Obj*>
295 template <
typename T>
300 return (from->*clone)(dest);
304template <
typename Obj,
bool movable,
bool nothrow,
bool copyable>
307 template <
typename T>
308 static auto do_move(
void* dest, Obj* from)
noexcept(nothrow) -> Obj* {
309 return static_cast<Obj*
>(
new (dest) T(std::move(*
static_cast<T*
>(from))));
312 auto (*p_move)(
void* dest, Obj* from)
noexcept(
false)
313 -> Obj* = &noop<Obj, nothrow>;
319 template <typename T>
321 : p_move(&do_move<T>) {}
325 return p_move(dest, from);
328template <
typename Obj,
bool nothrow>
331 template <typename T>
333 auto move(
void* dest, Obj* from)
noexcept(nothrow) -> Obj* =
delete;
336template <
typename Obj,
bool nothrow>
343 return this->
copy(dest, from);
349template <
typename Obj>
352 template <typename T>
355 auto destroy(Obj* obj) ->
void { obj->~Obj(); }
356 static_assert(std::has_virtual_destructor<Obj>::value,
357 "Obj must have a virtual destructor");
372template <
typename Obj,
382 constexpr static std::size_t default_capacity
388 constexpr static std::size_t alignment
389 =
std::max(
alignof(Obj),
alignof(std::max_align_t));
448 static_assert(std::is_empty<destroy_t>::value,
"");
451template <
typename Obj>
453template <
typename Obj>
476template <
typename Obj, std::size_t Capacity = 0,
480 Traits::copyable, Traits::movable, Traits::nothrow_movable)>
491 static constexpr std::size_t capacity
492 = Capacity > 0 ? Capacity : Traits::default_capacity;
494 static_assert(capacity >=
sizeof(Obj),
495 "Capacity must be large enough for the object type.");
496 static_assert(not std::is_array<Obj>::value,
497 "poly_obj of array type is disallowed.");
523 : ptr(new (data) Obj(obj)) {}
532 : ptr(
new (data) Obj(std::move(obj))) {}
540 template <
typename... Args,
542 std::is_constructible<Obj, Args...>::value,
int> = 0>
544 std::is_nothrow_constructible<Obj, Args&&...>::value)
545 :
ops_t(detail_poly::make_ops_t<Obj, Traits>())
546 , ptr(
new (data) Obj(std::forward<Args>(args)...)) {}
554 template <
typename... Args,
556 std::is_constructible<Obj, Args...>::value,
int> = 0>
558 std::is_nothrow_constructible<Obj, Args&&...>::value)
559 :
ops_t(detail_poly::make_ops_t<Obj, Traits>())
560 , ptr(
new (data) Obj{std::forward<Args>(args)...}) {}
574 template <
typename U,
typename... Args>
576 std::is_nothrow_constructible<U, Args&&...>::value) ->
poly_obj {
577 static_assert(
sizeof(U) <= capacity,
578 "U must fit inside of the inline capacity.");
579 static_assert(
alignof(U) <= Traits::alignment,
580 "U must be no more aligned than Traits::alignment");
581 static_assert(std::is_base_of<Obj, U>::value
582 and std::is_convertible<U*, Obj*>::value,
583 "Obj must be an accessible base of Obj.");
586 std::is_copy_constructible<U>::value>::value,
587 "U must be copy constructible if Traits::copyable is true.");
590 "U must be move constructible if Traits::movable is true.");
591 return {tag<U>{}, std::forward<Args>(args)...};
606 template <
typename U,
typename... Args>
608 std::is_nothrow_constructible<U, Args&&...>::value) ->
poly_obj {
609 static_assert(
sizeof(U) <= capacity,
610 "U must fit inside of the inline capacity.");
611 static_assert(
alignof(U) <= Traits::alignment,
612 "U must be no more aligned than Traits::alignment");
613 static_assert(std::is_base_of<Obj, U>::value
614 and std::is_convertible<U*, Obj*>::value,
615 "Obj must be an accessible base of Obj.");
618 std::is_copy_constructible<U>::value>::value,
619 "U must be copy constructible if Traits::copyable is true.");
622 "U must be move constructible if Traits::movable is true.");
623 return {tag<U, true>{}, std::forward<Args>(args)...};
642 ptr = this->
copy(data, other.ptr);
655 ,
ops_t(std::move(other)) {
657 ptr = this->
move(data, other.ptr);
672 if (
this == &other) {
676 static_cast<ops_t&
>(*this) = other;
678 ptr = this->
copy(data, other.ptr);
695 if (
this == &other) {
699 static_cast<ops_t&
>(*this) = other;
701 ptr = this->
move(data, other.ptr);
714 explicit operator bool() const& noexcept {
return has_value(); }
729 static_cast<ops_t&
>(*this) = {};
780 return std::move(*
get());
797 return std::move(*
get());
854 template <
typename... Args>
870 template <
typename... Args>
880 template <
typename member_type>
884 return get()->*member;
890 template <
typename member_type>
892 not std::is_member_function_pointer<member_type Obj::*>::value,
895 return get()->*member;
901 template <
typename member_type>
905 return std::move(
get()->*member);
911 template <
typename member_type>
913 not std::is_member_function_pointer<member_type Obj::*>::value,
916 return std::move(
get()->*member);
923 template <
typename member_type,
typename... Args>
925 member_type (Obj::*member)(Args...)) &
noexcept {
926 return [member, value =
get()](Args... args) ->
decltype(
auto) {
927 return (value->*member)(std::forward<Args>(args)...);
935 template <
typename member_type,
typename... Args>
938 return [member, value =
get()](Args... args) ->
decltype(
auto) {
939 return (value->*member)(std::forward<Args>(args)...);
947 template <
typename member_type,
typename... Args>
949 const) const& noexcept {
950 return [member, value =
get()](Args... args) ->
decltype(
auto) {
951 return (value->*member)(std::forward<Args>(args)...);
959 template <
typename member_type,
typename... Args>
962 return [member, value =
get()](Args... args) ->
decltype(
auto) {
963 return (value->*member)(std::forward<Args>(args)...);
971 template <
typename member_type,
typename... Args>
973 member_type (Obj::*member)(Args...) &) &
noexcept {
974 return [member, value =
get()](Args... args) ->
decltype(
auto) {
975 return (value->*member)(std::forward<Args>(args)...);
983 template <
typename member_type,
typename... Args>
986 return [member, value =
get()](Args... args) ->
decltype(
auto) {
987 return (value->*member)(std::forward<Args>(args)...);
995 template <
typename member_type,
typename... Args>
997 const&) const& noexcept {
998 return [member, value =
get()](Args... args) ->
decltype(
auto) {
999 return (value->*member)(std::forward<Args>(args)...);
1007 template <
typename member_type,
typename... Args>
1010 return [member, value =
get()](Args... args) ->
decltype(
auto) {
1011 return (std::move(*value).*member)(std::forward<Args>(args)...);
1019 template <
typename member_type,
typename... Args>
1021 const&) &&
noexcept {
1022 return [member, value =
get()](Args... args) ->
decltype(
auto) {
1023 return (value->*member)(std::forward<Args>(args)...);
1031 template <
typename member_type,
typename... Args>
1033 member_type (Obj::*member)(Args...)) &&
noexcept {
1034 return [member, value =
get()](Args... args) ->
decltype(
auto) {
1035 return (value->*member)(std::forward<Args>(args)...);
1043 template <
typename member_type,
typename... Args>
1045 const&&) &&
noexcept {
1046 return [member, value =
get()](Args... args) ->
decltype(
auto) {
1047 return (std::move(*value).*member)(std::forward<Args>(args)...);
1055 template <
typename member_type,
typename... Args>
1057 const&&) const&& noexcept {
1058 return [member, value =
get()](Args... args) ->
decltype(
auto) {
1059 return (std::move(*value).*member)(std::forward<Args>(args)...);
1064 alignas(Traits::alignment)
byte data[capacity]{};
1067 template <
typename U,
bool = false>
1070 template <
typename U,
typename... Args>
1071 poly_obj(
tag<U>, Args&&... args)
noexcept(
1072 std::is_nothrow_constructible<U, Args&&...>::value)
1073 : ops_t(detail_poly::make_ops_t<U, Traits>())
1074 , ptr(
new (data) U(std::forward<Args>(args)...)) {}
1076 template <
typename U,
typename... Args>
1078 std::is_nothrow_constructible<U, Args&&...>::value)
1079 : ops_t(detail_poly::make_ops_t<U, Traits>())
1080 , ptr(
new (data) U{std::forward<Args>(args)...}) {}
1089 "make_poly_obj<T, D, Capacity>(): Specifying capacity with this "
1090 "API is error-prone, consider "
1091 "using a type alias instead to avoid repetition.")]]
constexpr inline auto
1100template <
typename T,
typename D = T, std::size_t Capacity =
sizeof(D),
1101 typename Traits = poly_obj_traits<T>,
typename... Args>
1105 and Capacity > Traits::default_capacity)>())
1108 Traits>::template make<D>(std::forward<Args>(args)...);
Inline polymorphic object. Generally mimics the interfaces of std::optional and std::variant.
auto get() const &noexcept -> const Obj *
Returns a pointer to the contained object.
auto operator->*(member_type(Obj::*member)(Args...) const &&) &&noexcept
Call a member function using a pointer to member.
auto operator*() &noexcept -> Obj &
Returns a reference to the contained object.
enable_if_t< not std::is_member_function_pointer< member_type Obj::* >::value, member_type > & operator->*(member_type Obj::*member) &noexcept
Access a member variable using a pointer to member.
auto operator->*(member_type(Obj::*member)(Args...) const &) &noexcept
Call a member function using a pointer to member.
constexpr poly_obj(fakestd::in_place_t, Args &&... args) noexcept(std::is_nothrow_constructible< Obj, Args &&... >::value)
Constructs the contained object in-place without copying or moving.
auto operator*() &&noexcept(Traits::nothrow_movable) -> Obj &&
Returns a reference to the contained object.
enable_if_t< not std::is_member_function_pointer< member_type Obj::* >::value, member_type > && operator->*(member_type Obj::*member) &&noexcept
Access a member variable using a pointer to member.
auto operator->*(member_type(Obj::*member)(Args...)) &noexcept
Call a member function using a pointer to member.
auto operator->*(member_type(Obj::*member)(Args...) const &) const &noexcept
Call a member function using a pointer to member.
auto get() &noexcept -> Obj *
Returns a pointer to the contained object.
auto operator->*(member_type(Obj::*member)(Args...) &) &noexcept
Call a member function using a pointer to member.
auto operator=(poly_obj &&other) &noexcept(Traits::nothrow_movable) -> poly_obj &
Destroys the contained object, if any, and then moves from other as in the move constructor.
static auto make(Args &&... args) noexcept(std::is_nothrow_constructible< U, Args &&... >::value) -> poly_obj
Constructs a poly_obj containing an object of derived type.
constexpr poly_obj(Obj &&obj) noexcept(Traits::nothrow_movable)
Move-constructs the contained object from obj.
auto operator*() const &&noexcept(Traits::nothrow_movable) -> const Obj &&
Returns a reference to the contained object.
auto operator()(Args &&... args) const noexcept(is_nothrow_invocable< const Obj &, Args &&... >::value) -> fakestd::invoke_result_t< const Obj &, Args &&... >
Invokes the contained function object, if Obj is a callable type.
constexpr poly_obj(poly_obj &&other) noexcept(Traits::nothrow_movable)
Moves the contained object of other into this. Note that the moved- from poly_obj is not cleared; ins...
constexpr poly_obj(const Obj &obj)
Copy-constructs the contained object from obj.
constexpr poly_obj(const poly_obj &other)
Constructs a copy of other.
auto operator->*(member_type(Obj::*member)(Args...) const &&) const &&noexcept
Call a member function using a pointer to member.
auto operator=(const poly_obj &other) &-> poly_obj &
Destroys the contained object, if any, and then copies other as in the copy constructor.
auto operator->*(member_type(Obj::*member)(Args...) const) &noexcept
Call a member function using a pointer to member.
static auto make_aggregate(Args &&... args) noexcept(std::is_nothrow_constructible< U, Args &&... >::value) -> poly_obj
Constructs a poly_obj containing an object of derived type.
auto operator->() const &noexcept -> const Obj *
Returns a pointer to the contained object.
auto make_poly_obj(Args &&... args, std::nullptr_t=poly_warn_if<(Capacity !=sizeof(D) and Capacity > Traits::default_capacity)>()) -> poly_obj< T, std::max(Capacity, Traits::default_capacity), Traits >
A convenience factory for making poly_objs.
auto operator->*(member_type(Obj::*member)(Args...) const) const &noexcept
Call a member function using a pointer to member.
auto operator()(Args &&... args) noexcept(is_nothrow_invocable< Obj &, Args &&... >::value) -> fakestd::invoke_result_t< Obj &, Args &&... >
Invokes the contained function object, if Obj is a callable type.
constexpr poly_obj()=default
The default constructor does not construct any contained object.
auto operator->*(member_type(Obj::*member)(Args...) &&) &&noexcept
Call a member function using a pointer to member.
auto has_value() const &noexcept -> bool
const enable_if_t< not std::is_member_function_pointer< member_type Obj::* >::value, member_type > && operator->*(member_type Obj::*member) const &&noexcept
Access a member variable using a pointer to member.
auto operator->*(member_type(Obj::*member)(Args...) const) &&noexcept
Call a member function using a pointer to member.
constexpr poly_obj(std::nullptr_t) noexcept
Explicitly do not construct an object.
const enable_if_t< not std::is_member_function_pointer< member_type Obj::* >::value, member_type > & operator->*(member_type Obj::*member) const &noexcept
Access a member variable using a pointer to member.
auto operator*() const &noexcept -> const Obj &
Returns a reference to the contained object.
constexpr poly_obj(kblib::in_place_agg_t, Args &&... args) noexcept(std::is_nothrow_constructible< Obj, Args &&... >::value)
Constructs the contained object in-place without copying or moving.
auto operator->() &noexcept -> Obj *
Returns a pointer to the contained object.
auto operator->*(member_type(Obj::*member)(Args...) const &) &&noexcept
Call a member function using a pointer to member.
auto operator->*(member_type(Obj::*member)(Args...)) &&noexcept
Call a member function using a pointer to member.
auto clear() noexcept -> void
Empties the poly_obj, reverting to a default-constructed state.
Provides generic facilities for hashing data, and aliases for standard unordered containers using the...
constexpr auto make_ctype(bool copyable, bool movable, bool nothrow_movable) -> construct_type
constexpr construct_type construct_traits
constexpr auto movable(construct_type type) noexcept -> bool
constexpr auto copyable(construct_type type) noexcept -> bool
constexpr auto nothrow_movable(construct_type type) noexcept -> bool
auto make_ops_t() noexcept -> erased_construct< Traits >
typename invoke_result< F, ArgTypes... >::type invoke_result_t
typename make_void< Ts... >::type void_t
constexpr struct kblib::nums::max_t max
auto noop(void *, T *) noexcept(nothrow) -> T *
Does nothing; matches the move construction signature.
typename std::enable_if< B, T >::type enable_if_t
constexpr auto poly_warn_if() -> std::nullptr_t
constexpr auto poly_warn_if< true >() -> std::nullptr_t
constexpr auto operator|(construct_type l, construct_type r) noexcept -> construct_type
T alias
A simple identity alias for simplifying some compound type declarations, such as function pointers.
auto get(punner< Types... > &p) noexcept -> decltype(auto)
constexpr auto invoke(F &&f, Args &&... args) noexcept(noexcept(detail::do_invoke(std::forward< F >(f), std::forward< Args >(args)...))) -> decltype(auto)
typename void_if< b >::type void_if_t
constexpr auto operator&(construct_type l, construct_type r) noexcept -> construct_type
constexpr auto copy(InputIt first, EndIt last, OutputIt out) -> OutputIt
Copies all elements of [first, last) to out. It also allows for a sentinel end iterator.
constexpr auto etoi(E e) -> auto
constexpr auto operator*(construct_type l, bool r) noexcept -> construct_type
The primary template has to exist, but not be constructible, in order to be compatible with std::hash...
Implements copy construction using a virtual clone method. This type is provided mostly as an example...
clone_copy()=default
Does nothing.
auto copy(void *dest, const Obj *from) -> Obj *
Invokes the clone method to copy the object.
clone_copy(T *)
Does nothing.
auto copy(void *dest, const Obj *from) -> Obj *=delete
default_copy() noexcept=default
Implements type erasure for copy construction.
auto copy(void *dest, const Obj *from) -> Obj *
Copies an object of previously-established type.
default_copy() noexcept=default
Constructs an object which does nothing.
Uses the class's virtual destructor.
auto destroy(Obj *obj) -> void
default_destroy() noexcept=default
auto move(void *dest, Obj *from) noexcept(nothrow) -> Obj *=delete
default_move() noexcept=default
auto move(void *dest, const Obj *from) noexcept(nothrow) -> Obj *
Implements type erasure for move construction.
auto move(void *dest, Obj *from) noexcept(nothrow) -> Obj *
Moves an object of previously-established type.
default_move() noexcept=default
Constructs an object which does nothing.
~construct_conditional()=default
auto operator=(const construct_conditional &) -> construct_conditional &=default
construct_conditional() noexcept=default
auto operator=(construct_conditional &&) -> construct_conditional &=default
construct_conditional() noexcept=default
construct_conditional() noexcept=default
construct_conditional() noexcept=default
construct_conditional() noexcept=default
auto operator=(construct_conditional &&) -> construct_conditional &=default
~construct_conditional()=default
auto operator=(const construct_conditional &) -> construct_conditional &=default
static auto default_hash(void *obj) -> std::size_t
static auto default_hash(void *obj) -> std::size_t
A metafunction for logical implication. That is, if A, then B. If not A, B is unimportant.
poly_obj_traits is a traits class template which abstracts the allowed operations on a polymorphic ty...
#define KBLIB_NODISCARD
This internal macro is used to provide a fallback for [[nodiscard]] in C++14.
Provides utilities for working with std::variant more expressively and more efficiently.