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
#include "CommonTools/Utils/interface/parser/MethodChain.h"
#include "CommonTools/Utils/interface/parser/MethodInvoker.h"

#include "FWCore/Reflection/interface/ObjectWithDict.h"
#include "FWCore/Reflection/interface/FunctionWithDict.h"
#include "FWCore/Reflection/interface/MemberWithDict.h"
#include "FWCore/Reflection/interface/TypeWithDict.h"

#include <cassert>
#include <map>

using namespace reco::parser;
using namespace std;

MethodChain::Objects MethodChain::initObjects_() const {
  Objects objects(methods_.size(), {edm::ObjectWithDict(), false});
  assert(objects.size() == methods_.size());
  auto IO = objects.begin();
  for (auto const& method : methods_) {
    if (method.isFunction()) {
      edm::TypeWithDict retType = method.method().finalReturnType();
      IO->second = makeStorage(IO->first, retType);
    } else {
      *IO = {edm::ObjectWithDict(), false};
    }
    ++IO;
  }
  return objects;
}

MethodChain::MethodChain(const vector<MethodInvoker>& methods) : methods_(methods) { returnObjects(initObjects_()); }

MethodChain::MethodChain(const MethodChain& rhs) : methods_(rhs.methods_) { returnObjects(initObjects_()); }

MethodChain::Objects MethodChain::borrowObjects() const {
  Objects objects;
  if (objectsCache_.try_pop(objects)) {
    return objects;
  }
  return initObjects_();
}

void MethodChain::returnObjects(Objects&& iOb) const { objectsCache_.push(std::move(iOb)); }

MethodChain::~MethodChain() {
  Objects objects;
  while (objectsCache_.try_pop(objects)) {
    for (auto& o : objects) {
      delStorage(o.first);
    }
  }
}

void MethodChain::delStorage(edm::ObjectWithDict& obj) {
  if (!obj.address()) {
    return;
  }
  if (obj.typeOf().isPointer() || obj.typeOf().isReference()) {
    // just delete a void*, as that's what it was
    void** p = static_cast<void**>(obj.address());
    delete p;
  } else {
    //std::cout << "Calling Destruct on a " <<
    //  obj.typeOf().qualifiedName() << std::endl;
    obj.typeOf().deallocate(obj.address());
  }
}

bool MethodChain::makeStorage(edm::ObjectWithDict& obj, const edm::TypeWithDict& retType) {
  static const edm::TypeWithDict tVoid(edm::TypeWithDict::byName("void"));
  bool ret = false;
  if (retType == tVoid) {
    obj = edm::ObjectWithDict::byType(tVoid);
  } else if (retType.isPointer() || retType.isReference()) {
    // in this case, I have to allocate a void*, not an object!
    obj = edm::ObjectWithDict(retType, new void*);
  } else {
    obj = edm::ObjectWithDict(retType, retType.allocate());
    ret = retType.isClass();
    //std::cout << "MethodChain: reserved memory at "  << obj.address() <<
    //  " for a " << retType.qualifiedName() << " returned by " <<
    //  member.name() << std::endl;
  }
  return ret;
}

edm::ObjectWithDict MethodChain::value(const edm::ObjectWithDict& obj) const {
  edm::ObjectWithDict val(obj);
  auto objects = borrowObjects();
  auto IO = objects.begin();
  for (auto& m : methods_) {
    val = m.invoke(val, IO->first);
    ++IO;
  }
  for (auto RI = objects.rbegin(), RE = objects.rend(); RI != RE; ++RI) {
    if (RI->second) {
      RI->first.destruct(false);
    }
  }
  returnObjects(std::move(objects));
  return val;
}

LazyMethodChain::LazyMethodChain(const std::vector<LazyInvoker>& methods) : methods_(methods) {}

LazyMethodChain::~LazyMethodChain() {}

edm::ObjectWithDict LazyMethodChain::value(const edm::ObjectWithDict& o) const {
  edm::ObjectWithDict val = o;
  std::vector<StorageManager> storage;
  storage.reserve(methods_.size());

  std::vector<LazyInvoker>::const_iterator I = methods_.begin();
  std::vector<LazyInvoker>::const_iterator E = methods_.end();
  for (; I < E; ++I) {
    val = I->invoke(val, storage);
  }
  while (not storage.empty()) {
    storage.pop_back();
  }
  return val;
}