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_consumer.h"
#include "file_contents.h" #include "file_contents.h"
#include "language_server_api.h" #include "language_server_api.h"
#include "maybe.h"
#include "performance.h" #include "performance.h"
#include "position.h" #include "position.h"
#include "serializer.h" #include "serializer.h"
@ -165,8 +166,8 @@ struct TypeDefDefinitionData {
// It's also difficult to identify a `class Foo;` statement with the clang // 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 // indexer API (it's doable using cursor AST traversal), so we don't bother
// supporting the feature. // supporting the feature.
optional<Range> definition_spelling; Maybe<Range> definition_spelling;
optional<Range> definition_extent; Maybe<Range> definition_extent;
// 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).
@ -264,8 +265,8 @@ struct FuncDefDefinitionData {
std::string detailed_name; std::string detailed_name;
std::string hover; std::string hover;
std::string comments; std::string comments;
optional<Range> definition_spelling; Maybe<Range> definition_spelling;
optional<Range> definition_extent; Maybe<Range> definition_extent;
// Type which declares this one (ie, it is a method) // Type which declares this one (ie, it is a method)
optional<TypeId> declaring_type; optional<TypeId> declaring_type;
@ -390,8 +391,8 @@ struct VarDefDefinitionData {
std::string comments; std::string comments;
// TODO: definitions should be a list of ranges, since there can be more // TODO: definitions should be a list of ranges, since there can be more
// than one - when?? // than one - when??
optional<Range> definition_spelling; Maybe<Range> definition_spelling;
optional<Range> definition_extent; Maybe<Range> definition_extent;
// Type of the variable. // Type of the variable.
optional<TypeId> variable_type; 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 } // 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) {} 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; 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 // Position
void Reflect(Reader& visitor, Position& value) { void Reflect(Reader& visitor, Position& value) {
if (visitor.Format() == SerializeFormat::Json) { if (visitor.Format() == SerializeFormat::Json) {

View File

@ -1,12 +1,12 @@
#pragma once #pragma once
#include <cassert> #include "maybe.h"
#include <cstdint>
#include <string>
#include "serializer.h" #include "serializer.h"
#include "utils.h" #include "utils.h"
#include <stdint.h>
#include <string>
struct Position { struct Position {
int16_t line; int16_t line;
int16_t column; int16_t column;
@ -49,6 +49,11 @@ struct Range {
}; };
MAKE_HASHABLE(Range, t.start, t.end); MAKE_HASHABLE(Range, t.start, t.end);
template <>
bool Maybe<Position>::has_value() const;
template <>
bool Maybe<Range>::has_value() const;
// Reflection // Reflection
void Reflect(Reader& visitor, Position& value); void Reflect(Reader& visitor, Position& value);
void Reflect(Writer& 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) { for (const IndexType& type : indexed.types) {
if (type.def.definition_spelling.has_value()) if (type.def.definition_spelling.has_value())
add_all_symbols(id_map.ToSymbol(type.id), SymbolRole::Definition, 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()) 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) for (const Range& use : type.uses)
add_all_symbols(id_map.ToSymbol(type.id), SymbolRole::Reference, use); add_all_symbols(id_map.ToSymbol(type.id), SymbolRole::Reference, use);
} }
for (const IndexFunc& func : indexed.funcs) { for (const IndexFunc& func : indexed.funcs) {
if (func.def.definition_spelling.has_value()) if (func.def.definition_spelling.has_value())
add_all_symbols(id_map.ToSymbol(func.id), SymbolRole::Definition, 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()) 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) { for (const IndexFunc::Declaration& decl : func.declarations) {
add_all_symbols(id_map.ToSymbol(func.id), SymbolRole::Declaration, add_all_symbols(id_map.ToSymbol(func.id), SymbolRole::Declaration,
decl.spelling); decl.spelling);
@ -271,9 +271,9 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IdMap& id_map, const IndexFile& in
for (const IndexVar& var : indexed.vars) { for (const IndexVar& var : indexed.vars) {
if (var.def.definition_spelling.has_value()) if (var.def.definition_spelling.has_value())
add_all_symbols(id_map.ToSymbol(var.id), SymbolRole::Definition, 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()) 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) { for (const Range& decl : var.declarations) {
add_all_symbols(id_map.ToSymbol(var.id), SymbolRole::Declaration, decl); add_all_symbols(id_map.ToSymbol(var.id), SymbolRole::Declaration, decl);
add_outline(id_map.ToSymbol(var.id), decl); add_outline(id_map.ToSymbol(var.id), decl);
@ -357,6 +357,11 @@ inline optional<QueryVarId> GetQueryVarIdFromUsr(QueryDatabase* query_db,
} // namespace } // namespace
template <>
bool Maybe<QueryLocation>::has_value() const {
return storage.range.start.line >= 0;
}
optional<QueryFileId> QueryDatabase::GetQueryFileIdFromPath( optional<QueryFileId> QueryDatabase::GetQueryFileIdFromPath(
const std::string& path) { const std::string& path) {
return ::GetQueryFileIdFromPath(this, path, false); return ::GetQueryFileIdFromPath(this, path, false);

View File

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

View File

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

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "maybe.h"
#include "port.h" #include "port.h"
#include <macro_map.h> #include <macro_map.h>
@ -211,6 +212,26 @@ void Reflect(Writer& visitor, optional<T>& value) {
else else
visitor.Null(); 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> template <typename T>
void ReflectMember(Writer& visitor, const char* name, optional<T>& value) { void ReflectMember(Writer& visitor, const char* name, optional<T>& value) {
// For TypeScript optional property key?: value in the spec, // 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 // Backport C++17 std::disjunction
namespace { namespace {
template <typename B0, typename... Bs> template <typename B0, typename... Bs>