indirect_value.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  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_INDIRECT_VALUE_H_
  5. #define CARBON_COMMON_INDIRECT_VALUE_H_
  6. #include <memory>
  7. #include <type_traits>
  8. #include <utility>
  9. namespace Carbon {
  10. template <typename T>
  11. class IndirectValue;
  12. // Creates and returns an IndirectValue that holds the value returned by
  13. // `callable()`.
  14. template <typename Callable>
  15. auto MakeIndirectValue(Callable callable)
  16. -> IndirectValue<std::decay_t<decltype(callable())>>;
  17. // An IndirectValue<T> object stores a T value, using a layer of indirection
  18. // that allows us to name the IndirectValue<T> type, and even access the
  19. // underlying T value, in a context where T is not a complete type. This makes
  20. // it useful for things like defining recursive types. T must be an object type.
  21. //
  22. // The underlying value is accessed using the * and -> operators, but
  23. // IndirectValue does not otherwise behave like a pointer: it has no null state,
  24. // and separate IndirectValue objects are never aliases for the same T object.
  25. // Instead, an IndirectValue object behaves as much as possible like a T object:
  26. // the default constructor, copy operations, and move operations all delegate to
  27. // the corresponding operations on T, and a const IndirectValue object provides
  28. // only const access to the underlying T object. The address of the underlying T
  29. // object remains the same throughout the lifetime of the IndirectValue.
  30. //
  31. // IndirectValue is inspired by the indirect_value library proposed in
  32. // http://wg21.link/P1950R1, but makes some different design choices (notably,
  33. // not having an empty state) in order to provide a more value-like API.
  34. template <typename T>
  35. class IndirectValue {
  36. public:
  37. // TODO(geoffromer): consider using enable_if to disable constructors and
  38. // assignment operators when they wouldn't compile, so that traits like
  39. // std::is_constructible give correct answers.
  40. // Initializes the underlying T object as if by `T()`.
  41. IndirectValue() : value_(std::make_unique<T>()) {}
  42. // Initializes the underlying T object as if by `T(std::move(value))`.
  43. // NOLINTNEXTLINE(google-explicit-constructor): Implicit constructor.
  44. IndirectValue(T value) : value_(std::make_unique<T>(std::move(value))) {}
  45. // TODO(geoffromer): consider defining implicit conversions from
  46. // U and IndirectValue<U>, when U is implicitly convertible to T.
  47. IndirectValue(const IndirectValue& other)
  48. : value_(std::make_unique<T>(*other)) {}
  49. IndirectValue(IndirectValue&& other) noexcept
  50. : value_(std::make_unique<T>(std::move(*other))) {}
  51. auto operator=(const IndirectValue& other) -> IndirectValue& {
  52. *value_ = *other.value_;
  53. return *this;
  54. }
  55. auto operator=(IndirectValue&& other) noexcept -> IndirectValue& {
  56. *value_ = std::move(*other.value_);
  57. return *this;
  58. }
  59. auto operator*() -> T& { return *value_; }
  60. auto operator*() const -> const T& { return *value_; }
  61. auto operator->() -> T* { return value_.get(); }
  62. auto operator->() const -> const T* { return value_.get(); }
  63. // Returns the address of the stored value.
  64. //
  65. // TODO(geoffromer): Consider eliminating this method, which is not
  66. // present in comparable types like indirect_value<T> or optional<T>,
  67. // once our APIs are less pointer-centric.
  68. auto GetPointer() -> T* { return value_.get(); }
  69. auto GetPointer() const -> const T* { return value_.get(); }
  70. private:
  71. static_assert(std::is_object_v<T>, "T must be an object type");
  72. template <typename Callable>
  73. friend auto MakeIndirectValue(Callable callable)
  74. -> IndirectValue<std::decay_t<decltype(callable())>>;
  75. template <typename... Args>
  76. explicit IndirectValue(std::unique_ptr<T> value) : value_(std::move(value)) {}
  77. const std::unique_ptr<T> value_;
  78. };
  79. template <typename Callable>
  80. auto MakeIndirectValue(Callable callable)
  81. -> IndirectValue<std::decay_t<decltype(callable())>> {
  82. using T = std::decay_t<decltype(callable())>;
  83. return IndirectValue<T>(std::unique_ptr<T>(new T(callable())));
  84. }
  85. } // namespace Carbon
  86. #endif // CARBON_COMMON_INDIRECT_VALUE_H_