Rename IndexBase -> IdBase, ComparableIndexBase -> IndexBase. (#3436)

This reflects how we're naming classes that derive from these classes,
and matches usage for each existing `Id` and `Index` type, except:

- `Parse::NodeId` previously inherited from `ComparableIndexBase`, and
is no longer comparable.
- `SemIR::MemberIndex` previously inherited from `IndexBase`, and is now
comparable.

Making `Parse::NodeId` non-comparable reflects that it's intended to be
an opaque identifier for a node and that the ordering is an
implementation detail rather than part of the intended public interface.
`PostorderIterator` and `SiblingIterator` still rely on the numerical
meaning of `NodeId`s, but that's OK since they're part of the node
implementation.
This commit is contained in:
Richard Smith
2023-11-30 18:50:59 +00:00
committed by GitHub
parent 05723095bc
commit c6bc2cbb3d
7 changed files with 93 additions and 88 deletions
+39 -26
View File
@@ -15,15 +15,20 @@ namespace Carbon {
template <typename DataType>
class DataIterator;
// A lightweight handle to an item in a vector.
// A lightweight handle to an item identified by an opaque ID.
//
// DataIndex is designed to be passed by value, not reference or pointer. They
// are also designed to be small and efficient to store in data structures.
struct IndexBase : public Printable<IndexBase> {
// This class is intended to be derived from by classes representing a specific
// kind of ID, whose meaning as an integer is an implementation detail of the
// type that vends the IDs. Typically this will be a vector index.
//
// Classes derived from IdBase are designed to be passed by value, not
// reference or pointer. They are also designed to be small and efficient to
// store in data structures.
struct IdBase : public Printable<IdBase> {
static constexpr int32_t InvalidIndex = -1;
IndexBase() = delete;
constexpr explicit IndexBase(int index) : index(index) {}
IdBase() = delete;
constexpr explicit IdBase(int index) : index(index) {}
auto Print(llvm::raw_ostream& output) const -> void {
if (is_valid()) {
@@ -38,48 +43,56 @@ struct IndexBase : public Printable<IndexBase> {
int32_t index;
};
// Like IndexBase, but also provides < and > comparison operators.
struct ComparableIndexBase : public IndexBase {
using IndexBase::IndexBase;
// A lightweight handle to an item that behaves like an index.
//
// Unlike IdBase, classes derived from IndexBase are not completely opaque, and
// provide at least an ordering between indexes that has meaning to an API
// user. Additional semantics may be specified by the derived class.
struct IndexBase : public IdBase {
using IdBase::IdBase;
};
// Equality comparison for both IndexBase and ComparableIndexBase.
template <typename IndexType,
typename std::enable_if_t<std::is_base_of_v<IndexBase, IndexType>>* =
nullptr>
// Equality comparison for both IdBase and IndexBase.
template <
typename IndexType,
typename std::enable_if_t<std::is_base_of_v<IdBase, IndexType>>* = nullptr>
auto operator==(IndexType lhs, IndexType rhs) -> bool {
return lhs.index == rhs.index;
}
template <typename IndexType,
typename std::enable_if_t<std::is_base_of_v<IndexBase, IndexType>>* =
nullptr>
template <
typename IndexType,
typename std::enable_if_t<std::is_base_of_v<IdBase, IndexType>>* = nullptr>
auto operator!=(IndexType lhs, IndexType rhs) -> bool {
return lhs.index != rhs.index;
}
// The < and > comparisons for only ComparableIndexBase.
template <typename IndexType, typename std::enable_if_t<std::is_base_of_v<
ComparableIndexBase, IndexType>>* = nullptr>
// The < and > comparisons for only IndexBase.
template <typename IndexType,
typename std::enable_if_t<std::is_base_of_v<IndexBase, IndexType>>* =
nullptr>
auto operator<(IndexType lhs, IndexType rhs) -> bool {
return lhs.index < rhs.index;
}
template <typename IndexType, typename std::enable_if_t<std::is_base_of_v<
ComparableIndexBase, IndexType>>* = nullptr>
template <typename IndexType,
typename std::enable_if_t<std::is_base_of_v<IndexBase, IndexType>>* =
nullptr>
auto operator<=(IndexType lhs, IndexType rhs) -> bool {
return lhs.index <= rhs.index;
}
template <typename IndexType, typename std::enable_if_t<std::is_base_of_v<
ComparableIndexBase, IndexType>>* = nullptr>
template <typename IndexType,
typename std::enable_if_t<std::is_base_of_v<IndexBase, IndexType>>* =
nullptr>
auto operator>(IndexType lhs, IndexType rhs) -> bool {
return lhs.index > rhs.index;
}
template <typename IndexType, typename std::enable_if_t<std::is_base_of_v<
ComparableIndexBase, IndexType>>* = nullptr>
template <typename IndexType,
typename std::enable_if_t<std::is_base_of_v<IndexBase, IndexType>>* =
nullptr>
auto operator>=(IndexType lhs, IndexType rhs) -> bool {
return lhs.index >= rhs.index;
}
// Provides base support for use of IndexBase types as DenseMap/DenseSet keys.
// Provides base support for use of IdBase types as DenseMap/DenseSet keys.
//
// Usage (in global namespace):
// template <>
+15 -15
View File
@@ -48,37 +48,37 @@ class Real : public Printable<Real> {
};
// Corresponds to an integer value represented by an APInt.
struct IntId : public IndexBase, public Printable<IntId> {
struct IntId : public IdBase, public Printable<IntId> {
using IndexedType = const llvm::APInt;
static const IntId Invalid;
using IndexBase::IndexBase;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "int";
IndexBase::Print(out);
IdBase::Print(out);
}
};
constexpr IntId IntId::Invalid(IntId::InvalidIndex);
// Corresponds to a Real value.
struct RealId : public IndexBase, public Printable<RealId> {
struct RealId : public IdBase, public Printable<RealId> {
using IndexedType = const Real;
static const RealId Invalid;
using IndexBase::IndexBase;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "real";
IndexBase::Print(out);
IdBase::Print(out);
}
};
constexpr RealId RealId::Invalid(RealId::InvalidIndex);
// Corresponds to a StringRef.
struct StringId : public IndexBase, public Printable<StringId> {
struct StringId : public IdBase, public Printable<StringId> {
using IndexedType = const std::string;
static const StringId Invalid;
using IndexBase::IndexBase;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "str";
IndexBase::Print(out);
IdBase::Print(out);
}
};
constexpr StringId StringId::Invalid(StringId::InvalidIndex);
@@ -87,23 +87,23 @@ constexpr StringId StringId::Invalid(StringId::InvalidIndex);
//
// `NameId` relies on the values of this type other than `Invalid` all being
// non-negative.
struct IdentifierId : public IndexBase, public Printable<IdentifierId> {
struct IdentifierId : public IdBase, public Printable<IdentifierId> {
static const IdentifierId Invalid;
using IndexBase::IndexBase;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "strId";
IndexBase::Print(out);
IdBase::Print(out);
}
};
constexpr IdentifierId IdentifierId::Invalid(IdentifierId::InvalidIndex);
// Adapts StringId for string literals.
struct StringLiteralId : public IndexBase, public Printable<StringLiteralId> {
struct StringLiteralId : public IdBase, public Printable<StringLiteralId> {
static const StringLiteralId Invalid;
using IndexBase::IndexBase;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "strLit";
IndexBase::Print(out);
IdBase::Print(out);
}
};
constexpr StringLiteralId StringLiteralId::Invalid(
+2 -2
View File
@@ -21,8 +21,8 @@ namespace Carbon::Check {
//
// TODO: Move this struct and the name lookup code in context.h to a separate
// file.
struct ScopeIndex : public ComparableIndexBase, public Printable<ScopeIndex> {
using ComparableIndexBase::ComparableIndexBase;
struct ScopeIndex : public IndexBase, public Printable<ScopeIndex> {
using IndexBase::IndexBase;
};
class Context;
+4 -4
View File
@@ -39,11 +39,11 @@ class TokenizedBuffer;
// meaningfully compared.
//
// All other APIs to query a `TokenIndex` are on the `TokenizedBuffer`.
struct TokenIndex : public ComparableIndexBase {
struct TokenIndex : public IndexBase {
static const TokenIndex Invalid;
// Comments aren't tokenized, so this is the first token after FileStart.
static const TokenIndex FirstNonCommentToken;
using ComparableIndexBase::ComparableIndexBase;
using IndexBase::IndexBase;
};
constexpr TokenIndex TokenIndex::Invalid(TokenIndex::InvalidIndex);
@@ -60,9 +60,9 @@ constexpr TokenIndex TokenIndex::FirstNonCommentToken(1);
// same line or the relative position of different lines within the source.
//
// All other APIs to query a `LineIndex` are on the `TokenizedBuffer`.
struct LineIndex : public ComparableIndexBase {
struct LineIndex : public IndexBase {
static const LineIndex Invalid;
using ComparableIndexBase::ComparableIndexBase;
using IndexBase::IndexBase;
};
constexpr LineIndex LineIndex::Invalid(LineIndex::InvalidIndex);
+3 -11
View File
@@ -23,14 +23,11 @@ namespace Carbon::Parse {
// Objects of this type are small and cheap to copy and store. They don't
// contain any of the information about the node, and serve as a handle that
// can be used with the underlying tree to query for detailed information.
//
// That said, nodes can be compared and are part of a depth-first pre-order
// sequence across all nodes in the parse tree.
struct NodeId : public ComparableIndexBase {
struct NodeId : public IdBase {
// An explicitly invalid instance.
static const NodeId Invalid;
using ComparableIndexBase::ComparableIndexBase;
using IdBase::IdBase;
};
constexpr NodeId NodeId::Invalid = NodeId(NodeId::InvalidIndex);
@@ -282,7 +279,7 @@ class Tree::PostorderIterator
return node_ == rhs.node_;
}
auto operator<(const PostorderIterator& rhs) const -> bool {
return node_ < rhs.node_;
return node_.index < rhs.node_.index;
}
auto operator*() const -> NodeId { return node_; }
@@ -333,11 +330,6 @@ class Tree::SiblingIterator
auto operator==(const SiblingIterator& rhs) const -> bool {
return node_ == rhs.node_;
}
auto operator<(const SiblingIterator& rhs) const -> bool {
// Note that child iterators walk in reverse compared to the postorder
// index.
return node_ > rhs.node_;
}
auto operator*() const -> NodeId { return node_; }
+29 -29
View File
@@ -14,7 +14,7 @@
namespace Carbon::SemIR {
// The ID of an instruction.
struct InstId : public IndexBase, public Printable<InstId> {
struct InstId : public IdBase, public Printable<InstId> {
// An explicitly invalid instruction ID.
static const InstId Invalid;
@@ -28,11 +28,11 @@ struct InstId : public IndexBase, public Printable<InstId> {
return InstId(kind.AsInt());
}
using IndexBase::IndexBase;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "inst";
if (!is_valid()) {
IndexBase::Print(out);
IdBase::Print(out);
} else if (index < BuiltinKind::ValidCount) {
out << BuiltinKind::FromInt(index);
} else {
@@ -51,51 +51,51 @@ constexpr InstId InstId::Invalid = InstId(InstId::InvalidIndex);
#include "toolchain/sem_ir/builtin_kind.def"
// The ID of a function.
struct FunctionId : public IndexBase, public Printable<FunctionId> {
struct FunctionId : public IdBase, public Printable<FunctionId> {
// An explicitly invalid function ID.
static const FunctionId Invalid;
using IndexBase::IndexBase;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "function";
IndexBase::Print(out);
IdBase::Print(out);
}
};
constexpr FunctionId FunctionId::Invalid = FunctionId(FunctionId::InvalidIndex);
// The ID of a class.
struct ClassId : public IndexBase, public Printable<ClassId> {
struct ClassId : public IdBase, public Printable<ClassId> {
// An explicitly invalid class ID.
static const ClassId Invalid;
using IndexBase::IndexBase;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "class";
IndexBase::Print(out);
IdBase::Print(out);
}
};
constexpr ClassId ClassId::Invalid = ClassId(ClassId::InvalidIndex);
// The ID of a cross-referenced IR.
struct CrossRefIRId : public IndexBase, public Printable<CrossRefIRId> {
struct CrossRefIRId : public IdBase, public Printable<CrossRefIRId> {
static const CrossRefIRId Builtins;
using IndexBase::IndexBase;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "ir";
IndexBase::Print(out);
IdBase::Print(out);
}
};
constexpr CrossRefIRId CrossRefIRId::Builtins = CrossRefIRId(0);
// A boolean value.
struct BoolValue : public IndexBase, public Printable<BoolValue> {
struct BoolValue : public IdBase, public Printable<BoolValue> {
static const BoolValue False;
static const BoolValue True;
using IndexBase::IndexBase;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
switch (index) {
case 0:
@@ -115,7 +115,7 @@ constexpr BoolValue BoolValue::True = BoolValue(1);
// The ID of a name. A name is either a string or a special name such as
// `self`, or eventually `Self` or `base`.
struct NameId : public IndexBase, public Printable<NameId> {
struct NameId : public IdBase, public Printable<NameId> {
// An explicitly invalid ID.
static const NameId Invalid;
// The name of `self`.
@@ -134,7 +134,7 @@ struct NameId : public IndexBase, public Printable<NameId> {
return NameId(id.index);
}
using IndexBase::IndexBase;
using IdBase::IdBase;
// Returns the IdentifierId corresponding to this NameId, or an invalid
// IdentifierId if this is a special name.
@@ -152,7 +152,7 @@ struct NameId : public IndexBase, public Printable<NameId> {
out << "ReturnSlot";
} else {
CARBON_CHECK(index >= 0) << "Unknown index";
IndexBase::Print(out);
IdBase::Print(out);
}
}
};
@@ -163,14 +163,14 @@ constexpr NameId NameId::SelfType = NameId(NameId::InvalidIndex - 2);
constexpr NameId NameId::ReturnSlot = NameId(NameId::InvalidIndex - 3);
// The ID of a name scope.
struct NameScopeId : public IndexBase, public Printable<NameScopeId> {
struct NameScopeId : public IdBase, public Printable<NameScopeId> {
// An explicitly invalid ID.
static const NameScopeId Invalid;
using IndexBase::IndexBase;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "name_scope";
IndexBase::Print(out);
IdBase::Print(out);
}
};
@@ -178,7 +178,7 @@ constexpr NameScopeId NameScopeId::Invalid =
NameScopeId(NameScopeId::InvalidIndex);
// The ID of an instruction block.
struct InstBlockId : public IndexBase, public Printable<InstBlockId> {
struct InstBlockId : public IdBase, public Printable<InstBlockId> {
// All File instances must provide the 0th instruction block as empty.
static const InstBlockId Empty;
@@ -188,13 +188,13 @@ struct InstBlockId : public IndexBase, public Printable<InstBlockId> {
// An ID for unreachable code.
static const InstBlockId Unreachable;
using IndexBase::IndexBase;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
if (index == Unreachable.index) {
out << "unreachable";
} else {
out << "block";
IndexBase::Print(out);
IdBase::Print(out);
}
}
};
@@ -206,7 +206,7 @@ constexpr InstBlockId InstBlockId::Unreachable =
InstBlockId(InstBlockId::InvalidIndex - 1);
// The ID of a type.
struct TypeId : public IndexBase, public Printable<TypeId> {
struct TypeId : public IdBase, public Printable<TypeId> {
// The builtin TypeType.
static const TypeId TypeType;
@@ -216,7 +216,7 @@ struct TypeId : public IndexBase, public Printable<TypeId> {
// An explicitly invalid ID.
static const TypeId Invalid;
using IndexBase::IndexBase;
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "type";
if (index == TypeType.index) {
@@ -224,7 +224,7 @@ struct TypeId : public IndexBase, public Printable<TypeId> {
} else if (index == Error.index) {
out << "Error";
} else {
IndexBase::Print(out);
IdBase::Print(out);
}
}
};
@@ -234,11 +234,11 @@ constexpr TypeId TypeId::Error = TypeId(TypeId::InvalidIndex - 1);
constexpr TypeId TypeId::Invalid = TypeId(TypeId::InvalidIndex);
// The ID of a type block.
struct TypeBlockId : public IndexBase, public Printable<TypeBlockId> {
using IndexBase::IndexBase;
struct TypeBlockId : public IdBase, public Printable<TypeBlockId> {
using IdBase::IdBase;
auto Print(llvm::raw_ostream& out) const -> void {
out << "typeBlock";
IndexBase::Print(out);
IdBase::Print(out);
}
};
+1 -1
View File
@@ -159,7 +159,7 @@ class Inst : public Printable<Inst> {
arg1_(arg1) {}
// Convert a field to its raw representation, used as `arg0_` / `arg1_`.
static constexpr auto ToRaw(IndexBase base) -> int32_t { return base.index; }
static constexpr auto ToRaw(IdBase base) -> int32_t { return base.index; }
static constexpr auto ToRaw(BuiltinKind kind) -> int32_t {
return kind.AsInt();
}