Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #pragma once
- #include <boost/optional.hpp>
- namespace util {
- namespace shared_value_detail {
- using boost::optional;
- // Some values that we'd like to put into shared_value don't have the move
- // assign operator. As long as they have the move constructor we can still
- // use them.
- template<typename T, bool has_move_assign_op> struct assign;
- template<typename T>
- struct assign<optional<T>, true> {
- static void move(optional<T>& dst, optional<T>& src) {
- dst = std::move(src);
- }
- };
- template<typename T>
- struct assign<optional<T>, false> {
- static void move(optional<T>& dst, optional<T>& src) {
- // Destroying should be cheap because we always destroy
- // non initialized optional<T>.
- assert(dst == boost::none);
- dst.~optional<T>();
- new (&dst) optional<T>(std::move(src));
- }
- };
- };
- template<typename T>
- class shared_value {
- public:
- using value_type = std::decay_t<T>;
- shared_value() = default;
- shared_value(const shared_value&);
- shared_value& operator=(const shared_value&);
- template<typename K> shared_value(K);
- value_type& operator*() { return *value(); }
- const value_type& operator*() const { return *value(); }
- value_type* operator->() { return value(); }
- const value_type* operator->() const { return value(); }
- ~shared_value();
- private:
- void remove_self();
- void append_self_to_end(const shared_value&);
- value_type* value();
- private:
- shared_value* _prev = nullptr;
- shared_value* _next = nullptr;
- // We use optional to handle the case where value_type
- // doesn't have the default constructor.
- boost::optional<value_type> _value;
- };
- template<typename T>
- inline
- shared_value<T>::shared_value(const shared_value& other)
- {
- append_self_to_end(other);
- }
- template<typename T>
- template<typename K>
- inline
- shared_value<T>::shared_value(K value)
- : _value(std::move(value))
- {
- }
- template<typename T>
- inline
- shared_value<T>& shared_value<T>::operator=(const shared_value& other)
- {
- // Do nothing if this and other already share the same value.
- if (value() == other.value()) return *this;
- remove_self();
- append_self_to_end(other);
- return this;
- }
- template<typename T>
- inline
- void shared_value<T>::append_self_to_end(const shared_value& other)
- {
- shared_value* last = const_cast<shared_value*>(&other);
- while (last->_next) { last = last->_next; }
- last->_next = this;
- _prev = last;
- assert(_next = nullptr);
- }
- template<typename T>
- inline
- void shared_value<T>::remove_self()
- {
- if (_prev) {
- // We're not the first, so we don't have the value
- assert(!_value);
- _prev->_next = _next;
- if (_next) { _next->_prev = _prev; _next = nullptr; }
- _prev = nullptr;
- return;
- }
- if (_next == nullptr) {
- // We're the value owners, but we're not sharing it with anyone else.
- // Thus destroy the value and exit.
- _value = boost::none;
- return;
- }
- // We're the owners of the value and we're sharing it with others. Move the
- // value to the next one in line.
- shared_value_detail::assign< boost::optional<value_type>
- , std::is_move_assignable<value_type>::value
- >::move(_next->_value, _value);
- _value = boost::none;
- _next->_prev = nullptr;
- _next = nullptr;
- }
- template<typename T>
- inline
- typename shared_value<T>::value_type* shared_value<T>::value()
- {
- shared_value* first = this;
- while (first->_prev) { first = first->_prev; }
- if (!first->_value) return nullptr;
- return &*first->_value;
- }
- template<typename T>
- inline
- shared_value<T>::~shared_value()
- {
- remove_self();
- }
- } // namespace
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement