mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-03 16:39:01 -06:00 
			
		
		
		
	Merge pull request #9289 from liamwhite/fruit-company
general: fix compile for Apple Clang
This commit is contained in:
		@@ -112,6 +112,8 @@ else()
 | 
			
		||||
 | 
			
		||||
        $<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init>
 | 
			
		||||
        $<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field>
 | 
			
		||||
        $<$<CXX_COMPILER_ID:AppleClang>:-Wno-braced-scalar-init>
 | 
			
		||||
        $<$<CXX_COMPILER_ID:AppleClang>:-Wno-unused-private-field>
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    if (ARCHITECTURE_x86_64)
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
 | 
			
		||||
#include "audio_core/audio_event.h"
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
 | 
			
		||||
namespace AudioCore {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,8 @@
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
 | 
			
		||||
#include "audio_core/audio_event.h"
 | 
			
		||||
 | 
			
		||||
union Result;
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,8 @@
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
 | 
			
		||||
#include "audio_core/common/common.h"
 | 
			
		||||
#include "audio_core/renderer/system_manager.h"
 | 
			
		||||
#include "core/hle/service/audio/errors.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
 | 
			
		||||
namespace AudioCore {
 | 
			
		||||
constexpr u32 CurrentRevision = 11;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
 | 
			
		||||
#include "audio_core/renderer/adsp/command_list_processor.h"
 | 
			
		||||
#include "audio_core/renderer/command/effect/i3dl2_reverb.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
 | 
			
		||||
namespace AudioCore::AudioRenderer {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
 | 
			
		||||
#include "audio_core/renderer/adsp/command_list_processor.h"
 | 
			
		||||
#include "audio_core/renderer/command/effect/reverb.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
 | 
			
		||||
namespace AudioCore::AudioRenderer {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
 | 
			
		||||
#include "audio_core/renderer/mix/mix_context.h"
 | 
			
		||||
#include "audio_core/renderer/splitter/splitter_context.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
 | 
			
		||||
namespace AudioCore::AudioRenderer {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
#include <ranges>
 | 
			
		||||
 | 
			
		||||
#include "audio_core/renderer/voice/voice_context.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
 | 
			
		||||
namespace AudioCore::AudioRenderer {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -170,8 +170,8 @@ void SinkStream::ProcessAudioIn(std::span<const s16> input_buffer, std::size_t n
 | 
			
		||||
 | 
			
		||||
        // Get the minimum frames available between the currently playing buffer, and the
 | 
			
		||||
        // amount we have left to fill
 | 
			
		||||
        size_t frames_available{std::min(playing_buffer.frames - playing_buffer.frames_played,
 | 
			
		||||
                                         num_frames - frames_written)};
 | 
			
		||||
        size_t frames_available{std::min<u64>(playing_buffer.frames - playing_buffer.frames_played,
 | 
			
		||||
                                              num_frames - frames_written)};
 | 
			
		||||
 | 
			
		||||
        samples_buffer.Push(&input_buffer[frames_written * frame_size],
 | 
			
		||||
                            frames_available * frame_size);
 | 
			
		||||
@@ -241,8 +241,8 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
 | 
			
		||||
 | 
			
		||||
        // Get the minimum frames available between the currently playing buffer, and the
 | 
			
		||||
        // amount we have left to fill
 | 
			
		||||
        size_t frames_available{std::min(playing_buffer.frames - playing_buffer.frames_played,
 | 
			
		||||
                                         num_frames - frames_written)};
 | 
			
		||||
        size_t frames_available{std::min<u64>(playing_buffer.frames - playing_buffer.frames_played,
 | 
			
		||||
                                              num_frames - frames_written)};
 | 
			
		||||
 | 
			
		||||
        samples_buffer.Pop(&output_buffer[frames_written * frame_size],
 | 
			
		||||
                           frames_available * frame_size);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/fs/file.h"
 | 
			
		||||
#include "common/fs/fs.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
#include "common/fs/fs_util.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
 | 
			
		||||
namespace Common::FS {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
#include "common/fs/fs.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/param_package.h"
 | 
			
		||||
#include "common/uuid.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
#include <climits>
 | 
			
		||||
#include <stop_token>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
@@ -18,6 +17,7 @@
 | 
			
		||||
#include "common/fs/fs_paths.h"
 | 
			
		||||
#include "common/fs/path_util.h"
 | 
			
		||||
#include "common/literals.h"
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "common/thread.h"
 | 
			
		||||
 | 
			
		||||
#include "common/logging/backend.h"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										530
									
								
								src/common/polyfill_ranges.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										530
									
								
								src/common/polyfill_ranges.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,530 @@
 | 
			
		||||
// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// TODO: remove this file when ranges are supported by all compilation targets
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <version>
 | 
			
		||||
 | 
			
		||||
#ifndef __cpp_lib_ranges
 | 
			
		||||
 | 
			
		||||
namespace std {
 | 
			
		||||
namespace ranges {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
concept range = requires(T& t) {
 | 
			
		||||
    begin(t);
 | 
			
		||||
    end(t);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
concept input_range = range<T>;
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
concept output_range = range<T>;
 | 
			
		||||
 | 
			
		||||
template <range R>
 | 
			
		||||
using range_difference_t = ptrdiff_t;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// find, find_if, find_if_not
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
struct find_fn {
 | 
			
		||||
    template <typename Iterator, typename T, typename Proj = std::identity>
 | 
			
		||||
    constexpr Iterator operator()(Iterator first, Iterator last, const T& value,
 | 
			
		||||
                                  Proj proj = {}) const {
 | 
			
		||||
        for (; first != last; ++first) {
 | 
			
		||||
            if (std::invoke(proj, *first) == value) {
 | 
			
		||||
                return first;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return first;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename T, typename Proj = std::identity>
 | 
			
		||||
    constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), value, std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct find_if_fn {
 | 
			
		||||
    template <typename Iterator, typename Proj = std::identity, typename Pred>
 | 
			
		||||
    constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
 | 
			
		||||
        for (; first != last; ++first) {
 | 
			
		||||
            if (std::invoke(pred, std::invoke(proj, *first))) {
 | 
			
		||||
                return first;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return first;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename Proj = std::identity, typename Pred>
 | 
			
		||||
    constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct find_if_not_fn {
 | 
			
		||||
    template <typename Iterator, typename Proj = std::identity, typename Pred>
 | 
			
		||||
    constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
 | 
			
		||||
        for (; first != last; ++first) {
 | 
			
		||||
            if (!std::invoke(pred, std::invoke(proj, *first))) {
 | 
			
		||||
                return first;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return first;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename Proj = std::identity, typename Pred>
 | 
			
		||||
    constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline constexpr find_fn find;
 | 
			
		||||
inline constexpr find_if_fn find_if;
 | 
			
		||||
inline constexpr find_if_not_fn find_if_not;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// any_of, all_of, none_of
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
struct all_of_fn {
 | 
			
		||||
    template <typename Iterator, typename Proj = std::identity, typename Pred>
 | 
			
		||||
    constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
 | 
			
		||||
        return ranges::find_if_not(first, last, std::ref(pred), std::ref(proj)) == last;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename Proj = std::identity, typename Pred>
 | 
			
		||||
    constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct any_of_fn {
 | 
			
		||||
    template <typename Iterator, typename Proj = std::identity, typename Pred>
 | 
			
		||||
    constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
 | 
			
		||||
        return ranges::find_if(first, last, std::ref(pred), std::ref(proj)) != last;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename Proj = std::identity, typename Pred>
 | 
			
		||||
    constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct none_of_fn {
 | 
			
		||||
    template <typename Iterator, typename Proj = std::identity, typename Pred>
 | 
			
		||||
    constexpr bool operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
 | 
			
		||||
        return ranges::find_if(first, last, std::ref(pred), std::ref(proj)) == last;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename Proj = std::identity, typename Pred>
 | 
			
		||||
    constexpr bool operator()(R&& r, Pred pred, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline constexpr any_of_fn any_of;
 | 
			
		||||
inline constexpr all_of_fn all_of;
 | 
			
		||||
inline constexpr none_of_fn none_of;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// count, count_if
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
struct count_fn {
 | 
			
		||||
    template <typename Iterator, typename T, typename Proj = std::identity>
 | 
			
		||||
    constexpr ptrdiff_t operator()(Iterator first, Iterator last, const T& value,
 | 
			
		||||
                                   Proj proj = {}) const {
 | 
			
		||||
        ptrdiff_t counter = 0;
 | 
			
		||||
        for (; first != last; ++first)
 | 
			
		||||
            if (std::invoke(proj, *first) == value)
 | 
			
		||||
                ++counter;
 | 
			
		||||
        return counter;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename T, typename Proj = std::identity>
 | 
			
		||||
    constexpr ptrdiff_t operator()(R&& r, const T& value, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), value, std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct count_if_fn {
 | 
			
		||||
    template <typename Iterator, typename Proj = std::identity, typename Pred>
 | 
			
		||||
    constexpr ptrdiff_t operator()(Iterator first, Iterator last, Pred pred, Proj proj = {}) const {
 | 
			
		||||
        ptrdiff_t counter = 0;
 | 
			
		||||
        for (; first != last; ++first)
 | 
			
		||||
            if (std::invoke(pred, std::invoke(proj, *first)))
 | 
			
		||||
                ++counter;
 | 
			
		||||
        return counter;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename Proj = std::identity, typename Pred>
 | 
			
		||||
    constexpr ptrdiff_t operator()(R&& r, Pred pred, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline constexpr count_fn count;
 | 
			
		||||
inline constexpr count_if_fn count_if;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// transform
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
struct transform_fn {
 | 
			
		||||
    template <typename InputIterator, typename OutputIterator, typename F,
 | 
			
		||||
              typename Proj = std::identity>
 | 
			
		||||
    constexpr void operator()(InputIterator first1, InputIterator last1, OutputIterator result,
 | 
			
		||||
                              F op, Proj proj = {}) const {
 | 
			
		||||
        for (; first1 != last1; ++first1, (void)++result) {
 | 
			
		||||
            *result = std::invoke(op, std::invoke(proj, *first1));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename OutputIterator, typename F,
 | 
			
		||||
              typename Proj = std::identity>
 | 
			
		||||
    constexpr void operator()(R&& r, OutputIterator result, F op, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), result, std::ref(op), std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline constexpr transform_fn transform;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// sort
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
struct sort_fn {
 | 
			
		||||
    template <typename Iterator, typename Comp = ranges::less, typename Proj = std::identity>
 | 
			
		||||
    constexpr void operator()(Iterator first, Iterator last, Comp comp = {}, Proj proj = {}) const {
 | 
			
		||||
        if (first == last)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Iterator last_iter = ranges::next(first, last);
 | 
			
		||||
        std::sort(first, last_iter,
 | 
			
		||||
                  [&](auto& lhs, auto& rhs) { return comp(proj(lhs), proj(rhs)); });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename Comp = ranges::less, typename Proj = std::identity>
 | 
			
		||||
    constexpr void operator()(R&& r, Comp comp = {}, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::move(comp), std::move(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline constexpr sort_fn sort;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// fill
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
struct fill_fn {
 | 
			
		||||
    template <typename T, typename OutputIterator>
 | 
			
		||||
    constexpr OutputIterator operator()(OutputIterator first, OutputIterator last,
 | 
			
		||||
                                        const T& value) const {
 | 
			
		||||
        while (first != last) {
 | 
			
		||||
            *first++ = value;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return first;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T, ranges::output_range R>
 | 
			
		||||
    constexpr ranges::iterator_t<R> operator()(R&& r, const T& value) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), value);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline constexpr fill_fn fill;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// for_each
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
struct for_each_fn {
 | 
			
		||||
    template <typename Iterator, typename Proj = std::identity, typename Fun>
 | 
			
		||||
    constexpr void operator()(Iterator first, Iterator last, Fun f, Proj proj = {}) const {
 | 
			
		||||
        for (; first != last; ++first) {
 | 
			
		||||
            std::invoke(f, std::invoke(proj, *first));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename Proj = std::identity, typename Fun>
 | 
			
		||||
    constexpr void operator()(R&& r, Fun f, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::move(f), std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline constexpr for_each_fn for_each;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// min_element, max_element
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
struct min_element_fn {
 | 
			
		||||
    template <typename Iterator, typename Proj = std::identity, typename Comp = ranges::less>
 | 
			
		||||
    constexpr Iterator operator()(Iterator first, Iterator last, Comp comp = {},
 | 
			
		||||
                                  Proj proj = {}) const {
 | 
			
		||||
        if (first == last) {
 | 
			
		||||
            return last;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto smallest = first;
 | 
			
		||||
        ++first;
 | 
			
		||||
        for (; first != last; ++first) {
 | 
			
		||||
            if (!std::invoke(comp, std::invoke(proj, *smallest), std::invoke(proj, *first))) {
 | 
			
		||||
                smallest = first;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return smallest;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename Proj = std::identity, typename Comp = ranges::less>
 | 
			
		||||
    constexpr ranges::iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::ref(comp), std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct max_element_fn {
 | 
			
		||||
    template <typename Iterator, typename Proj = std::identity, typename Comp = ranges::less>
 | 
			
		||||
    constexpr Iterator operator()(Iterator first, Iterator last, Comp comp = {},
 | 
			
		||||
                                  Proj proj = {}) const {
 | 
			
		||||
        if (first == last) {
 | 
			
		||||
            return last;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto largest = first;
 | 
			
		||||
        ++first;
 | 
			
		||||
        for (; first != last; ++first) {
 | 
			
		||||
            if (std::invoke(comp, std::invoke(proj, *largest), std::invoke(proj, *first))) {
 | 
			
		||||
                largest = first;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return largest;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename Proj = std::identity, typename Comp = ranges::less>
 | 
			
		||||
    constexpr ranges::iterator_t<R> operator()(R&& r, Comp comp = {}, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::ref(comp), std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline constexpr min_element_fn min_element;
 | 
			
		||||
inline constexpr max_element_fn max_element;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// replace, replace_if
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
struct replace_fn {
 | 
			
		||||
    template <typename Iterator, typename T1, typename T2, typename Proj = std::identity>
 | 
			
		||||
    constexpr Iterator operator()(Iterator first, Iterator last, const T1& old_value,
 | 
			
		||||
                                  const T2& new_value, Proj proj = {}) const {
 | 
			
		||||
        for (; first != last; ++first) {
 | 
			
		||||
            if (old_value == std::invoke(proj, *first)) {
 | 
			
		||||
                *first = new_value;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return first;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename T1, typename T2, typename Proj = std::identity>
 | 
			
		||||
    constexpr ranges::iterator_t<R> operator()(R&& r, const T1& old_value, const T2& new_value,
 | 
			
		||||
                                               Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), old_value, new_value, std::move(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct replace_if_fn {
 | 
			
		||||
    template <typename Iterator, typename T, typename Proj = std::identity, typename Pred>
 | 
			
		||||
    constexpr Iterator operator()(Iterator first, Iterator last, Pred pred, const T& new_value,
 | 
			
		||||
                                  Proj proj = {}) const {
 | 
			
		||||
        for (; first != last; ++first) {
 | 
			
		||||
            if (!!std::invoke(pred, std::invoke(proj, *first))) {
 | 
			
		||||
                *first = new_value;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return std::move(first);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename T, typename Proj = std::identity, typename Pred>
 | 
			
		||||
    constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred, const T& new_value,
 | 
			
		||||
                                               Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::move(pred), new_value,
 | 
			
		||||
                          std::move(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline constexpr replace_fn replace;
 | 
			
		||||
inline constexpr replace_if_fn replace_if;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// copy, copy_if
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
struct copy_fn {
 | 
			
		||||
    template <typename InputIterator, typename OutputIterator>
 | 
			
		||||
    constexpr void operator()(InputIterator first, InputIterator last,
 | 
			
		||||
                              OutputIterator result) const {
 | 
			
		||||
        for (; first != last; ++first, (void)++result) {
 | 
			
		||||
            *result = *first;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename OutputIterator>
 | 
			
		||||
    constexpr void operator()(R&& r, OutputIterator result) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::move(result));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct copy_if_fn {
 | 
			
		||||
    template <typename InputIterator, typename OutputIterator, typename Proj = std::identity,
 | 
			
		||||
              typename Pred>
 | 
			
		||||
    constexpr void operator()(InputIterator first, InputIterator last, OutputIterator result,
 | 
			
		||||
                              Pred pred, Proj proj = {}) const {
 | 
			
		||||
        for (; first != last; ++first) {
 | 
			
		||||
            if (std::invoke(pred, std::invoke(proj, *first))) {
 | 
			
		||||
                *result = *first;
 | 
			
		||||
                ++result;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename OutputIterator, typename Proj = std::identity,
 | 
			
		||||
              typename Pred>
 | 
			
		||||
    constexpr void operator()(R&& r, OutputIterator result, Pred pred, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::move(result), std::ref(pred),
 | 
			
		||||
                          std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline constexpr copy_fn copy;
 | 
			
		||||
inline constexpr copy_if_fn copy_if;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// generate
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
struct generate_fn {
 | 
			
		||||
    template <typename Iterator, typename F>
 | 
			
		||||
    constexpr Iterator operator()(Iterator first, Iterator last, F gen) const {
 | 
			
		||||
        for (; first != last; *first = std::invoke(gen), ++first)
 | 
			
		||||
            ;
 | 
			
		||||
        return first;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename R, std::copy_constructible F>
 | 
			
		||||
    requires std::invocable<F&> && ranges::output_range<R>
 | 
			
		||||
    constexpr ranges::iterator_t<R> operator()(R&& r, F gen) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::move(gen));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline constexpr generate_fn generate;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// lower_bound, upper_bound
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
struct lower_bound_fn {
 | 
			
		||||
    template <typename Iterator, typename T, typename Proj = std::identity,
 | 
			
		||||
              typename Comp = ranges::less>
 | 
			
		||||
    constexpr Iterator operator()(Iterator first, Iterator last, const T& value, Comp comp = {},
 | 
			
		||||
                                  Proj proj = {}) const {
 | 
			
		||||
        Iterator it;
 | 
			
		||||
        std::ptrdiff_t _count, _step;
 | 
			
		||||
        _count = std::distance(first, last);
 | 
			
		||||
 | 
			
		||||
        while (_count > 0) {
 | 
			
		||||
            it = first;
 | 
			
		||||
            _step = _count / 2;
 | 
			
		||||
            ranges::advance(it, _step, last);
 | 
			
		||||
            if (comp(std::invoke(proj, *it), value)) {
 | 
			
		||||
                first = ++it;
 | 
			
		||||
                _count -= _step + 1;
 | 
			
		||||
            } else {
 | 
			
		||||
                _count = _step;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return first;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename T, typename Proj = std::identity,
 | 
			
		||||
              typename Comp = ranges::less>
 | 
			
		||||
    constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Comp comp = {},
 | 
			
		||||
                                               Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), value, std::ref(comp), std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct upper_bound_fn {
 | 
			
		||||
    template <typename Iterator, typename T, typename Proj = std::identity,
 | 
			
		||||
              typename Comp = ranges::less>
 | 
			
		||||
    constexpr Iterator operator()(Iterator first, Iterator last, const T& value, Comp comp = {},
 | 
			
		||||
                                  Proj proj = {}) const {
 | 
			
		||||
        Iterator it;
 | 
			
		||||
        std::ptrdiff_t _count, _step;
 | 
			
		||||
        _count = std::distance(first, last);
 | 
			
		||||
 | 
			
		||||
        while (_count > 0) {
 | 
			
		||||
            it = first;
 | 
			
		||||
            _step = _count / 2;
 | 
			
		||||
            ranges::advance(it, _step, last);
 | 
			
		||||
            if (!comp(value, std::invoke(proj, *it))) {
 | 
			
		||||
                first = ++it;
 | 
			
		||||
                _count -= _step + 1;
 | 
			
		||||
            } else {
 | 
			
		||||
                _count = _step;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return first;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename T, typename Proj = std::identity,
 | 
			
		||||
              typename Comp = ranges::less>
 | 
			
		||||
    constexpr ranges::iterator_t<R> operator()(R&& r, const T& value, Comp comp = {},
 | 
			
		||||
                                               Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), value, std::ref(comp), std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline constexpr lower_bound_fn lower_bound;
 | 
			
		||||
inline constexpr upper_bound_fn upper_bound;
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// adjacent_find
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
struct adjacent_find_fn {
 | 
			
		||||
    template <typename Iterator, typename Proj = std::identity, typename Pred = ranges::equal_to>
 | 
			
		||||
    constexpr Iterator operator()(Iterator first, Iterator last, Pred pred = {},
 | 
			
		||||
                                  Proj proj = {}) const {
 | 
			
		||||
        if (first == last)
 | 
			
		||||
            return first;
 | 
			
		||||
        auto _next = ranges::next(first);
 | 
			
		||||
        for (; _next != last; ++_next, ++first)
 | 
			
		||||
            if (std::invoke(pred, std::invoke(proj, *first), std::invoke(proj, *_next)))
 | 
			
		||||
                return first;
 | 
			
		||||
        return _next;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <ranges::input_range R, typename Proj = std::identity,
 | 
			
		||||
              typename Pred = ranges::equal_to>
 | 
			
		||||
    constexpr ranges::iterator_t<R> operator()(R&& r, Pred pred = {}, Proj proj = {}) const {
 | 
			
		||||
        return operator()(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline constexpr adjacent_find_fn adjacent_find;
 | 
			
		||||
 | 
			
		||||
} // namespace ranges
 | 
			
		||||
} // namespace std
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										323
									
								
								src/common/polyfill_thread.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										323
									
								
								src/common/polyfill_thread.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,323 @@
 | 
			
		||||
// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// TODO: remove this file when jthread is supported by all compilation targets
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <version>
 | 
			
		||||
 | 
			
		||||
#ifdef __cpp_lib_jthread
 | 
			
		||||
 | 
			
		||||
#include <stop_token>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
namespace Common {
 | 
			
		||||
 | 
			
		||||
template <typename Condvar, typename Lock, typename Pred>
 | 
			
		||||
void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred&& pred) {
 | 
			
		||||
    cv.wait(lock, token, std::move(pred));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Common
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#include <atomic>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <list>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
 | 
			
		||||
namespace std {
 | 
			
		||||
namespace polyfill {
 | 
			
		||||
 | 
			
		||||
using stop_state_callbacks = list<function<void()>>;
 | 
			
		||||
 | 
			
		||||
class stop_state {
 | 
			
		||||
public:
 | 
			
		||||
    stop_state() = default;
 | 
			
		||||
    ~stop_state() = default;
 | 
			
		||||
 | 
			
		||||
    bool request_stop() {
 | 
			
		||||
        stop_state_callbacks callbacks;
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            scoped_lock lk{m_lock};
 | 
			
		||||
 | 
			
		||||
            if (m_stop_requested.load()) {
 | 
			
		||||
                // Already set, nothing to do
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Set as requested
 | 
			
		||||
            m_stop_requested = true;
 | 
			
		||||
 | 
			
		||||
            // Copy callback list
 | 
			
		||||
            callbacks = m_callbacks;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (auto callback : callbacks) {
 | 
			
		||||
            callback();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool stop_requested() const {
 | 
			
		||||
        return m_stop_requested.load();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    stop_state_callbacks::const_iterator insert_callback(function<void()> f) {
 | 
			
		||||
        stop_state_callbacks::const_iterator ret{};
 | 
			
		||||
        bool should_run{};
 | 
			
		||||
 | 
			
		||||
        {
 | 
			
		||||
            scoped_lock lk{m_lock};
 | 
			
		||||
            should_run = m_stop_requested.load();
 | 
			
		||||
            m_callbacks.push_front(f);
 | 
			
		||||
            ret = m_callbacks.begin();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (should_run) {
 | 
			
		||||
            f();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void remove_callback(stop_state_callbacks::const_iterator it) {
 | 
			
		||||
        scoped_lock lk{m_lock};
 | 
			
		||||
        m_callbacks.erase(it);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    mutex m_lock;
 | 
			
		||||
    atomic<bool> m_stop_requested;
 | 
			
		||||
    stop_state_callbacks m_callbacks;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace polyfill
 | 
			
		||||
 | 
			
		||||
class stop_token;
 | 
			
		||||
class stop_source;
 | 
			
		||||
struct nostopstate_t {
 | 
			
		||||
    explicit nostopstate_t() = default;
 | 
			
		||||
};
 | 
			
		||||
inline constexpr nostopstate_t nostopstate{};
 | 
			
		||||
 | 
			
		||||
template <class Callback>
 | 
			
		||||
class stop_callback;
 | 
			
		||||
 | 
			
		||||
class stop_token {
 | 
			
		||||
public:
 | 
			
		||||
    stop_token() noexcept = default;
 | 
			
		||||
 | 
			
		||||
    stop_token(const stop_token&) noexcept = default;
 | 
			
		||||
    stop_token(stop_token&&) noexcept = default;
 | 
			
		||||
    stop_token& operator=(const stop_token&) noexcept = default;
 | 
			
		||||
    stop_token& operator=(stop_token&&) noexcept = default;
 | 
			
		||||
    ~stop_token() = default;
 | 
			
		||||
 | 
			
		||||
    void swap(stop_token& other) noexcept {
 | 
			
		||||
        m_stop_state.swap(other.m_stop_state);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] bool stop_requested() const noexcept {
 | 
			
		||||
        return m_stop_state && m_stop_state->stop_requested();
 | 
			
		||||
    }
 | 
			
		||||
    [[nodiscard]] bool stop_possible() const noexcept {
 | 
			
		||||
        return m_stop_state != nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    friend class stop_source;
 | 
			
		||||
    template <typename Callback>
 | 
			
		||||
    friend class stop_callback;
 | 
			
		||||
    stop_token(shared_ptr<polyfill::stop_state> stop_state) : m_stop_state(move(stop_state)) {}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    shared_ptr<polyfill::stop_state> m_stop_state;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class stop_source {
 | 
			
		||||
public:
 | 
			
		||||
    stop_source() : m_stop_state(make_shared<polyfill::stop_state>()) {}
 | 
			
		||||
    explicit stop_source(nostopstate_t) noexcept {}
 | 
			
		||||
 | 
			
		||||
    stop_source(const stop_source&) noexcept = default;
 | 
			
		||||
    stop_source(stop_source&&) noexcept = default;
 | 
			
		||||
    stop_source& operator=(const stop_source&) noexcept = default;
 | 
			
		||||
    stop_source& operator=(stop_source&&) noexcept = default;
 | 
			
		||||
    ~stop_source() = default;
 | 
			
		||||
    void swap(stop_source& other) noexcept {
 | 
			
		||||
        m_stop_state.swap(other.m_stop_state);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] stop_token get_token() const noexcept {
 | 
			
		||||
        return stop_token(m_stop_state);
 | 
			
		||||
    }
 | 
			
		||||
    [[nodiscard]] bool stop_possible() const noexcept {
 | 
			
		||||
        return m_stop_state != nullptr;
 | 
			
		||||
    }
 | 
			
		||||
    [[nodiscard]] bool stop_requested() const noexcept {
 | 
			
		||||
        return m_stop_state && m_stop_state->stop_requested();
 | 
			
		||||
    }
 | 
			
		||||
    bool request_stop() noexcept {
 | 
			
		||||
        return m_stop_state && m_stop_state->request_stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    friend class jthread;
 | 
			
		||||
    explicit stop_source(shared_ptr<polyfill::stop_state> stop_state)
 | 
			
		||||
        : m_stop_state(move(stop_state)) {}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    shared_ptr<polyfill::stop_state> m_stop_state;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Callback>
 | 
			
		||||
class stop_callback {
 | 
			
		||||
    static_assert(is_nothrow_destructible_v<Callback>);
 | 
			
		||||
    static_assert(is_invocable_v<Callback>);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    using callback_type = Callback;
 | 
			
		||||
 | 
			
		||||
    template <typename C>
 | 
			
		||||
    requires constructible_from<Callback, C>
 | 
			
		||||
    explicit stop_callback(const stop_token& st,
 | 
			
		||||
                           C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
 | 
			
		||||
        : m_stop_state(st.m_stop_state) {
 | 
			
		||||
        if (m_stop_state) {
 | 
			
		||||
            m_callback = m_stop_state->insert_callback(move(cb));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    template <typename C>
 | 
			
		||||
    requires constructible_from<Callback, C>
 | 
			
		||||
    explicit stop_callback(stop_token&& st,
 | 
			
		||||
                           C&& cb) noexcept(is_nothrow_constructible_v<Callback, C>)
 | 
			
		||||
        : m_stop_state(move(st.m_stop_state)) {
 | 
			
		||||
        if (m_stop_state) {
 | 
			
		||||
            m_callback = m_stop_state->insert_callback(move(cb));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    ~stop_callback() {
 | 
			
		||||
        if (m_stop_state && m_callback) {
 | 
			
		||||
            m_stop_state->remove_callback(*m_callback);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    stop_callback(const stop_callback&) = delete;
 | 
			
		||||
    stop_callback(stop_callback&&) = delete;
 | 
			
		||||
    stop_callback& operator=(const stop_callback&) = delete;
 | 
			
		||||
    stop_callback& operator=(stop_callback&&) = delete;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    shared_ptr<polyfill::stop_state> m_stop_state;
 | 
			
		||||
    optional<polyfill::stop_state_callbacks::const_iterator> m_callback;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Callback>
 | 
			
		||||
stop_callback(stop_token, Callback) -> stop_callback<Callback>;
 | 
			
		||||
 | 
			
		||||
class jthread {
 | 
			
		||||
public:
 | 
			
		||||
    using id = thread::id;
 | 
			
		||||
    using native_handle_type = thread::native_handle_type;
 | 
			
		||||
 | 
			
		||||
    jthread() noexcept = default;
 | 
			
		||||
 | 
			
		||||
    template <typename F, typename... Args,
 | 
			
		||||
              typename = enable_if_t<!is_same_v<remove_cvref_t<F>, jthread>>>
 | 
			
		||||
    explicit jthread(F&& f, Args&&... args)
 | 
			
		||||
        : m_stop_state(make_shared<polyfill::stop_state>()),
 | 
			
		||||
          m_thread(make_thread(move(f), move(args)...)) {}
 | 
			
		||||
 | 
			
		||||
    ~jthread() {
 | 
			
		||||
        if (joinable()) {
 | 
			
		||||
            request_stop();
 | 
			
		||||
            join();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    jthread(const jthread&) = delete;
 | 
			
		||||
    jthread(jthread&&) noexcept = default;
 | 
			
		||||
    jthread& operator=(const jthread&) = delete;
 | 
			
		||||
 | 
			
		||||
    jthread& operator=(jthread&& other) noexcept {
 | 
			
		||||
        m_thread.swap(other.m_thread);
 | 
			
		||||
        m_stop_state.swap(other.m_stop_state);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void swap(jthread& other) noexcept {
 | 
			
		||||
        m_thread.swap(other.m_thread);
 | 
			
		||||
        m_stop_state.swap(other.m_stop_state);
 | 
			
		||||
    }
 | 
			
		||||
    [[nodiscard]] bool joinable() const noexcept {
 | 
			
		||||
        return m_thread.joinable();
 | 
			
		||||
    }
 | 
			
		||||
    void join() {
 | 
			
		||||
        m_thread.join();
 | 
			
		||||
    }
 | 
			
		||||
    void detach() {
 | 
			
		||||
        m_thread.detach();
 | 
			
		||||
        m_stop_state.reset();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    [[nodiscard]] id get_id() const noexcept {
 | 
			
		||||
        return m_thread.get_id();
 | 
			
		||||
    }
 | 
			
		||||
    [[nodiscard]] native_handle_type native_handle() {
 | 
			
		||||
        return m_thread.native_handle();
 | 
			
		||||
    }
 | 
			
		||||
    [[nodiscard]] stop_source get_stop_source() noexcept {
 | 
			
		||||
        return stop_source(m_stop_state);
 | 
			
		||||
    }
 | 
			
		||||
    [[nodiscard]] stop_token get_stop_token() const noexcept {
 | 
			
		||||
        return stop_source(m_stop_state).get_token();
 | 
			
		||||
    }
 | 
			
		||||
    bool request_stop() noexcept {
 | 
			
		||||
        return get_stop_source().request_stop();
 | 
			
		||||
    }
 | 
			
		||||
    [[nodiscard]] static unsigned int hardware_concurrency() noexcept {
 | 
			
		||||
        return thread::hardware_concurrency();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    template <typename F, typename... Args>
 | 
			
		||||
    thread make_thread(F&& f, Args&&... args) {
 | 
			
		||||
        if constexpr (is_invocable_v<decay_t<F>, stop_token, decay_t<Args>...>) {
 | 
			
		||||
            return thread(move(f), get_stop_token(), move(args)...);
 | 
			
		||||
        } else {
 | 
			
		||||
            return thread(move(f), move(args)...);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    shared_ptr<polyfill::stop_state> m_stop_state;
 | 
			
		||||
    thread m_thread;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace std
 | 
			
		||||
 | 
			
		||||
namespace Common {
 | 
			
		||||
 | 
			
		||||
template <typename Condvar, typename Lock, typename Pred>
 | 
			
		||||
void CondvarWait(Condvar& cv, Lock& lock, std::stop_token token, Pred pred) {
 | 
			
		||||
    if (token.stop_requested()) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::stop_callback callback(token, [&] { cv.notify_all(); });
 | 
			
		||||
    cv.wait(lock, [&] { return pred() || token.stop_requested(); });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Common
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -7,13 +7,13 @@
 | 
			
		||||
#include <condition_variable>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <stop_token>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <queue>
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "common/thread.h"
 | 
			
		||||
#include "common/unique_function.h"
 | 
			
		||||
 | 
			
		||||
@@ -47,7 +47,8 @@ public:
 | 
			
		||||
                        if (requests.empty()) {
 | 
			
		||||
                            wait_condition.notify_all();
 | 
			
		||||
                        }
 | 
			
		||||
                        condition.wait(lock, stop_token, [this] { return !requests.empty(); });
 | 
			
		||||
                        Common::CondvarWait(condition, lock, stop_token,
 | 
			
		||||
                                            [this] { return !requests.empty(); });
 | 
			
		||||
                        if (stop_token.stop_requested()) {
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,8 @@
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
 | 
			
		||||
namespace Common {
 | 
			
		||||
template <typename T, bool with_stop_token = false>
 | 
			
		||||
class SPSCQueue {
 | 
			
		||||
@@ -97,7 +99,7 @@ public:
 | 
			
		||||
    T PopWait(std::stop_token stop_token) {
 | 
			
		||||
        if (Empty()) {
 | 
			
		||||
            std::unique_lock lock{cv_mutex};
 | 
			
		||||
            cv.wait(lock, stop_token, [this] { return !Empty(); });
 | 
			
		||||
            Common::CondvarWait(cv, lock, stop_token, [this] { return !Empty(); });
 | 
			
		||||
        }
 | 
			
		||||
        if (stop_token.stop_requested()) {
 | 
			
		||||
            return T{};
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
#include "common/fiber.h"
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "common/thread.h"
 | 
			
		||||
#include "core/hardware_properties.h"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@
 | 
			
		||||
#include <boost/process/async_pipe.hpp>
 | 
			
		||||
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "common/thread.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/debugger/debugger.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "core/crypto/aes_util.h"
 | 
			
		||||
#include "core/crypto/ctr_encryption_layer.h"
 | 
			
		||||
#include "core/crypto/key_manager.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/input.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/input.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -225,8 +225,8 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages,
 | 
			
		||||
    ON_RESULT_FAILURE {
 | 
			
		||||
        for (const auto& it : out->Nodes()) {
 | 
			
		||||
            auto& manager = this->GetManager(it.GetAddress());
 | 
			
		||||
            const size_t node_num_pages =
 | 
			
		||||
                std::min(it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize);
 | 
			
		||||
            const size_t node_num_pages = std::min<u64>(
 | 
			
		||||
                it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize);
 | 
			
		||||
            manager.Free(it.GetAddress(), node_num_pages);
 | 
			
		||||
        }
 | 
			
		||||
        out->Finalize();
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@
 | 
			
		||||
#include <atomic>
 | 
			
		||||
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/atomic_ops.h"
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/spin_lock.h"
 | 
			
		||||
@@ -82,16 +83,13 @@ private:
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void UpdatePeakImpl(uintptr_t obj) {
 | 
			
		||||
        static_assert(std::atomic_ref<uintptr_t>::is_always_lock_free);
 | 
			
		||||
        std::atomic_ref<uintptr_t> peak_ref(m_peak);
 | 
			
		||||
 | 
			
		||||
        const uintptr_t alloc_peak = obj + this->GetObjectSize();
 | 
			
		||||
        uintptr_t cur_peak = m_peak;
 | 
			
		||||
        do {
 | 
			
		||||
            if (alloc_peak <= cur_peak) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        } while (!peak_ref.compare_exchange_strong(cur_peak, alloc_peak));
 | 
			
		||||
        } while (!Common::AtomicCompareAndSwap(&m_peak, alloc_peak, cur_peak, cur_peak));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/intrusive_red_black_tree.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "core/hle/kernel/memory_types.h"
 | 
			
		||||
#include "core/hle/kernel/slab_helpers.h"
 | 
			
		||||
#include "core/hle/result.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "common/scope_exit.h"
 | 
			
		||||
#include "common/thread.h"
 | 
			
		||||
#include "core/hle/ipc_helpers.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -82,7 +82,7 @@ void SvcWrap64(Core::System& system) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Used by ControlCodeMemory
 | 
			
		||||
template <Result func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)>
 | 
			
		||||
template <Result func(Core::System&, Handle, u32, VAddr, size_t, Svc::MemoryPermission)>
 | 
			
		||||
void SvcWrap64(Core::System& system) {
 | 
			
		||||
    FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
 | 
			
		||||
                            static_cast<u32>(Param(system, 1)), Param(system, 2), Param(system, 3),
 | 
			
		||||
@@ -327,7 +327,7 @@ void SvcWrap64(Core::System& system) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Used by CreateCodeMemory
 | 
			
		||||
template <Result func(Core::System&, Handle*, u64, u64)>
 | 
			
		||||
template <Result func(Core::System&, Handle*, VAddr, size_t)>
 | 
			
		||||
void SvcWrap64(Core::System& system) {
 | 
			
		||||
    u32 param_1 = 0;
 | 
			
		||||
    const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2)).raw;
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
#include "common/fs/file.h"
 | 
			
		||||
#include "common/fs/path_util.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "common/string_util.h"
 | 
			
		||||
#include "common/swap.h"
 | 
			
		||||
#include "core/constants.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@
 | 
			
		||||
#include "common/fs/file.h"
 | 
			
		||||
#include "common/fs/fs.h"
 | 
			
		||||
#include "common/fs/path_util.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "common/settings.h"
 | 
			
		||||
#include "core/hle/service/acc/profile_manager.h"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1125,7 +1125,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
 | 
			
		||||
    const u64 offset{rp.Pop<u64>()};
 | 
			
		||||
    const std::vector<u8> data{ctx.ReadBuffer()};
 | 
			
		||||
    const std::size_t size{std::min(data.size(), backing.GetSize() - offset)};
 | 
			
		||||
    const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)};
 | 
			
		||||
 | 
			
		||||
    LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
 | 
			
		||||
 | 
			
		||||
@@ -1149,7 +1149,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    IPC::RequestParser rp{ctx};
 | 
			
		||||
 | 
			
		||||
    const u64 offset{rp.Pop<u64>()};
 | 
			
		||||
    const std::size_t size{std::min(ctx.GetWriteBufferSize(), backing.GetSize() - offset)};
 | 
			
		||||
    const std::size_t size{std::min<u64>(ctx.GetWriteBufferSize(), backing.GetSize() - offset)};
 | 
			
		||||
 | 
			
		||||
    LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@
 | 
			
		||||
#include "common/bit_util.h"
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "common/string_util.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/hle/ipc_helpers.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "core/hle/result.h"
 | 
			
		||||
#include "core/hle/service/kernel_helpers.h"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@
 | 
			
		||||
#include "common/bit_cast.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "common/settings.h"
 | 
			
		||||
#include "common/string_util.h"
 | 
			
		||||
#include "core/internal_network/network_interface.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -5,10 +5,10 @@
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <stop_token>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "input_common/input_engine.h"
 | 
			
		||||
 | 
			
		||||
struct libusb_context;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include <stop_token>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,9 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <stop_token>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "common/vector_math.h"
 | 
			
		||||
#include "input_common/input_engine.h"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
 | 
			
		||||
#include "common/fs/file.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -255,6 +255,7 @@ else()
 | 
			
		||||
        # Bracket depth determines maximum size of a fold expression in Clang since 9c9974c3ccb6.
 | 
			
		||||
        # And this in turns limits the size of a std::array.
 | 
			
		||||
        $<$<CXX_COMPILER_ID:Clang>:-fbracket-depth=1024>
 | 
			
		||||
        $<$<CXX_COMPILER_ID:AppleClang>:-fbracket-depth=1024>
 | 
			
		||||
    )
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "shader_recompiler/frontend/ir/type.h"
 | 
			
		||||
 | 
			
		||||
namespace Shader::IR {
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@
 | 
			
		||||
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "shader_recompiler/exception.h"
 | 
			
		||||
#include "shader_recompiler/frontend/maxwell/control_flow.h"
 | 
			
		||||
#include "shader_recompiler/frontend/maxwell/decode.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "shader_recompiler/exception.h"
 | 
			
		||||
#include "shader_recompiler/frontend/maxwell/decode.h"
 | 
			
		||||
#include "shader_recompiler/frontend/maxwell/opcodes.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@
 | 
			
		||||
 | 
			
		||||
#include <boost/intrusive/list.hpp>
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "shader_recompiler/environment.h"
 | 
			
		||||
#include "shader_recompiler/frontend/ir/basic_block.h"
 | 
			
		||||
#include "shader_recompiler/frontend/ir/ir_emitter.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -176,12 +176,13 @@ void TranslateF2I(TranslatorVisitor& v, u64 insn, const IR::F16F32F64& src_a) {
 | 
			
		||||
        (f2i.src_format == SrcFormat::F64) != (f2i.dest_format == DestFormat::I64);
 | 
			
		||||
    if (special_nan_cases) {
 | 
			
		||||
        if (f2i.dest_format == DestFormat::I32) {
 | 
			
		||||
            constexpr u32 nan_value = 0x8000'0000U;
 | 
			
		||||
            handled_special_case = true;
 | 
			
		||||
            result = IR::U32{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm32(0x8000'0000U), result)};
 | 
			
		||||
            result = IR::U32{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm32(nan_value), result)};
 | 
			
		||||
        } else if (f2i.dest_format == DestFormat::I64) {
 | 
			
		||||
            constexpr u64 nan_value = 0x8000'0000'0000'0000ULL;
 | 
			
		||||
            handled_special_case = true;
 | 
			
		||||
            result = IR::U64{
 | 
			
		||||
                v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm64(0x8000'0000'0000'0000UL), result)};
 | 
			
		||||
            result = IR::U64{v.ir.Select(v.ir.FPIsNan(op_a), v.ir.Imm64(nan_value), result)};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (!handled_special_case && is_signed) {
 | 
			
		||||
 
 | 
			
		||||
@@ -535,7 +535,7 @@ private:
 | 
			
		||||
        const u64* const state_words = Array<type>();
 | 
			
		||||
        const u64 num_query_words = size / BYTES_PER_WORD + 1;
 | 
			
		||||
        const u64 word_begin = offset / BYTES_PER_WORD;
 | 
			
		||||
        const u64 word_end = std::min(word_begin + num_query_words, NumWords());
 | 
			
		||||
        const u64 word_end = std::min<u64>(word_begin + num_query_words, NumWords());
 | 
			
		||||
        const u64 page_limit = Common::DivCeil(offset + size, BYTES_PER_PAGE);
 | 
			
		||||
        u64 page_index = (offset / BYTES_PER_PAGE) % PAGES_PER_WORD;
 | 
			
		||||
        for (u64 word_index = word_begin; word_index < word_end; ++word_index, page_index = 0) {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@
 | 
			
		||||
#include "common/literals.h"
 | 
			
		||||
#include "common/lru_cache.h"
 | 
			
		||||
#include "common/microprofile.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "common/settings.h"
 | 
			
		||||
#include "core/memory.h"
 | 
			
		||||
#include "video_core/buffer_cache/buffer_base.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -35,8 +35,6 @@ public:
 | 
			
		||||
    explicit ChannelInfo(Tegra::Control::ChannelState& state);
 | 
			
		||||
    ChannelInfo(const ChannelInfo& state) = delete;
 | 
			
		||||
    ChannelInfo& operator=(const ChannelInfo&) = delete;
 | 
			
		||||
    ChannelInfo(ChannelInfo&& other) = default;
 | 
			
		||||
    ChannelInfo& operator=(ChannelInfo&& other) = default;
 | 
			
		||||
 | 
			
		||||
    Tegra::Engines::Maxwell3D& maxwell3d;
 | 
			
		||||
    Tegra::Engines::KeplerCompute& kepler_compute;
 | 
			
		||||
 
 | 
			
		||||
@@ -125,7 +125,7 @@ u64 ThreadManager::PushCommand(CommandData&& command_data, bool block) {
 | 
			
		||||
    state.queue.Push(CommandDataContainer(std::move(command_data), fence, block));
 | 
			
		||||
 | 
			
		||||
    if (block) {
 | 
			
		||||
        state.cv.wait(lk, thread.get_stop_token(), [this, fence] {
 | 
			
		||||
        Common::CondvarWait(state.cv, lk, thread.get_stop_token(), [this, fence] {
 | 
			
		||||
            return fence <= state.signaled_fence.load(std::memory_order_relaxed);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <variant>
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "common/threadsafe_queue.h"
 | 
			
		||||
#include "video_core/framebuffer_config.h"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,8 @@
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <span>
 | 
			
		||||
#include <stop_token>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "video_core/engines/fermi_2d.h"
 | 
			
		||||
#include "video_core/gpu.h"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@
 | 
			
		||||
 | 
			
		||||
#include "common/literals.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "common/settings.h"
 | 
			
		||||
#include "shader_recompiler/stage.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_device.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
#include <stop_token>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
#include "common/bit_cast.h"
 | 
			
		||||
#include "common/cityhash.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_state_tracker.h"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/math_util.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "common/settings.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/frontend/emu_window.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_resource_pool.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
 | 
			
		||||
 | 
			
		||||
namespace Vulkan {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
namespace Vulkan {
 | 
			
		||||
 | 
			
		||||
struct RenderPassKey {
 | 
			
		||||
    auto operator<=>(const RenderPassKey&) const noexcept = default;
 | 
			
		||||
    bool operator==(const RenderPassKey&) const noexcept = default;
 | 
			
		||||
 | 
			
		||||
    std::array<VideoCore::Surface::PixelFormat, 8> color_formats;
 | 
			
		||||
    VideoCore::Surface::PixelFormat depth_format;
 | 
			
		||||
 
 | 
			
		||||
@@ -145,7 +145,7 @@ void Scheduler::WorkerThread(std::stop_token stop_token) {
 | 
			
		||||
            if (work_queue.empty()) {
 | 
			
		||||
                wait_cv.notify_all();
 | 
			
		||||
            }
 | 
			
		||||
            work_cv.wait(lock, stop_token, [this] { return !work_queue.empty(); });
 | 
			
		||||
            Common::CondvarWait(work_cv, lock, stop_token, [&] { return !work_queue.empty(); });
 | 
			
		||||
            if (stop_token.stop_requested()) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@
 | 
			
		||||
 | 
			
		||||
#include "common/alignment.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
 | 
			
		||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "common/settings.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "video_core/control/channel_state_cache.h"
 | 
			
		||||
#include "video_core/rasterizer_interface.h"
 | 
			
		||||
#include "video_core/shader_environment.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@
 | 
			
		||||
#include "common/fs/fs.h"
 | 
			
		||||
#include "common/fs/path_util.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "shader_recompiler/environment.h"
 | 
			
		||||
#include "video_core/engines/kepler_compute.h"
 | 
			
		||||
#include "video_core/memory_manager.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -10,12 +10,12 @@
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <span>
 | 
			
		||||
#include <stop_token>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "common/unique_function.h"
 | 
			
		||||
#include "shader_recompiler/environment.h"
 | 
			
		||||
#include "video_core/engines/maxwell_3d.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "video_core/texture_cache/formatter.h"
 | 
			
		||||
#include "video_core/texture_cache/image_base.h"
 | 
			
		||||
#include "video_core/texture_cache/image_info.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ namespace VideoCommon {
 | 
			
		||||
 | 
			
		||||
/// Framebuffer properties used to lookup a framebuffer
 | 
			
		||||
struct RenderTargets {
 | 
			
		||||
    constexpr auto operator<=>(const RenderTargets&) const noexcept = default;
 | 
			
		||||
    constexpr bool operator==(const RenderTargets&) const noexcept = default;
 | 
			
		||||
 | 
			
		||||
    constexpr bool Contains(std::span<const ImageViewId> elements) const noexcept {
 | 
			
		||||
        const auto contains = [elements](ImageViewId item) {
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@
 | 
			
		||||
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
 | 
			
		||||
namespace VideoCommon {
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@
 | 
			
		||||
#include "common/hash.h"
 | 
			
		||||
#include "common/literals.h"
 | 
			
		||||
#include "common/lru_cache.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "video_core/compatible_formats.h"
 | 
			
		||||
#include "video_core/control/channel_state_cache.h"
 | 
			
		||||
#include "video_core/delayed_destruction_ring.h"
 | 
			
		||||
@@ -60,8 +61,6 @@ public:
 | 
			
		||||
    TextureCacheChannelInfo(Tegra::Control::ChannelState& state) noexcept;
 | 
			
		||||
    TextureCacheChannelInfo(const TextureCacheChannelInfo& state) = delete;
 | 
			
		||||
    TextureCacheChannelInfo& operator=(const TextureCacheChannelInfo&) = delete;
 | 
			
		||||
    TextureCacheChannelInfo(TextureCacheChannelInfo&& other) noexcept = default;
 | 
			
		||||
    TextureCacheChannelInfo& operator=(TextureCacheChannelInfo&& other) noexcept = default;
 | 
			
		||||
 | 
			
		||||
    DescriptorTable<TICEntry> graphics_image_table{gpu_memory};
 | 
			
		||||
    DescriptorTable<TSCEntry> graphics_sampler_table{gpu_memory};
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@
 | 
			
		||||
 | 
			
		||||
#include "common/alignment.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "common/thread_worker.h"
 | 
			
		||||
#include "video_core/textures/astc.h"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@
 | 
			
		||||
 | 
			
		||||
#include "common/alignment.h"
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "shader_recompiler/shader_info.h"
 | 
			
		||||
#include "video_core/transform_feedback.h"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@
 | 
			
		||||
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/literals.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "common/settings.h"
 | 
			
		||||
#include "video_core/vulkan_common/nsight_aftermath_tracker.h"
 | 
			
		||||
#include "video_core/vulkan_common/vulkan_device.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/dynamic_library.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "core/frontend/emu_window.h"
 | 
			
		||||
#include "video_core/vulkan_common/vulkan_instance.h"
 | 
			
		||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/polyfill_ranges.h"
 | 
			
		||||
#include "video_core/vulkan_common/vulkan_device.h"
 | 
			
		||||
#include "video_core/vulkan_common/vulkan_memory_allocator.h"
 | 
			
		||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -118,7 +118,7 @@ void EmuThread::run() {
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            std::unique_lock lock{running_mutex};
 | 
			
		||||
            running_cv.wait(lock, stop_token, [this] { return IsRunning(); });
 | 
			
		||||
            Common::CondvarWait(running_cv, lock, stop_token, [&] { return IsRunning(); });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@
 | 
			
		||||
#include <QTouchEvent>
 | 
			
		||||
#include <QWidget>
 | 
			
		||||
 | 
			
		||||
#include "common/polyfill_thread.h"
 | 
			
		||||
#include "common/thread.h"
 | 
			
		||||
#include "core/frontend/emu_window.h"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2850,6 +2850,7 @@ void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_tex
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OnMenuReportCompatibility() {
 | 
			
		||||
#if defined(ARCHITECTURE_x86_64) && !defined(__APPLE__)
 | 
			
		||||
    const auto& caps = Common::GetCPUCaps();
 | 
			
		||||
    const bool has_fma = caps.fma || caps.fma4;
 | 
			
		||||
    const auto processor_count = std::thread::hardware_concurrency();
 | 
			
		||||
@@ -2876,6 +2877,11 @@ void GMainWindow::OnMenuReportCompatibility() {
 | 
			
		||||
               "> "
 | 
			
		||||
               "Web."));
 | 
			
		||||
    }
 | 
			
		||||
#else
 | 
			
		||||
    QMessageBox::critical(this, tr("Hardware requirements not met"),
 | 
			
		||||
                          tr("Your system does not meet the recommended hardware requirements. "
 | 
			
		||||
                             "Compatibility reporting has been disabled."));
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::OpenURL(const QUrl& url) {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <unordered_set>
 | 
			
		||||
#include <QDialog>
 | 
			
		||||
#include <QSortFilterProxyModel>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user