Created
January 22, 2019 11:38
-
-
Save facontidavide/f9ea9f859fd3c29880df3253bbb4c712 to your computer and use it in GitHub Desktop.
Copy on Write utility (from stlab)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Copyright 2013 Adobe | |
Distributed under the Boost Software License, Version 1.0. | |
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
*/ | |
/**************************************************************************************************/ | |
#ifndef STLAB_COPY_ON_WRITE_HPP | |
#define STLAB_COPY_ON_WRITE_HPP | |
/**************************************************************************************************/ | |
#include <atomic> | |
#include <cassert> | |
#include <cstddef> | |
#include <utility> | |
/**************************************************************************************************/ | |
namespace stlab { | |
/**************************************************************************************************/ | |
template <typename T> // T models Regular | |
class copy_on_write { | |
struct model { | |
std::atomic<std::size_t> _count{1}; | |
model() = default; | |
template <class... Args> | |
explicit model(Args&&... args) : _value(std::forward<Args>(args)...) {} | |
T _value; | |
}; | |
model* _self; | |
template <class U> | |
using disable_copy = std::enable_if_t<!std::is_same<std::decay_t<U>, copy_on_write>::value>*; | |
template <typename U> | |
using disable_copy_assign = | |
std::enable_if_t<!std::is_same<std::decay_t<U>, copy_on_write>::value, copy_on_write&>; | |
public: | |
/* [[deprecated]] */ using value_type = T; | |
using element_type = T; | |
copy_on_write() { | |
static model default_s; | |
_self = &default_s; | |
// coverity[useless_call] | |
++_self->_count; | |
} | |
template <class U> | |
copy_on_write(U&& x, disable_copy<U> = nullptr) : _self(new model(std::forward<U>(x))) {} | |
template <class U, class V, class... Args> | |
copy_on_write(U&& x, V&& y, Args&&... args) | |
: _self(new model(std::forward<U>(x), std::forward<V>(y), std::forward<Args>(args)...)) {} | |
copy_on_write(const copy_on_write& x) noexcept : _self(x._self) { | |
assert(_self && "FATAL (sparent) : using a moved copy_on_write object"); | |
// coverity[useless_call] | |
++_self->_count; | |
} | |
copy_on_write(copy_on_write&& x) noexcept : _self(x._self) { | |
assert(_self && "WARNING (sparent) : using a moved copy_on_write object"); | |
x._self = nullptr; | |
} | |
~copy_on_write() { | |
if (_self && (--_self->_count == 0)) delete _self; | |
} | |
auto operator=(const copy_on_write& x) noexcept -> copy_on_write& { | |
return *this = copy_on_write(x); | |
} | |
auto operator=(copy_on_write&& x) noexcept -> copy_on_write& { | |
auto tmp = std::move(x); | |
swap(*this, tmp); | |
return *this; | |
} | |
template <class U> | |
auto operator=(U&& x) -> disable_copy_assign<U> { | |
if (_self && unique()) { | |
_self->_value = std::forward<U>(x); | |
return *this; | |
} | |
return *this = copy_on_write(std::forward<U>(x)); | |
} | |
auto write() -> element_type& { | |
if (!unique()) *this = copy_on_write(read()); | |
return _self->_value; | |
} | |
auto read() const noexcept -> const element_type& { | |
assert(_self && "FATAL (sparent) : using a moved copy_on_write object"); | |
return _self->_value; | |
} | |
operator const element_type&() const noexcept { return read(); } | |
auto operator*() const noexcept -> const element_type& { return read(); } | |
auto operator-> () const noexcept -> const element_type* { return &read(); } | |
bool unique() const noexcept { | |
assert(_self && "FATAL (sparent) : using a moved copy_on_write object"); | |
return _self->_count == 1; | |
} | |
[[deprecated]] bool unique_instance() const noexcept { return unique(); } | |
bool identity(const copy_on_write& x) const noexcept { | |
assert((_self && x._self) && "FATAL (sparent) : using a moved copy_on_write object"); | |
return _self == x._self; | |
} | |
friend inline void swap(copy_on_write& x, copy_on_write& y) noexcept { | |
std::swap(x._self, y._self); | |
} | |
friend inline bool operator<(const copy_on_write& x, const copy_on_write& y) noexcept { | |
return !x.identity(y) && (*x < *y); | |
} | |
friend inline bool operator<(const copy_on_write& x, const element_type& y) noexcept { | |
return *x < y; | |
} | |
friend inline bool operator<(const element_type& x, const copy_on_write& y) noexcept { | |
return x < *y; | |
} | |
friend inline bool operator>(const copy_on_write& x, const copy_on_write& y) noexcept { | |
return y < x; | |
} | |
friend inline bool operator>(const copy_on_write& x, const element_type& y) noexcept { | |
return y < x; | |
} | |
friend inline bool operator>(const element_type& x, const copy_on_write& y) noexcept { | |
return y < x; | |
} | |
friend inline bool operator<=(const copy_on_write& x, const copy_on_write& y) noexcept { | |
return !(y < x); | |
} | |
friend inline bool operator<=(const copy_on_write& x, const element_type& y) noexcept { | |
return !(y < x); | |
} | |
friend inline bool operator<=(const element_type& x, const copy_on_write& y) noexcept { | |
return !(y < x); | |
} | |
friend inline bool operator>=(const copy_on_write& x, const copy_on_write& y) noexcept { | |
return !(x < y); | |
} | |
friend inline bool operator>=(const copy_on_write& x, const element_type& y) noexcept { | |
return !(x < y); | |
} | |
friend inline bool operator>=(const element_type& x, const copy_on_write& y) noexcept { | |
return !(x < y); | |
} | |
friend inline bool operator==(const copy_on_write& x, const copy_on_write& y) noexcept { | |
return x.identity(y) || (*x == *y); | |
} | |
friend inline bool operator==(const copy_on_write& x, const element_type& y) noexcept { | |
return *x == y; | |
} | |
friend inline bool operator==(const element_type& x, const copy_on_write& y) noexcept { | |
return x == *y; | |
} | |
friend inline bool operator!=(const copy_on_write& x, const copy_on_write& y) noexcept { | |
return !(x == y); | |
} | |
friend inline bool operator!=(const copy_on_write& x, const element_type& y) noexcept { | |
return !(x == y); | |
} | |
friend inline bool operator!=(const element_type& x, const copy_on_write& y) noexcept { | |
return !(x == y); | |
} | |
}; | |
/**************************************************************************************************/ | |
} // namespace stlab | |
/**************************************************************************************************/ | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment