diff --git a/core/clingutils/res/TClingUtils.h b/core/clingutils/res/TClingUtils.h index 593252673bf1d..2ade7a5b70a7e 100644 --- a/core/clingutils/res/TClingUtils.h +++ b/core/clingutils/res/TClingUtils.h @@ -14,16 +14,16 @@ #include "RConversionRuleParser.h" +#include #include +#include +#include #include #include +#include #include -#include -#include -#include #include - -#include +#include #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push @@ -163,21 +163,84 @@ class TClingLookupHelper : public TClassEdit::TInterpreterLookupHelper { typedef bool (*AutoParse_t)(const char *name); private: + class Cache { + using Map_t = std::unordered_map>; + Map_t fMappingAndLRU; + int fLRUGeneration = 0; + + int IncLRUGeneration() { + if (fLRUGeneration == std::numeric_limits::max() - 1) { + // We'll have mru values of say 16556, 12, 765765, 354 + // and need to bring them down to 2, 0, 3, 1. + // For that, fill the mru values into a vector, sort it, + // and find the values back, storing their index as mru value. + std::vector mrus; + mrus.reserve(fMappingAndLRU.size()); + for (auto &&m: fMappingAndLRU) + mrus.emplace_back(m.second.first); + std::sort(mrus.begin(), mrus.end()); + for (auto &&m: fMappingAndLRU) + m.second.first = std::lower_bound(mrus.begin(), mrus.end(), m.second.first) - mrus.begin(); + fLRUGeneration = mrus.size() - 1; + } + return ++fLRUGeneration; + } + + public: + const std::string *Find(const std::string &k) { + auto i = fMappingAndLRU.find(k); + if (i != fMappingAndLRU.end()) { + if (i->second.first != fLRUGeneration) { + i->second.first = IncLRUGeneration(); + } + return &i->second.second; + } + return nullptr; + } + + void Insert(const std::string &k, const std::string &v) { + if (fMappingAndLRU.size() > 1024 * 16) { + // We'll have mru values of say 16556, 12, 765765, 354 + // and want to find the smallest. + // For that, fill the mru values into a vector, sort it, + // and take the first element, and then remove the oldest + // 1024 elements. + std::vector mrus; + mrus.reserve(fMappingAndLRU.size()); + for (auto &&m: fMappingAndLRU) + mrus.emplace_back(m.second.first); + std::sort(mrus.begin(), mrus.end()); + int oldestGenerationToKeep = mrus[1024]; + // Instead of C++20 `erase_if` + for (auto I = fMappingAndLRU.begin(), E = fMappingAndLRU.end(); I != E; ) + if (I->second.first < oldestGenerationToKeep) + I = fMappingAndLRU.erase(I); + else + ++I; + } + fMappingAndLRU[k] = std::make_pair(IncLRUGeneration(), v); + } + }; + cling::Interpreter *fInterpreter; TNormalizedCtxt *fNormalizedCtxt; ExistingTypeCheck_t fExistingTypeCheck; AutoParse_t fAutoParse; + Cache fKnownGetPartiallyDesugaredNameMappings; + Cache fKnownPartiallyDesugaredNameWithScopeHandlingMappings; bool *fInterpreterIsShuttingDownPtr; const int *fPDebug; // debug flag, might change at runtime thus * bool WantDiags() const { return fPDebug && *fPDebug > 5; } + bool GetIfCached(Cache& cache, const std::string &name, std::string &result); + public: TClingLookupHelper(cling::Interpreter &interpreter, TNormalizedCtxt &normCtxt, ExistingTypeCheck_t existingTypeCheck, AutoParse_t autoParse, bool *shuttingDownPtr, const int *pgDebug = 0); - virtual ~TClingLookupHelper() { /* we're not owner */ } + virtual ~TClingLookupHelper() = default; virtual bool ExistingTypeCheck(const std::string &tname, std::string &result); virtual void GetPartiallyDesugaredName(std::string &nameLong); diff --git a/core/clingutils/src/TClingUtils.cxx b/core/clingutils/src/TClingUtils.cxx index 2373f0cd429df..60953d5de306b 100644 --- a/core/clingutils/src/TClingUtils.cxx +++ b/core/clingutils/src/TClingUtils.cxx @@ -543,6 +543,19 @@ TClingLookupHelper::TClingLookupHelper(cling::Interpreter &interpreter, { } +//////////////////////////////////////////////////////////////////////////////// +/// Search for a known type mapping and if found, set it and return true. +/// + +bool TClingLookupHelper::GetIfCached(Cache& cache, const std::string &name, std::string &result) +{ + if (const std::string *value = cache.Find(name)) { + result = *value; + return true; + } + return false; +} + //////////////////////////////////////////////////////////////////////////////// /// Helper routine to ry hard to avoid looking up in the Cling database as /// this could enduce an unwanted autoparsing. @@ -552,22 +565,39 @@ bool TClingLookupHelper::ExistingTypeCheck(const std::string &tname, { if (tname.empty()) return false; - if (fExistingTypeCheck) return fExistingTypeCheck(tname,result); - else return false; + if (GetIfCached(fKnownPartiallyDesugaredNameWithScopeHandlingMappings, tname, result)) + return true; + + if (GetIfCached(fKnownGetPartiallyDesugaredNameMappings, tname, result)) + return true; + + if (fExistingTypeCheck && fExistingTypeCheck(tname,result)) + return true; + + return false; } //////////////////////////////////////////////////////////////////////////////// void TClingLookupHelper::GetPartiallyDesugaredName(std::string &nameLong) { + std::string result; + if (GetIfCached(fKnownGetPartiallyDesugaredNameMappings, + const_cast(nameLong), result)) { + nameLong = result; + return; + } + const cling::LookupHelper& lh = fInterpreter->getLookupHelper(); clang::QualType t = lh.findType(nameLong, ToLHDS(WantDiags())); + std::string origName = nameLong; if (!t.isNull()) { clang::QualType dest = cling::utils::Transform::GetPartiallyDesugaredType(fInterpreter->getCI()->getASTContext(), t, fNormalizedCtxt->GetConfig(), true /* fully qualify */); if (!dest.isNull() && (dest != t)) { // getAsStringInternal() appends. nameLong.clear(); dest.getAsStringInternal(nameLong, fInterpreter->getCI()->getASTContext().getPrintingPolicy()); + fKnownGetPartiallyDesugaredNameMappings.Insert(origName, nameLong); } } } @@ -577,15 +607,9 @@ void TClingLookupHelper::GetPartiallyDesugaredName(std::string &nameLong) bool TClingLookupHelper::IsAlreadyPartiallyDesugaredName(const std::string &nondef, const std::string &nameLong) { - const cling::LookupHelper& lh = fInterpreter->getLookupHelper(); - clang::QualType t = lh.findType(nondef.c_str(), ToLHDS(WantDiags())); - if (!t.isNull()) { - clang::QualType dest = cling::utils::Transform::GetPartiallyDesugaredType(fInterpreter->getCI()->getASTContext(), t, fNormalizedCtxt->GetConfig(), true /* fully qualify */); - if (!dest.isNull() && (dest != t) && - nameLong == t.getAsString(fInterpreter->getCI()->getASTContext().getPrintingPolicy())) - return true; - } - return false; + std::string nondefDesugared = nondef; + GetPartiallyDesugaredName(nondefDesugared); + return nondefDesugared == nameLong; } //////////////////////////////////////////////////////////////////////////////// @@ -615,14 +639,14 @@ bool TClingLookupHelper::GetPartiallyDesugaredNameWithScopeHandling(const std::s { if (tname.empty()) return false; + if (GetIfCached(fKnownPartiallyDesugaredNameWithScopeHandlingMappings, tname, result)) + return true; + // Try hard to avoid looking up in the Cling database as this could enduce // an unwanted autoparsing. // Note: this is always done by the callers and thus is redundant. - // Maybe replace with + // Keep it as assert: assert(! (fExistingTypeCheck && fExistingTypeCheck(tname,result)) ); - if (fExistingTypeCheck && fExistingTypeCheck(tname,result)) { - return ! result.empty(); - } if (fAutoParse) fAutoParse(tname.c_str()); @@ -683,6 +707,7 @@ bool TClingLookupHelper::GetPartiallyDesugaredNameWithScopeHandling(const std::s // TMetaUtils::GetNormalizedName(alt, dest, *fInterpreter, *fNormalizedCtxt); // if (alt != result) fprintf(stderr,"norm: %s vs result=%s\n",alt.c_str(),result.c_str()); + fKnownPartiallyDesugaredNameWithScopeHandlingMappings.Insert(tname, result); return true; } }