Change containers of Query*::Def fields from std::vector to ccls::Vec

Query*::Def contain several immutable std::vector fields. Change them to
ccls::Vec to save bytes which were wasted by `capacity`.
This commit is contained in:
Fangrui Song 2019-03-15 09:33:44 -07:00
parent a0e76254de
commit 4276c2b383
5 changed files with 126 additions and 38 deletions

View File

@ -143,6 +143,9 @@ void Reflect(BinaryWriter &visitor, SymbolRef &value);
void Reflect(BinaryWriter &visitor, Use &value); void Reflect(BinaryWriter &visitor, Use &value);
void Reflect(BinaryWriter &visitor, DeclRef &value); void Reflect(BinaryWriter &visitor, DeclRef &value);
template <typename T>
using VectorAdapter = std::vector<T, std::allocator<T>>;
template <typename D> struct NameMixin { template <typename D> struct NameMixin {
std::string_view Name(bool qualified) const { std::string_view Name(bool qualified) const {
auto self = static_cast<const D *>(this); auto self = static_cast<const D *>(this);
@ -156,7 +159,8 @@ template <typename D> struct NameMixin {
} }
}; };
struct FuncDef : NameMixin<FuncDef> { template <template <typename T> class V>
struct FuncDef : NameMixin<FuncDef<V>> {
// General metadata. // General metadata.
const char *detailed_name = ""; const char *detailed_name = "";
const char *hover = ""; const char *hover = "";
@ -164,11 +168,11 @@ struct FuncDef : NameMixin<FuncDef> {
Maybe<DeclRef> spell; Maybe<DeclRef> spell;
// Method this method overrides. // Method this method overrides.
std::vector<Usr> bases; V<Usr> bases;
// Local variables or parameters. // Local variables or parameters.
std::vector<Usr> vars; V<Usr> vars;
// Functions that this function calls. // Functions that this function calls.
std::vector<SymbolRef> callees; V<SymbolRef> callees;
int file_id = -1; // not serialized int file_id = -1; // not serialized
int16_t qual_name_offset = 0; int16_t qual_name_offset = 0;
@ -178,14 +182,15 @@ struct FuncDef : NameMixin<FuncDef> {
SymbolKind parent_kind = SymbolKind::Unknown; SymbolKind parent_kind = SymbolKind::Unknown;
uint8_t storage = clang::SC_None; uint8_t storage = clang::SC_None;
std::vector<Usr> GetBases() const { return bases; } const Usr *bases_begin() const { return bases.begin(); }
const Usr *bases_end() const { return bases.end(); }
}; };
REFLECT_STRUCT(FuncDef, detailed_name, hover, comments, spell, bases, vars, REFLECT_STRUCT(FuncDef<VectorAdapter>, detailed_name, hover, comments, spell,
callees, qual_name_offset, short_name_offset, bases, vars, callees, qual_name_offset, short_name_offset,
short_name_size, kind, parent_kind, storage); short_name_size, kind, parent_kind, storage);
struct IndexFunc : NameMixin<IndexFunc> { struct IndexFunc : NameMixin<IndexFunc> {
using Def = FuncDef; using Def = FuncDef<VectorAdapter>;
Usr usr; Usr usr;
Def def; Def def;
std::vector<DeclRef> declarations; std::vector<DeclRef> declarations;
@ -193,17 +198,18 @@ struct IndexFunc : NameMixin<IndexFunc> {
std::vector<Use> uses; std::vector<Use> uses;
}; };
struct TypeDef : NameMixin<TypeDef> { template <template <typename T> class V>
struct TypeDef : NameMixin<TypeDef<V>> {
const char *detailed_name = ""; const char *detailed_name = "";
const char *hover = ""; const char *hover = "";
const char *comments = ""; const char *comments = "";
Maybe<DeclRef> spell; Maybe<DeclRef> spell;
std::vector<Usr> bases; V<Usr> bases;
// Types, functions, and variables defined in this type. // Types, functions, and variables defined in this type.
std::vector<Usr> funcs; V<Usr> funcs;
std::vector<Usr> types; V<Usr> types;
std::vector<std::pair<Usr, int64_t>> vars; V<std::pair<Usr, int64_t>> vars;
// If set, then this is the same underlying type as the given value (ie, this // If set, then this is the same underlying type as the given value (ie, this
// type comes from a using or typedef statement). // type comes from a using or typedef statement).
@ -215,14 +221,15 @@ struct TypeDef : NameMixin<TypeDef> {
SymbolKind kind = SymbolKind::Unknown; SymbolKind kind = SymbolKind::Unknown;
SymbolKind parent_kind = SymbolKind::Unknown; SymbolKind parent_kind = SymbolKind::Unknown;
std::vector<Usr> GetBases() const { return bases; } const Usr *bases_begin() const { return bases.begin(); }
const Usr *bases_end() const { return bases.end(); }
}; };
REFLECT_STRUCT(TypeDef, detailed_name, hover, comments, spell, bases, REFLECT_STRUCT(TypeDef<VectorAdapter>, detailed_name, hover, comments, spell,
funcs, types, vars, alias_of, qual_name_offset, bases, funcs, types, vars, alias_of, qual_name_offset,
short_name_offset, short_name_size, kind, parent_kind); short_name_offset, short_name_size, kind, parent_kind);
struct IndexType { struct IndexType {
using Def = TypeDef; using Def = TypeDef<VectorAdapter>;
Usr usr; Usr usr;
Def def; Def def;
std::vector<DeclRef> declarations; std::vector<DeclRef> declarations;
@ -260,7 +267,8 @@ struct VarDef : NameMixin<VarDef> {
storage == clang::SC_Register); storage == clang::SC_Register);
} }
std::vector<Usr> GetBases() const { return {}; } const Usr *bases_begin() const { return nullptr; }
const Usr *bases_end() const { return nullptr; }
}; };
REFLECT_STRUCT(VarDef, detailed_name, hover, comments, spell, type, REFLECT_STRUCT(VarDef, detailed_name, hover, comments, spell, type,
qual_name_offset, short_name_offset, short_name_size, kind, qual_name_offset, short_name_offset, short_name_size, kind,

View File

@ -16,8 +16,12 @@ limitations under the License.
#include "message_handler.hh" #include "message_handler.hh"
#include "query.hh" #include "query.hh"
#include <llvm/ADT/iterator_range.h>
#include <unordered_set> #include <unordered_set>
using namespace llvm;
namespace ccls { namespace ccls {
namespace { namespace {
struct ReferenceParam : public TextDocumentPositionParam { struct ReferenceParam : public TextDocumentPositionParam {
@ -80,7 +84,7 @@ void MessageHandler::textDocument_references(JsonReader &reader,
if (def.spell) { if (def.spell) {
parent_kind = GetSymbolKind(db, sym); parent_kind = GetSymbolKind(db, sym);
if (param.base) if (param.base)
for (Usr usr : def.GetBases()) for (Usr usr : make_range(def.bases_begin(), def.bases_end()))
if (!seen.count(usr)) { if (!seen.count(usr)) {
seen.insert(usr); seen.insert(usr);
stack.push_back(usr); stack.push_back(usr);

View File

@ -81,6 +81,51 @@ bool TryReplaceDef(llvm::SmallVectorImpl<Q> &def_list, Q &&def) {
} // namespace } // namespace
template <typename T> Vec<T> Convert(const std::vector<T> &o) {
Vec<T> r{std::make_unique<T[]>(o.size()), (int)o.size()};
std::copy(o.begin(), o.end(), r.begin());
return r;
}
QueryFunc::Def Convert(const IndexFunc::Def &o) {
QueryFunc::Def r;
r.detailed_name = o.detailed_name;
r.hover = o.hover;
r.comments = o.comments;
r.spell = o.spell;
r.bases = Convert(o.bases);
r.vars = Convert(o.vars);
r.callees = Convert(o.callees);
// no file_id
r.qual_name_offset = o.qual_name_offset;
r.short_name_offset = o.short_name_offset;
r.short_name_size = o.short_name_size;
r.kind = o.kind;
r.parent_kind = o.parent_kind;
r.storage = o.storage;
return r;
}
QueryType::Def Convert(const IndexType::Def &o) {
QueryType::Def r;
r.detailed_name = o.detailed_name;
r.hover = o.hover;
r.comments = o.comments;
r.spell = o.spell;
r.bases = Convert(o.bases);
r.funcs = Convert(o.funcs);
r.types = Convert(o.types);
r.vars = Convert(o.vars);
r.alias_of = o.alias_of;
// no file_id
r.qual_name_offset = o.qual_name_offset;
r.short_name_offset = o.short_name_offset;
r.short_name_size = o.short_name_size;
r.kind = o.kind;
r.parent_kind = o.parent_kind;
return r;
}
IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) { IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
IndexUpdate r; IndexUpdate r;
static IndexFile empty(current->path, "<empty>"); static IndexFile empty(current->path, "<empty>");
@ -94,7 +139,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
for (auto &it : previous->usr2func) { for (auto &it : previous->usr2func) {
auto &func = it.second; auto &func = it.second;
if (func.def.detailed_name[0]) if (func.def.detailed_name[0])
r.funcs_removed.emplace_back(func.usr, func.def); r.funcs_removed.emplace_back(func.usr, Convert(func.def));
r.funcs_declarations[func.usr].first = std::move(func.declarations); r.funcs_declarations[func.usr].first = std::move(func.declarations);
r.funcs_uses[func.usr].first = std::move(func.uses); r.funcs_uses[func.usr].first = std::move(func.uses);
r.funcs_derived[func.usr].first = std::move(func.derived); r.funcs_derived[func.usr].first = std::move(func.derived);
@ -102,7 +147,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
for (auto &it : current->usr2func) { for (auto &it : current->usr2func) {
auto &func = it.second; auto &func = it.second;
if (func.def.detailed_name[0]) if (func.def.detailed_name[0])
r.funcs_def_update.emplace_back(it.first, func.def); r.funcs_def_update.emplace_back(it.first, Convert(func.def));
r.funcs_declarations[func.usr].second = std::move(func.declarations); r.funcs_declarations[func.usr].second = std::move(func.declarations);
r.funcs_uses[func.usr].second = std::move(func.uses); r.funcs_uses[func.usr].second = std::move(func.uses);
r.funcs_derived[func.usr].second = std::move(func.derived); r.funcs_derived[func.usr].second = std::move(func.derived);
@ -112,7 +157,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
for (auto &it : previous->usr2type) { for (auto &it : previous->usr2type) {
auto &type = it.second; auto &type = it.second;
if (type.def.detailed_name[0]) if (type.def.detailed_name[0])
r.types_removed.emplace_back(type.usr, type.def); r.types_removed.emplace_back(type.usr, Convert(type.def));
r.types_declarations[type.usr].first = std::move(type.declarations); r.types_declarations[type.usr].first = std::move(type.declarations);
r.types_uses[type.usr].first = std::move(type.uses); r.types_uses[type.usr].first = std::move(type.uses);
r.types_derived[type.usr].first = std::move(type.derived); r.types_derived[type.usr].first = std::move(type.derived);
@ -121,7 +166,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
for (auto &it : current->usr2type) { for (auto &it : current->usr2type) {
auto &type = it.second; auto &type = it.second;
if (type.def.detailed_name[0]) if (type.def.detailed_name[0])
r.types_def_update.emplace_back(it.first, type.def); r.types_def_update.emplace_back(it.first, Convert(type.def));
r.types_declarations[type.usr].second = std::move(type.declarations); r.types_declarations[type.usr].second = std::move(type.declarations);
r.types_uses[type.usr].second = std::move(type.uses); r.types_uses[type.usr].second = std::move(type.uses);
r.types_derived[type.usr].second = std::move(type.derived); r.types_derived[type.usr].second = std::move(type.derived);
@ -214,8 +259,10 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
#define REMOVE_ADD(C, F) \ #define REMOVE_ADD(C, F) \
for (auto &it : u->C##s_##F) { \ for (auto &it : u->C##s_##F) { \
auto R = C##_usr.try_emplace({it.first}, C##_usr.size()); \ auto R = C##_usr.try_emplace({it.first}, C##_usr.size()); \
if (R.second) \ if (R.second) { \
C##s.emplace_back().usr = it.first; \ C##s.emplace_back(); \
C##s.back().usr = it.first; \
} \
auto &entity = C##s[R.first->second]; \ auto &entity = C##s[R.first->second]; \
RemoveRange(entity.F, it.second.first); \ RemoveRange(entity.F, it.second.first); \
AddRange(entity.F, it.second.second); \ AddRange(entity.F, it.second.second); \
@ -262,8 +309,10 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
llvm::DenseMap<Usr, int, DenseMapInfoForUsr> &entity_usr, llvm::DenseMap<Usr, int, DenseMapInfoForUsr> &entity_usr,
auto &entities, auto &p, bool hint_implicit) { auto &entities, auto &p, bool hint_implicit) {
auto R = entity_usr.try_emplace(usr, entity_usr.size()); auto R = entity_usr.try_emplace(usr, entity_usr.size());
if (R.second) if (R.second) {
entities.emplace_back().usr = usr; entities.emplace_back();
entities.back().usr = usr;
}
auto &entity = entities[R.first->second]; auto &entity = entities[R.first->second];
for (Use &use : p.first) { for (Use &use : p.first) {
if (hint_implicit && use.role & Role::Implicit) { if (hint_implicit && use.role & Role::Implicit) {
@ -497,10 +546,10 @@ int ComputeRangeSize(const Range &range) {
return range.end.column - range.start.column; return range.end.column - range.start.column;
} }
template <typename Q> template <typename Q, typename C>
std::vector<Use> std::vector<Use>
GetDeclarations(llvm::DenseMap<Usr, int, DenseMapInfoForUsr> &entity_usr, GetDeclarations(llvm::DenseMap<Usr, int, DenseMapInfoForUsr> &entity_usr,
std::vector<Q> &entities, const std::vector<Usr> &usrs) { llvm::SmallVectorImpl<Q> &entities, const C &usrs) {
std::vector<Use> ret; std::vector<Use> ret;
ret.reserve(usrs.size()); ret.reserve(usrs.size());
for (Usr usr : usrs) { for (Usr usr : usrs) {
@ -528,6 +577,9 @@ Maybe<DeclRef> GetDefinitionSpell(DB *db, SymbolIdx sym) {
std::vector<Use> GetFuncDeclarations(DB *db, const std::vector<Usr> &usrs) { std::vector<Use> GetFuncDeclarations(DB *db, const std::vector<Usr> &usrs) {
return GetDeclarations(db->func_usr, db->funcs, usrs); return GetDeclarations(db->func_usr, db->funcs, usrs);
} }
std::vector<Use> GetFuncDeclarations(DB *db, const Vec<Usr> &usrs) {
return GetDeclarations(db->func_usr, db->funcs, usrs);
}
std::vector<Use> GetTypeDeclarations(DB *db, const std::vector<Usr> &usrs) { std::vector<Use> GetTypeDeclarations(DB *db, const std::vector<Usr> &usrs) {
return GetDeclarations(db->type_usr, db->types, usrs); return GetDeclarations(db->type_usr, db->types, usrs);
} }

View File

@ -77,7 +77,7 @@ template <typename T>
using Update = using Update =
std::unordered_map<Usr, std::pair<std::vector<T>, std::vector<T>>>; std::unordered_map<Usr, std::pair<std::vector<T>, std::vector<T>>>;
struct QueryFunc : QueryEntity<QueryFunc, FuncDef> { struct QueryFunc : QueryEntity<QueryFunc, FuncDef<Vec>> {
Usr usr; Usr usr;
llvm::SmallVector<Def, 1> def; llvm::SmallVector<Def, 1> def;
std::vector<DeclRef> declarations; std::vector<DeclRef> declarations;
@ -85,7 +85,7 @@ struct QueryFunc : QueryEntity<QueryFunc, FuncDef> {
std::vector<Use> uses; std::vector<Use> uses;
}; };
struct QueryType : QueryEntity<QueryType, TypeDef> { struct QueryType : QueryEntity<QueryType, TypeDef<Vec>> {
Usr usr; Usr usr;
llvm::SmallVector<Def, 1> def; llvm::SmallVector<Def, 1> def;
std::vector<DeclRef> declarations; std::vector<DeclRef> declarations;
@ -158,9 +158,9 @@ struct DB {
std::vector<QueryFile> files; std::vector<QueryFile> files;
llvm::StringMap<int> name2file_id; llvm::StringMap<int> name2file_id;
llvm::DenseMap<Usr, int, DenseMapInfoForUsr> func_usr, type_usr, var_usr; llvm::DenseMap<Usr, int, DenseMapInfoForUsr> func_usr, type_usr, var_usr;
std::vector<QueryFunc> funcs; llvm::SmallVector<QueryFunc, 0> funcs;
std::vector<QueryType> types; llvm::SmallVector<QueryType, 0> types;
std::vector<QueryVar> vars; llvm::SmallVector<QueryVar, 0> vars;
void clear(); void clear();
@ -199,6 +199,7 @@ Maybe<DeclRef> GetDefinitionSpell(DB *db, SymbolIdx sym);
// Get defining declaration (if exists) or an arbitrary declaration (otherwise) // Get defining declaration (if exists) or an arbitrary declaration (otherwise)
// for each id. // for each id.
std::vector<Use> GetFuncDeclarations(DB *, const std::vector<Usr> &); std::vector<Use> GetFuncDeclarations(DB *, const std::vector<Usr> &);
std::vector<Use> GetFuncDeclarations(DB *, const Vec<Usr> &);
std::vector<Use> GetTypeDeclarations(DB *, const std::vector<Usr> &); std::vector<Use> GetTypeDeclarations(DB *, const std::vector<Usr> &);
std::vector<DeclRef> GetVarDeclarations(DB *, const std::vector<Usr> &, unsigned); std::vector<DeclRef> GetVarDeclarations(DB *, const std::vector<Usr> &, unsigned);
@ -268,8 +269,8 @@ void EachOccurrence(DB *db, SymbolIdx sym, bool include_decl, Fn &&fn) {
SymbolKind GetSymbolKind(DB *db, SymbolIdx sym); SymbolKind GetSymbolKind(DB *db, SymbolIdx sym);
template <typename Fn> template <typename C, typename Fn>
void EachDefinedFunc(DB *db, const std::vector<Usr> &usrs, Fn &&fn) { void EachDefinedFunc(DB *db, const C &usrs, Fn &&fn) {
for (Usr usr : usrs) { for (Usr usr : usrs) {
auto &obj = db->Func(usr); auto &obj = db->Func(usr);
if (!obj.def.empty()) if (!obj.def.empty())

View File

@ -140,4 +140,27 @@ public:
bool operator==(const Maybe &o) const { return storage == o.storage; } bool operator==(const Maybe &o) const { return storage == o.storage; }
bool operator!=(const Maybe &o) const { return !(*this == o); } bool operator!=(const Maybe &o) const { return !(*this == o); }
}; };
template <typename T> struct Vec {
std::unique_ptr<T[]> a;
int s = 0;
#if !(__clang__ || __GNUC__ > 7 || __GNUC__ == 7 && __GNUC_MINOR__ >= 4)
// Work around a bug in GCC<7.4 that optional<IndexUpdate> would not be
// construtible.
Vec() = default;
Vec(const Vec &o) : a(std::make_unique<T[]>(o.s)), s(o.s) {
std::copy(o.a.get(), o.a.get() + o.s, a.get());
}
Vec(Vec &&) = default;
Vec &operator=(Vec &&) = default;
Vec(std::unique_ptr<T[]> a, int s) : a(std::move(a)), s(s) {}
#endif
const T *begin() const { return a.get(); }
T *begin() { return a.get(); }
const T *end() const { return a.get() + s; }
T *end() { return a.get() + s; }
int size() const { return s; }
const T &operator[](size_t i) const { return a.get()[i]; }
T &operator[](size_t i) { return a.get()[i]; }
};
} // namespace ccls } // namespace ccls