[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