Skip to content

Commit 6eea5fa

Browse files
authored
Merge pull request #46702 from patinkaew/nanoaod_dev_collection_14_2_0_pre3
Add support for adding variable-size attributes (std::vector) within objects for NanoAOD
2 parents 2e78b5b + 4245ed3 commit 6eea5fa

File tree

8 files changed

+615
-0
lines changed

8 files changed

+615
-0
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#ifndef CommonTools_Utils_TypedStringObjectMethodCaller_h
2+
#define CommonTools_Utils_TypedStringObjectMethodCaller_h
3+
/* \class TypedStringObjectMethodCaller
4+
*
5+
* Object's method (or a chain of methods) caller functor with generic return-type, specified by string expression
6+
*
7+
*/
8+
9+
#include "FWCore/Utilities/interface/EDMException.h"
10+
#include "CommonTools/Utils/interface/parser/Exception.h"
11+
#include "CommonTools/Utils/interface/parser/MethodChain.h"
12+
#include "CommonTools/Utils/interface/parser/MethodChainGrammar.h"
13+
#include "FWCore/Reflection/interface/ObjectWithDict.h"
14+
15+
template <typename T, typename R, bool DefaultLazyness = false>
16+
struct TypedStringObjectMethodCaller {
17+
TypedStringObjectMethodCaller(const std::string expr, bool lazy = DefaultLazyness) : type_(typeid(T)) {
18+
using namespace boost::spirit::classic;
19+
reco::parser::MethodChainGrammar grammar(methodchain_, type_, lazy);
20+
const char* startingFrom = expr.c_str();
21+
try {
22+
if (!parse(startingFrom, grammar >> end_p, space_p).full) {
23+
throw edm::Exception(edm::errors::Configuration, "failed to parse \"" + expr + "\"");
24+
}
25+
} catch (reco::parser::BaseException& e) {
26+
throw edm::Exception(edm::errors::Configuration)
27+
<< "MethodChainGrammer parse error:" << reco::parser::baseExceptionWhat(e) << " (char "
28+
<< e.where - startingFrom << ")\n";
29+
}
30+
}
31+
32+
R operator()(const T& t) const {
33+
edm::ObjectWithDict o(type_, const_cast<T*>(&t));
34+
edm::ObjectWithDict ret = methodchain_->value(o);
35+
return *static_cast<R*>(ret.address());
36+
}
37+
38+
private:
39+
reco::parser::MethodChainPtr methodchain_;
40+
edm::TypeWithDict type_;
41+
};
42+
43+
#endif
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#ifndef CommonTools_Utils_MethodChain_h
2+
#define CommonTools_Utils_MethodChain_h
3+
4+
/* \class reco::parser::MethodChain
5+
*
6+
* Chain of methods
7+
* Based on ExpressionBase and ExpressionVar, but remove final conversion to double
8+
*
9+
*/
10+
11+
#include "CommonTools/Utils/interface/parser/MethodInvoker.h"
12+
#include "CommonTools/Utils/interface/TypeCode.h"
13+
14+
#include <vector>
15+
#include <oneapi/tbb/concurrent_queue.h>
16+
17+
namespace reco {
18+
namespace parser {
19+
20+
/// Based on Expression, but its value method returns an edm::ObjectWithDict instead of a double
21+
class MethodChainBase {
22+
public: // Public Methods
23+
virtual ~MethodChainBase() {}
24+
virtual edm::ObjectWithDict value(const edm::ObjectWithDict&) const = 0;
25+
};
26+
27+
/// Shared ptr to MethodChainBase
28+
typedef std::shared_ptr<MethodChainBase> MethodChainPtr;
29+
30+
/// Evaluate an object's method or datamember (or chain of them)
31+
class MethodChain : public MethodChainBase {
32+
private: // Private Data Members
33+
std::vector<MethodInvoker> methods_;
34+
using Objects = std::vector<std::pair<edm::ObjectWithDict, bool>>;
35+
mutable oneapi::tbb::concurrent_queue<Objects> objectsCache_;
36+
37+
private: // Private Methods
38+
[[nodiscard]] Objects initObjects_() const;
39+
40+
Objects borrowObjects() const;
41+
void returnObjects(Objects&&) const;
42+
43+
public: // Public Static Methods
44+
/// allocate an object to hold the result of a given member (if needed)
45+
/// this method is used also from the LazyInvoker code
46+
/// returns true if objects returned from this will require a destructor
47+
static bool makeStorage(edm::ObjectWithDict& obj, const edm::TypeWithDict& retType);
48+
49+
/// delete an objecty, if needed
50+
/// this method is used also from the LazyInvoker code
51+
static void delStorage(edm::ObjectWithDict&);
52+
53+
public: // Public Methods
54+
MethodChain(const std::vector<MethodInvoker>& methods);
55+
MethodChain(const MethodChain&);
56+
~MethodChain();
57+
edm::ObjectWithDict value(const edm::ObjectWithDict&) const override;
58+
};
59+
60+
/// Same as MethodChain but with lazy resolution of object methods
61+
/// using the dynamic type of the object, and not the one fixed at compile time
62+
class LazyMethodChain : public MethodChainBase {
63+
private: // Private Data Members
64+
std::vector<LazyInvoker> methods_;
65+
66+
public:
67+
LazyMethodChain(const std::vector<LazyInvoker>& methods);
68+
~LazyMethodChain() override;
69+
edm::ObjectWithDict value(const edm::ObjectWithDict&) const override;
70+
};
71+
72+
} // namespace parser
73+
} // namespace reco
74+
75+
#endif // CommonTools_Utils_MethodChain_h
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#ifndef CommonTools_Utils_MethodChainGrammar_h
2+
#define CommonTools_Utils_MethodChainGrammar_h
3+
/* \class MethodChainGrammer
4+
*
5+
* subset grammar of the full Grammer (CommonTools/Utils/interface/parser/Grammar.h), allowing only a chain of methods
6+
*
7+
*/
8+
9+
#include "boost/spirit/include/classic_core.hpp"
10+
#include "boost/spirit/include/classic_grammar_def.hpp"
11+
#include "boost/spirit/include/classic_chset.hpp"
12+
#include "FWCore/Utilities/interface/EDMException.h"
13+
#include "FWCore/Reflection/interface/ObjectWithDict.h"
14+
#include "CommonTools/Utils/interface/parser/MethodChain.h"
15+
#include "CommonTools/Utils/interface/parser/MethodChainSetter.h"
16+
#include "CommonTools/Utils/interface/parser/MethodSetter.h"
17+
#include "CommonTools/Utils/interface/parser/MethodArgumentSetter.h"
18+
#include "CommonTools/Utils/interface/parser/MethodInvoker.h"
19+
#include "CommonTools/Utils/interface/parser/MethodStack.h"
20+
#include "CommonTools/Utils/interface/parser/TypeStack.h"
21+
#include "CommonTools/Utils/interface/parser/MethodArgumentStack.h"
22+
#include "CommonTools/Utils/interface/parser/AnyMethodArgument.h"
23+
#include "CommonTools/Utils/interface/parser/Exception.h"
24+
25+
namespace reco {
26+
namespace parser {
27+
struct MethodChainGrammar : public boost::spirit::classic::grammar<MethodChainGrammar> {
28+
MethodChainPtr* methchain_;
29+
bool lazy_;
30+
mutable MethodStack methStack;
31+
mutable LazyMethodStack lazyMethStack;
32+
mutable MethodArgumentStack methArgStack;
33+
mutable TypeStack typeStack;
34+
35+
MethodChainGrammar(MethodChainPtr& methchain, const edm::TypeWithDict& iType, bool lazy = false)
36+
: methchain_(&methchain), lazy_(lazy) {
37+
typeStack.push_back(iType);
38+
}
39+
40+
template <typename ScannerT>
41+
struct definition {
42+
typedef boost::spirit::classic::rule<ScannerT> rule;
43+
rule metharg, method, arrayAccess, methodchain;
44+
definition(const MethodChainGrammar& self) {
45+
using namespace boost::spirit::classic;
46+
47+
MethodArgumentSetter methodArg_s(self.methArgStack);
48+
MethodSetter method_s(self.methStack, self.lazyMethStack, self.typeStack, self.methArgStack, self.lazy_);
49+
MethodChainSetter methodchain_s(*self.methchain_, self.methStack, self.lazyMethStack, self.typeStack);
50+
51+
BOOST_SPIRIT_DEBUG_RULE(methodchain);
52+
BOOST_SPIRIT_DEBUG_RULE(arrayAccess);
53+
BOOST_SPIRIT_DEBUG_RULE(method);
54+
BOOST_SPIRIT_DEBUG_RULE(metharg);
55+
56+
boost::spirit::classic::assertion<SyntaxErrors> expectParenthesis(kMissingClosingParenthesis);
57+
boost::spirit::classic::assertion<SyntaxErrors> expect(kSyntaxError);
58+
59+
metharg = (strict_real_p[methodArg_s]) | (int_p[methodArg_s]) |
60+
(ch_p('"') >> *(~ch_p('"')) >> ch_p('"'))[methodArg_s] |
61+
(ch_p('\'') >> *(~ch_p('\'')) >> ch_p('\''))[methodArg_s];
62+
method = // alnum_p doesn't accept underscores, so we use chset<>; lexeme_d needed to avoid whitespace skipping within method names
63+
(lexeme_d[alpha_p >> *chset<>("a-zA-Z0-9_")] >> ch_p('(') >> metharg >> *(ch_p(',') >> metharg) >>
64+
expectParenthesis(ch_p(')')))[method_s] |
65+
((lexeme_d[alpha_p >> *chset<>("a-zA-Z0-9_")])[method_s] >> !(ch_p('(') >> ch_p(')')));
66+
arrayAccess = (ch_p('[') >> metharg >> *(ch_p(',') >> metharg) >> expectParenthesis(ch_p(']')))[method_s];
67+
methodchain = (method >> *(arrayAccess | (ch_p('.') >> expect(method))))[methodchain_s];
68+
}
69+
70+
rule const& start() const { return methodchain; }
71+
};
72+
};
73+
} // namespace parser
74+
} // namespace reco
75+
76+
#endif
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#ifndef CommonTools_Utils_MethodChainSetter_h
2+
#define CommonTools_Utils_MethodChainSetter_h
3+
/* \class reco::parser::MethodChainSetter
4+
*
5+
* Method Chain setter, used to construct MethodChain when parsing with boost::spirit
6+
*
7+
*/
8+
#include "CommonTools/Utils/interface/parser/MethodChain.h"
9+
#include "CommonTools/Utils/interface/parser/MethodStack.h"
10+
#include "CommonTools/Utils/interface/parser/TypeStack.h"
11+
12+
#include <iostream>
13+
14+
namespace reco {
15+
namespace parser {
16+
struct MethodChainSetter {
17+
MethodChainSetter(MethodChainPtr &methchain,
18+
MethodStack &methStack,
19+
LazyMethodStack &lazyMethStack,
20+
TypeStack &typeStack)
21+
: methchain_(methchain), methStack_(methStack), lazyMethStack_(lazyMethStack), typeStack_(typeStack) {}
22+
void operator()(const char *, const char *) const;
23+
24+
private:
25+
void push(const char *, const char *) const;
26+
void lazyPush(const char *, const char *) const;
27+
28+
MethodChainPtr &methchain_;
29+
MethodStack &methStack_;
30+
LazyMethodStack &lazyMethStack_;
31+
TypeStack &typeStack_;
32+
};
33+
} // namespace parser
34+
} // namespace reco
35+
36+
#endif
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#include "CommonTools/Utils/interface/parser/MethodChain.h"
2+
#include "CommonTools/Utils/interface/parser/MethodInvoker.h"
3+
4+
#include "FWCore/Reflection/interface/ObjectWithDict.h"
5+
#include "FWCore/Reflection/interface/FunctionWithDict.h"
6+
#include "FWCore/Reflection/interface/MemberWithDict.h"
7+
#include "FWCore/Reflection/interface/TypeWithDict.h"
8+
9+
#include <cassert>
10+
#include <map>
11+
12+
using namespace reco::parser;
13+
using namespace std;
14+
15+
MethodChain::Objects MethodChain::initObjects_() const {
16+
Objects objects(methods_.size(), {edm::ObjectWithDict(), false});
17+
assert(objects.size() == methods_.size());
18+
auto IO = objects.begin();
19+
for (auto const& method : methods_) {
20+
if (method.isFunction()) {
21+
edm::TypeWithDict retType = method.method().finalReturnType();
22+
IO->second = makeStorage(IO->first, retType);
23+
} else {
24+
*IO = {edm::ObjectWithDict(), false};
25+
}
26+
++IO;
27+
}
28+
return objects;
29+
}
30+
31+
MethodChain::MethodChain(const vector<MethodInvoker>& methods) : methods_(methods) { returnObjects(initObjects_()); }
32+
33+
MethodChain::MethodChain(const MethodChain& rhs) : methods_(rhs.methods_) { returnObjects(initObjects_()); }
34+
35+
MethodChain::Objects MethodChain::borrowObjects() const {
36+
Objects objects;
37+
if (objectsCache_.try_pop(objects)) {
38+
return objects;
39+
}
40+
return initObjects_();
41+
}
42+
43+
void MethodChain::returnObjects(Objects&& iOb) const { objectsCache_.push(std::move(iOb)); }
44+
45+
MethodChain::~MethodChain() {
46+
Objects objects;
47+
while (objectsCache_.try_pop(objects)) {
48+
for (auto& o : objects) {
49+
delStorage(o.first);
50+
}
51+
}
52+
}
53+
54+
void MethodChain::delStorage(edm::ObjectWithDict& obj) {
55+
if (!obj.address()) {
56+
return;
57+
}
58+
if (obj.typeOf().isPointer() || obj.typeOf().isReference()) {
59+
// just delete a void*, as that's what it was
60+
void** p = static_cast<void**>(obj.address());
61+
delete p;
62+
} else {
63+
//std::cout << "Calling Destruct on a " <<
64+
// obj.typeOf().qualifiedName() << std::endl;
65+
obj.typeOf().deallocate(obj.address());
66+
}
67+
}
68+
69+
bool MethodChain::makeStorage(edm::ObjectWithDict& obj, const edm::TypeWithDict& retType) {
70+
static const edm::TypeWithDict tVoid(edm::TypeWithDict::byName("void"));
71+
bool ret = false;
72+
if (retType == tVoid) {
73+
obj = edm::ObjectWithDict::byType(tVoid);
74+
} else if (retType.isPointer() || retType.isReference()) {
75+
// in this case, I have to allocate a void*, not an object!
76+
obj = edm::ObjectWithDict(retType, new void*);
77+
} else {
78+
obj = edm::ObjectWithDict(retType, retType.allocate());
79+
ret = retType.isClass();
80+
//std::cout << "MethodChain: reserved memory at " << obj.address() <<
81+
// " for a " << retType.qualifiedName() << " returned by " <<
82+
// member.name() << std::endl;
83+
}
84+
return ret;
85+
}
86+
87+
edm::ObjectWithDict MethodChain::value(const edm::ObjectWithDict& obj) const {
88+
edm::ObjectWithDict val(obj);
89+
auto objects = borrowObjects();
90+
auto IO = objects.begin();
91+
for (auto& m : methods_) {
92+
val = m.invoke(val, IO->first);
93+
++IO;
94+
}
95+
for (auto RI = objects.rbegin(), RE = objects.rend(); RI != RE; ++RI) {
96+
if (RI->second) {
97+
RI->first.destruct(false);
98+
}
99+
}
100+
returnObjects(std::move(objects));
101+
return val;
102+
}
103+
104+
LazyMethodChain::LazyMethodChain(const std::vector<LazyInvoker>& methods) : methods_(methods) {}
105+
106+
LazyMethodChain::~LazyMethodChain() {}
107+
108+
edm::ObjectWithDict LazyMethodChain::value(const edm::ObjectWithDict& o) const {
109+
edm::ObjectWithDict val = o;
110+
std::vector<StorageManager> storage;
111+
storage.reserve(methods_.size());
112+
113+
std::vector<LazyInvoker>::const_iterator I = methods_.begin();
114+
std::vector<LazyInvoker>::const_iterator E = methods_.end();
115+
for (; I < E; ++I) {
116+
val = I->invoke(val, storage);
117+
}
118+
while (not storage.empty()) {
119+
storage.pop_back();
120+
}
121+
return val;
122+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include "CommonTools/Utils/interface/parser/MethodChainSetter.h"
2+
#include "CommonTools/Utils/interface/parser/MethodChain.h"
3+
#include "CommonTools/Utils/interface/returnType.h"
4+
#include "CommonTools/Utils/interface/parser/Exception.h"
5+
#include <string>
6+
7+
using namespace reco::parser;
8+
using namespace std;
9+
10+
void MethodChainSetter::operator()(const char *begin, const char *end) const {
11+
//std::cerr << "MethodChainSetter: Pushed [" << std::string(begin,end) << "]" << std::endl;
12+
if (!methStack_.empty())
13+
push(begin, end);
14+
else if (!lazyMethStack_.empty())
15+
lazyPush(begin, end);
16+
else
17+
throw Exception(begin) << " Expression didn't parse neither hastily nor lazyly. This must not happen.\n";
18+
}
19+
20+
void MethodChainSetter::push(const char *begin, const char *end) const {
21+
methchain_ = std::shared_ptr<MethodChainBase>(new MethodChain(methStack_));
22+
methStack_.clear();
23+
typeStack_.resize(1);
24+
}
25+
26+
void MethodChainSetter::lazyPush(const char *begin, const char *end) const {
27+
methchain_ = std::shared_ptr<MethodChainBase>(new LazyMethodChain(lazyMethStack_));
28+
lazyMethStack_.clear();
29+
typeStack_.resize(1);
30+
}

0 commit comments

Comments
 (0)