indirect_value.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  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 COMMON_INDIRECT_VALUE_H_
  5. #define 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 CreateIndirectValue(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. IndirectValue(T value) : value(std::make_unique<T>(std::move(value))) {}
  44. // TODO(geoffromer): consider defining implicit conversions from
  45. // U and IndirectValue<U>, when U is implicitly convertible to T.
  46. IndirectValue(const IndirectValue& other)
  47. : value(std::make_unique<T>(*other)) {}
  48. IndirectValue(IndirectValue&& other)
  49. : value(std::make_unique<T>(std::move(*other))) {}
  50. auto operator=(const IndirectValue& other) -> IndirectValue& {
  51. *value = *other.value;
  52. return *this;
  53. }
  54. auto operator=(IndirectValue&& other) -> IndirectValue& {
  55. *value = std::move(*other.value);
  56. return *this;
  57. }
  58. auto operator*() -> T& { return *value; }
  59. auto operator*() const -> const T& { return *value; }
  60. auto operator->() -> T* { return value.get(); }
  61. auto operator->() const -> const T* { return value.get(); }
  62. // Returns the address of the stored value.
  63. //
  64. // TODO(geoffromer): Consider eliminating this method, which is not
  65. // present in comparable types like indirect_value<T> or optional<T>,
  66. // once our APIs are less pointer-centric.
  67. auto GetPointer() -> T* { return value.get(); }
  68. auto GetPointer() const -> const T* { return value.get(); }
  69. private:
  70. static_assert(std::is_object_v<T>, "T must be an object type");
  71. template <typename Callable>
  72. friend auto CreateIndirectValue(Callable callable)
  73. -> IndirectValue<std::decay_t<decltype(callable())>>;
  74. template <typename... Args>
  75. IndirectValue(std::unique_ptr<T> value) : value(std::move(value)) {}
  76. const std::unique_ptr<T> value;
  77. };
  78. template <typename Callable>
  79. auto CreateIndirectValue(Callable callable)
  80. -> IndirectValue<std::decay_t<decltype(callable())>> {
  81. using T = std::decay_t<decltype(callable())>;
  82. return IndirectValue<T>(std::unique_ptr<T>(new T(callable())));
  83. }
  84. } // namespace Carbon
  85. #endif // COMMON_INDIRECT_VALUE_H_