index_base.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_TOOLCHAIN_BASE_INDEX_BASE_H_
  5. #define CARBON_TOOLCHAIN_BASE_INDEX_BASE_H_
  6. #include <compare>
  7. #include <concepts>
  8. #include <iterator>
  9. #include <type_traits>
  10. #include "common/ostream.h"
  11. #include "llvm/ADT/iterator.h"
  12. #include "llvm/Support/Format.h"
  13. namespace Carbon {
  14. template <typename DataType>
  15. class DataIterator;
  16. // Non-templated portions of `IdBase`.
  17. struct AnyIdBase {
  18. static constexpr int32_t NoneIndex = -1;
  19. AnyIdBase() = delete;
  20. constexpr explicit AnyIdBase(int index) : index(index) {}
  21. constexpr auto has_value() const -> bool { return index != NoneIndex; }
  22. int32_t index;
  23. };
  24. // A lightweight handle to an item identified by an opaque ID.
  25. //
  26. // This class is intended to be derived from by classes representing a specific
  27. // kind of ID, whose meaning as an integer is an implementation detail of the
  28. // type that vends the IDs. Typically this will be a vector index.
  29. //
  30. // Classes derived from IdBase are designed to be passed by value, not
  31. // reference or pointer. They are also designed to be small and efficient to
  32. // store in data structures.
  33. //
  34. // This uses CRTP for the `Print` function. Children should have:
  35. // static constexpr llvm::StringLiteral Label = "my_label";
  36. // Children can also define their own `Print` function, removing the dependency
  37. // on `Label`.
  38. template <typename IdT>
  39. struct IdBase : public AnyIdBase, public Printable<IdT> {
  40. using AnyIdBase::AnyIdBase;
  41. // Provide a standard `None` mapping to `NoneIndex`.
  42. //
  43. // This uses a `&` to trigger slightly different instantiation behaviors in
  44. // Clang. For context on why this is needed, see http://wg21.link/CWG2800.
  45. // NOLINTNEXTLINE(readability-identifier-naming)
  46. static const IdT& None;
  47. auto Print(llvm::raw_ostream& out) const -> void {
  48. out << IdT::Label;
  49. if (has_value()) {
  50. out << llvm::format_hex_no_prefix(index, 0, /*Upper=*/true);
  51. } else {
  52. out << "<none>";
  53. }
  54. }
  55. // Support simple equality comparison for ID types.
  56. friend constexpr auto operator==(IdBase<IdT> lhs, IdBase<IdT> rhs) -> bool {
  57. return lhs.index == rhs.index;
  58. }
  59. };
  60. template <typename IdT>
  61. constexpr const IdT& IdBase<IdT>::None = IdT(NoneIndex);
  62. // A lightweight handle to an item that behaves like an index.
  63. //
  64. // Unlike IdBase, classes derived from IndexBase are not completely opaque, and
  65. // provide at least an ordering between indexes that has meaning to an API
  66. // user. Additional semantics may be specified by the derived class.
  67. template <typename IdT>
  68. struct IndexBase : public IdBase<IdT> {
  69. using IdBase<IdT>::IdBase;
  70. // Support relational comparisons for index types.
  71. friend auto operator<=>(IndexBase<IdT> lhs, IndexBase<IdT> rhs)
  72. -> std::strong_ordering {
  73. return lhs.index <=> rhs.index;
  74. }
  75. // Print indexed ids in decimal, since they won't have tagging (because, as
  76. // the class comment explains, these ids are not entirely opaque).
  77. auto Print(llvm::raw_ostream& out) const -> void {
  78. out << IdT::Label;
  79. if (this->has_value()) {
  80. out << this->index;
  81. } else {
  82. out << "<none>";
  83. }
  84. }
  85. };
  86. // A random-access iterator for arrays using IndexBase-derived types.
  87. template <typename IndexT>
  88. class IndexIterator
  89. : public llvm::iterator_facade_base<IndexIterator<IndexT>,
  90. std::random_access_iterator_tag,
  91. const IndexT, int>,
  92. public Printable<IndexIterator<IndexT>> {
  93. public:
  94. IndexIterator() = delete;
  95. explicit IndexIterator(IndexT index) : index_(index) {}
  96. friend auto operator==(const IndexIterator& lhs, const IndexIterator& rhs)
  97. -> bool {
  98. return lhs.index_ == rhs.index_;
  99. }
  100. friend auto operator<=>(const IndexIterator& lhs, const IndexIterator& rhs)
  101. -> std::strong_ordering {
  102. return lhs.index_ <=> rhs.index_;
  103. }
  104. auto operator*() const -> const IndexT& { return index_; }
  105. using llvm::iterator_facade_base<IndexIterator,
  106. std::random_access_iterator_tag,
  107. const IndexT, int>::operator-;
  108. friend auto operator-(const IndexIterator& lhs, const IndexIterator& rhs)
  109. -> int {
  110. return lhs.index_.index - rhs.index_.index;
  111. }
  112. auto operator+=(int n) -> IndexIterator& {
  113. index_.index += n;
  114. return *this;
  115. }
  116. auto operator-=(int n) -> IndexIterator& {
  117. index_.index -= n;
  118. return *this;
  119. }
  120. // Prints the raw index.
  121. auto Print(llvm::raw_ostream& output) const -> void {
  122. output << index_.index;
  123. }
  124. private:
  125. IndexT index_;
  126. };
  127. } // namespace Carbon
  128. #endif // CARBON_TOOLCHAIN_BASE_INDEX_BASE_H_