opynsim
Unofficial C++ Documentation
Loading...
Searching...
No Matches
copy_on_upd_shared_value.h
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <atomic>
5#include <compare>
6#include <concepts>
7#include <cstddef>
8#include <memory>
9#include <new>
10#include <type_traits>
11#include <utility>
12
13namespace osc
14{
15 template<typename T>
17 public:
18 using pointer = T*;
19 using const_pointer = const T*;
20 using const_reference = const T&;
21
23 ptr_{other.ptr_}
24 {
25 ptr_->owners.fetch_add(1, std::memory_order::relaxed);
26 }
27
31
33 {
34 if (ptr_->owners.fetch_sub(1, std::memory_order_acq_rel) == 1) {
35 ptr_->deleter(ptr_);
36 }
37 }
38
40 {
42 swap(copy, *this);
43 return *this;
44 }
45
47 {
48 return *this = static_cast<const CopyOnUpdSharedValue&>(rhs);
49 }
50
51 friend void swap(CopyOnUpdSharedValue& a, CopyOnUpdSharedValue& b) noexcept
52 {
53 std::swap(a.ptr_, b.ptr_);
54 }
55
56 template<typename U>
57 friend bool operator==(const CopyOnUpdSharedValue& lhs, const CopyOnUpdSharedValue<U>& rhs) { return lhs.ptr_ == rhs.ptr_; }
58 template<typename U>
59 friend auto operator<=>(const CopyOnUpdSharedValue& lhs, const CopyOnUpdSharedValue<U>& rhs) { return lhs.ptr_ <=> rhs.ptr_; }
60
61 const_pointer get() const noexcept { return static_cast<const T*>(ptr_->data); }
63 const_reference operator*() const { return *get(); }
64
66 {
67 if (ptr_->owners.load(std::memory_order_acquire) == 1) {
68 return static_cast<T*>(ptr_->data);
69 }
70 CopyOnUpdSharedValue copy{allocate_representation(*get())};
71 swap(copy, *this);
72 return static_cast<T*>(ptr_->data);
73 }
74
75 long use_count() const noexcept { return ptr_->owners; }
76
77 private:
78 friend struct std::hash<CopyOnUpdSharedValue>;
79
80 template<typename U, typename... Args>
82
83 struct ControlBlock final {
84 explicit ControlBlock(void (*deleter)(ControlBlock*) noexcept, void* data) noexcept :
85 deleter{deleter},
86 data{data}
87 {}
88
89 std::atomic<long> owners = 1;
90 void (*deleter)(ControlBlock*) noexcept;
91 void* data;
92 };
93
94 explicit CopyOnUpdSharedValue(ControlBlock* ptr) noexcept : ptr_{ptr} {}
95
96 template<typename... Args>
97 requires std::constructible_from<T, Args&&...>
98 static ControlBlock* allocate_representation(Args&&... args)
99 {
100 // Calculate memory allocation layout, size, and alignment
101 constexpr size_t data_offset = (sizeof(ControlBlock) + (alignof(T) - 1)) & ~(alignof(T) - 1);
102 constexpr size_t allocation_size = data_offset + sizeof(T);
103 constexpr std::align_val_t allocation_alignment{std::max(alignof(ControlBlock), alignof(T))};
104
105 // Generate a type-erased and stateless destructor for `T`
106 auto deleter = [](ControlBlock* cb) noexcept -> void
107 {
108 std::destroy_at(static_cast<T*>(cb->data));
109 std::destroy_at(cb);
110 ::operator delete(static_cast<void*>(cb), allocation_alignment);
111 };
112
113 // Allocate a memory block containing both the control block and data
114 std::unique_ptr<void, void(*)(void*)> allocation{
116 [](void* p) { ::operator delete(p, allocation_alignment); },
117 };
118
119 // Construct `ControlBlock` and `T` representations in the memory block
120 std::byte* data_ptr = static_cast<std::byte*>(allocation.get()) + data_offset;
121 new (data_ptr) T(std::forward<Args>(args)...);
122 static_assert(std::is_nothrow_constructible_v<ControlBlock, decltype(deleter), decltype(data_ptr)>);
123 new (allocation.get()) ControlBlock(deleter, data_ptr);
124
125 return static_cast<ControlBlock*>(allocation.release());
126 }
127
128 ControlBlock* ptr_;
129 };
130
131 template<typename U, typename... Args>
136}
Definition copy_on_upd_shared_value.h:16
CopyOnUpdSharedValue & operator=(const CopyOnUpdSharedValue &rhs) noexcept
Definition copy_on_upd_shared_value.h:39
CopyOnUpdSharedValue(const CopyOnUpdSharedValue &other) noexcept
Definition copy_on_upd_shared_value.h:22
friend CopyOnUpdSharedValue< U > make_cowv(Args &&...)
const_reference operator*() const
Definition copy_on_upd_shared_value.h:63
~CopyOnUpdSharedValue() noexcept
Definition copy_on_upd_shared_value.h:32
pointer upd()
Definition copy_on_upd_shared_value.h:65
const_pointer operator->() const noexcept
Definition copy_on_upd_shared_value.h:62
const T * const_pointer
Definition copy_on_upd_shared_value.h:19
const_pointer get() const noexcept
Definition copy_on_upd_shared_value.h:61
long use_count() const noexcept
Definition copy_on_upd_shared_value.h:75
friend void swap(CopyOnUpdSharedValue &a, CopyOnUpdSharedValue &b) noexcept
Definition copy_on_upd_shared_value.h:51
CopyOnUpdSharedValue & operator=(CopyOnUpdSharedValue &&rhs) noexcept
Definition copy_on_upd_shared_value.h:46
CopyOnUpdSharedValue(CopyOnUpdSharedValue &&tmp) noexcept
Definition copy_on_upd_shared_value.h:28
friend auto operator<=>(const CopyOnUpdSharedValue &lhs, const CopyOnUpdSharedValue< U > &rhs)
Definition copy_on_upd_shared_value.h:59
T * pointer
Definition copy_on_upd_shared_value.h:18
const T & const_reference
Definition copy_on_upd_shared_value.h:20
friend bool operator==(const CopyOnUpdSharedValue &lhs, const CopyOnUpdSharedValue< U > &rhs)
Definition copy_on_upd_shared_value.h:57
Definition custom_decoration_generator.h:5
constexpr U to(T &&value)
Definition conversion.h:56
CopyOnUpdSharedValue< U > make_cowv(Args &&... args)
Definition copy_on_upd_shared_value.h:132