diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index e3291a465bc203..d51189d4c1c646 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -17,27 +17,27 @@ runs: if: ${{ inputs.os == 'Linux' }} shell: bash run: | - # These packages are already part of the ubuntu-22.04 image: + # These packages are already part of the ubuntu-24.04 image: # cmake libgmp-dev npm shellcheck # Packages below aren't. set -e wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main' + sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-18 main' sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update - sudo apt-get install ccache clang-18 clang++-18 clang-format-18 lld-18 gcc-13 g++-13 libstdc++-13-dev ninja-build unzip qt6-base-dev qt6-tools-dev-tools libqt6svg6-dev qt6-multimedia-dev libgl1-mesa-dev libpulse-dev libssl-dev libegl1-mesa-dev libclang-18-dev + sudo apt-get install ccache clang-18 clang++-18 clang-format-18 lld-18 gcc-14 g++-14 libstdc++-13-dev ninja-build unzip qt6-base-dev qt6-tools-dev-tools libqt6svg6-dev qt6-multimedia-dev libgl1-mesa-dev libpulse-dev libssl-dev libegl1-mesa-dev libclang-18-dev - sudo apt-get remove clang-{13,14,15} clang++-{13,14,15} libclang-{13,14,15}-dev llvm-{13,14,15} + sudo apt-get remove clang-{14,15} clang++-{14,15} libclang-{14,15}-dev llvm-{14,15} sudo apt-get install clang-18 clang++-18 llvm-18 llvm-18-dev sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-18 100 sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 100 - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 100 - sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 100 + sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100 + sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100 wget https://github.com/WebAssembly/wabt/releases/download/1.0.35/wabt-1.0.35-ubuntu-20.04.tar.gz tar -xzf ./wabt-1.0.35-ubuntu-20.04.tar.gz @@ -63,13 +63,13 @@ runs: set -e wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main' + sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-18 main' sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update - sudo apt-get remove clang-{13,14,15} clang++-{13,14,15} libclang-{13,14,15}-dev llvm-{13,14,15} - sudo apt-get install clang-format-18 ccache e2fsprogs gcc-13 g++-13 libstdc++-13-dev libmpfr-dev libmpc-dev ninja-build optipng qemu-utils qemu-system-i386 unzip generate-ninja libegl1-mesa-dev + sudo apt-get remove clang-{14,15} clang++-{14,15} libclang-{14,15}-dev llvm-{14,15} + sudo apt-get install clang-format-18 ccache e2fsprogs gcc-14 g++-14 libstdc++-13-dev libmpfr-dev libmpc-dev ninja-build optipng qemu-utils qemu-system-i386 unzip generate-ninja libegl1-mesa-dev sudo apt-get install clang-18 clang++-18 llvm-18 llvm-18-dev - name: Enable KVM group perms diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d23030322ee32..188dd4dfc087e6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,22 +14,22 @@ jobs: fail-fast: false matrix: toolchain: ['GNU', 'Clang'] - os: [ubuntu-22.04] + os: [ubuntu-24.04] arch: ['x86_64'] debug_options: ['NORMAL_DEBUG'] include: - toolchain: 'GNU' - os: ubuntu-22.04 + os: ubuntu-24.04 arch: 'aarch64' debug_options: 'NORMAL_DEBUG' - toolchain: 'GNU' - os: ubuntu-22.04 + os: ubuntu-24.04 arch: 'riscv64' debug_options: 'NORMAL_DEBUG' - toolchain: 'GNU' - os: ubuntu-22.04 + os: ubuntu-24.04 arch: 'x86_64' debug_options: 'ALL_DEBUG' @@ -47,7 +47,7 @@ jobs: fail-fast: false matrix: os_name: ['Linux'] - os: [ubuntu-22.04] + os: [ubuntu-24.04] fuzzer: ['NO_FUZZ', 'FUZZ'] include: - os_name: 'macOS' diff --git a/.github/workflows/discord.yml b/.github/workflows/discord.yml index c5cd2447d3fbbd..4e7aae7f700b10 100644 --- a/.github/workflows/discord.yml +++ b/.github/workflows/discord.yml @@ -4,7 +4,7 @@ on: [push, pull_request_target] jobs: notify_discord: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: always() && github.repository == 'SerenityOS/serenity' && (github.event_name == 'pull_request_target' || (github.event_name == 'push' && github.ref == 'refs/heads/master')) steps: diff --git a/.github/workflows/label-pull-requests.yml b/.github/workflows/label-pull-requests.yml index 3e079b81503f1b..9f63dec032d405 100644 --- a/.github/workflows/label-pull-requests.yml +++ b/.github/workflows/label-pull-requests.yml @@ -11,7 +11,7 @@ on: jobs: label_pull_request: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: always() && github.repository == 'SerenityOS/serenity' steps: diff --git a/.github/workflows/lagom-template.yml b/.github/workflows/lagom-template.yml index 6ab0fb4cc52901..447b6b633b112a 100644 --- a/.github/workflows/lagom-template.yml +++ b/.github/workflows/lagom-template.yml @@ -67,8 +67,8 @@ jobs: echo "host_cc=clang-18" >> "$GITHUB_OUTPUT" echo "host_cxx=clang++-18" >> "$GITHUB_OUTPUT" elif ${{ inputs.toolchain == 'GNU' }} ; then - echo "host_cc=gcc-13" >> "$GITHUB_OUTPUT" - echo "host_cxx=g++-13" >> "$GITHUB_OUTPUT" + echo "host_cc=gcc-14" >> "$GITHUB_OUTPUT" + echo "host_cxx=g++-14" >> "$GITHUB_OUTPUT" fi elif ${{ inputs.os_name == 'macOS' }} ; then echo "host_cc=$(brew --prefix llvm@18)/bin/clang" >> "$GITHUB_OUTPUT" @@ -82,7 +82,7 @@ jobs: - name: Build jakt toolchain if: ${{ steps.cache-restore.output.jakt_prebuilt_hit != 'true' }} - run: "ARCH=\"${{ inputs.arch }}\" CXX=g++-13 ${{ github.workspace }}/Toolchain/BuildJakt.sh lagom" + run: "ARCH=\"${{ inputs.arch }}\" CXX=g++-14 ${{ github.workspace }}/Toolchain/BuildJakt.sh lagom" - name: Create Build Environment @@ -110,8 +110,8 @@ jobs: -DBUILD_LAGOM=OFF \ -DCMAKE_INSTALL_PREFIX=tool-install \ -DSERENITY_CACHE_DIR=${{ github.workspace }}/Build/caches \ - -DCMAKE_C_COMPILER=gcc-13 \ - -DCMAKE_CXX_COMPILER=g++-13 \ + -DCMAKE_C_COMPILER=gcc-14 \ + -DCMAKE_CXX_COMPILER=g++-14 \ -Dpackage=LagomTools ninja -C tools-build install diff --git a/.github/workflows/lintcommits.yml b/.github/workflows/lintcommits.yml index cb4433d842a879..4da31c4fc28ece 100644 --- a/.github/workflows/lintcommits.yml +++ b/.github/workflows/lintcommits.yml @@ -7,7 +7,7 @@ on: [pull_request_target] jobs: lint_commits: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: always() && github.repository == 'SerenityOS/serenity' steps: diff --git a/.github/workflows/manpages.yml b/.github/workflows/manpages.yml index 9f36e7195d5990..48b6190d43950d 100644 --- a/.github/workflows/manpages.yml +++ b/.github/workflows/manpages.yml @@ -8,7 +8,7 @@ on: jobs: convert_using_pandoc: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: always() && github.repository == 'SerenityOS/serenity' && github.ref == 'refs/heads/master' steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 0edd252e28ac79..b91b7249f3cc2a 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -19,7 +19,7 @@ jobs: uses: ./.github/workflows/serenity-template.yml with: toolchain: 'Clang' - os: ubuntu-22.04 + os: ubuntu-24.04 arch: 'x86_64' coverage: 'ON' @@ -33,4 +33,4 @@ jobs: with: toolchain: 'GNU' os_name: 'Linux' - os: ubuntu-22.04 + os: ubuntu-24.04 diff --git a/.github/workflows/serenity-template.yml b/.github/workflows/serenity-template.yml index f32c635c213e5e..199b77006889cc 100644 --- a/.github/workflows/serenity-template.yml +++ b/.github/workflows/serenity-template.yml @@ -87,7 +87,7 @@ jobs: - name: Build jakt toolchain if: ${{ steps.cache-restore.output.jakt_prebuilt_hit != 'true' }} - run: ARCH="${{ inputs.arch }}" CXX=g++-13 ${{ github.workspace }}/Toolchain/BuildJakt.sh + run: ARCH="${{ inputs.arch }}" CXX=g++-14 ${{ github.workspace }}/Toolchain/BuildJakt.sh - name: Create Build Environment if: ${{ inputs.debug_options == 'ALL_DEBUG' }} @@ -98,8 +98,8 @@ jobs: -DSERENITY_ARCH=${{ inputs.arch }} \ -DSERENITY_TOOLCHAIN=${{ inputs.toolchain }} \ -DBUILD_LAGOM=ON \ - -DCMAKE_C_COMPILER=gcc-13 \ - -DCMAKE_CXX_COMPILER=g++-13 \ + -DCMAKE_C_COMPILER=gcc-14 \ + -DCMAKE_CXX_COMPILER=g++-14 \ -DENABLE_ALL_DEBUG_FACILITIES=ON \ -DENABLE_PCI_IDS_DOWNLOAD=OFF \ -DENABLE_USB_IDS_DOWNLOAD=OFF @@ -115,8 +115,8 @@ jobs: cmake -S Meta/CMake/Superbuild -B Build/superbuild -GNinja \ -DSERENITY_ARCH=${{ inputs.arch }} \ -DSERENITY_TOOLCHAIN=${{ inputs.toolchain }} \ - -DCMAKE_C_COMPILER=gcc-13 \ - -DCMAKE_CXX_COMPILER=g++-13 \ + -DCMAKE_C_COMPILER=gcc-14 \ + -DCMAKE_CXX_COMPILER=g++-14 \ -DENABLE_UNDEFINED_SANITIZER=ON \ -DUNDEFINED_BEHAVIOR_IS_FATAL=ON \ -DENABLE_USERSPACE_COVERAGE_COLLECTION=${{ inputs.coverage }} \ diff --git a/.github/workflows/social-media.yml b/.github/workflows/social-media.yml index a6e6b03356f695..b275f5e988c6cc 100644 --- a/.github/workflows/social-media.yml +++ b/.github/workflows/social-media.yml @@ -4,7 +4,7 @@ on: [ push ] jobs: notify_twitter: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: always() && github.repository == 'SerenityOS/serenity' && github.ref == 'refs/heads/master' steps: @@ -24,7 +24,7 @@ jobs: ACCESS_TOKEN_SECRET: ${{ secrets.ACCESS_TOKEN_SECRET }} notify_mastodon: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: always() && github.repository == 'SerenityOS/serenity' && github.ref == 'refs/heads/master' steps: diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 4b9058d9b60d46..74c044ec0bbfb1 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -9,7 +9,7 @@ concurrency: wasm jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: github.repository == 'SerenityOS/serenity' strategy: fail-fast: false @@ -53,8 +53,8 @@ jobs: -S ${{ github.workspace }}/Meta/Lagom \ -DBUILD_LAGOM=OFF \ -DSERENITY_CACHE_DIR=${{ github.workspace }}/Build/caches \ - -DCMAKE_C_COMPILER=gcc-13 \ - -DCMAKE_CXX_COMPILER=g++-13 \ + -DCMAKE_C_COMPILER=gcc-14 \ + -DCMAKE_CXX_COMPILER=g++-14 \ -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/Build/lagom-tools \ -Dpackage=LagomTools ninja -C ${{ github.workspace }}/Build/lagom-tools install diff --git a/AK/Badge.h b/AK/Badge.h index 01b3d198ca3092..4346f24999995c 100644 --- a/AK/Badge.h +++ b/AK/Badge.h @@ -15,8 +15,8 @@ class Badge { public: using Type = T; - Badge(Badge&&) = default; - Badge& operator=(Badge&&) = default; + constexpr Badge(Badge&&) = default; + constexpr Badge& operator=(Badge&&) = default; private: friend T; diff --git a/AK/FlyString.h b/AK/FlyString.h index fd2c21e51a9ec7..4e3854aa7458a8 100644 --- a/AK/FlyString.h +++ b/AK/FlyString.h @@ -15,6 +15,9 @@ namespace AK { +template<> +struct Traits; + class FlyString { AK_MAKE_DEFAULT_MOVABLE(FlyString); AK_MAKE_DEFAULT_COPYABLE(FlyString); @@ -79,6 +82,12 @@ class FlyString { return (... || this->operator==(forward(strings))); } + FlyString(Badge>) + : m_data(nullptr) + { + } + ALWAYS_INLINE constexpr bool is_null(Badge> badge) { return m_data.is_null(move(badge)); } + private: explicit FlyString(Detail::StringBase data) : m_data(move(data)) @@ -91,6 +100,9 @@ class FlyString { template<> struct Traits : public DefaultTraits { static unsigned hash(FlyString const&); + + constexpr static auto special_optional_empty_value(Badge> badge) { return FlyString(move(badge)); } + constexpr static bool optional_has_value(String const& str) { return !str.is_null(Badge> {}); } }; template<> diff --git a/AK/IPv4Address.h b/AK/IPv4Address.h index a32653a2e2b20e..4247cfd1fa69cc 100644 --- a/AK/IPv4Address.h +++ b/AK/IPv4Address.h @@ -23,6 +23,10 @@ namespace AK { +class IPv4Address; +template<> +struct Traits; + class [[gnu::packed]] IPv4Address { enum class SubnetClass : int { A = 0, diff --git a/AK/IPv6Address.h b/AK/IPv6Address.h index 9282e663b62ecd..3ca3c1e1f9dd5a 100644 --- a/AK/IPv6Address.h +++ b/AK/IPv6Address.h @@ -24,6 +24,10 @@ namespace AK { +class IPv6Address; +template<> +struct Traits; + class [[gnu::packed]] IPv6Address { public: using in6_addr_t = u8[16]; diff --git a/AK/MACAddress.h b/AK/MACAddress.h index b948575e5ad6f9..a10289d07f69ce 100644 --- a/AK/MACAddress.h +++ b/AK/MACAddress.h @@ -18,6 +18,12 @@ # include #endif +namespace AK { + +class MACAddress; +template<> +struct Traits; + class [[gnu::packed]] MACAddress { static constexpr size_t s_mac_address_length = 6u; @@ -108,11 +114,13 @@ class [[gnu::packed]] MACAddress { static_assert(sizeof(MACAddress) == 6u); -namespace AK { - template<> struct Traits : public DefaultTraits { static unsigned hash(MACAddress const& address) { return string_hash((char const*)&address, sizeof(address)); } }; } + +#if USING_AK_GLOBALLY +using AK::MACAddress; +#endif diff --git a/AK/NonnullOwnPtr.h b/AK/NonnullOwnPtr.h index e8ab1ab139eb3b..c4c686e3db82dd 100644 --- a/AK/NonnullOwnPtr.h +++ b/AK/NonnullOwnPtr.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include #include @@ -126,7 +127,11 @@ class [[nodiscard]] NonnullOwnPtr { return NonnullOwnPtr(NonnullOwnPtr::Adopt, static_cast(*leak_ptr())); } + constexpr NonnullOwnPtr(Badge>>) { } + private: + friend struct Traits>; + void clear() { auto* ptr = exchange(m_ptr, nullptr); @@ -192,6 +197,10 @@ struct Traits> : public DefaultTraits> { using ConstPeekType = T const*; static unsigned hash(NonnullOwnPtr const& p) { return ptr_hash(p.ptr()); } static bool equals(NonnullOwnPtr const& a, NonnullOwnPtr const& b) { return a.ptr() == b.ptr(); } + + constexpr static auto special_optional_empty_value(Badge>> badge) { return NonnullOwnPtr(move(badge)); } + constexpr static bool optional_has_value(NonnullOwnPtr const& ptr) { return ptr.m_ptr != nullptr; } + constexpr static bool optional_dont_move_empty = true; }; template diff --git a/AK/NonnullRefPtr.h b/AK/NonnullRefPtr.h index 24cdd781f04521..5e452f58ff1212 100644 --- a/AK/NonnullRefPtr.h +++ b/AK/NonnullRefPtr.h @@ -6,13 +6,14 @@ #pragma once -#define NONNULLREFPTR_SCRUB_BYTE 0xe1 - #include +#include #include #include #include +#define NONNULLREFPTR_SCRUB_BYTE 0xe1 + namespace AK { template @@ -207,6 +208,9 @@ class [[nodiscard]] NonnullRefPtr { return m_ptr == other; } + constexpr NonnullRefPtr(Badge>>) + : m_ptr(nullptr) {}; + private: NonnullRefPtr() = delete; @@ -294,6 +298,9 @@ struct Traits> : public DefaultTraits> { using ConstPeekType = T const*; static unsigned hash(NonnullRefPtr const& p) { return ptr_hash(p.ptr()); } static bool equals(NonnullRefPtr const& a, NonnullRefPtr const& b) { return a.ptr() == b.ptr(); } + + constexpr static auto special_optional_empty_value(Badge>> badge) { return NonnullRefPtr(move(badge)); } + constexpr static bool optional_dont_move_empty = true; }; } diff --git a/AK/Optional.h b/AK/Optional.h index 1646e16a83e6ca..e979afbd8e7149 100644 --- a/AK/Optional.h +++ b/AK/Optional.h @@ -53,7 +53,91 @@ struct OptionalNone { }; template -requires(!IsLvalueReference) class [[nodiscard]] Optional { +requires(!IsLvalueReference) +class [[nodiscard]] OptionalBase { +public: + using ValueType = T; + + template V> + ALWAYS_INLINE constexpr Self& operator=(this Self& self, V) + { + self.clear(); + return self; + } + + template + [[nodiscard]] ALWAYS_INLINE constexpr T* ptr(this Self& self) + { + return self.has_value() ? &self.value() : nullptr; + } + + template + [[nodiscard]] ALWAYS_INLINE constexpr O value_or(this Self&& self, Fallback&& fallback) + { + if (self.has_value()) + return forward(self).value(); + return forward(fallback); + } + + template + [[nodiscard]] ALWAYS_INLINE constexpr O value_or_lazy_evaluated(this Self const& self, Callback callback) + { + if (self.has_value()) + return self.value(); + return callback(); + } + + template + [[nodiscard]] ALWAYS_INLINE constexpr Optional value_or_lazy_evaluated_optional(this Self const& self, Callback callback) + { + if (self.has_value()) + return self.value(); + return callback(); + } + + template + [[nodiscard]] ALWAYS_INLINE constexpr ErrorOr try_value_or_lazy_evaluated(this Self const& self, Callback callback) + { + if (self.has_value()) + return self.value(); + return TRY(callback()); + } + + template + [[nodiscard]] ALWAYS_INLINE constexpr ErrorOr> try_value_or_lazy_evaluated_optional(this Self const& self, Callback callback) + { + if (self.has_value()) + return self.value(); + return TRY(callback()); + } + + template + [[nodiscard]] ALWAYS_INLINE constexpr CopyConst, T>& operator*(this Self&& self) { return self.value(); } + template + ALWAYS_INLINE constexpr CopyConst, T>* operator->(this Self&& self) { return &self.value(); } + + template()(declval())), + auto IsErrorOr = IsSpecializationOf, + typename OptionalType = Optional>> + ALWAYS_INLINE constexpr Conditional, OptionalType> map(this Self&& self, F&& mapper) + { + if constexpr (IsErrorOr) { + if (self.has_value()) + return OptionalType { TRY(mapper(forward(self).value())) }; + return OptionalType {}; + } else { + if (self.has_value()) + return OptionalType { mapper(forward(self).value()) }; + + return OptionalType {}; + } + } +}; + +template +requires(!IsLvalueReference && !requires { Traits::special_optional_empty_value; }) +class [[nodiscard]] Optional : public OptionalBase { template friend class Optional; @@ -304,88 +388,6 @@ requires(!IsLvalueReference) class [[nodiscard]] Optional { return released_value; } - [[nodiscard]] ALWAYS_INLINE constexpr T value_or(T const& fallback) const& - { - if (m_has_value) - return value(); - return fallback; - } - - [[nodiscard]] ALWAYS_INLINE constexpr T value_or(T&& fallback) && - { - if (m_has_value) - return move(value()); - return move(fallback); - } - - template - [[nodiscard]] ALWAYS_INLINE constexpr T value_or_lazy_evaluated(Callback callback) const - { - if (m_has_value) - return value(); - return callback(); - } - - template - [[nodiscard]] ALWAYS_INLINE constexpr Optional value_or_lazy_evaluated_optional(Callback callback) const - { - if (m_has_value) - return value(); - return callback(); - } - - template - [[nodiscard]] ALWAYS_INLINE constexpr ErrorOr try_value_or_lazy_evaluated(Callback callback) const - { - if (m_has_value) - return value(); - return TRY(callback()); - } - - template - [[nodiscard]] ALWAYS_INLINE constexpr ErrorOr> try_value_or_lazy_evaluated_optional(Callback callback) const - { - if (m_has_value) - return value(); - return TRY(callback()); - } - - ALWAYS_INLINE constexpr T const& operator*() const { return value(); } - ALWAYS_INLINE constexpr T& operator*() { return value(); } - - ALWAYS_INLINE constexpr T const* operator->() const { return &value(); } - ALWAYS_INLINE constexpr T* operator->() { return &value(); } - - template()(declval())), auto IsErrorOr = IsSpecializationOf, typename OptionalType = Optional>> - ALWAYS_INLINE constexpr Conditional, OptionalType> map(F&& mapper) - { - if constexpr (IsErrorOr) { - if (m_has_value) - return OptionalType { TRY(mapper(value())) }; - return OptionalType {}; - } else { - if (m_has_value) - return OptionalType { mapper(value()) }; - - return OptionalType {}; - } - } - - template()(declval())), auto IsErrorOr = IsSpecializationOf, typename OptionalType = Optional>> - ALWAYS_INLINE constexpr Conditional, OptionalType> map(F&& mapper) const - { - if constexpr (IsErrorOr) { - if (m_has_value) - return OptionalType { TRY(mapper(value())) }; - return OptionalType {}; - } else { - if (m_has_value) - return OptionalType { mapper(value()) }; - - return OptionalType {}; - } - } - private: union { // FIXME: GCC seems to have an issue with uninitialized unions and non trivial types, @@ -401,6 +403,7 @@ requires(!IsLvalueReference) class [[nodiscard]] Optional { template requires(IsLvalueReference) class [[nodiscard]] Optional { + // Note: This can't be based on OptionalBase, does not work with T&'s. template friend class Optional; @@ -629,6 +632,189 @@ requires(IsLvalueReference) class [[nodiscard]] Optional { RemoveReference* m_pointer { nullptr }; }; +template +requires(requires { Traits::special_optional_empty_value; }) +class [[nodiscard]] Optional : public OptionalBase { + + // Note: We need to go through this helper to not materialize a temporary at compile time + // which needs to be destroyed at compile time. + ALWAYS_INLINE constexpr static auto the_empty_value() -> T + { + if constexpr (IsSame::special_optional_empty_value), T>) + return Traits::special_optional_empty_value; + else if constexpr (IsCallableWithArguments::special_optional_empty_value), T>) + return Traits::special_optional_empty_value(); + else if constexpr (IsCallableWithArguments::special_optional_empty_value), T, Badge>>) + return Traits::special_optional_empty_value(Badge> {}); + } + + // Note: Some types don't like to be moved/touched when in their empty state, + // so we need to special case them + constexpr static bool dont_move_empty = requires { + Traits::optional_dont_move_empty; + requires(Traits::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 + +public: + ALWAYS_INLINE constexpr Optional() = default; + ALWAYS_INLINE constexpr Optional(OptionalNone) { } + template + requires(IsConstructible && !IsOneOf, Optional, OptionalNone>) + ALWAYS_INLINE constexpr Optional(U&& value) + : m_value(forward(value)) + { + } + + ALWAYS_INLINE constexpr Optional(Optional const&) = default; + ALWAYS_INLINE constexpr Optional& operator=(Optional const&) = default; + ALWAYS_INLINE constexpr Optional(Optional&&) = default; + ALWAYS_INLINE constexpr Optional& operator=(Optional&&) = default; + + ALWAYS_INLINE constexpr Optional(Optional const& other) + requires(dont_move_empty) + : m_value(other.has_value() ? other.value() : the_empty_value()) + { + } + ALWAYS_INLINE constexpr Optional& operator=(Optional const& other) + requires(dont_move_empty) + { + if (this == &other) + return *this; + + if (other.has_value()) + m_value = other.value(); + else + clear(); + return *this; + } + + ALWAYS_INLINE constexpr Optional(Optional&& other) + requires(dont_move_empty && !has_swap) + : m_value(other.has_value() ? other.release_value() : the_empty_value()) + { + } + ALWAYS_INLINE constexpr Optional& operator=(Optional&& other) + requires(dont_move_empty && !has_swap) + { + if (this == &other) + return *this; + + if (has_value() && other.has_value()) + value() = other.release_value(); + else if (has_value()) + clear(); + else if (other.has_value()) + m_value = other.release_value(); + + return *this; + } + + ALWAYS_INLINE constexpr Optional(Optional&& other) + requires(dont_move_empty && has_swap) + { + swap(m_value, other.m_value); + other.clear(); + } + ALWAYS_INLINE constexpr Optional& operator=(Optional&& other) + requires(dont_move_empty && has_swap) + { + if (this == &other) + return *this; + + swap(m_value, other.m_value); + other.clear(); + return *this; + } + + ALWAYS_INLINE constexpr bool operator==(Optional const& other) const + { + return has_value() == other.has_value() && (!has_value() || value() == other.value()); + } + + template + requires( + !IsScalar && IsConstructible + && !IsOneOf, Optional, OptionalNone>) + ALWAYS_INLINE constexpr Optional& operator=(U const& value) + { + m_value = value; + return *this; + } + template + requires( + !IsScalar && IsConstructible + && !IsOneOf, Optional, OptionalNone>) + ALWAYS_INLINE constexpr Optional& operator=(U&& value) + { + m_value = forward(value); + return *this; + } + + ALWAYS_INLINE constexpr bool has_value() const + { + return m_value != the_empty_value(); + } + ALWAYS_INLINE constexpr bool has_value() const + requires(requires(T const& t) {{ Traits::optional_has_value(t) } -> SameAs; }) + { + return Traits::optional_has_value(m_value); + } + ALWAYS_INLINE constexpr void clear() + { + if (has_value()) + (void)release_value(); + } + + ALWAYS_INLINE constexpr T& value() & + { + VERIFY(has_value()); + return m_value; + } + ALWAYS_INLINE constexpr T const& value() const& + { + VERIFY(has_value()); + return m_value; + } + + ALWAYS_INLINE constexpr T value() && { return release_value(); } + + ALWAYS_INLINE constexpr T release_value() + { + // FIXME: What to do here when we should not move empties around, + // But don't have a swap method to place it in? + VERIFY(has_value()); + return exchange(m_value, the_empty_value()); + } + + ALWAYS_INLINE constexpr T release_value() + requires(dont_move_empty && has_swap) + { + VERIFY(has_value()); + T value = the_empty_value(); + value.swap(m_value); + return value; + } + + template + requires(IsConstructible) + ALWAYS_INLINE constexpr void emplace(Ts&&... parameters) + { + clear(); + m_value = T(forward(parameters)...); + } + +private: + T m_value { the_empty_value() }; +}; + } #if USING_AK_GLOBALLY diff --git a/AK/String.h b/AK/String.h index 3ca2ace489a2e2..f880ed3549d824 100644 --- a/AK/String.h +++ b/AK/String.h @@ -202,6 +202,11 @@ class String : public Detail::StringBase { requires(IsSame, StringView>) static ErrorOr from_byte_string(T&&) = delete; + constexpr String(Badge>) + : StringBase(nullptr) + { + } + private: friend class ::AK::FlyString; @@ -216,6 +221,9 @@ class String : public Detail::StringBase { template<> struct Traits : public DefaultTraits { static unsigned hash(String const&); + + constexpr static auto special_optional_empty_value(Badge> badge) { return String(move(badge)); } + constexpr static bool optional_has_value(String const& str) { return !str.is_null(Badge> {}); } }; template<> diff --git a/AK/StringBase.cpp b/AK/StringBase.cpp index 62746b91a58495..4cb4a139f9ed2b 100644 --- a/AK/StringBase.cpp +++ b/AK/StringBase.cpp @@ -117,7 +117,7 @@ ErrorOr StringBase::substring_from_byte_offset_with_shared_superstri void StringBase::destroy_string() { - if (!is_short_string()) + if (!is_short_string() && m_raw != 0) m_data->unref(); } diff --git a/AK/StringBase.h b/AK/StringBase.h index 541f7b8bdded4d..b07d8e10dfff0e 100644 --- a/AK/StringBase.h +++ b/AK/StringBase.h @@ -69,9 +69,17 @@ class StringBase { [[nodiscard]] bool operator==(StringBase const&) const; - [[nodiscard]] ALWAYS_INLINE FlatPtr raw(Badge) const { return bit_cast(m_data); } + [[nodiscard]] ALWAYS_INLINE FlatPtr raw(Badge) const { return m_raw; } + template T> + [[nodiscard]] ALWAYS_INLINE constexpr bool is_null(Badge>) const { return m_raw; } protected: + // For Optional + constexpr explicit StringBase(nullptr_t) + : m_raw { 0 } + { + } + template ErrorOr replace_with_new_string(size_t byte_count, Func&& callback) { @@ -124,6 +132,7 @@ class StringBase { union { ShortString m_short_string; Detail::StringData const* m_data { nullptr }; + FlatPtr m_raw; }; }; diff --git a/Documentation/BuildInstructions.md b/Documentation/BuildInstructions.md index 53e40702d370ca..ad0879db6c435d 100644 --- a/Documentation/BuildInstructions.md +++ b/Documentation/BuildInstructions.md @@ -12,11 +12,11 @@ sudo apt install build-essential cmake curl libmpfr-dev libmpc-dev libgmp-dev e2 Optional: `fuse2fs` for [building images without root](https://github.com/SerenityOS/serenity/pull/11224). -#### GCC 13 or Clang 17+ +#### GCC 14 or Clang 18+ -A host compiler that supports C++23 features is required for building host tools, the newer the better. Tested versions include gcc-13 and Clang 17 through 19. +A host compiler that supports C++23 features is required for building host tools, the newer the better. Tested versions include gcc-14 and Clang 18 through 19. -On Ubuntu gcc-13 is available in the repositories of 24.04 (Noble) and later. +On Ubuntu gcc-14 is available in the repositories of 24.04 (Noble) and later. If you are running an older version, you will either need to upgrade, or find an alternative installation source (i.e. from the [ubuntu-toolchain-r/test PPA](https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test)). @@ -28,10 +28,10 @@ Next, update your local package information from the new repositories: sudo apt update ``` -Now on Ubuntu or Debian you can install gcc-13 with apt like this: +Now on Ubuntu or Debian you can install gcc-14 with apt like this: ```console -sudo apt install gcc-13 g++-13 +sudo apt install gcc-14 g++-14 ``` For Clang, the following packages are required (for example Clang 19). Note that the `-dev` packages are only necessary when jakt is enabled. diff --git a/Documentation/BuildInstructionsLadybird.md b/Documentation/BuildInstructionsLadybird.md index a5ae37656413ed..7a34d55fc74fef 100644 --- a/Documentation/BuildInstructionsLadybird.md +++ b/Documentation/BuildInstructionsLadybird.md @@ -5,7 +5,7 @@ ## Build Prerequisites -Qt6 development packages and a C++23 capable compiler are required. g++-13 or clang-17 are required at a minimum for c++23 support. +Qt6 development packages and a C++23 capable compiler are required. g++-14 or clang-18 are required at a minimum for c++23 support. NOTE: In all of the below lists of packages, the Qt6 multimedia package is not needed if your Linux system supports PulseAudio. diff --git a/Documentation/SelfHostedRunners.md b/Documentation/SelfHostedRunners.md index 6fb595c0e509e3..12dd08104a8163 100644 --- a/Documentation/SelfHostedRunners.md +++ b/Documentation/SelfHostedRunners.md @@ -25,13 +25,13 @@ sudo add-apt-repository ppa:canonical-server/server-backports wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main' apt update -apt install git build-essential make cmake clang-format-16 gcc-13 g++-13 libstdc++-13-dev libgmp-dev ccache libmpfr-dev libmpc-dev ninja-build e2fsprogs qemu-utils qemu-system-i386 wabt +apt install git build-essential make cmake clang-format-16 gcc-14 g++-14 libstdc++-13-dev libgmp-dev ccache libmpfr-dev libmpc-dev ninja-build e2fsprogs qemu-utils qemu-system-i386 wabt ``` ### Force usage of GCC 13 ```shell -update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 100 --slave /usr/bin/g++ g++ /usr/bin/g++-13 +update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100 --slave /usr/bin/g++ g++ /usr/bin/g++-14 ``` ### Create a new user account named 'runner' diff --git a/Documentation/Troubleshooting.md b/Documentation/Troubleshooting.md index 56e528c2fc0c91..ab737eb2aff6a8 100644 --- a/Documentation/Troubleshooting.md +++ b/Documentation/Troubleshooting.md @@ -43,9 +43,9 @@ If this happens, run `Meta/serenity.sh rebuild x86_64` to start over from a fres ### GCC is missing or is outdated -Ensure your gcc version is >= 13 with `gcc --version`. Otherwise, install it. If your gcc binary is not +Ensure your gcc version is >= 14 with `gcc --version`. Otherwise, install it. If your gcc binary is not called `gcc` you have to specify the names of your C and C++ compiler when you run cmake, e.g. -`cmake ../.. -GNinja -DCMAKE_C_COMPILER=gcc-13 -DCMAKE_CXX_COMPILER=g++-13`. +`cmake ../.. -GNinja -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14`. ### Legacy renegotiation is disabled diff --git a/Meta/build-image-extlinux.sh b/Meta/build-image-extlinux.sh index 1bef99b80faf33..2d253ad8d25809 100755 --- a/Meta/build-image-extlinux.sh +++ b/Meta/build-image-extlinux.sh @@ -4,6 +4,7 @@ set -e script_path=$(cd -P -- "$(dirname -- "$0")" && pwd -P) +# shellcheck source=/dev/null . "${script_path}/shell_include.sh" if [ "$(id -u)" != 0 ]; then @@ -30,7 +31,7 @@ for dir in "/usr/lib/syslinux/bios" "/usr/lib/syslinux" "/usr/share/syslinux"; d break fi done -if [ -z $syslinux_dir ]; then +if [ -z "$syslinux_dir" ]; then echo "can't find syslinux directory" exit 1 fi @@ -96,7 +97,7 @@ mkdir -p mnt/boot/extlinux extlinux --install mnt/boot/extlinux cp "$extlinux_cfg" mnt/boot/extlinux/extlinux.conf for module in mboot.c32 menu.c32 libutil.c32 libcom32.c32; do - cp $syslinux_dir/$module mnt/boot/extlinux/ + cp "$syslinux_dir/$module" mnt/boot/extlinux/ done -dd bs=440 count=1 conv=notrunc if=$syslinux_dir/mbr.bin of="$dev" +dd bs=440 count=1 conv=notrunc if="$syslinux_dir/mbr.bin" of="$dev" echo "done" diff --git a/Meta/build-image-grub-uefi.sh b/Meta/build-image-grub-uefi.sh index 880e028d2e93f8..c1e5d1725d12f7 100755 --- a/Meta/build-image-grub-uefi.sh +++ b/Meta/build-image-grub-uefi.sh @@ -4,6 +4,7 @@ set -e script_path=$(cd -P -- "$(dirname -- "$0")" && pwd -P) +# shellcheck source=/dev/null . "${script_path}/shell_include.sh" if [ "$(id -u)" != 0 ]; then diff --git a/Meta/build-image-grub.sh b/Meta/build-image-grub.sh index ca1c7fda4dc402..bb62e31064a184 100755 --- a/Meta/build-image-grub.sh +++ b/Meta/build-image-grub.sh @@ -4,6 +4,7 @@ set -e script_path=$(cd -P -- "$(dirname -- "$0")" && pwd -P) +# shellcheck source=/dev/null . "${script_path}/shell_include.sh" if [ "$(id -u)" != 0 ]; then diff --git a/Meta/build-image-limine.sh b/Meta/build-image-limine.sh index a59046254c809f..ef96f576d334f1 100755 --- a/Meta/build-image-limine.sh +++ b/Meta/build-image-limine.sh @@ -4,6 +4,7 @@ set -e script_path=$(cd -P -- "$(dirname -- "$0")" && pwd -P) +# shellcheck source=/dev/null . "${script_path}/shell_include.sh" if [ ! -d "limine" ]; then diff --git a/Meta/build-image-raspberry-pi.sh b/Meta/build-image-raspberry-pi.sh index ab73929ccd0669..3666355b69105b 100755 --- a/Meta/build-image-raspberry-pi.sh +++ b/Meta/build-image-raspberry-pi.sh @@ -4,6 +4,7 @@ set -e script_path=$(cd -P -- "$(dirname -- "$0")" && pwd -P) +# shellcheck source=/dev/null . "${script_path}/shell_include.sh" DISK_SIZE=$(($(disk_usage "$SERENITY_SOURCE_DIR/Base") + $(disk_usage Root) + 512 + 300)) diff --git a/Meta/build-native-partition.sh b/Meta/build-native-partition.sh index 2cc62f5dae6f5d..554eb67a9c3c0c 100755 --- a/Meta/build-native-partition.sh +++ b/Meta/build-native-partition.sh @@ -4,6 +4,7 @@ set -e script_path=$(cd -P -- "$(dirname -- "$0")" && pwd -P) +# shellcheck source=/dev/null . "${script_path}/shell_include.sh" cleanup() { diff --git a/Meta/find_compiler.sh b/Meta/find_compiler.sh index f7ae5920412df4..47a145f64401bf 100644 --- a/Meta/find_compiler.sh +++ b/Meta/find_compiler.sh @@ -15,14 +15,14 @@ is_supported_compiler() { if $COMPILER --version 2>&1 | grep "Apple clang" >/dev/null; then # Apple Clang version check BUILD_VERSION=$(echo | $COMPILER -dM -E - | grep __apple_build_version__ | cut -d ' ' -f3) - # Xcode 14.3, based on upstream LLVM 15 - [ "$BUILD_VERSION" -ge 14030022 ] && return 0 + # Xcode 16.3, based on upstream LLVM 19 + [ "$BUILD_VERSION" -ge 16030000 ] && return 0 elif $COMPILER --version 2>&1 | grep "clang" >/dev/null; then # Clang version check - [ "$MAJOR_VERSION" -ge 17 ] && return 0 + [ "$MAJOR_VERSION" -ge 18 ] && return 0 else # GCC version check - [ "$MAJOR_VERSION" -ge 13 ] && return 0 + [ "$MAJOR_VERSION" -ge 14 ] && return 0 fi return 1 } @@ -56,14 +56,14 @@ pick_host_compiler() { return fi - find_newest_compiler clang clang-17 clang-18 /opt/homebrew/opt/llvm/bin/clang + find_newest_compiler clang clang-18 /opt/homebrew/opt/llvm/bin/clang if is_supported_compiler "$HOST_COMPILER"; then export CC="${HOST_COMPILER}" export CXX="${HOST_COMPILER/clang/clang++}" return fi - find_newest_compiler egcc gcc gcc-13 gcc-14 /usr/local/bin/gcc-{13,14} /opt/homebrew/bin/gcc-{13,14} + find_newest_compiler egcc gcc gcc-14 /usr/local/bin/gcc-14 /opt/homebrew/bin/gcc-14 if is_supported_compiler "$HOST_COMPILER"; then export CC="${HOST_COMPILER}" export CXX="${HOST_COMPILER/gcc/g++}" @@ -71,8 +71,8 @@ pick_host_compiler() { fi if [ "$(uname -s)" = "Darwin" ]; then - die "Please make sure that Xcode 14.3, Homebrew Clang 17, or higher is installed." + die "Please make sure that Xcode 16.3, Homebrew Clang 18, or higher is installed." else - die "Please make sure that GCC version 13, Clang version 17, or higher is installed." + die "Please make sure that GCC version 14, Clang version 18, or higher is installed." fi } diff --git a/Tests/AK/TestOptional.cpp b/Tests/AK/TestOptional.cpp index d3030b0e22e1af..a1b212a3ca6a86 100644 --- a/Tests/AK/TestOptional.cpp +++ b/Tests/AK/TestOptional.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -304,6 +305,29 @@ TEST_CASE(comparison_reference) EXPECT_NE(opt1, opt3); } +TEST_CASE(nonnull_smart_pointers) +{ + Optional> opt; + EXPECT_EQ(opt.has_value(), false); + opt = make(3); + EXPECT_EQ(opt.has_value(), true); + EXPECT_EQ(*opt.value(), 3); + + Optional> opt2 = make(4); + EXPECT_EQ(opt2.has_value(), true); + EXPECT_EQ(*opt2.value(), 4); + + opt = move(opt2); + EXPECT_EQ(opt.has_value(), true); + EXPECT_EQ(*opt.value(), 4); + EXPECT_EQ(opt2.has_value(), false); + + (void)opt.release_value(); + EXPECT_EQ(opt.has_value(), false); + + // FIXME: Maybe test NonnullRefPtr, especially as that can be copied +} + TEST_CASE(uninitialized_constructor) { static bool was_constructed = false; diff --git a/Userland/Applications/HexEditor/AnnotationsModel.cpp b/Userland/Applications/HexEditor/AnnotationsModel.cpp index df2b4ed1639d97..b4c05ab578253d 100644 --- a/Userland/Applications/HexEditor/AnnotationsModel.cpp +++ b/Userland/Applications/HexEditor/AnnotationsModel.cpp @@ -116,7 +116,7 @@ ErrorOr AnnotationsModel::load_from_file(Core::File& file) annotation.start_offset = start_offset.value(); if (auto end_offset = json_object.get_u64("end_offset"sv); end_offset.has_value()) annotation.end_offset = end_offset.value(); - if (auto background_color = json_object.get_byte_string("background_color"sv).map([](auto& string) { return Color::from_string(string); }); background_color.has_value()) + if (auto background_color = json_object.get_byte_string("background_color"sv).map([](auto&& string) { return Color::from_string(string); }); background_color.has_value()) annotation.background_color = background_color->value(); if (auto comments = json_object.get_byte_string("comments"sv); comments.has_value()) annotation.comments = MUST(String::from_byte_string(comments.value())); diff --git a/Userland/Applications/Spreadsheet/Position.h b/Userland/Applications/Spreadsheet/Position.h index 04558f4b8380f0..4a35c8c4022227 100644 --- a/Userland/Applications/Spreadsheet/Position.h +++ b/Userland/Applications/Spreadsheet/Position.h @@ -48,3 +48,14 @@ struct Position { }; } + +namespace AK { +template<> +struct Traits : public DefaultTraits { + static constexpr bool is_trivial() { return false; } + static unsigned hash(Spreadsheet::Position const& p) + { + return p.hash(); + } +}; +} diff --git a/Userland/Applications/Spreadsheet/Spreadsheet.h b/Userland/Applications/Spreadsheet/Spreadsheet.h index 20e441a939ecc7..6afe3b65b8ca2d 100644 --- a/Userland/Applications/Spreadsheet/Spreadsheet.h +++ b/Userland/Applications/Spreadsheet/Spreadsheet.h @@ -175,16 +175,3 @@ class Sheet : public Core::EventReceiver { }; } - -namespace AK { - -template<> -struct Traits : public DefaultTraits { - static constexpr bool is_trivial() { return false; } - static unsigned hash(Spreadsheet::Position const& p) - { - return p.hash(); - } -}; - -} diff --git a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp index dfd81e8c582f2a..47cca790bfcaae 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -1164,7 +1164,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. @@ -8430,7 +8430,7 @@ Parser::ParseErrorOr> Parser::parse_css_value(Prope 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/Userland/Libraries/LibWeb/CSS/StyleValues/CSSMathValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/CSSMathValue.cpp index e32ee848156c46..16973cd6289368 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/CSSMathValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/CSSMathValue.cpp @@ -631,7 +631,7 @@ Optional InvertCalculationNode::determine_type(PropertyID proper // The sub-expression’s type is the result of multiplying the left type and right type. // NOTE: An InvertCalculationNode only represents the right argument here, and the multiplication // is handled in the parent ProductCalculationNode. - return m_value->determine_type(property_id).map([](auto& it) { return it.inverted(); }); + return m_value->determine_type(property_id).map([](auto&& it) { return it.inverted(); }); } bool InvertCalculationNode::contains_percentage() const diff --git a/Userland/Services/RequestServer/Protocol.cpp b/Userland/Services/RequestServer/Protocol.cpp index 1dce3e95398530..7a3ad310c418df 100644 --- a/Userland/Services/RequestServer/Protocol.cpp +++ b/Userland/Services/RequestServer/Protocol.cpp @@ -19,7 +19,7 @@ static HashMap>& all_protocols() Protocol* Protocol::find_by_name(ByteString const& name) { - return all_protocols().get(name).map([](auto& p) -> Protocol* { return p; }).value_or(nullptr); + return all_protocols().get(name).map([](auto&& p) -> Protocol* { return p; }).value_or(nullptr); } Protocol::Protocol(ByteString const& name)