diff --git a/src/parser/cxx/control.cc b/src/parser/cxx/control.cc index 44e0a64e..210f606f 100644 --- a/src/parser/cxx/control.cc +++ b/src/parser/cxx/control.cc @@ -54,9 +54,6 @@ template using LiteralSet = std::unordered_set, LiteralEqualTo>; -template -using NameSet = std::set; - } // namespace struct Control::Private { @@ -75,12 +72,12 @@ struct Control::Private { LiteralSet utf32StringLiterals; LiteralSet commentLiterals; - std::set> identifiers; - std::set operatorIds; - std::set destructorIds; - std::set literalOperatorIds; - std::set conversionFunctionIds; - std::set templateIds; + std::unordered_set identifiers; + std::unordered_set operatorIds; + std::unordered_set destructorIds; + std::unordered_set literalOperatorIds; + std::unordered_set conversionFunctionIds; + std::unordered_set templateIds; BuiltinVaListType builtinVaListType; VoidType voidType; diff --git a/src/parser/cxx/names.cc b/src/parser/cxx/names.cc index 7fe079e0..07809570 100644 --- a/src/parser/cxx/names.cc +++ b/src/parser/cxx/names.cc @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include @@ -31,6 +33,54 @@ namespace cxx { namespace { +struct ConstValueHash { + auto operator()(bool value) const -> std::size_t { + return std::hash{}(value); + } + auto operator()(std::int32_t value) const -> std::size_t { + return std::hash{}(value); + } + auto operator()(std::uint32_t value) const -> std::size_t { + return std::hash{}(value); + } + auto operator()(std::int64_t value) const -> std::size_t { + return std::hash{}(value); + } + auto operator()(std::uint64_t value) const -> std::size_t { + return std::hash{}(value); + } + auto operator()(float value) const -> std::size_t { + return std::hash{}(value); + } + auto operator()(double value) const -> std::size_t { + return std::hash{}(value); + } + auto operator()(long double value) const -> std::size_t { + return std::hash{}(value); + } + auto operator()(const StringLiteral* value) const -> std::size_t { + return value->hashCode(); + } +}; + +struct TemplateArgumentHash { + auto operator()(const Type* arg) const -> std::size_t { + return std::hash{}(arg); + } + + auto operator()(Symbol* arg) const -> std::size_t { + return arg->name() ? arg->name()->hashValue() : 0; + } + + auto operator()(ConstValue arg) const -> std::size_t { + return std::visit(ConstValueHash{}, arg); + } + + auto operator()(ExpressionAST* arg) const -> std::size_t { + return std::hash{}(arg); + } +}; + struct ConvertToName { Control* control_; @@ -107,4 +157,14 @@ auto Identifier::builtinTypeTrait() const -> BuiltinTypeTraitKind { return static_cast(info_)->trait(); } +auto TemplateId::hash(const Name* name, + const std::vector& args) + -> std::size_t { + std::size_t hash = name->hashValue(); + for (const auto& arg : args) { + hash_combine(hash, std::visit(TemplateArgumentHash{}, arg)); + } + return hash; +} + } // namespace cxx diff --git a/src/parser/cxx/names.h b/src/parser/cxx/names.h index 3a719185..98600d2e 100644 --- a/src/parser/cxx/names.h +++ b/src/parser/cxx/names.h @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -58,26 +57,33 @@ class TypeTraitIdentifierInfo final : public IdentifierInfo { class Name { public: - explicit Name(NameKind kind) : kind_(kind) {} + Name(NameKind kind, std::size_t hashValue) + : kind_(kind), hashValue_(hashValue) {} + virtual ~Name(); [[nodiscard]] auto kind() const -> NameKind { return kind_; } + [[nodiscard]] auto hashValue() const -> std::size_t { return hashValue_; } private: NameKind kind_; + std::size_t hashValue_; }; -class Identifier final : public Name, public std::tuple { +class Identifier final : public Name { public: static constexpr auto Kind = NameKind::kIdentifier; - explicit Identifier(std::string name) : Name(Kind), tuple(std::move(name)) {} + static auto hash(std::string_view name) -> std::size_t { + return std::hash{}(name); + } + + explicit Identifier(std::string name) + : Name(Kind, hash(name)), name_(std::move(name)) {} - [[nodiscard]] auto isAnonymous() const -> bool { return name().at(0) == '$'; } + [[nodiscard]] auto isAnonymous() const -> bool { return name_.at(0) == '$'; } - [[nodiscard]] auto name() const -> const std::string& { - return std::get<0>(*this); - } + [[nodiscard]] auto name() const -> const std::string& { return name_; } [[nodiscard]] auto value() const -> const std::string& { return name(); } @@ -88,72 +94,89 @@ class Identifier final : public Name, public std::tuple { void setInfo(const IdentifierInfo* info) const { info_ = info; } private: + std::string name_; mutable const IdentifierInfo* info_ = nullptr; }; -inline auto operator<(const Identifier& identifier, - const std::string_view& other) -> bool { - return identifier.name() < other; -} - -inline auto operator<(const std::string_view& other, - const Identifier& identifier) -> bool { - return other < identifier.name(); -} - -class OperatorId final : public Name, public std::tuple { +class OperatorId final : public Name { public: static constexpr auto Kind = NameKind::kOperatorId; - explicit OperatorId(TokenKind op) : Name(Kind), tuple(op) {} + static auto hash(TokenKind op) -> std::size_t { + return std::hash{}(static_cast(op)); + } + + explicit OperatorId(TokenKind op) : Name(Kind, hash(op)), op_(op) {} - [[nodiscard]] auto op() const -> TokenKind { return std::get<0>(*this); } + [[nodiscard]] auto op() const -> TokenKind { return op_; } + + private: + TokenKind op_; }; class DestructorId final : public Name, public std::tuple { public: static constexpr auto Kind = NameKind::kDestructorId; - explicit DestructorId(const Name* name) : Name(Kind), tuple(name) {} + explicit DestructorId(const Name* name) + : Name(Kind, name ? name->hashValue() : 0), tuple(name) {} [[nodiscard]] auto name() const -> const Name* { return std::get<0>(*this); } }; -class LiteralOperatorId final : public Name, public std::tuple { +class LiteralOperatorId final : public Name { public: static constexpr auto Kind = NameKind::kLiteralOperatorId; + static auto hash(std::string_view name) -> std::size_t { + return std::hash{}(name); + } + explicit LiteralOperatorId(std::string name) - : Name(Kind), tuple(std::move(name)) {} + : Name(Kind, hash(name)), name_(std::move(name)) {} - [[nodiscard]] auto name() const -> const std::string& { - return std::get<0>(*this); - } + [[nodiscard]] auto name() const -> const std::string& { return name_; } + + private: + std::string name_; }; -class ConversionFunctionId final : public Name, public std::tuple { +class ConversionFunctionId final : public Name { public: static constexpr auto Kind = NameKind::kConversionFunctionId; - explicit ConversionFunctionId(const Type* type) : Name(Kind), tuple(type) {} + static auto hash(const Type* type) -> std::size_t { + return std::hash{}(type); + } + + explicit ConversionFunctionId(const Type* type) + : Name(Kind, hash(type)), type_(type) {} + + [[nodiscard]] auto type() const -> const Type* { return type_; } - [[nodiscard]] auto type() const -> const Type* { return std::get<0>(*this); } + private: + const Type* type_; }; -class TemplateId final - : public Name, - public std::tuple> { +class TemplateId final : public Name { public: static constexpr auto Kind = NameKind::kTemplateId; + static auto hash(const Name* name, const std::vector& args) + -> std::size_t; + explicit TemplateId(const Name* name, std::vector args) - : Name(Kind), tuple(name, std::move(args)) {} + : Name(Kind, hash(name, args)), name_(name), args_(std::move(args)) {} - [[nodiscard]] auto name() const -> const Name* { return std::get<0>(*this); } + [[nodiscard]] auto name() const -> const Name* { return name_; } [[nodiscard]] auto arguments() const -> const std::vector& { - return std::get<1>(*this); + return args_; } + + private: + const Name* name_; + std::vector args_; }; template @@ -180,4 +203,188 @@ auto name_cast(const Name* name) -> const T* { [[nodiscard]] auto get_name(Control* control, UnqualifiedIdAST* id) -> const Name*; -} // namespace cxx \ No newline at end of file +} // namespace cxx + +template <> +struct std::hash { + using is_transparent = void; + + auto operator()(const cxx::Identifier& id) const -> std::size_t { + return id.hashValue(); + } + + auto operator()(const std::string_view& name) const -> std::size_t { + return cxx::Identifier::hash(name); + } + + auto operator()(const std::string& name) const -> std::size_t { + return cxx::Identifier::hash(name); + } +}; + +template <> +struct std::hash { + using is_transparent = void; + + auto operator()(const cxx::OperatorId& id) const -> std::size_t { + return id.hashValue(); + } + + auto operator()(const cxx::TokenKind& op) const -> std::size_t { + return cxx::OperatorId::hash(op); + } +}; + +template <> +struct std::hash { + using is_transparent = void; + + auto operator()(const cxx::DestructorId& id) const -> std::size_t { + return id.hashValue(); + } + + auto operator()(const cxx::Name* name) const -> std::size_t { + return name ? name->hashValue() : 0; + } +}; + +template <> +struct std::hash { + using is_transparent = void; + + auto operator()(const cxx::LiteralOperatorId& id) const -> std::size_t { + return id.hashValue(); + } + + auto operator()(const std::string_view& name) const -> std::size_t { + return cxx::LiteralOperatorId::hash(name); + } +}; + +template <> +struct std::hash { + using is_transparent = void; + + auto operator()(const cxx::ConversionFunctionId& id) const -> std::size_t { + return id.hashValue(); + } + + auto operator()(const cxx::Type* type) const -> std::size_t { + return cxx::ConversionFunctionId::hash(type); + } +}; + +template <> +struct std::hash { + auto operator()(const cxx::TemplateId& id) const -> std::size_t { + return id.hashValue(); + } +}; + +template <> +struct std::equal_to { + using is_transparent = void; + + auto operator()(const cxx::Identifier& id, const cxx::Identifier& other) const + -> bool { + return id.name() == other.name(); + } + + auto operator()(const cxx::Identifier& id, const std::string_view& name) const + -> bool { + return id.name() == name; + } + + auto operator()(const std::string_view& name, const cxx::Identifier& id) const + -> bool { + return id.name() == name; + } +}; + +template <> +struct std::equal_to { + using is_transparent = void; + + auto operator()(const cxx::OperatorId& id, const cxx::OperatorId& other) const + -> bool { + return id.op() == other.op(); + } + + auto operator()(const cxx::OperatorId& id, const cxx::TokenKind& op) const + -> bool { + return id.op() == op; + } + + auto operator()(const cxx::TokenKind& op, const cxx::OperatorId& id) const + -> bool { + return id.op() == op; + } +}; + +template <> +struct std::equal_to { + using is_transparent = void; + + auto operator()(const cxx::DestructorId& id, + const cxx::DestructorId& other) const -> bool { + return id.name() == other.name(); + } + + auto operator()(const cxx::DestructorId& id, const cxx::Name* name) const + -> bool { + return id.name() == name; + } + + auto operator()(const cxx::Name* name, const cxx::DestructorId& id) const + -> bool { + return id.name() == name; + } +}; + +template <> +struct std::equal_to { + using is_transparent = void; + + auto operator()(const cxx::LiteralOperatorId& id, + const cxx::LiteralOperatorId& other) const -> bool { + return id.name() == other.name(); + } + + auto operator()(const cxx::LiteralOperatorId& id, + const std::string_view& name) const -> bool { + return id.name() == name; + } + + auto operator()(const std::string_view& name, + const cxx::LiteralOperatorId& id) const -> bool { + return id.name() == name; + } +}; + +template <> +struct std::equal_to { + using is_transparent = void; + + auto operator()(const cxx::ConversionFunctionId& id, + const cxx::ConversionFunctionId& other) const -> bool { + return id.type() == other.type(); + } + + auto operator()(const cxx::ConversionFunctionId& id, + const cxx::Type* type) const -> bool { + return id.type() == type; + } + + auto operator()(const cxx::Type* type, + const cxx::ConversionFunctionId& id) const -> bool { + return id.type() == type; + } +}; + +template <> +struct std::equal_to { + auto operator()(const cxx::TemplateId& id, const cxx::TemplateId& other) const + -> bool { + return id.name() == other.name() && id.arguments() == other.arguments(); + } +}; \ No newline at end of file diff --git a/src/parser/cxx/names_fwd.h b/src/parser/cxx/names_fwd.h index ef11ea44..08bdcba4 100644 --- a/src/parser/cxx/names_fwd.h +++ b/src/parser/cxx/names_fwd.h @@ -25,6 +25,7 @@ #include #include +#include #include namespace cxx { @@ -61,4 +62,4 @@ class TypeTraitIdentifierInfo; auto to_string(const Name* name) -> std::string; -} // namespace cxx \ No newline at end of file +} // namespace cxx diff --git a/src/parser/cxx/preprocessor.cc b/src/parser/cxx/preprocessor.cc index 381114de..420909c0 100644 --- a/src/parser/cxx/preprocessor.cc +++ b/src/parser/cxx/preprocessor.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -261,11 +262,6 @@ template <> struct std::hash { using is_transparent = void; - template - void hash_combine(std::size_t &seed, const T &val) const { - seed ^= std::hash()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - } - auto operator()(const Hideset &hideset) const -> std::size_t { return operator()(hideset.names()); } @@ -273,13 +269,13 @@ struct std::hash { auto operator()(const std::set &names) const -> std::size_t { std::size_t seed = 0; - for (const auto &name : names) hash_combine(seed, name); + for (const auto &name : names) cxx::hash_combine(seed, name); return seed; } auto operator()(const std::string_view &name) const -> std::size_t { std::size_t seed = 0; - hash_combine(seed, name); + cxx::hash_combine(seed, name); return seed; } }; diff --git a/src/parser/cxx/scope.cc b/src/parser/cxx/scope.cc index 8092f975..c243dead 100644 --- a/src/parser/cxx/scope.cc +++ b/src/parser/cxx/scope.cc @@ -26,7 +26,6 @@ #include #include -#include namespace cxx { @@ -111,10 +110,19 @@ void Scope::addSymbol(Symbol* symbol) { symbol->setEnclosingScope(this); symbols_.push_back(symbol); + if (name_cast(symbol->name())) { + if (auto functionSymbol = symbol_cast(symbol)) { + if (auto classSymbol = symbol_cast(owner_)) { + classSymbol->addConversionFunction(functionSymbol); + } + } + } + if (3 * symbols_.size() >= 2 * buckets_.size()) { rehash(); } else { - const auto h = std::hash{}(symbol->name()) % buckets_.size(); + auto h = symbol->name() ? symbol->name()->hashValue() : 0; + h = h % buckets_.size(); symbol->link_ = buckets_[h]; buckets_[h] = symbol; } @@ -125,10 +133,9 @@ void Scope::rehash() { buckets_ = std::vector(newSize); - std::hash hash_value; - for (auto symbol : symbols_) { - auto index = hash_value(symbol->name()) % newSize; + auto h = symbol->name() ? symbol->name()->hashValue() : 0; + auto index = h % newSize; symbol->link_ = buckets_[index]; buckets_[index] = symbol; } @@ -148,7 +155,9 @@ void Scope::replaceSymbol(Symbol* symbol, Symbol* newSymbol) { newSymbol->link_ = symbol->link_; - const auto h = std::hash{}(newSymbol->name()) % buckets_.size(); + auto h = newSymbol->name() ? newSymbol->name()->hashValue() : 0; + h = h % buckets_.size(); + if (buckets_[h] == symbol) { buckets_[h] = newSymbol; } else { @@ -169,7 +178,8 @@ void Scope::addUsingDirective(Scope* scope) { auto Scope::find(const Name* name) const -> SymbolChainView { if (!symbols_.empty()) { - const auto h = std::hash{}(name) % buckets_.size(); + auto h = name ? name->hashValue() : 0; + h = h % buckets_.size(); for (auto symbol = buckets_[h]; symbol; symbol = symbol->link_) { if (symbol->name() == name) { return SymbolChainView{symbol}; @@ -179,4 +189,26 @@ auto Scope::find(const Name* name) const -> SymbolChainView { return SymbolChainView{nullptr}; } +auto Scope::find(TokenKind op) const -> SymbolChainView { + if (!symbols_.empty()) { + const auto h = OperatorId::hash(op) % buckets_.size(); + for (auto symbol = buckets_[h]; symbol; symbol = symbol->link_) { + auto id = name_cast(symbol->name()); + if (id && id->op() == op) return SymbolChainView{symbol}; + } + } + return SymbolChainView{nullptr}; +} + +auto Scope::find(const std::string_view& name) const -> SymbolChainView { + if (!symbols_.empty()) { + const auto h = Identifier::hash(name) % buckets_.size(); + for (auto symbol = buckets_[h]; symbol; symbol = symbol->link_) { + auto id = name_cast(symbol->name()); + if (id && id->name() == name) return SymbolChainView{symbol}; + } + } + return SymbolChainView{nullptr}; +} + } // namespace cxx diff --git a/src/parser/cxx/scope.h b/src/parser/cxx/scope.h index 9b4fea7d..91715052 100644 --- a/src/parser/cxx/scope.h +++ b/src/parser/cxx/scope.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,11 @@ class Scope { [[nodiscard]] auto find(const Name* name) const -> SymbolChainView; + [[nodiscard]] auto find(const std::string_view& name) const + -> SymbolChainView; + + [[nodiscard]] auto find(TokenKind op) const -> SymbolChainView; + void setParent(Scope* parent) { parent_ = parent; } void setOwner(ScopedSymbol* owner) { owner_ = owner; } diff --git a/src/parser/cxx/symbols.cc b/src/parser/cxx/symbols.cc index 54fb4c85..5c8c49f2 100644 --- a/src/parser/cxx/symbols.cc +++ b/src/parser/cxx/symbols.cc @@ -215,6 +215,15 @@ auto ClassSymbol::hasBaseClass( return false; } +auto ClassSymbol::conversionFunctions() const + -> const std::vector& { + return conversionFunctions_; +} + +void ClassSymbol::addConversionFunction(FunctionSymbol* conversionFunction) { + conversionFunctions_.push_back(conversionFunction); +} + auto ClassSymbol::declaration() const -> SpecifierAST* { return specifier_; } void ClassSymbol::setDeclaration(SpecifierAST* specifier) { diff --git a/src/parser/cxx/symbols.h b/src/parser/cxx/symbols.h index 73940f16..d9fcfc47 100644 --- a/src/parser/cxx/symbols.h +++ b/src/parser/cxx/symbols.h @@ -246,6 +246,11 @@ class ClassSymbol final : public ScopedSymbol { void addConstructor(FunctionSymbol* constructor); + [[nodiscard]] auto conversionFunctions() const + -> const std::vector&; + + void addConversionFunction(FunctionSymbol* conversionFunction); + [[nodiscard]] auto isFinal() const -> bool; void setFinal(bool isFinal); @@ -316,6 +321,7 @@ class ClassSymbol final : public ScopedSymbol { private: std::vector baseClasses_; std::vector constructors_; + std::vector conversionFunctions_; std::unique_ptr> templateInfo_; SpecifierAST* specifier_ = nullptr; TemplateDeclarationAST* templateDeclaration_ = nullptr; diff --git a/src/parser/cxx/util.h b/src/parser/cxx/util.h index 954e9955..dc7e7a10 100644 --- a/src/parser/cxx/util.h +++ b/src/parser/cxx/util.h @@ -20,6 +20,15 @@ #pragma once +#include + namespace cxx { + auto align_to(int n, int align) -> int; -} \ No newline at end of file + +template +void hash_combine(std::size_t &seed, const T &val) { + seed ^= std::hash()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2); +} + +} // namespace cxx \ No newline at end of file diff --git a/src/parser/cxx/views/symbol_chain.h b/src/parser/cxx/views/symbol_chain.h index b6af2f73..8dac430b 100644 --- a/src/parser/cxx/views/symbol_chain.h +++ b/src/parser/cxx/views/symbol_chain.h @@ -28,7 +28,7 @@ namespace cxx { class SymbolChainView : public std::ranges::view_interface { public: - explicit SymbolChainView(Symbol* symbol) : symbol_{symbol} {} + explicit SymbolChainView(Symbol* symbol = nullptr) : symbol_{symbol} {} auto begin() const { return Generator{symbol_}; } auto end() const { return std::default_sentinel; }