From 9e5a2efb03e8e575d811a365d1abadf54c7c5160 Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Fri, 31 Mar 2023 14:21:07 +0200 Subject: [PATCH] [K/N] Add kotlin::raw_ptr helper class ^KT-56233 kotlin::raw_ptr is exactly T* but with the default constructor setting value to nullptr and with destructive move. --- kotlin-native/runtime/src/main/cpp/RawPtr.hpp | 181 ++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 kotlin-native/runtime/src/main/cpp/RawPtr.hpp diff --git a/kotlin-native/runtime/src/main/cpp/RawPtr.hpp b/kotlin-native/runtime/src/main/cpp/RawPtr.hpp new file mode 100644 index 00000000000..de6c8599166 --- /dev/null +++ b/kotlin-native/runtime/src/main/cpp/RawPtr.hpp @@ -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 +#include +#include + +#include "Utils.hpp" + +namespace kotlin { + +// raw_ptr is T* but +// * with default constructor setting value to null +// * with destructive move +// * with <, <=, >=, > guaranteeing total order. +template +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 rhs) const noexcept { return impl_ == rhs.impl_; } + + bool operator!=(raw_ptr rhs) const noexcept { return impl_ != rhs.impl_; } + + bool operator<(raw_ptr rhs) const noexcept { return std::less<>()(impl_, rhs.impl_); } + + bool operator<=(raw_ptr rhs) const noexcept { return std::less_equal<>()(impl_, rhs.impl_); } + + bool operator>(raw_ptr rhs) const noexcept { return std::greater<>()(impl_, rhs.impl_); } + + bool operator>=(raw_ptr rhs) const noexcept { return std::greater_equal<>()(impl_, rhs.impl_); } + + raw_ptr& operator++() noexcept { + ++impl_; + return *this; + } + + raw_ptr operator++(int) noexcept { return impl_++; } + + raw_ptr& operator--() noexcept { + --impl_; + return *this; + } + + raw_ptr operator--(int) noexcept { return impl_--; } + + raw_ptr& operator+=(std::ptrdiff_t arg) noexcept { + impl_ += arg; + return *this; + } + + raw_ptr& operator-=(std::ptrdiff_t arg) noexcept { + impl_ -= arg; + return *this; + } + + raw_ptr operator+(std::ptrdiff_t arg) const noexcept { return impl_ + arg; } + + raw_ptr operator-(std::ptrdiff_t arg) const noexcept { return impl_ - arg; } + + std::ptrdiff_t operator-(raw_ptr rhs) const noexcept { return impl_ - rhs.impl_; } + + explicit operator T*() const noexcept { return impl_; } + +private: + friend struct std::atomic; + + T* impl_ = nullptr; +}; + +} // namespace kotlin + +namespace std { + +template +struct atomic> : kotlin::Pinned { +public: + static constexpr bool is_always_lock_free = atomic::is_always_lock_free; + + atomic() noexcept = default; + + atomic(kotlin::raw_ptr ptr) noexcept : impl_(static_cast(ptr)) {} + + kotlin::raw_ptr operator=(kotlin::raw_ptr ptr) noexcept { return impl_ = static_cast(ptr); } + + bool is_lock_free() const noexcept { return impl_.is_lock_free(); } + + void store(kotlin::raw_ptr ptr, memory_order order = memory_order_seq_cst) noexcept { impl_.store(static_cast(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 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() const noexcept { return static_cast(impl_); } + + [[nodiscard("use store if result is not needed")]] kotlin::raw_ptr exchange( + kotlin::raw_ptr desired, memory_order order = memory_order_seq_cst) noexcept { + return impl_.exchange(static_cast(desired), order); + } + + bool compare_exchange_weak( + kotlin::raw_ptr& expected, kotlin::raw_ptr desired, memory_order success, memory_order failure) noexcept { + return impl_.compare_exchange_weak(expected.impl_, static_cast(desired), success, failure); + } + + bool compare_exchange_weak( + kotlin::raw_ptr& expected, kotlin::raw_ptr desired, memory_order order = memory_order_seq_cst) noexcept { + return impl_.compare_exchange_weak(expected.impl_, static_cast(desired), order); + } + + bool compare_exchange_strong( + kotlin::raw_ptr& expected, kotlin::raw_ptr desired, memory_order success, memory_order failure) noexcept { + return impl_.compare_exchange_strong(expected.impl_, static_cast(desired), success, failure); + } + + bool compare_exchange_strong( + kotlin::raw_ptr& expected, kotlin::raw_ptr desired, memory_order order = memory_order_seq_cst) noexcept { + return impl_.compare_exchange_strong(expected.impl_, static_cast(desired), order); + } + + kotlin::raw_ptr fetch_add(ptrdiff_t arg, memory_order order = memory_order_seq_cst) noexcept { return impl_.fetch_add(arg, order); } + + kotlin::raw_ptr fetch_sub(ptrdiff_t arg, memory_order order = memory_order_seq_cst) noexcept { return impl_.fetch_sub(arg, order); } + + kotlin::raw_ptr operator++() noexcept { return impl_++; } + + kotlin::raw_ptr operator++(int) noexcept { return ++impl_; } + + kotlin::raw_ptr operator--() noexcept { return impl_--; } + + kotlin::raw_ptr operator--(int) noexcept { return --impl_; } + + kotlin::raw_ptr operator+=(ptrdiff_t arg) noexcept { return impl_ += arg; } + + kotlin::raw_ptr operator-=(ptrdiff_t arg) noexcept { return impl_ -= arg; } + +private: + atomic impl_; +}; + +template +struct hash> { +public: + size_t operator()(kotlin::raw_ptr ptr) const { return impl_(static_cast(ptr)); } + +private: + hash impl_; +}; + +} // namespace std