std::string {hover,comments} -> NTString (null-terminated string)

Typically, sizeof(std::string) = 32, sizeof(NTString) = 8
hover and comments are usually empty and thus wasteful to spend 24*2 bytes for them
This commit is contained in:
Fangrui Song 2018-02-10 21:36:15 -08:00
parent e019968f51
commit 8ab45cb43d
9 changed files with 132 additions and 47 deletions

View File

@ -434,6 +434,25 @@ std::string GetDocumentContentInRange(CXTranslationUnit cx_tu,
return result;
}
void SetUsePreflight(IndexFile* db, ClangCursor lex_parent) {
switch (GetSymbolKind(lex_parent.get_kind())) {
default:
break;
case SymbolKind::Func: {
(void)db->ToFuncId(lex_parent.cx_cursor);
break;
}
case SymbolKind::Type: {
(void)db->ToTypeId(lex_parent.cx_cursor);
break;
}
case SymbolKind::Var: {
(void)db->ToVarId(lex_parent.cx_cursor);
break;
}
}
}
void SetUse(IndexFile* db, Maybe<Use>* def, Range range, ClangCursor lex_parent, Role role) {
switch (GetSymbolKind(lex_parent.get_kind())) {
default:
@ -561,8 +580,8 @@ void SetVarDetail(IndexVar* var,
def.detailed_name = param->PrettyPrintCursor(cursor.cx_cursor, false);
def.hover = std::move(qualified_name);
#else
def.detailed_name = std::move(type_name);
ConcatTypeAndName(def.detailed_name, qualified_name);
ConcatTypeAndName(type_name, qualified_name);
def.detailed_name = type_name;
// Append the textual initializer, bit field, constructor to |hover|.
// Omit |hover| for these types:
// int (*a)(); int (&a)(); int (&&a)(); int a[1]; auto x = ...
@ -580,7 +599,7 @@ void SetVarDetail(IndexVar* var,
optional<int> spell_end = fc.ToOffset(cursor.get_spelling_range().end);
optional<int> extent_end = fc.ToOffset(cursor.get_extent().end);
if (extent_end && *spell_end < *extent_end)
def.hover = def.detailed_name +
def.hover = std::string(def.detailed_name.c_str()) +
fc.content.substr(*spell_end, *extent_end - *spell_end);
}
#endif
@ -1210,21 +1229,22 @@ ClangCursor::VisitResult VisitMacroDefinitionAndExpansions(ClangCursor cursor,
else
decl_usr = cursor.get_referenced().get_usr_hash();
SetUsePreflight(db, parent);
IndexVar* var_def = db->Resolve(db->ToVarId(decl_usr));
if (cursor.get_kind() == CXCursor_MacroDefinition) {
CXSourceRange cx_extent = clang_getCursorExtent(cursor.cx_cursor);
var_def->def.detailed_name = cursor.get_display_name();
var_def->def.short_name_offset = 0;
var_def->def.short_name_size = int(var_def->def.detailed_name.size());
var_def->def.short_name_size =
int16_t(strlen(var_def->def.detailed_name.c_str()));
var_def->def.hover =
"#define " + GetDocumentContentInRange(param->tu->cx_tu, cx_extent);
var_def->def.kind = ClangSymbolKind::Macro;
var_def->def.comments = cursor.get_comments();
ClangCursor lex_parent;
SetUse(db, &var_def->def.spell, decl_loc_spelling, lex_parent,
SetUse(db, &var_def->def.spell, decl_loc_spelling, parent,
Role::Definition);
SetUse(db, &var_def->def.extent,
ResolveCXSourceRange(cx_extent, nullptr), lex_parent, Role::None);
ResolveCXSourceRange(cx_extent, nullptr), parent, Role::None);
} else
UniqueAddUse(db, var_def->uses, decl_loc_spelling, parent);
@ -1257,6 +1277,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
case CXCursor_DeclRefExpr: {
ClangCursor ref_cursor = clang_getCursorReferenced(cursor.cx_cursor);
if (ref_cursor.get_kind() == CXCursor_NonTypeTemplateParameter) {
SetUsePreflight(db, parent);
IndexVar* ref_var =
db->Resolve(db->ToVarId(ref_cursor.get_usr_hash()));
if (ref_var->def.detailed_name.empty()) {
@ -1305,6 +1326,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
case CXCursor_TemplateRef: {
ClangCursor ref_cursor = clang_getCursorReferenced(cursor.cx_cursor);
if (ref_cursor.get_kind() == CXCursor_TemplateTemplateParameter) {
SetUsePreflight(db, parent);
IndexType* ref_index =
db->Resolve(db->ToTypeId(ref_cursor.get_usr_hash()));
// TODO It seems difficult to get references to template template
@ -1321,7 +1343,8 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
ref_index->def.detailed_name = ref_cursor.get_spelling();
#endif
ref_index->def.short_name_offset = 0;
ref_index->def.short_name_size = ref_index->def.detailed_name.size();
ref_index->def.short_name_size =
int16_t(strlen(ref_index->def.detailed_name.c_str()));
ref_index->def.kind = ClangSymbolKind::Parameter;
}
UniqueAddUseSpell(db, ref_index->uses, cursor);
@ -1331,6 +1354,7 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
case CXCursor_TypeRef: {
ClangCursor ref_cursor = clang_getCursorReferenced(cursor.cx_cursor);
if (ref_cursor.get_kind() == CXCursor_TemplateTypeParameter) {
SetUsePreflight(db, parent);
IndexType* ref_index =
db->Resolve(db->ToTypeId(ref_cursor.get_usr_hash()));
// TODO It seems difficult to get a FunctionTemplate's template
@ -1347,7 +1371,8 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor,
ref_index->def.detailed_name = ref_cursor.get_spelling();
#endif
ref_index->def.short_name_offset = 0;
ref_index->def.short_name_size = ref_index->def.detailed_name.size();
ref_index->def.short_name_size =
int16_t(strlen(ref_index->def.detailed_name.c_str()));
ref_index->def.kind = ClangSymbolKind::Parameter;
}
UniqueAddUseSpell(db, ref_index->uses, cursor);
@ -1455,6 +1480,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
NamespaceHelper* ns = &param->ns;
ClangCursor lex_parent(fromContainer(decl->lexicalContainer));
SetUsePreflight(db, lex_parent);
switch (decl->entityInfo->kind) {
case CXIdxEntity_CXXNamespace: {
@ -1745,7 +1771,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
if (extent_start && spell_start && spell_end && extent_end) {
type->def.hover =
fc.content.substr(*extent_start, *spell_start - *extent_start) +
type->def.detailed_name +
type->def.detailed_name.c_str() +
fc.content.substr(*spell_end, *extent_end - *spell_end);
}
}
@ -1935,6 +1961,7 @@ void OnIndexReference(CXClientData client_data, const CXIdxEntityRefInfo* ref) {
ClangCursor cursor(ref->cursor);
ClangCursor lex_parent(fromContainer(ref->container));
SetUsePreflight(db, lex_parent);
switch (ref->referencedEntity->kind) {
case CXIdxEntity_CXXNamespaceAlias:

View File

@ -9,6 +9,7 @@
#include "file_contents.h"
#include "language_server_api.h"
#include "maybe.h"
#include "ntstring.h"
#include "performance.h"
#include "position.h"
#include "serializer.h"
@ -160,8 +161,8 @@ template <typename F>
struct TypeDefDefinitionData {
// General metadata.
std::string detailed_name;
std::string hover;
std::string comments;
NTString hover;
NTString comments;
// While a class/type can technically have a separate declaration/definition,
// it doesn't really happen in practice. The declaration never contains
@ -258,8 +259,8 @@ template <typename F>
struct FuncDefDefinitionData {
// General metadata.
std::string detailed_name;
std::string hover;
std::string comments;
NTString hover;
NTString comments;
Maybe<Use> spell;
Maybe<Use> extent;
@ -368,8 +369,8 @@ template <typename F>
struct VarDefDefinitionData {
// General metadata.
std::string detailed_name;
std::string hover;
std::string comments;
NTString hover;
NTString comments;
// TODO: definitions should be a list of ranges, since there can be more
// than one - when??
Maybe<Use> spell;

View File

@ -180,7 +180,7 @@ MAKE_REFLECT_STRUCT(lsLocation, uri, range);
// cquery extension
struct lsLocationEx : lsLocation {
optional<std::string> containerName;
optional<std::string_view> containerName;
};
MAKE_REFLECT_STRUCT(lsLocationEx, uri, range, containerName);

View File

@ -14,7 +14,7 @@ REGISTER_IPC_MESSAGE(Ipc_CqueryTypeHierarchyTree);
struct Out_CqueryTypeHierarchyTree
: public lsOutMessage<Out_CqueryTypeHierarchyTree> {
struct TypeEntry {
std::string name;
std::string_view name;
optional<lsLocation> location;
std::vector<TypeEntry> children;
};
@ -36,7 +36,7 @@ BuildParentInheritanceHierarchyForType(QueryDatabase* db,
EachWithGen(db->types, root_type.def->parents, [&](QueryType& parent_type) {
Out_CqueryTypeHierarchyTree::TypeEntry parent_entry;
parent_entry.name = parent_type.def->detailed_name;
parent_entry.name = parent_type.def->detailed_name.c_str();
if (parent_type.def->spell)
parent_entry.location = GetLsLocation(
db, working_files, *parent_type.def->spell);

View File

@ -11,25 +11,28 @@ std::pair<std::string_view, std::string_view> GetCommentsAndHover(
case SymbolKind::Type: {
QueryType& type = db->types[sym.Idx()];
if (type.def)
return {type.def->comments, type.def->hover.size()
? type.def->hover
: type.def->detailed_name};
return {type.def->comments,
!type.def->hover.empty()
? std::string_view(type.def->hover)
: std::string_view(type.def->detailed_name)};
break;
}
case SymbolKind::Func: {
QueryFunc& func = db->funcs[sym.Idx()];
if (func.def)
return {func.def->comments, func.def->hover.size()
? func.def->hover
: func.def->detailed_name};
return {func.def->comments,
!func.def->hover.empty()
? std::string_view(func.def->hover)
: std::string_view(func.def->detailed_name)};
break;
}
case SymbolKind::Var: {
QueryVar& var = db->vars[sym.Idx()];
if (var.def)
return {var.def->comments, var.def->hover.size()
? var.def->hover
: var.def->detailed_name};
return {var.def->comments,
!var.def->hover.empty()
? std::string_view(var.def->hover)
: std::string_view(var.def->detailed_name)};
break;
}
case SymbolKind::File:

57
src/ntstring.h Normal file
View File

@ -0,0 +1,57 @@
#pragma once
#include <string_view.h>
#include <string.h>
#include <memory>
#include <utility>
class Reader;
class Writer;
// Null-terminated string
// This is used in Query{Func,Type,Var}::def to reduce memory footprint.
class NTString {
using size_type = std::string::size_type;
std::unique_ptr<char[]> str;
public:
NTString() : str(new char[1]()) {}
NTString(const NTString& o) : str(new char[strlen(o.c_str()) + 1]) {
strcpy(str.get(), o.c_str());
}
NTString(NTString&& o) = default;
NTString(std::string_view sv) {
*this = sv;
}
operator std::string_view() const { return str.get(); }
const char* c_str() const { return str.get(); }
std::string_view substr(size_type pos, size_type cnt) const {
return std::string_view(c_str() + pos, cnt);
}
bool empty() const { return !str || str.get()[0] == '\0'; }
size_type find(const char* s) {
const char *p = strstr(c_str(), s);
return p ? std::string::size_type(p - c_str()) : std::string::npos;
}
size_type find(const char* s, size_type pos, size_type cnt) {
auto* p = (const char*)memmem(c_str() + pos, strlen(c_str()) - pos, s, cnt);
return p ? std::string::size_type(p - c_str()) : std::string::npos;
}
size_type find(std::string_view sv) {
return find(sv.data(), 0, sv.size());
}
void operator=(std::string_view sv) {
str = std::unique_ptr<char[]>(new char[sv.size() + 1]);
memcpy(str.get(), sv.data(), sv.size());
str.get()[sv.size()] = '\0';
}
void operator=(const NTString& o) {
*this = static_cast<std::string_view>(o);
}
bool operator==(const NTString& o) const {
return strcmp(c_str(), o.c_str()) == 0;
}
};

View File

@ -406,19 +406,19 @@ optional<lsLocationEx> GetLsLocationEx(QueryDatabase* db,
case SymbolKind::Func: {
QueryFunc& func = db->GetFunc(use);
if (func.def)
ret.containerName = func.def->detailed_name;
ret.containerName = std::string_view(func.def->detailed_name);
break;
}
case SymbolKind::Type: {
QueryType& type = db->GetType(use);
if (type.def)
ret.containerName = type.def->detailed_name;
ret.containerName = std::string_view(type.def->detailed_name);
break;
}
case SymbolKind::Var: {
QueryVar& var = db->GetVar(use);
if (var.def)
ret.containerName = var.def->detailed_name;
ret.containerName = std::string_view(var.def->detailed_name);
break;
}
}
@ -470,7 +470,7 @@ optional<lsSymbolInformation> GetSymbolInfo(QueryDatabase* db,
info.name = type.def->ShortName();
else
info.name = type.def->detailed_name;
if (type.def->detailed_name != type.def->ShortName())
if (type.def->detailed_name.c_str() != type.def->ShortName())
info.containerName = type.def->detailed_name;
// TODO ClangSymbolKind -> lsSymbolKind
switch (type.def->kind) {

View File

@ -125,18 +125,14 @@ void Reflect(Writer& visitor, std::string_view& data) {
visitor.String(&data[0], (rapidjson::SizeType)data.size());
}
void Reflect(Reader& visitor, std::unique_ptr<char[]>& value) {
void Reflect(Reader& visitor, NTString& value) {
if (!visitor.IsString())
throw std::invalid_argument("std::string");
std::string t = visitor.GetString();
value = std::unique_ptr<char[]>(new char[t.size() + 1]);
strcpy(value.get(), t.c_str());
value = visitor.GetString();
}
void Reflect(Writer& visitor, std::unique_ptr<char[]>& value) {
if (!value)
visitor.String("");
else
visitor.String(value.get());
void Reflect(Writer& visitor, NTString& value) {
const char* s = value.c_str();
visitor.String(s ? s : "");
}
// TODO: Move this to indexer.cc
@ -169,9 +165,9 @@ void ReflectHoverAndComments(Reader& visitor, Def& def) {
template <typename Def>
void ReflectHoverAndComments(Writer& visitor, Def& def) {
// Don't emit empty hover and comments in JSON test mode.
if (!gTestOutputMode || def.hover.size())
if (!gTestOutputMode || !def.hover.empty())
ReflectMember(visitor, "hover", def.hover);
if (!gTestOutputMode || def.comments.size())
if (!gTestOutputMode || !def.comments.empty())
ReflectMember(visitor, "comments", def.comments);
}
@ -192,8 +188,8 @@ void ReflectShortName(Reader& visitor, Def& def) {
template <typename Def>
void ReflectShortName(Writer& visitor, Def& def) {
if (gTestOutputMode) {
std::string short_name =
def.detailed_name.substr(def.short_name_offset, def.short_name_size);
std::string short_name(
def.detailed_name.substr(def.short_name_offset, def.short_name_size));
ReflectMember(visitor, "short_name", short_name);
} else {
ReflectMember(visitor, "short_name_offset", def.short_name_offset);

View File

@ -1,6 +1,7 @@
#pragma once
#include "maybe.h"
#include "ntstring.h"
#include "port.h"
#include <macro_map.h>
@ -160,8 +161,8 @@ void Reflect(Writer& visitor, std::string& value);
void Reflect(Reader& visitor, std::string_view& view);
void Reflect(Writer& visitor, std::string_view& view);
void Reflect(Reader& visitor, std::unique_ptr<char[]>& value);
void Reflect(Writer& visitor, std::unique_ptr<char[]>& value);
void Reflect(Reader& visitor, NTString& value);
void Reflect(Writer& visitor, NTString& value);
// std::monostate is used to represent JSON null
void Reflect(Reader& visitor, std::monostate&);