From 9eff94aa1cca9c174277ace50b2901dcfe435444 Mon Sep 17 00:00:00 2001 From: Krishna Date: Fri, 24 Apr 2026 17:12:23 +0200 Subject: [PATCH 01/10] lola: Change order of args in constructors The new order allows us to set the bindings to nullptrs by default for test only constructors. This will be useful for fields which will require optionally inserting get / set bindings. We change all constructors so that they're all consistent. --- score/mw/com/impl/generic_proxy_event.cpp | 10 +- score/mw/com/impl/generic_proxy_event.h | 4 +- .../mw/com/impl/generic_proxy_event_test.cpp | 10 +- score/mw/com/impl/methods/proxy_method_base.h | 2 +- .../mw/com/impl/methods/proxy_method_test.cpp | 24 ++--- .../impl/methods/proxy_method_with_in_args.h | 10 +- .../proxy_method_with_in_args_and_return.h | 12 +-- .../methods/proxy_method_with_return_type.h | 12 +-- .../proxy_method_without_in_args_or_return.h | 8 +- .../impl/mocking/proxy_event_mock_test.cpp | 4 +- score/mw/com/impl/proxy_base_test.cpp | 32 +++---- score/mw/com/impl/proxy_event.h | 18 ++-- score/mw/com/impl/proxy_event_base.cpp | 4 +- score/mw/com/impl/proxy_event_base.h | 4 +- score/mw/com/impl/proxy_event_base_test.cpp | 26 ++--- score/mw/com/impl/proxy_event_test.cpp | 8 +- score/mw/com/impl/proxy_field.h | 94 +++++++++---------- score/mw/com/impl/proxy_field_base.h | 2 +- 18 files changed, 142 insertions(+), 142 deletions(-) diff --git a/score/mw/com/impl/generic_proxy_event.cpp b/score/mw/com/impl/generic_proxy_event.cpp index da5499356..15e670f66 100644 --- a/score/mw/com/impl/generic_proxy_event.cpp +++ b/score/mw/com/impl/generic_proxy_event.cpp @@ -21,9 +21,9 @@ namespace score::mw::com::impl GenericProxyEvent::GenericProxyEvent(ProxyBase& base, const std::string_view event_name) : ProxyEventBase{base, + event_name, ProxyBaseView{base}.GetBinding(), - GenericProxyEventBindingFactory::Create(base, event_name), - event_name} + GenericProxyEventBindingFactory::Create(base, event_name)} { ProxyBaseView proxy_base_view{base}; if (!binding_base_) @@ -34,9 +34,9 @@ GenericProxyEvent::GenericProxyEvent(ProxyBase& base, const std::string_view eve } GenericProxyEvent::GenericProxyEvent(ProxyBase& base, - std::unique_ptr proxy_binding, - const std::string_view event_name) - : ProxyEventBase{base, ProxyBaseView{base}.GetBinding(), std::move(proxy_binding), event_name} + const std::string_view event_name, + std::unique_ptr proxy_binding) + : ProxyEventBase{base, event_name, ProxyBaseView{base}.GetBinding(), std::move(proxy_binding)} { ProxyBaseView proxy_base_view{base}; if (!binding_base_) diff --git a/score/mw/com/impl/generic_proxy_event.h b/score/mw/com/impl/generic_proxy_event.h index c6e08b186..60e3ea7d3 100644 --- a/score/mw/com/impl/generic_proxy_event.h +++ b/score/mw/com/impl/generic_proxy_event.h @@ -47,8 +47,8 @@ class GenericProxyEvent : public ProxyEventBase /// /// \param proxy_binding The binding that shall be associated with this proxy. explicit GenericProxyEvent(ProxyBase& base, - std::unique_ptr proxy_binding, - const std::string_view event_name); + const std::string_view event_name, + std::unique_ptr proxy_binding); /// \brief Constructs a ProxyEvent by querying the base proxie's ProxyBinding for the respective ProxyEventBinding. /// diff --git a/score/mw/com/impl/generic_proxy_event_test.cpp b/score/mw/com/impl/generic_proxy_event_test.cpp index c9e18dbe2..3e639a1c9 100644 --- a/score/mw/com/impl/generic_proxy_event_test.cpp +++ b/score/mw/com/impl/generic_proxy_event_test.cpp @@ -87,7 +87,7 @@ TEST(GenericProxyEventTest, SamplePtrsToSlotDataAreConst) ProxyBase empty_proxy(std::make_unique(), make_HandleType(make_InstanceIdentifier(kEmptyInstanceDeployment, kEmptyTypeDeployment))); GenericProxyEvent proxy_event{ - empty_proxy, std::unique_ptr{std::move(mock_proxy_event_ptr)}, kEventName}; + empty_proxy, kEventName, std::unique_ptr{std::move(mock_proxy_event_ptr)}}; EXPECT_CALL(mock_proxy_event, Subscribe(max_num_samples)); EXPECT_CALL(mock_proxy_event, GetNewSamples(_, _)); @@ -120,7 +120,7 @@ TEST(GenericProxyEventDeathTest, DieOnProxyDestructionWhileHoldingSamplePtrs) ProxyBase empty_proxy(std::make_unique(), make_HandleType(make_InstanceIdentifier(kEmptyInstanceDeployment, kEmptyTypeDeployment))); auto proxy_event = std::make_unique( - empty_proxy, std::unique_ptr{std::move(mock_proxy_event_ptr)}, kEventName); + empty_proxy, kEventName, std::unique_ptr{std::move(mock_proxy_event_ptr)}); EXPECT_CALL(mock_proxy_event, Subscribe(max_num_samples)); EXPECT_CALL(mock_proxy_event, GetNewSamples(_, _)); @@ -158,7 +158,7 @@ TEST(GenericProxyEventGetSampleSizeTest, GetSampleSizeDispatchesToBinding) ProxyBase empty_proxy(std::make_unique(), make_HandleType(make_InstanceIdentifier(kEmptyInstanceDeployment, kEmptyTypeDeployment))); GenericProxyEvent proxy_event{ - empty_proxy, std::unique_ptr{std::move(mock_proxy_event_ptr)}, kEventName}; + empty_proxy, kEventName, std::unique_ptr{std::move(mock_proxy_event_ptr)}}; // Expect that GetSampleSize is called once on the binding EXPECT_CALL(mock_proxy_event, GetSampleSize()).WillOnce(Return(expected_sample_size)); @@ -186,7 +186,7 @@ TEST(GenericProxyEventHasSerializedFormatTest, HasSerializedFormatDispatchesToBi ProxyBase empty_proxy(std::make_unique(), make_HandleType(make_InstanceIdentifier(kEmptyInstanceDeployment, kEmptyTypeDeployment))); GenericProxyEvent proxy_event{ - empty_proxy, std::unique_ptr{std::move(mock_proxy_event_ptr)}, kEventName}; + empty_proxy, kEventName, std::unique_ptr{std::move(mock_proxy_event_ptr)}}; // Expect that HasSerializedFormat is called once on the binding EXPECT_CALL(mock_proxy_event, HasSerializedFormat()).WillOnce(Return(expected_has_serialized_format)); @@ -217,7 +217,7 @@ TEST(GenericProxyEventGetNewSamplesTest, GetNewSamplesContainsCorrectReceiverSig ProxyBase empty_proxy(std::make_unique(), make_HandleType(make_InstanceIdentifier(kEmptyInstanceDeployment, kEmptyTypeDeployment))); GenericProxyEvent proxy_event{ - empty_proxy, std::unique_ptr{std::move(mock_proxy_event_ptr)}, kEventName}; + empty_proxy, kEventName, std::unique_ptr{std::move(mock_proxy_event_ptr)}}; // Expect that GetNewSamples is called once on the binding EXPECT_CALL(mock_proxy_event, GetNewSamples(_, _)) diff --git a/score/mw/com/impl/methods/proxy_method_base.h b/score/mw/com/impl/methods/proxy_method_base.h index 5e194bf00..4e6b41665 100644 --- a/score/mw/com/impl/methods/proxy_method_base.h +++ b/score/mw/com/impl/methods/proxy_method_base.h @@ -32,8 +32,8 @@ class ProxyMethodBase { public: ProxyMethodBase(ProxyBase& proxy_base, - std::unique_ptr proxy_method_binding, std::string_view method_name, + std::unique_ptr proxy_method_binding, MethodType method_type = MethodType::kMethod) noexcept : proxy_base_{proxy_base}, method_name_{method_name}, diff --git a/score/mw/com/impl/methods/proxy_method_test.cpp b/score/mw/com/impl/methods/proxy_method_test.cpp index 3c017bde2..8e08e0239 100644 --- a/score/mw/com/impl/methods/proxy_method_test.cpp +++ b/score/mw/com/impl/methods/proxy_method_test.cpp @@ -88,7 +88,7 @@ class ProxyMethodTestFixture : public ::testing::Test ProxyMethodTestFixture& GivenAValidProxyMethod() { unit_ = std::make_unique( - proxy_base_, std::make_unique(proxy_method_binding_mock_), kMethodName); + proxy_base_, kMethodName, std::make_unique(proxy_method_binding_mock_)); return *this; } @@ -160,8 +160,8 @@ TYPED_TEST(ProxyMethodAllArgCombinationsTestFixture, Construction) // Then the ProxyMethod can be constructed using ProxyMethodType = ProxyMethod; ProxyMethodType{this->proxy_base_, - std::make_unique(this->proxy_method_binding_mock_), - kMethodName}; + kMethodName, + std::make_unique(this->proxy_method_binding_mock_)}; } TYPED_TEST(ProxyMethodAllArgCombinationsTestFixture, WhenMoveConstructingProxyMethodUpdateMethodIsCalled) @@ -171,8 +171,8 @@ TYPED_TEST(ProxyMethodAllArgCombinationsTestFixture, WhenMoveConstructingProxyMe // Given a proxy method auto proxy_method = ProxyMethodType{this->proxy_base_, - std::make_unique(this->proxy_method_binding_mock_), - kMethodName}; + kMethodName, + std::make_unique(this->proxy_method_binding_mock_)}; // When movie-constructing this method auto moved_method{std::move(proxy_method)}; @@ -190,15 +190,15 @@ TYPED_TEST(ProxyMethodAllArgCombinationsTestFixture, WhenMoveAssigningProxyMetho // Given a proxy method auto proxy_method = ProxyMethodType{this->proxy_base_, - std::make_unique(this->proxy_method_binding_mock_), - kMethodName}; + kMethodName, + std::make_unique(this->proxy_method_binding_mock_)}; ProxyBase other_proxy_base = {std::make_unique(), this->config_store_.GetHandle()}; auto other_proxy_method = ProxyMethodType{other_proxy_base, - std::make_unique(this->proxy_method_binding_mock_), - "this_method_will_be_overwritten_soon"}; + "this_method_will_be_overwritten_soon", + std::make_unique(this->proxy_method_binding_mock_)}; // When move-assigning this method other_proxy_method = std::move(proxy_method); @@ -218,8 +218,8 @@ TYPED_TEST(ProxyMethodAllArgCombinationsTestFixture, // Given a proxy method auto proxy_method = ProxyMethodType{this->proxy_base_, - std::make_unique(this->proxy_method_binding_mock_), - kMethodName}; + kMethodName, + std::make_unique(this->proxy_method_binding_mock_)}; auto same_method_ptr = &proxy_method; // When move-assigning this method to itself @@ -263,7 +263,7 @@ TYPED_TEST(ProxyMethodAllArgCombinationsTestFixture, InvalidBindingInConstructor using ProxyMethodType = ProxyMethod; // When a proxy method is created with an invalid binding - auto proxy_method = std::make_unique(this->proxy_base_, nullptr, kMethodName); + auto proxy_method = std::make_unique(this->proxy_base_, kMethodName, nullptr); // Then calling AreBindingsValid returns false EXPECT_FALSE(ProxyBaseView{this->proxy_base_}.AreBindingsValid()); diff --git a/score/mw/com/impl/methods/proxy_method_with_in_args.h b/score/mw/com/impl/methods/proxy_method_with_in_args.h index 113b7e8d9..9d1280f23 100644 --- a/score/mw/com/impl/methods/proxy_method_with_in_args.h +++ b/score/mw/com/impl/methods/proxy_method_with_in_args.h @@ -52,18 +52,18 @@ class ProxyMethod final : public ProxyMethodBase public: ProxyMethod(ProxyBase& proxy_base, std::string_view method_name) noexcept : ProxyMethod(proxy_base, + method_name, ProxyMethodBindingFactory::Create(proxy_base.GetHandle(), ProxyBaseView{proxy_base}.GetBinding(), method_name, - MethodType::kMethod), - method_name) + MethodType::kMethod)) { } ProxyMethod(ProxyBase& proxy_base, - std::unique_ptr proxy_method_binding, - std::string_view method_name) noexcept - : ProxyMethodBase(proxy_base, std::move(proxy_method_binding), method_name, MethodType::kMethod), + std::string_view method_name, + std::unique_ptr proxy_method_binding) noexcept + : ProxyMethodBase(proxy_base, method_name, std::move(proxy_method_binding), MethodType::kMethod), are_in_arg_ptrs_active_(kCallQueueSize) { auto proxy_base_view = ProxyBaseView{proxy_base}; diff --git a/score/mw/com/impl/methods/proxy_method_with_in_args_and_return.h b/score/mw/com/impl/methods/proxy_method_with_in_args_and_return.h index fcfb3bcf5..e9e979a99 100644 --- a/score/mw/com/impl/methods/proxy_method_with_in_args_and_return.h +++ b/score/mw/com/impl/methods/proxy_method_with_in_args_and_return.h @@ -68,11 +68,11 @@ class ProxyMethod final : public ProxyMethodBase ProxyMethod(ProxyBase& proxy_base, std::string_view method_name) noexcept : ProxyMethodBase( proxy_base, + method_name, ProxyMethodBindingFactory::Create(proxy_base.GetHandle(), ProxyBaseView{proxy_base}.GetBinding(), method_name, MethodType::kMethod), - method_name, MethodType::kMethod), are_in_arg_ptrs_active_(kCallQueueSize) { @@ -86,9 +86,9 @@ class ProxyMethod final : public ProxyMethodBase } ProxyMethod(ProxyBase& proxy_base, - std::unique_ptr proxy_method_binding, - std::string_view method_name) noexcept - : ProxyMethodBase(proxy_base, std::move(proxy_method_binding), method_name, MethodType::kMethod), + std::string_view method_name, + std::unique_ptr proxy_method_binding) noexcept + : ProxyMethodBase(proxy_base, method_name, std::move(proxy_method_binding), MethodType::kMethod), are_in_arg_ptrs_active_(kCallQueueSize) { auto proxy_base_view = ProxyBaseView{proxy_base}; @@ -101,10 +101,10 @@ class ProxyMethod final : public ProxyMethodBase } ProxyMethod(ProxyBase& proxy_base, - std::unique_ptr proxy_method_binding, std::string_view method_name, + std::unique_ptr proxy_method_binding, FieldOnlyConstructorEnabler) noexcept - : ProxyMethodBase(proxy_base, std::move(proxy_method_binding), method_name, MethodType::kSet), + : ProxyMethodBase(proxy_base, method_name, std::move(proxy_method_binding), MethodType::kSet), are_in_arg_ptrs_active_(kCallQueueSize) { auto proxy_base_view = ProxyBaseView{proxy_base}; diff --git a/score/mw/com/impl/methods/proxy_method_with_return_type.h b/score/mw/com/impl/methods/proxy_method_with_return_type.h index edeea7b8c..22fb37469 100644 --- a/score/mw/com/impl/methods/proxy_method_with_return_type.h +++ b/score/mw/com/impl/methods/proxy_method_with_return_type.h @@ -61,11 +61,11 @@ class ProxyMethod final : public ProxyMethodBase public: ProxyMethod(ProxyBase& proxy_base, std::string_view method_name) noexcept : ProxyMethodBase(proxy_base, + method_name, ProxyMethodBindingFactory::Create(proxy_base.GetHandle(), ProxyBaseView{proxy_base}.GetBinding(), method_name, MethodType::kMethod), - method_name, MethodType::kMethod) { auto proxy_base_view = ProxyBaseView{proxy_base}; @@ -78,9 +78,9 @@ class ProxyMethod final : public ProxyMethodBase } ProxyMethod(ProxyBase& proxy_base, - std::unique_ptr proxy_method_binding, - std::string_view method_name) noexcept - : ProxyMethodBase(proxy_base, std::move(proxy_method_binding), method_name, MethodType::kMethod) + std::string_view method_name, + std::unique_ptr proxy_method_binding) noexcept + : ProxyMethodBase(proxy_base, method_name, std::move(proxy_method_binding), MethodType::kMethod) { auto proxy_base_view = ProxyBaseView{proxy_base}; proxy_base_view.RegisterMethod(method_name_, *this); @@ -92,10 +92,10 @@ class ProxyMethod final : public ProxyMethodBase } ProxyMethod(ProxyBase& proxy_base, - std::unique_ptr proxy_method_binding, std::string_view method_name, + std::unique_ptr proxy_method_binding, FieldOnlyConstructorEnabler) noexcept - : ProxyMethodBase(proxy_base, std::move(proxy_method_binding), method_name, MethodType::kGet) + : ProxyMethodBase(proxy_base, method_name, std::move(proxy_method_binding), MethodType::kGet) { auto proxy_base_view = ProxyBaseView{proxy_base}; if (binding_ == nullptr) diff --git a/score/mw/com/impl/methods/proxy_method_without_in_args_or_return.h b/score/mw/com/impl/methods/proxy_method_without_in_args_or_return.h index e9a36fd28..c45467fad 100644 --- a/score/mw/com/impl/methods/proxy_method_without_in_args_or_return.h +++ b/score/mw/com/impl/methods/proxy_method_without_in_args_or_return.h @@ -46,11 +46,11 @@ class ProxyMethod final : public ProxyMethodBase public: ProxyMethod(ProxyBase& proxy_base, std::string_view method_name) noexcept : ProxyMethodBase(proxy_base, + method_name, ProxyMethodBindingFactory::Create(proxy_base.GetHandle(), ProxyBaseView{proxy_base}.GetBinding(), method_name, MethodType::kMethod), - method_name, MethodType::kMethod) { auto proxy_base_view = ProxyBaseView{proxy_base}; @@ -63,9 +63,9 @@ class ProxyMethod final : public ProxyMethodBase } ProxyMethod(ProxyBase& proxy_base, - std::unique_ptr proxy_method_binding, - std::string_view method_name) noexcept - : ProxyMethodBase(proxy_base, std::move(proxy_method_binding), method_name, MethodType::kMethod) + std::string_view method_name, + std::unique_ptr proxy_method_binding) noexcept + : ProxyMethodBase(proxy_base, method_name, std::move(proxy_method_binding), MethodType::kMethod) { auto proxy_base_view = ProxyBaseView{proxy_base}; proxy_base_view.RegisterMethod(method_name_, *this); diff --git a/score/mw/com/impl/mocking/proxy_event_mock_test.cpp b/score/mw/com/impl/mocking/proxy_event_mock_test.cpp index 30966ed05..6bee8e59f 100644 --- a/score/mw/com/impl/mocking/proxy_event_mock_test.cpp +++ b/score/mw/com/impl/mocking/proxy_event_mock_test.cpp @@ -52,8 +52,8 @@ class ProxyEventFieldMockFixture : public ::testing::Test ProxyEventFieldMock proxy_service_element_mock_{}; ProxyBase proxy_base_{nullptr, MakeFakeHandle(1U)}; ProxyEventField unit_{proxy_base_, - std::unique_ptr>{nullptr}, - kDummyEventFieldName}; + kDummyEventFieldName, + std::unique_ptr>{nullptr}}; }; struct ProxyEventStruct diff --git a/score/mw/com/impl/proxy_base_test.cpp b/score/mw/com/impl/proxy_base_test.cpp index 2ed375ad0..c696379af 100644 --- a/score/mw/com/impl/proxy_base_test.cpp +++ b/score/mw/com/impl/proxy_base_test.cpp @@ -593,27 +593,27 @@ class ProxyBaseServiceElementReferencesFixture : public ::testing::Test MyProxy proxy_{std::make_unique(proxy_binding_mock_), handle_}; ProxyEventBase event_0_{proxy_, + event_name_0_, &proxy_binding_mock_, - std::make_unique(), - event_name_0_}; + std::make_unique()}; ProxyEventBase event_1_{proxy_, + event_name_1_, &proxy_binding_mock_, - std::make_unique(), - event_name_1_}; + std::make_unique()}; ProxyEventBase field_event_dispatch_0_{proxy_, + field_name_0_, &proxy_binding_mock_, - std::make_unique(), - field_name_0_}; + std::make_unique()}; ProxyEventBase field_event_dispatch_1_{proxy_, + field_name_1_, &proxy_binding_mock_, - std::make_unique(), - field_name_1_}; - ProxyFieldBase field_0_{proxy_, &field_event_dispatch_0_, field_name_0_}; - ProxyFieldBase field_1_{proxy_, &field_event_dispatch_1_, field_name_1_}; + std::make_unique()}; + ProxyFieldBase field_0_{proxy_, field_name_0_, &field_event_dispatch_0_}; + ProxyFieldBase field_1_{proxy_, field_name_1_, &field_event_dispatch_1_}; - DummyProxyMethod method_0_{proxy_, std::make_unique(), method_name_0_}; - DummyProxyMethod method_1_{proxy_, std::make_unique(), method_name_1_}; + DummyProxyMethod method_0_{proxy_, method_name_0_, std::make_unique()}; + DummyProxyMethod method_1_{proxy_, method_name_1_, std::make_unique()}; }; TEST_F(ProxyBaseServiceElementReferencesFixture, RegisteringServiceElementStoresReferenceInMap) @@ -707,11 +707,11 @@ TEST_F(ProxyBaseServiceElementReferencesFixture, MoveAssigningUpdatesReferencesT // and given that an Event, Field and Method were registered on the second proxy ProxyEventBase event{ - proxy_2, &proxy_binding_mock, std::make_unique(), other_event_name}; + proxy_2, other_event_name, &proxy_binding_mock, std::make_unique()}; ProxyEventBase field_event_dispatch{ - proxy_2, &proxy_binding_mock, std::make_unique(), other_field_name}; - ProxyFieldBase field{proxy_2, &field_event_dispatch, other_field_name}; - DummyProxyMethod method{proxy_2, std::make_unique(), other_method_name}; + proxy_2, other_field_name, &proxy_binding_mock, std::make_unique()}; + ProxyFieldBase field{proxy_2, other_field_name, &field_event_dispatch}; + DummyProxyMethod method{proxy_2, other_method_name, std::make_unique()}; ProxyBaseView{proxy_2}.RegisterEvent(other_event_name, event); ProxyBaseView{proxy_2}.RegisterField(other_field_name, field); ProxyBaseView{proxy_2}.RegisterMethod(other_method_name, method); diff --git a/score/mw/com/impl/proxy_event.h b/score/mw/com/impl/proxy_event.h index cd699be9b..27263c788 100644 --- a/score/mw/com/impl/proxy_event.h +++ b/score/mw/com/impl/proxy_event.h @@ -80,8 +80,8 @@ class ProxyEvent final : public ProxyEventBase /// /// \param proxy_binding The binding that shall be associated with this proxy. ProxyEvent(ProxyBase& base, - std::unique_ptr> proxy_event_binding, - const std::string_view event_name); + const std::string_view event_name, + std::unique_ptr> proxy_event_binding); /// \brief Constructor that allows to set the binding directly. /// @@ -89,8 +89,8 @@ class ProxyEvent final : public ProxyEventBase /// /// \param proxy_binding The binding that shall be associated with this proxy. ProxyEvent(ProxyBase& base, - std::unique_ptr> proxy_binding, const std::string_view event_name, + std::unique_ptr> proxy_binding, FieldOnlyConstructorEnabler); /// \brief Constructs a ProxyEvent by querying the base proxie's ProxyBinding for the respective ProxyEventBinding. @@ -143,9 +143,9 @@ class ProxyEvent final : public ProxyEventBase template ProxyEvent::ProxyEvent(ProxyBase& base, - std::unique_ptr> proxy_event_binding, - const std::string_view event_name) - : ProxyEventBase{base, ProxyBaseView{base}.GetBinding(), std::move(proxy_event_binding), event_name}, + const std::string_view event_name, + std::unique_ptr> proxy_event_binding) + : ProxyEventBase{base, event_name, ProxyBaseView{base}.GetBinding(), std::move(proxy_event_binding)}, proxy_event_mock_{nullptr} { ProxyBaseView proxy_base_view{base}; @@ -158,7 +158,7 @@ ProxyEvent::ProxyEvent(ProxyBase& base, template ProxyEvent::ProxyEvent(ProxyBase& base, const std::string_view event_name) - : ProxyEvent{base, ProxyEventBindingFactory::Create(base, event_name), event_name} + : ProxyEvent{base, event_name, ProxyEventBindingFactory::Create(base, event_name)} { if (GetTypedEventBinding() != nullptr) { @@ -171,10 +171,10 @@ ProxyEvent::ProxyEvent(ProxyBase& base, const std::string_view event template ProxyEvent::ProxyEvent(ProxyBase& base, - std::unique_ptr> proxy_binding, const std::string_view event_name, + std::unique_ptr> proxy_binding, FieldOnlyConstructorEnabler) - : ProxyEvent{base, std::move(proxy_binding), event_name} + : ProxyEvent{base, event_name, std::move(proxy_binding)} { // This is the specific ctor that is used by ProxyField for its "dispatch event" composite. Therefore, we do not // register the event in the ProxyBase's event map, since registration in the correct field map is done by diff --git a/score/mw/com/impl/proxy_event_base.cpp b/score/mw/com/impl/proxy_event_base.cpp index 4e748c0d8..c8e7c3fd1 100644 --- a/score/mw/com/impl/proxy_event_base.cpp +++ b/score/mw/com/impl/proxy_event_base.cpp @@ -77,9 +77,9 @@ class EventBindingRegistrationGuard final // This is false positive. Function is declared only once. // coverity[autosar_cpp14_a3_1_1_violation] ProxyEventBase::ProxyEventBase(ProxyBase& proxy_base, + std::string_view event_name, ProxyBinding* proxy_binding_ptr, - std::unique_ptr proxy_event_binding, - std::string_view event_name) noexcept + std::unique_ptr proxy_event_binding) noexcept : binding_base_{std::move(proxy_event_binding)}, proxy_base_(proxy_base), event_name_{event_name}, diff --git a/score/mw/com/impl/proxy_event_base.h b/score/mw/com/impl/proxy_event_base.h index 1e8ccf594..1092d3247 100644 --- a/score/mw/com/impl/proxy_event_base.h +++ b/score/mw/com/impl/proxy_event_base.h @@ -59,9 +59,9 @@ class ProxyEventBase /// \param proxy_event_binding The binding that shall be associated with this proxy event. /// \param event_name Event name of the event. ProxyEventBase(ProxyBase& proxy_base, + std::string_view event_name, ProxyBinding* proxy_binding_ptr, - std::unique_ptr proxy_event_binding, - std::string_view event_name) noexcept; + std::unique_ptr proxy_event_binding) noexcept; /// \brief A ProxyEventBase shall not be copyable ProxyEventBase(const ProxyEventBase&) = delete; diff --git a/score/mw/com/impl/proxy_event_base_test.cpp b/score/mw/com/impl/proxy_event_base_test.cpp index 6ec683ec8..47a18a00c 100644 --- a/score/mw/com/impl/proxy_event_base_test.cpp +++ b/score/mw/com/impl/proxy_event_base_test.cpp @@ -74,7 +74,7 @@ class ProxyEventBaseFixture : public ::testing::Test mock_service_element_binding_ = mock_service_element_binding_ptr.get(); service_element_ = - std::make_unique(empty_proxy_, std::move(mock_service_element_binding_ptr), kEventName); + std::make_unique(empty_proxy_, kEventName, std::move(mock_service_element_binding_ptr)); ON_CALL(*mock_service_element_binding_, SetReceiveHandler(_)).WillByDefault(Return(score::Result{})); } @@ -165,7 +165,7 @@ TYPED_TEST(ProxyEventBaseCreationFixture, CreatingServiceElementWithValidEventBi // When creating a ProxyEvent with a valid binding auto service_element = std::make_unique::ServiceElementType>( - dummy_proxy, std::move(valid_proxy_event_binding), kEventName); + dummy_proxy, kEventName, std::move(valid_proxy_event_binding)); // Then the proxy should report that all bindings are valid EXPECT_TRUE(dummy_proxy.AreBindingsValid()); @@ -180,8 +180,8 @@ TYPED_TEST(ProxyEventBaseCreationFixture, CreatingServiceElementWithInvalidEvent // When creating a ProxyEvent with an invalid binding auto service_element = std::make_unique::ServiceElementType>( dummy_proxy, - std::unique_ptr::MockServiceElementType>(nullptr), - kEventName); + kEventName, + std::unique_ptr::MockServiceElementType>(nullptr)); // Then the proxy should report that all bindings are not valid EXPECT_FALSE(dummy_proxy.AreBindingsValid()); @@ -198,7 +198,7 @@ TYPED_TEST(ProxyEventBaseCreationFixture, CreatingServiceElementWithInvalidProxy // When creating a ProxyEvent with a valid binding auto service_element = std::make_unique::ServiceElementType>( - dummy_proxy, std::move(valid_proxy_event_binding), kEventName); + dummy_proxy, kEventName, std::move(valid_proxy_event_binding)); // Then the proxy should report that all bindings are not valid EXPECT_FALSE(dummy_proxy.AreBindingsValid()); @@ -224,7 +224,7 @@ TYPED_TEST(ProxyEventBaseCreationFixture, // When creating a ProxyEvent with a valid binding auto service_element = std::make_unique::ServiceElementType>( - dummy_proxy, std::move(valid_proxy_event_binding), kEventName); + dummy_proxy, kEventName, std::move(valid_proxy_event_binding)); } TYPED_TEST(ProxyEventBaseCreationFixture, @@ -245,8 +245,8 @@ TYPED_TEST(ProxyEventBaseCreationFixture, // When creating a ProxyEvent with an invalid binding auto service_element = std::make_unique::ServiceElementType>( dummy_proxy, - std::unique_ptr::MockServiceElementType>(nullptr), - kEventName); + kEventName, + std::unique_ptr::MockServiceElementType>(nullptr)); } TYPED_TEST(ProxyEventBaseUnsubscribeFixture, CallingUnsubscribeWhileSubscribedCallsUnsubscribeOnBinding) @@ -358,7 +358,7 @@ class AServiceElement : public ::testing::Test mock_service_element_binding_ = mock_service_element_binding_ptr.get(); service_element_ = - std::make_unique(empty_proxy_, std::move(mock_service_element_binding_ptr), kEventName); + std::make_unique(empty_proxy_, kEventName, std::move(mock_service_element_binding_ptr)); ASSERT_NE(service_element_, nullptr); ON_CALL(*mock_service_element_binding_, SetReceiveHandler(_)).WillByDefault(Return(score::Result{})); @@ -1040,7 +1040,7 @@ TEST(ProxyEventBaseTest, MoveConstructingProxyEventDoesNotCrash) // Given a Service Element, that is connected to a mock binding ProxyEventBase dummy_event{ - empty_proxy, ProxyBaseView{empty_proxy}.GetBinding(), std::move(mock_proxy_event_binding_ptr), kEventName}; + empty_proxy, kEventName, ProxyBaseView{empty_proxy}.GetBinding(), std::move(mock_proxy_event_binding_ptr)}; // And a new Service Element is created with the move constructor ProxyEventBase dummy_event_2{std::move(dummy_event)}; @@ -1066,13 +1066,13 @@ TEST(ProxyEventBaseTest, MoveAssigningProxyEventDoesNotCrash) // Given a Service Element, that is connected to a mock binding ProxyEventBase dummy_event{ - empty_proxy, ProxyBaseView{empty_proxy}.GetBinding(), std::move(mock_proxy_event_binding_ptr), kEventName}; + empty_proxy, kEventName, ProxyBaseView{empty_proxy}.GetBinding(), std::move(mock_proxy_event_binding_ptr)}; // And a new Service Element is created and move assigned ProxyEventBase dummy_event_2{empty_proxy, + kEventName2, ProxyBaseView{empty_proxy}.GetBinding(), - std::make_unique>(), - kEventName2}; + std::make_unique>()}; dummy_event_2 = std::move(dummy_event); // Expect that Subscribe is called on the binding only once diff --git a/score/mw/com/impl/proxy_event_test.cpp b/score/mw/com/impl/proxy_event_test.cpp index d6b24f899..2d90c7f3a 100644 --- a/score/mw/com/impl/proxy_event_test.cpp +++ b/score/mw/com/impl/proxy_event_test.cpp @@ -106,7 +106,7 @@ class ProxyEventFixture : public ::testing::Test make_HandleType(make_InstanceIdentifier(kEmptyInstanceDeployment, kEmptyTypeDeployment))}, mock_proxy_event_ptr_{std::make_unique()}, mock_proxy_event_{*mock_proxy_event_ptr_}, - proxy_event_{empty_proxy_, std::move(mock_proxy_event_ptr_), kEventName} + proxy_event_{empty_proxy_, kEventName, std::move(mock_proxy_event_ptr_)} { } @@ -303,7 +303,7 @@ TYPED_TEST(ProxyEventFixture, CanConstructUnboundProxy) // When creating an unbound proxy event (note we need a different event name here as the fixture already uses the // first) - ProxyEvent proxy_event{this->empty_proxy_, nullptr, kEventName2}; + ProxyEvent proxy_event{this->empty_proxy_, kEventName2, nullptr}; // Nothing bad happens } @@ -448,7 +448,7 @@ TEST(ProxyEventTest, SamplePtrsToSlotDataAreConst) ProxyBase empty_proxy(std::make_unique(), make_HandleType(make_InstanceIdentifier(kEmptyInstanceDeployment, kEmptyTypeDeployment))); ProxyEvent proxy{ - empty_proxy, std::unique_ptr>{std::move(mock_proxy_ptr)}, kEventName}; + empty_proxy, kEventName, std::unique_ptr>{std::move(mock_proxy_ptr)}}; EXPECT_CALL(mock_proxy, Subscribe(max_num_samples)); EXPECT_CALL(mock_proxy, GetNewSamples(_, _)); @@ -481,7 +481,7 @@ TEST(ProxyEventDeathTest, DieOnProxyDestructionWhileHoldingSamplePtrs) ProxyBase empty_proxy(std::make_unique(), make_HandleType(make_InstanceIdentifier(kEmptyInstanceDeployment, kEmptyTypeDeployment))); auto proxy = std::make_unique>( - empty_proxy, std::unique_ptr>{std::move(mock_proxy_ptr)}, kEventName); + empty_proxy, kEventName, std::unique_ptr>{std::move(mock_proxy_ptr)}); EXPECT_CALL(mock_proxy, Subscribe(max_num_samples)); EXPECT_CALL(mock_proxy, GetNewSamples(_, _)); diff --git a/score/mw/com/impl/proxy_field.h b/score/mw/com/impl/proxy_field.h index 6019f55b8..148dbe9c6 100644 --- a/score/mw/com/impl/proxy_field.h +++ b/score/mw/com/impl/proxy_field.h @@ -71,24 +71,24 @@ class ProxyField final : public ProxyFieldBase /// here. template > ProxyField(ProxyBase& proxy_base, + const std::string_view field_name, std::unique_ptr> event_binding, std::unique_ptr get_method_binding, std::unique_ptr set_method_binding, - const std::string_view field_name, detail::EnableBothTag = {}) : ProxyField{proxy_base, - std::make_unique>(proxy_base, std::move(event_binding), field_name), + field_name, + std::make_unique>(proxy_base, field_name, std::move(event_binding)), std::make_unique>( proxy_base, - std::move(get_method_binding), field_name, + std::move(get_method_binding), typename ProxyMethod::FieldOnlyConstructorEnabler{}), std::make_unique>( proxy_base, - std::move(set_method_binding), field_name, - typename ProxyMethod::FieldOnlyConstructorEnabler{}), - field_name} + std::move(set_method_binding), + typename ProxyMethod::FieldOnlyConstructorEnabler{})} { } @@ -98,18 +98,18 @@ class ProxyField final : public ProxyFieldBase /// here. template > ProxyField(ProxyBase& proxy_base, + const std::string_view field_name, std::unique_ptr> event_binding, std::unique_ptr get_method_binding, - const std::string_view field_name, detail::EnableGetOnlyTag = {}) : ProxyField{proxy_base, - std::make_unique>(proxy_base, std::move(event_binding), field_name), + field_name, + std::make_unique>(proxy_base, field_name, std::move(event_binding)), std::make_unique>( proxy_base, - std::move(get_method_binding), field_name, - typename ProxyMethod::FieldOnlyConstructorEnabler{}), - field_name} + std::move(get_method_binding), + typename ProxyMethod::FieldOnlyConstructorEnabler{})} { } @@ -119,18 +119,18 @@ class ProxyField final : public ProxyFieldBase /// here. template > ProxyField(ProxyBase& proxy_base, + const std::string_view field_name, std::unique_ptr> event_binding, std::unique_ptr set_method_binding, - const std::string_view field_name, detail::EnableSetOnlyTag = {}) : ProxyField{proxy_base, - std::make_unique>(proxy_base, std::move(event_binding), field_name), + field_name, + std::make_unique>(proxy_base, field_name, std::move(event_binding)), std::make_unique>( proxy_base, - std::move(set_method_binding), field_name, - typename ProxyMethod::FieldOnlyConstructorEnabler{}), - field_name} + std::move(set_method_binding), + typename ProxyMethod::FieldOnlyConstructorEnabler{})} { } @@ -140,12 +140,12 @@ class ProxyField final : public ProxyFieldBase /// here. template > ProxyField(ProxyBase& proxy_base, - std::unique_ptr> event_binding, const std::string_view field_name, + std::unique_ptr> event_binding, detail::EnableNeitherTag = {}) : ProxyField{proxy_base, - std::make_unique>(proxy_base, std::move(event_binding), field_name), - field_name} + field_name, + std::make_unique>(proxy_base, field_name, std::move(event_binding))} { } @@ -154,22 +154,22 @@ class ProxyField final : public ProxyFieldBase template > ProxyField(ProxyBase& proxy_base, const std::string_view field_name, detail::EnableBothTag = {}) : ProxyField{proxy_base, + field_name, std::make_unique>( proxy_base, - ProxyFieldBindingFactory::CreateEventBinding(proxy_base, field_name), field_name, + ProxyFieldBindingFactory::CreateEventBinding(proxy_base, field_name), typename ProxyEvent::FieldOnlyConstructorEnabler{}), std::make_unique>( proxy_base, - ProxyFieldBindingFactory::CreateGetMethodBinding(proxy_base, field_name), field_name, + ProxyFieldBindingFactory::CreateGetMethodBinding(proxy_base, field_name), typename ProxyMethod::FieldOnlyConstructorEnabler{}), std::make_unique>( proxy_base, - ProxyFieldBindingFactory::CreateSetMethodBinding(proxy_base, field_name), field_name, - typename ProxyMethod::FieldOnlyConstructorEnabler{}), - field_name} + ProxyFieldBindingFactory::CreateSetMethodBinding(proxy_base, field_name), + typename ProxyMethod::FieldOnlyConstructorEnabler{})} { } @@ -177,17 +177,17 @@ class ProxyField final : public ProxyFieldBase template > ProxyField(ProxyBase& proxy_base, const std::string_view field_name, detail::EnableGetOnlyTag = {}) : ProxyField{proxy_base, + field_name, std::make_unique>( proxy_base, - ProxyFieldBindingFactory::CreateEventBinding(proxy_base, field_name), field_name, + ProxyFieldBindingFactory::CreateEventBinding(proxy_base, field_name), typename ProxyEvent::FieldOnlyConstructorEnabler{}), std::make_unique>( proxy_base, - ProxyFieldBindingFactory::CreateGetMethodBinding(proxy_base, field_name), field_name, - typename ProxyMethod::FieldOnlyConstructorEnabler{}), - field_name} + ProxyFieldBindingFactory::CreateGetMethodBinding(proxy_base, field_name), + typename ProxyMethod::FieldOnlyConstructorEnabler{})} { } @@ -195,17 +195,17 @@ class ProxyField final : public ProxyFieldBase template > ProxyField(ProxyBase& proxy_base, const std::string_view field_name, detail::EnableSetOnlyTag = {}) : ProxyField{proxy_base, + field_name, std::make_unique>( proxy_base, - ProxyFieldBindingFactory::CreateEventBinding(proxy_base, field_name), field_name, + ProxyFieldBindingFactory::CreateEventBinding(proxy_base, field_name), typename ProxyEvent::FieldOnlyConstructorEnabler{}), std::make_unique>( proxy_base, - ProxyFieldBindingFactory::CreateSetMethodBinding(proxy_base, field_name), field_name, - typename ProxyMethod::FieldOnlyConstructorEnabler{}), - field_name} + ProxyFieldBindingFactory::CreateSetMethodBinding(proxy_base, field_name), + typename ProxyMethod::FieldOnlyConstructorEnabler{})} { } @@ -214,12 +214,12 @@ class ProxyField final : public ProxyFieldBase template > ProxyField(ProxyBase& proxy_base, const std::string_view field_name, detail::EnableNeitherTag = {}) : ProxyField{proxy_base, + field_name, std::make_unique>( proxy_base, - ProxyFieldBindingFactory::CreateEventBinding(proxy_base, field_name), field_name, - typename ProxyEvent::FieldOnlyConstructorEnabler{}), - field_name} + ProxyFieldBindingFactory::CreateEventBinding(proxy_base, field_name), + typename ProxyEvent::FieldOnlyConstructorEnabler{})} { } @@ -275,11 +275,11 @@ class ProxyField final : public ProxyFieldBase /// \brief Private constructor overload for when both EnableGet and EnableSet are true. template > ProxyField(ProxyBase& proxy_base, + const std::string_view field_name, std::unique_ptr> proxy_event_dispatch, std::unique_ptr> proxy_method_get_dispatch, - std::unique_ptr> proxy_method_set_dispatch, - const std::string_view field_name) - : ProxyFieldBase{proxy_base, proxy_event_dispatch.get(), field_name}, + std::unique_ptr> proxy_method_set_dispatch) + : ProxyFieldBase{proxy_base, field_name, proxy_event_dispatch.get()}, proxy_event_dispatch_{std::move(proxy_event_dispatch)}, proxy_method_get_dispatch_{std::move(proxy_method_get_dispatch)}, proxy_method_set_dispatch_{std::move(proxy_method_set_dispatch)} @@ -293,10 +293,10 @@ class ProxyField final : public ProxyFieldBase /// \brief Private constructor overload for when only EnableGet is true. template > ProxyField(ProxyBase& proxy_base, + const std::string_view field_name, std::unique_ptr> proxy_event_dispatch, - std::unique_ptr> proxy_method_get_dispatch, - const std::string_view field_name) - : ProxyFieldBase{proxy_base, proxy_event_dispatch.get(), field_name}, + std::unique_ptr> proxy_method_get_dispatch) + : ProxyFieldBase{proxy_base, field_name, proxy_event_dispatch.get()}, proxy_event_dispatch_{std::move(proxy_event_dispatch)}, proxy_method_get_dispatch_{std::move(proxy_method_get_dispatch)} { @@ -309,10 +309,10 @@ class ProxyField final : public ProxyFieldBase /// \brief Private constructor overload for when only EnableSet is true. template > ProxyField(ProxyBase& proxy_base, + const std::string_view field_name, std::unique_ptr> proxy_event_dispatch, - std::unique_ptr> proxy_method_set_dispatch, - const std::string_view field_name) - : ProxyFieldBase{proxy_base, proxy_event_dispatch.get(), field_name}, + std::unique_ptr> proxy_method_set_dispatch) + : ProxyFieldBase{proxy_base, field_name, proxy_event_dispatch.get()}, proxy_event_dispatch_{std::move(proxy_event_dispatch)}, proxy_method_set_dispatch_{std::move(proxy_method_set_dispatch)} { @@ -325,9 +325,9 @@ class ProxyField final : public ProxyFieldBase /// \brief Private constructor overload for when both EnableGet and EnableSet are false. template > ProxyField(ProxyBase& proxy_base, - std::unique_ptr> proxy_event_dispatch, - const std::string_view field_name) - : ProxyFieldBase{proxy_base, proxy_event_dispatch.get(), field_name}, + const std::string_view field_name, + std::unique_ptr> proxy_event_dispatch) + : ProxyFieldBase{proxy_base, field_name, proxy_event_dispatch.get()}, proxy_event_dispatch_{std::move(proxy_event_dispatch)} { SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD(proxy_event_dispatch_ != nullptr); diff --git a/score/mw/com/impl/proxy_field_base.h b/score/mw/com/impl/proxy_field_base.h index dc49bcaee..f017e2410 100644 --- a/score/mw/com/impl/proxy_field_base.h +++ b/score/mw/com/impl/proxy_field_base.h @@ -30,7 +30,7 @@ namespace score::mw::com::impl class ProxyFieldBase { public: - ProxyFieldBase(ProxyBase& proxy_base, ProxyEventBase* proxy_event_base_dispatch, std::string_view field_name) + ProxyFieldBase(ProxyBase& proxy_base, std::string_view field_name, ProxyEventBase* proxy_event_base_dispatch) : proxy_base_{proxy_base}, proxy_event_base_dispatch_{proxy_event_base_dispatch}, field_name_{field_name} { SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD(proxy_event_base_dispatch != nullptr); From b26ddd271ed1d0b3a397d7661c876304757ca72a Mon Sep 17 00:00:00 2001 From: Krishna Date: Fri, 24 Apr 2026 17:12:23 +0200 Subject: [PATCH 02/10] mw/com: Remove excess ProxyField constructors - Use a single test constructor which creates the get / set methods according to the provided bindings. This allows us to remove the test-only constructor overloads for each template arg combination. - Always store the get / set method dispatches as unique_ptrs even if they're not enabled (when disabled, they'll simply be nullptrs). This allows us to have a single private constructor which always accepts unique_ptrs (which may be valid or nullptrs). --- .../proxy_method_with_in_args_and_return.h | 9 +- .../methods/proxy_method_with_return_type.h | 7 + score/mw/com/impl/proxy_field.h | 162 ++++-------------- 3 files changed, 43 insertions(+), 135 deletions(-) diff --git a/score/mw/com/impl/methods/proxy_method_with_in_args_and_return.h b/score/mw/com/impl/methods/proxy_method_with_in_args_and_return.h index e9e979a99..5356522e7 100644 --- a/score/mw/com/impl/methods/proxy_method_with_in_args_and_return.h +++ b/score/mw/com/impl/methods/proxy_method_with_in_args_and_return.h @@ -55,10 +55,15 @@ class ProxyMethod final : public ProxyMethodBase // coverity[autosar_cpp14_a11_3_1_violation] friend class ProxyMethodView; - friend class ProxyField; - friend class ProxyField; + /// gtodo: check this. + friend class ProxyField; + friend class ProxyField; friend class ProxyField; friend class ProxyField; + friend class ProxyField; + friend class ProxyField; + friend class ProxyField; + friend class ProxyField; struct FieldOnlyConstructorEnabler { diff --git a/score/mw/com/impl/methods/proxy_method_with_return_type.h b/score/mw/com/impl/methods/proxy_method_with_return_type.h index 22fb37469..48adfc00f 100644 --- a/score/mw/com/impl/methods/proxy_method_with_return_type.h +++ b/score/mw/com/impl/methods/proxy_method_with_return_type.h @@ -49,6 +49,13 @@ class ProxyMethod final : public ProxyMethodBase // This enables us to hide unnecessary internals from the end-user. // coverity[autosar_cpp14_a11_3_1_violation] friend class ProxyMethodView; + friend class ProxyField; + friend class ProxyField; + friend class ProxyField; + friend class ProxyField; + friend class ProxyField; + friend class ProxyField; + friend class ProxyField; friend class ProxyField; friend class ProxyField; friend class ProxyField; diff --git a/score/mw/com/impl/proxy_field.h b/score/mw/com/impl/proxy_field.h index 148dbe9c6..5e6894aba 100644 --- a/score/mw/com/impl/proxy_field.h +++ b/score/mw/com/impl/proxy_field.h @@ -16,7 +16,6 @@ #include "score/mw/com/impl/methods/proxy_method_with_in_args_and_return.h" #include "score/mw/com/impl/methods/proxy_method_with_return_type.h" #include "score/mw/com/impl/plumbing/proxy_field_binding_factory.h" -#include "score/mw/com/impl/plumbing/sample_ptr.h" #include "score/mw/com/impl/proxy_event.h" #include "score/mw/com/impl/proxy_event_binding.h" #include "score/mw/com/impl/proxy_field_base.h" @@ -69,83 +68,31 @@ class ProxyField final : public ProxyFieldBase /// /// This is used for testing only. Allows for directly setting the bindings, and usually the mock binding is used /// here. - template > ProxyField(ProxyBase& proxy_base, const std::string_view field_name, std::unique_ptr> event_binding, - std::unique_ptr get_method_binding, - std::unique_ptr set_method_binding, + std::unique_ptr get_method_binding = nullptr, + std::unique_ptr set_method_binding = nullptr, detail::EnableBothTag = {}) - : ProxyField{proxy_base, - field_name, - std::make_unique>(proxy_base, field_name, std::move(event_binding)), - std::make_unique>( - proxy_base, - field_name, - std::move(get_method_binding), - typename ProxyMethod::FieldOnlyConstructorEnabler{}), - std::make_unique>( - proxy_base, - field_name, - std::move(set_method_binding), - typename ProxyMethod::FieldOnlyConstructorEnabler{})} - { - } - - /// Constructor that allows to set the binding directly (only EnableGet is true). - /// - /// This is used for testing only. Allows for directly setting the bindings, and usually the mock binding is used - /// here. - template > - ProxyField(ProxyBase& proxy_base, - const std::string_view field_name, - std::unique_ptr> event_binding, - std::unique_ptr get_method_binding, - detail::EnableGetOnlyTag = {}) - : ProxyField{proxy_base, - field_name, - std::make_unique>(proxy_base, field_name, std::move(event_binding)), - std::make_unique>( - proxy_base, - field_name, - std::move(get_method_binding), - typename ProxyMethod::FieldOnlyConstructorEnabler{})} - { - } - - /// Constructor that allows to set the binding directly (only EnableSet is true). - /// - /// This is used for testing only. Allows for directly setting the bindings, and usually the mock binding is used - /// here. - template > - ProxyField(ProxyBase& proxy_base, - const std::string_view field_name, - std::unique_ptr> event_binding, - std::unique_ptr set_method_binding, - detail::EnableSetOnlyTag = {}) - : ProxyField{proxy_base, - field_name, - std::make_unique>(proxy_base, field_name, std::move(event_binding)), - std::make_unique>( - proxy_base, - field_name, - std::move(set_method_binding), - typename ProxyMethod::FieldOnlyConstructorEnabler{})} - { - } - - /// Constructor that allows to set the binding directly (both EnableGet and EnableSet are false). - /// - /// This is used for testing only. Allows for directly setting the bindings, and usually the mock binding is used - /// here. - template > - ProxyField(ProxyBase& proxy_base, - const std::string_view field_name, - std::unique_ptr> event_binding, - detail::EnableNeitherTag = {}) - : ProxyField{proxy_base, - field_name, - std::make_unique>(proxy_base, field_name, std::move(event_binding))} + : ProxyField{ + proxy_base, + field_name, + std::make_unique>(proxy_base, field_name, std::move(event_binding)), + // If a binding is not provided, then we don't create the method. This ensures that the ProxyMethod + // doesn't report that the binding is invalid (via proxy_base_view.MarkServiceElementBindingInvalid()) + get_method_binding == nullptr ? nullptr + : std::make_unique>( + proxy_base, + field_name, + std::move(get_method_binding), + typename ProxyMethod::FieldOnlyConstructorEnabler{}), + set_method_binding == nullptr + ? nullptr + : std::make_unique>( + proxy_base, + field_name, + std::move(set_method_binding), + typename ProxyMethod::FieldOnlyConstructorEnabler{})} { } @@ -187,7 +134,8 @@ class ProxyField final : public ProxyFieldBase proxy_base, field_name, ProxyFieldBindingFactory::CreateGetMethodBinding(proxy_base, field_name), - typename ProxyMethod::FieldOnlyConstructorEnabler{})} + typename ProxyMethod::FieldOnlyConstructorEnabler{}), + nullptr} { } @@ -201,6 +149,7 @@ class ProxyField final : public ProxyFieldBase field_name, ProxyFieldBindingFactory::CreateEventBinding(proxy_base, field_name), typename ProxyEvent::FieldOnlyConstructorEnabler{}), + nullptr, std::make_unique>( proxy_base, field_name, @@ -219,7 +168,9 @@ class ProxyField final : public ProxyFieldBase proxy_base, field_name, ProxyFieldBindingFactory::CreateEventBinding(proxy_base, field_name), - typename ProxyEvent::FieldOnlyConstructorEnabler{})} + typename ProxyEvent::FieldOnlyConstructorEnabler{}), + nullptr, + nullptr} { } @@ -272,8 +223,6 @@ class ProxyField final : public ProxyFieldBase } private: - /// \brief Private constructor overload for when both EnableGet and EnableSet are true. - template > ProxyField(ProxyBase& proxy_base, const std::string_view field_name, std::unique_ptr> proxy_event_dispatch, @@ -290,63 +239,10 @@ class ProxyField final : public ProxyFieldBase proxy_base_view.RegisterField(field_name, *this); } - /// \brief Private constructor overload for when only EnableGet is true. - template > - ProxyField(ProxyBase& proxy_base, - const std::string_view field_name, - std::unique_ptr> proxy_event_dispatch, - std::unique_ptr> proxy_method_get_dispatch) - : ProxyFieldBase{proxy_base, field_name, proxy_event_dispatch.get()}, - proxy_event_dispatch_{std::move(proxy_event_dispatch)}, - proxy_method_get_dispatch_{std::move(proxy_method_get_dispatch)} - { - SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD(proxy_event_dispatch_ != nullptr); - - ProxyBaseView proxy_base_view{proxy_base}; - proxy_base_view.RegisterField(field_name, *this); - } - - /// \brief Private constructor overload for when only EnableSet is true. - template > - ProxyField(ProxyBase& proxy_base, - const std::string_view field_name, - std::unique_ptr> proxy_event_dispatch, - std::unique_ptr> proxy_method_set_dispatch) - : ProxyFieldBase{proxy_base, field_name, proxy_event_dispatch.get()}, - proxy_event_dispatch_{std::move(proxy_event_dispatch)}, - proxy_method_set_dispatch_{std::move(proxy_method_set_dispatch)} - { - SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD(proxy_event_dispatch_ != nullptr); - - ProxyBaseView proxy_base_view{proxy_base}; - proxy_base_view.RegisterField(field_name, *this); - } - - /// \brief Private constructor overload for when both EnableGet and EnableSet are false. - template > - ProxyField(ProxyBase& proxy_base, - const std::string_view field_name, - std::unique_ptr> proxy_event_dispatch) - : ProxyFieldBase{proxy_base, field_name, proxy_event_dispatch.get()}, - proxy_event_dispatch_{std::move(proxy_event_dispatch)} - { - SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD(proxy_event_dispatch_ != nullptr); - - ProxyBaseView proxy_base_view{proxy_base}; - proxy_base_view.RegisterField(field_name, *this); - } - std::unique_ptr> proxy_event_dispatch_; - struct empty - { - }; - - using ProxyGetMethodType = std::conditional_t>, empty>; - using ProxySetMethodType = std::conditional_t>, empty>; - - ProxyGetMethodType proxy_method_get_dispatch_; - ProxySetMethodType proxy_method_set_dispatch_; + std::unique_ptr> proxy_method_get_dispatch_; + std::unique_ptr> proxy_method_set_dispatch_; static_assert(std::is_same>>::value, "proxy_event_dispatch_ needs to be a unique_ptr since we pass a pointer to it to ProxyFieldBase, so " From 2f5a0da8cfd748a909b4951e832935fbfbd84009 Mon Sep 17 00:00:00 2001 From: Krishna Date: Fri, 24 Apr 2026 17:12:23 +0200 Subject: [PATCH 03/10] mw/com: Use tag types instead of bools for field enable flags Replaces the EnableGet/EnableSet/EnableNotifier bool template parameters on ProxyField and SkeletonField with a variadic pack of tags (WithGetter, WithSetter) declared in field_tags.h. Presence of a tag enables the matching API. The notifier surface stays unconditional on both sides, since a field without a notifier cannot propagate value changes. Also updates friend/forward declarations in ProxyEvent, ProxyMethod, SkeletonEvent and SkeletonMethod, the Trait::Field aliases plus the traits example doc, and the skeleton_field_test.cpp call sites. --- score/mw/com/impl/BUILD | 12 + score/mw/com/impl/field_tags.cpp | 13 + score/mw/com/impl/field_tags.h | 51 ++++ score/mw/com/impl/method_type.h | 20 -- .../proxy_method_with_in_args_and_return.h | 15 +- .../methods/proxy_method_with_return_type.h | 18 +- score/mw/com/impl/methods/skeleton_method.h | 4 +- score/mw/com/impl/proxy_event.h | 8 +- score/mw/com/impl/proxy_field.h | 70 +++--- score/mw/com/impl/skeleton_event.h | 4 +- score/mw/com/impl/skeleton_field.h | 222 +++++++----------- score/mw/com/impl/skeleton_field_test.cpp | 19 +- score/mw/com/impl/traits.h | 23 +- 13 files changed, 227 insertions(+), 252 deletions(-) create mode 100644 score/mw/com/impl/field_tags.cpp create mode 100644 score/mw/com/impl/field_tags.h diff --git a/score/mw/com/impl/BUILD b/score/mw/com/impl/BUILD index 3d3363b74..ed5fcffc2 100644 --- a/score/mw/com/impl/BUILD +++ b/score/mw/com/impl/BUILD @@ -223,6 +223,7 @@ cc_library( "//score/mw/com:__subpackages__", ], deps = [ + ":field_tags", ":method_type", ":skeleton_event", ":skeleton_field_base", @@ -247,6 +248,7 @@ cc_library( "//score/mw/com:__subpackages__", ], deps = [ + ":field_tags", ":flag_owner", ":proxy_base", ":proxy_event", @@ -286,6 +288,7 @@ cc_library( "//score/mw/com:__subpackages__", ], deps = [ + ":field_tags", ":method_type", ":proxy_event", ":proxy_event_binding", @@ -689,6 +692,15 @@ cc_library( visibility = ["//score/mw/com:__subpackages__"], ) +cc_library( + name = "field_tags", + srcs = ["field_tags.cpp"], + hdrs = ["field_tags.h"], + features = COMPILER_WARNING_FEATURES, + tags = ["FFI"], + visibility = ["//score/mw/com:__subpackages__"], +) + cc_library( name = "service_element_type", srcs = ["service_element_type.cpp"], diff --git a/score/mw/com/impl/field_tags.cpp b/score/mw/com/impl/field_tags.cpp new file mode 100644 index 000000000..f5cae1c66 --- /dev/null +++ b/score/mw/com/impl/field_tags.cpp @@ -0,0 +1,13 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +#include "score/mw/com/impl/field_tags.h" diff --git a/score/mw/com/impl/field_tags.h b/score/mw/com/impl/field_tags.h new file mode 100644 index 000000000..7d468ba8b --- /dev/null +++ b/score/mw/com/impl/field_tags.h @@ -0,0 +1,51 @@ +/******************************************************************************** + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +#ifndef PLATFORM_AAS_MW_COM_IMPL_FIELD_TAGS_H +#define PLATFORM_AAS_MW_COM_IMPL_FIELD_TAGS_H + +#include + +namespace score::mw::com::impl +{ + +/// \brief Tag types used on ProxyField/SkeletonField level to accomplish overload-resolution for various signatures, +/// which depend on the availability of Get/Set/Notifier. +struct WithGetter +{ +}; + +struct WithSetter +{ +}; + +namespace detail +{ + +template +struct contains_type : std::disjunction...> +{ +}; + +// SFINAE only works when the condition depends on the function-template parameters, not the class-template +// parameters. The std::is_same line ties substitution to a function-template +// parameter so the check fires at overload resolution instead of class instantiation. +template +struct is_tag_enabled : std::conjunction, std::is_same> +{ +}; + +} // namespace detail + +} // namespace score::mw::com::impl + +#endif // PLATFORM_AAS_MW_COM_IMPL_FIELD_TAGS_H diff --git a/score/mw/com/impl/method_type.h b/score/mw/com/impl/method_type.h index e880e6033..804a0d3d2 100644 --- a/score/mw/com/impl/method_type.h +++ b/score/mw/com/impl/method_type.h @@ -19,26 +19,6 @@ namespace score::mw::com::impl { -namespace detail -{ - -/// \brief Tag types used on ProxyField/SkeletonField level to accomplish overload-resolution for various signatures, -/// which depend on the availability of Get/Set/Notifier. -struct EnableBothTag -{ -}; -struct EnableGetOnlyTag -{ -}; -struct EnableSetOnlyTag -{ -}; -struct EnableNeitherTag -{ -}; - -} // namespace detail - /// \brief Enum used to differentiate between regular service methods and field Get/Set methods. enum class MethodType : std::uint8_t { diff --git a/score/mw/com/impl/methods/proxy_method_with_in_args_and_return.h b/score/mw/com/impl/methods/proxy_method_with_in_args_and_return.h index 5356522e7..b8163f75e 100644 --- a/score/mw/com/impl/methods/proxy_method_with_in_args_and_return.h +++ b/score/mw/com/impl/methods/proxy_method_with_in_args_and_return.h @@ -40,7 +40,7 @@ namespace score::mw::com::impl { -template +template class ProxyField; /// \brief Partial specialization of ProxyMethod for function signatures with arguments and non-void return @@ -55,15 +55,10 @@ class ProxyMethod final : public ProxyMethodBase // coverity[autosar_cpp14_a11_3_1_violation] friend class ProxyMethodView; - /// gtodo: check this. - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; + // ProxyField needs to instantiate ProxyMethod via the private FieldOnlyConstructorEnabler tag. + // coverity[autosar_cpp14_a11_3_1_violation] + template + friend class ProxyField; struct FieldOnlyConstructorEnabler { diff --git a/score/mw/com/impl/methods/proxy_method_with_return_type.h b/score/mw/com/impl/methods/proxy_method_with_return_type.h index 48adfc00f..f8bcad6a9 100644 --- a/score/mw/com/impl/methods/proxy_method_with_return_type.h +++ b/score/mw/com/impl/methods/proxy_method_with_return_type.h @@ -36,7 +36,7 @@ namespace score::mw::com::impl { -template +template class ProxyField; /// \brief Partial specialization of ProxyMethod for function signatures with no arguments and non-void return @@ -49,17 +49,11 @@ class ProxyMethod final : public ProxyMethodBase // This enables us to hide unnecessary internals from the end-user. // coverity[autosar_cpp14_a11_3_1_violation] friend class ProxyMethodView; - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; - friend class ProxyField; + + // ProxyField needs to instantiate ProxyMethod via the private FieldOnlyConstructorEnabler tag. + // coverity[autosar_cpp14_a11_3_1_violation] + template + friend class ProxyField; struct FieldOnlyConstructorEnabler { diff --git a/score/mw/com/impl/methods/skeleton_method.h b/score/mw/com/impl/methods/skeleton_method.h index 8164f2761..63c7e9508 100644 --- a/score/mw/com/impl/methods/skeleton_method.h +++ b/score/mw/com/impl/methods/skeleton_method.h @@ -31,7 +31,7 @@ namespace score::mw::com::impl { -template +template class SkeletonField; template @@ -53,7 +53,7 @@ class SkeletonMethod final : public SkeletonMethodBase static_assert(return_value_is_not_a_pointer, "Return value can not be a pointer, since we can not put them in shared memory."); - template + template // coverity[autosar_cpp14_a11_3_1_violation] friend class SkeletonField; diff --git a/score/mw/com/impl/proxy_event.h b/score/mw/com/impl/proxy_event.h index 27263c788..3ebcdae85 100644 --- a/score/mw/com/impl/proxy_event.h +++ b/score/mw/com/impl/proxy_event.h @@ -40,7 +40,7 @@ namespace score::mw::com::impl // False Positive: this is a normal forward declaration. // Which is used to avoid cyclic dependency with proxy_field.h // coverity[autosar_cpp14_m3_2_3_violation] -template +template class ProxyField; /// \brief This is the user-visible class of an event that is part of a proxy. It contains ProxyEvent functionality that @@ -59,10 +59,10 @@ class ProxyEvent final : public ProxyEventBase // coverity[autosar_cpp14_a11_3_1_violation] friend class ProxyEventView; - // Design decission: ProxyField uses composition pattern to reuse code from ProxyEvent. These two classes also have - // shared private APIs which necessitates the use of the friend keyword. + // ProxyField uses composition pattern to reuse code from ProxyEvent and needs access to + // FieldOnlyConstructorEnabler. // coverity[autosar_cpp14_a11_3_1_violation] - template + template friend class ProxyField; // Empty struct that is used to make the second constructor only accessible to ProxyField (as it is a friend). diff --git a/score/mw/com/impl/proxy_field.h b/score/mw/com/impl/proxy_field.h index 5e6894aba..e71e14e2d 100644 --- a/score/mw/com/impl/proxy_field.h +++ b/score/mw/com/impl/proxy_field.h @@ -13,9 +13,11 @@ #ifndef SCORE_MW_COM_IMPL_PROXY_FIELD_H #define SCORE_MW_COM_IMPL_PROXY_FIELD_H +#include "score/mw/com/impl/field_tags.h" #include "score/mw/com/impl/methods/proxy_method_with_in_args_and_return.h" #include "score/mw/com/impl/methods/proxy_method_with_return_type.h" #include "score/mw/com/impl/plumbing/proxy_field_binding_factory.h" +#include "score/mw/com/impl/plumbing/sample_ptr.h" #include "score/mw/com/impl/proxy_event.h" #include "score/mw/com/impl/proxy_event_binding.h" #include "score/mw/com/impl/proxy_field_base.h" @@ -45,14 +47,9 @@ class ProxyFieldAttorney; /// ProxyEvent. /// /// \tparam SampleDataType Type of data that is transferred by the event. -/// \tparam EnableGet Whether the get method shall be enabled for this field. If true, a Get() method will be available. -/// \tparam EnableSet Whether the set method shall be enabled for this field. If true, a Set() method will be available. -/// \tparam EnableNotifier Whether the notifier functionality shall be enabled for this field. Whether this has an -/// effect, depends on the binding that is used. The LoLa/shm-binding ignores this template parameter. -template +/// \tparam Tags Optional tag pack; presence of WithGetter / WithSetter enables Get() / Set() respectively. +/// The notifier surface (Subscribe, GetNewSamples, ...) is part of every field. +template class ProxyField final : public ProxyFieldBase { // Suppress "AUTOSAR C++14 A11-3-1", The rule declares: "Friend declarations shall not be used". @@ -64,16 +61,13 @@ class ProxyField final : public ProxyFieldBase public: using FieldType = SampleDataType; - /// Constructor that allows to set the binding directly (both EnableGet and EnableSet are true). - /// - /// This is used for testing only. Allows for directly setting the bindings, and usually the mock binding is used - /// here. + /// Testing ctor: bindings are passed in directly (used with mock bindings). + /// Method bindings default to nullptr; passing nullptr means the corresponding ProxyMethod is not built. ProxyField(ProxyBase& proxy_base, const std::string_view field_name, std::unique_ptr> event_binding, std::unique_ptr get_method_binding = nullptr, - std::unique_ptr set_method_binding = nullptr, - detail::EnableBothTag = {}) + std::unique_ptr set_method_binding = nullptr) : ProxyField{ proxy_base, field_name, @@ -96,10 +90,11 @@ class ProxyField final : public ProxyFieldBase { } - /// \brief Constructs a ProxyField (both EnableGet and EnableSet are true). Normal ctor that is used in production - /// code. - template > - ProxyField(ProxyBase& proxy_base, const std::string_view field_name, detail::EnableBothTag = {}) + /// \brief Normal ctor selected when the tag pack contains both WithGetter and WithSetter. + template ::value && + detail::is_tag_enabled::value>> + ProxyField(ProxyBase& proxy_base, const std::string_view field_name, WithGetter = {}, WithSetter = {}) : ProxyField{proxy_base, field_name, std::make_unique>( @@ -120,9 +115,11 @@ class ProxyField final : public ProxyFieldBase { } - /// \brief Constructs a ProxyField (only EnableGet is true). Normal ctor that is used in production code. - template > - ProxyField(ProxyBase& proxy_base, const std::string_view field_name, detail::EnableGetOnlyTag = {}) + /// \brief Normal ctor selected when the tag pack contains WithGetter but not WithSetter. + template ::value && + !detail::is_tag_enabled::value>> + ProxyField(ProxyBase& proxy_base, const std::string_view field_name, WithGetter = {}) : ProxyField{proxy_base, field_name, std::make_unique>( @@ -139,9 +136,11 @@ class ProxyField final : public ProxyFieldBase { } - /// \brief Constructs a ProxyField (only EnableSet is true). Normal ctor that is used in production code. - template > - ProxyField(ProxyBase& proxy_base, const std::string_view field_name, detail::EnableSetOnlyTag = {}) + /// \brief Normal ctor selected when the tag pack contains WithSetter but not WithGetter. + template ::value && + detail::is_tag_enabled::value>> + ProxyField(ProxyBase& proxy_base, const std::string_view field_name, WithSetter = {}) : ProxyField{proxy_base, field_name, std::make_unique>( @@ -158,10 +157,11 @@ class ProxyField final : public ProxyFieldBase { } - /// \brief Constructs a ProxyField (both EnableGet and EnableSet are false). Normal ctor that is used in production - /// code. - template > - ProxyField(ProxyBase& proxy_base, const std::string_view field_name, detail::EnableNeitherTag = {}) + /// \brief Normal ctor selected when the tag pack contains neither WithGetter nor WithSetter. + template ::value && + !detail::is_tag_enabled::value>> + ProxyField(ProxyBase& proxy_base, const std::string_view field_name) : ProxyField{proxy_base, field_name, std::make_unique>( @@ -204,14 +204,14 @@ class ProxyField final : public ProxyFieldBase } template ::value>> + typename = std::enable_if_t::value>> score::Result> Get() noexcept { return proxy_method_get_dispatch_->operator()(); } template ::value>> + typename = std::enable_if_t::value>> score::Result> Set(SampleDataType& new_field_value) noexcept { return proxy_method_set_dispatch_->operator()(new_field_value); @@ -249,8 +249,8 @@ class ProxyField final : public ProxyFieldBase "we must ensure that it doesn't move when the ProxyField is moved to avoid dangling references. "); }; -template -ProxyField::ProxyField(ProxyField&& other) noexcept +template +ProxyField::ProxyField(ProxyField&& other) noexcept : ProxyFieldBase(std::move(static_cast(other))), proxy_event_dispatch_(std::move(other.proxy_event_dispatch_)), proxy_method_get_dispatch_(std::move(other.proxy_method_get_dispatch_)), @@ -260,14 +260,14 @@ ProxyField::ProxyField(ProxyFie proxy_base_view.UpdateField(field_name_, *this); } -template +template // Suppress "AUTOSAR C++14 A6-2-1" rule violation. The rule states "Move and copy assignment operators shall either move // or respectively copy base classes and data members of a class, without any side effects." // Rationale: The parent proxy stores a reference to the ProxyEvent. The address that is pointed to must be // updated when the ProxyField is moved. Therefore, side effects are required. // coverity[autosar_cpp14_a6_2_1_violation] -auto ProxyField::operator=(ProxyField&& other) & noexcept - -> ProxyField& +auto ProxyField::operator=(ProxyField&& other) & noexcept + -> ProxyField& { if (this != &other) { diff --git a/score/mw/com/impl/skeleton_event.h b/score/mw/com/impl/skeleton_event.h index ac50d016a..27c341639 100644 --- a/score/mw/com/impl/skeleton_event.h +++ b/score/mw/com/impl/skeleton_event.h @@ -36,7 +36,7 @@ namespace score::mw::com::impl // False Positive: this is a normal forward declaration. // coverity[autosar_cpp14_m3_2_3_violation] -template +template class SkeletonField; template @@ -51,7 +51,7 @@ class SkeletonEvent : public SkeletonEventBase // SkeletonField uses composition pattern to reuse code from SkeletonEvent. These two classes also have shared // private APIs which necessitates the use of the friend keyword. // coverity[autosar_cpp14_a11_3_1_violation] - template + template friend class SkeletonField; // Empty struct that is used to make the second constructor only accessible to SkeletonEvent and SkeletonField (as diff --git a/score/mw/com/impl/skeleton_field.h b/score/mw/com/impl/skeleton_field.h index 228ab650d..fe39e42aa 100644 --- a/score/mw/com/impl/skeleton_field.h +++ b/score/mw/com/impl/skeleton_field.h @@ -13,6 +13,7 @@ #ifndef SCORE_MW_COM_IMPL_SKELETON_FIELD_H #define SCORE_MW_COM_IMPL_SKELETON_FIELD_H +#include "score/mw/com/impl/field_tags.h" #include "score/mw/com/impl/method_type.h" #include "score/mw/com/impl/methods/skeleton_method.h" #include "score/mw/com/impl/plumbing/sample_allocatee_ptr.h" @@ -26,6 +27,7 @@ #include "score/result/result.h" #include +#include #include #include @@ -35,37 +37,37 @@ namespace score::mw::com::impl { -template +template class SkeletonField : public SkeletonFieldBase { public: using FieldType = SampleDataType; - /// \brief Constructs a SkeletonField with setter enabled. Normal ctor used in production code. - /// - /// \param parent Skeleton that contains this field. - /// \param field_name Field name of the field. - /// \param detail::EnableSetOnlyTag This parameter is only used for constructor overload disambiguation and - /// has no semantic meaning. The tag disambiguates the setter-enabled ctor from the no-setter ctor, as - /// otherwise both would have the same signature. - template > - SkeletonField(SkeletonBase& parent, const std::string_view field_name, detail::EnableSetOnlyTag = {}); - - /// \brief Constructs a SkeletonField with no setter. Normal ctor used in production code. - /// - /// \param parent Skeleton that contains this field. - /// \param field_name Field name of the field. - /// \param detail::EnableNeitherTag This parameter is only used for constructor overload disambiguation and - /// has no semantic meaning. - template > - SkeletonField(SkeletonBase& parent, const std::string_view field_name, detail::EnableNeitherTag = {}); - - /// Constructor that allows to set the binding directly. - /// - /// This is used only used for testing. + /// Normal ctor, setter enabled. + template ::value>> + SkeletonField(SkeletonBase& parent, const std::string_view field_name, WithSetter = {}) + : SkeletonField{parent, MakeSkeletonEvent(parent, field_name), field_name, WithSetter{}} + { + } + + /// Normal ctor, setter not enabled. + template ::value>> + SkeletonField(SkeletonBase& parent, const std::string_view field_name) + : SkeletonField{parent, MakeSkeletonEvent(parent, field_name), field_name} + { + } + + /// Testing ctor: binding is passed in directly (used with mock bindings). SkeletonField(SkeletonBase& skeleton_base, const std::string_view field_name, - std::unique_ptr> binding); + std::unique_ptr> binding) + : SkeletonField{skeleton_base, + std::make_unique>(skeleton_base, field_name, std::move(binding)), + field_name} + { + } ~SkeletonField() override = default; @@ -112,14 +114,12 @@ class SkeletonField : public SkeletonFieldBase skeleton_field_mock_ = &skeleton_field_mock; } - // SFINAE-gated: only exists when EnableSet == true - // - // \ brief Registers a handler that is invoked by the middleware whenever a proxy calls the field setter. - // - // \tparam CallableType Any callable (std::function, score::cpp::callback, lambda, ...) with the signature: - // void(FieldType& new_value) - // - new_value : the value requested by the proxy. - template ::type = 0, typename CallableType> + /// Registers a handler invoked when a proxy issues the field setter. + /// The handler receives the proxy-requested value by reference and may modify it in-place; + /// the (possibly modified) value is then stored as the "latest value" via call to SkeletonField::Update(). + template ::value>> Result RegisterSetHandler(CallableType&& handler) { static_assert(std::is_invocable_v, @@ -159,50 +159,45 @@ class SkeletonField : public SkeletonFieldBase SkeletonEvent* GetTypedEvent() const noexcept; - std::unique_ptr initial_field_value_; - ISkeletonField* skeleton_field_mock_; - - // Zero-cost conditional storage: unique_ptr when EnableSet=true, zero-size tag when false. - using SetMethodSignature = FieldType(FieldType); - using SetMethodType = - std::conditional_t>, detail::EnableSetOnlyTag>; - SetMethodType set_method_; - - // Stores the user-provided set handler. Kept as a member so that the wrapped - // callback can invoke it via this->set_handler_. The concrete storage type is - // score::cpp::callback with the expected signature so that any callable provided - // to RegisterSetHandler is type-erased here. - // Zero-cost when EnableSet=false. - using SetHandlerStorageType = - std::conditional_t, detail::EnableSetOnlyTag>; - SetHandlerStorageType set_handler_{}; - - // Tracks whether RegisterSetHandler() has been called. Zero-cost when EnableSet=false. - using IsSetHandlerRegisteredType = std::conditional_t; - IsSetHandlerRegisteredType is_set_handler_registered_{}; - - // EnableSet=true: checks the flag; EnableSet=false: no setter, no handler required. bool IsSetHandlerRegistered() const noexcept override { - if constexpr (EnableSet) + if constexpr (detail::contains_type::value) { return is_set_handler_registered_; } return true; } + static std::unique_ptr> MakeSkeletonEvent(SkeletonBase& parent, + const std::string_view field_name) + { + return std::make_unique>( + parent, + field_name, + SkeletonFieldBindingFactory::CreateEventBinding( + SkeletonBaseView{parent}.GetAssociatedInstanceIdentifier(), parent, field_name), + typename SkeletonEvent::FieldOnlyConstructorEnabler{}); + } + /// \brief Private delegating constructor used by the setter-enabled public ctor. - template > SkeletonField(SkeletonBase& parent, std::unique_ptr> skeleton_event_dispatch, const std::string_view field_name, - detail::EnableSetOnlyTag); + WithSetter); /// \brief Private delegating constructor used by the no-setter public ctor and testing ctor. SkeletonField(SkeletonBase& parent, std::unique_ptr> skeleton_event_dispatch, const std::string_view field_name); + std::unique_ptr initial_field_value_; + ISkeletonField* skeleton_field_mock_; + + using SetMethodSignature = FieldType(FieldType); + std::unique_ptr> set_method_; + score::cpp::callback set_handler_; + bool is_set_handler_registered_{false}; + // TODO: Move get_method_ initialization into the delegating constructors (like set_method_) once the // Get handler is implemented. using GetMethodSignature = FieldType(); @@ -214,65 +209,11 @@ class SkeletonField : public SkeletonFieldBase typename SkeletonMethod::FieldOnlyConstructorEnabler{})}; }; -/// \brief Public ctor — EnableSet=true: delegates to the private ctor that also creates the set method. -template -template -SkeletonField::SkeletonField(SkeletonBase& parent, - const std::string_view field_name, - detail::EnableSetOnlyTag) - : SkeletonField{ - parent, - std::make_unique>(parent, - field_name, - SkeletonFieldBindingFactory::CreateEventBinding( - SkeletonBaseView{parent}.GetAssociatedInstanceIdentifier(), - parent, - field_name), - typename SkeletonEvent::FieldOnlyConstructorEnabler{}), - field_name, - detail::EnableSetOnlyTag{}} -{ -} - -/// \brief Public ctor — EnableSet=false: delegates to the private ctor with no set method. -template -template -SkeletonField::SkeletonField(SkeletonBase& parent, - const std::string_view field_name, - detail::EnableNeitherTag) - : SkeletonField{ - parent, - std::make_unique>(parent, - field_name, - SkeletonFieldBindingFactory::CreateEventBinding( - SkeletonBaseView{parent}.GetAssociatedInstanceIdentifier(), - parent, - field_name), - typename SkeletonEvent::FieldOnlyConstructorEnabler{}), - field_name} -{ -} - -/// \brief Testing ctor: binding is provided directly (used with mock bindings in tests). -template -SkeletonField::SkeletonField( - SkeletonBase& skeleton_base, - const std::string_view field_name, - std::unique_ptr> binding) - : SkeletonField{skeleton_base, - std::make_unique>(skeleton_base, field_name, std::move(binding)), - field_name} -{ -} - -/// \brief Private delegating ctor — setter enabled. -template -template -SkeletonField::SkeletonField( - SkeletonBase& parent, - std::unique_ptr> skeleton_event_dispatch, - const std::string_view field_name, - detail::EnableSetOnlyTag) +template +SkeletonField::SkeletonField(SkeletonBase& parent, + std::unique_ptr> skeleton_event_dispatch, + const std::string_view field_name, + WithSetter) : SkeletonFieldBase{parent, field_name, std::move(skeleton_event_dispatch)}, initial_field_value_{nullptr}, skeleton_field_mock_{nullptr} @@ -286,12 +227,10 @@ SkeletonField::SkeletonField( skeleton_base_view.RegisterField(field_name, *this); } -/// \brief Private delegating ctor — no setter. Receives the already-constructed event. -template -SkeletonField::SkeletonField( - SkeletonBase& parent, - std::unique_ptr> skeleton_event_dispatch, - const std::string_view field_name) +template +SkeletonField::SkeletonField(SkeletonBase& parent, + std::unique_ptr> skeleton_event_dispatch, + const std::string_view field_name) : SkeletonFieldBase{parent, field_name, std::move(skeleton_event_dispatch)}, initial_field_value_{nullptr}, skeleton_field_mock_{nullptr} @@ -300,8 +239,8 @@ SkeletonField::SkeletonField( skeleton_base_view.RegisterField(field_name, *this); } -template -SkeletonField::SkeletonField(SkeletonField&& other) noexcept +template +SkeletonField::SkeletonField(SkeletonField&& other) noexcept : SkeletonFieldBase(static_cast(other)), // known llvm bug (https://github.com/llvm/llvm-project/issues/63202) // This usage is safe because the previous line only moves the base class portion via static_cast. @@ -319,9 +258,9 @@ SkeletonField::SkeletonField(Skeleton skeleton_base_view.UpdateField(field_name_, *this); } -template -auto SkeletonField::operator=(SkeletonField&& other) & noexcept - -> SkeletonField& +template +auto SkeletonField::operator=(SkeletonField&& other) & noexcept + -> SkeletonField& { if (this != &other) { @@ -346,8 +285,8 @@ auto SkeletonField::operator=(Skeleto /// field cannot be set until the Skeleton has been set up via Skeleton::OfferService(). Therefore, we create a /// callback that will update the field value with sample_value which will be called in the first call to /// SkeletonFieldBase::PrepareOffer(). -template -Result SkeletonField::Update(const FieldType& sample_value) noexcept +template +Result SkeletonField::Update(const FieldType& sample_value) noexcept { if (skeleton_field_mock_ != nullptr) { @@ -364,9 +303,8 @@ Result SkeletonField::Update(co /// \brief FieldType is previously allocated by middleware and provided by the user to indicate that he is finished /// filling the provided pointer with live data. Dispatches to SkeletonEvent::Send() -template -Result SkeletonField::Update( - SampleAllocateePtr sample) noexcept +template +Result SkeletonField::Update(SampleAllocateePtr sample) noexcept { if (skeleton_field_mock_ != nullptr) { @@ -381,8 +319,8 @@ Result SkeletonField::Update( /// /// This function cannot be currently called to set the initial value of a field as the shared memory must be first /// set up in the Skeleton::PrepareOffer() before the user can obtain / use a SampleAllocateePtr. -template -Result> SkeletonField::Allocate() noexcept +template +Result> SkeletonField::Allocate() noexcept { if (skeleton_field_mock_ != nullptr) { @@ -400,12 +338,12 @@ Result> SkeletonFieldAllocate(); } -template +template // Suppress "AUTOSAR C++14 A0-1-3" rule finding. This rule states: "Every function defined in an anonymous // namespace, or static function with internal linkage, or private member function shall be used.". // False-positive, method is used in the base class in PrepareOffer(). // coverity[autosar_cpp14_a0_1_3_violation : FALSE] -Result SkeletonField::DoDeferredUpdate() noexcept +Result SkeletonField::DoDeferredUpdate() noexcept { SCORE_LANGUAGE_FUTURECPP_ASSERT_MESSAGE( initial_field_value_ != nullptr, @@ -421,16 +359,14 @@ Result SkeletonField::DoDeferre return Result{}; } -template -Result SkeletonField::UpdateImpl( - const FieldType& sample_value) noexcept +template +Result SkeletonField::UpdateImpl(const FieldType& sample_value) noexcept { return GetTypedEvent()->Send(sample_value); } -template -auto SkeletonField::GetTypedEvent() const noexcept - -> SkeletonEvent* +template +auto SkeletonField::GetTypedEvent() const noexcept -> SkeletonEvent* { auto* const typed_event = dynamic_cast*>(skeleton_event_dispatch_.get()); SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(typed_event != nullptr, "Downcast to SkeletonEvent failed!"); diff --git a/score/mw/com/impl/skeleton_field_test.cpp b/score/mw/com/impl/skeleton_field_test.cpp index 1967b65c0..bc4f4513f 100644 --- a/score/mw/com/impl/skeleton_field_test.cpp +++ b/score/mw/com/impl/skeleton_field_test.cpp @@ -959,35 +959,32 @@ TEST(SkeletonFieldDeathTest, UpdateWithInvalidFieldNameTriggersTermination) EXPECT_DEATH(SkeletonBaseView{unit}.UpdateField("non_existing_test_field_name", field);, ".*"); } -// Helper skeleton that holds an EnableSet=true field (setter-capable field) +// Helper skeleton that holds a setter-capable field (tagged WithSetter). class MySetterSkeleton : public SkeletonBase { public: using SkeletonBase::SkeletonBase; - SkeletonField my_setter_field_{*this, kFieldName}; + SkeletonField my_setter_field_{*this, kFieldName}; }; // Static type-trait tests for RegisterSetHandler availability -TEST(SkeletonFieldSetHandlerTest, RegisterSetHandlerOnlyExistsWhenEnableSetIsTrue) +TEST(SkeletonFieldSetHandlerTest, RegisterSetHandlerOnlyExistsWhenWithSetterTagPresent) { RecordProperty("Description", - "RegisterSetHandler() shall only exist on SkeletonField. " - "Verify via has_member detection that it is absent when EnableSet=false."); + "RegisterSetHandler() shall only exist on SkeletonField tagged WithSetter. " + "Verify that the tag distinguishes the two types."); RecordProperty("TestType", "Requirements-based test"); RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - // RegisterSetHandler should be callable on EnableSet=true - static_assert(std::is_same_v::FieldType, TestSampleType>, + static_assert(std::is_same_v::FieldType, TestSampleType>, "Setter-capable field must expose FieldType"); - // EnableSet=false field must not expose SetHandlerType at the member function level. We verify - // indirectly that the EnableSet template parameter distinguishes the types. - static_assert(!std::is_same_v, SkeletonField>, - "EnableSet=false and EnableSet=true fields must be different types"); + static_assert(!std::is_same_v, SkeletonField>, + "Tagged and untagged fields must be different types"); } // RegisterSetHandler – happy-path: handler forwarded to method binding diff --git a/score/mw/com/impl/traits.h b/score/mw/com/impl/traits.h index 1c51a0587..00111fcba 100644 --- a/score/mw/com/impl/traits.h +++ b/score/mw/com/impl/traits.h @@ -14,6 +14,7 @@ #define SCORE_MW_COM_IMPL_TRAITS_H #include "score/mw/com/impl/com_error.h" +#include "score/mw/com/impl/field_tags.h" #include "score/mw/com/impl/flag_owner.h" #include "score/mw/com/impl/handle_type.h" #include "score/mw/com/impl/instance_identifier.h" @@ -100,18 +101,16 @@ class ProxyWrapperClassTestView; /// typename Trait::template Event struct_event_1_{*this, event_name_0}; /// typename Trait::template Event struct_event_2_{*this, event_name_1}; /// -/// typename Trait::template Field struct_field_1_{*this, -/// field_name_0}; -/// typename Trait::template Field -/// struct_field_2_{*this, field_name_1}; +/// typename Trait::template Field struct_field_1_{*this, field_name_0}; +/// typename Trait::template Field struct_field_2_{*this, field_name_1}; /// /// typename Trait::template Method struct_method_1_{*this, method_name_0}; /// typename Trait::template Method struct_method_2_{*this, method_name_1}; /// /// }; -/// Notes regarding template args: A field has (besides its data type arg) three bool template args (enable_getter, -/// enable_setter and enable_notifier). The enable_notifier template parameter is only relevant for certain bindings, -/// e.g. the LoLa binding does not distinguish between true/false of this template parameter. +/// Notes regarding template args: a field takes its data type plus an optional pack of tags. Presence of WithGetter +/// or WithSetter enables Get() / Set() respectively on the field. The notifier surface (Subscribe/GetNewSamples on +/// the proxy side, Update/Allocate on the skeleton side) is part of every field and is not controlled by a tag. /// A method has a template arg describing the method signature in the form ReturnType(InArgType1, InArgType2, ...). /// InArgs and ReturnType are optional. Therefore, these are valid signatures: /// - void() @@ -139,10 +138,8 @@ class ProxyTrait template using Event = ProxyEvent; - // Note : at the moment the SkeletonField::Get implementation is not in the branch which means the skeleton and - // proxy side does not have same template parameters. - template - using Field = ProxyField; + template + using Field = ProxyField; template using Method = ProxyMethod; @@ -164,8 +161,8 @@ class SkeletonTrait template using Event = SkeletonEvent; - template - using Field = SkeletonField; + template + using Field = SkeletonField; template using Method = SkeletonMethod; From c45d01a05849fdc37b583f57cb80134ef14a56fa Mon Sep 17 00:00:00 2001 From: Krishna Date: Tue, 28 Apr 2026 10:42:13 +0200 Subject: [PATCH 04/10] mw/com: add WithNotifier field tag and enforce observable conditions * Introducing a WithNotifier field tag * When both getter and notification mechanism is turned off there is no way for the consumer to observe the field values. making this configuration a compile time failure. --- score/mw/com/impl/field_tags.h | 7 +++- .../impl/mocking/proxy_event_mock_test.cpp | 2 +- .../proxy_wrapper_class_test_view_test.cpp | 4 +- .../impl/mocking/skeleton_field_mock_test.cpp | 2 +- score/mw/com/impl/proxy_event_base_test.cpp | 2 +- score/mw/com/impl/proxy_event_test.cpp | 2 +- score/mw/com/impl/proxy_field.h | 10 ++++- score/mw/com/impl/proxy_field_test.cpp | 29 ++++++++++---- score/mw/com/impl/skeleton_base_test.cpp | 2 +- score/mw/com/impl/skeleton_field_test.cpp | 38 +++++++++++++------ score/mw/com/impl/test/proxy_resources.h | 12 +++--- .../tracing/test/proxy_event_tracing_test.cpp | 2 +- .../test/skeleton_field_tracing_test.cpp | 2 +- score/mw/com/impl/traits.h | 12 +++--- score/mw/com/impl/traits_test.cpp | 2 +- .../common_test_resources/test_interface.h | 4 +- .../test/field_initial_value/test_datatype.h | 2 +- .../test/find_any_semantics/test_datatype.h | 2 +- score/mw/com/types.h | 6 +++ 19 files changed, 95 insertions(+), 47 deletions(-) diff --git a/score/mw/com/impl/field_tags.h b/score/mw/com/impl/field_tags.h index 7d468ba8b..52a47cf45 100644 --- a/score/mw/com/impl/field_tags.h +++ b/score/mw/com/impl/field_tags.h @@ -19,7 +19,8 @@ namespace score::mw::com::impl { /// \brief Tag types used on ProxyField/SkeletonField level to accomplish overload-resolution for various signatures, -/// which depend on the availability of Get/Set/Notifier. +/// which depend on the availability of Get/Set/Notifier. A field must enable WithGetter or WithNotifier +/// (a write-only field would be invisible to consumers). struct WithGetter { }; @@ -28,6 +29,10 @@ struct WithSetter { }; +struct WithNotifier +{ +}; + namespace detail { diff --git a/score/mw/com/impl/mocking/proxy_event_mock_test.cpp b/score/mw/com/impl/mocking/proxy_event_mock_test.cpp index 6bee8e59f..9c2361cb4 100644 --- a/score/mw/com/impl/mocking/proxy_event_mock_test.cpp +++ b/score/mw/com/impl/mocking/proxy_event_mock_test.cpp @@ -64,7 +64,7 @@ struct ProxyEventStruct struct ProxyFieldStruct { - using ProxyEventField = ProxyField; + using ProxyEventField = ProxyField; using ProxyEventFieldMock = ProxyEventMock; }; diff --git a/score/mw/com/impl/mocking/proxy_wrapper_class_test_view_test.cpp b/score/mw/com/impl/mocking/proxy_wrapper_class_test_view_test.cpp index 674527449..5d1f64587 100644 --- a/score/mw/com/impl/mocking/proxy_wrapper_class_test_view_test.cpp +++ b/score/mw/com/impl/mocking/proxy_wrapper_class_test_view_test.cpp @@ -54,7 +54,7 @@ class MyInterface : public InterfaceTrait::Base typename InterfaceTrait::template Event some_event{*this, kEventName}; typename InterfaceTrait::template Event some_event_2{*this, kEventName2}; - typename InterfaceTrait::template Field some_field{*this, kFieldName}; + typename InterfaceTrait::template Field some_field{*this, kFieldName}; }; using MyProxy = AsProxy; @@ -230,7 +230,7 @@ class FieldOnlyInterface : public InterfaceTrait::Base public: using InterfaceTrait::Base::Base; - typename InterfaceTrait::template Field some_field{*this, kFieldName}; + typename InterfaceTrait::template Field some_field{*this, kFieldName}; }; using FieldOnlyProxy = AsProxy; diff --git a/score/mw/com/impl/mocking/skeleton_field_mock_test.cpp b/score/mw/com/impl/mocking/skeleton_field_mock_test.cpp index a3bf86536..a1e7081b7 100644 --- a/score/mw/com/impl/mocking/skeleton_field_mock_test.cpp +++ b/score/mw/com/impl/mocking/skeleton_field_mock_test.cpp @@ -41,7 +41,7 @@ class SkeletonFieldMockFixture : public ::testing::Test SkeletonFieldMock skeleton_field_mock_{}; SkeletonBase skeleton_base_{nullptr, MakeFakeInstanceIdentifier(1U)}; - SkeletonField unit_{skeleton_base_, kDummyFieldName, nullptr}; + SkeletonField unit_{skeleton_base_, kDummyFieldName, nullptr}; }; TEST_F(SkeletonFieldMockFixture, AllocateDispatchesToMockAfterInjectingMock) diff --git a/score/mw/com/impl/proxy_event_base_test.cpp b/score/mw/com/impl/proxy_event_base_test.cpp index 47a18a00c..40b16f1a1 100644 --- a/score/mw/com/impl/proxy_event_base_test.cpp +++ b/score/mw/com/impl/proxy_event_base_test.cpp @@ -99,7 +99,7 @@ struct GenericProxyEventStruct struct ProxyFieldStruct { - using ServiceElementType = ProxyField; + using ServiceElementType = ProxyField; using MockServiceElementType = mock_binding::ProxyEvent; }; diff --git a/score/mw/com/impl/proxy_event_test.cpp b/score/mw/com/impl/proxy_event_test.cpp index 2d90c7f3a..7e3524858 100644 --- a/score/mw/com/impl/proxy_event_test.cpp +++ b/score/mw/com/impl/proxy_event_test.cpp @@ -83,7 +83,7 @@ struct GenericProxyEventStruct struct ProxyFieldStruct { using SampleType = TestSampleType; - using ProxyEventType = ProxyField; + using ProxyEventType = ProxyField; using MockProxyEventType = StrictMock>; }; diff --git a/score/mw/com/impl/proxy_field.h b/score/mw/com/impl/proxy_field.h index e71e14e2d..d5c782288 100644 --- a/score/mw/com/impl/proxy_field.h +++ b/score/mw/com/impl/proxy_field.h @@ -40,7 +40,7 @@ namespace score::mw::com::impl // Suppress "AUTOSAR C++14 M3-2-3" rule finding. This rule states: "An identifier with external linkage shall have // exactly one definition". This a forward class declaration. // coverity[autosar_cpp14_m3_2_3_violation] -template +template class ProxyFieldAttorney; /// \brief This is the user-visible class of a field that is part of a proxy. It delegates all functionality to @@ -52,11 +52,17 @@ class ProxyFieldAttorney; template class ProxyField final : public ProxyFieldBase { + + static_assert( + detail::contains_type::value || detail::contains_type::value, + "A field must either have WithGetter or WithNotifier enabled otherwise, there is no way for the consumer to " + "receive the field values."); + // Suppress "AUTOSAR C++14 A11-3-1", The rule declares: "Friend declarations shall not be used". // Design decision: The "*Attorney" class is a helper, which sets the internal state of this class accessing // private members and used for testing purposes only. // coverity[autosar_cpp14_a11_3_1_violation] - friend class ProxyFieldAttorney; + friend class ProxyFieldAttorney; public: using FieldType = SampleDataType; diff --git a/score/mw/com/impl/proxy_field_test.cpp b/score/mw/com/impl/proxy_field_test.cpp index e637d19fd..51f8430e8 100644 --- a/score/mw/com/impl/proxy_field_test.cpp +++ b/score/mw/com/impl/proxy_field_test.cpp @@ -45,14 +45,18 @@ TEST(ProxyFieldTest, NotCopyable) RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - static_assert(!std::is_copy_constructible>::value, "Is wrongly copyable"); - static_assert(!std::is_copy_assignable>::value, "Is wrongly copyable"); + static_assert(!std::is_copy_constructible>::value, + "Is wrongly copyable"); + static_assert(!std::is_copy_assignable>::value, + "Is wrongly copyable"); } TEST(ProxyFieldTest, IsMoveable) { - static_assert(std::is_move_constructible>::value, "Is not move constructible"); - static_assert(std::is_move_assignable>::value, "Is not move assignable"); + static_assert(std::is_move_constructible>::value, + "Is not move constructible"); + static_assert(std::is_move_assignable>::value, + "Is not move assignable"); } TEST(ProxyFieldTest, ClassTypeDependsOnFieldDataType) @@ -63,12 +67,20 @@ TEST(ProxyFieldTest, ClassTypeDependsOnFieldDataType) RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - using FirstProxyFieldType = ProxyField; - using SecondProxyFieldType = ProxyField; + using FirstProxyFieldType = ProxyField; + using SecondProxyFieldType = ProxyField; static_assert(!std::is_same_v, "Class type does not depend on field data type"); } +TEST(ProxyFieldTest, ClassTypeDependsOnFieldTagType) +{ + using FirstProxyFieldType = ProxyField; + using SecondProxyFieldType = ProxyField; + static_assert(!std::is_same_v, + "Class type does not depend on field tag type"); +} + TEST(ProxyFieldTest, ProxyFieldContainsPublicFieldType) { RecordProperty("Verifies", "SCR-17291997"); @@ -79,8 +91,9 @@ TEST(ProxyFieldTest, ProxyFieldContainsPublicFieldType) RecordProperty("DerivationTechnique", "Analysis of requirements"); using CustomFieldType = std::uint16_t; - static_assert(std::is_same::FieldType, CustomFieldType>::value, - "Incorrect FieldType."); + static_assert( + std::is_same::FieldType, CustomFieldType>::value, + "Incorrect FieldType."); } } // namespace diff --git a/score/mw/com/impl/skeleton_base_test.cpp b/score/mw/com/impl/skeleton_base_test.cpp index 5f2138b2b..efbefbbf9 100644 --- a/score/mw/com/impl/skeleton_base_test.cpp +++ b/score/mw/com/impl/skeleton_base_test.cpp @@ -63,7 +63,7 @@ class MyDummySkeleton final : public SkeletonBase SkeletonEvent dummy_event{*this, kDummyEventName}; SkeletonEvent dummy_event2{*this, kDummyEventName2}; - SkeletonField dummy_field{*this, kDummyFieldName}; + SkeletonField dummy_field{*this, kDummyFieldName}; }; mock_binding::Skeleton* GetMockBinding(MyDummySkeleton& skeleton) noexcept diff --git a/score/mw/com/impl/skeleton_field_test.cpp b/score/mw/com/impl/skeleton_field_test.cpp index bc4f4513f..7058a6daf 100644 --- a/score/mw/com/impl/skeleton_field_test.cpp +++ b/score/mw/com/impl/skeleton_field_test.cpp @@ -65,7 +65,7 @@ class MyDummySkeleton : public SkeletonBase public: using SkeletonBase::SkeletonBase; - SkeletonField my_dummy_field_{*this, kFieldName}; + SkeletonField my_dummy_field_{*this, kFieldName}; }; TEST(SkeletonFieldTest, NotCopyable) @@ -76,14 +76,18 @@ TEST(SkeletonFieldTest, NotCopyable) RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - static_assert(!std::is_copy_constructible>::value, "Is wrongly copyable"); - static_assert(!std::is_copy_assignable>::value, "Is wrongly copyable"); + static_assert(!std::is_copy_constructible>::value, + "Is wrongly copyable"); + static_assert(!std::is_copy_assignable>::value, + "Is wrongly copyable"); } TEST(SkeletonFieldTest, IsMoveable) { - static_assert(std::is_move_constructible>::value, "Is not move constructible"); - static_assert(std::is_move_assignable>::value, "Is not move assignable"); + static_assert(std::is_move_constructible>::value, + "Is not move constructible"); + static_assert(std::is_move_assignable>::value, + "Is not move assignable"); } TEST(SkeletonFieldTest, ClassTypeDependsOnFieldDataType) @@ -94,12 +98,20 @@ TEST(SkeletonFieldTest, ClassTypeDependsOnFieldDataType) RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - using FirstSkeletonFieldType = SkeletonField; - using SecondSkeletonFieldType = SkeletonField; + using FirstSkeletonFieldType = SkeletonField; + using SecondSkeletonFieldType = SkeletonField; static_assert(!std::is_same_v, "Class type does not depend on field data type"); } +TEST(SkeletonFieldTest, ClassTypeDependsOnFieldTagType) +{ + using FirstSkeletonFieldType = SkeletonField; + using SecondSkeletonFieldType = SkeletonField; + static_assert(!std::is_same_v, + "Class type does not depend on field tag type"); +} + TEST(SkeletonFieldTest, SkeletonFieldContainsPublicSampleType) { RecordProperty("Verifies", "SCR-17433130"); @@ -109,7 +121,8 @@ TEST(SkeletonFieldTest, SkeletonFieldContainsPublicSampleType) RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - static_assert(std::is_same::FieldType, TestSampleType>::value, + static_assert(std::is_same::FieldType, + TestSampleType>::value, "Incorrect FieldType."); } @@ -966,7 +979,7 @@ class MySetterSkeleton : public SkeletonBase public: using SkeletonBase::SkeletonBase; - SkeletonField my_setter_field_{*this, kFieldName}; + SkeletonField my_setter_field_{*this, kFieldName}; }; // Static type-trait tests for RegisterSetHandler availability @@ -980,11 +993,12 @@ TEST(SkeletonFieldSetHandlerTest, RegisterSetHandlerOnlyExistsWhenWithSetterTagP RecordProperty("Priority", "1"); RecordProperty("DerivationTechnique", "Analysis of requirements"); - static_assert(std::is_same_v::FieldType, TestSampleType>, + static_assert(std::is_same_v::FieldType, TestSampleType>, "Setter-capable field must expose FieldType"); - static_assert(!std::is_same_v, SkeletonField>, - "Tagged and untagged fields must be different types"); + static_assert(!std::is_same_v, + SkeletonField>, + "Distinct tag packs must produce distinct types"); } // RegisterSetHandler – happy-path: handler forwarded to method binding diff --git a/score/mw/com/impl/test/proxy_resources.h b/score/mw/com/impl/test/proxy_resources.h index f33ff549d..fe75c5110 100644 --- a/score/mw/com/impl/test/proxy_resources.h +++ b/score/mw/com/impl/test/proxy_resources.h @@ -24,11 +24,11 @@ namespace score::mw::com::impl { -template +template class ProxyFieldAttorney { public: - ProxyFieldAttorney(ProxyField& proxy_field) noexcept : proxy_field_{proxy_field} {} + ProxyFieldAttorney(ProxyField& proxy_field) noexcept : proxy_field_{proxy_field} {} ProxyEvent& GetProxyEvent() noexcept { @@ -37,7 +37,7 @@ class ProxyFieldAttorney } private: - ProxyField& proxy_field_; + ProxyField& proxy_field_; }; class ProxyEventBaseAttorney @@ -45,9 +45,9 @@ class ProxyEventBaseAttorney public: ProxyEventBaseAttorney(ProxyEventBase& proxy_event_base) noexcept : proxy_event_base_{proxy_event_base} {} - template - ProxyEventBaseAttorney(ProxyField& proxy_field) noexcept - : proxy_event_base_{ProxyFieldAttorney{proxy_field}.GetProxyEvent()} + template + ProxyEventBaseAttorney(ProxyField& proxy_field) noexcept + : proxy_event_base_{ProxyFieldAttorney{proxy_field}.GetProxyEvent()} { } diff --git a/score/mw/com/impl/tracing/test/proxy_event_tracing_test.cpp b/score/mw/com/impl/tracing/test/proxy_event_tracing_test.cpp index 6549d0700..1a098abc6 100644 --- a/score/mw/com/impl/tracing/test/proxy_event_tracing_test.cpp +++ b/score/mw/com/impl/tracing/test/proxy_event_tracing_test.cpp @@ -69,7 +69,7 @@ class MyDummyProxyWithField : public ProxyBase public: using ProxyBase::ProxyBase; - ProxyField my_service_element_{*this, kServiceElementName}; + ProxyField my_service_element_{*this, kServiceElementName}; }; /// \brief Structs containing types for templated gtests. diff --git a/score/mw/com/impl/tracing/test/skeleton_field_tracing_test.cpp b/score/mw/com/impl/tracing/test/skeleton_field_tracing_test.cpp index 0c5afa436..3d0b5fb36 100644 --- a/score/mw/com/impl/tracing/test/skeleton_field_tracing_test.cpp +++ b/score/mw/com/impl/tracing/test/skeleton_field_tracing_test.cpp @@ -73,7 +73,7 @@ class MyDummySkeleton : public SkeletonBase public: using SkeletonBase::SkeletonBase; - SkeletonField my_dummy_field_{*this, kFieldName}; + SkeletonField my_dummy_field_{*this, kFieldName}; }; TEST(SkeletonFieldTracingTest, TracePointsAreDisabledIfConfigNotReturnedByRuntime) diff --git a/score/mw/com/impl/traits.h b/score/mw/com/impl/traits.h index 00111fcba..8bfd35816 100644 --- a/score/mw/com/impl/traits.h +++ b/score/mw/com/impl/traits.h @@ -101,16 +101,18 @@ class ProxyWrapperClassTestView; /// typename Trait::template Event struct_event_1_{*this, event_name_0}; /// typename Trait::template Event struct_event_2_{*this, event_name_1}; /// -/// typename Trait::template Field struct_field_1_{*this, field_name_0}; -/// typename Trait::template Field struct_field_2_{*this, field_name_1}; +/// typename Trait::template Field struct_field_1_{*this, +/// field_name_0}; +/// typename Trait::template Field struct_field_2_{*this, field_name_1}; /// /// typename Trait::template Method struct_method_1_{*this, method_name_0}; /// typename Trait::template Method struct_method_2_{*this, method_name_1}; /// /// }; -/// Notes regarding template args: a field takes its data type plus an optional pack of tags. Presence of WithGetter -/// or WithSetter enables Get() / Set() respectively on the field. The notifier surface (Subscribe/GetNewSamples on -/// the proxy side, Update/Allocate on the skeleton side) is part of every field and is not controlled by a tag. +/// Notes regarding template args: a field takes its data type plus a pack of tags from {WithGetter, WithSetter, +/// WithNotifier}. WithGetter / WithSetter enable Get() / Set() on the proxy. WithNotifier enables the proxy notifier +/// surface (Subscribe, GetNewSamples, ...). At least one of WithGetter or WithNotifier must be present, otherwise the +/// value would be invisible to consumers. The skeleton-side Update/Allocate are part of every field. /// A method has a template arg describing the method signature in the form ReturnType(InArgType1, InArgType2, ...). /// InArgs and ReturnType are optional. Therefore, these are valid signatures: /// - void() diff --git a/score/mw/com/impl/traits_test.cpp b/score/mw/com/impl/traits_test.cpp index 7074a6829..bcb82672a 100644 --- a/score/mw/com/impl/traits_test.cpp +++ b/score/mw/com/impl/traits_test.cpp @@ -67,7 +67,7 @@ class MyInterface : public InterfaceTrait::Base using InterfaceTrait::Base::Base; typename InterfaceTrait::template Event some_event{*this, kEventName}; - typename InterfaceTrait::template Field some_field{*this, kFieldName}; + typename InterfaceTrait::template Field some_field{*this, kFieldName}; typename InterfaceTrait::template Method some_method{*this, kMethodName}; }; using MyProxy = AsProxy; diff --git a/score/mw/com/test/common_test_resources/test_interface.h b/score/mw/com/test/common_test_resources/test_interface.h index 64cf4997e..0f2a63250 100644 --- a/score/mw/com/test/common_test_resources/test_interface.h +++ b/score/mw/com/test/common_test_resources/test_interface.h @@ -14,6 +14,8 @@ #ifndef SCORE_MW_COM_TEST_COMMON_TEST_RESOURCES_TEST_INTERFACE_H #define SCORE_MW_COM_TEST_COMMON_TEST_RESOURCES_TEST_INTERFACE_H +#include "score/mw/com/types.h" + #include #include @@ -26,7 +28,7 @@ class TestInterface : public T::Base public: using T::Base::Base; - typename T::template Field test_field{*this, "test_field"}; + typename T::template Field test_field{*this, "test_field"}; }; } // namespace score::mw::com::test diff --git a/score/mw/com/test/field_initial_value/test_datatype.h b/score/mw/com/test/field_initial_value/test_datatype.h index 3f7348692..174ccff15 100644 --- a/score/mw/com/test/field_initial_value/test_datatype.h +++ b/score/mw/com/test/field_initial_value/test_datatype.h @@ -31,7 +31,7 @@ class TestInterface : public T::Base public: using T::Base::Base; - typename T::template Field test_field{*this, "test_field"}; + typename T::template Field test_field{*this, "test_field"}; }; using TestDataProxy = score::mw::com::AsProxy; diff --git a/score/mw/com/test/find_any_semantics/test_datatype.h b/score/mw/com/test/find_any_semantics/test_datatype.h index b6aa58428..5daddd695 100644 --- a/score/mw/com/test/find_any_semantics/test_datatype.h +++ b/score/mw/com/test/find_any_semantics/test_datatype.h @@ -34,7 +34,7 @@ class TestInterface : public T::Base public: using T::Base::Base; - typename T::template Field test_field{*this, "test_field"}; + typename T::template Field test_field{*this, "test_field"}; }; using TestDataProxy = score::mw::com::AsProxy; diff --git a/score/mw/com/types.h b/score/mw/com/types.h index c29f16ab9..7c9e5bca4 100644 --- a/score/mw/com/types.h +++ b/score/mw/com/types.h @@ -105,6 +105,12 @@ using MethodInArgTypePtr = impl::MethodInArgPtr; /// \requirement SWS_CM_00309 using EventReceiveHandler = impl::EventReceiveHandler; +/// \api +/// \brief Field tag types used in service-interface definitions to enable Get/Set/Notifier on a field. +using WithGetter = impl::WithGetter; +using WithSetter = impl::WithSetter; +using WithNotifier = impl::WithNotifier; + /// \api /// \brief Interpret an interface that follows our traits as proxy (cf. impl/traits.h) template