mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-05 01:10:24 +00:00
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:
committed by
Jelle Raaijmakers
parent
fd4888e800
commit
bcd01da91d
Notes:
github-actions[bot]
2025-11-20 15:28:30 +00:00
Author: https://github.com/Hendiadyoin1 Commit: https://github.com/LadybirdBrowser/ladybird/commit/bcd01da91d3 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6782
147
AK/Optional.h
147
AK/Optional.h
@@ -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
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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 {};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user