Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 69 additions & 6 deletions core/clingutils/res/TClingUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@

#include "RConversionRuleParser.h"

#include <cstdlib>
#include <functional>
#include <list>
#include <map>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <list>
#include <map>
#include <utility>

#include <cstdlib>
#include <vector>

#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
Expand Down Expand Up @@ -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<std::string, std::pair<int, std::string>>;
Map_t fMappingAndLRU;
int fLRUGeneration = 0;

int IncLRUGeneration() {
if (fLRUGeneration == std::numeric_limits<int>::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<int> 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<int> 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);
Expand Down
55 changes: 40 additions & 15 deletions core/clingutils/src/TClingUtils.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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<const std::string&>(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);
}
}
}
Expand All @@ -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;
}

////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -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());

Expand Down Expand Up @@ -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;
}
}
Expand Down