diff --git a/AK/Optional.h b/AK/Optional.h index 6342b7120e73..cd4694073007 100644 --- a/AK/Optional.h +++ b/AK/Optional.h @@ -9,7 +9,11 @@ #pragma once #include +#include +#include #include +#include +#include #include #include #include @@ -33,10 +37,17 @@ struct ConditionallyResultType { using Type = T; }; +template +struct AddConstIfNeeded { + using Type = Conditional> && !IsConst, AddConst, T>; +}; + } template using ConditionallyResultType = typename Detail::ConditionallyResultType::Type; +template +using AddConstIfNeeded = typename Detail::AddConstIfNeeded::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> -requires(!IsLvalueReference) class [[nodiscard]] OptionalBase { +template +requires(!IsLvalueReference) +class [[nodiscard]] OptionalBase { public: using ValueType = T; - template V> - ALWAYS_INLINE constexpr Self& operator=(V) + template V> + ALWAYS_INLINE constexpr Self& operator=(this Self& self, V) { - static_cast(*this).clear(); - return static_cast(*this); + self.clear(); + return self; } - [[nodiscard]] ALWAYS_INLINE constexpr T* ptr() & + template + [[nodiscard]] ALWAYS_INLINE constexpr AddConstIfNeeded* ptr(this Self& self) { - return static_cast(*this).has_value() ? __builtin_launder(reinterpret_cast(&static_cast(*this).value())) : nullptr; + return self.has_value() ? &self.value() : nullptr; } - [[nodiscard]] ALWAYS_INLINE constexpr T const* ptr() const& + template + [[nodiscard]] ALWAYS_INLINE constexpr O value_or(this Self&& self, Fallback&& fallback) { - return static_cast(*this).has_value() ? __builtin_launder(reinterpret_cast(&static_cast(*this).value())) : nullptr; + if (self.has_value()) + return forward(self).value(); + return forward(fallback); } - template - [[nodiscard]] ALWAYS_INLINE constexpr O value_or(Fallback const& fallback) const& + template + [[nodiscard]] ALWAYS_INLINE constexpr O value_or_lazy_evaluated(this Self&& self, Callback callback) { - if (static_cast(*this).has_value()) - return static_cast(*this).value(); - return fallback; - } - - template - requires(!IsLvalueReference && !IsRvalueReference) - [[nodiscard]] ALWAYS_INLINE constexpr O value_or(Fallback&& fallback) && - { - if (static_cast(*this).has_value()) - return move(static_cast(*this).value()); - return move(fallback); - } - - template - [[nodiscard]] ALWAYS_INLINE constexpr O value_or_lazy_evaluated(Callback callback) const - { - if (static_cast(*this).has_value()) - return static_cast(*this).value(); + if (self.has_value()) + return forward(self).value(); return callback(); } - template - [[nodiscard]] ALWAYS_INLINE constexpr Optional value_or_lazy_evaluated_optional(Callback callback) const + template + [[nodiscard]] ALWAYS_INLINE constexpr Optional value_or_lazy_evaluated_optional(this Self&& self, Callback callback) { - if (static_cast(*this).has_value()) - return static_cast(*this).value(); + if (self.has_value()) + return forward(self); return callback(); } - template - [[nodiscard]] ALWAYS_INLINE constexpr ErrorOr try_value_or_lazy_evaluated(Callback callback) const + template + [[nodiscard]] ALWAYS_INLINE constexpr ErrorOr try_value_or_lazy_evaluated(this Self&& self, Callback callback) { - if (static_cast(*this).has_value()) - return static_cast(*this).value(); + if (self.has_value()) + return forward(self).value(); return TRY(callback()); } - template - [[nodiscard]] ALWAYS_INLINE constexpr ErrorOr> try_value_or_lazy_evaluated_optional(Callback callback) const + template + [[nodiscard]] ALWAYS_INLINE constexpr ErrorOr> try_value_or_lazy_evaluated_optional(this Self&& self, Callback callback) { - if (static_cast(*this).has_value()) - return static_cast(*this).value(); + if (self.has_value()) + return forward(self); return TRY(callback()); } - template - [[nodiscard]] ALWAYS_INLINE constexpr T& ensure(Callable callable) & + template + [[nodiscard]] ALWAYS_INLINE constexpr T& ensure(this Self& self, Callable callable) { - if (!static_cast(*this).has_value()) - static_cast(*this) = callable(); - return static_cast(*this).value(); + if (!self.has_value()) + self = callable(); + return self.value(); } - [[nodiscard]] ALWAYS_INLINE constexpr T const& operator*() const { return static_cast(*this).value(); } - [[nodiscard]] ALWAYS_INLINE constexpr T& operator*() { return static_cast(*this).value(); } - - ALWAYS_INLINE constexpr T const* operator->() const { return &static_cast(*this).value(); } - ALWAYS_INLINE constexpr T* operator->() { return &static_cast(*this).value(); } + template + [[nodiscard]] ALWAYS_INLINE constexpr auto operator*(this Self&& self) -> decltype(forward(self).value()) { return forward(self).value(); } + template + [[nodiscard]] ALWAYS_INLINE constexpr AddConstIfNeeded* operator->(this Self&& self) { return &self.value(); } - template()(declval())), auto IsErrorOr = IsSpecializationOf, typename OptionalType = Optional>> - ALWAYS_INLINE constexpr Conditional, OptionalType> map(F&& mapper) - { - if constexpr (IsErrorOr) { - if (static_cast(*this).has_value()) - return OptionalType { TRY(mapper(static_cast(*this).value())) }; - return OptionalType {}; - } else { - if (static_cast(*this).has_value()) - return OptionalType { mapper(static_cast(*this).value()) }; - - return OptionalType {}; - } - } - - template()(declval())), auto IsErrorOr = IsSpecializationOf, typename OptionalType = Optional>> - ALWAYS_INLINE constexpr Conditional, OptionalType> map(F&& mapper) const + template()(declval())), + auto IsErrorOr = IsSpecializationOf, + typename OptionalType = Optional>, + typename Self> + ALWAYS_INLINE constexpr Conditional, OptionalType> map(this Self&& self, F&& mapper) { if constexpr (IsErrorOr) { - if (static_cast(*this).has_value()) - return OptionalType { TRY(mapper(static_cast(*this).value())) }; + if (self.has_value()) + return OptionalType { TRY(mapper(forward(self).value())) }; return OptionalType {}; } else { - if (static_cast(*this).has_value()) - return OptionalType { mapper(static_cast(*this).value()) }; + if (self.has_value()) + return OptionalType { mapper(forward(self).value()) }; return OptionalType {}; } @@ -170,7 +157,7 @@ requires(!IsLvalueReference) class [[nodiscard]] OptionalBase { }; template -requires(!IsLvalueReference) class [[nodiscard]] Optional : public OptionalBase> { +requires(!IsLvalueReference) class [[nodiscard]] Optional : public OptionalBase { template friend class Optional; @@ -509,12 +496,12 @@ requires(IsLvalueReference) class [[nodiscard]] Optional { [[nodiscard]] ALWAYS_INLINE constexpr bool has_value() const { return m_pointer != nullptr; } - [[nodiscard]] ALWAYS_INLINE RemoveReference* ptr() + [[nodiscard]] ALWAYS_INLINE constexpr RemoveReference* ptr() { return m_pointer; } - [[nodiscard]] ALWAYS_INLINE RemoveReference const* ptr() const + [[nodiscard]] ALWAYS_INLINE constexpr RemoveReference const* ptr() const { return m_pointer; } @@ -532,7 +519,7 @@ requires(IsLvalueReference) class [[nodiscard]] Optional { } template - requires(IsBaseOf, U>) [[nodiscard]] ALWAYS_INLINE constexpr AddConstToReferencedType value_or(U& fallback) const + requires(IsBaseOf, U>) [[nodiscard]] ALWAYS_INLINE constexpr AddConstToReferencedType value_or(U& fallback) const { if (m_pointer) return value(); @@ -555,8 +542,8 @@ requires(IsLvalueReference) class [[nodiscard]] Optional { ALWAYS_INLINE constexpr AddConstToReferencedType operator*() const { return value(); } ALWAYS_INLINE constexpr T operator*() { return value(); } - ALWAYS_INLINE RawPtr>> operator->() const { return &value(); } - ALWAYS_INLINE RawPtr> operator->() { return &value(); } + ALWAYS_INLINE constexpr RawPtr>> operator->() const { return &value(); } + ALWAYS_INLINE constexpr RawPtr> operator->() { return &value(); } // Conversion operators from Optional -> Optional, implicit when T is trivially copyable. ALWAYS_INLINE constexpr operator Optional>() const diff --git a/Libraries/LibWeb/CSS/CSSMathClamp.cpp b/Libraries/LibWeb/CSS/CSSMathClamp.cpp index 6c419e06e2a9..8189f2294bc8 100644 --- a/Libraries/LibWeb/CSS/CSSMathClamp.cpp +++ b/Libraries/LibWeb/CSS/CSSMathClamp.cpp @@ -34,7 +34,7 @@ WebIDL::ExceptionOr> 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 }; } diff --git a/Libraries/LibWeb/CSS/CSSStyleProperties.cpp b/Libraries/LibWeb/CSS/CSSStyleProperties.cpp index 0a1bfa6ce353..4f141121143f 100644 --- a/Libraries/LibWeb/CSS/CSSStyleProperties.cpp +++ b/Libraries/LibWeb/CSS/CSSStyleProperties.cpp @@ -559,7 +559,7 @@ Optional 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) diff --git a/Libraries/LibWeb/CSS/CalculatedOr.cpp b/Libraries/LibWeb/CSS/CalculatedOr.cpp index 6faa1caec87c..9bf045ff718f 100644 --- a/Libraries/LibWeb/CSS/CalculatedOr.cpp +++ b/Libraries/LibWeb/CSS/CalculatedOr.cpp @@ -70,7 +70,7 @@ NonnullRefPtr LengthOrCalculated::create_style_value() const Optional LengthOrAutoOrCalculated::resolve_calculated(NonnullRefPtr 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 LengthOrAutoOrCalculated::create_style_value() const diff --git a/Libraries/LibWeb/CSS/MediaQuery.cpp b/Libraries/LibWeb/CSS/MediaQuery.cpp index 588207e4094d..7f6b0b598902 100644 --- a/Libraries/LibWeb/CSS/MediaQuery.cpp +++ b/Libraries/LibWeb/CSS/MediaQuery.cpp @@ -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: diff --git a/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Libraries/LibWeb/CSS/Parser/Parser.cpp index 77a890927eba..4959074b9017 100644 --- a/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -1229,7 +1229,7 @@ Optional Parser::parse_a_rule(TokenStream& input) // Otherwise, if the next token from input is an , // 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. diff --git a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp index e1bb7a63f256..1b20719c4508 100644 --- a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp +++ b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp @@ -165,7 +165,7 @@ RefPtr Parser::parse_coordinating_value_list_shorthand(TokenSt RefPtr Parser::parse_css_value_for_property(PropertyID property_id, TokenStream& 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); } diff --git a/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp b/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp index b1cff7ccc2af..04e1adc2743c 100644 --- a/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp +++ b/Libraries/LibWeb/CSS/Parser/ValueParsing.cpp @@ -4006,14 +4006,14 @@ Optional Parser::parse_grid_fixed_size(TokenStream 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); }; diff --git a/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp index 279ebb399c57..ac52c4bfd803 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp @@ -1271,7 +1271,7 @@ Optional 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 {}; diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index 7dfd3d28a81e..187f51991c11 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -852,7 +852,7 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_inherited_style() RefPtr old_animated_value = computed_properties->animated_property_values().get(property_id).value_or({}); RefPtr 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); diff --git a/Libraries/LibWeb/Painting/PaintableBox.cpp b/Libraries/LibWeb/Painting/PaintableBox.cpp index 3e00a7c32616..ed85e3708a7c 100644 --- a/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -1688,7 +1688,7 @@ Optional PaintableBox::resolve_filter(CSS::Filter const& computed_f .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(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(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.