mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-25 17:11:59 +00:00
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:
parent
e576df4f6f
commit
7bee63d0e0
@ -131,6 +131,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);
|
||||||
@ -144,7 +147,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 = "";
|
||||||
@ -152,11 +156,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;
|
||||||
@ -166,14 +170,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;
|
||||||
@ -181,17 +186,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).
|
||||||
@ -203,14 +209,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;
|
||||||
@ -248,7 +255,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,
|
||||||
|
@ -4,8 +4,12 @@
|
|||||||
#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 {
|
||||||
@ -68,7 +72,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);
|
||||||
|
72
src/query.cc
72
src/query.cc
@ -69,6 +69,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>");
|
||||||
@ -82,7 +127,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);
|
||||||
@ -90,7 +135,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);
|
||||||
@ -100,7 +145,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);
|
||||||
@ -109,7 +154,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);
|
||||||
@ -202,8 +247,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); \
|
||||||
@ -250,8 +297,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) {
|
||||||
@ -485,10 +534,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) {
|
||||||
@ -516,6 +565,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);
|
||||||
}
|
}
|
||||||
|
15
src/query.hh
15
src/query.hh
@ -66,7 +66,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;
|
||||||
@ -74,7 +74,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;
|
||||||
@ -147,9 +147,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();
|
||||||
|
|
||||||
@ -188,6 +188,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);
|
||||||
|
|
||||||
@ -257,8 +258,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())
|
||||||
|
23
src/utils.hh
23
src/utils.hh
@ -128,4 +128,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
|
||||||
|
Loading…
Reference in New Issue
Block a user