blob: d4c04999b05454ab1ad27ed7e07768bbbd6d8fc2 [file] [log] [blame]
// Copyright 2018 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_IDENTIFIER_BASE_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_IDENTIFIER_BASE_H_
#include <string>
#include <utility>
#include <vector>
namespace zxdb {
// Identifiers can be explicitly global qualified ("::foo" in C++) or without
// global qualification ("foo" or "Foo::Bar" in C++). Note that relative
// can still include class or namespace qualifications.
enum class IdentifierQualification { kGlobal, kRelative };
// Base class for identifiers that have different types of components.
// Different languages might want to represent different aspects of an
// identifier. This class encapsulates the core hierarchical part of an
// identifier.
//
// Most code will want to use an "Identifier" which contains language-neutral
// string components.
//
// The ComponentType must be copyable and moveable and implement:
// - Construction from simple name:
// ComponentType(const std::string&)
// - Conversion to a string:
// std::string GetName(bool include_debug)
template <class ComponentType>
class IdentifierBase {
public:
using Qualification = IdentifierQualification;
explicit IdentifierBase(Qualification qual = Qualification::kRelative)
: qualification_(qual) {}
// Makes an identifier from a single component. Without the qualification
// means relative.
explicit IdentifierBase(ComponentType comp)
: qualification_(Qualification::kRelative),
components_({std::move(comp)}) {}
IdentifierBase(Qualification qual, ComponentType comp)
: qualification_(qual), components_({std::move(comp)}) {}
// Construction of a relative identifier from a simple single-name string.
// This string is passed to the underlying component's constructor.
IdentifierBase(const std::string& name)
: qualification_(Qualification::kRelative),
components_({ComponentType(name)}) {}
// Makes an identifier over a range of components.
template <class InputIterator>
IdentifierBase(Qualification qual, InputIterator first, InputIterator last)
: qualification_(qual), components_(first, last) {}
std::vector<ComponentType>& components() { return components_; }
const std::vector<ComponentType>& components() const { return components_; }
bool empty() const {
return components_.empty() && qualification_ == Qualification::kRelative;
}
// Appends a single component.
void AppendComponent(ComponentType c) { components_.push_back(std::move(c)); }
// Appends the components from the other identifier to this one.
void Append(IdentifierBase<ComponentType> other) {
for (auto& cur : other.components())
components_.push_back(std::move(cur));
}
Qualification qualification() const { return qualification_; }
// Returns a new identifier that's the scope of this one. The scope is
// everything but the last component. The qualification remains unchanged.
//
// If there is only one component, the resulting identifier will be empty
// (still leaving the qualification unchanged). Examples:
// "foo::bar<int>::baz" -> "foo::bar<int>"
// "::foo::bar::baz" -> "::foo::bar"
// "foo" -> ""
// "" -> ""
// "::foo" -> "::"
// "::" -> "::"
IdentifierBase<ComponentType> GetScope() const {
if (components_.size() <= 1)
return IdentifierBase<ComponentType>(qualification_);
return IdentifierBase<ComponentType>(qualification_, components_.begin(),
components_.end() - 1);
}
// Returns the full name with all components concatenated together.
std::string GetFullName() const { return GetName(false); }
// Returns a form for debugging where the parsing is more visible.
std::string GetDebugName() const { return GetName(true); }
// Returns the separator string for components. This is currently always "::"
// but is exposed here as a getter to avoid hardcoding it everywhere and to
// allow us to do language-specific separators in the future.
const char* GetSeparator() const { return "::"; }
private:
// Backend for the name getters.
std::string GetName(bool include_debug) const {
std::string result;
if (qualification_ == Qualification::kGlobal)
result += GetSeparator();
bool first = true;
for (const auto& c : components_) {
if (first) {
first = false;
} else {
if (include_debug)
result += "; ";
result += GetSeparator();
}
result += c.GetName(include_debug);
}
return result;
}
Qualification qualification_ = Qualification::kRelative;
std::vector<ComponentType> components_;
};
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_IDENTIFIER_BASE_H_