Skip to content

Commit

Permalink
Use compiler, not introspection, to find nested typedefs
Browse files Browse the repository at this point in the history
  • Loading branch information
wmtan committed Oct 5, 2014
1 parent 998fe2b commit 3ae5972
Show file tree
Hide file tree
Showing 24 changed files with 337 additions and 314 deletions.
1 change: 1 addition & 0 deletions DataFormats/Common/interface/PtrVector.h
Expand Up @@ -106,6 +106,7 @@ namespace edm {
typedef PtrVectorItr<T> const_iterator;
typedef PtrVectorItr<T> iterator; // make boost::sub_range happy (std allows this)
typedef Ptr<T> value_type;
typedef T member_type;
typedef void collection_type;

friend class PtrVectorItr<T>;
Expand Down
49 changes: 49 additions & 0 deletions DataFormats/Common/interface/Wrapper.h
Expand Up @@ -53,6 +53,8 @@ namespace edm {
virtual std::type_info const& dynamicTypeInfo_() const GCC11_OVERRIDE {return typeid(T);}
virtual std::type_info const& wrappedTypeInfo_() const GCC11_OVERRIDE {return typeid(Wrapper<T>);}

virtual std::type_info const& valueTypeInfo_() const GCC11_OVERRIDE;
virtual std::type_info const& memberTypeInfo_() const GCC11_OVERRIDE;
#ifndef __GCCXML__
virtual bool isMergeable_() const GCC11_OVERRIDE;
virtual bool mergeProduct_(WrapperBase const* newProduct) GCC11_OVERRIDE;
Expand Down Expand Up @@ -254,6 +256,41 @@ namespace edm {
};

#ifndef __GCCXML__

template <typename T> static yes_tag& has_value_type(typename T::value_type*);
template <typename T> static no_tag& has_value_type(...);
template <typename T> struct has_typedef_value_type {
static const bool value = sizeof(has_value_type<T>(nullptr)) == sizeof(yes_tag);
};
template <typename T, bool = has_typedef_value_type<T>::value> struct getValueType;
template <typename T> struct getValueType<T, true> {
std::type_info const& operator()() {
return typeid(typename T::value_type);
}
};
template <typename T> struct getValueType<T, false> {
std::type_info const& operator()() {
return typeid(void);
}
};

template <typename T> static yes_tag& has_member_type(typename T::member_type*);
template <typename T> static no_tag& has_member_type(...);
template <typename T> struct has_typedef_member_type {
static const bool value = sizeof(has_member_type<T>(nullptr)) == sizeof(yes_tag);
};
template <typename T, bool = has_typedef_member_type<T>::value> struct getMemberType;
template <typename T> struct getMemberType<T, true> {
std::type_info const& operator()() {
return typeid(typename T::member_type);
}
};
template <typename T> struct getMemberType<T, false> {
std::type_info const& operator()() {
return typeid(void);
}
};

template <typename T, bool (T::*)(T const&)> struct mergeProduct_function;
template <typename T> no_tag has_mergeProduct_helper(...);
template <typename T> yes_tag has_mergeProduct_helper(mergeProduct_function<T, &T::mergeProduct> * dummy);
Expand Down Expand Up @@ -310,6 +347,18 @@ namespace edm {
}
#endif

#ifndef __GCCXML__
template <typename T>
std::type_info const& Wrapper<T>::valueTypeInfo_() const {
return detail::getValueType<T>()();
}

template <typename T>
std::type_info const& Wrapper<T>::memberTypeInfo_() const {
return detail::getMemberType<T>()();
}
#endif

#ifndef __GCCXML__
template <typename T>
bool Wrapper<T>::isMergeable_() const {
Expand Down
3 changes: 2 additions & 1 deletion DataFormats/Common/interface/WrapperBase.h
Expand Up @@ -8,12 +8,13 @@ WrapperBase: The base class of all things that will be inserted into the Event.
----------------------------------------------------------------------*/

#include "DataFormats/Common/interface/EDProductfwd.h"
#include "DataFormats/Provenance/interface/ViewTypeChecker.h"

#include <typeinfo>
#include <vector>

namespace edm {
class WrapperBase {
class WrapperBase : public ViewTypeChecker {
public:
WrapperBase();
virtual ~WrapperBase();
Expand Down
2 changes: 1 addition & 1 deletion DataFormats/Common/src/WrapperBase.cc
Expand Up @@ -7,7 +7,7 @@
#include <cassert>

namespace edm {
WrapperBase::WrapperBase() {}
WrapperBase::WrapperBase() : ViewTypeChecker() {}

WrapperBase::~WrapperBase() {}

Expand Down
3 changes: 2 additions & 1 deletion DataFormats/Common/src/classes_def.xml
@@ -1,6 +1,7 @@
<lcgdict>
<class name="edm::WrapperBase" ClassVersion="2">
<class name="edm::WrapperBase" ClassVersion="3">
<version ClassVersion="2" checksum="2150796830"/>
<version ClassVersion="3" checksum="1936948526"/>
</class>
<class name="edm::EDProductGetter" ClassVersion="10">
<version ClassVersion="10" checksum="2702412727"/>
Expand Down
70 changes: 0 additions & 70 deletions DataFormats/Common/test/DictionaryTools_t.cpp
Expand Up @@ -20,11 +20,6 @@ class TestDictionaries: public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(TestDictionaries);
CPPUNIT_TEST(default_is_invalid);
CPPUNIT_TEST(no_dictionary_is_invalid);
CPPUNIT_TEST(find_nested);
CPPUNIT_TEST(burrowing);
CPPUNIT_TEST(burrowing_failure);
CPPUNIT_TEST(wrapper_type);
CPPUNIT_TEST(wrapper_type_failure);
CPPUNIT_TEST(not_a_template_instance);
CPPUNIT_TEST(demangling);
CPPUNIT_TEST_SUITE_END();
Expand All @@ -37,11 +32,6 @@ class TestDictionaries: public CppUnit::TestFixture {

void default_is_invalid();
void no_dictionary_is_invalid();
void find_nested();
void burrowing();
void burrowing_failure();
void wrapper_type();
void wrapper_type_failure();
void not_a_template_instance();
void demangling();

Expand All @@ -61,66 +51,6 @@ void TestDictionaries::no_dictionary_is_invalid() {
CPPUNIT_ASSERT(!t);
}

void TestDictionaries::find_nested() {
edm::TypeWithDict intvec(edm::TypeWithDict::byName("std::vector<int>"));
CPPUNIT_ASSERT(intvec);

edm::TypeWithDict found_type;

CPPUNIT_ASSERT(edm::find_nested_type_named("const_iterator",
intvec,
found_type));

CPPUNIT_ASSERT(!edm::find_nested_type_named("WankelRotaryEngine",
intvec,
found_type));
}

void TestDictionaries::burrowing() {
edm::TypeWithDict wrapper_type(typeid(edm::Wrapper<int>));
CPPUNIT_ASSERT(wrapper_type);
edm::TypeWithDict wrapped_type;
CPPUNIT_ASSERT(edm::find_nested_type_named("wrapped_type",
wrapper_type,
wrapped_type));
CPPUNIT_ASSERT(wrapped_type);
edm::TypeWithDict wrapped_Dict_type(wrapped_type.typeInfo());
CPPUNIT_ASSERT(!wrapped_Dict_type.isTypedef());
CPPUNIT_ASSERT(wrapped_Dict_type.isFundamental());
CPPUNIT_ASSERT(wrapped_type == edm::TypeWithDict::byName("int"));
CPPUNIT_ASSERT(wrapped_type.typeInfo() == typeid(int));
}

void TestDictionaries::burrowing_failure() {
edm::TypeWithDict not_a_wrapper(edm::TypeWithDict::byName("double"));
CPPUNIT_ASSERT(not_a_wrapper);
edm::TypeWithDict no_such_wrapped_type;
CPPUNIT_ASSERT(!no_such_wrapped_type);
CPPUNIT_ASSERT(!edm::find_nested_type_named("wrapped_type",
not_a_wrapper,
no_such_wrapped_type));
CPPUNIT_ASSERT(!no_such_wrapped_type);
}

void TestDictionaries::wrapper_type() {
edm::TypeWithDict wrapper_type(typeid(edm::Wrapper<int>));
edm::TypeWithDict wrapped_type;
CPPUNIT_ASSERT(edm::wrapper_type_of(wrapper_type, wrapped_type));
edm::TypeWithDict wrapped_Dict_type(wrapped_type.typeInfo());
CPPUNIT_ASSERT(!wrapped_Dict_type.isTypedef());
CPPUNIT_ASSERT(wrapped_type == edm::TypeWithDict::byName("int"));
}

void TestDictionaries::wrapper_type_failure() {
edm::TypeWithDict not_a_wrapper(edm::TypeWithDict::byName("double"));
CPPUNIT_ASSERT(not_a_wrapper);
edm::TypeWithDict no_such_wrapped_type;
CPPUNIT_ASSERT(!no_such_wrapped_type);
CPPUNIT_ASSERT(!edm::wrapper_type_of(not_a_wrapper,
no_such_wrapped_type));
CPPUNIT_ASSERT(!no_such_wrapped_type);
}

void TestDictionaries::not_a_template_instance() {
edm::TypeWithDict not_a_template(edm::TypeWithDict::byName("double"));
CPPUNIT_ASSERT(not_a_template);
Expand Down
32 changes: 29 additions & 3 deletions DataFormats/Provenance/interface/ProductHolderIndexHelper.h
Expand Up @@ -62,7 +62,24 @@ ProductRegistry is frozen.
#include <vector>

namespace edm {
class TypeWithDict;

namespace productholderindexhelper {
// The next function supports views. For the given wrapped type,
// which must be Wrapper<T>,
// this function returns the type of the contained type of T.
// If the type is not a recongnized container, it returns
// a TypeID(typeid(void)).
TypeID getContainedTypeFromWrapper(TypeID const& wrappedtypeID, std::string const& className);

// The next function supports views. For the given type T,
// this function returns the type of the contained type of T.
// If the type is not a recongnized container, it returns
// a TypeID(typeid(void)).
// This calls getContainedTypefromWrapped internally
// If the TypeID for the wrapped type is already available,
// it is faster to call getContainedTypeFromWrapper directly.
TypeID getContainedType(TypeID const& typeID);
}

class ProductHolderIndexHelper {
public:
Expand Down Expand Up @@ -152,10 +169,19 @@ namespace edm {
// entry with a new ProductHolderIndex for the case
// which searches for the most recent process.
ProductHolderIndex
insert(TypeWithDict const& typeWithDict,
insert(TypeID const& typeID,
char const* moduleLabel,
char const* instance,
char const* process,
TypeID const& containedTypeID);

ProductHolderIndex
insert(TypeID const& typeID,
char const* moduleLabel,
char const* instance,
char const* process);
char const* process) {
return insert(typeID, moduleLabel, instance, process, productholderindexhelper::getContainedType(typeID));
}

// Before the object is frozen the accessors above will
// fail to find a match. Once frozen, no more new entries
Expand Down
26 changes: 26 additions & 0 deletions DataFormats/Provenance/interface/ViewTypeChecker.h
@@ -0,0 +1,26 @@
#ifndef DataFormats_Provenance_ViewTypeChecker_h
#define DataFormats_Provenance_ViewTypeChecker_h

/*----------------------------------------------------------------------
Checks for "value_type" and "member_type" typedefs inside T (of Wrapper<T>).
----------------------------------------------------------------------*/

#include <typeinfo>

namespace edm {
class ViewTypeChecker {
public:
ViewTypeChecker();
virtual ~ViewTypeChecker();

std::type_info const& valueTypeInfo() const {return valueTypeInfo_();}
std::type_info const& memberTypeInfo() const {return memberTypeInfo_();}

private:
virtual std::type_info const& valueTypeInfo_() const = 0;
virtual std::type_info const& memberTypeInfo_() const = 0;
};
}
#endif
63 changes: 51 additions & 12 deletions DataFormats/Provenance/src/ProductHolderIndexHelper.cc
@@ -1,14 +1,59 @@

#include "DataFormats/Provenance/interface/ProductHolderIndexHelper.h"
#include "DataFormats/Provenance/interface/ViewTypeChecker.h"
#include "FWCore/Utilities/interface/DictionaryTools.h"
#include "FWCore/Utilities/interface/EDMException.h"
#include "FWCore/Utilities/interface/TypeWithDict.h"
#include "FWCore/Utilities/interface/WrappedClassName.h"
#include "FWCore/Utilities/interface/getAnyPtr.h"

#include <TClass.h>

#include <cassert>
#include <iostream>
#include <limits>

namespace edm {

namespace productholderindexhelper {
TypeID
getContainedTypeFromWrapper(TypeID const& wrappedTypeID, std::string const& className) {
static int const vtcOffset = TClass::GetClass("edm::WrapperBase")->GetBaseClassOffset(TClass::GetClass("edm::ViewTypeChecker"));
static TClass const* const wbClass = TClass::GetClass("edm::WrapperBase");
static std::string const refVector("edm::RefVector<");
static std::string const refToBaseVector("edm::RefToBaseVector<");
static std::string const ptrVector("edm::PtrVector<");
static size_t rvsize = refVector.size();
static size_t rtbvsize = refToBaseVector.size();
static size_t pvsize = ptrVector.size();
bool mayBeRefVector = (className.substr(0, rvsize) == refVector)
|| (className.substr(0, rtbvsize) == refToBaseVector)
|| (className.substr(0, pvsize) == ptrVector);
TClass* cl = TClass::GetClass(wrappedTypeID.className().c_str());
if(cl == nullptr) {
return TypeID(typeid(void));
}
void* p = cl->New();
int offset = cl->GetBaseClassOffset(wbClass) + vtcOffset;;
std::unique_ptr<ViewTypeChecker> checker = getAnyPtr<ViewTypeChecker>(p, offset);
if(mayBeRefVector) {
std::type_info const& ti = checker->memberTypeInfo();
if(ti != typeid(void)) {
return TypeID(ti);
}
}
return TypeID(checker->valueTypeInfo());
}

TypeID
getContainedType(TypeID const& typeID) {
std::string className = typeID.className();
TypeWithDict const wrappedType = TypeWithDict::byName(wrappedClassName(className));
TypeID const wrappedTypeID = TypeID(wrappedType.typeInfo());
return getContainedTypeFromWrapper(wrappedTypeID, className);
}
}

ProductHolderIndexHelper::ProductHolderIndexHelper() :
nextIndexValue_(0),
beginElements_(0),
Expand Down Expand Up @@ -112,10 +157,11 @@ namespace edm {
}

ProductHolderIndex
ProductHolderIndexHelper::insert(TypeWithDict const& typeWithDict,
ProductHolderIndexHelper::insert(TypeID const& typeID,
char const* moduleLabel,
char const* instance,
char const* process) {
char const* process,
TypeID const& containedTypeID) {
if (!items_) {
throw Exception(errors::LogicError)
<< "ProductHolderIndexHelper::insert - Attempt to insert more elements after frozen.\n";
Expand All @@ -126,8 +172,6 @@ namespace edm {
<< "ProductHolderIndexHelper::insert - Empty process.\n";
}

TypeID typeID(typeWithDict.typeInfo());

// Throw if this has already been inserted
Item item(PRODUCT_TYPE, typeID, moduleLabel, instance, process, 0);
std::set<Item>::iterator iter = items_->find(item);
Expand All @@ -154,14 +198,9 @@ namespace edm {

// Now put in entries for a contained class if this is a
// recognized container.
TypeWithDict containedType;
if((is_RefVector(typeWithDict, containedType) ||
is_PtrVector(typeWithDict, containedType) ||
is_RefToBaseVector(typeWithDict, containedType) ||
value_type_of(typeWithDict, containedType))
&& bool(containedType)) {

TypeID containedTypeID(containedType.typeInfo());
if(containedTypeID != TypeID(typeid(void)) && containedTypeID != TypeID()) {
TypeWithDict containedType(containedTypeID.typeInfo());

Item containedItem(ELEMENT_TYPE, containedTypeID, moduleLabel, instance, process, savedProductIndex);
iter = items_->find(containedItem);
if (iter != items_->end()) {
Expand Down

0 comments on commit 3ae5972

Please sign in to comment.