Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 67 additions & 80 deletions AK/Optional.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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:
Expand All @@ -53,124 +64,100 @@ 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(); }

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 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(); }

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)
{
if constexpr (IsErrorOr) {
if (static_cast<Self&>(*this).has_value())
return OptionalType { TRY(mapper(static_cast<Self&>(*this).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
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 const&>(*this).has_value())
return OptionalType { TRY(mapper(static_cast<Self const&>(*this).value())) };
if (self.has_value())
return OptionalType { TRY(mapper(forward<Self>(self).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 {};
}
}
};

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;

Expand Down Expand Up @@ -509,12 +496,12 @@ requires(IsLvalueReference<T>) class [[nodiscard]] Optional<T> {

[[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;
}
Expand All @@ -532,7 +519,7 @@ requires(IsLvalueReference<T>) class [[nodiscard]] Optional<T> {
}

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();
Expand All @@ -555,8 +542,8 @@ requires(IsLvalueReference<T>) class [[nodiscard]] Optional<T> {
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
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/CSS/CSSMathClamp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
}
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/CSS/CSSStyleProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,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)
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/CSS/CalculatedOr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions Libraries/LibWeb/CSS/MediaQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/CSS/Parser/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,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);
}

Expand Down
4 changes: 2 additions & 2 deletions Libraries/LibWeb/CSS/Parser/ValueParsing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4006,14 +4006,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;
}
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/CSS/StyleComputer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2558,7 +2558,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);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {};

Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/DOM/Element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,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);
Expand Down
2 changes: 1 addition & 1 deletion Libraries/LibWeb/Painting/PaintableBox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1688,7 +1688,7 @@ Optional<Gfx::Filter> 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<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.
Expand Down
Loading