#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "TClassEdit.h"
#include <ctype.h>
#include "Rstrstream.h"
#include <set>
#include <memory>
#include "RStringView.h"
namespace {
static TClassEdit::TInterpreterLookupHelper *gInterpreterHelper = 0;
}
namespace std {} using namespace std;
static size_t StdLen(const std::string_view name)
{
size_t len = 0;
if (name.compare(0,5,"std::")==0) {
len = 5;
if (gInterpreterHelper) {
for(size_t i = 5; i < name.length(); ++i) {
if (name[i] == '<') break;
if (name[i] == ':') {
bool isInlined;
std::string scope(name.data(),i);
std::string scoperesult;
static std::set<std::string> gInlined;
if (gInlined.find(scope) != gInlined.end()) {
len = i;
if (i+1<name.length() && name[i+1]==':') {
len += 2;
}
}
if (!gInterpreterHelper->ExistingTypeCheck(scope, scoperesult)
&& gInterpreterHelper->IsDeclaredScope(scope,isInlined)) {
if (isInlined) {
gInlined.insert(scope);
len = i;
if (i+1<name.length() && name[i+1]==':') {
len += 2;
}
}
}
}
}
}
}
return len;
}
static void RemoveStd(std::string &name, size_t pos = 0)
{
size_t len = StdLen({name.data()+pos,name.length()-pos});
if (len) {
name.erase(pos,len);
}
}
static void RemoveStd(std::string_view &name)
{
size_t len = StdLen(name);
if (len) {
name.remove_prefix(len);
}
}
TClassEdit::EComplexType TClassEdit::GetComplexType(const char* clName)
{
if (0 == strncmp(clName, "complex<", 8)) {
const char *clNamePlus8 = clName + 8;
if (0 == strcmp("float>", clNamePlus8)) {
return EComplexType::kFloat;
}
if (0 == strcmp("double>", clNamePlus8)) {
return EComplexType::kDouble;
}
if (0 == strcmp("int>", clNamePlus8)) {
return EComplexType::kInt;
}
if (0 == strcmp("long>", clNamePlus8)) {
return EComplexType::kLong;
}
}
return EComplexType::kNone;
}
void TClassEdit::Init(TClassEdit::TInterpreterLookupHelper *helper)
{
gInterpreterHelper = helper;
}
TClassEdit::TSplitType::TSplitType(const char *type2split, EModType mode) : fName(type2split), fNestedLocation(0)
{
TClassEdit::GetSplit(type2split, fElements, fNestedLocation, mode);
}
ROOT::ESTLType TClassEdit::TSplitType::IsInSTL() const
{
if (fElements[0].empty()) return ROOT::kNotSTL;
return STLKind(fElements[0]);
}
int TClassEdit::TSplitType::IsSTLCont(int testAlloc) const
{
if (fElements[0].empty()) return 0;
int numb = fElements.size();
if (!fElements[numb-1].empty() && fElements[numb-1][0]=='*') --numb;
if ( fNestedLocation ) {
return 0;
}
int kind = STLKind(fElements[0]);
if (kind==ROOT::kSTLvector || kind==ROOT::kSTLlist || kind==ROOT::kSTLforwardlist) {
int nargs = STLArgs(kind);
if (testAlloc && (numb-1 > nargs) && !IsDefAlloc(fElements[numb-1].c_str(),fElements[1].c_str())) {
kind = -kind;
} else {
int k = TClassEdit::IsSTLCont(fElements[1].c_str(),testAlloc);
if (k<0) kind = -kind;
}
}
if(kind>2) kind = - kind;
return kind;
}
#include <iostream>
void TClassEdit::TSplitType::ShortType(std::string &answ, int mode)
{
answ.clear();
int narg = fElements.size();
int tailLoc = 0;
if (narg == 0) {
answ = fName;
return ;
}
if (fElements[narg-1].empty() == false &&
(fElements[narg-1][0]=='*'
|| fElements[narg-1][0]=='&'
|| fElements[narg-1][0]=='['
|| 0 == fElements[narg-1].compare(0,6,"const*")
|| 0 == fElements[narg-1].compare(0,6,"const&")
|| 0 == fElements[narg-1].compare(0,6,"const[")
|| 0 == fElements[narg-1].compare("const")
)
) {
if ((mode&1)==0) tailLoc = narg-1;
}
else { assert(fElements[narg-1].empty()); };
narg--;
mode &= (~1);
if (fNestedLocation) narg--;
const int kind = STLKind(fElements[0]);
const int iall = STLArgs(kind);
if (mode&(8|16)) {
while(narg-1>iall) { fElements.pop_back(); narg--;}
if (!fElements[0].empty() && tailLoc) {
tailLoc = 0;
}
fElements[0].clear();
mode&=(~8);
}
if (mode & kDropAllDefault) mode |= kDropStlDefault;
if (mode & kDropStlDefault) mode |= kDropDefaultAlloc;
if (kind) {
bool allocRemoved = false;
if ( mode & (kDropDefaultAlloc|kDropAlloc) ) {
if (narg-1 == iall+1) {
bool dropAlloc = false;
if (mode & kDropAlloc) {
dropAlloc = true;
} else if (mode & kDropDefaultAlloc) {
switch (kind) {
case ROOT::kSTLvector:
case ROOT::kSTLlist:
case ROOT::kSTLforwardlist:
case ROOT::kSTLdeque:
case ROOT::kSTLset:
case ROOT::kSTLmultiset:
case ROOT::kSTLunorderedset:
case ROOT::kSTLunorderedmultiset:
dropAlloc = IsDefAlloc(fElements[iall+1].c_str(),fElements[1].c_str());
break;
case ROOT::kSTLmap:
case ROOT::kSTLmultimap:
case ROOT::kSTLunorderedmap:
case ROOT::kSTLunorderedmultimap:
dropAlloc = IsDefAlloc(fElements[iall+1].c_str(),fElements[1].c_str(),fElements[2].c_str());
break;
default:
dropAlloc = false;
}
}
if (dropAlloc) {
narg--;
allocRemoved = true;
}
} else {
allocRemoved = true;
}
}
if ( allocRemoved && (mode & kDropStlDefault) && narg-1 == iall) {
if ( IsDefComp( fElements[iall].c_str(), fElements[1].c_str() ) ) {
narg--;
}
} else if ( mode & kDropComparator ) {
switch (kind) {
case ROOT::kSTLvector:
case ROOT::kSTLlist:
case ROOT::kSTLforwardlist:
case ROOT::kSTLdeque:
break;
case ROOT::kSTLset:
case ROOT::kSTLmultiset:
case ROOT::kSTLmap:
case ROOT::kSTLmultimap:
if (!allocRemoved && narg-1 == iall+1) {
narg--;
allocRemoved = true;
}
if (narg-1 == iall) narg--;
break;
default:
break;
}
}
if (kind == ROOT::kSTLunorderedset || kind == ROOT::kSTLunorderedmultiset || kind == ROOT::kSTLunorderedmap || kind == ROOT::kSTLunorderedmultimap){
bool predRemoved = false;
if ( allocRemoved && (mode & kDropStlDefault) && narg-1 == iall) {
if ( IsDefPred( fElements[iall].c_str(), fElements[1].c_str() ) ) {
predRemoved=true;
narg--;
}
}
if ( predRemoved && (mode & kDropStlDefault) && narg == iall) {
if ( IsDefHash( fElements[iall-1].c_str(), fElements[1].c_str() ) ) {
narg--;
}
}
}
}
else {
if ( (mode & kDropStlDefault) && (narg >= 3)) {
unsigned int offset = (0==strncmp("const ",fElements[0].c_str(),6)) ? 6 : 0;
offset += (0==strncmp("std::",fElements[0].c_str()+offset,5)) ? 5 : 0;
if (0 == strcmp(fElements[0].c_str()+offset,"__shared_ptr"))
{
#ifdef _CONCURRENCE_H
static const std::string sharedPtrDef = std::to_string(__gnu_cxx::__default_lock_policy);
#else
static const std::string sharedPtrDef = std::to_string(2);
#endif
if (fElements[2] == sharedPtrDef) {
narg--;
}
}
}
}
for (int i=1;i<narg; i++) {
if (strchr(fElements[i].c_str(),'<')==0) {
if (mode&kDropStd) {
unsigned int offset = (0==strncmp("const ",fElements[i].c_str(),6)) ? 6 : 0;
RemoveStd( fElements[i], offset );
}
if (mode&kResolveTypedef) {
fElements[i] = ResolveTypedef(fElements[i].c_str(),true);
}
continue;
}
fElements[i] = TClassEdit::ShortType(fElements[i].c_str(),mode | TClassEdit::kKeepOuterConst);
if (mode&kResolveTypedef) {
string typeresult;
if (gInterpreterHelper->ExistingTypeCheck(fElements[i], typeresult)
|| gInterpreterHelper->GetPartiallyDesugaredNameWithScopeHandling(fElements[i], typeresult)) {
if (!typeresult.empty()) fElements[i] = typeresult;
}
}
}
unsigned int tailOffset = 0;
if (tailLoc && fElements[tailLoc].compare(0,5,"const") == 0) {
if (mode & kKeepOuterConst) answ += "const ";
tailOffset = 5;
}
if (!fElements[0].empty()) {answ += fElements[0]; answ +="<";}
#if 0
if (mode & kDropAllDefault) {
int nargNonDefault = 0;
std::string nonDefName = answ;
std::string nameSuperLong = fName;
if (gInterpreterHelper)
gInterpreterHelper->GetPartiallyDesugaredName(nameSuperLong);
while (++nargNonDefault < narg) {
const char* closeTemplate = " >";
if (nonDefName[nonDefName.length() - 1] != '>')
++closeTemplate;
string nondef = nonDefName + closeTemplate;
if (gInterpreterHelper &&
gInterpreterHelper->IsAlreadyPartiallyDesugaredName(nondef, nameSuperLong))
break;
if (nargNonDefault>1) nonDefName += ",";
nonDefName += fElements[nargNonDefault];
}
if (nargNonDefault < narg)
narg = nargNonDefault;
}
#endif
{ for (int i=1;i<narg-1; i++) { answ += fElements[i]; answ+=",";} }
if (narg>1) { answ += fElements[narg-1]; }
if (!fElements[0].empty()) {
if ( answ.at(answ.size()-1) == '>') {
answ += " >";
} else {
answ += '>';
}
}
if (fNestedLocation) {
fElements[fNestedLocation] = TClassEdit::ShortType(fElements[fNestedLocation].c_str(),mode);
answ += fElements[fNestedLocation];
}
if (tailLoc) answ += fElements[tailLoc].c_str()+tailOffset;
}
ROOT::ESTLType TClassEdit::STLKind(std::string_view type)
{
unsigned char offset = 0;
if (type.compare(0,6,"const ")==0) { offset += 6; }
offset += StdLen(type.substr(offset));
static const char *stls[] =
{ "any", "vector", "list", "deque", "map", "multimap", "set", "multiset", "bitset",
"forward_list", "unordered_set", "unordered_multiset", "unordered_map", "unordered_multimap", 0};
static const size_t stllen[] =
{ 3, 6, 4, 5, 3, 8, 3, 8, 6,
12, 13, 18, 13, 18, 0};
static const ROOT::ESTLType values[] =
{ ROOT::kNotSTL, ROOT::kSTLvector,
ROOT::kSTLlist, ROOT::kSTLdeque,
ROOT::kSTLmap, ROOT::kSTLmultimap,
ROOT::kSTLset, ROOT::kSTLmultiset,
ROOT::kSTLbitset,
ROOT::kSTLforwardlist,
ROOT::kSTLunorderedset, ROOT::kSTLunorderedmultiset,
ROOT::kSTLunorderedmap, ROOT::kSTLunorderedmultimap,
ROOT::kNotSTL
};
auto len = type.length();
if (len) {
len -= offset;
for(int k=1;stls[k];k++) {
if (len == stllen[k]) {
if (type.compare(offset,len,stls[k])==0) return values[k];
}
}
} else {
for(int k=1;stls[k];k++) {if (type.compare(offset,len,stls[k])==0) return values[k];}
}
return ROOT::kNotSTL;
}
int TClassEdit::STLArgs(int kind)
{
static const char stln[] =
{ 1, 1, 1, 1, 3, 3, 2, 2, 1,
1, 3, 3, 4, 4};
return stln[kind];
}
static size_t findNameEnd(const std::string_view full)
{
int level = 0;
for(size_t i = 0; i < full.length(); ++i) {
switch(full[i]) {
case '<': { ++level; break; }
case '>': {
if (level == 0) return i;
else --level;
break;
}
case ',': {
if (level == 0) return i;
break;
}
default: break;
}
}
return full.length();
}
static size_t findNameEnd(const std::string &full, size_t pos)
{
return pos + findNameEnd( {full.data()+pos,full.length()-pos} );
}
bool TClassEdit::IsDefAlloc(const char *allocname, const char *classname)
{
string_view a( allocname );
RemoveStd(a);
if (a=="alloc") return true;
if (a=="__default_alloc_template<true,0>") return true;
if (a=="__malloc_alloc_template<0>") return true;
const static int alloclen = strlen("allocator<");
if (a.compare(0,alloclen,"allocator<") != 0) {
return false;
}
a.remove_prefix(alloclen);
RemoveStd(a);
string_view k = classname;
RemoveStd(k);
if (a.compare(0,k.length(),k) != 0) {
size_t end = findNameEnd(a);
std::string valuepart;
GetNormalizedName(valuepart,std::string_view(a.data(),end));
std::string norm_value;
GetNormalizedName(norm_value,k);
if (valuepart != norm_value) {
return false;
}
a.remove_prefix(end);
} else {
a.remove_prefix(k.length());
}
if (a.compare(0,1,">")!=0 && a.compare(0,2," >")!=0) {
return false;
}
return true;
}
bool TClassEdit::IsDefAlloc(const char *allocname,
const char *keyclassname,
const char *valueclassname)
{
if (IsDefAlloc(allocname,keyclassname)) return true;
string_view a( allocname );
RemoveStd(a);
const static int alloclen = strlen("allocator<");
if (a.compare(0,alloclen,"allocator<") != 0) {
return false;
}
a.remove_prefix(alloclen);
RemoveStd(a);
const static int pairlen = strlen("pair<");
if (a.compare(0,pairlen,"pair<") != 0) {
return false;
}
a.remove_prefix(pairlen);
const static int constlen = strlen("const ");
if (a.compare(0,constlen,"const ") == 0) {
a.remove_prefix(constlen);
}
RemoveStd(a);
string_view k = keyclassname;
RemoveStd(k);
if (a.compare(0,k.length(),k) != 0) {
size_t end = findNameEnd(a);
std::string keypart;
GetNormalizedName(keypart,std::string_view(a.data(),end));
std::string norm_key;
GetNormalizedName(norm_key,k);
if (keypart != norm_key) {
if ( k[k.length()-1] == '*' ) {
keypart += "const";
if (keypart != norm_key) {
return false;
}
} else {
return false;
}
}
a.remove_prefix(end);
} else {
a.remove_prefix(k.length());
}
if (a[0] != ',') {
return false;
}
a.remove_prefix(1);
RemoveStd(a);
string_view v = valueclassname;
RemoveStd(v);
if (a.compare(0,v.length(),v) != 0) {
size_t end = findNameEnd(a);
std::string valuepart;
GetNormalizedName(valuepart,std::string_view(a.data(),end));
std::string norm_value;
GetNormalizedName(norm_value,v);
if (valuepart != norm_value) {
return false;
}
a.remove_prefix(end);
} else {
a.remove_prefix(v.length());
}
if (a.compare(0,1,">")!=0 && a.compare(0,2," >")!=0) {
return false;
}
return true;
}
static bool IsDefElement(const char *elementName, const char* defaultElementName, const char *classname)
{
string c = elementName;
size_t pos = StdLen(c);
const int elementlen = strlen(defaultElementName);
if (c.compare(pos,elementlen,defaultElementName) != 0) {
return false;
}
pos += elementlen;
string k = classname;
if (c.compare(pos,k.length(),k) != 0) {
size_t end = findNameEnd(c,pos);
std::string keypart;
TClassEdit::GetNormalizedName(keypart,std::string_view(c.c_str()+pos,end-pos));
std::string norm_key;
TClassEdit::GetNormalizedName(norm_key,k.c_str());
if (keypart != norm_key) {
return false;
}
pos = end;
} else {
pos += k.length();
}
if (c.compare(pos,1,">")!=0 && c.compare(pos,2," >")!=0) {
return false;
}
return true;
}
bool TClassEdit::IsDefComp(const char *compname, const char *classname)
{
return IsDefElement(compname, "less<", classname);
}
bool TClassEdit::IsDefPred(const char *predname, const char *classname)
{
return IsDefElement(predname, "equal_to<", classname);
}
bool TClassEdit::IsDefHash(const char *hashname, const char *classname)
{
return IsDefElement(hashname, "hash<", classname);
}
void TClassEdit::GetNormalizedName(std::string &norm_name, std::string_view name)
{
norm_name = std::string(name);
TClassEdit::TSplitType splitname(norm_name.c_str(),(TClassEdit::EModType)(TClassEdit::kLong64 | TClassEdit::kDropStd | TClassEdit::kDropStlDefault | TClassEdit::kKeepOuterConst));
splitname.ShortType(norm_name,TClassEdit::kDropStd | TClassEdit::kDropStlDefault | TClassEdit::kResolveTypedef | TClassEdit::kKeepOuterConst);
if (norm_name.length()>2 && norm_name[0]==':' && norm_name[1]==':') {
norm_name.erase(0,2);
}
if (gInterpreterHelper) {
std::string typeresult;
if (gInterpreterHelper->ExistingTypeCheck(norm_name, typeresult)
|| gInterpreterHelper->GetPartiallyDesugaredNameWithScopeHandling(norm_name, typeresult)) {
if (!typeresult.empty()) norm_name = typeresult;
}
}
}
string TClassEdit::GetLong64_Name(const char* original)
{
if (original==0)
return "";
else
return GetLong64_Name(string(original));
}
string TClassEdit::GetLong64_Name(const string& original)
{
static const char* longlong_s = "long long";
static const char* ulonglong_s = "unsigned long long";
static const unsigned int longlong_len = strlen(longlong_s);
static const unsigned int ulonglong_len = strlen(ulonglong_s);
string result = original;
int pos = 0;
while( (pos = result.find(ulonglong_s,pos) ) >=0 ) {
result.replace(pos, ulonglong_len, "ULong64_t");
}
pos = 0;
while( (pos = result.find(longlong_s,pos) ) >=0 ) {
result.replace(pos, longlong_len, "Long64_t");
}
return result;
}
const char *TClassEdit::GetUnqualifiedName(const char *original)
{
const char *lastPos = original;
{
long depth = 0;
for(auto cursor = original; *cursor != '\0'; ++cursor) {
if ( *cursor == '<' || *cursor == '(') ++depth;
else if ( *cursor == '>' || *cursor == ')' ) --depth;
else if ( *cursor == ':' ) {
if (depth==0 && *(cursor+1) == ':' && *(cursor+2) != '\0') {
lastPos = cursor+2;
}
}
}
}
return lastPos;
}
static void R__FindTrailing(std::string &full,
std::string &stars
)
{
const char *t = full.c_str();
const unsigned int tlen( full.size() );
const char *starloc = t + tlen - 1;
bool hasconst = false;
if ( (*starloc)=='t'
&& (starloc-t) > 4 && 0 == strncmp((starloc-4),"const",5)
&& ( (*(starloc-5)) == ' ' || (*(starloc-5)) == '*' || (*(starloc-5)) == '&'
|| (*(starloc-5)) == '>' || (*(starloc-5)) == ']') ) {
starloc -= 4;
if ((*starloc-1)==' ') {
starloc--;
}
hasconst = true;
}
if ( hasconst || (*starloc)=='*' || (*starloc)=='&' || (*starloc)==']' ) {
bool isArray = ( (*starloc)==']' );
while( t<=(starloc-1) && ((*(starloc-1))=='*' || (*(starloc-1))=='&' || (*(starloc-1))=='t' || isArray)) {
if (isArray) {
starloc--;
isArray = ! ( (*starloc)=='[' );
} else if ( (*(starloc-1))=='t' ) {
if ( (starloc-1-t) > 5 && 0 == strncmp((starloc-5),"const",5)
&& ( (*(starloc-6)) == ' ' || (*(starloc-6)) == '*' || (*(starloc-6)) == '&'
|| (*(starloc-6)) == '>' || (*(starloc-6)) == ']')) {
starloc -= 5;
} else {
break;
}
} else {
starloc--;
}
}
stars = starloc;
if ((*(starloc-1))==' ') {
starloc--;
}
const unsigned int starlen = strlen(starloc);
full.erase(tlen-starlen,starlen);
} else if (hasconst) {
stars = starloc;
const unsigned int starlen = strlen(starloc);
full.erase(tlen-starlen,starlen);
}
}
int TClassEdit::GetSplit(const char *type, vector<string>& output, int &nestedLoc, EModType mode)
{
nestedLoc = 0;
output.clear();
if (strlen(type)==0) return 0;
int cleantypeMode = 1 ;
if (mode & kKeepOuterConst) {
cleantypeMode = 0;
}
string full( mode & kLong64 ? TClassEdit::GetLong64_Name( CleanType(type, cleantypeMode) )
: CleanType(type, cleantypeMode) );
{
unsigned int const_offset = (0==strncmp("const ",full.c_str(),6)) ? 6 : 0;
bool isString = false;
bool isStdString = false;
static const char* basic_string_std = "std::basic_string<char";
static const unsigned int basic_string_std_len = strlen(basic_string_std);
if (full.compare(const_offset,basic_string_std_len,basic_string_std) == 0
&& full.size() > basic_string_std_len) {
isString = true;
isStdString = true;
} else if (full.compare(const_offset,basic_string_std_len-5,basic_string_std+5) == 0
&& full.size() > (basic_string_std_len-5)) {
isString = true;
}
if (isString) {
size_t offset = isStdString ? basic_string_std_len : basic_string_std_len - 5;
offset += const_offset;
if ( full[offset] == '>' ) {
} else if (full[offset] == ',') {
++offset;
if (full.compare(offset, 5, "std::") == 0) {
offset += 5;
}
static const char* char_traits_s = "char_traits<char>";
static const unsigned int char_traits_len = strlen(char_traits_s);
if (full.compare(offset, char_traits_len, char_traits_s) == 0) {
offset += char_traits_len;
if ( full[offset] == '>') {
} else if (full[offset] == ' ' && full[offset+1] == '>') {
++offset;
} else if (full[offset] == ',') {
++offset;
if (full.compare(offset, 5, "std::") == 0) {
offset += 5;
}
static const char* allocator_s = "allocator<char>";
static const unsigned int allocator_len = strlen(allocator_s);
if (full.compare(offset, allocator_len, allocator_s) == 0) {
offset += allocator_len;
if ( full[offset] == '>') {
} else if (full[offset] == ' ' && full[offset+1] == '>') {
++offset;
} else {
isString = false;
}
}
} else {
isString = false;
}
} else {
isString = false;
}
} else {
isString = false;
}
if (isString) {
output.push_back(string());
if (const_offset && (mode & kKeepOuterConst)) {
if (isStdString && !(mode & kDropStd)) {
output.push_back("const std::string");
} else {
output.push_back("const string");
}
} else {
if (isStdString && !(mode & kDropStd)) {
output.push_back("std::string");
} else {
output.push_back("string");
}
}
if (offset < full.length()) {
string right( full.substr(offset) );
string stars;
R__FindTrailing(right, stars);
output.back().append(right.c_str()+1);
output.push_back(stars);
} else {
output.push_back("");
}
return output.size();
}
}
}
if ( mode & kDropStd) {
unsigned int offset = (0==strncmp("const ",full.c_str(),6)) ? 6 : 0;
RemoveStd( full, offset );
}
string stars;
if ( !full.empty() ) {
R__FindTrailing(full, stars);
}
const char *c = strchr(full.c_str(),'<');
if (c) {
output.push_back(string(full,0,c - full.c_str()));
const char *cursor;
int level = 0;
for(cursor = c + 1; *cursor != '\0' && !(level==0 && *cursor == '>'); ++cursor) {
switch (*cursor) {
case '<': ++level; break;
case '>': --level; break;
case ',':
if (level == 0) {
output.push_back(std::string(c+1,cursor));
c = cursor;
}
break;
}
}
if (*cursor=='>') {
if (*(cursor-1) == ' ') {
output.push_back(std::string(c+1,cursor-1));
} else {
output.push_back(std::string(c+1,cursor));
}
if (*(cursor+1)==':') {
nestedLoc = output.size();
output.push_back((cursor+1));
}
} else if (level >= 0) {
output.push_back(std::string(c+1,cursor));
}
} else {
output.push_back(string());
output.push_back(full);
}
if (!output.empty()) output.push_back(stars);
return output.size();
}
string TClassEdit::CleanType(const char *typeDesc, int mode, const char **tail)
{
static const char* remove[] = {"class","const","volatile",0};
static bool isinit = false;
static std::vector<size_t> lengths;
if (!isinit) {
for (int k=0; remove[k]; ++k) {
lengths.push_back(strlen(remove[k]));
}
isinit = true;
}
string result;
result.reserve(strlen(typeDesc)*2);
int lev=0,kbl=1;
const char* c;
for(c=typeDesc;*c;c++) {
if (c[0]==' ') {
if (kbl) continue;
if (!isalnum(c[ 1]) && c[ 1] !='_') continue;
}
if (kbl && (mode>=2 || lev==0)) {
int done = 0;
int n = (mode) ? 999 : 1;
for (int k=0; k<n && remove[k]; k++) {
int rlen = lengths[k];
if (strncmp(remove[k],c,rlen)) continue;
if (isalnum(c[rlen]) || c[rlen]=='_' || c[rlen]=='$') continue;
c+=rlen-1; done = 1; break;
}
if (done) continue;
}
kbl = (!isalnum(c[ 0]) && c[ 0]!='_' && c[ 0]!='$' && c[0]!='[' && c[0]!=']' && c[0]!='-' && c[0]!='@');
if (*c == '<' || *c == '(') lev++;
if (lev==0 && !isalnum(*c)) {
if (!strchr("*&:._$ []-@",*c)) break;
}
if (c[0]=='>' && result.size() && result[result.size()-1]=='>') result+=" ";
result += c[0];
if (*c == '>' || *c == ')') lev--;
}
if(tail) *tail=c;
return result;
}
string TClassEdit::ShortType(const char *typeDesc, int mode)
{
string answer;
if (typeDesc) {
TSplitType arglist(typeDesc, (EModType) mode);
arglist.ShortType(answer, mode);
}
return answer;
}
bool TClassEdit::IsInterpreterDetail(const char *type)
{
size_t len = strlen(type);
if (len < 2 || strncmp(type+len-2,"_t",2) != 0) return false;
unsigned char offset = 0;
if (strncmp(type,"const ",6)==0) { offset += 6; }
static const char *names[] = { "CallFunc_t","ClassInfo_t","BaseClassInfo_t",
"DataMemberInfo_t","FuncTempInfo_t","MethodInfo_t","MethodArgInfo_t",
"TypeInfo_t","TypedefInfo_t",0};
for(int k=1;names[k];k++) {if (strcmp(type+offset,names[k])==0) return true;}
return false;
}
bool TClassEdit::IsSTLBitset(const char *classname)
{
size_t offset = StdLen(classname);
if ( strncmp(classname+offset,"bitset<",strlen("bitset<"))==0) return true;
return false;
}
ROOT::ESTLType TClassEdit::UnderlyingIsSTLCont(std::string_view type)
{
if (type.compare(0,6,"const ",6) == 0)
type.remove_prefix(6);
while(type[type.length()-1]=='*' ||
type[type.length()-1]=='&' ||
type[type.length()-1]==' ') {
type.remove_suffix(1);
}
return IsSTLCont(type);
}
ROOT::ESTLType TClassEdit::IsSTLCont(std::string_view type)
{
auto pos = type.find('<');
if (pos==std::string_view::npos) return ROOT::kNotSTL;
auto c = pos+1;
for (decltype(type.length()) level = 1; c < type.length(); ++c) {
if (type[c] == '<') ++level;
if (type[c] == '>') --level;
if (level == 0) break;
}
if (c != (type.length()-1) ) {
return ROOT::kNotSTL;
}
return STLKind({type.data(),pos});
}
int TClassEdit::IsSTLCont(const char *type, int testAlloc)
{
if (strchr(type,'<')==0) return 0;
TSplitType arglist( type );
return arglist.IsSTLCont(testAlloc);
}
bool TClassEdit::IsStdClass(const char *classname)
{
classname += StdLen( classname );
if ( strcmp(classname,"string")==0 ) return true;
if ( strncmp(classname,"bitset<",strlen("bitset<"))==0) return true;
if ( strncmp(classname,"pair<",strlen("pair<"))==0) return true;
if ( strcmp(classname,"allocator")==0) return true;
if ( strncmp(classname,"allocator<",strlen("allocator<"))==0) return true;
if ( strncmp(classname,"greater<",strlen("greater<"))==0) return true;
if ( strncmp(classname,"less<",strlen("less<"))==0) return true;
if ( strncmp(classname,"equal_to<",strlen("equal_to<"))==0) return true;
if ( strncmp(classname,"hash<",strlen("hash<"))==0) return true;
if ( strncmp(classname,"auto_ptr<",strlen("auto_ptr<"))==0) return true;
if ( strncmp(classname,"vector<",strlen("vector<"))==0) return true;
if ( strncmp(classname,"list<",strlen("list<"))==0) return true;
if ( strncmp(classname,"forward_list<",strlen("forward_list<"))==0) return true;
if ( strncmp(classname,"deque<",strlen("deque<"))==0) return true;
if ( strncmp(classname,"map<",strlen("map<"))==0) return true;
if ( strncmp(classname,"multimap<",strlen("multimap<"))==0) return true;
if ( strncmp(classname,"set<",strlen("set<"))==0) return true;
if ( strncmp(classname,"multiset<",strlen("multiset<"))==0) return true;
if ( strncmp(classname,"unordered_set<",strlen("unordered_set<"))==0) return true;
if ( strncmp(classname,"unordered_multiset<",strlen("unordered_multiset<"))==0) return true;
if ( strncmp(classname,"unordered_map<",strlen("unordered_map<"))==0) return true;
if ( strncmp(classname,"unordered_multimap<",strlen("unordered_multimap<"))==0) return true;
if ( strncmp(classname,"bitset<",strlen("bitset<"))==0) return true;
return false;
}
bool TClassEdit::IsVectorBool(const char *name) {
TSplitType splitname( name );
return ( TClassEdit::STLKind( splitname.fElements[0] ) == ROOT::kSTLvector)
&& ( splitname.fElements[1] == "bool" || splitname.fElements[1]=="Bool_t");
}
static void ResolveTypedefProcessType(const char *tname,
unsigned int ,
unsigned int cursor,
bool constprefix,
unsigned int start_of_type,
unsigned int end_of_type,
unsigned int mod_start_of_type,
bool &modified,
std::string &result)
{
std::string type(modified && (mod_start_of_type < result.length()) ?
result.substr(mod_start_of_type, string::npos)
: string(tname, start_of_type, end_of_type == 0 ? cursor - start_of_type : end_of_type - start_of_type));
string typeresult;
if (gInterpreterHelper->ExistingTypeCheck(type, typeresult)
|| gInterpreterHelper->GetPartiallyDesugaredNameWithScopeHandling(type, typeresult)) {
if (!typeresult.empty()) {
if (modified) {
result.replace(mod_start_of_type, string::npos,
typeresult);
}
else {
modified = true;
mod_start_of_type = start_of_type;
result += string(tname,0,start_of_type);
if (constprefix && typeresult.compare(0,6,"const ",6) == 0) {
result += typeresult.substr(6,string::npos);
} else {
result += typeresult;
}
}
} else if (modified) {
result.replace(mod_start_of_type, string::npos,
type);
}
if (modified) {
if (end_of_type != 0 && end_of_type!=cursor) {
result += std::string(tname,end_of_type,cursor-end_of_type);
}
}
} else {
if (modified) {
if (end_of_type != 0 && end_of_type!=cursor) {
result += std::string(tname,end_of_type,cursor-end_of_type);
}
}
}
}
static void ResolveTypedefImpl(const char *tname,
unsigned int len,
unsigned int &cursor,
bool &modified,
std::string &result)
{
bool constprefix = false;
if (tname[cursor]==' ') {
if (!modified) {
modified = true;
result += string(tname,0,cursor);
}
while (tname[cursor]==' ') ++cursor;
}
if (tname[cursor]=='c' && (cursor+6<len)) {
if (strncmp(tname+cursor,"const ",6) == 0) {
cursor += 6;
if (modified) result += "const ";
}
constprefix = true;
}
if (len > 5 && strncmp(tname+cursor,"std::",5) == 0) {
cursor += 5;
}
if (len > 2 && strncmp(tname+cursor,"::",2) == 0) {
cursor += 2;
len -= 2;
}
unsigned int start_of_type = cursor;
unsigned int end_of_type = 0;
unsigned int mod_start_of_type = result.length();
unsigned int prevScope = cursor;
for ( ; cursor<len; ++cursor) {
switch (tname[cursor]) {
case ':': {
if ((cursor+1)>=len || tname[cursor+1]!=':') {
if (modified) result += (tname+prevScope);
return;
}
string scope;
if (modified) {
scope = result.substr(mod_start_of_type, string::npos);
scope += std::string(tname+prevScope,cursor-prevScope);
} else {
scope = std::string(tname, start_of_type, cursor - start_of_type);
}
std::string scoperesult;
bool isInlined = false;
if (gInterpreterHelper->ExistingTypeCheck(scope, scoperesult)
||gInterpreterHelper->GetPartiallyDesugaredNameWithScopeHandling(scope, scoperesult)) {
if (!scoperesult.empty()) {
if (modified) {
if (constprefix && scoperesult.compare(0,6,"const ",6) != 0) mod_start_of_type -= 6;
result.replace(mod_start_of_type, string::npos,
scoperesult);
result += "::";
} else {
modified = true;
mod_start_of_type = start_of_type;
result += string(tname,0,start_of_type);
result += scoperesult;
result += "::";
}
} else if (modified) {
result += std::string(tname+prevScope,cursor+1-prevScope);
}
} else if (!gInterpreterHelper->IsDeclaredScope(scope,isInlined)) {
if (modified) result += (tname+prevScope);
return;
} else if (isInlined) {
if (!modified) {
modified = true;
mod_start_of_type = start_of_type;
result += string(tname,0,start_of_type);
result += string(tname,start_of_type,prevScope - start_of_type);
}
} else if (modified) {
result += std::string(tname+prevScope,cursor+1-prevScope);
}
++cursor;
prevScope = cursor+1;
break;
}
case '<': {
if (modified) {
result += std::string(tname+prevScope,cursor+1-prevScope);
}
do {
++cursor;
ResolveTypedefImpl(tname,len,cursor,modified,result);
} while( cursor<len && tname[cursor] == ',' );
while (cursor<len && tname[cursor+1]==' ') ++cursor;
if (cursor+2<len && tname[cursor+1]==':' && tname[cursor+2]==':') {
if (modified) result += "::";
cursor += 2;
prevScope = cursor+1;
}
if ( (cursor+1)<len && tname[cursor+1] == ',') {
++cursor;
if (modified) result += ',';
return;
}
if ( (cursor+1)<len && tname[cursor+1] == '>') {
++cursor;
if (modified) result += " >";
return;
}
if ( (cursor+1) >= len) {
return;
}
if (tname[cursor] != ' ') break;
if (modified) prevScope = cursor+1;
}
case ' ': {
end_of_type = cursor;
while ((cursor+1)<len && tname[cursor+1] == ' ') ++cursor;
auto next = cursor+1;
if (strncmp(tname+next,"const",5) == 0 && ((next+5)==len || tname[next+5] == ' ' || tname[next+5] == '*' || tname[next+5] == '&' || tname[next+5] == ',' || tname[next+5] == '>' || tname[next+5] == ']'))
{
if (!modified) {
modified = true;
result += string(tname,0,start_of_type);
result += "const ";
mod_start_of_type = start_of_type + 6;
result += string(tname,start_of_type,end_of_type-start_of_type);
} else if (mod_start_of_type < result.length()) {
result.insert(mod_start_of_type,"const ");
mod_start_of_type += 6;
} else {
result += "const ";
mod_start_of_type += 6;
result += string(tname,start_of_type,end_of_type-start_of_type);
}
cursor += 5;
end_of_type = cursor+1;
prevScope = end_of_type;
if (tname[next+5] == ',' || tname[next+5] == '>' || tname[next+5] == '[') {
break;
}
} else if (next!=len && tname[next] != '*' && tname[next] != '&') {
end_of_type = 0;
break;
}
++cursor;
}
case '*':
case '&': {
if (tname[cursor] != ' ') end_of_type = cursor;
auto next = cursor+1;
if (strncmp(tname+next,"const",5) == 0) {
if ((next+5)==len || tname[next+5] == ' ' || tname[next+5] == '*' || tname[next+5] == '&' || tname[next+5] == ',' || tname[next+5] == '>' || tname[next+5] == '[') {
next += 5;
}
}
while (next<len &&
(tname[next] == ' ' || tname[next] == '*' || tname[next] == '&')) {
++next;
if (strncmp(tname+next,"const",5) == 0) {
if ((next+5)==len || tname[next+5] == ' ' || tname[next+5] == '*' || tname[next+5] == '&' || tname[next+5] == ',' || tname[next+5] == '>' || tname[next+5] == '[') {
next += 5;
}
}
}
cursor = next-1;
break;
}
case ',': {
if (modified && prevScope) {
result += std::string(tname+prevScope,(end_of_type == 0 ? cursor : end_of_type)-prevScope);
}
ResolveTypedefProcessType(tname,len,cursor,constprefix,start_of_type,end_of_type,mod_start_of_type,
modified, result);
if (modified) result += ',';
return;
}
case '>': {
if (modified && prevScope) {
result += std::string(tname+prevScope,(end_of_type == 0 ? cursor : end_of_type)-prevScope);
}
ResolveTypedefProcessType(tname,len,cursor,constprefix,start_of_type,end_of_type,mod_start_of_type,
modified, result);
if (modified) result += '>';
return;
}
default:
end_of_type = 0;
}
}
if (prevScope && modified) result += std::string(tname+prevScope,(end_of_type == 0 ? cursor : end_of_type)-prevScope);
ResolveTypedefProcessType(tname,len,cursor,constprefix,start_of_type,end_of_type,mod_start_of_type,
modified, result);
}
string TClassEdit::ResolveTypedef(const char *tname, bool )
{
if ( tname==0 || tname[0]==0 || !gInterpreterHelper) return "";
std::string result;
if (gInterpreterHelper->ExistingTypeCheck(tname, result))
{
if (result.empty()) return tname;
else return result;
}
unsigned int len = strlen(tname);
unsigned int cursor = 0;
bool modified = false;
ResolveTypedefImpl(tname,len,cursor,modified,result);
if (!modified) return tname;
else return result;
}
string TClassEdit::InsertStd(const char *tname)
{
static const char* sSTLtypes[] = {
"allocator",
"auto_ptr",
"bad_alloc",
"bad_cast",
"bad_exception",
"bad_typeid",
"basic_filebuf",
"basic_fstream",
"basic_ifstream",
"basic_ios",
"basic_iostream",
"basic_istream",
"basic_istringstream",
"basic_ofstream",
"basic_ostream",
"basic_ostringstream",
"basic_streambuf",
"basic_string",
"basic_stringbuf",
"basic_stringstream",
"binary_function",
"binary_negate",
"bitset",
"char_traits",
"codecvt_byname",
"codecvt",
"collate",
"collate_byname",
"compare",
"complex",
"ctype_byname",
"ctype",
"deque",
"divides",
"domain_error",
"equal_to",
"exception",
"forward_list",
"fpos",
"greater_equal",
"greater",
"gslice_array",
"gslice",
"hash",
"indirect_array",
"invalid_argument",
"ios_base",
"istream_iterator",
"istreambuf_iterator",
"istrstream",
"iterator_traits",
"iterator",
"length_error",
"less_equal",
"less",
"list",
"locale",
"localedef utility",
"locale utility",
"logic_error",
"logical_and",
"logical_not",
"logical_or",
"map",
"mask_array",
"mem_fun",
"mem_fun_ref",
"messages",
"messages_byname",
"minus",
"modulus",
"money_get",
"money_put",
"moneypunct",
"moneypunct_byname",
"multimap",
"multiplies",
"multiset",
"negate",
"not_equal_to",
"num_get",
"num_put",
"numeric_limits",
"numpunct",
"numpunct_byname",
"ostream_iterator",
"ostreambuf_iterator",
"ostrstream",
"out_of_range",
"overflow_error",
"pair",
"plus",
"pointer_to_binary_function",
"pointer_to_unary_function",
"priority_queue",
"queue",
"range_error",
"raw_storage_iterator",
"reverse_iterator",
"runtime_error",
"set",
"slice_array",
"slice",
"stack",
"string",
"strstream",
"strstreambuf",
"time_get_byname",
"time_get",
"time_put_byname",
"time_put",
"unary_function",
"unary_negate",
"underflow_error",
"unordered_map",
"unordered_multimap",
"unordered_multiset",
"unordered_set",
"valarray",
"vector",
"wstring"
};
static set<string> sSetSTLtypes;
if (tname==0 || tname[0]==0) return "";
if (sSetSTLtypes.empty()) {
const size_t nSTLtypes = sizeof(sSTLtypes) / sizeof(const char*);
for (size_t i = 0; i < nSTLtypes; ++i)
sSetSTLtypes.insert(sSTLtypes[i]);
}
size_t b = 0;
size_t len = strlen(tname);
string ret;
ret.reserve(len + 20);
string id;
while (b < len) {
bool precScope = false;
while (!(isalnum(tname[b]) || tname[b] == '_') && b < len) {
precScope = (b < len - 2) && (tname[b] == ':') && (tname[b + 1] == ':');
if (precScope) {
ret += "::";
b += 2;
} else
ret += tname[b++];
}
size_t e = b;
id.clear();
while (e < len && (isalnum(tname[e]) || tname[e] == '_'))
id += tname[e++];
if (!id.empty()) {
if (!precScope) {
set<string>::const_iterator iSTLtype = sSetSTLtypes.find(id);
if (iSTLtype != sSetSTLtypes.end())
ret += "std::";
}
ret += id;
b = e;
}
}
return ret;
}
char* TClassEdit::DemangleTypeIdName(const std::type_info& ti, int& errorCode)
{
const char* mangled_name = ti.name();
return DemangleName(mangled_name, errorCode);
}