79 changed files with 952 additions and 37 deletions
-
3externals/CMakeLists.txt
-
2src/CMakeLists.txt
-
1src/audio_core/audio_event.cpp
-
2src/audio_core/audio_manager.h
-
2src/audio_core/audio_render_manager.h
-
1src/audio_core/common/feature_support.h
-
1src/audio_core/renderer/command/effect/i3dl2_reverb.cpp
-
1src/audio_core/renderer/command/effect/reverb.cpp
-
1src/audio_core/renderer/mix/mix_context.cpp
-
1src/audio_core/renderer/voice/voice_context.cpp
-
8src/audio_core/sink/sink_stream.cpp
-
2src/common/fs/file.cpp
-
1src/common/fs/fs_util.cpp
-
1src/common/fs/path_util.cpp
-
1src/common/input.h
-
2src/common/logging/backend.cpp
-
530src/common/polyfill_ranges.h
-
323src/common/polyfill_thread.h
-
5src/common/thread_worker.h
-
4src/common/threadsafe_queue.h
-
1src/core/cpu_manager.h
-
1src/core/debugger/debugger.cpp
-
1src/core/file_sys/content_archive.cpp
-
1src/core/frontend/applets/controller.h
-
1src/core/hid/emulated_controller.h
-
1src/core/hid/emulated_devices.h
-
4src/core/hle/kernel/k_memory_manager.cpp
-
6src/core/hle/kernel/k_slab_heap.h
-
1src/core/hle/kernel/k_thread_local_page.h
-
1src/core/hle/kernel/service_thread.cpp
-
4src/core/hle/kernel/svc_wrap.h
-
1src/core/hle/service/acc/acc.cpp
-
1src/core/hle/service/acc/profile_manager.cpp
-
4src/core/hle/service/am/am.cpp
-
1src/core/hle/service/audio/audren_u.cpp
-
1src/core/hle/service/nvflinger/nvflinger.h
-
1src/core/internal_network/network_interface.cpp
-
2src/input_common/drivers/gc_adapter.h
-
1src/input_common/drivers/mouse.cpp
-
2src/input_common/drivers/mouse.h
-
1src/input_common/drivers/tas_input.cpp
-
1src/shader_recompiler/CMakeLists.txt
-
1src/shader_recompiler/frontend/ir/opcodes.h
-
1src/shader_recompiler/frontend/maxwell/control_flow.cpp
-
1src/shader_recompiler/frontend/maxwell/decode.cpp
-
1src/shader_recompiler/frontend/maxwell/structured_control_flow.cpp
-
7src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
-
2src/video_core/buffer_cache/buffer_base.h
-
1src/video_core/buffer_cache/buffer_cache.h
-
2src/video_core/control/channel_state_cache.h
-
2src/video_core/gpu_thread.cpp
-
1src/video_core/gpu_thread.h
-
2src/video_core/rasterizer_interface.h
-
1src/video_core/renderer_opengl/gl_device.cpp
-
1src/video_core/renderer_opengl/gl_shader_cache.h
-
1src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
-
1src/video_core/renderer_vulkan/vk_blit_screen.cpp
-
1src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
-
1src/video_core/renderer_vulkan/vk_master_semaphore.h
-
2src/video_core/renderer_vulkan/vk_render_pass_cache.h
-
2src/video_core/renderer_vulkan/vk_scheduler.cpp
-
1src/video_core/renderer_vulkan/vk_scheduler.h
-
1src/video_core/renderer_vulkan/vk_swapchain.cpp
-
1src/video_core/shader_cache.h
-
1src/video_core/shader_environment.cpp
-
2src/video_core/shader_environment.h
-
1src/video_core/texture_cache/formatter.cpp
-
2src/video_core/texture_cache/render_targets.h
-
1src/video_core/texture_cache/slot_vector.h
-
3src/video_core/texture_cache/texture_cache_base.h
-
1src/video_core/textures/astc.cpp
-
1src/video_core/transform_feedback.cpp
-
1src/video_core/vulkan_common/vulkan_device.cpp
-
1src/video_core/vulkan_common/vulkan_instance.cpp
-
1src/video_core/vulkan_common/vulkan_memory_allocator.cpp
-
2src/yuzu/bootmanager.cpp
-
1src/yuzu/bootmanager.h
-
6src/yuzu/main.cpp
-
1src/yuzu/multiplayer/chat_room.h
@ -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 |
|||
@ -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 |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue