array_stack.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  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_COMMON_ARRAY_STACK_H_
  5. #define CARBON_COMMON_ARRAY_STACK_H_
  6. #include "common/check.h"
  7. #include "llvm/ADT/ArrayRef.h"
  8. #include "llvm/ADT/SmallVector.h"
  9. namespace Carbon {
  10. // Provides a stack of arrays. Only the array at the top of the stack can have
  11. // elements added.
  12. //
  13. // Example usage:
  14. // // Push to start.
  15. // PushArray();
  16. // // Add values.
  17. // AppendToTop(3);
  18. // // Look at values.
  19. // PeekArray();
  20. // // Pop when done.
  21. // PopArray();
  22. //
  23. // By using a single vector for elements, the intent is that as arrays are
  24. // pushed and popped, the same storage will be reused. This should yield
  25. // efficiencies for heap allocations. For example, in the toolchain we
  26. // frequently have an array per scope, and only add to the current scope's
  27. // array; this allows better reuse when entering and leaving scopes.
  28. template <typename ValueT>
  29. class ArrayStack {
  30. public:
  31. // Pushes a new array onto the stack.
  32. auto PushArray() -> void { array_offsets_.push_back(values_.size()); }
  33. // Pops the top array from the stack.
  34. auto PopArray() -> void {
  35. auto region = array_offsets_.pop_back_val();
  36. values_.truncate(region);
  37. }
  38. // Returns the top array from the stack.
  39. auto PeekArray() const -> llvm::ArrayRef<ValueT> {
  40. CARBON_CHECK(!array_offsets_.empty());
  41. return llvm::ArrayRef(values_).slice(array_offsets_.back());
  42. }
  43. auto PeekArray() -> llvm::MutableArrayRef<ValueT> {
  44. CARBON_CHECK(!array_offsets_.empty());
  45. return llvm::MutableArrayRef(values_).slice(array_offsets_.back());
  46. }
  47. // Returns the array at a specific index.
  48. auto PeekArrayAt(int index) const -> llvm::ArrayRef<ValueT> {
  49. auto ref = llvm::ArrayRef(values_).slice(array_offsets_[index]);
  50. if (index + 1 < static_cast<int>(array_offsets_.size())) {
  51. ref = ref.take_front(array_offsets_[index + 1] - array_offsets_[index]);
  52. }
  53. return ref;
  54. }
  55. // Returns the full set of values on the stack, regardless of whether any
  56. // arrays are pushed.
  57. auto PeekAllValues() const -> llvm::ArrayRef<ValueT> { return values_; }
  58. // Appends a value to the top array on the stack.
  59. auto AppendToTop(const ValueT& value) -> void {
  60. CARBON_CHECK(!array_offsets_.empty(),
  61. "Must call PushArray before AppendToTop.");
  62. values_.push_back(value);
  63. }
  64. // Appends a value to the top array on the stack.
  65. auto AppendToTop(ValueT&& value) -> void {
  66. CARBON_CHECK(!array_offsets_.empty(),
  67. "Must call PushArray before AppendToTop.");
  68. values_.push_back(std::move(value));
  69. }
  70. // Adds multiple values to the top array on the stack.
  71. auto AppendToTop(llvm::ArrayRef<ValueT> values) -> void {
  72. CARBON_CHECK(!array_offsets_.empty(),
  73. "Must call PushArray before AppendToTop.");
  74. llvm::append_range(values_, values);
  75. }
  76. // Returns the current number of values in all arrays.
  77. auto all_values_size() const -> size_t { return values_.size(); }
  78. // Returns true if the stack has no arrays pushed.
  79. auto empty() const -> bool { return array_offsets_.empty(); }
  80. private:
  81. // For each pushed array, the start index in `values_`.
  82. llvm::SmallVector<int32_t> array_offsets_;
  83. // The full set of elements in all arrays.
  84. llvm::SmallVector<ValueT> values_;
  85. };
  86. } // namespace Carbon
  87. #endif // CARBON_COMMON_ARRAY_STACK_H_