[K/N] Add kotlin::raw_ptr<T> helper class ^KT-56233
kotlin::raw_ptr<T> is exactly T* but with the default constructor setting value to nullptr and with destructive move.
This commit is contained in:
committed by
Space Team
parent
4bc1271f55
commit
9e5a2efb03
@@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <functional>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "Utils.hpp"
|
||||||
|
|
||||||
|
namespace kotlin {
|
||||||
|
|
||||||
|
// raw_ptr<T> is T* but
|
||||||
|
// * with default constructor setting value to null
|
||||||
|
// * with destructive move
|
||||||
|
// * with <, <=, >=, > guaranteeing total order.
|
||||||
|
template <typename T>
|
||||||
|
class [[clang::trivial_abi]] raw_ptr final {
|
||||||
|
// TODO: Look up if there're active C++ proposals for that.
|
||||||
|
// TODO: Support type casts.
|
||||||
|
public:
|
||||||
|
raw_ptr() noexcept = default;
|
||||||
|
raw_ptr(std::nullptr_t) noexcept {}
|
||||||
|
raw_ptr(T* impl) noexcept : impl_(impl) {} // implicit by design
|
||||||
|
|
||||||
|
raw_ptr(const raw_ptr&) noexcept = default;
|
||||||
|
raw_ptr& operator=(const raw_ptr&) noexcept = default;
|
||||||
|
|
||||||
|
raw_ptr(raw_ptr&& rhs) noexcept : impl_(rhs.impl_) { rhs.impl_ = nullptr; }
|
||||||
|
|
||||||
|
raw_ptr& operator=(raw_ptr&& rhs) noexcept {
|
||||||
|
raw_ptr tmp(std::move(rhs));
|
||||||
|
swap(tmp);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~raw_ptr() = default;
|
||||||
|
|
||||||
|
void swap(raw_ptr& rhs) noexcept { std::swap(impl_, rhs.impl_); }
|
||||||
|
|
||||||
|
T& operator*() const noexcept { return *impl_; }
|
||||||
|
|
||||||
|
T* operator->() const noexcept { return impl_; }
|
||||||
|
|
||||||
|
explicit operator bool() const noexcept { return impl_; }
|
||||||
|
|
||||||
|
bool operator==(raw_ptr<T> rhs) const noexcept { return impl_ == rhs.impl_; }
|
||||||
|
|
||||||
|
bool operator!=(raw_ptr<T> rhs) const noexcept { return impl_ != rhs.impl_; }
|
||||||
|
|
||||||
|
bool operator<(raw_ptr<T> rhs) const noexcept { return std::less<>()(impl_, rhs.impl_); }
|
||||||
|
|
||||||
|
bool operator<=(raw_ptr<T> rhs) const noexcept { return std::less_equal<>()(impl_, rhs.impl_); }
|
||||||
|
|
||||||
|
bool operator>(raw_ptr<T> rhs) const noexcept { return std::greater<>()(impl_, rhs.impl_); }
|
||||||
|
|
||||||
|
bool operator>=(raw_ptr<T> rhs) const noexcept { return std::greater_equal<>()(impl_, rhs.impl_); }
|
||||||
|
|
||||||
|
raw_ptr<T>& operator++() noexcept {
|
||||||
|
++impl_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_ptr<T> operator++(int) noexcept { return impl_++; }
|
||||||
|
|
||||||
|
raw_ptr<T>& operator--() noexcept {
|
||||||
|
--impl_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_ptr<T> operator--(int) noexcept { return impl_--; }
|
||||||
|
|
||||||
|
raw_ptr<T>& operator+=(std::ptrdiff_t arg) noexcept {
|
||||||
|
impl_ += arg;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_ptr<T>& operator-=(std::ptrdiff_t arg) noexcept {
|
||||||
|
impl_ -= arg;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_ptr<T> operator+(std::ptrdiff_t arg) const noexcept { return impl_ + arg; }
|
||||||
|
|
||||||
|
raw_ptr<T> operator-(std::ptrdiff_t arg) const noexcept { return impl_ - arg; }
|
||||||
|
|
||||||
|
std::ptrdiff_t operator-(raw_ptr<T> rhs) const noexcept { return impl_ - rhs.impl_; }
|
||||||
|
|
||||||
|
explicit operator T*() const noexcept { return impl_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend struct std::atomic<raw_ptr>;
|
||||||
|
|
||||||
|
T* impl_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace kotlin
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct atomic<kotlin::raw_ptr<T>> : kotlin::Pinned {
|
||||||
|
public:
|
||||||
|
static constexpr bool is_always_lock_free = atomic<T*>::is_always_lock_free;
|
||||||
|
|
||||||
|
atomic() noexcept = default;
|
||||||
|
|
||||||
|
atomic(kotlin::raw_ptr<T> ptr) noexcept : impl_(static_cast<T*>(ptr)) {}
|
||||||
|
|
||||||
|
kotlin::raw_ptr<T> operator=(kotlin::raw_ptr<T> ptr) noexcept { return impl_ = static_cast<T*>(ptr); }
|
||||||
|
|
||||||
|
bool is_lock_free() const noexcept { return impl_.is_lock_free(); }
|
||||||
|
|
||||||
|
void store(kotlin::raw_ptr<T> ptr, memory_order order = memory_order_seq_cst) noexcept { impl_.store(static_cast<T*>(ptr), order); }
|
||||||
|
|
||||||
|
// This loads a copy of a pointer. To perform a destructive load (i.e. null out `this`, use `exchange(nullptr)`).
|
||||||
|
[[nodiscard("expensive pure function")]] kotlin::raw_ptr<T> load(memory_order order = memory_order_seq_cst) const noexcept {
|
||||||
|
return impl_.load(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This loads a copy of a pointer. To perform a destructive load (i.e. null out `this`, use `exchange(nullptr)`).
|
||||||
|
[[nodiscard("expensive pure function")]] operator kotlin::raw_ptr<T>() const noexcept { return static_cast<T*>(impl_); }
|
||||||
|
|
||||||
|
[[nodiscard("use store if result is not needed")]] kotlin::raw_ptr<T> exchange(
|
||||||
|
kotlin::raw_ptr<T> desired, memory_order order = memory_order_seq_cst) noexcept {
|
||||||
|
return impl_.exchange(static_cast<T*>(desired), order);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compare_exchange_weak(
|
||||||
|
kotlin::raw_ptr<T>& expected, kotlin::raw_ptr<T> desired, memory_order success, memory_order failure) noexcept {
|
||||||
|
return impl_.compare_exchange_weak(expected.impl_, static_cast<T*>(desired), success, failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compare_exchange_weak(
|
||||||
|
kotlin::raw_ptr<T>& expected, kotlin::raw_ptr<T> desired, memory_order order = memory_order_seq_cst) noexcept {
|
||||||
|
return impl_.compare_exchange_weak(expected.impl_, static_cast<T*>(desired), order);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compare_exchange_strong(
|
||||||
|
kotlin::raw_ptr<T>& expected, kotlin::raw_ptr<T> desired, memory_order success, memory_order failure) noexcept {
|
||||||
|
return impl_.compare_exchange_strong(expected.impl_, static_cast<T*>(desired), success, failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compare_exchange_strong(
|
||||||
|
kotlin::raw_ptr<T>& expected, kotlin::raw_ptr<T> desired, memory_order order = memory_order_seq_cst) noexcept {
|
||||||
|
return impl_.compare_exchange_strong(expected.impl_, static_cast<T*>(desired), order);
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin::raw_ptr<T> fetch_add(ptrdiff_t arg, memory_order order = memory_order_seq_cst) noexcept { return impl_.fetch_add(arg, order); }
|
||||||
|
|
||||||
|
kotlin::raw_ptr<T> fetch_sub(ptrdiff_t arg, memory_order order = memory_order_seq_cst) noexcept { return impl_.fetch_sub(arg, order); }
|
||||||
|
|
||||||
|
kotlin::raw_ptr<T> operator++() noexcept { return impl_++; }
|
||||||
|
|
||||||
|
kotlin::raw_ptr<T> operator++(int) noexcept { return ++impl_; }
|
||||||
|
|
||||||
|
kotlin::raw_ptr<T> operator--() noexcept { return impl_--; }
|
||||||
|
|
||||||
|
kotlin::raw_ptr<T> operator--(int) noexcept { return --impl_; }
|
||||||
|
|
||||||
|
kotlin::raw_ptr<T> operator+=(ptrdiff_t arg) noexcept { return impl_ += arg; }
|
||||||
|
|
||||||
|
kotlin::raw_ptr<T> operator-=(ptrdiff_t arg) noexcept { return impl_ -= arg; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
atomic<T*> impl_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct hash<kotlin::raw_ptr<T>> {
|
||||||
|
public:
|
||||||
|
size_t operator()(kotlin::raw_ptr<T> ptr) const { return impl_(static_cast<T*>(ptr)); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
hash<T*> impl_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
Reference in New Issue
Block a user