[common] Switch to boost::unordered_flat containers (#4326)

Replaces all instances of ankerl's unordered map/set with boost's
`unordered_flat_*` classes. This uses std::hash since boost::hash is
actually a lot slower.

Also adds an abstraction layer in `Common` so future changes are quicker
and easier.

Other implementation details:
- ankerl provided hash specializations for tuple and pair, so those were
  ported here
- std::erase_if doesn't work on boost, so just used the ADL'd erase_if

This should be about equal or superior performance as unordered_dense for everything except iteration.

Signed-off-by: crueter <crueter@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4326
Reviewed-by: Lizzie and Samuel <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
This commit is contained in:
crueter
2026-08-31 02:58:09 +02:00
parent 106a61c943
commit 7fda6dde73
118 changed files with 348 additions and 340 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
#include <atomic>
#include <memory>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include <dynarmic/interface/A64/a64.h>
#include <dynarmic/interface/code_page.h>
+2 -2
View File
@@ -4,7 +4,7 @@
#pragma once
#include <span>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include <vector>
#include <oaknut/code_block.hpp>
#include <oaknut/oaknut.hpp>
@@ -46,7 +46,7 @@ enum class PatchMode : u32 {
using ModuleTextAddress = u64;
using PatchTextAddress = u64;
using EntryTrampolines = ankerl::unordered_dense::map<ModuleTextAddress, PatchTextAddress>;
using EntryTrampolines = ::Common::unordered_map<ModuleTextAddress, PatchTextAddress>;
class Patcher {
public:
+2 -2
View File
@@ -8,7 +8,7 @@
#include <utility>
#include <span>
#include <cctype>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include "common/hex_util.h"
#include "common/logging.h"
@@ -104,7 +104,7 @@ struct IPSwitchRecord {
size_t count;
};
struct IPSwitchCompiler::IPSwitchPatch {
ankerl::unordered_dense::map<u32, IPSwitchRecord> records;
::Common::unordered_map<u32, IPSwitchRecord> records;
bool enabled;
};
+1 -1
View File
@@ -566,7 +566,7 @@ VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
return file;
}
static std::optional<NcaID> CheckMapForContentRecord(const ankerl::unordered_dense::map<u64, CNMT>& map, u64 title_id, ContentRecordType type) {
static std::optional<NcaID> CheckMapForContentRecord(const ::Common::unordered_map<u64, CNMT>& map, u64 title_id, ContentRecordType type) {
auto cmnt_iter = map.find(title_id);
u8 id_offset = 0;
+6 -6
View File
@@ -12,7 +12,7 @@
#include <optional>
#include <string>
#include <vector>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include <boost/container/flat_map.hpp>
#include "common/common_types.h"
#include "core/crypto/key_manager.h"
@@ -209,11 +209,11 @@ private:
ContentProviderParsingFunction parser;
// maps tid -> NcaID of meta
ankerl::unordered_dense::map<u64, NcaID> meta_id;
::Common::unordered_map<u64, NcaID> meta_id;
// maps tid -> meta
ankerl::unordered_dense::map<u64, CNMT> meta;
::Common::unordered_map<u64, CNMT> meta;
// maps tid -> meta for CNMT in yuzu_meta
ankerl::unordered_dense::map<u64, CNMT> yuzu_meta;
::Common::unordered_map<u64, CNMT> yuzu_meta;
};
enum class ContentProviderUnionSlot {
@@ -313,8 +313,8 @@ private:
void ProcessXCI(const VirtualFile& file);
std::vector<VirtualDir> load_dirs;
ankerl::unordered_dense::map<std::tuple<u64, ContentRecordType, TitleType>, VirtualFile> entries;
ankerl::unordered_dense::map<u64, u32> versions;
::Common::unordered_map<std::tuple<u64, ContentRecordType, TitleType>, VirtualFile> entries;
::Common::unordered_map<u64, u32> versions;
std::vector<ExternalUpdateEntry> multi_version_entries;
};
+3 -3
View File
@@ -6,7 +6,7 @@
#include <algorithm>
#include <set>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_set.h"
#include <utility>
#include "core/file_sys/vfs/vfs_layered.h"
@@ -63,7 +63,7 @@ std::string LayeredVfsDirectory::GetFullPath() const {
std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
std::vector<VirtualFile> out;
ankerl::unordered_dense::set<std::string> out_names;
::Common::unordered_set<std::string> out_names;
for (const auto& layer : dirs) {
for (auto& file : layer->GetFiles()) {
@@ -79,7 +79,7 @@ std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const {
std::vector<VirtualDir> out;
ankerl::unordered_dense::set<std::string> out_names;
::Common::unordered_set<std::string> out_names;
for (const auto& layer : dirs) {
for (const auto& sd : layer->GetSubdirectories()) {
+2 -2
View File
@@ -78,7 +78,7 @@ private:
std::array<DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS> m_watchpoints{};
std::map<KProcessAddress, u64> m_debug_page_refcounts{};
#ifdef HAS_NCE
ankerl::unordered_dense::map<u64, u64> m_post_handlers{};
::Common::unordered_map<u64, u64> m_post_handlers{};
#endif
std::unique_ptr<Core::ExclusiveMonitor> m_exclusive_monitor;
Core::Memory::Memory m_memory;
@@ -494,7 +494,7 @@ public:
static void Switch(KernelCore& kernel, KProcess* cur_process, KProcess* next_process);
#ifdef HAS_NCE
ankerl::unordered_dense::map<u64, u64>& GetPostHandlers() noexcept {
::Common::unordered_map<u64, u64>& GetPostHandlers() noexcept {
return m_post_handlers;
}
#endif
+4 -3
View File
@@ -10,7 +10,8 @@
#include <functional>
#include <memory>
#include <thread>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include "common/container/unordered_set.h"
#include <utility>
#include "common/assert.h"
@@ -792,8 +793,8 @@ struct KernelCore::Impl {
std::optional<KObjectNameGlobalData> object_name_global_data;
ankerl::unordered_dense::set<KAutoObject*> registered_objects;
ankerl::unordered_dense::set<KAutoObject*> registered_in_use_objects;
::Common::unordered_set<KAutoObject*> registered_objects;
::Common::unordered_set<KAutoObject*> registered_in_use_objects;
std::mutex server_lock;
std::vector<std::unique_ptr<Service::ServerManager>> server_managers;
+1 -1
View File
@@ -11,7 +11,7 @@
#include <list>
#include <memory>
#include <string>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include <vector>
#include "common/polyfill_thread.h"
@@ -7,7 +7,7 @@
#pragma once
#include <array>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include <vector>
#include "common/common_funcs.h"
@@ -176,6 +176,6 @@ struct WebCommonReturnValue {
};
static_assert(sizeof(WebCommonReturnValue) == 0x1010, "WebCommonReturnValue has incorrect size.");
using WebArgInputTLVMap = ankerl::unordered_dense::map<WebArgInputTLVType, std::vector<u8>>;
using WebArgInputTLVMap = ::Common::unordered_map<WebArgInputTLVType, std::vector<u8>>;
} // namespace Service::AM::Frontend
@@ -40,8 +40,8 @@ std::vector<u8> default_logo_small;
std::vector<u8> default_logo_large;
bool default_logos_loaded = false;
ankerl::unordered_dense::map<std::string, std::vector<u8>> news_images_small;
ankerl::unordered_dense::map<std::string, std::vector<u8>> news_images_large;
::Common::unordered_map<std::string, std::vector<u8>> news_images_small;
::Common::unordered_map<std::string, std::vector<u8>> news_images_large;
std::mutex images_mutex;
@@ -12,7 +12,7 @@
#include <optional>
#include <span>
#include <string>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include <vector>
#include "common/common_types.h"
@@ -93,7 +93,7 @@ private:
static s64 Now();
mutable std::mutex mtx;
ankerl::unordered_dense::map<std::string, StoredNews> items;
::Common::unordered_map<std::string, StoredNews> items;
size_t open_counter{};
};
+2 -2
View File
@@ -6,7 +6,7 @@
#pragma once
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include "common/fs/fs.h"
#include "core/hle/result.h"
@@ -88,7 +88,7 @@ private:
AlbumFileDateTime ConvertToAlbumDateTime(u64 posix_time) const;
bool is_mounted{};
ankerl::unordered_dense::map<AlbumFileId, std::filesystem::path> album_files;
::Common::unordered_map<AlbumFileId, std::filesystem::path> album_files;
Core::System& system;
};
+2 -2
View File
@@ -15,7 +15,7 @@
#include <random>
#include <span>
#include <thread>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include "common/logging.h"
#include "common/socket_types.h"
@@ -119,7 +119,7 @@ protected:
std::array<LanStation, StationCountMax> stations;
std::array<NodeLatestUpdate, NodeCountMax> node_changes{};
std::array<u8, NodeCountMax> node_last_states{};
ankerl::unordered_dense::map<MacAddress, NetworkInfo, MACAddressHash> scan_results{};
::Common::unordered_map<MacAddress, NetworkInfo, MACAddressHash> scan_results{};
NodeInfo node_info{};
NetworkInfo network_info{};
State state{State::None};
+2 -2
View File
@@ -7,7 +7,7 @@
#include <string>
#include <optional>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include <boost/container_hash/hash.hpp>
#include "common/logging.h"
#include "core/core.h"
@@ -331,7 +331,7 @@ private:
};
static_assert(sizeof(LogPacketHeader) == 0x18, "LogPacketHeader is an invalid size");
ankerl::unordered_dense::map<LogPacketHeaderEntry, std::vector<u8>> entries{};
::Common::unordered_map<LogPacketHeaderEntry, std::vector<u8>> entries{};
LogDestination destination{LogDestination::All};
};
+1 -1
View File
@@ -23,7 +23,7 @@
#include <mutex>
#include <optional>
#include <thread>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include <common/settings.h>
#ifdef _WIN32
+1 -1
View File
@@ -9,7 +9,7 @@
#include <deque>
#include <memory>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include "core/device_memory_manager.h"
#include "core/hle/service/nvdrv/nvdata.h"
+2 -2
View File
@@ -12,7 +12,7 @@
#include <memory>
#include <mutex>
#include <optional>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include <assert.h>
#include "common/bit_field.h"
@@ -161,7 +161,7 @@ private:
std::list<std::shared_ptr<Handle>> unmap_queue{};
std::mutex unmap_queue_lock{}; //!< Protects access to `unmap_queue`
ankerl::unordered_dense::map<Handle::Id, std::shared_ptr<Handle>>
::Common::unordered_map<Handle::Id, std::shared_ptr<Handle>>
handles{}; //!< Main owning map of handles
std::mutex handles_lock; //!< Protects access to `handles`
@@ -13,7 +13,7 @@
#include <memory>
#include <mutex>
#include <optional>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_set.h"
#include <vector>
#include "common/address_space.h"
@@ -113,7 +113,7 @@ private:
};
static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size");
ankerl::unordered_dense::set<s64_le> map_buffer_offsets{};
::Common::unordered_set<s64_le> map_buffer_offsets{};
struct IoctlMapBufferEx {
MappingFlags flags{}; // bit0: fixed_offset, bit2: cacheable
@@ -217,7 +217,7 @@ private:
NvCore::SyncpointManager& syncpoint_manager;
NvCore::NvMap& nvmap;
std::shared_ptr<Tegra::Control::ChannelState> channel_state;
ankerl::unordered_dense::map<DeviceFD, NvCore::SessionId> sessions;
::Common::unordered_map<DeviceFD, NvCore::SessionId> sessions;
u32 channel_syncpoint;
std::mutex channel_mutex;
@@ -7,7 +7,7 @@
#pragma once
#include <deque>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include <vector>
#include "common/common_types.h"
@@ -138,7 +138,7 @@ protected:
NvCore::NvMap& nvmap;
NvCore::ChannelType channel_type;
std::array<u32, MaxSyncPoints> device_syncpoints{};
ankerl::unordered_dense::map<DeviceFD, NvCore::SessionId> sessions;
::Common::unordered_map<DeviceFD, NvCore::SessionId> sessions;
};
}; // namespace Devices
} // namespace Service::Nvidia
+2 -2
View File
@@ -7,7 +7,7 @@
#pragma once
#include <memory>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include <vector>
#include "common/common_funcs.h"
#include "common/common_types.h"
@@ -118,7 +118,7 @@ private:
NvCore::Container& container;
NvCore::NvMap& file;
ankerl::unordered_dense::map<DeviceFD, NvCore::SessionId> sessions;
::Common::unordered_map<DeviceFD, NvCore::SessionId> sessions;
};
} // namespace Service::Nvidia::Devices
+3 -3
View File
@@ -12,7 +12,7 @@
#include <memory>
#include <span>
#include <string>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include "common/common_types.h"
#include "core/hle/service/kernel_helpers.h"
@@ -103,7 +103,7 @@ private:
/// Id to use for the next open file descriptor.
DeviceFD next_fd = 1;
using FilesContainerType = ankerl::unordered_dense::map<DeviceFD, std::shared_ptr<Devices::nvdevice>>;
using FilesContainerType = ::Common::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>>;
/// Mapping of file descriptors to the devices they reference.
FilesContainerType open_files;
@@ -111,7 +111,7 @@ private:
EventInterface events_interface;
ankerl::unordered_dense::map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders;
::Common::unordered_map<std::string, std::function<FilesContainerType::iterator(DeviceFD)>> builders;
};
void LoopProcess(Core::System& system);
@@ -8,7 +8,7 @@
#include <memory>
#include <mutex>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include "common/common_types.h"
#include "core/hle/service/nvnflinger/binder.h"
@@ -39,8 +39,8 @@ private:
mutable std::mutex lock;
s32 last_id = 0;
ankerl::unordered_dense::map<s32, std::shared_ptr<android::IBinder>> binders;
ankerl::unordered_dense::map<s32, RefCounts> refcounts;
::Common::unordered_map<s32, std::shared_ptr<android::IBinder>> binders;
::Common::unordered_map<s32, RefCounts> refcounts;
};
} // namespace Service::Nvnflinger
@@ -6,7 +6,7 @@
#pragma once
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include "common/uuid.h"
#include "core/hle/service/cmif_types.h"
@@ -56,10 +56,10 @@ private:
}
};
ankerl::unordered_dense::map<AppKey, bool, AppKeyHash> app_auto_transfer_{};
ankerl::unordered_dense::map<Common::UUID, bool> global_auto_upload_{};
ankerl::unordered_dense::map<Common::UUID, bool> global_auto_download_{};
ankerl::unordered_dense::map<AppKey, u8, AppKeyHash> autonomy_task_status_{};
::Common::unordered_map<AppKey, bool, AppKeyHash> app_auto_transfer_{};
::Common::unordered_map<Common::UUID, bool> global_auto_upload_{};
::Common::unordered_map<Common::UUID, bool> global_auto_download_{};
::Common::unordered_map<AppKey, u8, AppKeyHash> autonomy_task_status_{};
};
} // namespace Service::OLSC
+3 -3
View File
@@ -8,7 +8,7 @@
#include <cstddef>
#include <mutex>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include "common/common_types.h"
#include "core/hle/service/hle_ipc.h"
@@ -99,8 +99,8 @@ private:
void ReportUnimplementedFunction(HLERequestContext& ctx, const FunctionInfoBase* info);
protected:
ankerl::unordered_dense::map<u32, FunctionInfoBase> handlers;
ankerl::unordered_dense::map<u32, FunctionInfoBase> handlers_tipc;
::Common::unordered_map<u32, FunctionInfoBase> handlers;
::Common::unordered_map<u32, FunctionInfoBase> handlers_tipc;
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
std::mutex lock_service;
/// System context that the service operates under.
+3 -3
View File
@@ -10,7 +10,7 @@
#include <memory>
#include <mutex>
#include <string>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include <concepts>
#include "core/hle/kernel/k_port.h"
@@ -100,8 +100,8 @@ private:
/// Map of registered services, retrieved using GetServicePort.
mutable std::mutex lock;
ankerl::unordered_dense::map<std::string, SessionRequestHandlerFactory> registered_services;
ankerl::unordered_dense::map<std::string, Kernel::KClientPort*> service_ports;
::Common::unordered_map<std::string, SessionRequestHandlerFactory> registered_services;
::Common::unordered_map<std::string, Kernel::KClientPort*> service_ports;
/// Kernel context
Kernel::KernelCore& kernel;
+2 -2
View File
@@ -7,7 +7,7 @@
#pragma once
#include <memory>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include "common/common_types.h"
#include "common/polyfill_thread.h"
@@ -49,7 +49,7 @@ private:
private:
Core::System& m_system;
Container& m_container;
ankerl::unordered_dense::map<u64, VsyncManager> m_vsync_managers;
::Common::unordered_map<u64, VsyncManager> m_vsync_managers;
std::shared_ptr<Core::Timing::EventType> m_event;
Common::Event m_signal;
std::jthread m_thread;
+3 -3
View File
@@ -8,7 +8,7 @@
#include <mutex>
#include <sstream>
#include <string>
#include <ankerl/unordered_dense.h>
#include "common/container/unordered_map.h"
#include <fmt/format.h>
#include <nlohmann/json.hpp>
@@ -21,8 +21,8 @@
namespace Core::LaunchTimestampCache {
namespace {
using CacheMap = ankerl::unordered_dense::map<u64, s64>;
using CountMap = ankerl::unordered_dense::map<u64, u64>;
using CacheMap = ::Common::unordered_map<u64, s64>;
using CountMap = ::Common::unordered_map<u64, u64>;
std::mutex g_mutex;
CacheMap g_cache;