17#ifndef STLAB_COPY_ON_WRITE_HPP
18#define STLAB_COPY_ON_WRITE_HPP
103#include <type_traits>
126 std::atomic<std::size_t> _count{1};
128 model()
noexcept(std::is_nothrow_constructible_v<T>) =
default;
130 template <
class... Args>
131 explicit model(Args&&... args)
noexcept(std::is_nothrow_constructible_v<T, Args&&...>) :
132 _value(std::forward<Args>(args)...) {}
140 using disable_copy = std::enable_if_t<!std::is_same_v<std::decay_t<U>,
copy_on_write>>*;
142 template <
typename U>
143 using disable_copy_assign =
146 auto default_model()
noexcept(std::is_nothrow_constructible_v<T>) -> model* {
147 static model default_s;
171 _self = default_model();
174 _self->_count.fetch_add(1, std::memory_order_relaxed);
181 copy_on_write(U&& x, disable_copy<U> =
nullptr) : _self(new model(std::forward<U>(x))) {}
187 template <
class U,
class V,
class... Args>
189 _self(new model(std::forward<U>(x), std::forward<V>(y), std::forward<Args>(args)...)) {}
195 assert(_self &&
"FATAL (sparent) : using a moved copy_on_write object");
198 _self->_count.fetch_add(1, std::memory_order_relaxed);
205 assert(_self &&
"WARNING (sparent) : using a moved copy_on_write object");
212 assert(!_self || ((_self->_count > 0) &&
"FATAL (sparent) : double delete"));
213 if (_self && (_self->_count.fetch_sub(1, std::memory_order_release) == 1)) {
214 std::atomic_thread_fence(std::memory_order_acquire);
215 if constexpr (std::is_default_constructible_v<element_type>) {
216 assert(_self != default_model());
227 assert(
this != &x &&
"self-assignment is not allowed");
235 auto tmp{std::move(x)};
247 _self->_value = std::forward<U>(x);
266 return _self->_value;
282 template <
class Transform,
class Inplace>
284 static_assert(std::is_invocable_r_v<T, Transform, const T&>,
285 "Transform must be invocable with const T&");
286 static_assert(std::is_invocable_r_v<void, Inplace, T&>,
287 "Inplace must be invocable with T&");
292 inplace(_self->_value);
295 return _self->_value;
302 assert(_self &&
"FATAL (sparent) : using a moved copy_on_write object");
304 return _self->_value;
327 [[nodiscard]]
auto unique() const noexcept ->
bool {
328 assert(_self &&
"FATAL (sparent) : using a moved copy_on_write object");
330 return _self->_count.load(std::memory_order_acquire) == 1;
343 assert((_self && x._self) &&
"FATAL (sparent) : using a moved copy_on_write object");
345 return _self == x._self;
358 std::swap(x._self, y._self);
366 return !x.identity(y) && (*x < *y);
414 return x.identity(y) || (*x == *y);
copy_on_write(U &&x, V &&y, Args &&... args)
Constructs a new instance by forwarding multiple arguments to the wrapped value constructor.
Definition copy_on_write.hpp:188
auto operator=(copy_on_write &&x) noexcept -> copy_on_write &
Move assignment operator that takes ownership of the source object's data.
Definition copy_on_write.hpp:234
copy_on_write(U &&x, disable_copy< U >=nullptr)
Constructs a new instance by forwarding arguments to the wrapped value constructor.
Definition copy_on_write.hpp:181
auto operator=(const copy_on_write &x) noexcept -> copy_on_write &
Copy assignment operator that shares the underlying data with the source object.
Definition copy_on_write.hpp:225
~copy_on_write()
Destructor.
Definition copy_on_write.hpp:211
copy_on_write() noexcept(std::is_nothrow_constructible_v< T >)
Default constructs the wrapped value.
Definition copy_on_write.hpp:170
auto operator=(U &&x) -> disable_copy_assign< U >
Assigns a new value to the wrapped object, optimizing for in-place assignment when unique.
Definition copy_on_write.hpp:245
copy_on_write(const copy_on_write &x) noexcept
Copy constructor that shares the underlying data with the source object.
Definition copy_on_write.hpp:194
copy_on_write(copy_on_write &&x) noexcept
Move constructor that takes ownership of the source object's data.
Definition copy_on_write.hpp:204
T element_type
The type of value stored.
Definition copy_on_write.hpp:162
T value_type
Definition copy_on_write.hpp:157
friend void swap(copy_on_write &x, copy_on_write &y) noexcept
Efficiently swaps the contents of two copy_on_write objects.
Definition copy_on_write.hpp:357
friend auto operator<(const element_type &x, const copy_on_write &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:373
friend auto operator!=(const element_type &x, const copy_on_write &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:433
friend auto operator<(const copy_on_write &x, const copy_on_write &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:365
friend auto operator>=(const copy_on_write &x, const copy_on_write &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:401
friend auto operator<=(const element_type &x, const copy_on_write &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:397
friend auto operator!=(const copy_on_write &x, const element_type &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:429
friend auto operator>=(const element_type &x, const copy_on_write &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:409
friend auto operator==(const copy_on_write &x, const copy_on_write &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:413
friend auto operator<(const copy_on_write &x, const element_type &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:369
friend auto operator>=(const copy_on_write &x, const element_type &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:405
friend auto operator<=(const copy_on_write &x, const element_type &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:393
friend auto operator>(const copy_on_write &x, const copy_on_write &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:377
friend auto operator>(const element_type &x, const copy_on_write &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:385
friend auto operator<=(const copy_on_write &x, const copy_on_write &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:389
friend auto operator!=(const copy_on_write &x, const copy_on_write &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:425
friend auto operator==(const copy_on_write &x, const element_type &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:417
friend auto operator==(const element_type &x, const copy_on_write &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:421
friend auto operator>(const copy_on_write &x, const element_type &y) noexcept -> bool
Comparisons can be done with the underlying value or the copy_on_write object.
Definition copy_on_write.hpp:381
auto write(Transform transform, Inplace inplace) -> element_type &
If the object is not unique, the transform is applied to the underlying value to copy it and a refere...
Definition copy_on_write.hpp:283
auto operator*() const noexcept -> const element_type &
Dereference operator that returns a const reference to the underlying value.
Definition copy_on_write.hpp:315
auto identity(const copy_on_write &x) const noexcept -> bool
Returns true if this object and the given object share the same underlying data.
Definition copy_on_write.hpp:342
auto read() const noexcept -> const element_type &
Returns a const reference to the underlying value for read-only access.
Definition copy_on_write.hpp:301
auto unique_instance() const noexcept -> bool
Definition copy_on_write.hpp:337
auto operator->() const noexcept -> const element_type *
Arrow operator that returns a const pointer to the underlying value.
Definition copy_on_write.hpp:320
auto unique() const noexcept -> bool
Returns true if this is the only reference to the underlying object.
Definition copy_on_write.hpp:327
auto write() -> element_type &
Obtains a non-const reference to the underlying value.
Definition copy_on_write.hpp:263
Definition copy_on_write.hpp:111