LazyInvoker

MethodInvoker

SingleInvoker

StorageManager

TypeIDHasher

Macros

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
#ifndef CommonTools_Utils_MethodInvoker_h
#define CommonTools_Utils_MethodInvoker_h

#include "CommonTools/Utils/interface/parser/AnyMethodArgument.h"
#include "CommonTools/Utils/interface/TypeCode.h"
#include "FWCore/Reflection/interface/FunctionWithDict.h"
#include "FWCore/Reflection/interface/MemberWithDict.h"
#include "FWCore/Reflection/interface/ObjectWithDict.h"
#include "FWCore/Utilities/interface/TypeID.h"

#include <map>
#include <vector>

#include "oneapi/tbb/concurrent_unordered_map.h"
#include "oneapi/tbb/concurrent_queue.h"

namespace edm {
  struct TypeIDHasher {
    size_t operator()(TypeID const& tid) const { return std::hash<std::string>{}(std::string(tid.name())); }
  };
}  // namespace edm

namespace reco {
  namespace parser {

    class MethodInvoker {
    private:  // Private Data Members
      edm::FunctionWithDict method_;
      edm::MemberWithDict member_;
      std::vector<AnyMethodArgument> ints_;  // already fixed to the correct type
      std::vector<void*> args_;

      bool isFunction_;
      edm::TypeWithDict retTypeFinal_;

    private:  // Private Function Members
      void setArgs();

    public:  // Public Function Members
      explicit MethodInvoker(const edm::FunctionWithDict& method,
                             const std::vector<AnyMethodArgument>& ints = std::vector<AnyMethodArgument>());
      explicit MethodInvoker(const edm::MemberWithDict&);
      MethodInvoker(const MethodInvoker&);
      MethodInvoker& operator=(const MethodInvoker&);

      edm::FunctionWithDict const method() const { return method_; }
      edm::MemberWithDict const member() const { return member_; }
      bool isFunction() const { return isFunction_; }
      std::string methodName() const;
      std::string returnTypeName() const;

      /// Invokes the method, putting the result in retval.
      /// Returns the Object that points to the result value,
      /// after removing any "*" and "&"
      /// Caller code is responsible for allocating retstore
      /// before calling 'invoke', and of deallocating it afterwards
      edm::ObjectWithDict invoke(const edm::ObjectWithDict& obj, edm::ObjectWithDict& retstore) const;
    };

    struct SingleInvoker;

    //Handles temporary object storage
    struct StorageManager {
    private:
      edm::ObjectWithDict object_;
      SingleInvoker const* invoker_;
      bool needsDestructor_;

    public:
      StorageManager(edm::ObjectWithDict const& iObj, SingleInvoker const* iInvoker, bool iNeedsDestructor_)
          : object_(iObj), invoker_(iInvoker), needsDestructor_(iNeedsDestructor_) {}

      StorageManager(const StorageManager&) = delete;
      StorageManager(StorageManager&& iOther)
          : object_(iOther.object_), invoker_(iOther.invoker_), needsDestructor_(iOther.needsDestructor_) {
        iOther.needsDestructor_ = false;
        iOther.invoker_ = nullptr;
      }
      StorageManager& operator=(const StorageManager&) = delete;
      StorageManager& operator=(StorageManager&&) = delete;

      ~StorageManager();
    };
    /// A bigger brother of the MethodInvoker:
    /// - it owns also the object in which to store the result
    /// - it handles by itself the popping out of Refs and Ptrs
    /// in this way, it can map 1-1 to a name and set of args
    struct SingleInvoker {
    private:  // Private Data Members
      method::TypeCode retType_;
      std::vector<MethodInvoker> invokers_;
      mutable oneapi::tbb::concurrent_queue<edm::ObjectWithDict> storage_;
      bool storageNeedsDestructor_;
      /// true if this invoker just pops out a ref and returns (ref.get(), false)
      bool isRefGet_;

      edm::ObjectWithDict borrowStorage() const;

      edm::ObjectWithDict createStorage(bool& needsDestructor) const;

    public:
      SingleInvoker(const SingleInvoker&) = delete;
      SingleInvoker& operator=(const SingleInvoker&) = delete;

      SingleInvoker(const edm::TypeWithDict&, const std::string& name, const std::vector<AnyMethodArgument>& args);
      ~SingleInvoker();

      /// If the member is found in object o, evaluate and
      /// return (value,true)
      /// If the member is not found but o is a Ref/RefToBase/Ptr,
      /// (return o.get(), false)
      /// the actual edm::ObjectWithDict where the result is stored
      /// will be pushed in vector so that, if needed, its destructor
      /// can be called
      std::pair<edm::ObjectWithDict, bool> invoke(const edm::ObjectWithDict& o, std::vector<StorageManager>& v) const;

      /// convert the output of invoke to a double, if possible
      double retToDouble(const edm::ObjectWithDict&) const;

      void throwFailedConversion(const edm::ObjectWithDict&) const;

      void returnStorage(edm::ObjectWithDict&&) const;
    };

    /// Keeps different SingleInvokers for each dynamic type of the objects passed to invoke()
    struct LazyInvoker {
      typedef std::shared_ptr<SingleInvoker> SingleInvokerPtr;
      typedef tbb::concurrent_unordered_map<edm::TypeID, SingleInvokerPtr, edm::TypeIDHasher> InvokerMap;

    private:  // Private Data Members
      std::string name_;
      std::vector<AnyMethodArgument> argsBeforeFixups_;
      // the shared ptr is only to make the code exception safe
      // otherwise I think it could leak if the constructor of
      // SingleInvoker throws an exception (which can happen)
      mutable InvokerMap invokers_;

    private:  // Private Function Members
      const SingleInvoker& invoker(const edm::TypeWithDict&) const;

    public:  // Public Function Members
      explicit LazyInvoker(const std::string& name, const std::vector<AnyMethodArgument>& args);
      ~LazyInvoker();

      /// invoke method, returns object that points to result
      /// (after stripping '*' and '&')
      /// the object is still owned by the LazyInvoker
      /// the actual edm::ObjectWithDict where the result is
      /// stored will be pushed in vector
      /// so that, if needed, its destructor can be called
      edm::ObjectWithDict invoke(const edm::ObjectWithDict& o, std::vector<StorageManager>& v) const;

      /// invoke and coerce result to double
      double invokeLast(const edm::ObjectWithDict& o, std::vector<StorageManager>& v) const;
    };

  }  // namespace parser
}  // namespace reco

#endif  // CommonTools_Utils_MethodInvoker_h