1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 07:07:34 +00:00

AK: Slap Optional with the ALWAYS_INLINE stick

I saw some Optional constructors when profiling the dynamic loader
and that seemed silly since we can inline them at no/little cost.
This commit is contained in:
Andreas Kling 2021-02-23 09:41:26 +01:00
parent de52fe6156
commit 145923bdc9

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -36,28 +36,28 @@ namespace AK {
template<typename T> template<typename T>
class alignas(T) [[nodiscard]] Optional { class alignas(T) [[nodiscard]] Optional {
public: public:
Optional() = default; ALWAYS_INLINE Optional() = default;
Optional(const T& value) ALWAYS_INLINE Optional(const T& value)
: m_has_value(true) : m_has_value(true)
{ {
new (&m_storage) T(value); new (&m_storage) T(value);
} }
template<typename U> template<typename U>
Optional(const U& value) ALWAYS_INLINE Optional(const U& value)
: m_has_value(true) : m_has_value(true)
{ {
new (&m_storage) T(value); new (&m_storage) T(value);
} }
Optional(T&& value) ALWAYS_INLINE Optional(T&& value)
: m_has_value(true) : m_has_value(true)
{ {
new (&m_storage) T(move(value)); new (&m_storage) T(move(value));
} }
Optional(Optional&& other) ALWAYS_INLINE Optional(Optional&& other)
: m_has_value(other.m_has_value) : m_has_value(other.m_has_value)
{ {
if (other.has_value()) { if (other.has_value()) {
@ -66,15 +66,15 @@ public:
} }
} }
Optional(const Optional& other) ALWAYS_INLINE Optional(const Optional& other)
: m_has_value(other.m_has_value) : m_has_value(other.m_has_value)
{ {
if (m_has_value) { if (m_has_value) {
new (&m_storage) T(other.value_without_consume_state()); new (&m_storage) T(other.value());
} }
} }
Optional& operator=(const Optional& other) ALWAYS_INLINE Optional& operator=(const Optional& other)
{ {
if (this != &other) { if (this != &other) {
clear(); clear();
@ -86,7 +86,7 @@ public:
return *this; return *this;
} }
Optional& operator=(Optional&& other) ALWAYS_INLINE Optional& operator=(Optional&& other)
{ {
if (this != &other) { if (this != &other) {
clear(); clear();
@ -98,7 +98,7 @@ public:
} }
template<typename O> template<typename O>
bool operator==(const Optional<O>& other) const ALWAYS_INLINE bool operator==(const Optional<O>& other) const
{ {
return has_value() == other.has_value() && (!has_value() || value() == other.value()); return has_value() == other.has_value() && (!has_value() || value() == other.value());
} }
@ -134,7 +134,8 @@ public:
[[nodiscard]] ALWAYS_INLINE const T& value() const [[nodiscard]] ALWAYS_INLINE const T& value() const
{ {
return value_without_consume_state(); ASSERT(m_has_value);
return *reinterpret_cast<const T*>(&m_storage);
} }
[[nodiscard]] T release_value() [[nodiscard]] T release_value()
@ -153,19 +154,13 @@ public:
return fallback; return fallback;
} }
const T& operator*() const { return value(); } ALWAYS_INLINE const T& operator*() const { return value(); }
T& operator*() { return value(); } ALWAYS_INLINE T& operator*() { return value(); }
const T* operator->() const { return &value(); } ALWAYS_INLINE const T* operator->() const { return &value(); }
T* operator->() { return &value(); } ALWAYS_INLINE T* operator->() { return &value(); }
private: private:
// Call when we don't want to alter the consume state
ALWAYS_INLINE const T& value_without_consume_state() const
{
ASSERT(m_has_value);
return *reinterpret_cast<const T*>(&m_storage);
}
u8 m_storage[sizeof(T)] { 0 }; u8 m_storage[sizeof(T)] { 0 };
bool m_has_value { false }; bool m_has_value { false };
}; };