2020-12-05 13:08:24 +01:00
|
|
|
#pragma once
|
2015-03-06 23:58:42 +01:00
|
|
|
|
2020-12-12 13:01:29 +01:00
|
|
|
#include "util/types.hpp"
|
2025-04-08 18:46:57 +02:00
|
|
|
#include "util/mutex.h"
|
2015-11-30 16:10:17 +01:00
|
|
|
|
2016-04-27 00:27:24 +02:00
|
|
|
#include <memory>
|
|
|
|
|
#include <vector>
|
2024-12-22 19:59:48 +01:00
|
|
|
#include <span>
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
#include "util/serialization.hpp"
|
2024-12-22 19:59:48 +01:00
|
|
|
#include "util/shared_ptr.hpp"
|
2021-03-30 18:37:51 +02:00
|
|
|
#include "util/fixed_typemap.hpp"
|
|
|
|
|
|
|
|
|
|
extern stx::manual_typemap<void, 0x20'00000, 128> g_fixed_typemap;
|
|
|
|
|
|
|
|
|
|
constexpr auto* g_fxo = &g_fixed_typemap;
|
|
|
|
|
|
2021-06-05 21:15:15 +02:00
|
|
|
enum class thread_state : u32;
|
|
|
|
|
|
2023-12-25 13:35:09 +01:00
|
|
|
extern u16 serial_breathe_and_tag(utils::serial& ar, std::string_view name, bool tag_bit);
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
template <typename T>
|
2025-04-05 21:50:45 +02:00
|
|
|
concept IdmCompatible = requires() { u32{T::id_base}, u32{T::id_step}, u32{T::id_count}; };
|
2024-12-22 19:59:48 +01:00
|
|
|
|
|
|
|
|
template <typename T>
|
2025-04-05 21:50:45 +02:00
|
|
|
concept IdmBaseCompatible = (std::is_final_v<T> ? IdmCompatible<T> : !!(requires() { u32{T::id_step}, u32{T::id_count}; }));
|
2024-12-22 19:59:48 +01:00
|
|
|
|
|
|
|
|
template <typename T>
|
2025-04-24 12:41:04 +02:00
|
|
|
concept IdmSavable = IdmBaseCompatible<T> && T::savestate_init_pos != 0 && (requires(T& t, utils::serial& ar) { t.save(exact_t<utils::serial&>(ar)); });
|
2024-12-22 19:59:48 +01:00
|
|
|
|
|
|
|
|
// If id_base is declared in base type, than storage type must declare id_type
|
|
|
|
|
template <typename Base, typename Type>
|
2025-04-05 21:50:45 +02:00
|
|
|
concept IdmTypesCompatible = PtrSame<Base, Type> && IdmCompatible<Type> && IdmBaseCompatible<Base> && (std::is_same_v<Base, Type> || !IdmCompatible<Base> || !!(requires() { u32{Type::id_type}; }));
|
2024-12-22 19:59:48 +01:00
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
// Helper namespace
|
2016-04-14 00:59:00 +02:00
|
|
|
namespace id_manager
|
2015-11-26 09:06:29 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
using pointer_keeper = std::function<void(void*)>;
|
|
|
|
|
|
2017-01-25 18:50:30 +01:00
|
|
|
// Common global mutex
|
|
|
|
|
extern shared_mutex g_mutex;
|
|
|
|
|
|
2021-06-16 17:14:49 +02:00
|
|
|
template <typename T>
|
|
|
|
|
constexpr std::pair<u32, u32> get_invl_range()
|
2016-04-14 00:59:00 +02:00
|
|
|
{
|
2021-06-16 17:14:49 +02:00
|
|
|
return {0, 0};
|
|
|
|
|
}
|
2019-11-28 11:17:16 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
template <typename T>
|
|
|
|
|
requires requires() { T::id_invl_range.first + T::id_invl_range.second; }
|
2021-06-16 17:14:49 +02:00
|
|
|
constexpr std::pair<u32, u32> get_invl_range()
|
2019-11-28 11:17:16 +01:00
|
|
|
{
|
2021-06-16 17:14:49 +02:00
|
|
|
return T::id_invl_range;
|
|
|
|
|
}
|
2019-11-28 11:17:16 +01:00
|
|
|
|
2022-09-04 14:29:35 +02:00
|
|
|
template <typename T>
|
|
|
|
|
consteval bool get_force_lowest_id()
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
template <typename T>
|
|
|
|
|
requires requires() { bool{T::id_lowest}; }
|
2022-09-04 14:29:35 +02:00
|
|
|
consteval bool get_force_lowest_id()
|
|
|
|
|
{
|
|
|
|
|
return T::id_lowest;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
// Last allocated ID for constructors
|
|
|
|
|
extern thread_local u32 g_id;
|
|
|
|
|
|
2021-06-16 17:14:49 +02:00
|
|
|
// ID traits
|
2017-01-29 17:50:18 +01:00
|
|
|
template <typename T>
|
2021-06-16 17:14:49 +02:00
|
|
|
struct id_traits
|
2016-04-14 00:59:00 +02:00
|
|
|
{
|
2021-06-16 17:14:49 +02:00
|
|
|
static_assert(IdmCompatible<T>, "ID object must specify: id_base, id_step, id_count");
|
2019-11-28 11:17:16 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static constexpr u32 base = T::id_base; // First ID (N = 0)
|
|
|
|
|
static constexpr u32 step = T::id_step; // Any ID: N * id_setp + id_base
|
2022-09-13 15:08:55 +02:00
|
|
|
static constexpr u32 count = T::id_count; // Limit: N < id_count
|
2025-04-05 21:50:45 +02:00
|
|
|
static constexpr u32 invalid = -+!base; // Invalid ID sample
|
2021-06-16 17:14:49 +02:00
|
|
|
|
|
|
|
|
static constexpr std::pair<u32, u32> invl_range = get_invl_range<T>();
|
2022-09-04 14:29:35 +02:00
|
|
|
static constexpr bool uses_lowest_id = get_force_lowest_id<T>();
|
2015-11-26 09:06:29 +01:00
|
|
|
|
2023-07-11 20:40:30 +02:00
|
|
|
static_assert(u32{count} && u32{step} && u64{step} * (count - 1) + base < u32{umax} + u64{base != 0 ? 1 : 0}, "ID traits: invalid object range");
|
2020-12-12 13:01:29 +01:00
|
|
|
|
2019-11-28 11:17:16 +01:00
|
|
|
// TODO: Add more conditions
|
2025-04-05 21:50:45 +02:00
|
|
|
static_assert(!invl_range.second || (u64{invl_range.second} + invl_range.first <= 32 /*....*/));
|
2016-04-14 00:59:00 +02:00
|
|
|
};
|
2015-08-11 18:14:53 +02:00
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
static constexpr u32 get_index(u32 id, u32 base, u32 step, u32 count, std::pair<u32, u32> invl_range)
|
2016-04-14 00:59:00 +02:00
|
|
|
{
|
2022-07-04 15:02:17 +02:00
|
|
|
u32 mask_out = ((1u << invl_range.second) - 1) << invl_range.first;
|
2015-11-26 09:06:29 +01:00
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
// Note: if id is lower than base, diff / step will be higher than count
|
|
|
|
|
u32 diff = (id & ~mask_out) - base;
|
2016-04-14 00:59:00 +02:00
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
if (diff % step)
|
|
|
|
|
{
|
|
|
|
|
// id is invalid, return invalid index
|
|
|
|
|
return count;
|
2017-01-29 17:50:18 +01:00
|
|
|
}
|
2016-04-14 00:59:00 +02:00
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
// Get actual index
|
|
|
|
|
return diff / step;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ID traits
|
2025-01-03 11:00:18 +01:00
|
|
|
template <typename T>
|
2022-07-04 15:02:17 +02:00
|
|
|
struct id_traits_load_func
|
|
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
static constexpr pointer_keeper (*load)(utils::serial&) = [](utils::serial& ar) -> pointer_keeper {
|
2024-12-22 19:59:48 +01:00
|
|
|
stx::shared_ptr<T> ptr;
|
|
|
|
|
|
2025-04-24 12:41:04 +02:00
|
|
|
if constexpr (std::is_constructible_v<T, exact_t<const stx::launch_retainer&>, exact_t<utils::serial&>>)
|
2023-12-28 18:37:24 +01:00
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
ptr = stx::make_shared<T>(stx::launch_retainer{}, exact_t<utils::serial&>(ar));
|
2023-12-28 18:37:24 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
ptr = stx::make_shared<T>(exact_t<utils::serial&>(ar));
|
2023-12-28 18:37:24 +01:00
|
|
|
}
|
2024-12-22 19:59:48 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
return [ptr](void* storage)
|
|
|
|
|
{
|
|
|
|
|
*static_cast<stx::atomic_ptr<T>*>(storage) = ptr;
|
|
|
|
|
};
|
2023-12-28 18:37:24 +01:00
|
|
|
};
|
2022-07-04 15:02:17 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
2025-01-03 11:00:18 +01:00
|
|
|
requires requires() { &T::load; }
|
|
|
|
|
struct id_traits_load_func<T>
|
2022-07-04 15:02:17 +02:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
static constexpr pointer_keeper (*load)(utils::serial&) = [](utils::serial& ar) -> pointer_keeper {
|
2025-04-24 12:41:04 +02:00
|
|
|
return T::load(exact_t<utils::serial&>(ar));
|
2023-12-28 18:37:24 +01:00
|
|
|
};
|
2022-07-04 15:02:17 +02:00
|
|
|
};
|
|
|
|
|
|
2025-01-03 11:00:18 +01:00
|
|
|
template <typename T>
|
2022-07-04 15:02:17 +02:00
|
|
|
struct id_traits_savable_func
|
|
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
static constexpr bool (*savable)(void*) = [](void*) -> bool
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
};
|
2022-07-04 15:02:17 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
2025-01-03 11:00:18 +01:00
|
|
|
requires requires { &T::savable; }
|
|
|
|
|
struct id_traits_savable_func<T>
|
2022-07-04 15:02:17 +02:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
static constexpr bool (*savable)(void* ptr) = [](void* ptr) -> bool
|
|
|
|
|
{
|
|
|
|
|
return static_cast<const T*>(ptr)->savable();
|
|
|
|
|
};
|
2022-07-04 15:02:17 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct dummy_construct
|
|
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
dummy_construct() = default;
|
|
|
|
|
dummy_construct(utils::serial&) noexcept {}
|
2022-07-04 15:02:17 +02:00
|
|
|
void save(utils::serial&) {}
|
|
|
|
|
|
|
|
|
|
static constexpr u32 id_base = 1, id_step = 1, id_count = 1;
|
|
|
|
|
static constexpr double savestate_init_pos = 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct typeinfo;
|
|
|
|
|
|
|
|
|
|
// Use a vector instead of map to reduce header dependencies in this commonly used header
|
|
|
|
|
std::vector<std::pair<u128, typeinfo>>& get_typeinfo_map();
|
|
|
|
|
|
|
|
|
|
struct typeinfo
|
|
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
public:
|
2025-04-05 21:50:45 +02:00
|
|
|
std::function<void(void*)> (*load)(utils::serial&);
|
|
|
|
|
void (*save)(utils::serial&, void*);
|
|
|
|
|
bool (*savable)(void* ptr);
|
2022-07-04 15:02:17 +02:00
|
|
|
|
|
|
|
|
u32 base;
|
|
|
|
|
u32 step;
|
|
|
|
|
u32 count;
|
2022-09-04 14:29:35 +02:00
|
|
|
bool uses_lowest_id;
|
2022-07-04 15:02:17 +02:00
|
|
|
std::pair<u32, u32> invl_range;
|
|
|
|
|
|
|
|
|
|
// Unique type ID within the same container: we use id_base if nothing else was specified
|
|
|
|
|
template <typename T>
|
|
|
|
|
static consteval u32 get_type()
|
2016-06-21 10:22:30 +02:00
|
|
|
{
|
2022-07-04 15:02:17 +02:00
|
|
|
return T::id_base;
|
2016-04-14 00:59:00 +02:00
|
|
|
}
|
2015-09-18 00:41:14 +02:00
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
// Specified type ID for containers which their types may be sharing an overlapping IDs range
|
2025-04-05 21:50:45 +02:00
|
|
|
template <typename T>
|
|
|
|
|
requires requires() { u32{T::id_type}; }
|
2022-07-04 15:02:17 +02:00
|
|
|
static consteval u32 get_type()
|
|
|
|
|
{
|
|
|
|
|
return T::id_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
static typeinfo make_typeinfo()
|
|
|
|
|
{
|
|
|
|
|
typeinfo info{};
|
|
|
|
|
|
2023-10-05 03:20:27 +02:00
|
|
|
using C = std::conditional_t<IdmCompatible<T> && IdmSavable<T>, T, dummy_construct>;
|
2022-07-04 15:02:17 +02:00
|
|
|
using Type = std::conditional_t<IdmCompatible<T>, T, dummy_construct>;
|
|
|
|
|
|
|
|
|
|
if constexpr (std::is_same_v<C, T>)
|
|
|
|
|
{
|
|
|
|
|
info =
|
2025-04-05 21:50:45 +02:00
|
|
|
{
|
|
|
|
|
+id_traits_load_func<C>::load,
|
|
|
|
|
+[](utils::serial& ar, void* obj)
|
|
|
|
|
{
|
|
|
|
|
static_cast<C*>(obj)->save(ar);
|
|
|
|
|
},
|
|
|
|
|
+id_traits_savable_func<C>::savable,
|
|
|
|
|
id_traits<C>::base,
|
|
|
|
|
id_traits<C>::step,
|
|
|
|
|
id_traits<C>::count,
|
|
|
|
|
id_traits<C>::uses_lowest_id,
|
|
|
|
|
id_traits<C>::invl_range,
|
|
|
|
|
};
|
2022-07-04 15:02:17 +02:00
|
|
|
|
|
|
|
|
const u128 key = u128{get_type<C>()} << 64 | std::bit_cast<u64>(C::savestate_init_pos);
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
for (const auto& [tkey, tinfo] : get_typeinfo_map())
|
2022-07-04 15:02:17 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
if (!(tkey ^ key))
|
2022-07-04 15:02:17 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
ensure(tinfo == info);
|
2022-07-04 15:02:17 +02:00
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// id_base must be unique within all the objects with the same initialization posistion by definition of id_map with multiple types
|
|
|
|
|
get_typeinfo_map().emplace_back(key, info);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
info =
|
2025-04-05 21:50:45 +02:00
|
|
|
{
|
|
|
|
|
nullptr,
|
|
|
|
|
nullptr,
|
|
|
|
|
nullptr,
|
|
|
|
|
id_traits<Type>::base,
|
|
|
|
|
id_traits<Type>::step,
|
|
|
|
|
id_traits<Type>::count,
|
|
|
|
|
id_traits<Type>::uses_lowest_id,
|
|
|
|
|
id_traits<Type>::invl_range,
|
|
|
|
|
};
|
2022-07-04 15:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return info;
|
|
|
|
|
}
|
2024-12-22 19:59:48 +01:00
|
|
|
|
|
|
|
|
bool operator==(const typeinfo& rhs) const noexcept
|
|
|
|
|
{
|
|
|
|
|
return base == rhs.base && invl_range == rhs.invl_range && save == rhs.save;
|
|
|
|
|
}
|
2022-07-04 15:02:17 +02:00
|
|
|
};
|
2016-08-01 00:35:53 +02:00
|
|
|
|
|
|
|
|
// ID value with additional type stored
|
|
|
|
|
class id_key
|
|
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
u32 m_value = 0; // ID value
|
|
|
|
|
u32 m_base = umax; // ID base (must be unique for each type in the same container)
|
2016-08-01 00:35:53 +02:00
|
|
|
|
|
|
|
|
public:
|
2024-12-22 19:59:48 +01:00
|
|
|
id_key() noexcept = default;
|
2016-08-01 00:35:53 +02:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
id_key(u32 value, u32 type) noexcept
|
2025-04-05 21:50:45 +02:00
|
|
|
: m_value(value), m_base(type)
|
2016-08-01 00:35:53 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
u32 value() const
|
2016-08-01 00:35:53 +02:00
|
|
|
{
|
|
|
|
|
return m_value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 type() const
|
|
|
|
|
{
|
2022-07-04 15:02:17 +02:00
|
|
|
return m_base;
|
2016-08-01 00:35:53 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
void clear()
|
|
|
|
|
{
|
|
|
|
|
m_base = umax;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
operator u32() const noexcept
|
2017-01-28 15:59:43 +01:00
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
return m_value;
|
2017-01-28 15:59:43 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2021-03-30 18:37:51 +02:00
|
|
|
template <typename T>
|
|
|
|
|
struct id_map
|
|
|
|
|
{
|
2023-10-05 03:20:27 +02:00
|
|
|
static_assert(IdmBaseCompatible<T>, "Please specify IDM compatible type.");
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
std::array<stx::atomic_ptr<T>, T::id_count> vec_data{};
|
|
|
|
|
std::array<stx::shared_ptr<T>, T::id_count> private_copy{};
|
|
|
|
|
std::array<id_key, T::id_count> vec_keys{};
|
2024-12-28 12:31:17 +01:00
|
|
|
u32 highest_index = 0;
|
2024-12-22 19:59:48 +01:00
|
|
|
|
2021-04-19 10:11:24 +02:00
|
|
|
shared_mutex mutex{}; // TODO: Use this instead of global mutex
|
2021-03-30 18:37:51 +02:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
id_map() noexcept = default;
|
2021-06-05 21:15:15 +02:00
|
|
|
|
2022-07-04 19:12:22 +02:00
|
|
|
// Order it directly before the source type's position
|
2023-06-11 22:45:47 +02:00
|
|
|
static constexpr double savestate_init_pos_original = T::savestate_init_pos;
|
|
|
|
|
static constexpr double savestate_init_pos = std::bit_cast<double>(std::bit_cast<u64>(savestate_init_pos_original) - 1);
|
2022-07-04 15:02:17 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
id_map(utils::serial& ar) noexcept
|
|
|
|
|
requires IdmSavable<T>
|
2022-07-04 15:02:17 +02:00
|
|
|
{
|
2023-12-25 13:35:09 +01:00
|
|
|
while (true)
|
2022-07-04 15:02:17 +02:00
|
|
|
{
|
2023-12-25 13:35:09 +01:00
|
|
|
const u16 tag = serial_breathe_and_tag(ar, g_fxo->get_name<id_map<T>>(), false);
|
|
|
|
|
|
|
|
|
|
if (tag >> 15)
|
|
|
|
|
{
|
|
|
|
|
// End
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
// ID, type hash
|
2023-12-25 13:35:09 +01:00
|
|
|
const u32 id = ar.pop<u32>();
|
2022-07-04 15:02:17 +02:00
|
|
|
|
2023-12-25 13:35:09 +01:00
|
|
|
const u128 type_init_pos = u128{ar.pop<u32>()} << 64 | std::bit_cast<u64>(T::savestate_init_pos);
|
2022-07-04 15:02:17 +02:00
|
|
|
const typeinfo* info = nullptr;
|
|
|
|
|
|
|
|
|
|
// Search load functions for the one of this type (see make_typeinfo() for explenation about key composition reasoning)
|
|
|
|
|
for (const auto& typeinfo : get_typeinfo_map())
|
|
|
|
|
{
|
|
|
|
|
if (!(typeinfo.first ^ type_init_pos))
|
|
|
|
|
{
|
|
|
|
|
info = std::addressof(typeinfo.second);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-13 15:08:55 +02:00
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
ensure(info);
|
|
|
|
|
|
|
|
|
|
// Construct each object from information collected
|
|
|
|
|
|
|
|
|
|
// Simulate construction semantics (idm::last_id() value)
|
|
|
|
|
g_id = id;
|
|
|
|
|
|
2024-12-28 12:31:17 +01:00
|
|
|
const u32 object_index = get_index(id, info->base, info->step, info->count, info->invl_range);
|
2024-12-22 19:59:48 +01:00
|
|
|
auto& obj = ::at32(vec_data, object_index);
|
|
|
|
|
ensure(!obj);
|
2022-07-04 15:02:17 +02:00
|
|
|
|
2024-12-28 12:31:17 +01:00
|
|
|
highest_index = std::max(highest_index, object_index + 1);
|
2023-12-25 13:35:09 +01:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
vec_keys[object_index] = id_key(id, static_cast<u32>(static_cast<u64>(type_init_pos >> 64)));
|
|
|
|
|
info->load(ar)(&obj);
|
2022-07-04 15:02:17 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
void save(utils::serial& ar)
|
|
|
|
|
requires IdmSavable<T>
|
2022-07-04 15:02:17 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
for (const auto& p : vec_data)
|
2022-07-04 15:02:17 +02:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
if (!p)
|
|
|
|
|
continue;
|
2024-12-22 19:59:48 +01:00
|
|
|
|
|
|
|
|
auto& key = vec_keys[&p - vec_data.data()];
|
2022-07-04 15:02:17 +02:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
const u128 type_init_pos = u128{key.type()} << 64 | std::bit_cast<u64>(T::savestate_init_pos);
|
2022-07-04 15:02:17 +02:00
|
|
|
const typeinfo* info = nullptr;
|
|
|
|
|
|
|
|
|
|
// Search load functions for the one of this type (see make_typeinfo() for explenation about key composition reasoning)
|
|
|
|
|
for (const auto& typeinfo : get_typeinfo_map())
|
|
|
|
|
{
|
|
|
|
|
if (!(typeinfo.first ^ type_init_pos))
|
|
|
|
|
{
|
|
|
|
|
ensure(!std::exchange(info, std::addressof(typeinfo.second)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save each object with needed information
|
2024-12-22 19:59:48 +01:00
|
|
|
if (info && info->savable(p.observe()))
|
2022-07-04 15:02:17 +02:00
|
|
|
{
|
2023-12-25 13:35:09 +01:00
|
|
|
// Create a tag for each object
|
|
|
|
|
serial_breathe_and_tag(ar, g_fxo->get_name<id_map<T>>(), false);
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
ar(key.value(), key.type());
|
|
|
|
|
info->save(ar, p.observe());
|
2022-07-04 15:02:17 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-25 13:35:09 +01:00
|
|
|
// End sequence with tag bit set
|
|
|
|
|
serial_breathe_and_tag(ar, g_fxo->get_name<id_map<T>>(), true);
|
2022-07-04 15:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
id_map& operator=(thread_state state) noexcept
|
|
|
|
|
requires(std::is_assignable_v<T&, thread_state>)
|
2021-06-05 21:15:15 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
if (highest_index)
|
2023-12-28 18:37:24 +01:00
|
|
|
{
|
2021-06-05 21:15:15 +02:00
|
|
|
reader_lock lock(g_mutex);
|
|
|
|
|
|
|
|
|
|
// Save all entries
|
2024-12-28 12:31:17 +01:00
|
|
|
for (u32 i = 0; i < highest_index; i++)
|
2024-12-22 19:59:48 +01:00
|
|
|
{
|
|
|
|
|
private_copy[i] = vec_data[i].load();
|
|
|
|
|
}
|
2021-06-05 21:15:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Signal or join threads
|
2024-12-22 19:59:48 +01:00
|
|
|
for (const auto& ptr : private_copy)
|
2021-06-05 21:15:15 +02:00
|
|
|
{
|
|
|
|
|
if (ptr)
|
|
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
*ptr = state;
|
2021-06-05 21:15:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
2021-03-30 18:37:51 +02:00
|
|
|
};
|
2025-04-05 21:50:45 +02:00
|
|
|
} // namespace id_manager
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
|
|
|
// Object manager for emulated process. Multiple objects of specified arbitrary type are given unique IDs.
|
|
|
|
|
class idm
|
|
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
template <typename T>
|
|
|
|
|
static constexpr u32 get_index(u32 id)
|
|
|
|
|
{
|
2019-07-27 12:59:17 +02:00
|
|
|
using traits = id_manager::id_traits<T>;
|
|
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
return id_manager::get_index(id, traits::base, traits::step, traits::count, traits::invl_range);
|
2017-01-29 17:50:18 +01:00
|
|
|
}
|
|
|
|
|
|
2016-05-13 16:01:48 +02:00
|
|
|
// Helper
|
2017-01-29 17:50:18 +01:00
|
|
|
template <typename F>
|
2016-05-13 16:01:48 +02:00
|
|
|
struct function_traits;
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
template <typename F, typename R, typename A1, typename A2>
|
|
|
|
|
struct function_traits<R (F::*)(A1, A2&) const>
|
2016-05-13 16:01:48 +02:00
|
|
|
{
|
2017-01-25 01:45:36 +01:00
|
|
|
using object_type = A2;
|
|
|
|
|
using result_type = R;
|
|
|
|
|
};
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
template <typename F, typename R, typename A1, typename A2>
|
|
|
|
|
struct function_traits<R (F::*)(A1, A2&)>
|
2017-01-25 01:45:36 +01:00
|
|
|
{
|
|
|
|
|
using object_type = A2;
|
|
|
|
|
using result_type = R;
|
|
|
|
|
};
|
|
|
|
|
|
2017-02-02 18:32:49 +01:00
|
|
|
// Helper type: pointer + return value propagated
|
2017-01-29 17:50:18 +01:00
|
|
|
template <typename T, typename RT>
|
2024-12-22 19:59:48 +01:00
|
|
|
struct return_pair;
|
|
|
|
|
|
|
|
|
|
template <typename T, typename RT>
|
|
|
|
|
struct return_pair<stx::shared_ptr<T>, RT>
|
2016-05-13 16:01:48 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
stx::shared_ptr<T> ptr;
|
2017-02-02 18:32:49 +01:00
|
|
|
RT ret;
|
2017-01-25 01:45:36 +01:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
explicit operator bool() const noexcept
|
2016-05-13 16:01:48 +02:00
|
|
|
{
|
2017-01-25 01:45:36 +01:00
|
|
|
return ptr.operator bool();
|
2016-05-13 16:01:48 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
T& operator*() const noexcept
|
2020-03-03 21:39:40 +01:00
|
|
|
{
|
|
|
|
|
return *ptr;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
T* operator->() const noexcept
|
2016-05-13 16:01:48 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
return ptr.operator->();
|
2016-05-13 16:01:48 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2017-02-02 18:32:49 +01:00
|
|
|
// Unsafe specialization (not refcounted)
|
|
|
|
|
template <typename T, typename RT>
|
|
|
|
|
struct return_pair<T*, RT>
|
2017-01-25 01:45:36 +01:00
|
|
|
{
|
2017-02-02 18:32:49 +01:00
|
|
|
T* ptr;
|
|
|
|
|
RT ret;
|
2017-01-25 01:45:36 +01:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
explicit operator bool() const noexcept
|
2017-01-25 01:45:36 +01:00
|
|
|
{
|
2017-02-02 18:32:49 +01:00
|
|
|
return ptr != nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
T& operator*() const noexcept
|
2020-03-03 21:39:40 +01:00
|
|
|
{
|
|
|
|
|
return *ptr;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
T* operator->() const noexcept
|
2017-02-02 18:32:49 +01:00
|
|
|
{
|
|
|
|
|
return ptr;
|
2017-01-25 01:45:36 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
// Get type ID that is meant to be unique within the same container
|
|
|
|
|
template <typename T>
|
|
|
|
|
static consteval u32 get_type()
|
|
|
|
|
{
|
|
|
|
|
return id_manager::typeinfo::get_type<T>();
|
|
|
|
|
}
|
2021-03-30 18:37:51 +02:00
|
|
|
|
2017-01-25 01:45:36 +01:00
|
|
|
// Prepare new ID (returns nullptr if out of resources)
|
2024-12-28 12:31:17 +01:00
|
|
|
static id_manager::id_key* allocate_id(std::span<id_manager::id_key> keys, u32& highest_index, u32 type_id, u32 dst_id, u32 base, u32 step, u32 count, bool uses_lowest_id, std::pair<u32, u32> invl_range);
|
2017-01-29 17:50:18 +01:00
|
|
|
|
2022-08-03 10:20:38 +02:00
|
|
|
// Get object by internal index if exists (additionally check type if types are not equal)
|
2017-01-29 17:50:18 +01:00
|
|
|
template <typename T, typename Type>
|
2024-12-22 19:59:48 +01:00
|
|
|
static std::pair<atomic_ptr<T>*, id_manager::id_key*> find_index(u32 index, u32 id)
|
2017-01-29 17:50:18 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
static_assert(IdmTypesCompatible<T, Type>, "Invalid ID type combination");
|
2017-01-29 17:50:18 +01:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
auto& map = g_fxo->get<id_manager::id_map<T>>();
|
2017-01-29 17:50:18 +01:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
if (index >= map.highest_index)
|
2017-01-29 17:50:18 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
return {};
|
2017-01-29 17:50:18 +01:00
|
|
|
}
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
auto& data = map.vec_data[index];
|
|
|
|
|
auto& key = map.vec_keys[index];
|
2017-01-31 13:57:32 +01:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
if (data)
|
2017-01-29 17:50:18 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
if (std::is_same_v<T, Type> || key.type() == get_type<Type>())
|
2017-01-29 17:50:18 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
if (!id_manager::id_traits<Type>::invl_range.second || key.value() == id)
|
2019-11-28 11:17:16 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
return {&data, &key};
|
2019-11-28 11:17:16 +01:00
|
|
|
}
|
2017-01-29 17:50:18 +01:00
|
|
|
}
|
|
|
|
|
}
|
2017-01-25 18:50:30 +01:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
return {};
|
2017-01-29 17:50:18 +01:00
|
|
|
}
|
2015-08-04 12:46:05 +02:00
|
|
|
|
2022-08-03 10:20:38 +02:00
|
|
|
// Find ID
|
|
|
|
|
template <typename T, typename Type>
|
2024-12-22 19:59:48 +01:00
|
|
|
static std::pair<atomic_ptr<T>*, id_manager::id_key*> find_id(u32 id)
|
2022-08-03 10:20:38 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
static_assert(IdmTypesCompatible<T, Type>, "Invalid ID type combination");
|
2022-08-03 10:20:38 +02:00
|
|
|
|
|
|
|
|
const u32 index = get_index<Type>(id);
|
|
|
|
|
|
|
|
|
|
return find_index<T, Type>(index, id);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
// Allocate new ID (or use fixed ID) and assign the object from the provider()
|
2017-01-29 17:50:18 +01:00
|
|
|
template <typename T, typename Type, typename F>
|
2024-12-22 19:59:48 +01:00
|
|
|
static stx::shared_ptr<Type> create_id(F&& provider, u32 id = id_manager::id_traits<Type>::invalid)
|
2016-04-14 00:59:00 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
static_assert(IdmTypesCompatible<T, Type>, "Invalid ID type combination");
|
2017-01-25 18:50:30 +01:00
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
// ID traits
|
|
|
|
|
using traits = id_manager::id_traits<Type>;
|
2016-04-14 00:59:00 +02:00
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
// Ensure make_typeinfo() is used for this type
|
2022-09-13 15:08:55 +02:00
|
|
|
[[maybe_unused]] auto& td = stx::typedata<id_manager::typeinfo, Type>();
|
2022-07-04 15:02:17 +02:00
|
|
|
|
2017-01-25 18:50:30 +01:00
|
|
|
// Allocate new id
|
2018-09-03 21:28:33 +02:00
|
|
|
std::lock_guard lock(id_manager::g_mutex);
|
2017-01-29 17:50:18 +01:00
|
|
|
|
2021-03-30 18:37:51 +02:00
|
|
|
auto& map = g_fxo->get<id_manager::id_map<T>>();
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
if (auto* key_ptr = allocate_id({map.vec_keys.data(), map.vec_keys.size()}, map.highest_index, get_type<Type>(), id, traits::base, traits::step, traits::count, traits::uses_lowest_id, traits::invl_range))
|
2016-04-14 00:59:00 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
auto& place = map.vec_data[key_ptr - map.vec_keys.data()];
|
2017-01-31 13:57:32 +01:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
// Get object, store it
|
|
|
|
|
if (auto object = provider())
|
2017-01-31 13:57:32 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
place = object;
|
|
|
|
|
return object;
|
|
|
|
|
}
|
2024-12-23 02:06:49 +01:00
|
|
|
|
|
|
|
|
*key_ptr = {};
|
2015-08-04 12:46:05 +02:00
|
|
|
}
|
2015-07-01 00:25:52 +02:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
return {};
|
2015-07-01 00:25:52 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
public:
|
2020-05-07 16:15:06 +02:00
|
|
|
// Remove all objects of a type
|
|
|
|
|
template <typename T>
|
|
|
|
|
static inline void clear()
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard lock(id_manager::g_mutex);
|
2024-12-22 19:59:48 +01:00
|
|
|
|
|
|
|
|
for (auto& ptr : g_fxo->get<id_manager::id_map<T>>().vec_data)
|
|
|
|
|
{
|
|
|
|
|
ptr.reset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (auto& key : g_fxo->get<id_manager::id_map<T>>().vec_keys)
|
|
|
|
|
{
|
|
|
|
|
key.clear();
|
|
|
|
|
}
|
2020-05-07 16:15:06 +02:00
|
|
|
}
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
// Get last ID (updated in create_id/allocate_id)
|
2017-01-25 18:50:30 +01:00
|
|
|
static inline u32 last_id()
|
|
|
|
|
{
|
2022-07-04 15:02:17 +02:00
|
|
|
return id_manager::g_id;
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
// Add a new ID of specified type with specified constructor arguments (returns object or null_ptr)
|
2025-04-05 21:50:45 +02:00
|
|
|
template <typename T, typename Make = T, typename... Args>
|
|
|
|
|
requires(std::is_constructible_v<Make, Args && ...>)
|
2024-12-22 19:59:48 +01:00
|
|
|
static inline stx::shared_ptr<Make> make_ptr(Args&&... args)
|
2015-03-12 20:02:02 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
if (auto pair = create_id<T, Make>([&]
|
|
|
|
|
{
|
|
|
|
|
return stx::make_shared<Make>(std::forward<Args>(args)...);
|
|
|
|
|
}))
|
2015-08-04 12:46:05 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
return pair;
|
2015-08-04 12:46:05 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
return null_ptr;
|
2015-08-04 12:46:05 +02:00
|
|
|
}
|
|
|
|
|
|
2015-11-26 09:06:29 +01:00
|
|
|
// Add a new ID of specified type with specified constructor arguments (returns id)
|
2025-04-05 21:50:45 +02:00
|
|
|
template <typename T, typename Make = T, typename... Args>
|
|
|
|
|
requires(std::is_constructible_v<Make, Args && ...>)
|
2021-06-16 17:14:49 +02:00
|
|
|
static inline u32 make(Args&&... args)
|
2015-08-07 23:28:09 +02:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
if (create_id<T, Make>([&]
|
|
|
|
|
{
|
|
|
|
|
return stx::make_shared<Make>(std::forward<Args>(args)...);
|
|
|
|
|
}))
|
2015-08-07 23:28:09 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
return last_id();
|
2015-08-07 23:28:09 +02:00
|
|
|
}
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
return id_manager::id_traits<Make>::invalid;
|
2015-08-07 23:28:09 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
// Add a new ID for an object returned by provider()
|
2024-12-22 19:59:48 +01:00
|
|
|
template <typename T, typename Made = T, typename F>
|
|
|
|
|
requires IdmTypesCompatible<T, Made> && std::is_convertible_v<std::invoke_result_t<F&&>, stx::shared_ptr<Made>>
|
2022-07-04 15:02:17 +02:00
|
|
|
static inline u32 import(F&& provider, u32 id = id_manager::id_traits<Made>::invalid)
|
2016-04-14 00:59:00 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
if (create_id<T, Made>(std::forward<F>(provider), id))
|
2016-04-14 00:59:00 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
return last_id();
|
2016-04-14 00:59:00 +02:00
|
|
|
}
|
|
|
|
|
|
2017-01-31 13:57:32 +01:00
|
|
|
return id_manager::id_traits<Made>::invalid;
|
2016-04-14 00:59:00 +02:00
|
|
|
}
|
2015-11-26 09:06:29 +01:00
|
|
|
|
2021-06-16 17:14:49 +02:00
|
|
|
// Add a new ID for an existing object provided (returns new id)
|
|
|
|
|
template <typename T, typename Made = T>
|
2024-12-22 19:59:48 +01:00
|
|
|
requires IdmTypesCompatible<T, Made>
|
|
|
|
|
static inline u32 import_existing(stx::shared_ptr<Made> ptr, u32 id = id_manager::id_traits<Made>::invalid)
|
2017-02-02 18:32:49 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
return import <T, Made>([&]() -> stx::shared_ptr<Made>
|
|
|
|
|
{
|
|
|
|
|
return std::move(ptr);
|
|
|
|
|
},
|
|
|
|
|
id);
|
2017-02-02 18:32:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check the ID without locking (can be called from other method)
|
|
|
|
|
template <typename T, typename Get = T>
|
2024-12-22 19:59:48 +01:00
|
|
|
requires IdmTypesCompatible<T, Get>
|
2017-02-02 18:32:49 +01:00
|
|
|
static inline Get* check_unlocked(u32 id)
|
|
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
if (const auto found = find_id<T, Get>(id); found.first)
|
2017-02-02 18:32:49 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
return static_cast<Get*>(found.first->observe());
|
2017-02-02 18:32:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-25 01:45:36 +01:00
|
|
|
// Check the ID, access object under shared lock
|
2018-09-05 14:10:37 +02:00
|
|
|
template <typename T, typename Get = T, typename F, typename FRT = std::invoke_result_t<F, Get&>>
|
2024-12-22 19:59:48 +01:00
|
|
|
requires IdmTypesCompatible<T, Get>
|
2022-08-03 10:20:38 +02:00
|
|
|
static inline std::conditional_t<std::is_void_v<FRT>, Get*, return_pair<Get*, FRT>> check(u32 id, F&& func)
|
2017-01-25 01:45:36 +01:00
|
|
|
{
|
2022-08-03 10:20:38 +02:00
|
|
|
const u32 index = get_index<Get>(id);
|
|
|
|
|
|
|
|
|
|
if (index >= id_manager::id_traits<Get>::count)
|
|
|
|
|
{
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-25 18:50:30 +01:00
|
|
|
reader_lock lock(id_manager::g_mutex);
|
2017-01-25 01:45:36 +01:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
if (const auto found = find_index<T, Get>(index, id); found.first)
|
2017-01-25 01:45:36 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
const auto ptr = static_cast<Get*>(found.first->observe());
|
2022-08-03 10:20:38 +02:00
|
|
|
|
2018-09-05 14:10:37 +02:00
|
|
|
if constexpr (!std::is_void_v<FRT>)
|
|
|
|
|
{
|
|
|
|
|
return return_pair<Get*, FRT>{ptr, func(*ptr)};
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
func(*ptr);
|
|
|
|
|
return ptr;
|
|
|
|
|
}
|
2017-01-25 01:45:36 +01:00
|
|
|
}
|
2018-08-23 23:31:27 +02:00
|
|
|
|
2022-08-03 10:20:38 +02:00
|
|
|
return {};
|
2017-02-02 18:32:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the object without locking (can be called from other method)
|
|
|
|
|
template <typename T, typename Get = T>
|
2024-12-22 19:59:48 +01:00
|
|
|
requires IdmTypesCompatible<T, Get>
|
|
|
|
|
static inline stx::shared_ptr<Get> get_unlocked(u32 id)
|
2017-02-02 18:32:49 +01:00
|
|
|
{
|
2017-01-29 17:50:18 +01:00
|
|
|
const auto found = find_id<T, Get>(id);
|
2017-01-25 01:45:36 +01:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
if (!found.first) [[unlikely]]
|
2017-01-25 01:45:36 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
return null_ptr;
|
2017-01-25 01:45:36 +01:00
|
|
|
}
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
return static_cast<stx::shared_ptr<Get>>(found.first->load());
|
2016-04-14 00:59:00 +02:00
|
|
|
}
|
|
|
|
|
|
2017-01-25 01:45:36 +01:00
|
|
|
// Get the object, access object under reader lock
|
2018-09-05 14:10:37 +02:00
|
|
|
template <typename T, typename Get = T, typename F, typename FRT = std::invoke_result_t<F, Get&>>
|
2024-12-22 19:59:48 +01:00
|
|
|
requires IdmTypesCompatible<T, Get>
|
|
|
|
|
static inline std::conditional_t<std::is_void_v<FRT>, stx::shared_ptr<Get>, return_pair<stx::shared_ptr<Get>, FRT>> get(u32 id, F&& func)
|
2015-11-26 09:06:29 +01:00
|
|
|
{
|
2022-08-03 10:20:38 +02:00
|
|
|
const u32 index = get_index<Get>(id);
|
|
|
|
|
|
|
|
|
|
if (index >= id_manager::id_traits<Get>::count)
|
|
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
return {};
|
2022-08-03 10:20:38 +02:00
|
|
|
}
|
|
|
|
|
|
2017-01-25 18:50:30 +01:00
|
|
|
reader_lock lock(id_manager::g_mutex);
|
2016-04-14 00:59:00 +02:00
|
|
|
|
2022-08-03 10:20:38 +02:00
|
|
|
const auto found = find_index<T, Get>(index, id);
|
2016-05-13 16:01:48 +02:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
if (!found.first) [[unlikely]]
|
2016-05-13 16:01:48 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
return {};
|
2016-05-13 16:01:48 +02:00
|
|
|
}
|
2015-07-08 17:01:59 +02:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
auto ptr = static_cast<stx::shared_ptr<Get>>(found.first->load());
|
|
|
|
|
Get* obj_ptr = ptr.get();
|
2017-01-25 01:45:36 +01:00
|
|
|
|
2018-09-05 14:10:37 +02:00
|
|
|
if constexpr (std::is_void_v<FRT>)
|
2017-01-25 01:45:36 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
func(*obj_ptr);
|
|
|
|
|
return ptr;
|
2018-09-05 14:10:37 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
return {std::move(ptr), func(*obj_ptr)};
|
2017-01-25 01:45:36 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-16 17:14:49 +02:00
|
|
|
static constexpr std::false_type unlocked{};
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
// Access all objects of specified type. Returns the number of objects processed.
|
2021-06-16 17:14:49 +02:00
|
|
|
// If function result evaluates to true, stop and return the object and the value.
|
|
|
|
|
template <typename T, typename... Get, typename F, typename Lock = std::true_type>
|
2024-12-22 19:59:48 +01:00
|
|
|
requires IdmBaseCompatible<T> && (IdmCompatible<Get> && ...) && (std::is_invocable_v<F, u32, Get&> && ...)
|
|
|
|
|
static inline auto select(F&& func, Lock = std::true_type{})
|
2017-01-25 01:45:36 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
static_assert((IdmTypesCompatible<T, Get> && ...), "Invalid ID type combination");
|
2017-01-29 17:50:18 +01:00
|
|
|
|
2022-09-13 15:08:55 +02:00
|
|
|
[[maybe_unused]] std::conditional_t<!!Lock(), reader_lock, const shared_mutex&> lock(id_manager::g_mutex);
|
2017-01-25 01:45:36 +01:00
|
|
|
|
2021-06-16 17:14:49 +02:00
|
|
|
using func_traits = function_traits<decltype(&decltype(std::function(std::declval<F>()))::operator())>;
|
|
|
|
|
using object_type = typename func_traits::object_type;
|
|
|
|
|
using result_type = typename func_traits::result_type;
|
2017-01-25 01:45:36 +01:00
|
|
|
|
2021-06-16 17:14:49 +02:00
|
|
|
static_assert(PtrSame<object_type, T>, "Invalid function argument type combination");
|
2016-05-13 16:01:48 +02:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
std::conditional_t<std::is_void_v<result_type>, u32, return_pair<stx::shared_ptr<object_type>, result_type>> result{};
|
2016-05-13 16:01:48 +02:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
auto& map = g_fxo->get<id_manager::id_map<T>>();
|
|
|
|
|
|
|
|
|
|
for (auto& id : map.vec_data)
|
2016-05-13 16:01:48 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
if (auto ptr = static_cast<object_type*>(id.observe()))
|
2016-05-13 16:01:48 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
auto& key = map.vec_keys[&id - map.vec_data.data()];
|
|
|
|
|
|
|
|
|
|
if (sizeof...(Get) == 0 || ((key.type() == get_type<Get>()) || ...))
|
2016-05-13 16:01:48 +02:00
|
|
|
{
|
2021-06-16 17:14:49 +02:00
|
|
|
if constexpr (std::is_void_v<result_type>)
|
|
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
func(key, *ptr);
|
2021-06-16 17:14:49 +02:00
|
|
|
result++;
|
|
|
|
|
}
|
2024-12-22 19:59:48 +01:00
|
|
|
else
|
2017-01-29 17:50:18 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
if ((result.ret = func(key, *ptr)))
|
|
|
|
|
{
|
|
|
|
|
result.ptr = static_cast<stx::shared_ptr<object_type>>(id.load());
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-01-29 17:50:18 +01:00
|
|
|
}
|
2016-05-13 16:01:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
2015-07-08 17:01:59 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-16 17:14:49 +02:00
|
|
|
return result;
|
2016-05-13 16:01:48 +02:00
|
|
|
}
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
// Remove the ID
|
|
|
|
|
template <typename T, typename Get = T>
|
2024-12-22 19:59:48 +01:00
|
|
|
requires IdmTypesCompatible<T, Get>
|
2018-09-05 15:24:11 +02:00
|
|
|
static inline bool remove(u32 id)
|
2016-05-13 16:01:48 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
stx::shared_ptr<T> ptr;
|
2016-08-01 01:26:55 +02:00
|
|
|
{
|
2018-09-03 21:28:33 +02:00
|
|
|
std::lock_guard lock(id_manager::g_mutex);
|
2016-08-01 01:26:55 +02:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
if (const auto found = find_id<T, Get>(id); found.first)
|
2016-08-01 01:26:55 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
ptr = found.first->exchange(null_ptr);
|
|
|
|
|
found.second->clear();
|
2017-01-29 17:50:18 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
2016-08-01 01:26:55 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-23 14:13:14 +01:00
|
|
|
if constexpr (std::is_assignable_v<Get&, thread_state>)
|
|
|
|
|
{
|
|
|
|
|
if (ptr)
|
|
|
|
|
{
|
2025-01-05 06:44:56 +01:00
|
|
|
constexpr thread_state destroying_context{7};
|
|
|
|
|
*static_cast<Get*>(ptr.get()) = destroying_context;
|
2024-12-23 14:13:14 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
return true;
|
2015-08-04 12:46:05 +02:00
|
|
|
}
|
|
|
|
|
|
2020-03-03 21:39:40 +01:00
|
|
|
// Remove the ID if matches the weak/shared ptr
|
2024-12-22 19:59:48 +01:00
|
|
|
template <typename T, typename Get = T, typename Ptr, typename Lock = std::true_type>
|
|
|
|
|
requires IdmTypesCompatible<T, Get> && std::is_convertible_v<Lock, bool>
|
|
|
|
|
static inline bool remove_verify(u32 id, Ptr&& sptr, Lock = std::true_type{})
|
2020-03-03 21:39:40 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
stx::shared_ptr<T> ptr;
|
2020-03-03 21:39:40 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
[[maybe_unused]] std::conditional_t<!!Lock(), std::lock_guard<shared_mutex>, const shared_mutex&> lock(id_manager::g_mutex);
|
2020-03-03 21:39:40 +01:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
if (const auto found = find_id<T, Get>(id); found.first && found.first->is_equal(sptr))
|
2020-03-03 21:39:40 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
ptr = found.first->exchange(null_ptr);
|
|
|
|
|
found.second->clear();
|
2020-03-03 21:39:40 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-23 14:13:14 +01:00
|
|
|
if constexpr (std::is_assignable_v<Get&, thread_state>)
|
|
|
|
|
{
|
|
|
|
|
if (ptr)
|
|
|
|
|
{
|
2025-01-05 06:44:56 +01:00
|
|
|
constexpr thread_state destroying_context{7};
|
|
|
|
|
*static_cast<Get*>(ptr.get()) = destroying_context;
|
2024-12-23 14:13:14 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-03 21:39:40 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-25 01:45:36 +01:00
|
|
|
// Remove the ID and return the object
|
2024-12-22 19:59:48 +01:00
|
|
|
template <typename T, typename Get = T, typename Lock = std::true_type>
|
|
|
|
|
requires IdmTypesCompatible<T, Get>
|
|
|
|
|
static inline stx::shared_ptr<Get> withdraw(u32 id, int = 0, Lock = std::true_type{})
|
2015-08-07 23:28:09 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
stx::shared_ptr<Get> ptr;
|
2016-04-14 00:59:00 +02:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
[[maybe_unused]] std::conditional_t<!!Lock(), std::lock_guard<shared_mutex>, const shared_mutex&> lock(id_manager::g_mutex);
|
2017-01-29 17:50:18 +01:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
if (const auto found = find_id<T, Get>(id); found.first)
|
2017-01-29 17:50:18 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
ptr = static_cast<stx::shared_ptr<Get>>(found.first->exchange(null_ptr));
|
|
|
|
|
found.second->clear();
|
2017-01-29 17:50:18 +01:00
|
|
|
}
|
2015-11-26 09:06:29 +01:00
|
|
|
}
|
2015-08-07 23:28:09 +02:00
|
|
|
|
2020-04-09 18:05:36 +02:00
|
|
|
return ptr;
|
2017-01-25 01:45:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove the ID after accessing the object under writer lock, return the object and propagate return value
|
2018-09-05 14:10:37 +02:00
|
|
|
template <typename T, typename Get = T, typename F, typename FRT = std::invoke_result_t<F, Get&>>
|
2024-12-22 19:59:48 +01:00
|
|
|
requires IdmTypesCompatible<T, Get> && std::is_invocable_v<F, Get&>
|
|
|
|
|
static inline std::conditional_t<std::is_void_v<FRT>, stx::shared_ptr<Get>, return_pair<stx::shared_ptr<Get>, FRT>> withdraw(u32 id, F&& func)
|
2017-01-25 01:45:36 +01:00
|
|
|
{
|
2022-08-03 10:20:38 +02:00
|
|
|
const u32 index = get_index<Get>(id);
|
|
|
|
|
|
|
|
|
|
if (index >= id_manager::id_traits<Get>::count)
|
|
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
return {};
|
2022-08-03 10:20:38 +02:00
|
|
|
}
|
|
|
|
|
|
2018-09-05 14:10:37 +02:00
|
|
|
std::unique_lock lock(id_manager::g_mutex);
|
2017-01-25 01:45:36 +01:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
if (const auto found = find_index<T, Get>(index, id); found.first)
|
2017-01-25 01:45:36 +01:00
|
|
|
{
|
2024-12-22 19:59:48 +01:00
|
|
|
const auto _ptr = static_cast<Get*>(found.first->observe());
|
2017-01-25 01:45:36 +01:00
|
|
|
|
2018-09-05 14:10:37 +02:00
|
|
|
if constexpr (std::is_void_v<FRT>)
|
2017-01-29 17:50:18 +01:00
|
|
|
{
|
2018-09-05 14:10:37 +02:00
|
|
|
func(*_ptr);
|
2024-12-22 19:59:48 +01:00
|
|
|
found.second->clear();
|
|
|
|
|
return static_cast<stx::shared_ptr<Get>>(found.first->exchange(null_ptr));
|
2017-01-29 17:50:18 +01:00
|
|
|
}
|
|
|
|
|
else
|
2017-01-25 01:45:36 +01:00
|
|
|
{
|
2018-09-05 14:10:37 +02:00
|
|
|
FRT ret = func(*_ptr);
|
2017-01-25 01:45:36 +01:00
|
|
|
|
2017-01-29 17:50:18 +01:00
|
|
|
if (ret)
|
|
|
|
|
{
|
2018-09-05 14:10:37 +02:00
|
|
|
// If return value evaluates to true, don't delete the object (error code)
|
2024-12-22 19:59:48 +01:00
|
|
|
return {static_cast<stx::shared_ptr<Get>>(found.first->load()), std::move(ret)};
|
2017-01-29 17:50:18 +01:00
|
|
|
}
|
2017-01-25 01:45:36 +01:00
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
found.second->clear();
|
|
|
|
|
return {static_cast<stx::shared_ptr<Get>>(found.first->exchange(null_ptr)), std::move(ret)};
|
2016-05-13 16:01:48 +02:00
|
|
|
}
|
2015-07-01 00:25:52 +02:00
|
|
|
}
|
|
|
|
|
|
2024-12-22 19:59:48 +01:00
|
|
|
return {};
|
2015-07-01 00:25:52 +02:00
|
|
|
}
|
2016-04-14 00:59:00 +02:00
|
|
|
};
|