toctave

t(iny)octave
git clone https://0xff.ir/g/toctave.git
Log | Files | Refs | README

copy_on_write.hpp (6595B)


      1 /*
      2     Copyright 2013 Adobe
      3     Distributed under the Boost Software License, Version 1.0.
      4     (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
      5 */
      6 /**************************************************************************************************/
      7 
      8 #ifndef STLAB_COPY_ON_WRITE_HPP
      9 #define STLAB_COPY_ON_WRITE_HPP
     10 
     11 /**************************************************************************************************/
     12 
     13 #include <atomic>
     14 #include <cassert>
     15 #include <cstddef>
     16 #include <utility>
     17 
     18 /**************************************************************************************************/
     19 
     20 namespace stlab {
     21 
     22 /**************************************************************************************************/
     23 
     24 template <typename T> // T models Regular
     25 class copy_on_write {
     26     struct model {
     27         std::atomic<std::size_t> _count{1};
     28 
     29         model() = default;
     30 
     31         template <class... Args>
     32         explicit model(Args&&... args) : _value(std::forward<Args>(args)...) {}
     33 
     34         T _value;
     35     };
     36 
     37     model* _self;
     38 
     39     template <class U>
     40     using disable_copy = std::enable_if_t<!std::is_same<std::decay_t<U>, copy_on_write>::value>*;
     41 
     42     template <typename U>
     43     using disable_copy_assign =
     44         std::enable_if_t<!std::is_same<std::decay_t<U>, copy_on_write>::value, copy_on_write&>;
     45 
     46 public:
     47     /* [[deprecated]] */ using value_type = T;
     48 
     49     using element_type = T;
     50 
     51     copy_on_write() {
     52         static model default_s;
     53         _self = &default_s;
     54 
     55         // coverity[useless_call]
     56         ++_self->_count;
     57     }
     58 
     59     template <class U>
     60     copy_on_write(U&& x, disable_copy<U> = nullptr) : _self(new model(std::forward<U>(x))) {}
     61 
     62     template <class U, class V, class... Args>
     63     copy_on_write(U&& x, V&& y, Args&&... args)
     64         : _self(new model(std::forward<U>(x), std::forward<V>(y), std::forward<Args>(args)...)) {}
     65 
     66     copy_on_write(const copy_on_write& x) noexcept : _self(x._self) {
     67         assert(_self && "FATAL (sparent) : using a moved copy_on_write object");
     68 
     69         // coverity[useless_call]
     70         ++_self->_count;
     71     }
     72     copy_on_write(copy_on_write&& x) noexcept : _self(x._self) {
     73         assert(_self && "WARNING (sparent) : using a moved copy_on_write object");
     74         x._self = nullptr;
     75     }
     76 
     77     ~copy_on_write() {
     78         if (_self && (--_self->_count == 0)) delete _self;
     79     }
     80 
     81     auto operator=(const copy_on_write& x) noexcept -> copy_on_write& {
     82         return *this = copy_on_write(x);
     83     }
     84 
     85     auto operator=(copy_on_write&& x) noexcept -> copy_on_write& {
     86         auto tmp = std::move(x);
     87         swap(*this, tmp);
     88         return *this;
     89     }
     90 
     91     template <class U>
     92     auto operator=(U&& x) -> disable_copy_assign<U> {
     93         if (_self && unique()) {
     94             _self->_value = std::forward<U>(x);
     95             return *this;
     96         }
     97 
     98         return *this = copy_on_write(std::forward<U>(x));
     99     }
    100 
    101     auto write() -> element_type& {
    102         if (!unique()) *this = copy_on_write(read());
    103 
    104         return _self->_value;
    105     }
    106 
    107     auto read() const noexcept -> const element_type& {
    108         assert(_self && "FATAL (sparent) : using a moved copy_on_write object");
    109 
    110         return _self->_value;
    111     }
    112 
    113     operator const element_type&() const noexcept { return read(); }
    114 
    115     auto operator*() const noexcept -> const element_type& { return read(); }
    116 
    117     auto operator-> () const noexcept -> const element_type* { return &read(); }
    118 
    119     bool unique() const noexcept {
    120         assert(_self && "FATAL (sparent) : using a moved copy_on_write object");
    121 
    122         return _self->_count == 1;
    123     }
    124     [[deprecated]] bool unique_instance() const noexcept { return unique(); }
    125 
    126     bool identity(const copy_on_write& x) const noexcept {
    127         assert((_self && x._self) && "FATAL (sparent) : using a moved copy_on_write object");
    128 
    129         return _self == x._self;
    130     }
    131 
    132     friend inline void swap(copy_on_write& x, copy_on_write& y) noexcept {
    133         std::swap(x._self, y._self);
    134     }
    135 
    136     friend inline bool operator<(const copy_on_write& x, const copy_on_write& y) noexcept {
    137         return !x.identity(y) && (*x < *y);
    138     }
    139 
    140     friend inline bool operator<(const copy_on_write& x, const element_type& y) noexcept {
    141         return *x < y;
    142     }
    143 
    144     friend inline bool operator<(const element_type& x, const copy_on_write& y) noexcept {
    145         return x < *y;
    146     }
    147 
    148     friend inline bool operator>(const copy_on_write& x, const copy_on_write& y) noexcept {
    149         return y < x;
    150     }
    151 
    152     friend inline bool operator>(const copy_on_write& x, const element_type& y) noexcept {
    153         return y < x;
    154     }
    155 
    156     friend inline bool operator>(const element_type& x, const copy_on_write& y) noexcept {
    157         return y < x;
    158     }
    159 
    160     friend inline bool operator<=(const copy_on_write& x, const copy_on_write& y) noexcept {
    161         return !(y < x);
    162     }
    163 
    164     friend inline bool operator<=(const copy_on_write& x, const element_type& y) noexcept {
    165         return !(y < x);
    166     }
    167 
    168     friend inline bool operator<=(const element_type& x, const copy_on_write& y) noexcept {
    169         return !(y < x);
    170     }
    171 
    172     friend inline bool operator>=(const copy_on_write& x, const copy_on_write& y) noexcept {
    173         return !(x < y);
    174     }
    175 
    176     friend inline bool operator>=(const copy_on_write& x, const element_type& y) noexcept {
    177         return !(x < y);
    178     }
    179 
    180     friend inline bool operator>=(const element_type& x, const copy_on_write& y) noexcept {
    181         return !(x < y);
    182     }
    183 
    184     friend inline bool operator==(const copy_on_write& x, const copy_on_write& y) noexcept {
    185         return x.identity(y) || (*x == *y);
    186     }
    187 
    188     friend inline bool operator==(const copy_on_write& x, const element_type& y) noexcept {
    189         return *x == y;
    190     }
    191 
    192     friend inline bool operator==(const element_type& x, const copy_on_write& y) noexcept {
    193         return x == *y;
    194     }
    195 
    196     friend inline bool operator!=(const copy_on_write& x, const copy_on_write& y) noexcept {
    197         return !(x == y);
    198     }
    199 
    200     friend inline bool operator!=(const copy_on_write& x, const element_type& y) noexcept {
    201         return !(x == y);
    202     }
    203 
    204     friend inline bool operator!=(const element_type& x, const copy_on_write& y) noexcept {
    205         return !(x == y);
    206     }
    207 };
    208 /**************************************************************************************************/
    209 
    210 } // namespace stlab
    211 
    212 /**************************************************************************************************/
    213 
    214 #endif
    215 
    216 /**************************************************************************************************/