From 810e72b1a17dc56286066a329d2bb8118bdcdd96 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 5 May 2026 15:10:29 +0200 Subject: [PATCH 1/3] PdmObject: Add macro-free template alternatives to CAF_PDM_Init macros Introduce initPdmObject(), initField(), and initFieldNoDefault() template methods on PdmObject as a macro-free alternative to CAF_PDM_InitObject, CAF_PDM_InitField, and CAF_PDM_InitFieldNoDefault. A new PdmKeyword non-type template parameter type carries the field keyword at compile time, enabling the existing XML keyword validation static_asserts to run without macros. A PdmObjectDerived concept constrains the templates so misuse produces a clear diagnostic. --- Fwk/AppFwk/cafProjectDataModel/cafPdmObject.h | 140 ++++++++++++++++++ .../cafPdmXml/cafPdmXmlStringValidation.h | 35 +++++ 2 files changed, 175 insertions(+) diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmObject.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmObject.h index a60cfad94c3..257deb4353b 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmObject.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmObject.h @@ -48,6 +48,8 @@ class QXmlStreamWriter; #include "cafPdmXmlObjectHandle.h" #include "cafPdmXmlObjectHandleMacros.h" +#include + namespace caf { class PdmFieldHandle; @@ -151,6 +153,14 @@ class PdmObjectCapability; namespace caf { +class PdmObject; + +/// Concept satisfied by any class publicly derived from PdmObject. Used to constrain the +/// macro-free init template methods so misuse produces a clear "constraints not satisfied" +/// diagnostic instead of a deep template error. +template +concept PdmObjectDerived = std::derived_from; + class PdmObject : public PdmObjectHandle, public PdmXmlObjectHandle, public PdmUiObjectHandle { public: @@ -206,6 +216,136 @@ class PdmObject : public PdmObjectHandle, public PdmXmlObjectHandle, public PdmU /// Consider this method private. Please use the CAF_PDM_InitFieldNoDefault() macro instead. void addFieldUiNoDefault( PdmFieldHandle* field, const QString& keyword, PdmUiItemInfo* fieldDescription ); + /// Macro-free alternative to CAF_PDM_InitObject. + /// + /// The DerivedClass template parameter ensures each class gets its own unique + /// static PdmUiItemInfo instance (stored as a function-local static in each + /// template instantiation). All instances of the same DerivedClass share the + /// same static item info, matching the behavior of the macro. + /// + /// Example: + /// @code + /// MyClass::MyClass() + /// { + /// initPdmObject( "UI Name", ":/icon.png", "Tooltip", "WhatsThis" ); + /// } + /// @endcode + template + void initPdmObject( const QString& uiName, + const QString& iconResourceName = {}, + const QString& toolTip = {}, + const QString& whatsThis = {} ) + { + this->isInheritedFromPdmUiObject(); + this->isInheritedFromPdmXmlSerializable(); + this->registerClassKeyword( classKeyword() ); + + static caf::PdmUiItemInfo objectDescription( uiName, iconResourceName, toolTip, whatsThis ); + this->setUiItemInfo( &objectDescription ); + } + + /// Macro-free alternative to CAF_PDM_InitField. + /// + /// The DerivedClass and Keyword template parameters together ensure each + /// (class, field-keyword) pair gets its own unique static PdmUiItemInfo. + /// The Keyword non-type template parameter also enables compile-time + /// validation that the keyword is a valid XML element name. + /// + /// Example: + /// @code + /// MyClass::MyClass() + /// { + /// initField( &m_field, 42, "UI Name" ); + /// } + /// @endcode + template + void initField( PdmField* field, + const FieldDataType& defaultValue, + const QString& uiName, + const QString& iconResourceName = {}, + const QString& toolTip = {}, + const QString& whatsThis = {} ) + { + static_assert( isFirstCharacterValidInXmlKeyword( Keyword.value ), "First character in keyword is invalid" ); + static_assert( !isFirstThreeCharactersXml( Keyword.value ), "Keyword starts with invalid sequence xml" ); + static_assert( isValidXmlKeyword( Keyword.value ), "Detected invalid character in keyword" ); + + // Compile/link-time guard mirroring CAF_PDM_InitField: ensures CAF_PDM_HEADER_INIT and + // CAF_PDM_SOURCE_INIT were added to DerivedClass. Missing HEADER_INIT yields a compile + // error (no such member); missing SOURCE_INIT yields a link error referencing this symbol. + static bool checkingThePresenceOfHeaderAndSourceInitMacros = + DerivedClass::Error_You_forgot_to_add_the_macro_CAF_PDM_XML_HEADER_INIT_and_or_CAF_PDM_XML_SOURCE_INIT_to_your_cpp_file_for_this_class(); + Q_UNUSED( checkingThePresenceOfHeaderAndSourceInitMacros ) + + this->isInheritedFromPdmUiObject(); + this->isInheritedFromPdmXmlSerializable(); + + addXmlCapabilityToField( field ); + addUiCapabilityToField( field ); + configureCapabilities( field ); + registerClassWithField( classKeyword(), field ); + + static caf::PdmUiItemInfo fieldDescription( uiName, iconResourceName, toolTip, whatsThis, Keyword.value ); + addFieldUi( field, QString( Keyword.value ), defaultValue, &fieldDescription ); + } + + /// Overload of initField() for PdmField> that accepts a raw enum value as the default, + /// matching the convenience provided by CAF_PDM_InitField (which dispatches via overload resolution + /// on addFieldUi). Without this overload, callers would have to write + /// `AppEnum{ MyEnum::Value }` for the default. + template + void initField( PdmField>* field, + const EnumType& defaultValue, + const QString& uiName, + const QString& iconResourceName = {}, + const QString& toolTip = {}, + const QString& whatsThis = {} ) + { + initField( field, AppEnum( defaultValue ), uiName, iconResourceName, toolTip, whatsThis ); + } + + /// Macro-free alternative to CAF_PDM_InitFieldNoDefault. + /// + /// Like initField(), but does not assign a default value to the field. + /// See initField() documentation for usage details. + /// + /// Example: + /// @code + /// MyClass::MyClass() + /// { + /// initFieldNoDefault( &m_field, "UI Name" ); + /// } + /// @endcode + template + void initFieldNoDefault( FieldType* field, + const QString& uiName, + const QString& iconResourceName = {}, + const QString& toolTip = {}, + const QString& whatsThis = {} ) + { + static_assert( isFirstCharacterValidInXmlKeyword( Keyword.value ), "First character in keyword is invalid" ); + static_assert( !isFirstThreeCharactersXml( Keyword.value ), "Keyword starts with invalid sequence xml" ); + static_assert( isValidXmlKeyword( Keyword.value ), "Detected invalid character in keyword" ); + + // Compile/link-time guard mirroring CAF_PDM_InitFieldNoDefault: ensures CAF_PDM_HEADER_INIT + // and CAF_PDM_SOURCE_INIT were added to DerivedClass. Missing HEADER_INIT yields a compile + // error (no such member); missing SOURCE_INIT yields a link error referencing this symbol. + static bool checkingThePresenceOfHeaderAndSourceInitMacros = + DerivedClass::Error_You_forgot_to_add_the_macro_CAF_PDM_XML_HEADER_INIT_and_or_CAF_PDM_XML_SOURCE_INIT_to_your_cpp_file_for_this_class(); + Q_UNUSED( checkingThePresenceOfHeaderAndSourceInitMacros ) + + this->isInheritedFromPdmUiObject(); + this->isInheritedFromPdmXmlSerializable(); + + addXmlCapabilityToField( field ); + addUiCapabilityToField( field ); + configureCapabilities( field ); + registerClassWithField( classKeyword(), field ); + + static caf::PdmUiItemInfo fieldDescription( uiName, iconResourceName, toolTip, whatsThis, Keyword.value ); + addFieldUiNoDefault( field, QString( Keyword.value ), &fieldDescription ); + } + protected: PdmObjectHandle* doCopyObject() const override; }; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlStringValidation.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlStringValidation.h index 5be6359c33d..ea9acf5d5a3 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlStringValidation.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlStringValidation.h @@ -1,5 +1,7 @@ #pragma once +#include + constexpr bool isLowerCase( char c ) { return ( c >= 'a' && c <= 'z' ); @@ -49,3 +51,36 @@ constexpr bool isFirstThreeCharactersXml( const char ( &arr )[N] ) { return ( N < 3 ) ? false : arr[0] == 'x' && arr[1] == 'm' && arr[2] == 'l'; } + +namespace caf +{ +/// A structural type suitable for use as a non-type template parameter for PDM keywords. +/// +/// By capturing the keyword as a compile-time template argument, this enables +/// compile-time XML keyword validation via static_assert in template functions, +/// providing a macro-free alternative to CAF_PDM_InitField and +/// CAF_PDM_InitFieldNoDefault. +/// +/// Example usage: +/// @code +/// MyClass::MyClass() +/// { +/// initField( &m_field, 0, "UI Name" ); +/// } +/// @endcode +template +struct PdmKeyword +{ + // N is the size of the string literal including the null terminator. + // For a keyword "MyField", N = 8 (7 characters + null terminator). + char value[N]{}; + + // NOLINTNEXTLINE(google-explicit-constructor): intentionally implicit from string literal + constexpr PdmKeyword( const char ( &str )[N] ) noexcept + { + for ( std::size_t i = 0; i < N; ++i ) + value[i] = str[i]; + } +}; + +} // namespace caf From f4d3c21fad82cf555e673e02bf19ecdc4c3b9387 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 5 May 2026 15:26:25 +0200 Subject: [PATCH 2/3] PdmObject: Add tests and compile-time benchmarks for macro-free init API Add unit tests covering the new initPdmObject/initField/initFieldNoDefault template methods, including the AppEnum raw-enum overload, field keyword registration, UI capability wiring, and object UI name. Add compile-time benchmark translation units that mirror each existing benchmark using the macro-free template API, so the per-TU compile cost of the two APIs can be compared directly. A new bench_heavy_fields pair (50 classes with mixed field types) amplifies the signal beyond run-to-run noise. /bigobj is enabled for MSVC because the heavy template TU exceeds the default COFF section limit. --- .../cafPdm_CompileBench/CMakeLists.txt | 22 +++- .../bench_basic_fields_template.cpp | 60 +++++++++ .../bench_container_fields_template.cpp | 59 +++++++++ .../bench_enum_fields_template.cpp | 49 +++++++ .../bench_filepath_fields_template.cpp | 52 ++++++++ .../bench_heavy_fields.cpp | 120 ++++++++++++++++++ .../bench_heavy_fields_template.cpp | 118 +++++++++++++++++ .../bench_mixed_fields_template.cpp | 68 ++++++++++ .../cafPdmBasicTest.cpp | 87 +++++++++++++ 9 files changed, 633 insertions(+), 2 deletions(-) create mode 100644 Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_basic_fields_template.cpp create mode 100644 Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_container_fields_template.cpp create mode 100644 Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_enum_fields_template.cpp create mode 100644 Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_filepath_fields_template.cpp create mode 100644 Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_heavy_fields.cpp create mode 100644 Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_heavy_fields_template.cpp create mode 100644 Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_mixed_fields_template.cpp diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/CMakeLists.txt index d9709776c8e..eb5c462279d 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/CMakeLists.txt @@ -10,8 +10,18 @@ find_package( qt_standard_project_setup() set(PROJECT_FILES - bench_basic_fields.cpp bench_enum_fields.cpp bench_container_fields.cpp - bench_filepath_fields.cpp bench_mixed_fields.cpp + bench_basic_fields.cpp + bench_enum_fields.cpp + bench_container_fields.cpp + bench_filepath_fields.cpp + bench_mixed_fields.cpp + bench_heavy_fields.cpp + bench_basic_fields_template.cpp + bench_enum_fields_template.cpp + bench_container_fields_template.cpp + bench_filepath_fields_template.cpp + bench_mixed_fields_template.cpp + bench_heavy_fields_template.cpp ) # OBJECT library: compiles each file individually without linking. This isolates @@ -21,6 +31,14 @@ add_library(${PROJECT_NAME} OBJECT ${PROJECT_FILES}) # Disable unity build for this target — each file must compile independently set_target_properties(${PROJECT_NAME} PROPERTIES UNITY_BUILD OFF) +# bench_heavy_fields_template.cpp generates many per-template-instantiation +# sections (one function-local static per (Class, Keyword) pair) and exceeds the +# default COFF section limit. /bigobj raises the limit; impact on compile time +# is negligible. +if(MSVC) + target_compile_options(${PROJECT_NAME} PRIVATE /bigobj) +endif() + target_link_libraries( ${PROJECT_NAME} PRIVATE cafProjectDataModel Qt6::Core Qt6::Widgets ) diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_basic_fields_template.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_basic_fields_template.cpp new file mode 100644 index 00000000000..7cc09cfbcf2 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_basic_fields_template.cpp @@ -0,0 +1,60 @@ +// Compile-time benchmark: same as bench_basic_fields.cpp, but uses the macro-free +// initPdmObject/initField template API. Used to measure the compile-time delta of the +// new API versus the CAF_PDM_InitObject/CAF_PDM_InitField macros. + +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include + +// clang-format off + +#define BENCH_BASIC_OBJECT_T( N ) \ +class BenchBasicObjT##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchBasicObjT##N() \ + { \ + initPdmObject( "BenchBasicObjT" #N ); \ + initField( &m_intA, 0, "Int A" ); \ + initField( &m_intB, 0, "Int B" ); \ + initField( &m_dblA, 0.0, "Double A" ); \ + initField( &m_dblB, 0.0, "Double B" ); \ + initField( &m_boolA, false, "Bool A" ); \ + initField( &m_boolB, false, "Bool B" ); \ + initField( &m_strA, QString(), "String A" ); \ + initField( &m_strB, QString(), "String B" ); \ + } \ + caf::PdmField m_intA; \ + caf::PdmField m_intB; \ + caf::PdmField m_dblA; \ + caf::PdmField m_dblB; \ + caf::PdmField m_boolA; \ + caf::PdmField m_boolB; \ + caf::PdmField m_strA; \ + caf::PdmField m_strB; \ +}; + +BENCH_BASIC_OBJECT_T( 01 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT01, "BenchBasicObjT01" ); +BENCH_BASIC_OBJECT_T( 02 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT02, "BenchBasicObjT02" ); +BENCH_BASIC_OBJECT_T( 03 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT03, "BenchBasicObjT03" ); +BENCH_BASIC_OBJECT_T( 04 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT04, "BenchBasicObjT04" ); +BENCH_BASIC_OBJECT_T( 05 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT05, "BenchBasicObjT05" ); +BENCH_BASIC_OBJECT_T( 06 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT06, "BenchBasicObjT06" ); +BENCH_BASIC_OBJECT_T( 07 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT07, "BenchBasicObjT07" ); +BENCH_BASIC_OBJECT_T( 08 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT08, "BenchBasicObjT08" ); +BENCH_BASIC_OBJECT_T( 09 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT09, "BenchBasicObjT09" ); +BENCH_BASIC_OBJECT_T( 10 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT10, "BenchBasicObjT10" ); +BENCH_BASIC_OBJECT_T( 11 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT11, "BenchBasicObjT11" ); +BENCH_BASIC_OBJECT_T( 12 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT12, "BenchBasicObjT12" ); +BENCH_BASIC_OBJECT_T( 13 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT13, "BenchBasicObjT13" ); +BENCH_BASIC_OBJECT_T( 14 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT14, "BenchBasicObjT14" ); +BENCH_BASIC_OBJECT_T( 15 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT15, "BenchBasicObjT15" ); +BENCH_BASIC_OBJECT_T( 16 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT16, "BenchBasicObjT16" ); +BENCH_BASIC_OBJECT_T( 17 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT17, "BenchBasicObjT17" ); +BENCH_BASIC_OBJECT_T( 18 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT18, "BenchBasicObjT18" ); +BENCH_BASIC_OBJECT_T( 19 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT19, "BenchBasicObjT19" ); +BENCH_BASIC_OBJECT_T( 20 ) CAF_PDM_SOURCE_INIT( BenchBasicObjT20, "BenchBasicObjT20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_container_fields_template.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_container_fields_template.cpp new file mode 100644 index 00000000000..4287d2e03f7 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_container_fields_template.cpp @@ -0,0 +1,59 @@ +// Compile-time benchmark: same as bench_container_fields.cpp, but uses the macro-free +// initPdmObject/initField/initFieldNoDefault template API. + +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include +#include +#include + +// clang-format off + +#define BENCH_CONTAINER_OBJECT_T( N ) \ +class BenchContainerObjT##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchContainerObjT##N() \ + { \ + initPdmObject( "BenchContainerObjT" #N ); \ + initFieldNoDefault( &m_vecDouble, "Vector of doubles" ); \ + initFieldNoDefault( &m_vecInt, "Vector of ints" ); \ + initFieldNoDefault( &m_vecString, "Vector of strings" ); \ + initFieldNoDefault( &m_optDouble, "Optional double" ); \ + initFieldNoDefault( &m_optString, "Optional string" ); \ + initField( &m_pairBoolDbl, std::make_pair( false, 0.0 ), "Pair bool/double" ); \ + initField( &m_pairBoolStr, std::make_pair( false, QString() ), "Pair bool/string" ); \ + } \ + caf::PdmField> m_vecDouble; \ + caf::PdmField> m_vecInt; \ + caf::PdmField> m_vecString; \ + caf::PdmField> m_optDouble; \ + caf::PdmField> m_optString; \ + caf::PdmField> m_pairBoolDbl; \ + caf::PdmField> m_pairBoolStr; \ +}; + +BENCH_CONTAINER_OBJECT_T( 01 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT01, "BenchContainerObjT01" ); +BENCH_CONTAINER_OBJECT_T( 02 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT02, "BenchContainerObjT02" ); +BENCH_CONTAINER_OBJECT_T( 03 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT03, "BenchContainerObjT03" ); +BENCH_CONTAINER_OBJECT_T( 04 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT04, "BenchContainerObjT04" ); +BENCH_CONTAINER_OBJECT_T( 05 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT05, "BenchContainerObjT05" ); +BENCH_CONTAINER_OBJECT_T( 06 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT06, "BenchContainerObjT06" ); +BENCH_CONTAINER_OBJECT_T( 07 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT07, "BenchContainerObjT07" ); +BENCH_CONTAINER_OBJECT_T( 08 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT08, "BenchContainerObjT08" ); +BENCH_CONTAINER_OBJECT_T( 09 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT09, "BenchContainerObjT09" ); +BENCH_CONTAINER_OBJECT_T( 10 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT10, "BenchContainerObjT10" ); +BENCH_CONTAINER_OBJECT_T( 11 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT11, "BenchContainerObjT11" ); +BENCH_CONTAINER_OBJECT_T( 12 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT12, "BenchContainerObjT12" ); +BENCH_CONTAINER_OBJECT_T( 13 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT13, "BenchContainerObjT13" ); +BENCH_CONTAINER_OBJECT_T( 14 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT14, "BenchContainerObjT14" ); +BENCH_CONTAINER_OBJECT_T( 15 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT15, "BenchContainerObjT15" ); +BENCH_CONTAINER_OBJECT_T( 16 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT16, "BenchContainerObjT16" ); +BENCH_CONTAINER_OBJECT_T( 17 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT17, "BenchContainerObjT17" ); +BENCH_CONTAINER_OBJECT_T( 18 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT18, "BenchContainerObjT18" ); +BENCH_CONTAINER_OBJECT_T( 19 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT19, "BenchContainerObjT19" ); +BENCH_CONTAINER_OBJECT_T( 20 ) CAF_PDM_SOURCE_INIT( BenchContainerObjT20, "BenchContainerObjT20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_enum_fields_template.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_enum_fields_template.cpp new file mode 100644 index 00000000000..645b2cda16d --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_enum_fields_template.cpp @@ -0,0 +1,49 @@ +// Compile-time benchmark: same as bench_enum_fields.cpp, but uses the macro-free +// initPdmObject/initField template API (raw-enum overload). + +#include "cafAppEnum.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +// clang-format off + +#define BENCH_ENUM_OBJECT_T( N ) \ +enum class BenchEnumT##N { ValueA, ValueB, ValueC, ValueD }; \ +class BenchEnumObjT##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchEnumObjT##N() \ + { \ + initPdmObject( "BenchEnumObjT" #N ); \ + initField( &m_enumA, BenchEnumT##N::ValueA, "Enum A" ); \ + initField( &m_enumB, BenchEnumT##N::ValueB, "Enum B" ); \ + initField( &m_enumC, BenchEnumT##N::ValueC, "Enum C" ); \ + } \ + caf::PdmField> m_enumA; \ + caf::PdmField> m_enumB; \ + caf::PdmField> m_enumC; \ +}; + +BENCH_ENUM_OBJECT_T( 01 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT01, "BenchEnumObjT01" ); +BENCH_ENUM_OBJECT_T( 02 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT02, "BenchEnumObjT02" ); +BENCH_ENUM_OBJECT_T( 03 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT03, "BenchEnumObjT03" ); +BENCH_ENUM_OBJECT_T( 04 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT04, "BenchEnumObjT04" ); +BENCH_ENUM_OBJECT_T( 05 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT05, "BenchEnumObjT05" ); +BENCH_ENUM_OBJECT_T( 06 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT06, "BenchEnumObjT06" ); +BENCH_ENUM_OBJECT_T( 07 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT07, "BenchEnumObjT07" ); +BENCH_ENUM_OBJECT_T( 08 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT08, "BenchEnumObjT08" ); +BENCH_ENUM_OBJECT_T( 09 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT09, "BenchEnumObjT09" ); +BENCH_ENUM_OBJECT_T( 10 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT10, "BenchEnumObjT10" ); +BENCH_ENUM_OBJECT_T( 11 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT11, "BenchEnumObjT11" ); +BENCH_ENUM_OBJECT_T( 12 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT12, "BenchEnumObjT12" ); +BENCH_ENUM_OBJECT_T( 13 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT13, "BenchEnumObjT13" ); +BENCH_ENUM_OBJECT_T( 14 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT14, "BenchEnumObjT14" ); +BENCH_ENUM_OBJECT_T( 15 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT15, "BenchEnumObjT15" ); +BENCH_ENUM_OBJECT_T( 16 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT16, "BenchEnumObjT16" ); +BENCH_ENUM_OBJECT_T( 17 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT17, "BenchEnumObjT17" ); +BENCH_ENUM_OBJECT_T( 18 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT18, "BenchEnumObjT18" ); +BENCH_ENUM_OBJECT_T( 19 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT19, "BenchEnumObjT19" ); +BENCH_ENUM_OBJECT_T( 20 ) CAF_PDM_SOURCE_INIT( BenchEnumObjT20, "BenchEnumObjT20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_filepath_fields_template.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_filepath_fields_template.cpp new file mode 100644 index 00000000000..4ec41feb066 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_filepath_fields_template.cpp @@ -0,0 +1,52 @@ +// Compile-time benchmark: same as bench_filepath_fields.cpp, but uses the macro-free +// initPdmObject/initFieldNoDefault template API. + +#include "cafFilePath.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include + +// clang-format off + +#define BENCH_FILEPATH_OBJECT_T( N ) \ +class BenchFilePathObjT##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchFilePathObjT##N() \ + { \ + initPdmObject( "BenchFilePathObjT" #N ); \ + initFieldNoDefault( &m_fileA, "File A" ); \ + initFieldNoDefault( &m_fileB, "File B" ); \ + initFieldNoDefault( &m_fileC, "File C" ); \ + initFieldNoDefault( &m_files, "File list" ); \ + } \ + caf::PdmField m_fileA; \ + caf::PdmField m_fileB; \ + caf::PdmField m_fileC; \ + caf::PdmField> m_files; \ +}; + +BENCH_FILEPATH_OBJECT_T( 01 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT01, "BenchFilePathObjT01" ); +BENCH_FILEPATH_OBJECT_T( 02 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT02, "BenchFilePathObjT02" ); +BENCH_FILEPATH_OBJECT_T( 03 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT03, "BenchFilePathObjT03" ); +BENCH_FILEPATH_OBJECT_T( 04 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT04, "BenchFilePathObjT04" ); +BENCH_FILEPATH_OBJECT_T( 05 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT05, "BenchFilePathObjT05" ); +BENCH_FILEPATH_OBJECT_T( 06 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT06, "BenchFilePathObjT06" ); +BENCH_FILEPATH_OBJECT_T( 07 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT07, "BenchFilePathObjT07" ); +BENCH_FILEPATH_OBJECT_T( 08 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT08, "BenchFilePathObjT08" ); +BENCH_FILEPATH_OBJECT_T( 09 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT09, "BenchFilePathObjT09" ); +BENCH_FILEPATH_OBJECT_T( 10 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT10, "BenchFilePathObjT10" ); +BENCH_FILEPATH_OBJECT_T( 11 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT11, "BenchFilePathObjT11" ); +BENCH_FILEPATH_OBJECT_T( 12 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT12, "BenchFilePathObjT12" ); +BENCH_FILEPATH_OBJECT_T( 13 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT13, "BenchFilePathObjT13" ); +BENCH_FILEPATH_OBJECT_T( 14 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT14, "BenchFilePathObjT14" ); +BENCH_FILEPATH_OBJECT_T( 15 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT15, "BenchFilePathObjT15" ); +BENCH_FILEPATH_OBJECT_T( 16 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT16, "BenchFilePathObjT16" ); +BENCH_FILEPATH_OBJECT_T( 17 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT17, "BenchFilePathObjT17" ); +BENCH_FILEPATH_OBJECT_T( 18 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT18, "BenchFilePathObjT18" ); +BENCH_FILEPATH_OBJECT_T( 19 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT19, "BenchFilePathObjT19" ); +BENCH_FILEPATH_OBJECT_T( 20 ) CAF_PDM_SOURCE_INIT( BenchFilePathObjT20, "BenchFilePathObjT20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_heavy_fields.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_heavy_fields.cpp new file mode 100644 index 00000000000..696babe5a32 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_heavy_fields.cpp @@ -0,0 +1,120 @@ +// Compile-time benchmark: heavy version of bench_mixed_fields with 50 classes (instead of 20) +// to push compile time into the ~10s range. Used to amplify any compile-time signal between the +// CAF_PDM_Init* macros and the macro-free template API beyond run-to-run noise. + +#include "cafAppEnum.h" +#include "cafFilePath.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include +#include +#include + +// clang-format off + +#define BENCH_HEAVY_OBJECT( N ) \ +enum class BenchHeavyEnum##N { Alpha, Beta, Gamma, Delta }; \ +class BenchHeavyObj##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchHeavyObj##N() \ + { \ + CAF_PDM_InitObject( "BenchHeavyObj" #N ); \ + CAF_PDM_InitField( &m_intVal, "IntVal", 0, "Int" ); \ + CAF_PDM_InitField( &m_dblVal, "DblVal", 0.0, "Double" ); \ + CAF_PDM_InitField( &m_boolVal, "BoolVal", false, "Bool" ); \ + CAF_PDM_InitField( &m_strVal, "StrVal", QString(), "String" ); \ + CAF_PDM_InitField( &m_enumVal, "EnumVal", BenchHeavyEnum##N::Alpha, "Enum" ); \ + CAF_PDM_InitFieldNoDefault( &m_vecDbl, "VecDbl", "Vector of doubles" ); \ + CAF_PDM_InitFieldNoDefault( &m_vecStr, "VecStr", "Vector of strings" ); \ + CAF_PDM_InitFieldNoDefault( &m_optDbl, "OptDbl", "Optional double" ); \ + CAF_PDM_InitFieldNoDefault( &m_fileA, "FileA", "File A" ); \ + auto pairInit = std::make_pair( false, 0.0 ); \ + CAF_PDM_InitField( &m_pairVal, "PairVal", pairInit, "Pair" ); \ + } \ + caf::PdmField m_intVal; \ + caf::PdmField m_dblVal; \ + caf::PdmField m_boolVal; \ + caf::PdmField m_strVal; \ + caf::PdmField> m_enumVal; \ + caf::PdmField> m_vecDbl; \ + caf::PdmField> m_vecStr; \ + caf::PdmField> m_optDbl; \ + caf::PdmField m_fileA; \ + caf::PdmField> m_pairVal; \ +}; + +BENCH_HEAVY_OBJECT( 01 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj01, "BenchHeavyObj01" ); +BENCH_HEAVY_OBJECT( 02 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj02, "BenchHeavyObj02" ); +BENCH_HEAVY_OBJECT( 03 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj03, "BenchHeavyObj03" ); +BENCH_HEAVY_OBJECT( 04 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj04, "BenchHeavyObj04" ); +BENCH_HEAVY_OBJECT( 05 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj05, "BenchHeavyObj05" ); +BENCH_HEAVY_OBJECT( 06 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj06, "BenchHeavyObj06" ); +BENCH_HEAVY_OBJECT( 07 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj07, "BenchHeavyObj07" ); +BENCH_HEAVY_OBJECT( 08 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj08, "BenchHeavyObj08" ); +BENCH_HEAVY_OBJECT( 09 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj09, "BenchHeavyObj09" ); +BENCH_HEAVY_OBJECT( 10 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj10, "BenchHeavyObj10" ); +BENCH_HEAVY_OBJECT( 11 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj11, "BenchHeavyObj11" ); +BENCH_HEAVY_OBJECT( 12 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj12, "BenchHeavyObj12" ); +BENCH_HEAVY_OBJECT( 13 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj13, "BenchHeavyObj13" ); +BENCH_HEAVY_OBJECT( 14 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj14, "BenchHeavyObj14" ); +BENCH_HEAVY_OBJECT( 15 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj15, "BenchHeavyObj15" ); +BENCH_HEAVY_OBJECT( 16 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj16, "BenchHeavyObj16" ); +BENCH_HEAVY_OBJECT( 17 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj17, "BenchHeavyObj17" ); +BENCH_HEAVY_OBJECT( 18 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj18, "BenchHeavyObj18" ); +BENCH_HEAVY_OBJECT( 19 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj19, "BenchHeavyObj19" ); +BENCH_HEAVY_OBJECT( 20 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj20, "BenchHeavyObj20" ); +BENCH_HEAVY_OBJECT( 21 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj21, "BenchHeavyObj21" ); +BENCH_HEAVY_OBJECT( 22 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj22, "BenchHeavyObj22" ); +BENCH_HEAVY_OBJECT( 23 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj23, "BenchHeavyObj23" ); +BENCH_HEAVY_OBJECT( 24 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj24, "BenchHeavyObj24" ); +BENCH_HEAVY_OBJECT( 25 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj25, "BenchHeavyObj25" ); +BENCH_HEAVY_OBJECT( 26 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj26, "BenchHeavyObj26" ); +BENCH_HEAVY_OBJECT( 27 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj27, "BenchHeavyObj27" ); +BENCH_HEAVY_OBJECT( 28 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj28, "BenchHeavyObj28" ); +BENCH_HEAVY_OBJECT( 29 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj29, "BenchHeavyObj29" ); +BENCH_HEAVY_OBJECT( 30 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj30, "BenchHeavyObj30" ); +BENCH_HEAVY_OBJECT( 31 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj31, "BenchHeavyObj31" ); +BENCH_HEAVY_OBJECT( 32 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj32, "BenchHeavyObj32" ); +BENCH_HEAVY_OBJECT( 33 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj33, "BenchHeavyObj33" ); +BENCH_HEAVY_OBJECT( 34 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj34, "BenchHeavyObj34" ); +BENCH_HEAVY_OBJECT( 35 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj35, "BenchHeavyObj35" ); +BENCH_HEAVY_OBJECT( 36 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj36, "BenchHeavyObj36" ); +BENCH_HEAVY_OBJECT( 37 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj37, "BenchHeavyObj37" ); +BENCH_HEAVY_OBJECT( 38 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj38, "BenchHeavyObj38" ); +BENCH_HEAVY_OBJECT( 39 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj39, "BenchHeavyObj39" ); +BENCH_HEAVY_OBJECT( 40 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj40, "BenchHeavyObj40" ); +BENCH_HEAVY_OBJECT( 41 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj41, "BenchHeavyObj41" ); +BENCH_HEAVY_OBJECT( 42 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj42, "BenchHeavyObj42" ); +BENCH_HEAVY_OBJECT( 43 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj43, "BenchHeavyObj43" ); +BENCH_HEAVY_OBJECT( 44 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj44, "BenchHeavyObj44" ); +BENCH_HEAVY_OBJECT( 45 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj45, "BenchHeavyObj45" ); +BENCH_HEAVY_OBJECT( 46 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj46, "BenchHeavyObj46" ); +BENCH_HEAVY_OBJECT( 47 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj47, "BenchHeavyObj47" ); +BENCH_HEAVY_OBJECT( 48 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj48, "BenchHeavyObj48" ); +BENCH_HEAVY_OBJECT( 49 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj49, "BenchHeavyObj49" ); +BENCH_HEAVY_OBJECT( 50 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj50, "BenchHeavyObj50" ); +BENCH_HEAVY_OBJECT( 51 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj51, "BenchHeavyObj51" ); +BENCH_HEAVY_OBJECT( 52 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj52, "BenchHeavyObj52" ); +BENCH_HEAVY_OBJECT( 53 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj53, "BenchHeavyObj53" ); +BENCH_HEAVY_OBJECT( 54 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj54, "BenchHeavyObj54" ); +BENCH_HEAVY_OBJECT( 55 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj55, "BenchHeavyObj55" ); +BENCH_HEAVY_OBJECT( 56 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj56, "BenchHeavyObj56" ); +BENCH_HEAVY_OBJECT( 57 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj57, "BenchHeavyObj57" ); +BENCH_HEAVY_OBJECT( 58 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj58, "BenchHeavyObj58" ); +BENCH_HEAVY_OBJECT( 59 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj59, "BenchHeavyObj59" ); +BENCH_HEAVY_OBJECT( 60 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj60, "BenchHeavyObj60" ); +BENCH_HEAVY_OBJECT( 61 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj61, "BenchHeavyObj61" ); +BENCH_HEAVY_OBJECT( 62 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj62, "BenchHeavyObj62" ); +BENCH_HEAVY_OBJECT( 63 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj63, "BenchHeavyObj63" ); +BENCH_HEAVY_OBJECT( 64 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj64, "BenchHeavyObj64" ); +BENCH_HEAVY_OBJECT( 65 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj65, "BenchHeavyObj65" ); +BENCH_HEAVY_OBJECT( 66 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj66, "BenchHeavyObj66" ); +BENCH_HEAVY_OBJECT( 67 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj67, "BenchHeavyObj67" ); +BENCH_HEAVY_OBJECT( 68 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj68, "BenchHeavyObj68" ); +BENCH_HEAVY_OBJECT( 69 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj69, "BenchHeavyObj69" ); +BENCH_HEAVY_OBJECT( 70 ) CAF_PDM_SOURCE_INIT( BenchHeavyObj70, "BenchHeavyObj70" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_heavy_fields_template.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_heavy_fields_template.cpp new file mode 100644 index 00000000000..b7d6acf0196 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_heavy_fields_template.cpp @@ -0,0 +1,118 @@ +// Compile-time benchmark: same as bench_heavy_fields.cpp (50 classes, 10 fields each), but +// using the macro-free initPdmObject / initField / initFieldNoDefault template API. + +#include "cafAppEnum.h" +#include "cafFilePath.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include +#include +#include + +// clang-format off + +#define BENCH_HEAVY_OBJECT_T( N ) \ +enum class BenchHeavyEnumT##N { Alpha, Beta, Gamma, Delta }; \ +class BenchHeavyObjT##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchHeavyObjT##N() \ + { \ + initPdmObject( "BenchHeavyObjT" #N ); \ + initField( &m_intVal, 0, "Int" ); \ + initField( &m_dblVal, 0.0, "Double" ); \ + initField( &m_boolVal, false, "Bool" ); \ + initField( &m_strVal, QString(), "String" ); \ + initField( &m_enumVal, BenchHeavyEnumT##N::Alpha, "Enum" ); \ + initFieldNoDefault( &m_vecDbl, "Vector of doubles" ); \ + initFieldNoDefault( &m_vecStr, "Vector of strings" ); \ + initFieldNoDefault( &m_optDbl, "Optional double" ); \ + initFieldNoDefault( &m_fileA, "File A" ); \ + initField( &m_pairVal, std::make_pair( false, 0.0 ), "Pair" ); \ + } \ + caf::PdmField m_intVal; \ + caf::PdmField m_dblVal; \ + caf::PdmField m_boolVal; \ + caf::PdmField m_strVal; \ + caf::PdmField> m_enumVal; \ + caf::PdmField> m_vecDbl; \ + caf::PdmField> m_vecStr; \ + caf::PdmField> m_optDbl; \ + caf::PdmField m_fileA; \ + caf::PdmField> m_pairVal; \ +}; + +BENCH_HEAVY_OBJECT_T( 01 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT01, "BenchHeavyObjT01" ); +BENCH_HEAVY_OBJECT_T( 02 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT02, "BenchHeavyObjT02" ); +BENCH_HEAVY_OBJECT_T( 03 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT03, "BenchHeavyObjT03" ); +BENCH_HEAVY_OBJECT_T( 04 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT04, "BenchHeavyObjT04" ); +BENCH_HEAVY_OBJECT_T( 05 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT05, "BenchHeavyObjT05" ); +BENCH_HEAVY_OBJECT_T( 06 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT06, "BenchHeavyObjT06" ); +BENCH_HEAVY_OBJECT_T( 07 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT07, "BenchHeavyObjT07" ); +BENCH_HEAVY_OBJECT_T( 08 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT08, "BenchHeavyObjT08" ); +BENCH_HEAVY_OBJECT_T( 09 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT09, "BenchHeavyObjT09" ); +BENCH_HEAVY_OBJECT_T( 10 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT10, "BenchHeavyObjT10" ); +BENCH_HEAVY_OBJECT_T( 11 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT11, "BenchHeavyObjT11" ); +BENCH_HEAVY_OBJECT_T( 12 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT12, "BenchHeavyObjT12" ); +BENCH_HEAVY_OBJECT_T( 13 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT13, "BenchHeavyObjT13" ); +BENCH_HEAVY_OBJECT_T( 14 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT14, "BenchHeavyObjT14" ); +BENCH_HEAVY_OBJECT_T( 15 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT15, "BenchHeavyObjT15" ); +BENCH_HEAVY_OBJECT_T( 16 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT16, "BenchHeavyObjT16" ); +BENCH_HEAVY_OBJECT_T( 17 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT17, "BenchHeavyObjT17" ); +BENCH_HEAVY_OBJECT_T( 18 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT18, "BenchHeavyObjT18" ); +BENCH_HEAVY_OBJECT_T( 19 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT19, "BenchHeavyObjT19" ); +BENCH_HEAVY_OBJECT_T( 20 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT20, "BenchHeavyObjT20" ); +BENCH_HEAVY_OBJECT_T( 21 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT21, "BenchHeavyObjT21" ); +BENCH_HEAVY_OBJECT_T( 22 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT22, "BenchHeavyObjT22" ); +BENCH_HEAVY_OBJECT_T( 23 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT23, "BenchHeavyObjT23" ); +BENCH_HEAVY_OBJECT_T( 24 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT24, "BenchHeavyObjT24" ); +BENCH_HEAVY_OBJECT_T( 25 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT25, "BenchHeavyObjT25" ); +BENCH_HEAVY_OBJECT_T( 26 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT26, "BenchHeavyObjT26" ); +BENCH_HEAVY_OBJECT_T( 27 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT27, "BenchHeavyObjT27" ); +BENCH_HEAVY_OBJECT_T( 28 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT28, "BenchHeavyObjT28" ); +BENCH_HEAVY_OBJECT_T( 29 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT29, "BenchHeavyObjT29" ); +BENCH_HEAVY_OBJECT_T( 30 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT30, "BenchHeavyObjT30" ); +BENCH_HEAVY_OBJECT_T( 31 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT31, "BenchHeavyObjT31" ); +BENCH_HEAVY_OBJECT_T( 32 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT32, "BenchHeavyObjT32" ); +BENCH_HEAVY_OBJECT_T( 33 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT33, "BenchHeavyObjT33" ); +BENCH_HEAVY_OBJECT_T( 34 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT34, "BenchHeavyObjT34" ); +BENCH_HEAVY_OBJECT_T( 35 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT35, "BenchHeavyObjT35" ); +BENCH_HEAVY_OBJECT_T( 36 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT36, "BenchHeavyObjT36" ); +BENCH_HEAVY_OBJECT_T( 37 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT37, "BenchHeavyObjT37" ); +BENCH_HEAVY_OBJECT_T( 38 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT38, "BenchHeavyObjT38" ); +BENCH_HEAVY_OBJECT_T( 39 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT39, "BenchHeavyObjT39" ); +BENCH_HEAVY_OBJECT_T( 40 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT40, "BenchHeavyObjT40" ); +BENCH_HEAVY_OBJECT_T( 41 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT41, "BenchHeavyObjT41" ); +BENCH_HEAVY_OBJECT_T( 42 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT42, "BenchHeavyObjT42" ); +BENCH_HEAVY_OBJECT_T( 43 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT43, "BenchHeavyObjT43" ); +BENCH_HEAVY_OBJECT_T( 44 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT44, "BenchHeavyObjT44" ); +BENCH_HEAVY_OBJECT_T( 45 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT45, "BenchHeavyObjT45" ); +BENCH_HEAVY_OBJECT_T( 46 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT46, "BenchHeavyObjT46" ); +BENCH_HEAVY_OBJECT_T( 47 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT47, "BenchHeavyObjT47" ); +BENCH_HEAVY_OBJECT_T( 48 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT48, "BenchHeavyObjT48" ); +BENCH_HEAVY_OBJECT_T( 49 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT49, "BenchHeavyObjT49" ); +BENCH_HEAVY_OBJECT_T( 50 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT50, "BenchHeavyObjT50" ); +BENCH_HEAVY_OBJECT_T( 51 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT51, "BenchHeavyObjT51" ); +BENCH_HEAVY_OBJECT_T( 52 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT52, "BenchHeavyObjT52" ); +BENCH_HEAVY_OBJECT_T( 53 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT53, "BenchHeavyObjT53" ); +BENCH_HEAVY_OBJECT_T( 54 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT54, "BenchHeavyObjT54" ); +BENCH_HEAVY_OBJECT_T( 55 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT55, "BenchHeavyObjT55" ); +BENCH_HEAVY_OBJECT_T( 56 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT56, "BenchHeavyObjT56" ); +BENCH_HEAVY_OBJECT_T( 57 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT57, "BenchHeavyObjT57" ); +BENCH_HEAVY_OBJECT_T( 58 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT58, "BenchHeavyObjT58" ); +BENCH_HEAVY_OBJECT_T( 59 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT59, "BenchHeavyObjT59" ); +BENCH_HEAVY_OBJECT_T( 60 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT60, "BenchHeavyObjT60" ); +BENCH_HEAVY_OBJECT_T( 61 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT61, "BenchHeavyObjT61" ); +BENCH_HEAVY_OBJECT_T( 62 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT62, "BenchHeavyObjT62" ); +BENCH_HEAVY_OBJECT_T( 63 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT63, "BenchHeavyObjT63" ); +BENCH_HEAVY_OBJECT_T( 64 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT64, "BenchHeavyObjT64" ); +BENCH_HEAVY_OBJECT_T( 65 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT65, "BenchHeavyObjT65" ); +BENCH_HEAVY_OBJECT_T( 66 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT66, "BenchHeavyObjT66" ); +BENCH_HEAVY_OBJECT_T( 67 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT67, "BenchHeavyObjT67" ); +BENCH_HEAVY_OBJECT_T( 68 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT68, "BenchHeavyObjT68" ); +BENCH_HEAVY_OBJECT_T( 69 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT69, "BenchHeavyObjT69" ); +BENCH_HEAVY_OBJECT_T( 70 ) CAF_PDM_SOURCE_INIT( BenchHeavyObjT70, "BenchHeavyObjT70" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_mixed_fields_template.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_mixed_fields_template.cpp new file mode 100644 index 00000000000..eb3c2d27425 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdm_CompileBench/bench_mixed_fields_template.cpp @@ -0,0 +1,68 @@ +// Compile-time benchmark: same as bench_mixed_fields.cpp, but uses the macro-free +// initPdmObject/initField/initFieldNoDefault template API. + +#include "cafAppEnum.h" +#include "cafFilePath.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include +#include +#include + +// clang-format off + +#define BENCH_MIXED_OBJECT_T( N ) \ +enum class BenchMixedEnumT##N { Alpha, Beta, Gamma, Delta }; \ +class BenchMixedObjT##N : public caf::PdmObject \ +{ \ + CAF_PDM_HEADER_INIT; \ +public: \ + BenchMixedObjT##N() \ + { \ + initPdmObject( "BenchMixedObjT" #N ); \ + initField( &m_intVal, 0, "Int" ); \ + initField( &m_dblVal, 0.0, "Double" ); \ + initField( &m_boolVal, false, "Bool" ); \ + initField( &m_strVal, QString(), "String" ); \ + initField( &m_enumVal, BenchMixedEnumT##N::Alpha, "Enum" ); \ + initFieldNoDefault( &m_vecDbl, "Vector of doubles" ); \ + initFieldNoDefault( &m_vecStr, "Vector of strings" ); \ + initFieldNoDefault( &m_optDbl, "Optional double" ); \ + initFieldNoDefault( &m_fileA, "File A" ); \ + initField( &m_pairVal, std::make_pair( false, 0.0 ), "Pair" ); \ + } \ + caf::PdmField m_intVal; \ + caf::PdmField m_dblVal; \ + caf::PdmField m_boolVal; \ + caf::PdmField m_strVal; \ + caf::PdmField> m_enumVal; \ + caf::PdmField> m_vecDbl; \ + caf::PdmField> m_vecStr; \ + caf::PdmField> m_optDbl; \ + caf::PdmField m_fileA; \ + caf::PdmField> m_pairVal; \ +}; + +BENCH_MIXED_OBJECT_T( 01 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT01, "BenchMixedObjT01" ); +BENCH_MIXED_OBJECT_T( 02 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT02, "BenchMixedObjT02" ); +BENCH_MIXED_OBJECT_T( 03 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT03, "BenchMixedObjT03" ); +BENCH_MIXED_OBJECT_T( 04 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT04, "BenchMixedObjT04" ); +BENCH_MIXED_OBJECT_T( 05 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT05, "BenchMixedObjT05" ); +BENCH_MIXED_OBJECT_T( 06 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT06, "BenchMixedObjT06" ); +BENCH_MIXED_OBJECT_T( 07 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT07, "BenchMixedObjT07" ); +BENCH_MIXED_OBJECT_T( 08 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT08, "BenchMixedObjT08" ); +BENCH_MIXED_OBJECT_T( 09 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT09, "BenchMixedObjT09" ); +BENCH_MIXED_OBJECT_T( 10 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT10, "BenchMixedObjT10" ); +BENCH_MIXED_OBJECT_T( 11 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT11, "BenchMixedObjT11" ); +BENCH_MIXED_OBJECT_T( 12 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT12, "BenchMixedObjT12" ); +BENCH_MIXED_OBJECT_T( 13 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT13, "BenchMixedObjT13" ); +BENCH_MIXED_OBJECT_T( 14 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT14, "BenchMixedObjT14" ); +BENCH_MIXED_OBJECT_T( 15 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT15, "BenchMixedObjT15" ); +BENCH_MIXED_OBJECT_T( 16 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT16, "BenchMixedObjT16" ); +BENCH_MIXED_OBJECT_T( 17 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT17, "BenchMixedObjT17" ); +BENCH_MIXED_OBJECT_T( 18 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT18, "BenchMixedObjT18" ); +BENCH_MIXED_OBJECT_T( 19 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT19, "BenchMixedObjT19" ); +BENCH_MIXED_OBJECT_T( 20 ) CAF_PDM_SOURCE_INIT( BenchMixedObjT20, "BenchMixedObjT20" ); + +// clang-format on diff --git a/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp index 98f8b9876c1..84ca7ce6fab 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp @@ -1032,3 +1032,90 @@ TEST( BaseTest, CopyObject ) auto objectCopy = std::unique_ptr( ihd1->copyObject() ); EXPECT_EQ( testValue, objectCopy->m_doubleMember ); } + +/// A PDM object that uses the macro-free template functions (initPdmObject, initField, +/// initFieldNoDefault) instead of the CAF_PDM_InitObject / CAF_PDM_InitField macros. +/// CAF_PDM_HEADER_INIT and CAF_PDM_SOURCE_INIT are still required for class/factory registration. +class MacroFreeObj : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + MacroFreeObj() + { + initPdmObject( "Macro-Free Object", "", "Tooltip MacroFreeObj", "WhatsThis MacroFreeObj" ); + + initField( &m_intField, 42, "Integer Field", "", "Int tooltip" ); + initField( &m_doubleField, 3.14, "Double Field" ); + initFieldNoDefault( &m_stringField, "String Field" ); + + // Exercises the AppEnum overload: raw enum value (InheritedDemoObj::T2) as the default. + initField( &m_enumField, InheritedDemoObj::T2, "Enum Field" ); + } + + caf::PdmField m_intField; + caf::PdmField m_doubleField; + caf::PdmField m_stringField; + caf::PdmField> m_enumField; +}; +CAF_PDM_SOURCE_INIT( MacroFreeObj, "MacroFreeObj" ); + +TEST( MacroFreeTest, FieldRegistrationAndDefaults ) +{ + MacroFreeObj obj; + + // Verify fields are accessible and have the expected default values + EXPECT_EQ( 42, obj.m_intField() ); + EXPECT_DOUBLE_EQ( 3.14, obj.m_doubleField() ); + + // Verify all fields are registered with the object + EXPECT_EQ( 4u, obj.fields().size() ); +} + +TEST( MacroFreeTest, AppEnumDefaultFromRawEnum ) +{ + MacroFreeObj obj; + + // The raw-enum overload of initField() must wrap the value in AppEnum<>. + EXPECT_EQ( InheritedDemoObj::T2, obj.m_enumField() ); + EXPECT_EQ( QString( "EnumField" ), obj.m_enumField.keyword() ); +} + +TEST( MacroFreeTest, FieldKeywords ) +{ + MacroFreeObj obj; + + EXPECT_EQ( QString( "IntField" ), obj.m_intField.keyword() ); + EXPECT_EQ( QString( "DoubleField" ), obj.m_doubleField.keyword() ); + EXPECT_EQ( QString( "StringField" ), obj.m_stringField.keyword() ); +} + +TEST( MacroFreeTest, UiCapabilitiesPresent ) +{ + MacroFreeObj obj; + + EXPECT_NE( nullptr, obj.m_intField.uiCapability() ); + EXPECT_NE( nullptr, obj.m_doubleField.uiCapability() ); + EXPECT_NE( nullptr, obj.m_stringField.uiCapability() ); +} + +TEST( MacroFreeTest, UiItemInfoUiName ) +{ + MacroFreeObj obj; + + EXPECT_EQ( QString( "Integer Field" ), obj.m_intField.uiCapability()->uiName() ); + EXPECT_EQ( QString( "Double Field" ), obj.m_doubleField.uiCapability()->uiName() ); + EXPECT_EQ( QString( "String Field" ), obj.m_stringField.uiCapability()->uiName() ); +} + +TEST( MacroFreeTest, ObjectUiName ) +{ + MacroFreeObj obj; + + EXPECT_EQ( QString( "Macro-Free Object" ), obj.uiCapability()->uiName() ); +} + +TEST( MacroFreeTest, ClassKeyword ) +{ + EXPECT_EQ( QString( "MacroFreeObj" ), MacroFreeObj::classKeywordStatic() ); +} From d6817f61eccef449d7b8bb8242738ae3028432c1 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Tue, 5 May 2026 15:48:41 +0200 Subject: [PATCH 3/3] PdmField: Suppress per-TU instantiation of hot specializations Add extern template declarations for the 13 most common PdmField specializations (primitive types, QString, vector/optional/pair containers) in cafPdmField.h, with matching explicit instantiations in a new cafPdmField.cpp. Every TU that includes cafPdmField.h now skips re-instantiating these specializations while still inlining the hot in-class members. --- .../cafPdmCore/CMakeLists.txt | 1 + .../cafPdmCore/cafPdmField.cpp | 27 +++++++++++++++++++ .../cafPdmCore/cafPdmField.h | 27 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmField.cpp diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt index 2d4de6e8adc..d57259a389e 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt @@ -27,6 +27,7 @@ set(PROJECT_FILES cafPdmChildField.inl cafPdmDataValueField.h cafPdmField.h + cafPdmField.cpp cafPdmFieldCapability.h cafPdmFieldHandle.cpp cafPdmFieldHandle.h diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmField.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmField.cpp new file mode 100644 index 00000000000..536c60d1f27 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmField.cpp @@ -0,0 +1,27 @@ +// Explicit instantiation of the hot PdmField specializations. The matching +// `extern template class PdmField;` declarations live in cafPdmField.h, suppressing +// re-instantiation in every TU that includes the header. + +#include "cafPdmField.h" + +// PdmFieldHandle::capability() uses dynamic_cast on PdmFieldCapability*, which requires a +// complete polymorphic type at the point of instantiation. Bring it in here so the explicit +// instantiations of setValueWithFieldChanged() can compile. +#include "cafPdmFieldCapability.h" + +namespace caf +{ +template class PdmField; +template class PdmField; +template class PdmField; +template class PdmField; +template class PdmField; +template class PdmField; +template class PdmField>; +template class PdmField>; +template class PdmField>; +template class PdmField>; +template class PdmField>; +template class PdmField>; +template class PdmField>; +} // namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmField.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmField.h index a764f81f2d6..acc874c5f98 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmField.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmField.h @@ -5,3 +5,30 @@ #include "cafPdmDataValueField.h" #undef PdmDataValueField #undef CAF_IS_DEFINING_PDM_FIELD + +// Suppress per-TU instantiation of the hot PdmField specializations used throughout the +// codebase. The matching `template class PdmField;` lines live in cafPdmField.cpp. +// +// extern template only suppresses out-of-class members and the vtable; in-class inline members +// (value(), operator==, etc.) are unaffected and still inlined where called. +// +// The includes for QString / std::vector / std::optional / std::pair come transitively via +// cafPdmDataValueField.h (QVariant, , , etc.). cafFilePath.h is the only +// header we need to add explicitly. + +namespace caf +{ +extern template class PdmField; +extern template class PdmField; +extern template class PdmField; +extern template class PdmField; +extern template class PdmField; +extern template class PdmField; +extern template class PdmField>; +extern template class PdmField>; +extern template class PdmField>; +extern template class PdmField>; +extern template class PdmField>; +extern template class PdmField>; +extern template class PdmField>; +} // namespace caf