text: // Copyright 2019 The Fuchsia Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_INDEX_NODE_H_
  #define SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_INDEX_NODE_H_
  
  #include <iosfwd>
  #include <map>
  #include <string>
  #include <vector>
  
  namespace zxdb {
  
  class DwarfSymbolFactory;
  
  // An in-progress replacement for IndexNode. Not ready to use yet.
  class IndexNode {
   public:
    using Map = std::map<std::string, IndexNode>;
  
    // The type of an index node. There are several "physical" kinds which are associated with
    // children of each node. These physical ones count up from 0 so one can iterate over them
    // from to up until < kEndPhysical to iterate the child categories.
    enum class Kind : int {
      kNamespace = 0,
      kType,
      kFunction,
      kVar,
      kEndPhysical,  // Marker for the end of the kinds that have children for every node.
  
      kNone = kEndPhysical,
      kRoot,  // Root index node (meaning nothing semantically).
    };
  
    // A reference to a DIE that doesn't need the unit or the underlying llvm::DwarfDebugInfoEntry to
    // be kept. This allows the discarding of the full parsed DIE structures after indexing. It can be
    // converted back to a DIE, which will cause the DWARFUnit to be re-parsed.
    //
    // The offset stored in this structure is the offset from the beginning of the .debug_info
    // section, which is the same as the offset stored in the llvm::DWARFDebugInfoEntry.
    //
    // Random code reading the index can convert a SymbolRef to a Symbol object using
    // ModuleSymbols::IndexSymbolRefToSymbol().
    //
    // TODO(bug 53091) in the future we may want to add ELF symbol support to this class.
    class SymbolRef {
     public:
      enum Kind {
        kNull,              // Empty.
        kDwarf,             // Normal DWARF symbol.
        kDwarfDeclaration,  // A DWARF declaration.
      };
  
      SymbolRef() = default;
      SymbolRef(Kind kind, uint32_t offset) : kind_(kind), offset_(offset) {}
  
      Kind kind() const { return kind_; }
      bool is_declaration() const { return kind_ == kDwarfDeclaration; }
      uint32_t offset() const { return offset_; }
  
     private:
      Kind kind_ = kNull;
      uint32_t offset_ = 0;
    };
  
    explicit IndexNode(Kind kind) : kind_(kind) {}
    ~IndexNode() = default;
  
    Kind kind() const { return kind_; }
  
    // The SymbolRef can be omitted when indexing namespaces as the DIEs are not stored for that case.
    IndexNode* AddChild(Kind kind, const char* name);
    IndexNode* AddChild(Kind kind, const char* name, const SymbolRef& ref);
    void AddDie(const SymbolRef& ref);
  
    const Map& namespaces() const { return children_[static_cast<int>(Kind::kNamespace)]; }
    Map& namespaces() { return children_[static_cast<int>(Kind::kNamespace)]; }
  
    const Map& types() const { return children_[static_cast<int>(Kind::kType)]; }
    Map& types() { return children_[static_cast<int>(Kind::kType)]; }
  
    const Map& functions() const { return children_[static_cast<int>(Kind::kFunction)]; }
    Map& functions() { return children_[static_cast<int>(Kind::kFunction)]; }
  
    const Map& vars() const { return children_[static_cast<int>(Kind::kVar)]; }
    Map& vars() { return children_[static_cast<int>(Kind::kVar)]; }
  
    // Returns the map for the given child kind. This will assert for >= kEndPhysical ("kNone" and
    // "kRoot") which aren't child kinds.
    const Map& MapForKind(Kind kind) const;
    Map& MapForKind(Kind kind);
  
    // AsString is useful only in small unit tests since even a small module can have many megabytes
    // of dump.
    std::string AsString(int indent_level = 0) const;
  
    // Dump DIEs for debugging. A node does not contain its own name (this is stored in the parent's
    // map). If printing some node other than the root, specify the name.
    //
    // If non-null, |factory_for_loc| will be used to add extra location information to certain types
    // of entries. Currently this prints out the relative code ranges for functions, and the DIE
    // offset of the indexed item for everything else.
    void Dump(std::ostream& out, DwarfSymbolFactory* factory_for_loc = nullptr,
              int indent_level = 0) const;
    void Dump(const std::string& name, std::ostream& out,
              DwarfSymbolFactory* factory_for_loc = nullptr, int indent_level = 0) const;
  
    const std::vector<SymbolRef>& dies() const { return dies_; }
  
   private:
    Kind kind_;
  
    // TODO(brettw) evaluate whether we can save a lot of memory using optionally-null unique_ptrs
    // here since in most cases all but one of these maps will be empty.
    Map children_[static_cast<int>(Kind::kEndPhysical)];
  
    // Contains the references to the definitions (if possible) or the declarations (if not) of the
    // type, function, or variable. This will not have any entries for namespaces.
    //
    // TODO(brettw) consider an optimization because in most cases there will be exactly one DIE.
    std::vector<SymbolRef> dies_;
  };
  
  }  // namespace zxdb
  
  #endif  // SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_INDEX_NODE_H_
  