diff --git a/FWCore/Reflection/interface/DataProductReflectionInfo.h b/FWCore/Reflection/interface/DataProductReflectionInfo.h new file mode 100644 index 0000000000000..f887bffef95a4 --- /dev/null +++ b/FWCore/Reflection/interface/DataProductReflectionInfo.h @@ -0,0 +1,65 @@ +#ifndef FWCore_Reflection_DataProductReflectionInfo_h +#define FWCore_Reflection_DataProductReflectionInfo_h +// -*- C++ -*- +// +// Package: FWCore/Reflection +// Class : DataProductReflectionInfo +// +/**\class DataProductReflectionInfo DataProductReflectionInfo.h "FWCore/Reflection/interface/DataProductReflectionInfo.h" + + Description: [one line class summary] + + Usage: + + +*/ +// +// Original Author: Christopher Jones +// Created: Wed, 27 Jul 2022 20:49:53 GMT +// + +// system include files + +// user include files +#include "FWCore/Reflection/interface/InheritanceReflection.h" +#include "FWCore/Reflection/interface/StaticDataProductReflection.h" + +// forward declarations +namespace edm { + struct DataProductReflectionInfo { + using BaseRange = InheritanceReflection::BaseRange; + + constexpr DataProductReflectionInfo(InheritanceReflection iType, std::type_info const* iElementType) + : m_type(iType), m_elementType(iElementType) {} + + constexpr std::type_info const& typeInfo() const noexcept { return m_type.typeInfo(); } + constexpr BaseRange inheritsFrom() const noexcept { return m_type.inheritsFrom(); } + + constexpr bool isContainer() const noexcept { return static_cast(m_elementType); } + constexpr std::type_info const& elementType() const noexcept { + if (m_elementType) { + return *m_elementType; + } + return m_type.typeInfo(); + } + + private: + InheritanceReflection const m_type; + std::type_info const* const m_elementType; + }; + + template + //can't make this constexpr until C++23 + const DataProductReflectionInfo makeDataProductReflectionInfo() { + using Reflectn = StaticDataProductReflection; + static auto const s_bases = Reflectn::inherits_from(); + InheritanceReflection reflection(&typeid(T), + InheritanceReflection::BaseRange(s_bases.data(), s_bases.data() + s_bases.size())); + if constexpr (Reflectn::is_container) { + return DataProductReflectionInfo{reflection, &typeid(typename Reflectn::element_type)}; + } + return DataProductReflectionInfo{reflection, nullptr}; + } + +} // namespace edm +#endif diff --git a/FWCore/Reflection/interface/DataProductReflectionInfoRegistry.h b/FWCore/Reflection/interface/DataProductReflectionInfoRegistry.h new file mode 100644 index 0000000000000..9d7d41abea963 --- /dev/null +++ b/FWCore/Reflection/interface/DataProductReflectionInfoRegistry.h @@ -0,0 +1,77 @@ +#ifndef FWCore_Reflection_DataProductReflectionInfoRegistry_h +#define FWCore_Reflection_DataProductReflectionInfoRegistry_h +// -*- C++ -*- +// +// Package: FWCore/Reflection +// Class : DataProductReflectionInfoRegistry +// +/**\class DataProductReflectionInfoRegistry DataProductReflectionInfoRegistry.h "FWCore/Reflection/interface/DataProductReflectionInfoRegistry.h" + + Description: [one line class summary] + + Usage: + + +*/ +// +// Original Author: Christopher Jones +// Created: Wed, 27 Jul 2022 21:00:33 GMT +// + +// system include files +#include +#include +#include "oneapi/tbb/concurrent_unordered_map.h" + +// user include files +#include "FWCore/Reflection/interface/DataProductReflectionInfo.h" + +// forward declarations +namespace edm { + class DataProductReflectionInfoRegistry { + public: + ~DataProductReflectionInfoRegistry(); + + DataProductReflectionInfoRegistry(const DataProductReflectionInfoRegistry&) = delete; // stop default + const DataProductReflectionInfoRegistry& operator=(const DataProductReflectionInfoRegistry&) = + delete; // stop default + + // ---------- const member functions --------------------- + DataProductReflectionInfo const* findType(std::type_index) const; + + // ---------- static member functions -------------------- + static DataProductReflectionInfoRegistry& instance(); + + // ---------- member functions --------------------------- + void registerDataProduct(std::type_index, DataProductReflectionInfo); + + private: + // ---------- member data -------------------------------- + DataProductReflectionInfoRegistry(); + + oneapi::tbb::concurrent_unordered_map m_registry; + }; + + template + struct RegisterDataProductReflectionInfo { + RegisterDataProductReflectionInfo() { + DataProductReflectionInfoRegistry::instance().registerDataProduct(std::type_index(typeid(T)), + makeDataProductReflectionInfo()); + } + }; + +} // namespace edm + +#define EDM_DATAPRODUCTINFO_SYM(x, y) EDM_DATAPRODUCTINFO_SYM2(x, y) +#define EDM_DATAPRODUCTINFO_SYM2(x, y) x##y + +#define DEFINE_DATA_PRODUCT_INFO(type, ...) \ + namespace edm { \ + template <> \ + struct StaticDataProductReflection \ + : public StaticDataProductReflectionBase {}; \ + static const RegisterDataProductReflectionInfo EDM_DATAPRODUCTINFO_SYM(s_registry, __LINE__); \ + } \ + using require_semicolon = int + +#endif diff --git a/FWCore/Reflection/interface/InheritanceReflection.h b/FWCore/Reflection/interface/InheritanceReflection.h new file mode 100644 index 0000000000000..7f94e3c0d3c48 --- /dev/null +++ b/FWCore/Reflection/interface/InheritanceReflection.h @@ -0,0 +1,60 @@ +#ifndef FWCore_Reflection_InheritanceReflection_h +#define FWCore_Reflection_InheritanceReflection_h +// -*- C++ -*- +// +// Package: FWCore/Reflection +// Class : InheritanceReflection +// +/**\class InheritanceReflection InheritanceReflection.h "FWCore/Reflection/interface/InheritanceReflection.h" + + Description: A type-agnostic holder of inheritance information used for runtime reflection + + Usage: + + +*/ +// +// Original Author: Christopher Jones +// Created: Wed, 27 Jul 2022 20:47:16 GMT +// + +// system include files +#include +#include + +// user include files + +// forward declarations +namespace edm { + class InheritanceReflection { + public: + class BaseRange { + public: + using const_iterator_type = std::type_info const* const*; + using element_type = std::type_info const* const; + + constexpr BaseRange(const_iterator_type iBegin, const_iterator_type iEnd) : m_begin(iBegin), m_end(iEnd) {} + + const_iterator_type begin() const { return m_begin; } + const_iterator_type end() const { return m_end; } + + size_t size() const { return m_end - m_begin; } + bool empty() const { return m_end == m_begin; } + + private: + const_iterator_type m_begin; + const_iterator_type m_end; + }; + + constexpr InheritanceReflection(std::type_info const* iType, BaseRange iBases) : m_type(iType), m_bases(iBases) {} + + constexpr std::type_info const& typeInfo() const noexcept { return *m_type; } + constexpr BaseRange inheritsFrom() const noexcept { return m_bases; } + + private: + std::type_info const* m_type; + BaseRange const m_bases; + }; +} // namespace edm + +#endif diff --git a/FWCore/Reflection/interface/StaticDataProductReflection.h b/FWCore/Reflection/interface/StaticDataProductReflection.h new file mode 100644 index 0000000000000..9095409a58d37 --- /dev/null +++ b/FWCore/Reflection/interface/StaticDataProductReflection.h @@ -0,0 +1,73 @@ +#ifndef FWCore_Reflection_StaticDataProductReflection_h +#define FWCore_Reflection_StaticDataProductReflection_h +// -*- C++ -*- +// +// Package: FWCore/Reflection +// Class : StaticDataProductReflection +// +/**\class StaticDataProductReflection StaticDataProductReflection.h "FWCore/Reflection/interface/StaticDataProductReflection.h" + + Description: template class describing compile time infor about a data product + + Usage: + Developers must specialize a StaticDataProductReflection for each data product type. This is done by inheriting from + StaticDataProductReflectionBase and declaring all inherited classes in the template arguments + + template<> class StaticDataProductReflection : public StaticDataProductReflectionBase {}; + +*/ +// +// Original Author: Christopher Jones +// Created: Wed, 27 Jul 2022 20:39:27 GMT +// + +// system include files +#include +#include +#include + +// user include files +#include "FWCore/Reflection/interface/TypeInfoList.h" + +// forward declarations + +namespace edm { + template + struct StaticDataProductReflectionBase { + static constexpr bool is_container = false; + using element_type = T; + using Inheritance = TypeInfoList; + + static constexpr unsigned int nBases = Inheritance::nTypes; + static constexpr std::array inherits_from() noexcept { + Inheritance::test_inheritance(static_cast(nullptr)); + return Inheritance::list(); + }; + }; + + template + struct StaticDataProductReflectionBase { + static constexpr bool is_container = false; + using element_type = T; + + static constexpr unsigned int nBases = 0; + static constexpr std::array inherits_from() noexcept { return {}; }; + + static constexpr std::array class_and_inherits_from() noexcept { return {{&typeid(T)}}; }; + }; + + template + struct StaticDataProductReflectionBase> { + static constexpr bool is_container = true; + + using element_type = typename std::vector::value_type; + + static constexpr unsigned int nBases = 0; + static constexpr std::array inherits_from() noexcept { return {}; }; + }; + + template + struct StaticDataProductReflection; + +} // namespace edm +#endif diff --git a/FWCore/Reflection/interface/TypeInfoList.h b/FWCore/Reflection/interface/TypeInfoList.h new file mode 100644 index 0000000000000..1a5f604287c3d --- /dev/null +++ b/FWCore/Reflection/interface/TypeInfoList.h @@ -0,0 +1,63 @@ +#ifndef FWCore_Reflection_TypeInfoList_h +#define FWCore_Reflection_TypeInfoList_h +// -*- C++ -*- +// +// Package: FWCore/Reflection +// Class : TypeInfoList +// +/**\class TypeInfoList TypeInfoList.h "FWCore/Reflection/interface/TypeInfoList.h" + + Description: Converts types in template argument to a container of std::type_infos + + Usage: + + +*/ +// +// Original Author: Christopher Jones +// Created: Wed, 27 Jul 2022 20:36:03 GMT +// + +// system include files +#include +#include + +// user include files + +// forward declarations + +namespace edm { + template + struct TypeInfoList; + + template + struct TypeInfoList { + static constexpr unsigned int nTypes = TypeInfoList::nTypes + 1; + static constexpr std::array list() noexcept { + auto i = previous_list(); + std::array v = {{&typeid(T)}}; + std::copy(i.begin(), i.end(), v.begin() + 1); + return v; + }; + template + static constexpr void test_inheritance(D const* iD) { + test_inheritance_(iD); + TypeInfoList::test_inheritance(iD); + } + + private: + static constexpr std::array previous_list() noexcept { + return TypeInfoList::list(); + } + static constexpr void test_inheritance_(T const*) {} + }; + + template <> + struct TypeInfoList<> { + static constexpr unsigned int nTypes = 0; + static constexpr std::array list() noexcept { return {}; }; + template + static constexpr void test_inheritance(D const* iD) {} + }; +} // namespace edm +#endif diff --git a/FWCore/Reflection/src/DataProductReflectionInfoRegistry.cc b/FWCore/Reflection/src/DataProductReflectionInfoRegistry.cc new file mode 100644 index 0000000000000..70767eacab11f --- /dev/null +++ b/FWCore/Reflection/src/DataProductReflectionInfoRegistry.cc @@ -0,0 +1,58 @@ +// -*- C++ -*- +// +// Package: FWCore/Reflection +// Class : DataProductReflectionInfoRegistry +// +// Implementation: +// [Notes on implementation] +// +// Original Author: Christopher Jones +// Created: Wed, 27 Jul 2022 21:12:54 GMT +// + +// system include files + +// user include files +#include "FWCore/Reflection/interface/DataProductReflectionInfoRegistry.h" + +// +// constants, enums and typedefs +// + +// +// static data member definitions +// + +// +// constructors and destructor +// +edm::DataProductReflectionInfoRegistry::DataProductReflectionInfoRegistry() {} + +edm::DataProductReflectionInfoRegistry::~DataProductReflectionInfoRegistry() {} + +// +// member functions +// +void edm::DataProductReflectionInfoRegistry::registerDataProduct(std::type_index iIndex, + DataProductReflectionInfo iInfo) { + m_registry.emplace(iIndex, iInfo); +} + +// +// const member functions +// +edm::DataProductReflectionInfo const* edm::DataProductReflectionInfoRegistry::findType(std::type_index iIndex) const { + auto itFound = m_registry.find(iIndex); + if (itFound == m_registry.end()) { + return nullptr; + } + return &(itFound->second); +} + +// +// static member functions +// +edm::DataProductReflectionInfoRegistry& edm::DataProductReflectionInfoRegistry::instance() { + static DataProductReflectionInfoRegistry s_registry; + return s_registry; +} diff --git a/FWCore/Reflection/test/BuildFile.xml b/FWCore/Reflection/test/BuildFile.xml new file mode 100644 index 0000000000000..1c1a0a349bf91 --- /dev/null +++ b/FWCore/Reflection/test/BuildFile.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/FWCore/Reflection/test/test_catch2_main.cc b/FWCore/Reflection/test/test_catch2_main.cc new file mode 100644 index 0000000000000..0c7c351f437f5 --- /dev/null +++ b/FWCore/Reflection/test/test_catch2_main.cc @@ -0,0 +1,2 @@ +#define CATCH_CONFIG_MAIN +#include "catch.hpp" diff --git a/FWCore/Reflection/test/test_catch2_registry.cc b/FWCore/Reflection/test/test_catch2_registry.cc new file mode 100644 index 0000000000000..9ec1a783c855e --- /dev/null +++ b/FWCore/Reflection/test/test_catch2_registry.cc @@ -0,0 +1,82 @@ +#include "FWCore/Reflection/interface/DataProductReflectionInfoRegistry.h" +#include + +#include "catch.hpp" + +namespace test { + struct Foo { + virtual ~Foo() = default; + }; + + struct Bar : public Foo {}; + struct DiveBar : private Foo {}; + struct GoodBar : public Bar {}; + + struct NotRegistered {}; +} // namespace test + +using namespace test; + +//Below must be specified by developer +DEFINE_DATA_PRODUCT_INFO(Foo); +DEFINE_DATA_PRODUCT_INFO(Bar, Foo); +DEFINE_DATA_PRODUCT_INFO(GoodBar, Bar, Foo); +DEFINE_DATA_PRODUCT_INFO(DiveBar); +DEFINE_DATA_PRODUCT_INFO(std::vector); +//will fail to compile which is good +//DEFINE_DATA_PRODUCT_INFO(DiveBar, Foo); + +TEST_CASE("Test DataProductReflectionInfoRegistry", "[DataProductReflectionInfoRegistry]") { + SECTION("Exists") { + REQUIRE(edm::DataProductReflectionInfoRegistry::instance().findType(std::type_index(typeid(Foo)))); + REQUIRE(edm::DataProductReflectionInfoRegistry::instance().findType(std::type_index(typeid(Bar)))); + REQUIRE(edm::DataProductReflectionInfoRegistry::instance().findType(std::type_index(typeid(DiveBar)))); + + REQUIRE(edm::DataProductReflectionInfoRegistry::instance().findType(std::type_index(typeid(GoodBar)))); + REQUIRE(edm::DataProductReflectionInfoRegistry::instance().findType(std::type_index(typeid(std::vector)))); + } + SECTION("Missing") { + REQUIRE(not edm::DataProductReflectionInfoRegistry::instance().findType(std::type_index(typeid(NotRegistered)))); + } + SECTION("Check info") { + SECTION("Base no inheritance") { + auto fooInfo = edm::DataProductReflectionInfoRegistry::instance().findType(std::type_index(typeid(Foo))); + REQUIRE(fooInfo); + REQUIRE(fooInfo->typeInfo() == typeid(Foo)); + REQUIRE(not fooInfo->isContainer()); + auto range = fooInfo->inheritsFrom(); + REQUIRE(range.empty()); + } + SECTION("Single public inheritance") { + auto info = edm::DataProductReflectionInfoRegistry::instance().findType(std::type_index(typeid(Bar))); + REQUIRE(info); + REQUIRE(info->typeInfo() == typeid(Bar)); + REQUIRE(not info->isContainer()); + auto range = info->inheritsFrom(); + REQUIRE(not range.empty()); + REQUIRE(range.size() == 1); + REQUIRE(*(*range.begin()) == typeid(Foo)); + } + SECTION("Multiple public inheritance") { + auto info = edm::DataProductReflectionInfoRegistry::instance().findType(std::type_index(typeid(GoodBar))); + REQUIRE(info); + REQUIRE(info->typeInfo() == typeid(GoodBar)); + REQUIRE(not info->isContainer()); + auto range = info->inheritsFrom(); + REQUIRE(not range.empty()); + REQUIRE(range.size() == 2); + REQUIRE(*(*range.begin()) == typeid(Bar)); + REQUIRE(*(*(range.begin() + 1)) == typeid(Foo)); + } + SECTION("Container, no inheritance") { + auto info = + edm::DataProductReflectionInfoRegistry::instance().findType(std::type_index(typeid(std::vector))); + REQUIRE(info); + REQUIRE(info->typeInfo() == typeid(std::vector)); + REQUIRE(info->isContainer()); + REQUIRE(info->elementType() == typeid(Foo)); + auto range = info->inheritsFrom(); + REQUIRE(range.empty()); + } + } +}