SHARE
TWEET

Untitled

a guest Jul 21st, 2019 71 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #pragma once
  2.  
  3. #include <boost/optional.hpp>
  4.  
  5. namespace util {
  6.  
  7. namespace shared_value_detail {
  8.     using boost::optional;
  9.  
  10.     // Some values that we'd like to put into shared_value don't have the move
  11.     // assign operator. As long as they have the move constructor we can still
  12.     // use them.
  13.     template<typename T, bool has_move_assign_op> struct assign;
  14.  
  15.     template<typename T>
  16.     struct assign<optional<T>, true> {
  17.         static void move(optional<T>& dst, optional<T>& src) {
  18.             dst = std::move(src);
  19.         }
  20.     };
  21.  
  22.     template<typename T>
  23.     struct assign<optional<T>, false> {
  24.         static void move(optional<T>& dst, optional<T>& src) {
  25.             // Destroying should be cheap because we always destroy
  26.             // non initialized optional<T>.
  27.             assert(dst == boost::none);
  28.             dst.~optional<T>();
  29.             new (&dst) optional<T>(std::move(src));
  30.         }
  31.     };
  32. };
  33.  
  34. template<typename T>
  35. class shared_value {
  36. public:
  37.     using value_type = std::decay_t<T>;
  38.  
  39.     shared_value() = default;
  40.  
  41.     shared_value(const shared_value&);
  42.     shared_value& operator=(const shared_value&);
  43.  
  44.     template<typename K> shared_value(K);
  45.  
  46.     value_type&       operator*()        { return *value(); }
  47.     const value_type& operator*() const  { return *value(); }
  48.  
  49.     value_type*       operator->()       { return value(); }
  50.     const value_type* operator->() const { return value(); }
  51.  
  52.     ~shared_value();
  53.  
  54. private:
  55.     void remove_self();
  56.     void append_self_to_end(const shared_value&);
  57.     value_type* value();
  58.  
  59. private:
  60.     shared_value* _prev = nullptr;
  61.     shared_value* _next = nullptr;
  62.  
  63.     // We use optional to handle the case where value_type
  64.     // doesn't have the default constructor.
  65.     boost::optional<value_type> _value;
  66. };
  67.  
  68. template<typename T>
  69. inline
  70. shared_value<T>::shared_value(const shared_value& other)
  71. {
  72.     append_self_to_end(other);
  73. }
  74.  
  75. template<typename T>
  76. template<typename K>
  77. inline
  78. shared_value<T>::shared_value(K value)
  79.     : _value(std::move(value))
  80. {
  81. }
  82.  
  83. template<typename T>
  84. inline
  85. shared_value<T>& shared_value<T>::operator=(const shared_value& other)
  86. {
  87.     // Do nothing if this and other already share the same value.
  88.     if (value() == other.value()) return *this;
  89.  
  90.     remove_self();
  91.     append_self_to_end(other);
  92.  
  93.     return *this;
  94. }
  95.  
  96. template<typename T>
  97. inline
  98. void shared_value<T>::append_self_to_end(const shared_value& other)
  99. {
  100.     shared_value* last = const_cast<shared_value*>(&other);
  101.     while (last->_next) { last = last->_next; }
  102.     last->_next = this;
  103.     _prev = last;
  104.     assert(_next = nullptr);
  105. }
  106.  
  107. template<typename T>
  108. inline
  109. void shared_value<T>::remove_self()
  110. {
  111.     if (_prev) {
  112.         // We're not the first, so we don't have the value
  113.         assert(!_value);
  114.         _prev->_next = _next;
  115.         if (_next) { _next->_prev = _prev; _next = nullptr; }
  116.         _prev = nullptr;
  117.         return;
  118.     }
  119.  
  120.     if (_next == nullptr) {
  121.         // We're the value owners, but we're not sharing it with anyone else.
  122.         // Thus destroy the value and exit.
  123.         _value = boost::none;
  124.         return;
  125.     }
  126.  
  127.     // We're the owners of the value and we're sharing it with others. Move the
  128.     // value to the next one in line.
  129.     shared_value_detail::assign< boost::optional<value_type>
  130.                                , std::is_move_assignable<value_type>::value
  131.                                >::move(_next->_value, _value);
  132.  
  133.     _value = boost::none;
  134.     _next->_prev = nullptr;
  135.     _next = nullptr;
  136. }
  137.  
  138. template<typename T>
  139. inline
  140. typename shared_value<T>::value_type* shared_value<T>::value()
  141. {
  142.     shared_value* first = this;
  143.     while (first->_prev) { first = first->_prev; }
  144.     if (!first->_value) return nullptr;
  145.     return &*first->_value;
  146. }
  147.  
  148. template<typename T>
  149. inline
  150. shared_value<T>::~shared_value()
  151. {
  152.     remove_self();
  153. }
  154.  
  155. } // namespace
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top