| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
- // Exceptions. See /LICENSE for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- #ifndef COMMON_INDIRECT_VALUE_H_
- #define COMMON_INDIRECT_VALUE_H_
- #include <memory>
- #include <type_traits>
- #include <utility>
- namespace Carbon {
- template <typename T>
- class IndirectValue;
- // Creates and returns an IndirectValue that holds the value returned by
- // `callable()`.
- template <typename Callable>
- auto CreateIndirectValue(Callable callable)
- -> IndirectValue<std::decay_t<decltype(callable())>>;
- // An IndirectValue<T> object stores a T value, using a layer of indirection
- // that allows us to name the IndirectValue<T> type, and even access the
- // underlying T value, in a context where T is not a complete type. This makes
- // it useful for things like defining recursive types. T must be an object type.
- //
- // The underlying value is accessed using the * and -> operators, but
- // IndirectValue does not otherwise behave like a pointer: it has no null state,
- // and separate IndirectValue objects are never aliases for the same T object.
- // Instead, an IndirectValue object behaves as much as possible like a T object:
- // the default constructor, copy operations, and move operations all delegate to
- // the corresponding operations on T, and a const IndirectValue object provides
- // only const access to the underlying T object. The address of the underlying T
- // object remains the same throughout the lifetime of the IndirectValue.
- //
- // IndirectValue is inspired by the indirect_value library proposed in
- // http://wg21.link/P1950R1, but makes some different design choices (notably,
- // not having an empty state) in order to provide a more value-like API.
- template <typename T>
- class IndirectValue {
- public:
- // TODO(geoffromer): consider using enable_if to disable constructors and
- // assignment operators when they wouldn't compile, so that traits like
- // std::is_constructible give correct answers.
- // Initializes the underlying T object as if by `T()`.
- IndirectValue() : value(std::make_unique<T>()) {}
- // Initializes the underlying T object as if by `T(std::move(value))`.
- IndirectValue(T value) : value(std::make_unique<T>(std::move(value))) {}
- // TODO(geoffromer): consider defining implicit conversions from
- // U and IndirectValue<U>, when U is implicitly convertible to T.
- IndirectValue(const IndirectValue& other)
- : value(std::make_unique<T>(*other)) {}
- IndirectValue(IndirectValue&& other)
- : value(std::make_unique<T>(std::move(*other))) {}
- auto operator=(const IndirectValue& other) -> IndirectValue& {
- *value = *other.value;
- return *this;
- }
- auto operator=(IndirectValue&& other) -> IndirectValue& {
- *value = std::move(*other.value);
- return *this;
- }
- auto operator*() -> T& { return *value; }
- auto operator*() const -> const T& { return *value; }
- auto operator->() -> T* { return value.get(); }
- auto operator->() const -> const T* { return value.get(); }
- // Returns the address of the stored value.
- //
- // TODO(geoffromer): Consider eliminating this method, which is not
- // present in comparable types like indirect_value<T> or optional<T>,
- // once our APIs are less pointer-centric.
- auto GetPointer() -> T* { return value.get(); }
- auto GetPointer() const -> const T* { return value.get(); }
- private:
- static_assert(std::is_object_v<T>, "T must be an object type");
- template <typename Callable>
- friend auto CreateIndirectValue(Callable callable)
- -> IndirectValue<std::decay_t<decltype(callable())>>;
- template <typename... Args>
- IndirectValue(std::unique_ptr<T> value) : value(std::move(value)) {}
- const std::unique_ptr<T> value;
- };
- template <typename Callable>
- auto CreateIndirectValue(Callable callable)
- -> IndirectValue<std::decay_t<decltype(callable())>> {
- using T = std::decay_t<decltype(callable())>;
- return IndirectValue<T>(std::unique_ptr<T>(new T(callable())));
- }
- } // namespace Carbon
- #endif // COMMON_INDIRECT_VALUE_H_
|