blob: 1ffa5c3deff834ecc8ed996c76771ce597a89e38 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIB_FIDL_LLCPP_UNOWNED_PTR_H_
#define LIB_FIDL_LLCPP_UNOWNED_PTR_H_
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <type_traits>
namespace fidl {
// unowned_ptr_t is a pointer that is explicitly marked as unowned.
//
// Functionally, unowned_ptr_t behaves like a raw pointer - it can be copied, dereferenced
// and reassigned. The motivation for unowned_ptr_t is to make ownership explicit within
// tracking_ptr.
// For example:
// tracking_ptr<T> obj = unowned_ptr_t<T>(&x);
template <typename T>
class unowned_ptr_t {
template <typename U>
using disable_if_void = typename std::enable_if_t<!std::is_void<U>::value>;
public:
constexpr unowned_ptr_t() noexcept : ptr_(nullptr) {}
constexpr unowned_ptr_t(std::nullptr_t) noexcept : ptr_(nullptr) {}
unowned_ptr_t(const unowned_ptr_t<T>&) noexcept = default;
unowned_ptr_t(unowned_ptr_t<T>&&) noexcept = default;
template <typename U = T>
explicit unowned_ptr_t(U* ptr) noexcept : ptr_(ptr) {}
// Enable static casting from types where it is possible on the underlying pointer.
template <typename U>
unowned_ptr_t(const unowned_ptr_t<U>& other) noexcept : ptr_(static_cast<T*>(other.get())) {}
unowned_ptr_t<T>& operator=(unowned_ptr_t<T>&&) = default;
unowned_ptr_t<T>& operator=(const unowned_ptr_t<T>&) = default;
unowned_ptr_t<T>& operator=(T* ptr) noexcept {
ptr_ = ptr;
return *this;
}
T* get() const noexcept { return ptr_; }
template <typename U = T, typename = disable_if_void<U>>
U& operator*() const {
return *ptr_;
}
template <typename U = T, typename = disable_if_void<U>>
U* operator->() const noexcept {
return ptr_;
}
template <typename U = T, typename = disable_if_void<U>>
U& operator[](size_t index) const {
return ptr_[index];
}
explicit operator bool() const noexcept { return ptr_ != nullptr; }
private:
T* ptr_;
};
static_assert(sizeof(fidl::unowned_ptr_t<void>) == sizeof(void*),
"unowned_ptr_t has the same size as a raw pointer");
#define UNIQUE_PTR_OPERATOR_COMPARISONS(func_name, op) \
template <typename T1, typename T2> \
bool func_name(const unowned_ptr_t<T1> p1, const unowned_ptr_t<T2> p2) { \
return p1.get() op p2.get(); \
}
#define UNIQUE_PTR_NULLPTR_COMPARISONS(func_name, op) \
template <typename T1> \
bool func_name(const unowned_ptr_t<T1> p1, const std::nullptr_t p2) { \
return p1.get() op nullptr; \
} \
template <typename T2> \
bool func_name(const std::nullptr_t p1, const unowned_ptr_t<T2> p2) { \
return nullptr op p2.get(); \
}
UNIQUE_PTR_OPERATOR_COMPARISONS(operator==, ==)
UNIQUE_PTR_NULLPTR_COMPARISONS(operator==, ==)
UNIQUE_PTR_OPERATOR_COMPARISONS(operator!=, !=)
UNIQUE_PTR_NULLPTR_COMPARISONS(operator!=, !=)
UNIQUE_PTR_OPERATOR_COMPARISONS(operator<, <)
UNIQUE_PTR_OPERATOR_COMPARISONS(operator<=, <=)
UNIQUE_PTR_OPERATOR_COMPARISONS(operator>, >)
UNIQUE_PTR_OPERATOR_COMPARISONS(operator>=, >=)
} // namespace fidl
namespace std {
template <typename T>
void swap(fidl::unowned_ptr_t<T>& lhs, fidl::unowned_ptr_t<T>& rhs) noexcept {
auto temp = rhs;
rhs = lhs;
lhs = temp;
}
template <class T>
struct hash<fidl::unowned_ptr_t<T>> {
size_t operator()(const fidl::unowned_ptr_t<T>& ptr) const { return hash<T*>{}(ptr.get()); }
};
} // namespace std
#endif // LIB_FIDL_LLCPP_UNOWNED_PTR_H_