AK: Use Deducing this for OptionalBase

This is taken from and akin to
https://github.com/SerenityOS/serenity/pull/25894
This commit is contained in:
Hendiadyoin1
2025-07-15 00:22:12 +02:00
committed by Jelle Raaijmakers
parent fd4888e800
commit bcd01da91d
Notes: github-actions[bot] 2025-11-20 15:28:30 +00:00
12 changed files with 81 additions and 94 deletions

View File

@@ -9,7 +9,11 @@
#pragma once
#include <AK/Assertions.h>
#include <AK/Concepts.h>
#include <AK/Forward.h>
#include <AK/Noncopyable.h>
#include <AK/Platform.h>
#include <AK/StdLibExtraDetails.h>
#include <AK/StdLibExtras.h>
#include <AK/Traits.h>
#include <AK/Try.h>
@@ -33,10 +37,17 @@ struct ConditionallyResultType<false, T> {
using Type = T;
};
template<typename Self, typename T>
struct AddConstIfNeeded {
using Type = Conditional<IsConst<RemoveReference<Self>> && !IsConst<T>, AddConst<T>, T>;
};
}
template<auto condition, typename T>
using ConditionallyResultType = typename Detail::ConditionallyResultType<condition, T>::Type;
template<typename Self, typename T>
using AddConstIfNeeded = typename Detail::AddConstIfNeeded<Self, T>::Type;
// NOTE: If you're here because of an internal compiler error in GCC 10.3.0+,
// it's because of the following bug:
@@ -53,116 +64,92 @@ struct OptionalNone {
explicit constexpr OptionalNone() = default;
};
template<typename T, typename Self = Optional<T>>
requires(!IsLvalueReference<Self>) class [[nodiscard]] OptionalBase {
template<typename T>
requires(!IsLvalueReference<T>)
class [[nodiscard]] OptionalBase {
public:
using ValueType = T;
template<SameAs<OptionalNone> V>
ALWAYS_INLINE constexpr Self& operator=(V)
template<typename Self, SameAs<OptionalNone> V>
ALWAYS_INLINE constexpr Self& operator=(this Self& self, V)
{
static_cast<Self&>(*this).clear();
return static_cast<Self&>(*this);
self.clear();
return self;
}
[[nodiscard]] ALWAYS_INLINE constexpr T* ptr() &
template<typename Self>
[[nodiscard]] ALWAYS_INLINE constexpr AddConstIfNeeded<Self, T>* ptr(this Self& self)
{
return static_cast<Self&>(*this).has_value() ? __builtin_launder(reinterpret_cast<T*>(&static_cast<Self&>(*this).value())) : nullptr;
return self.has_value() ? &self.value() : nullptr;
}
[[nodiscard]] ALWAYS_INLINE constexpr T const* ptr() const&
template<typename O = T, typename Fallback = O, typename Self>
[[nodiscard]] ALWAYS_INLINE constexpr O value_or(this Self&& self, Fallback&& fallback)
{
return static_cast<Self const&>(*this).has_value() ? __builtin_launder(reinterpret_cast<T const*>(&static_cast<Self const&>(*this).value())) : nullptr;
if (self.has_value())
return forward<Self>(self).value();
return forward<Fallback>(fallback);
}
template<typename O = T, typename Fallback = O>
[[nodiscard]] ALWAYS_INLINE constexpr O value_or(Fallback const& fallback) const&
template<typename Callback, typename O = T, typename Self>
[[nodiscard]] ALWAYS_INLINE constexpr O value_or_lazy_evaluated(this Self&& self, Callback callback)
{
if (static_cast<Self const&>(*this).has_value())
return static_cast<Self const&>(*this).value();
return fallback;
}
template<typename O = T, typename Fallback = O>
requires(!IsLvalueReference<O> && !IsRvalueReference<O>)
[[nodiscard]] ALWAYS_INLINE constexpr O value_or(Fallback&& fallback) &&
{
if (static_cast<Self&>(*this).has_value())
return move(static_cast<Self&>(*this).value());
return move(fallback);
}
template<typename Callback, typename O = T>
[[nodiscard]] ALWAYS_INLINE constexpr O value_or_lazy_evaluated(Callback callback) const
{
if (static_cast<Self const&>(*this).has_value())
return static_cast<Self const&>(*this).value();
if (self.has_value())
return forward<Self>(self).value();
return callback();
}
template<typename Callback, typename O = T>
[[nodiscard]] ALWAYS_INLINE constexpr Optional<O> value_or_lazy_evaluated_optional(Callback callback) const
template<typename Callback, typename O = T, typename Self>
[[nodiscard]] ALWAYS_INLINE constexpr Optional<O> value_or_lazy_evaluated_optional(this Self&& self, Callback callback)
{
if (static_cast<Self const&>(*this).has_value())
return static_cast<Self const&>(*this).value();
if (self.has_value())
return forward<Self>(self);
return callback();
}
template<typename Callback, typename O = T>
[[nodiscard]] ALWAYS_INLINE constexpr ErrorOr<O> try_value_or_lazy_evaluated(Callback callback) const
template<typename Callback, typename O = T, typename Self>
[[nodiscard]] ALWAYS_INLINE constexpr ErrorOr<O> try_value_or_lazy_evaluated(this Self&& self, Callback callback)
{
if (static_cast<Self const&>(*this).has_value())
return static_cast<Self const&>(*this).value();
if (self.has_value())
return forward<Self>(self).value();
return TRY(callback());
}
template<typename Callback, typename O = T>
[[nodiscard]] ALWAYS_INLINE constexpr ErrorOr<Optional<O>> try_value_or_lazy_evaluated_optional(Callback callback) const
template<typename Callback, typename O = T, typename Self>
[[nodiscard]] ALWAYS_INLINE constexpr ErrorOr<Optional<O>> try_value_or_lazy_evaluated_optional(this Self&& self, Callback callback)
{
if (static_cast<Self const&>(*this).has_value())
return static_cast<Self const&>(*this).value();
if (self.has_value())
return forward<Self>(self);
return TRY(callback());
}
template<typename Callable>
[[nodiscard]] ALWAYS_INLINE constexpr T& ensure(Callable callable) &
template<typename Callable, typename Self>
[[nodiscard]] ALWAYS_INLINE constexpr T& ensure(this Self& self, Callable callable)
{
if (!static_cast<Self&>(*this).has_value())
static_cast<Self&>(*this) = callable();
return static_cast<Self&>(*this).value();
if (!self.has_value())
self = callable();
return self.value();
}
[[nodiscard]] ALWAYS_INLINE constexpr T const& operator*() const { return static_cast<Self const&>(*this).value(); }
[[nodiscard]] ALWAYS_INLINE constexpr T& operator*() { return static_cast<Self&>(*this).value(); }
template<typename Self>
[[nodiscard]] ALWAYS_INLINE constexpr auto operator*(this Self&& self) -> decltype(forward<Self>(self).value()) { return forward<Self>(self).value(); }
template<typename Self>
[[nodiscard]] ALWAYS_INLINE constexpr AddConstIfNeeded<Self, T>* operator->(this Self&& self) { return &self.value(); }
ALWAYS_INLINE constexpr T const* operator->() const { return &static_cast<Self const&>(*this).value(); }
ALWAYS_INLINE constexpr T* operator->() { return &static_cast<Self&>(*this).value(); }
template<typename F, typename MappedType = decltype(declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
ALWAYS_INLINE constexpr Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(F&& mapper)
template<typename F,
typename MappedType = decltype(declval<F>()(declval<T&>())),
auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>,
typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>,
typename Self>
ALWAYS_INLINE constexpr Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(this Self&& self, F&& mapper)
{
if constexpr (IsErrorOr) {
if (static_cast<Self&>(*this).has_value())
return OptionalType { TRY(mapper(static_cast<Self&>(*this).value())) };
if (self.has_value())
return OptionalType { TRY(mapper(forward<Self>(self).value())) };
return OptionalType {};
} else {
if (static_cast<Self&>(*this).has_value())
return OptionalType { mapper(static_cast<Self&>(*this).value()) };
return OptionalType {};
}
}
template<typename F, typename MappedType = decltype(declval<F>()(declval<T&>())), auto IsErrorOr = IsSpecializationOf<MappedType, ErrorOr>, typename OptionalType = Optional<ConditionallyResultType<IsErrorOr, MappedType>>>
ALWAYS_INLINE constexpr Conditional<IsErrorOr, ErrorOr<OptionalType>, OptionalType> map(F&& mapper) const
{
if constexpr (IsErrorOr) {
if (static_cast<Self const&>(*this).has_value())
return OptionalType { TRY(mapper(static_cast<Self const&>(*this).value())) };
return OptionalType {};
} else {
if (static_cast<Self const&>(*this).has_value())
return OptionalType { mapper(static_cast<Self const&>(*this).value()) };
if (self.has_value())
return OptionalType { mapper(forward<Self>(self).value()) };
return OptionalType {};
}
@@ -170,7 +157,7 @@ public:
};
template<typename T>
requires(!IsLvalueReference<T>) class [[nodiscard]] Optional<T> : public OptionalBase<T, Optional<T>> {
requires(!IsLvalueReference<T>) class [[nodiscard]] Optional<T> : public OptionalBase<T> {
template<typename U>
friend class Optional;
@@ -509,12 +496,12 @@ public:
[[nodiscard]] ALWAYS_INLINE constexpr bool has_value() const { return m_pointer != nullptr; }
[[nodiscard]] ALWAYS_INLINE RemoveReference<T>* ptr()
[[nodiscard]] ALWAYS_INLINE constexpr RemoveReference<T>* ptr()
{
return m_pointer;
}
[[nodiscard]] ALWAYS_INLINE RemoveReference<T> const* ptr() const
[[nodiscard]] ALWAYS_INLINE constexpr RemoveReference<T> const* ptr() const
{
return m_pointer;
}
@@ -532,7 +519,7 @@ public:
}
template<typename U>
requires(IsBaseOf<RemoveReference<T>, U>) [[nodiscard]] ALWAYS_INLINE constexpr AddConstToReferencedType<T> value_or(U& fallback) const
requires(IsBaseOf<RemoveCVReference<T>, U>) [[nodiscard]] ALWAYS_INLINE constexpr AddConstToReferencedType<T> value_or(U& fallback) const
{
if (m_pointer)
return value();
@@ -555,8 +542,8 @@ public:
ALWAYS_INLINE constexpr AddConstToReferencedType<T> operator*() const { return value(); }
ALWAYS_INLINE constexpr T operator*() { return value(); }
ALWAYS_INLINE RawPtr<AddConst<RemoveReference<T>>> operator->() const { return &value(); }
ALWAYS_INLINE RawPtr<RemoveReference<T>> operator->() { return &value(); }
ALWAYS_INLINE constexpr RawPtr<AddConst<RemoveReference<T>>> operator->() const { return &value(); }
ALWAYS_INLINE constexpr RawPtr<RemoveReference<T>> operator->() { return &value(); }
// Conversion operators from Optional<T&> -> Optional<T>, implicit when T is trivially copyable.
ALWAYS_INLINE constexpr operator Optional<RemoveCVReference<T>>() const

View File

@@ -34,7 +34,7 @@ WebIDL::ExceptionOr<GC::Ref<CSSMathClamp>> CSSMathClamp::construct_impl(JS::Real
// 2. Let type be the result of adding the types of lower, value, and upper. If type is failure, throw a TypeError.
auto type = lower_rectified->type()
.added_to(value_rectified->type())
.map([&](auto& type) { return type.added_to(upper_rectified->type()); });
.map([&](auto&& type) { return type.added_to(upper_rectified->type()); });
if (!type.has_value()) {
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Cannot create a CSSMathClamp with values of incompatible types"sv };
}

View File

@@ -555,7 +555,7 @@ Optional<StyleProperty> CSSStyleProperties::get_direct_property(PropertyNameAndI
}
if (property_name_and_id.is_custom_property())
return custom_property(property_name_and_id.name()).map([](auto& it) { return it; });
return custom_property(property_name_and_id.name()).copy();
for (auto const& property : m_properties) {
if (property.property_id == property_id)

View File

@@ -70,7 +70,7 @@ NonnullRefPtr<StyleValue const> LengthOrCalculated::create_style_value() const
Optional<LengthOrAuto> LengthOrAutoOrCalculated::resolve_calculated(NonnullRefPtr<CalculatedStyleValue const> const& calculated, CalculationResolutionContext const& context) const
{
return calculated->resolve_length(context).map([](auto& length) { return LengthOrAuto { length }; });
return calculated->resolve_length(context).map([](auto&& length) { return LengthOrAuto { length }; });
}
NonnullRefPtr<StyleValue const> LengthOrAutoOrCalculated::create_style_value() const

View File

@@ -125,7 +125,7 @@ MatchResult MediaFeature::evaluate(DOM::Document const* document) const
if (queried_value.is_ratio())
return as_match_result(!queried_value.ratio().is_degenerate());
if (queried_value.is_resolution())
return as_match_result(queried_value.resolution().resolved(calculation_context).map([](auto& it) { return it.to_dots_per_pixel(); }).value_or(0) != 0);
return as_match_result(queried_value.resolution().resolved(calculation_context).map([](auto&& it) { return it.to_dots_per_pixel(); }).value_or(0) != 0);
if (queried_value.is_ident()) {
if (media_feature_keyword_is_falsey(m_id, queried_value.ident()))
return MatchResult::False;
@@ -237,8 +237,8 @@ MatchResult MediaFeature::compare(DOM::Document const& document, MediaFeatureVal
}
if (left.is_resolution()) {
auto left_dppx = left.resolution().resolved(calculation_context).map([](auto& it) { return it.to_dots_per_pixel(); }).value_or(0);
auto right_dppx = right.resolution().resolved(calculation_context).map([](auto& it) { return it.to_dots_per_pixel(); }).value_or(0);
auto left_dppx = left.resolution().resolved(calculation_context).map([](auto&& it) { return it.to_dots_per_pixel(); }).value_or(0);
auto right_dppx = right.resolution().resolved(calculation_context).map([](auto&& it) { return it.to_dots_per_pixel(); }).value_or(0);
switch (comparison) {
case Comparison::Equal:

View File

@@ -1229,7 +1229,7 @@ Optional<Rule> Parser::parse_a_rule(TokenStream<T>& input)
// Otherwise, if the next token from input is an <at-keyword-token>,
// consume an at-rule from input, and let rule be the return value.
else if (input.next_token().is(Token::Type::AtKeyword)) {
rule = consume_an_at_rule(m_token_stream).map([](auto& it) { return Rule { it }; });
rule = consume_an_at_rule(m_token_stream).map([](auto&& it) { return Rule { it }; });
}
// Otherwise, consume a qualified rule from input and let rule be the return value.
// If nothing or an invalid rule error was returned, return a syntax error.

View File

@@ -166,7 +166,7 @@ RefPtr<StyleValue const> Parser::parse_coordinating_value_list_shorthand(TokenSt
RefPtr<StyleValue const> Parser::parse_css_value_for_property(PropertyID property_id, TokenStream<ComponentValue>& tokens)
{
return parse_css_value_for_properties({ &property_id, 1 }, tokens)
.map([](auto& it) { return it.style_value; })
.map([](auto&& it) { return it.style_value; })
.value_or(nullptr);
}

View File

@@ -4010,14 +4010,14 @@ Optional<ExplicitGridTrack> Parser::parse_grid_fixed_size(TokenStream<ComponentV
auto const& function_token = token.function();
if (function_token.name.equals_ignoring_ascii_case("minmax"sv)) {
{
GridMinMaxParamParser parse_min = [this](auto& tokens) { return parse_grid_fixed_breadth(tokens).map([](auto& it) { return GridSize(Size::make_length_percentage(it)); }); };
GridMinMaxParamParser parse_min = [this](auto& tokens) { return parse_grid_fixed_breadth(tokens).map([](auto&& it) { return GridSize(Size::make_length_percentage(it)); }); };
GridMinMaxParamParser parse_max = [this](auto& tokens) { return parse_grid_track_breadth(tokens); };
if (auto result = parse_grid_minmax(tokens, parse_min, parse_max); result.has_value())
return result;
}
{
GridMinMaxParamParser parse_min = [this](auto& tokens) { return parse_grid_inflexible_breadth(tokens); };
GridMinMaxParamParser parse_max = [this](auto& tokens) { return parse_grid_fixed_breadth(tokens).map([](auto& it) { return GridSize(Size::make_length_percentage(it)); }); };
GridMinMaxParamParser parse_max = [this](auto& tokens) { return parse_grid_fixed_breadth(tokens).map([](auto&& it) { return GridSize(Size::make_length_percentage(it)); }); };
if (auto result = parse_grid_minmax(tokens, parse_min, parse_max); result.has_value())
return result;
}

View File

@@ -2488,7 +2488,7 @@ RefPtr<StyleValue const> StyleComputer::recascade_font_size_if_needed(DOM::Abstr
VERIFY(font_size_value->is_length());
auto inherited_line_height = ancestor.element_to_inherit_style_from().map([](auto& parent_element) { return parent_element.computed_properties()->line_height(); }).value_or(InitialValues::line_height());
auto inherited_line_height = ancestor.element_to_inherit_style_from().map([](auto&& parent_element) { return parent_element.computed_properties()->line_height(); }).value_or(InitialValues::line_height());
current_size_in_px = font_size_value->as_length().length().to_px(viewport_rect(), Length::FontMetrics { current_size_in_px, monospace_font->with_size(current_size_in_px * 0.75f)->pixel_metrics(), inherited_line_height }, m_root_element_font_metrics);
};

View File

@@ -1271,7 +1271,7 @@ Optional<CalculatedStyleValue::CalculationResult> ClampCalculationNode::run_oper
if (!max_result.has_value())
return {};
auto consistent_type = min_result->type()->consistent_type(center_result->type().value()).map([&](auto& it) { return it.consistent_type(max_result->type().value()); });
auto consistent_type = min_result->type()->consistent_type(center_result->type().value()).map([&](auto&& it) { return it.consistent_type(max_result->type().value()); });
if (!consistent_type.has_value())
return {};

View File

@@ -861,7 +861,7 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_inherited_style()
RefPtr<CSS::StyleValue const> old_animated_value = computed_properties->animated_property_values().get(property_id).value_or({});
RefPtr<CSS::StyleValue const> new_animated_value = CSS::StyleComputer::get_animated_inherit_value(property_id, { *this })
.map([&](auto& value) { return value.ptr(); })
.map([](auto&& value) { return value.ptr(); })
.value_or({});
invalidation |= CSS::compute_property_invalidation(property_id, old_animated_value, new_animated_value);

View File

@@ -1735,7 +1735,7 @@ Optional<Gfx::Filter> PaintableBox::resolve_filter(DisplayListRecordingContext&
.length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(layout_node_with_style_and_box_metrics()),
};
auto to_px = [&](CSS::LengthOrCalculated const& length) {
return static_cast<float>(length.resolved(context).map([&](auto& it) { return it.to_px(layout_node_with_style_and_box_metrics()).to_double(); }).value_or(0.0));
return static_cast<float>(length.resolved(context).map([&](auto&& it) { return it.to_px(layout_node_with_style_and_box_metrics()).to_double(); }).value_or(0.0));
};
// The default value for omitted values is missing length values set to 0
// and the missing used color is taken from the color property.