array_stack.h 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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. // Returns the array at a specific index.
  44. auto PeekArrayAt(int index) const -> llvm::ArrayRef<ValueT> {
  45. auto ref = llvm::ArrayRef(values_).slice(array_offsets_[index]);
  46. if (index + 1 < static_cast<int>(array_offsets_.size())) {
  47. ref = ref.take_front(array_offsets_[index + 1] - array_offsets_[index]);
  48. }
  49. return ref;
  50. }
  51. // Returns the full set of values on the stack, regardless of whether any
  52. // arrays are pushed.
  53. auto PeekAllValues() const -> llvm::ArrayRef<ValueT> { return values_; }
  54. // Appends a value to the top array on the stack.
  55. auto AppendToTop(ValueT value) -> void {
  56. CARBON_CHECK(!array_offsets_.empty(),
  57. "Must call PushArray before AppendToTop.");
  58. values_.push_back(value);
  59. }
  60. // Prepends a value to the top array on the stack.
  61. auto PrependToTop(ValueT value) -> void {
  62. CARBON_CHECK(!array_offsets_.empty(),
  63. "Must call PushArray before PrependToTop.");
  64. values_.insert(values_.begin() + array_offsets_.back(), value);
  65. }
  66. // Adds multiple values to the top array on the stack.
  67. auto AppendToTop(llvm::ArrayRef<ValueT> values) -> void {
  68. CARBON_CHECK(!array_offsets_.empty(),
  69. "Must call PushArray before PushValues.");
  70. llvm::append_range(values_, values);
  71. }
  72. // Returns the current number of values in all arrays.
  73. auto all_values_size() const -> size_t { return values_.size(); }
  74. // Returns true if the stack has no arrays pushed.
  75. auto empty() const -> bool { return array_offsets_.empty(); }
  76. private:
  77. // For each pushed array, the start index in elements_.
  78. llvm::SmallVector<int32_t> array_offsets_;
  79. // The full set of elements in all arrays.
  80. llvm::SmallVector<ValueT> values_;
  81. };
  82. } // namespace Carbon
  83. #endif // CARBON_COMMON_ARRAY_STACK_H_