Skip to content

AK: Add an OptionalBase helper, and allow specializing Optional with dedicated empty values #25894

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

Hendiadyoin1
Copy link
Contributor

CC: @LucasChollet
CC: @nico to cross check if apple-clang really supports this or if wikipedia is weird
CC: Whoever knows if the CI changes are correct

Based on LadybirdBrowser/ladybird#2032
But still need to cherry-pick and adapt the String changes

Depends on #25891 for the GCC version bump

@Hendiadyoin1
Copy link
Contributor Author

Ah wait the CI containers dont ship gcc-14?

@Hendiadyoin1 Hendiadyoin1 force-pushed the OptionalBase branch 2 times, most recently from 48ca83b to fa1f40e Compare April 18, 2025 15:30
@Hendiadyoin1 Hendiadyoin1 marked this pull request as ready for review April 18, 2025 18:32
@Hendiadyoin1 Hendiadyoin1 requested a review from alimpfard as a code owner April 18, 2025 18:32
@github-actions github-actions bot added the 👀 pr-needs-review PR needs review from a maintainer or community member label Apr 18, 2025
@@ -4,6 +4,7 @@ set -e

script_path=$(cd -P -- "$(dirname -- "$0")" && pwd -P)

# shellcheck source=/dev/null
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC these don't fail in CI, but only in the pre-commit check, because we only pass the changed scripts to shellcheck, which doesn't include shell_include.sh.

So most (if not all) # shellcheck source=/dev/null we already have in master might be unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well it failed CI without the one in this exact file you point out....

Copy link
Member

@spholz spholz Apr 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird, I have no idea why it fails here then.
I'm 99% sure that the build-image-raspberry-pi.sh one only failed in the pre-commit hook.

@Hendiadyoin1
Copy link
Contributor Author

Whoops, this breaks jakt builds

@Hendiadyoin1
Copy link
Contributor Author

Also Something in the NNRP code still seems off, will continue to test

This also makes the monadic helpers a bit stricter with their value
types, hence the drive-by changes.
This will be needed in the next commit, as Optional then starts to
call into Traits, and the affected Ts initialize their own Optional
so Traits specialization also already needs to be declared.
@Hendiadyoin1 Hendiadyoin1 force-pushed the OptionalBase branch 2 times, most recently from b40676b to fd5a34f Compare April 18, 2025 22:24
Comment on lines +773 to +792
// FIXME: What to do here when we should not move empties around,
// But don't have a swap method to place it in?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I just add an static_assert(dont_move_empty | has_swap) in the mean time?

Comment on lines +780 to +804
requires(dont_move_empty && has_swap)
{
VERIFY(has_value());
T value = the_empty_value();
value.swap(m_value);
return value;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay back to shenanigans
(although this looks like a normal move constructor)

if (this == &other)
return *this;
swap(m_value, other.m_value);
other.clear();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clear is needed to be clearing on move, which the other optional promises
with non trivial types, which we definitely hit here

AK/Optional.h Outdated
Comment on lines 651 to 664
// Note: Some types don't like to be moved when in their empty state,
// so we need to special case them
constexpr static bool dont_move_empty = requires {
Traits<T>::optional_dont_move_empty;
requires(Traits<T>::optional_dont_move_empty);
};
// Note: Some types don't like to get their empty values assigned
// but provide a swap method, which usually does not go through
// that check, so let's try to leverage that when we cant move empty values
constexpr static bool has_swap = requires(T& t1, T& t2) { t1.swap(t2); };

// FIXME: We should investigate if we could guess trivial swappability
// based on attributes the T has (see trivially relocatable/replaceable)
// This might also be useful for the normal Optional implementation
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please read during review
especially if you have better ideas

ALWAYS_INLINE constexpr void emplace(Ts&&... parameters)
{
clear();
m_value = T(forward<Ts>(parameters)...);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if construct_at is nicer here as m_value is usually in a replaceable state here

AK/Optional.h Outdated
// This might also be useful for the normal Optional implementation

public:
ALWAYS_INLINE constexpr Optional() {};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: = default

The new Optional implementation is chosen when a
`Traits<T>::special_optional_empty_value` exists,
this can be an immediate value or a function optionally taking a
Badge<Optional<T>>.

You can also define a custom specialization of
`Traits<T>::optional_has_value`, as otherwise the default goes through
the `==`/`!=` operators, which may not be defined.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
👀 pr-needs-review PR needs review from a maintainer or community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants