Add Maybe<T> and change definition_{spelling,extent} from optional to Maybe

sizeof(db->funcs[0].def) decreases from 248 to 232
sizeof(db->types[0].def) decreases from 272 to 256
sizeof(db->vars[0].def) decreases from 184 to 168
This commit is contained in:
Fangrui Song 2018-02-01 21:31:56 -08:00
parent 74f9be1d6f
commit 392cd79d04
8 changed files with 116 additions and 18 deletions

View File

@ -8,6 +8,7 @@
#include "file_consumer.h"
#include "file_contents.h"
#include "language_server_api.h"
#include "maybe.h"
#include "performance.h"
#include "position.h"
#include "serializer.h"
@ -165,8 +166,8 @@ struct TypeDefDefinitionData {
// It's also difficult to identify a `class Foo;` statement with the clang
// indexer API (it's doable using cursor AST traversal), so we don't bother
// supporting the feature.
optional<Range> definition_spelling;
optional<Range> definition_extent;
Maybe<Range> definition_spelling;
Maybe<Range> definition_extent;
// If set, then this is the same underlying type as the given value (ie, this
// type comes from a using or typedef statement).
@ -264,8 +265,8 @@ struct FuncDefDefinitionData {
std::string detailed_name;
std::string hover;
std::string comments;
optional<Range> definition_spelling;
optional<Range> definition_extent;
Maybe<Range> definition_spelling;
Maybe<Range> definition_extent;
// Type which declares this one (ie, it is a method)
optional<TypeId> declaring_type;
@ -390,8 +391,8 @@ struct VarDefDefinitionData {
std::string comments;
// TODO: definitions should be a list of ranges, since there can be more
// than one - when??
optional<Range> definition_spelling;
optional<Range> definition_extent;
Maybe<Range> definition_spelling;
Maybe<Range> definition_extent;
// Type of the variable.
optional<TypeId> variable_type;

44
src/maybe.h Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#include <optional.h>
#include <utility>
template <typename T>
class Maybe {
T storage;
public:
constexpr Maybe() = default;
Maybe(const Maybe&) = default;
Maybe(const T& x) : storage(x) {}
Maybe(T&& x) : storage(std::forward<T>(x)) {}
Maybe& operator=(const Maybe&) = default;
Maybe& operator=(const T& x) {
storage = x;
return *this;
}
const T *operator->() const { return &storage; }
T *operator->() { return &storage; }
const T& operator*() const { return storage; }
T& operator*() { return storage; }
bool has_value() const;
explicit operator bool() const { return has_value(); }
operator optional<T>() const {
if (has_value())
return storage;
return nullopt;
}
void operator=(optional<T>&& o) {
storage = o ? *o : T();
}
// Does not test if has_value()
bool operator==(const Maybe& o) const {
return storage == o.storage;
}
};

View File

@ -11,7 +11,7 @@ const char* SkipAfter(const char* input, char skip_after) {
}
} // namespace
Position::Position() : line(0), column(0) {}
Position::Position() : line(-1), column(-1) {}
Position::Position(int16_t line, int16_t column) : line(line), column(column) {}
@ -146,6 +146,16 @@ bool Range::operator<(const Range& that) const {
return end < that.end;
}
template <>
bool Maybe<Position>::has_value() const {
return storage.line >= 0;
}
template <>
bool Maybe<Range>::has_value() const {
return storage.start.line >= 0;
}
// Position
void Reflect(Reader& visitor, Position& value) {
if (visitor.Format() == SerializeFormat::Json) {

View File

@ -1,12 +1,12 @@
#pragma once
#include <cassert>
#include <cstdint>
#include <string>
#include "maybe.h"
#include "serializer.h"
#include "utils.h"
#include <stdint.h>
#include <string>
struct Position {
int16_t line;
int16_t column;
@ -49,6 +49,11 @@ struct Range {
};
MAKE_HASHABLE(Range, t.start, t.end);
template <>
bool Maybe<Position>::has_value() const;
template <>
bool Maybe<Range>::has_value() const;
// Reflection
void Reflect(Reader& visitor, Position& value);
void Reflect(Writer& visitor, Position& value);

View File

@ -233,18 +233,18 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IdMap& id_map, const IndexFile& in
for (const IndexType& type : indexed.types) {
if (type.def.definition_spelling.has_value())
add_all_symbols(id_map.ToSymbol(type.id), SymbolRole::Definition,
type.def.definition_spelling.value());
*type.def.definition_spelling);
if (type.def.definition_extent.has_value())
add_outline(id_map.ToSymbol(type.id), type.def.definition_extent.value());
add_outline(id_map.ToSymbol(type.id), *type.def.definition_extent);
for (const Range& use : type.uses)
add_all_symbols(id_map.ToSymbol(type.id), SymbolRole::Reference, use);
}
for (const IndexFunc& func : indexed.funcs) {
if (func.def.definition_spelling.has_value())
add_all_symbols(id_map.ToSymbol(func.id), SymbolRole::Definition,
func.def.definition_spelling.value());
*func.def.definition_spelling);
if (func.def.definition_extent.has_value())
add_outline(id_map.ToSymbol(func.id), func.def.definition_extent.value());
add_outline(id_map.ToSymbol(func.id), *func.def.definition_extent);
for (const IndexFunc::Declaration& decl : func.declarations) {
add_all_symbols(id_map.ToSymbol(func.id), SymbolRole::Declaration,
decl.spelling);
@ -271,9 +271,9 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IdMap& id_map, const IndexFile& in
for (const IndexVar& var : indexed.vars) {
if (var.def.definition_spelling.has_value())
add_all_symbols(id_map.ToSymbol(var.id), SymbolRole::Definition,
var.def.definition_spelling.value());
*var.def.definition_spelling);
if (var.def.definition_extent.has_value())
add_outline(id_map.ToSymbol(var.id), var.def.definition_extent.value());
add_outline(id_map.ToSymbol(var.id), *var.def.definition_extent);
for (const Range& decl : var.declarations) {
add_all_symbols(id_map.ToSymbol(var.id), SymbolRole::Declaration, decl);
add_outline(id_map.ToSymbol(var.id), decl);
@ -357,6 +357,11 @@ inline optional<QueryVarId> GetQueryVarIdFromUsr(QueryDatabase* query_db,
} // namespace
template <>
bool Maybe<QueryLocation>::has_value() const {
return storage.range.start.line >= 0;
}
optional<QueryFileId> QueryDatabase::GetQueryFileIdFromPath(
const std::string& path) {
return ::GetQueryFileIdFromPath(this, path, false);

View File

@ -57,6 +57,9 @@ struct hash<::SymbolKind> {
};
} // namespace std
template <>
bool Maybe<QueryLocation>::has_value() const;
struct SymbolIdx {
SymbolKind kind;
size_t idx;

View File

@ -45,7 +45,7 @@ optional<QueryLocation> GetDefinitionSpellingOfSymbol(QueryDatabase* db,
case SymbolKind::Type: {
QueryType& type = db->types[symbol.idx];
if (type.def)
return type.def->definition_spelling;
return *type.def->definition_spelling;
break;
}
case SymbolKind::Func: {

View File

@ -1,5 +1,6 @@
#pragma once
#include "maybe.h"
#include "port.h"
#include <macro_map.h>
@ -211,6 +212,26 @@ void Reflect(Writer& visitor, optional<T>& value) {
else
visitor.Null();
}
// The same as std::optional
template <typename T>
void Reflect(Reader& visitor, Maybe<T>& value) {
if (visitor.IsNull()) {
visitor.GetNull();
return;
}
T real_value;
Reflect(visitor, real_value);
value = real_value;
}
template <typename T>
void Reflect(Writer& visitor, Maybe<T>& value) {
if (value)
Reflect(visitor, *value);
else
visitor.Null();
}
template <typename T>
void ReflectMember(Writer& visitor, const char* name, optional<T>& value) {
// For TypeScript optional property key?: value in the spec,
@ -222,6 +243,15 @@ void ReflectMember(Writer& visitor, const char* name, optional<T>& value) {
}
}
// The same as std::optional
template <typename T>
void ReflectMember(Writer& visitor, const char* name, Maybe<T>& value) {
if (value.has_value() || visitor.Format() != SerializeFormat::Json) {
visitor.Key(name);
Reflect(visitor, value);
}
}
// Backport C++17 std::disjunction
namespace {
template <typename B0, typename... Bs>