api更新

This commit is contained in:
2026-08-07 20:20:46 +08:00
parent 3205dd84e8
commit caec91ae3f
13 changed files with 653 additions and 201 deletions
@@ -79,6 +79,7 @@ public:
}
};
}
/// Result of type-erased runtime property access. Runtime lookup never performs implicit type conversion.
enum class Runtime_Access_Result {
ok,
unknown_property,
@@ -86,7 +87,11 @@ enum class Runtime_Access_Result {
not_writable,
type_mismatch
};
/// Callback used by `runtime_read`.
/// The value pointer is valid only for the duration of the callback and must be consumed or copied synchronously. For synchronized writable state, the corresponding managed read lock remains held while the callback executes, so the callback must not re-enter a conflicting write on the same lock domain.
using Runtime_Read_Callback = void (*)(void*, std::size_t, std::string_view, const std::type_info&, const void*);
/// Type-erased boundary intended for adapters that discover a property key only at runtime.
/// Normal C++ business code should prefer `Property_Object::read/write`, which preserve compile-time type and capability checking.
class Property_Object_Base {
struct Runtime_Interface {
const std::type_info& (*object_type)() noexcept;
@@ -105,19 +110,26 @@ protected:
template <class Object, Synchronization_Policy Policy>
friend class Property_Object;
public:
/// Returns the concrete managed object type represented by this erased base.
const std::type_info& runtime_object_type() const noexcept {
return runtime_interface_->object_type();
}
/// Returns the number of properties in the concrete object's schema.
std::size_t runtime_property_count() const noexcept {
return runtime_interface_->property_count();
}
/// Looks up `key` at runtime and invokes `callback` exactly once on success.
/// The operation follows the same intrinsic readable capability and synchronization rules as typed `read`; stored read-only properties therefore keep their zero-lock fast path. `callback` is a required non-null function pointer.
Runtime_Access_Result runtime_read(std::string_view key, void* context, Runtime_Read_Callback callback) const {
return runtime_interface_->read(*this, key, context, callback);
}
/// Looks up `key` at runtime and performs the same managed write used by typed `write`.
/// `value_type` must exactly match the property's declared value type and `value` must point to a live object of that exact type for the duration of the call. No numeric, string or user-defined conversion is attempted.
Runtime_Access_Result runtime_write(std::string_view key, const std::type_info& value_type, const void* value) {
return runtime_interface_->write(*this, key, value_type, value);
}
};
/// Explicit per-instance synchronization override. The contained plan changes only lock topology; it does not change property capability or validation.
struct Property_Synchronization {
Synchronization_Plan plan;
};
@@ -129,6 +141,8 @@ Property_Synchronization property_synchronization(Source&& source) requires Prop
using Schema = type_descriptor_schema_t<Object>;
return {materialize_synchronization_plan<Schema>(std::forward<Source>(source))};
}
/// Non-owning inspection view of the effective synchronization topology for one object instance.
/// `unsynchronized_slot` means that managed access for the property owns no mutex domain. For stored read-only properties this is automatic.
struct Resolved_Synchronization_View {
static constexpr std::size_t unsynchronized_slot = std::numeric_limits<std::size_t>::max();
std::span<const std::size_t> lock_slots;
@@ -323,12 +337,10 @@ private:
public:
Single_Read_View(const Property_Object& owner, std::size_t property_index, std::size_t lock_slot) : owner_(&owner), property_index_(property_index), lock_slot_(lock_slot) {}
template <auto Member>
decltype(auto) get() const {
decltype(auto) get() const requires Schema_Readable_Property_Member<type_descriptor_schema_t<Derived>, Member> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_member_property_index_v<Schema, Member>;
static_assert(index < Schema::property_count);
using Property = typename Schema::template property_type<index>;
static_assert(Property::readable);
if constexpr (!Property::writable && !Property::accessor_type::synchronized_view_read) {
return owner_->template read_unlocked<index>(*this);
}
@@ -338,12 +350,10 @@ private:
return owner_->template read_unlocked<index>(*this);
}
template <Fixed_String Key>
decltype(auto) get_key() const {
decltype(auto) get() const requires Schema_Readable_Property_Key<type_descriptor_schema_t<Derived>, Key> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_property_index_v<Schema, Key>;
static_assert(index < Schema::property_count);
using Property = typename Schema::template property_type<index>;
static_assert(Property::readable);
if constexpr (!Property::writable && !Property::accessor_type::synchronized_view_read) {
return owner_->template read_unlocked<index>(*this);
}
@@ -413,27 +423,22 @@ private:
}
public:
template <std::size_t Index>
decltype(auto) get_index() const {
using Schema = type_descriptor_schema_t<Derived>;
static_assert(Index < Schema::property_count);
static_assert(Schema::template property_type<Index>::readable);
decltype(auto) get_index() const requires Schema_Readable_Property_Index<type_descriptor_schema_t<Derived>, Index> {
if (!holds(Index)) {
throw std::logic_error("Property is outside the held synchronization set");
}
return owner_->template read_unlocked<Index>(*this);
}
template <auto Member>
decltype(auto) get() const {
decltype(auto) get() const requires Schema_Readable_Property_Member<type_descriptor_schema_t<Derived>, Member> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_member_property_index_v<Schema, Member>;
static_assert(index < Schema::property_count);
return get_index<index>();
}
template <Fixed_String Key>
decltype(auto) get_key() const {
decltype(auto) get() const requires Schema_Readable_Property_Key<type_descriptor_schema_t<Derived>, Key> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_property_index_v<Schema, Key>;
static_assert(index < Schema::property_count);
return get_index<index>();
}
};
@@ -460,51 +465,41 @@ private:
}
public:
template <std::size_t Index>
decltype(auto) get_index() const {
using Schema = type_descriptor_schema_t<Derived>;
static_assert(Index < Schema::property_count);
static_assert(Schema::template property_type<Index>::readable);
decltype(auto) get_index() const requires Schema_Readable_Property_Index<type_descriptor_schema_t<Derived>, Index> {
if (!holds(Index)) {
throw std::logic_error("Property is outside the held synchronization set");
}
return owner_->template read_unlocked<Index>(*this);
}
template <auto Member>
decltype(auto) get() const {
decltype(auto) get() const requires Schema_Readable_Property_Member<type_descriptor_schema_t<Derived>, Member> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_member_property_index_v<Schema, Member>;
static_assert(index < Schema::property_count);
return get_index<index>();
}
template <Fixed_String Key>
decltype(auto) get_key() const {
decltype(auto) get() const requires Schema_Readable_Property_Key<type_descriptor_schema_t<Derived>, Key> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_property_index_v<Schema, Key>;
static_assert(index < Schema::property_count);
return get_index<index>();
}
template <std::size_t Index, class Value>
void set_index(Value&& value) {
using Schema = type_descriptor_schema_t<Derived>;
static_assert(Index < Schema::property_count);
static_assert(Schema::template property_type<Index>::writable);
void set_index(Value&& value) requires Schema_Writable_Property_Index<type_descriptor_schema_t<Derived>, Index> {
if (!holds(Index)) {
throw std::logic_error("Property is outside the held synchronization set");
}
owner_->template write_unlocked<Index>(std::forward<Value>(value));
}
template <auto Member, class Value>
void set(Value&& value) {
void set(Value&& value) requires Schema_Writable_Property_Member<type_descriptor_schema_t<Derived>, Member> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_member_property_index_v<Schema, Member>;
static_assert(index < Schema::property_count);
set_index<index>(std::forward<Value>(value));
}
template <Fixed_String Key, class Value>
void set_key(Value&& value) {
void set(Value&& value) requires Schema_Writable_Property_Key<type_descriptor_schema_t<Derived>, Key> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_property_index_v<Schema, Key>;
static_assert(index < Schema::property_count);
set_index<index>(std::forward<Value>(value));
}
};
@@ -530,27 +525,22 @@ private:
}
public:
template <std::size_t Index>
decltype(auto) get_index() const {
using Schema = type_descriptor_schema_t<Derived>;
static_assert(Index < Schema::property_count);
static_assert(Schema::template property_type<Index>::readable);
decltype(auto) get_index() const requires Schema_Readable_Property_Index<type_descriptor_schema_t<Derived>, Index> {
if (!holds(Index)) {
throw std::logic_error("Property is outside the held synchronization set");
}
return owner_->template read_unlocked<Index>(*this);
}
template <auto Member>
decltype(auto) get() const {
decltype(auto) get() const requires Schema_Readable_Property_Member<type_descriptor_schema_t<Derived>, Member> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_member_property_index_v<Schema, Member>;
static_assert(index < Schema::property_count);
return get_index<index>();
}
template <Fixed_String Key>
decltype(auto) get_key() const {
decltype(auto) get() const requires Schema_Readable_Property_Key<type_descriptor_schema_t<Derived>, Key> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_property_index_v<Schema, Key>;
static_assert(index < Schema::property_count);
return get_index<index>();
}
};
@@ -576,51 +566,41 @@ private:
}
public:
template <std::size_t Index>
decltype(auto) get_index() const {
using Schema = type_descriptor_schema_t<Derived>;
static_assert(Index < Schema::property_count);
static_assert(Schema::template property_type<Index>::readable);
decltype(auto) get_index() const requires Schema_Readable_Property_Index<type_descriptor_schema_t<Derived>, Index> {
if (!holds(Index)) {
throw std::logic_error("Property is outside the held synchronization set");
}
return owner_->template read_unlocked<Index>(*this);
}
template <auto Member>
decltype(auto) get() const {
decltype(auto) get() const requires Schema_Readable_Property_Member<type_descriptor_schema_t<Derived>, Member> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_member_property_index_v<Schema, Member>;
static_assert(index < Schema::property_count);
return get_index<index>();
}
template <Fixed_String Key>
decltype(auto) get_key() const {
decltype(auto) get() const requires Schema_Readable_Property_Key<type_descriptor_schema_t<Derived>, Key> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_property_index_v<Schema, Key>;
static_assert(index < Schema::property_count);
return get_index<index>();
}
template <std::size_t Index, class Value>
void set_index(Value&& value) {
using Schema = type_descriptor_schema_t<Derived>;
static_assert(Index < Schema::property_count);
static_assert(Schema::template property_type<Index>::writable);
void set_index(Value&& value) requires Schema_Writable_Property_Index<type_descriptor_schema_t<Derived>, Index> {
if (!holds(Index)) {
throw std::logic_error("Property is outside the held synchronization set");
}
owner_->template write_unlocked<Index>(std::forward<Value>(value));
}
template <auto Member, class Value>
void set(Value&& value) {
void set(Value&& value) requires Schema_Writable_Property_Member<type_descriptor_schema_t<Derived>, Member> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_member_property_index_v<Schema, Member>;
static_assert(index < Schema::property_count);
set_index<index>(std::forward<Value>(value));
}
template <Fixed_String Key, class Value>
void set_key(Value&& value) {
void set(Value&& value) requires Schema_Writable_Property_Key<type_descriptor_schema_t<Derived>, Key> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_property_index_v<Schema, Key>;
static_assert(index < Schema::property_count);
set_index<index>(std::forward<Value>(value));
}
};
@@ -778,6 +758,7 @@ public:
const auto& schema() const noexcept {
return type_descriptor<Derived>();
}
/// Returns the effective lock topology after intrinsic capability filtering and any per-instance override.
Resolved_Synchronization_View resolved_synchronization() const noexcept {
using Schema = type_descriptor_schema_t<Derived>;
if (custom_lock_layout_) {
@@ -796,30 +777,27 @@ public:
auto read() const requires Schema_Readable_Property_Member<type_descriptor_schema_t<Derived>, Member> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_member_property_index_v<Schema, Member>;
static_assert(index < Schema::property_count);
return read_one<index>();
}
template <Fixed_String Key>
auto read_key() const requires Schema_Readable_Property_Key<type_descriptor_schema_t<Derived>, Key> {
auto read() const requires Schema_Readable_Property_Key<type_descriptor_schema_t<Derived>, Key> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_property_index_v<Schema, Key>;
static_assert(index < Schema::property_count);
return read_one<index>();
}
template <auto Member, class Value>
void write(Value&& value) requires Schema_Writable_Property_Member<type_descriptor_schema_t<Derived>, Member> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_member_property_index_v<Schema, Member>;
static_assert(index < Schema::property_count);
write_one<index>(std::forward<Value>(value));
}
template <Fixed_String Key, class Value>
void write_key(Value&& value) requires Schema_Writable_Property_Key<type_descriptor_schema_t<Derived>, Key> {
void write(Value&& value) requires Schema_Writable_Property_Key<type_descriptor_schema_t<Derived>, Key> {
using Schema = type_descriptor_schema_t<Derived>;
constexpr auto index = schema_property_index_v<Schema, Key>;
static_assert(index < Schema::property_count);
write_one<index>(std::forward<Value>(value));
}
/// Returns the resolved lock slot for a registered member. `unsynchronized_slot` means no mutex is created for that property.
template <auto Member>
std::size_t lock_slot() const noexcept {
using Schema = type_descriptor_schema_t<Derived>;
@@ -855,22 +833,26 @@ private:
return Static_Write_Guard<sizeof...(Members)>{*this, std::move(targets)};
}
public:
/// Runtime-key shared guard. Keys are validated at runtime; unknown or non-readable properties throw `std::invalid_argument`. Lock domains are deduplicated and acquired in stable slot order.
Read_Guard lock_shared(std::span<const std::string_view> keys) const {
return lock_shared_impl(keys);
}
Read_Guard lock_shared(std::initializer_list<std::string_view> keys) const {
return lock_shared_impl(keys);
}
/// Runtime-key unique guard. Keys are validated at runtime; unknown or non-writable properties throw `std::invalid_argument`. Lock domains are deduplicated and acquired in stable slot order.
Write_Guard lock_unique(std::span<const std::string_view> keys) {
return lock_unique_impl(keys);
}
Write_Guard lock_unique(std::initializer_list<std::string_view> keys) {
return lock_unique_impl(keys);
}
/// Compile-time shared guard for registered readable members. Invalid or non-readable selections are removed by constraints before the function can be called.
template <auto... Members>
auto lock_shared() const requires (Schema_Readable_Property_Member<type_descriptor_schema_t<Derived>, Members> && ...) {
return lock_shared_impl<Members...>();
}
/// Compile-time unique guard for registered writable members. The implementation sorts and deduplicates resolved slots so callers may request members in any order without introducing lock-order inversion.
template <auto... Members>
auto lock_unique() requires (Schema_Writable_Property_Member<type_descriptor_schema_t<Derived>, Members> && ...) {
return lock_unique_impl<Members...>();