60 return r ? l : construct_type::none;
68namespace detail_poly {
72 return (type & construct_type::copy_only) != construct_type::none;
76 return (type & construct_type::move) != construct_type::none;
80 return (type & construct_type::move) != construct_type::none
81 and (type & construct_type::throw_move) == construct_type::none;
88 return construct_type::copy_only;
90 return construct_type::both;
92 return construct_type::both_throw;
95 return construct_type::move;
97 return construct_type::none;
101 template <construct_type traits>
172 template <
typename T>
176 | construct_type::throw_move
180 template <
typename T,
typename hash =
void>
183 template <
typename T>
186 return std::hash<T>()(*
static_cast<const T*
>(obj));
189 alias<std::size_t (*)(
void*)> hash = &default_hash;
192 template <
typename T,
typename hash =
void>
195 template <
typename T>
202 alias<std::size_t (*)(
void*)> hash = &default_hash;
205 template <
typename Traits>
209 , Traits::destroy_t {
211 using Traits::move_t::move;
213 using Traits::destroy_t::destroy;
216 template <
typename T,
typename Traits>
220 "T must be copy constructible if Traits is.");
224 "T must be nothrow move constructible if Traits is.");
227 "T must be move constructible if Traits is.");
228 return {{
typename Traits::copy_t{
static_cast<T*
>(
nullptr)}},
229 {
typename Traits::move_t{
static_cast<T*
>(
nullptr)}},
230 {
typename Traits::destroy_t{
static_cast<T*
>(
nullptr)}}};
233 template <
typename T,
typename =
void>
235 : std::integral_constant<std::size_t, sizeof(T)> {};
236 template <
typename T>
238 : std::integral_constant<std::size_t, T::max_derived_size> {};
244inline auto noop(
void*,
const T*) -> T* {
248template <
typename T,
bool nothrow>
249inline auto noop(
void*, T*)
noexcept(nothrow) -> T* {
253template <
typename Obj,
bool copyable>
256 template <
typename T>
257 static auto do_copy(
void* dest,
const Obj* from) -> Obj* {
258 return static_cast<Obj*
>(
new (dest) T(*
static_cast<const T*
>(from)));
261 auto (*p_copy)(
void* dest,
const Obj* from) -> Obj* = &noop<Obj>;
267 template <typename T>
269 : p_copy(&do_copy<T>) {}
273 return p_copy(dest, from);
276template <
typename Obj>
279 template <typename T>
281 auto copy(
void* dest,
const Obj* from) -> Obj* =
delete;
287template <
typename Obj,
auto (Obj::* clone)(
void*)
const->Obj*>
292 template <
typename T>
297 return (from->*clone)(dest);
301template <
typename Obj,
bool movable,
bool nothrow,
bool copyable>
304 template <
typename T>
305 static auto do_move(
void* dest, Obj* from)
noexcept(nothrow) -> Obj* {
306 return static_cast<Obj*
>(
new (dest) T(std::move(*
static_cast<T*
>(from))));
309 auto (*p_move)(
void* dest,
310 Obj* from)
noexcept(
false) -> Obj* = &noop<Obj, nothrow>;
316 template <typename T>
318 : p_move(&do_move<T>) {}
322 return p_move(dest, from);
325template <
typename Obj,
bool nothrow>
328 template <typename T>
330 auto move(
void* dest, Obj* from)
noexcept(nothrow) -> Obj* =
delete;
333template <
typename Obj,
bool nothrow>
339 const Obj* from)
noexcept(nothrow) -> Obj* {
340 return this->
copy(dest, from);
346template <
typename Obj>
349 template <typename T>
352 auto destroy(Obj* obj) ->
void { obj->~Obj(); }
354 "Obj must have a virtual destructor");
369template <
typename Obj,
379 constexpr static std::size_t default_capacity
385 constexpr static std::size_t alignment
386 =
std::max(
alignof(Obj),
alignof(std::max_align_t));
448template <
typename Obj>
450template <
typename Obj>
473template <
typename Obj, std::size_t Capacity = 0,
477 Traits::copyable, Traits::movable, Traits::nothrow_movable)>
488 static constexpr std::size_t capacity
489 = Capacity > 0 ? Capacity : Traits::default_capacity;
491 static_assert(capacity >=
sizeof(Obj),
492 "Capacity must be large enough for the object type.");
494 "poly_obj of array type is disallowed.");
520 : ptr(new(data) Obj(obj)) {}
529 : ptr(
new(data) Obj(std::move(obj))) {}
537 template <
typename... Args,
539 std::is_constructible<Obj, Args...>
::value,
int>
542 std::is_nothrow_constructible<Obj, Args&&...>
::value)
543 :
ops_t(detail_poly::make_ops_t<Obj, Traits>())
544 , ptr(
new(data) Obj(std::forward<Args>(args)...)) {}
552 template <
typename... Args,
554 std::is_constructible<Obj, Args...>
::value,
int>
557 std::is_nothrow_constructible<Obj, Args&&...>
::value)
558 :
ops_t(detail_poly::make_ops_t<Obj, Traits>())
559 , ptr(
new(data) Obj{std::forward<Args>(args)...}) {}
562 template <
typename U>
563 constexpr static void assert_emplaceable() {
564 static_assert(
sizeof(U) <= capacity,
565 "U must fit inside of the inline capacity.");
566 static_assert(
alignof(U) <= Traits::alignment,
567 "U must be no more aligned than Traits::alignment");
570 "Obj must be an accessible base of U.");
574 "U must be copy constructible if Traits::copyable is true.");
577 "U must be move constructible if Traits::movable is true.");
581 template <
typename U,
bool aggregate = false>
584 template <
typename U,
typename... Args>
586 std::is_nothrow_constructible<U, Args&&...>
::value)
587 :
ops_t(detail_poly::make_ops_t<U, Traits>())
588 , ptr(
new(data) U(std::forward<Args>(args)...)) {
589 assert_emplaceable<U>();
592 template <
typename U,
typename... Args>
594 std::is_nothrow_constructible<U, Args&&...>
::value)
595 :
ops_t(detail_poly::make_ops_t<U, Traits>())
596 , ptr(
new(data) U{std::forward<Args>(args)...}) {
597 assert_emplaceable<U>();
612 template <
typename U,
typename... Args>
615 assert_emplaceable<U>();
616 return {
tag<U>{}, std::forward<Args>(args)...};
631 template <
typename U,
typename... Args>
634 assert_emplaceable<U>();
639 template <
typename U,
typename... Args>
640 constexpr auto emplace(Args&&... args)
noexcept(
641 std::is_nothrow_constructible<U, Args&&...>
::value) -> U* {
642 assert_emplaceable<U>();
645 static_cast<ops_t&
>(*this) = detail_poly::make_ops_t<U, Traits>();
646 auto r =
new (data) U(std::forward<Args>(args)...);
666 ptr = this->
copy(data, other.ptr);
679 ,
ops_t(std::move(other)) {
681 ptr = this->
move(data, other.ptr);
696 if (
this == &other) {
700 static_cast<ops_t&
>(*this) = other;
702 ptr = this->
copy(data, other.ptr);
719 if (
this == &other) {
723 static_cast<ops_t&
>(*this) = other;
725 ptr = this->
move(data, other.ptr);
738 explicit operator bool() const& noexcept {
return has_value(); }
753 static_cast<ops_t&
>(*this) = {};
804 return std::move(*
get());
821 return std::move(*
get());
878 template <
typename... Args>
894 template <
typename... Args>
904 template <
typename member_type>
908 return get()->*member;
914 template <
typename member_type>
919 return get()->*member;
925 template <
typename member_type>
929 return std::move(
get()->*member);
935 template <
typename member_type>
940 return std::move(
get()->*member);
947 template <
typename member_type,
typename... Args>
949 member_type (Obj::* member)(Args...)) &
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 const) const& 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 member_type (Obj::* member)(Args...) &) &
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>
1009 const&) &
noexcept {
1010 return [member,
value =
get()](Args... args) ->
decltype(
auto) {
1011 return (
value->*member)(std::forward<Args>(args)...);
1019 template <
typename member_type,
typename... Args>
1021 const&) 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 (std::move(*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 (
value->*member)(std::forward<Args>(args)...);
1055 template <
typename member_type,
typename... Args>
1057 member_type (Obj::* member)(Args...)) &&
noexcept {
1058 return [member,
value =
get()](Args... args) ->
decltype(
auto) {
1059 return (
value->*member)(std::forward<Args>(args)...);
1067 template <
typename member_type,
typename... Args>
1069 const&&) &&
noexcept {
1070 return [member,
value =
get()](Args... args) ->
decltype(
auto) {
1071 return (std::move(*value).*member)(std::forward<Args>(args)...);
1079 template <
typename member_type,
typename... Args>
1081 const&&) const&& noexcept {
1082 return [member,
value =
get()](Args... args) ->
decltype(
auto) {
1083 return (std::move(*value).*member)(std::forward<Args>(args)...);
1088 alignas(Traits::alignment)
byte data[capacity]{};
1098 "make_poly_obj<T, D, Capacity>(): Specifying capacity with this "
1099 "API is error-prone, consider "
1100 "using a type alias instead to avoid repetition.")]]
constexpr inline auto
1109template <
typename T,
typename D = T, std::size_t Capacity =
sizeof(D),
1110 typename Traits = poly_obj_traits<T>,
typename... Args>
1114 and Capacity > Traits::default_capacity)>())
1117 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 auto emplace(Args &&... args) noexcept(std::is_nothrow_constructible< U, Args &&... >::value) -> U *
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.
poly_obj(tag< U >, Args &&... args) noexcept(std::is_nothrow_constructible< U, Args &&... >::value)
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.
poly_obj(tag< U, true >, Args &&... args) noexcept(std::is_nothrow_constructible< U, Args &&... >::value)
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...
GeneratorWrapper< T > value(T &&value)
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.