From 392cd79d045c3cdf3298d2435f2f82c96f563050 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Thu, 1 Feb 2018 21:31:56 -0800 Subject: [PATCH] Add Maybe 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 --- src/indexer.h | 13 +++++++------ src/maybe.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/position.cc | 12 +++++++++++- src/position.h | 13 +++++++++---- src/query.cc | 17 +++++++++++------ src/query.h | 3 +++ src/query_utils.cc | 2 +- src/serializer.h | 30 ++++++++++++++++++++++++++++++ 8 files changed, 116 insertions(+), 18 deletions(-) create mode 100644 src/maybe.h diff --git a/src/indexer.h b/src/indexer.h index 9e1b40fb..f5b148a9 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -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 definition_spelling; - optional definition_extent; + Maybe definition_spelling; + Maybe 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 definition_spelling; - optional definition_extent; + Maybe definition_spelling; + Maybe definition_extent; // Type which declares this one (ie, it is a method) optional 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 definition_spelling; - optional definition_extent; + Maybe definition_spelling; + Maybe definition_extent; // Type of the variable. optional variable_type; diff --git a/src/maybe.h b/src/maybe.h new file mode 100644 index 00000000..19628151 --- /dev/null +++ b/src/maybe.h @@ -0,0 +1,44 @@ +#pragma once + +#include + +#include + +template +class Maybe { + T storage; + +public: + constexpr Maybe() = default; + Maybe(const Maybe&) = default; + Maybe(const T& x) : storage(x) {} + Maybe(T&& x) : storage(std::forward(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() const { + if (has_value()) + return storage; + return nullopt; + } + + void operator=(optional&& o) { + storage = o ? *o : T(); + } + + // Does not test if has_value() + bool operator==(const Maybe& o) const { + return storage == o.storage; + } +}; diff --git a/src/position.cc b/src/position.cc index d102b030..d750793f 100644 --- a/src/position.cc +++ b/src/position.cc @@ -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::has_value() const { + return storage.line >= 0; +} + +template <> +bool Maybe::has_value() const { + return storage.start.line >= 0; +} + // Position void Reflect(Reader& visitor, Position& value) { if (visitor.Format() == SerializeFormat::Json) { diff --git a/src/position.h b/src/position.h index 18809c69..123320c2 100644 --- a/src/position.h +++ b/src/position.h @@ -1,12 +1,12 @@ #pragma once -#include -#include -#include - +#include "maybe.h" #include "serializer.h" #include "utils.h" +#include +#include + struct Position { int16_t line; int16_t column; @@ -49,6 +49,11 @@ struct Range { }; MAKE_HASHABLE(Range, t.start, t.end); +template <> +bool Maybe::has_value() const; +template <> +bool Maybe::has_value() const; + // Reflection void Reflect(Reader& visitor, Position& value); void Reflect(Writer& visitor, Position& value); diff --git a/src/query.cc b/src/query.cc index da85212b..29e3001a 100644 --- a/src/query.cc +++ b/src/query.cc @@ -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 GetQueryVarIdFromUsr(QueryDatabase* query_db, } // namespace +template <> +bool Maybe::has_value() const { + return storage.range.start.line >= 0; +} + optional QueryDatabase::GetQueryFileIdFromPath( const std::string& path) { return ::GetQueryFileIdFromPath(this, path, false); diff --git a/src/query.h b/src/query.h index 3abf8f7e..6d05db7c 100644 --- a/src/query.h +++ b/src/query.h @@ -57,6 +57,9 @@ struct hash<::SymbolKind> { }; } // namespace std +template <> +bool Maybe::has_value() const; + struct SymbolIdx { SymbolKind kind; size_t idx; diff --git a/src/query_utils.cc b/src/query_utils.cc index ebb5d1ed..4aa5632b 100644 --- a/src/query_utils.cc +++ b/src/query_utils.cc @@ -45,7 +45,7 @@ optional 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: { diff --git a/src/serializer.h b/src/serializer.h index f93c95aa..c3439f56 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -1,5 +1,6 @@ #pragma once +#include "maybe.h" #include "port.h" #include @@ -211,6 +212,26 @@ void Reflect(Writer& visitor, optional& value) { else visitor.Null(); } + +// The same as std::optional +template +void Reflect(Reader& visitor, Maybe& value) { + if (visitor.IsNull()) { + visitor.GetNull(); + return; + } + T real_value; + Reflect(visitor, real_value); + value = real_value; +} +template +void Reflect(Writer& visitor, Maybe& value) { + if (value) + Reflect(visitor, *value); + else + visitor.Null(); +} + template void ReflectMember(Writer& visitor, const char* name, optional& value) { // For TypeScript optional property key?: value in the spec, @@ -222,6 +243,15 @@ void ReflectMember(Writer& visitor, const char* name, optional& value) { } } +// The same as std::optional +template +void ReflectMember(Writer& visitor, const char* name, Maybe& value) { + if (value.has_value() || visitor.Format() != SerializeFormat::Json) { + visitor.Key(name); + Reflect(visitor, value); + } +} + // Backport C++17 std::disjunction namespace { template