Skip to content

Commit 98a15af

Browse files
authored
Allow types from different data models in interfaces (#714)
* add detail function for object rank that can be used for comparison add detecting if `uintptr_t` is defined * add extension data model with interface add test for interface with types from data model and its extension * hide rank value in a proxy * rename 'Rank' to 'OrderKey' * add comments, mention in docs * compare with `std::less`, remove obsolete typedefs, sprinkle `noexcept` * allow cross-model interfaces in relations * test relations IO with cross-edm interface * test links IO with cross-edm interfaces * fix missing link to extension datamodel in cmake testing function
1 parent c97bdf1 commit 98a15af

File tree

18 files changed

+255
-15
lines changed

18 files changed

+255
-15
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ install
55
tests/src
66
tests/datamodel
77
tests/extension_model
8+
tests/interface_extension_model
89
tests/datamodeljulia
910
tests/unittests/Project.toml
1011
tests/unittests/Manifest.toml

cmake/podioTest.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ function(CREATE_PODIO_TEST sourcefile additional_libs)
2727
add_executable( ${name} ${sourcefile} )
2828
add_test(NAME ${name} COMMAND ${name})
2929

30-
target_link_libraries(${name} PRIVATE TestDataModel ExtensionDataModel ${additional_libs})
30+
target_link_libraries(${name} PRIVATE TestDataModel ExtensionDataModel InterfaceExtensionDataModel ${additional_libs})
3131
PODIO_SET_TEST_ENV(${name})
3232
endfunction()

doc/datamodel_syntax.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,5 +268,6 @@ The podio `PODIO_GENERATE_DATAMODEL` cmake macro has gained an additional parame
268268
### Potential pitfalls
269269
- The cmake macros do not handle linking against an upstream datamodel automatically. It is the users responsibility to explicitly link against the upstream datamodel.
270270
- When generating two datamodels side-by-side and into the same output directory and using the `ROOT` backend, the generated `selection.xml` file might be overwritten if both datamodels are generated into the same output directory.
271+
- The [interfaces](#definition-of-custom-interfaces) defined in a datamodel can list the datatypes defined in an upstream datamodel only if both datamodels have the same [`getSyntax`](#global-options) value.
271272

272273
Limiting this functionality to one upstream datamodel is a conscious choice to limit the potential for abuse of this feature.

include/podio/detail/OrderKey.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#ifndef PODIO_DETAIL_ORDERKEY_H
2+
#define PODIO_DETAIL_ORDERKEY_H
3+
#include <functional>
4+
namespace podio::detail {
5+
/// Internal class allowing datatype objects to be placed in data structures like maps and sets by providing a way to
6+
/// compare them. The comparison is based on addresses of their internal data objects.
7+
///
8+
/// This class is intended to be used as the return value of internal `podio::detail::getOrderKey` free functions. These
9+
/// functions are friends of each datatype, allowing them to access the internal data objects and define less-than
10+
/// comparison operators for both datatypes and interface types.
11+
///
12+
/// The friend free function design is used in order to reduce the coupling between interfaces and datatypes. Interfaces
13+
/// do not need to be friends of datatypes to define the less-than comparison operator, which allows using datatypes
14+
/// from different datamodels in an interface type.
15+
class OrderKey {
16+
public:
17+
OrderKey(void* orderKey) noexcept : m_orderKey(orderKey) {
18+
}
19+
friend bool operator<(const OrderKey& lhs, const OrderKey& rhs) noexcept {
20+
return std::less<void*>{}(lhs.m_orderKey, rhs.m_orderKey);
21+
}
22+
23+
private:
24+
void* m_orderKey;
25+
};
26+
} // namespace podio::detail
27+
28+
#endif // PODIO_DETAIL_ORDERKEY_H

python/podio/test_Frame.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@
4747
"interface_examples",
4848
}
4949

50+
# The expected collections from the interface extension (only present in the other_events category)
51+
EXPECTED_INTERFACE_EXTENSION_COLL_NAMES = {
52+
"anotherHits",
53+
"extension_interface_relation",
54+
"extension_interface_links",
55+
}
56+
5057
# The expected parameter names in each frame
5158
EXPECTED_PARAM_NAMES = {
5259
"anInt",
@@ -167,7 +174,9 @@ def test_frame_collections(self):
167174
self.assertEqual(set(self.event.getAvailableCollections()), EXPECTED_COLL_NAMES)
168175
self.assertEqual(
169176
set(self.other_event.getAvailableCollections()),
170-
EXPECTED_COLL_NAMES.union(EXPECTED_EXTENSION_COLL_NAMES),
177+
EXPECTED_COLL_NAMES.union(EXPECTED_EXTENSION_COLL_NAMES).union(
178+
EXPECTED_INTERFACE_EXTENSION_COLL_NAMES
179+
),
171180
)
172181

173182
# Not going over all collections here, as that should all be covered by the

python/podio/test_Reader.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ def test_frame_iterator_invalid_category(self):
7575
def test_available_datamodels(self):
7676
"""Make sure that the datamodel information can be retrieved"""
7777
datamodels = self.reader.datamodel_definitions
78-
self.assertEqual(len(datamodels), 2)
78+
self.assertEqual(len(datamodels), 3)
7979
for model in datamodels:
80-
self.assertTrue(model in ("datamodel", "extension_model"))
80+
self.assertTrue(model in ("datamodel", "extension_model", "interface_extension_model"))
8181

8282
self.assertEqual(self.reader.current_file_version("datamodel"), build_version)
8383

python/podio_gen/cpp_generator.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,10 @@ def _preprocess_for_collection(self, datatype):
340340
self._build_include_for_class(relation.bare_type, include_from)
341341
)
342342
for int_type in relation.interface_types:
343+
int_type_include_from = self._needs_include(int_type.full_type)
343344
includes_cc.add(
344345
self._build_include_for_class(
345-
int_type.bare_type + "Collection", include_from
346+
int_type.bare_type + "Collection", int_type_include_from
346347
)
347348
)
348349
else:

python/templates/Interface.h.jinja2

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "podio/ObjectID.h"
1414
#include "podio/utilities/TypeHelpers.h"
15+
#include "podio/detail/OrderKey.h"
1516

1617
#include <memory>
1718
#include <ostream>
@@ -59,7 +60,7 @@ private:
5960
{{ macros.member_getters_concept(Members, use_get_syntax) }}
6061
virtual const std::type_info& typeInfo() const = 0;
6162
virtual bool equal(const Concept* rhs) const = 0;
62-
virtual const void* objAddress() const = 0;
63+
virtual podio::detail::OrderKey objOrderKey() const = 0;
6364
};
6465

6566
template<typename ValueT>
@@ -88,8 +89,8 @@ private:
8889
return false;
8990
}
9091

91-
const void* objAddress() const final {
92-
return m_value.m_obj.get();
92+
podio::detail::OrderKey objOrderKey() const final {
93+
return podio::detail::getOrderKey(m_value);
9394
}
9495

9596
{{ macros.member_getters_model(Members, use_get_syntax) }}
@@ -169,7 +170,7 @@ public:
169170
}
170171

171172
friend bool operator<(const {{ class.bare_type }}& lhs, const {{ class.bare_type }}& rhs) {
172-
return lhs.m_self->objAddress() < rhs.m_self->objAddress();
173+
return lhs.m_self->objOrderKey() < rhs.m_self->objOrderKey();
173174
}
174175

175176
{{ macros.member_getters(Members, use_get_syntax) }}

python/templates/Object.cc.jinja2

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,7 @@
4343
VectorMembers, use_get_syntax)}}
4444

4545
{{ utils.namespace_close(class.namespace) }}
46+
47+
podio::detail::OrderKey podio::detail::getOrderKey(const {{ class.namespace }}::{{ class.bare_type }}& obj) {
48+
return podio::detail::OrderKey{obj.m_obj.get()};
49+
}

python/templates/Object.h.jinja2

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
{% endfor %}
1313

1414
#include "podio/utilities/MaybeSharedPtr.h"
15+
#include "podio/detail/OrderKey.h"
1516

1617
#include <ostream>
1718
#include <cstdint>
@@ -22,6 +23,11 @@
2223

2324
{{ utils.forward_decls(forward_declarations) }}
2425

26+
namespace podio::detail {
27+
// Internal function used in less comparison operators of the datatypes and interface types
28+
OrderKey getOrderKey(const {{ class.namespace }}::{{ class.bare_type }}& obj);
29+
};
30+
2531
{{ utils.namespace_open(class.namespace) }}
2632
class Mutable{{ class.bare_type }};
2733
class {{ class.bare_type }}Collection;
@@ -34,9 +40,7 @@ class {{ class.bare_type }} {
3440
friend class {{ class.bare_type }}Collection;
3541
friend class {{ class.full_type }}CollectionData;
3642
friend class {{ class.bare_type }}CollectionIterator;
37-
{% for interface in using_interface_types %}
38-
friend class {{ interface }};
39-
{% endfor %}
43+
friend podio::detail::OrderKey podio::detail::getOrderKey(const {{ class.bare_type }} & obj);
4044

4145
public:
4246
using mutable_type = Mutable{{ class.bare_type }};

0 commit comments

Comments
 (0)