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, DeclRef &value);
template <typename T>
using VectorAdapter = std::vector<T, std::allocator<T>>;
template <typename D> struct NameMixin {
std::string_view Name(bool qualified) const {
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.
const char *detailed_name = "";
const char *hover = "";
@ -164,11 +168,11 @@ struct FuncDef : NameMixin<FuncDef> {
Maybe<DeclRef> spell;
// Method this method overrides.
std::vector<Usr> bases;
V<Usr> bases;
// Local variables or parameters.
std::vector<Usr> vars;
V<Usr> vars;
// Functions that this function calls.
std::vector<SymbolRef> callees;
V<SymbolRef> callees;
int file_id = -1; // not serialized
int16_t qual_name_offset = 0;
@ -178,14 +182,15 @@ struct FuncDef : NameMixin<FuncDef> {
SymbolKind parent_kind = SymbolKind::Unknown;
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,
callees, qual_name_offset, short_name_offset,
REFLECT_STRUCT(FuncDef<VectorAdapter>, detailed_name, hover, comments, spell,
bases, vars, callees, qual_name_offset, short_name_offset,
short_name_size, kind, parent_kind, storage);
struct IndexFunc : NameMixin<IndexFunc> {
using Def = FuncDef;
using Def = FuncDef<VectorAdapter>;
Usr usr;
Def def;
std::vector<DeclRef> declarations;
@ -193,17 +198,18 @@ struct IndexFunc : NameMixin<IndexFunc> {
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 *hover = "";
const char *comments = "";
Maybe<DeclRef> spell;
std::vector<Usr> bases;
V<Usr> bases;
// Types, functions, and variables defined in this type.
std::vector<Usr> funcs;
std::vector<Usr> types;
std::vector<std::pair<Usr, int64_t>> vars;
V<Usr> funcs;
V<Usr> types;
V<std::pair<Usr, int64_t>> vars;
// If set, then this is the same underlying type as the given value (ie, this
// type comes from a using or typedef statement).
@ -215,14 +221,15 @@ struct TypeDef : NameMixin<TypeDef> {
SymbolKind 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,
funcs, types, vars, alias_of, qual_name_offset,
REFLECT_STRUCT(TypeDef<VectorAdapter>, detailed_name, hover, comments, spell,
bases, funcs, types, vars, alias_of, qual_name_offset,
short_name_offset, short_name_size, kind, parent_kind);
struct IndexType {
using Def = TypeDef;
using Def = TypeDef<VectorAdapter>;
Usr usr;
Def def;
std::vector<DeclRef> declarations;
@ -260,7 +267,8 @@ struct VarDef : NameMixin<VarDef> {
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,
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 "query.hh"
#include <llvm/ADT/iterator_range.h>
#include <unordered_set>
using namespace llvm;
namespace ccls {
namespace {
struct ReferenceParam : public TextDocumentPositionParam {
@ -80,7 +84,7 @@ void MessageHandler::textDocument_references(JsonReader &reader,
if (def.spell) {
parent_kind = GetSymbolKind(db, sym);
if (param.base)
for (Usr usr : def.GetBases())
for (Usr usr : make_range(def.bases_begin(), def.bases_end()))
if (!seen.count(usr)) {
seen.insert(usr);
stack.push_back(usr);

View File

@ -81,6 +81,51 @@ bool TryReplaceDef(llvm::SmallVectorImpl<Q> &def_list, Q &&def) {
} // 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 r;
static IndexFile empty(current->path, "<empty>");
@ -94,7 +139,7 @@ IndexUpdate IndexUpdate::CreateDelta(IndexFile *previous, IndexFile *current) {
for (auto &it : previous->usr2func) {
auto &func = it.second;
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_uses[func.usr].first = std::move(func.uses);
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) {
auto &func = it.second;
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_uses[func.usr].second = std::move(func.uses);
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) {
auto &type = it.second;
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_uses[type.usr].first = std::move(type.uses);
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) {
auto &type = it.second;
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_uses[type.usr].second = std::move(type.uses);
r.types_derived[type.usr].second = std::move(type.derived);
@ -214,8 +259,10 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
#define REMOVE_ADD(C, F) \
for (auto &it : u->C##s_##F) { \
auto R = C##_usr.try_emplace({it.first}, C##_usr.size()); \
if (R.second) \
C##s.emplace_back().usr = it.first; \
if (R.second) { \
C##s.emplace_back(); \
C##s.back().usr = it.first; \
} \
auto &entity = C##s[R.first->second]; \
RemoveRange(entity.F, it.second.first); \
AddRange(entity.F, it.second.second); \
@ -262,8 +309,10 @@ void DB::ApplyIndexUpdate(IndexUpdate *u) {
llvm::DenseMap<Usr, int, DenseMapInfoForUsr> &entity_usr,
auto &entities, auto &p, bool hint_implicit) {
auto R = entity_usr.try_emplace(usr, entity_usr.size());
if (R.second)
entities.emplace_back().usr = usr;
if (R.second) {
entities.emplace_back();
entities.back().usr = usr;
}
auto &entity = entities[R.first->second];
for (Use &use : p.first) {
if (hint_implicit && use.role & Role::Implicit) {
@ -497,10 +546,10 @@ int ComputeRangeSize(const Range &range) {
return range.end.column - range.start.column;
}
template <typename Q>
template <typename Q, typename C>
std::vector<Use>
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;
ret.reserve(usrs.size());
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) {
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) {
return GetDeclarations(db->type_usr, db->types, usrs);
}

View File

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