mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-09 09:34:57 +09:00
AK: Use conditionally trivial special member functions
This commit makes use of the conditionally trivial special member functions introduced in C++20. Basically, `Optional` and `Variant` inherits whether its wrapped type is trivially copy constructible, trivially copy assignable or trivially destructible. This lets the compiler optimize optimize a large number of their use cases. The constraints have been applied to `Optional`'s converting constructors too in order to make the API more explicit. This feature is not supported by Clang yet, so we use conditional compilation so that Lagom can be built on macOS. Once Clang has P0848R3 support, these can be removed.
This commit is contained in:
parent
6c0b9919ce
commit
515e2d9734
Notes:
sideshowbarker
2024-07-18 10:31:10 +09:00
Author: https://github.com/BertalanD
Commit: 515e2d9734
Pull-request: https://github.com/SerenityOS/serenity/pull/8391
Reviewed-by: https://github.com/alimpfard
3 changed files with 70 additions and 37 deletions
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
||||||
|
* Copyright (c) 2021, Daniel Bertalan <dani@danielbertalan.dev>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -20,23 +21,30 @@ public:
|
||||||
|
|
||||||
ALWAYS_INLINE Optional() = default;
|
ALWAYS_INLINE Optional() = default;
|
||||||
|
|
||||||
ALWAYS_INLINE Optional(const T& value)
|
#ifdef AK_HAS_CONDITIONALLY_TRIVIAL
|
||||||
: m_has_value(true)
|
Optional(const Optional& other) requires(!IsCopyConstructible<T>) = delete;
|
||||||
{
|
Optional(const Optional& other) = default;
|
||||||
new (&m_storage) T(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
Optional(Optional&& other) requires(!IsMoveConstructible<T>) = delete;
|
||||||
ALWAYS_INLINE Optional(const U& value)
|
|
||||||
: m_has_value(true)
|
|
||||||
{
|
|
||||||
new (&m_storage) T(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
ALWAYS_INLINE Optional(T&& value)
|
Optional& operator=(const Optional&) requires(!IsCopyConstructible<T> || !IsDestructible<T>) = delete;
|
||||||
: m_has_value(true)
|
Optional& operator=(const Optional&) = default;
|
||||||
|
|
||||||
|
Optional& operator=(Optional&& other) requires(!IsMoveConstructible<T> || !IsDestructible<T>) = delete;
|
||||||
|
|
||||||
|
~Optional() requires(!IsDestructible<T>) = delete;
|
||||||
|
~Optional() = default;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ALWAYS_INLINE Optional(const Optional& other)
|
||||||
|
#ifdef AK_HAS_CONDITIONALLY_TRIVIAL
|
||||||
|
requires(!IsTriviallyCopyConstructible<T>)
|
||||||
|
#endif
|
||||||
|
: m_has_value(other.m_has_value)
|
||||||
{
|
{
|
||||||
new (&m_storage) T(move(value));
|
if (other.has_value()) {
|
||||||
|
new (&m_storage) T(other.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Optional(Optional&& other)
|
ALWAYS_INLINE Optional(Optional&& other)
|
||||||
|
@ -44,39 +52,25 @@ public:
|
||||||
{
|
{
|
||||||
if (other.has_value()) {
|
if (other.has_value()) {
|
||||||
new (&m_storage) T(other.release_value());
|
new (&m_storage) T(other.release_value());
|
||||||
other.m_has_value = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Optional(const Optional& other)
|
template<typename U = T>
|
||||||
: m_has_value(other.m_has_value)
|
ALWAYS_INLINE explicit(!IsConvertible<U&&, T>) Optional(U&& value) requires(!IsSame<RemoveCVReference<U>, Optional<T>> && IsConstructible<T, U&&>)
|
||||||
{
|
|
||||||
if (m_has_value) {
|
|
||||||
new (&m_storage) T(other.value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ALWAYS_INLINE Optional(Optional& other)
|
|
||||||
: m_has_value(other.m_has_value)
|
|
||||||
{
|
|
||||||
if (m_has_value) {
|
|
||||||
new (&m_storage) T(other.value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
ALWAYS_INLINE Optional(U& value)
|
|
||||||
: m_has_value(true)
|
: m_has_value(true)
|
||||||
{
|
{
|
||||||
new (&m_storage) T(value);
|
new (&m_storage) T(forward<U>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Optional& operator=(const Optional& other)
|
ALWAYS_INLINE Optional& operator=(const Optional& other)
|
||||||
|
#ifdef AK_HAS_CONDITIONALLY_TRIVIAL
|
||||||
|
requires(!IsTriviallyCopyConstructible<T> || !IsTriviallyDestructible<T>)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
clear();
|
clear();
|
||||||
m_has_value = other.m_has_value;
|
m_has_value = other.m_has_value;
|
||||||
if (m_has_value) {
|
if (other.has_value()) {
|
||||||
new (&m_storage) T(other.value());
|
new (&m_storage) T(other.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,8 +82,9 @@ public:
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
clear();
|
clear();
|
||||||
m_has_value = other.m_has_value;
|
m_has_value = other.m_has_value;
|
||||||
if (other.has_value())
|
if (other.has_value()) {
|
||||||
new (&m_storage) T(other.release_value());
|
new (&m_storage) T(other.release_value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -107,6 +102,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE ~Optional()
|
ALWAYS_INLINE ~Optional()
|
||||||
|
#ifdef AK_HAS_CONDITIONALLY_TRIVIAL
|
||||||
|
requires(!IsTriviallyDestructible<T>)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
@ -167,7 +165,6 @@ private:
|
||||||
alignas(T) u8 m_storage[sizeof(T)];
|
alignas(T) u8 m_storage[sizeof(T)];
|
||||||
bool m_has_value { false };
|
bool m_has_value { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using AK::Optional;
|
using AK::Optional;
|
||||||
|
|
|
@ -25,6 +25,10 @@
|
||||||
|
|
||||||
#define ARCH(arch) (defined(AK_ARCH_##arch) && AK_ARCH_##arch)
|
#define ARCH(arch) (defined(AK_ARCH_##arch) && AK_ARCH_##arch)
|
||||||
|
|
||||||
|
#if !defined(__clang__)
|
||||||
|
# define AK_HAS_CONDITIONALLY_TRIVIAL
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ALWAYS_INLINE
|
#ifdef ALWAYS_INLINE
|
||||||
# undef ALWAYS_INLINE
|
# undef ALWAYS_INLINE
|
||||||
#endif
|
#endif
|
||||||
|
|
32
AK/Variant.h
32
AK/Variant.h
|
@ -210,7 +210,27 @@ public:
|
||||||
template<typename... NewTs>
|
template<typename... NewTs>
|
||||||
friend struct Variant;
|
friend struct Variant;
|
||||||
|
|
||||||
|
#ifdef AK_HAS_CONDITIONALLY_TRIVIAL
|
||||||
|
Variant(const Variant&) requires(!(IsCopyConstructible<Ts> && ...)) = delete;
|
||||||
|
Variant(const Variant&) = default;
|
||||||
|
|
||||||
|
Variant(Variant&&) requires(!(IsMoveConstructible<Ts> && ...)) = delete;
|
||||||
|
Variant(Variant&&) = default;
|
||||||
|
|
||||||
|
~Variant() requires(!(IsDestructible<Ts> && ...)) = delete;
|
||||||
|
~Variant() = default;
|
||||||
|
|
||||||
|
Variant& operator=(const Variant&) requires(!(IsCopyConstructible<Ts> && ...) || !(IsDestructible<Ts> && ...)) = delete;
|
||||||
|
Variant& operator=(const Variant&) = default;
|
||||||
|
|
||||||
|
Variant& operator=(Variant&&) requires(!(IsMoveConstructible<Ts> && ...) || !(IsDestructible<Ts> && ...)) = delete;
|
||||||
|
Variant& operator=(Variant&&) = default;
|
||||||
|
#endif
|
||||||
|
|
||||||
ALWAYS_INLINE Variant(const Variant& old)
|
ALWAYS_INLINE Variant(const Variant& old)
|
||||||
|
#ifdef AK_HAS_CONDITIONALLY_TRIVIAL
|
||||||
|
requires(!(IsTriviallyCopyConstructible<Ts> && ...))
|
||||||
|
#endif
|
||||||
: Detail::MergeAndDeduplicatePacks<Detail::VariantConstructors<Ts, Variant<Ts...>>...>()
|
: Detail::MergeAndDeduplicatePacks<Detail::VariantConstructors<Ts, Variant<Ts...>>...>()
|
||||||
, m_data {}
|
, m_data {}
|
||||||
, m_index(old.m_index)
|
, m_index(old.m_index)
|
||||||
|
@ -223,6 +243,9 @@ public:
|
||||||
// and if a variant with a nontrivial move ctor is moved from, it may or may not be valid
|
// and if a variant with a nontrivial move ctor is moved from, it may or may not be valid
|
||||||
// but it will still contain the "moved-from" state of the object it previously contained.
|
// but it will still contain the "moved-from" state of the object it previously contained.
|
||||||
ALWAYS_INLINE Variant(Variant&& old)
|
ALWAYS_INLINE Variant(Variant&& old)
|
||||||
|
#ifdef AK_HAS_CONDITIONALLY_TRIVIAL
|
||||||
|
requires(!(IsTriviallyMoveConstructible<Ts> && ...))
|
||||||
|
#endif
|
||||||
: Detail::MergeAndDeduplicatePacks<Detail::VariantConstructors<Ts, Variant<Ts...>>...>()
|
: Detail::MergeAndDeduplicatePacks<Detail::VariantConstructors<Ts, Variant<Ts...>>...>()
|
||||||
, m_data {}
|
, m_data {}
|
||||||
, m_index(old.m_index)
|
, m_index(old.m_index)
|
||||||
|
@ -231,11 +254,17 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE ~Variant()
|
ALWAYS_INLINE ~Variant()
|
||||||
|
#ifdef AK_HAS_CONDITIONALLY_TRIVIAL
|
||||||
|
requires(!(IsTriviallyDestructible<Ts> && ...))
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
Helper::delete_(m_index, m_data);
|
Helper::delete_(m_index, m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Variant& operator=(const Variant& other)
|
ALWAYS_INLINE Variant& operator=(const Variant& other)
|
||||||
|
#ifdef AK_HAS_CONDITIONALLY_TRIVIAL
|
||||||
|
requires(!(IsTriviallyCopyConstructible<Ts> && ...) || !(IsTriviallyDestructible<Ts> && ...))
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
m_index = other.m_index;
|
m_index = other.m_index;
|
||||||
Helper::copy_(other.m_index, other.m_data, m_data);
|
Helper::copy_(other.m_index, other.m_data, m_data);
|
||||||
|
@ -243,6 +272,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE Variant& operator=(Variant&& other)
|
ALWAYS_INLINE Variant& operator=(Variant&& other)
|
||||||
|
#ifdef AK_HAS_CONDITIONALLY_TRIVIAL
|
||||||
|
requires(!(IsTriviallyMoveConstructible<Ts> && ...) || !(IsTriviallyDestructible<Ts> && ...))
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
m_index = other.m_index;
|
m_index = other.m_index;
|
||||||
Helper::move_(other.m_index, other.m_data, m_data);
|
Helper::move_(other.m_index, other.m_data, m_data);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue