[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:
Alexander Shabalin
2023-03-31 14:21:07 +02:00
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