arena.h 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  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_EXPLORER_COMMON_ARENA_H_
  5. #define CARBON_EXPLORER_COMMON_ARENA_H_
  6. #include <memory>
  7. #include <type_traits>
  8. #include <vector>
  9. #include "explorer/common/nonnull.h"
  10. namespace Carbon {
  11. class Arena {
  12. public:
  13. // Values of this type can be passed as the first argument to New in order to
  14. // have the address of the created object written to the given pointer before
  15. // the constructor is run. This is used during cloning to support pointer
  16. // cycles within the AST.
  17. template <typename T>
  18. struct WriteAddressTo {
  19. Nonnull<T**> target;
  20. };
  21. template <typename T>
  22. WriteAddressTo(T** target) -> WriteAddressTo<T>;
  23. // Allocates an object in the arena, returning a pointer to it.
  24. template <
  25. typename T, typename... Args,
  26. typename std::enable_if_t<std::is_constructible_v<T, Args...>>* = nullptr>
  27. auto New(Args&&... args) -> Nonnull<T*> {
  28. auto smart_ptr =
  29. std::make_unique<ArenaEntryTyped<T>>(std::forward<Args>(args)...);
  30. Nonnull<T*> ptr = smart_ptr->Instance();
  31. arena_.push_back(std::move(smart_ptr));
  32. allocated_ += sizeof(T);
  33. return ptr;
  34. }
  35. // Allocates an object in the arena, writing its address to the given pointer.
  36. template <
  37. typename T, typename U, typename... Args,
  38. typename std::enable_if_t<std::is_constructible_v<T, Args...>>* = nullptr>
  39. void New(WriteAddressTo<U> addr, Args&&... args) {
  40. arena_.push_back(std::make_unique<ArenaEntryTyped<T>>(
  41. addr, std::forward<Args>(args)...));
  42. allocated_ += sizeof(T);
  43. }
  44. auto allocated() -> int64_t { return allocated_; }
  45. private:
  46. // Virtualizes arena entries so that a single vector can contain many types,
  47. // avoiding templated statics.
  48. class ArenaEntry {
  49. public:
  50. virtual ~ArenaEntry() = default;
  51. };
  52. // Templated destruction of a pointer.
  53. template <typename T>
  54. class ArenaEntryTyped : public ArenaEntry {
  55. public:
  56. struct WriteAddressHelper {};
  57. template <typename... Args>
  58. explicit ArenaEntryTyped(Args&&... args)
  59. : instance_(std::forward<Args>(args)...) {}
  60. template <typename... Args>
  61. explicit ArenaEntryTyped(WriteAddressHelper, Args&&... args)
  62. : ArenaEntryTyped(std::forward<Args>(args)...) {}
  63. template <typename U, typename... Args>
  64. explicit ArenaEntryTyped(WriteAddressTo<U> write_address, Args&&... args)
  65. : ArenaEntryTyped(
  66. (*write_address.target = &instance_, WriteAddressHelper{}),
  67. std::forward<Args>(args)...) {}
  68. auto Instance() -> Nonnull<T*> { return Nonnull<T*>(&instance_); }
  69. private:
  70. T instance_;
  71. };
  72. // Manages allocations in an arena for destruction at shutdown.
  73. std::vector<std::unique_ptr<ArenaEntry>> arena_;
  74. int64_t allocated_ = 0;
  75. };
  76. } // namespace Carbon
  77. #endif // CARBON_EXPLORER_COMMON_ARENA_H_