[/
 / Copyright (c) 2013 Vicente J. Botet Escriba
 /
 / 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)
 /]

[section:synchronized_value_ref Reference ]


  #include <boost/thread/synchronized_value.hpp>
  namespace boost 
  {

    template<typename T, typename Lockable = mutex>
    class synchronized_value;

    // Specialized swap algorithm
    template <typename T, typename L>
    void swap(synchronized_value<T,L> & lhs, synchronized_value<T,L> & rhs);
    template <typename T, typename L>
    void swap(synchronized_value<T,L> & lhs, T & rhs);
    template <typename T, typename L>
    void swap(T & lhs, synchronized_value<T,L> & rhs);

    // Hash support
    template<typename T, typename L>
    struct hash<synchronized_value<T,L> >;

    // Comparison
    template <typename T, typename L>
    bool operator==(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
    template <typename T, typename L>
    bool operator!=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
    template <typename T, typename L>
    bool operator<(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
    template <typename T, typename L>
    bool operator<=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
    template <typename T, typename L>
    bool operator>(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
    template <typename T, typename L>
    bool operator>=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)

    // Comparison with T
    template <typename T, typename L>
    bool operator==(T const& lhs, synchronized_value<T,L> const&rhs);
    template <typename T, typename L>
    bool operator!=(T const& lhs, synchronized_value<T,L> const&rhs);
    template <typename T, typename L>
    bool operator<(T const& lhs, synchronized_value<T,L> const&rhs);
    template <typename T, typename L>
    bool operator<=(T const& lhs, synchronized_value<T,L> const&rhs);
    template <typename T, typename L>
    bool operator>(T const& lhs, synchronized_value<T,L> const&rhs);
    template <typename T, typename L>
    bool operator>=(T const& lhs, synchronized_value<T,L> const&rhs);

    template <typename T, typename L>
    bool operator==(synchronized_value<T,L> const& lhs, T const& rhs);
    template <typename T, typename L>
    bool operator!=(synchronized_value<T,L> const& lhs, T const& rhs);
    template <typename T, typename L>
    bool operator<(synchronized_value<T,L> const& lhs, T const& rhs);
    template <typename T, typename L>
    bool operator<=(synchronized_value<T,L> const& lhs, T const& rhs);
    template <typename T, typename L>
    bool operator>(synchronized_value<T,L> const& lhs, T const& rhs);
    template <typename T, typename L>
    bool operator>=(synchronized_value<T,L> const& lhs, T const& rhs);

  #if ! defined(BOOST_THREAD_NO_SYNCHRONIZE)
    template <typename ...SV>
    std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv);
  #endif
  }

[section:synchronized_value Class `synchronized_value`]

  #include <boost/thread/synchronized_value.hpp>

  namespace boost 
  {

    template<typename T, typename Lockable = mutex>
    class synchronized_value
    {
    public:
      typedef T value_type;
      typedef Lockable mutex_type;

      synchronized_value() noexcept(is_nothrow_default_constructible<T>::value);
      synchronized_value(T const& other) noexcept(is_nothrow_copy_constructible<T>::value);
      synchronized_value(T&& other) noexcept(is_nothrow_move_constructible<T>::value);
      synchronized_value(synchronized_value const& rhs);
      synchronized_value(synchronized_value&& other);

      // mutation
      synchronized_value& operator=(synchronized_value const& rhs);
      synchronized_value& operator=(value_type const& val);
      void swap(synchronized_value & rhs);
      void swap(value_type & rhs);

      //observers
      T get() const;
    #if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
      explicit operator T() const;
    #endif

      strict_lock_ptr<T,Lockable> operator->();
      const_strict_lock_ptr<T,Lockable> operator->() const;
      strict_lock_ptr<T,Lockable> synchronize();
      const_strict_lock_ptr<T,Lockable> synchronize() const;

      deref_value operator*();;
      const_deref_value operator*() const;

    private:
      T value_; // for exposition only
      mutable mutex_type mtx_;  // for exposition only
    };
  }

[variablelist

[[Requires:] [`Lockable` is `Lockable`.]]

]


[section:constructor `synchronized_value()`]

      synchronized_value() noexcept(is_nothrow_default_constructible<T>::value);

[variablelist

[[Requires:] [`T` is `DefaultConstructible`.]]
[[Effects:] [Default constructs the cloaked value_type]]

[[Throws:] [Any exception thrown by `value_type()`.]]

]

[endsect]


[section:constructor_vt `synchronized_value(T const&)`]

      synchronized_value(T const& other) noexcept(is_nothrow_copy_constructible<T>::value);

[variablelist

[[Requires:] [`T` is `CopyConstructible`.]]
[[Effects:] [Copy constructs the cloaked value_type using the parameter `other`]]

[[Throws:] [Any exception thrown by `value_type(other)`.]]

]

[endsect]

[section:copy_cons `synchronized_value(synchronized_value const&)`]

      synchronized_value(synchronized_value const& rhs);

[variablelist

[[Requires:] [`T` is `DefaultConstructible` and `Assignable`.]]
[[Effects:] [Assigns the value on a scope protected by the mutex of the rhs. The mutex is not copied.]]

[[Throws:] [Any exception thrown by `value_type()` or `value_type& operator=(value_type&)` or `mtx_.lock()`.]]

]

[endsect]

[section:move_vt `synchronized_value(T&&)`]

      synchronized_value(T&& other) noexcept(is_nothrow_move_constructible<T>::value);

[variablelist

[[Requires:] [`T` is `MoveConstructible `.]]
[[Effects:] [Move constructs the cloaked value_type]]

[[Throws:] [Any exception thrown by `value_type(value_type&&)`.]]

]

[endsect]

[section:move `synchronized_value(synchronized_value&&)`]

      synchronized_value(synchronized_value&& other);

[variablelist

[[Requires:] [`T` is `MoveConstructible `.]]
[[Effects:] [Move constructs the cloaked value_type]]

[[Throws:] [Any exception thrown by `value_type(value_type&&)` or `mtx_.lock()`.]]

]

[endsect]

[section:assign `operator=(synchronized_value const&)`]

      synchronized_value& operator=(synchronized_value const& rhs);

[variablelist

[[Requires:] [`T` is `Assignable`.]]
[[Effects:] [Copies the underlying value on a scope protected by the two mutexes. The mutex is not copied. The locks are acquired avoiding deadlock. For example, there is no problem if one thread assigns `a = b` and the other assigns `b = a`.]]
[[Return:] [`*this`]]

[[Throws:] [Any exception thrown by `value_type& operator(value_type const&)` or `mtx_.lock()`.]]

]

[endsect]
[section:assign_vt `operator=(T const&)`]

      synchronized_value& operator=(value_type const& val);

[variablelist

[[Requires:] [`T` is `Assignable`.]]
[[Effects:] [Copies the value on a scope protected by the mutex.]]
[[Return:] [`*this`]]

[[Throws:] [Any exception thrown by `value_type& operator(value_type const&)` or `mtx_.lock()`.]]

]

[endsect]

[section:get `get() const`]

      T get() const;

[variablelist

[[Requires:] [`T` is `CopyConstructible`.]]
[[Return:] [`A copy of the protected value obtained on a scope protected by the mutex.`]]

[[Throws:] [Any exception thrown by `value_type(value_type const&)` or `mtx_.lock()`.]]

]

[endsect]


[section:T `operator T() const`]

    #if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
      explicit operator T() const;
    #endif

[variablelist

[[Requires:] [`T` is `CopyConstructible`.]]
[[Return:] [`A copy of the protected value obtained on a scope protected by the mutex.`]]

[[Throws:] [Any exception thrown by `value_type(value_type const&)` or `mtx_.lock()`.]]

]

[endsect]

[section:swap `swap(synchronized_value&)`]

      void swap(synchronized_value & rhs);

[variablelist

[[Requires:] [`T` is `Assignable`.]]
[[Effects:] [Swaps the data on a scope protected by both mutex. Both mutex are acquired to avoid dead-lock. The mutexes are not swapped.]]

[[Throws:] [Any exception thrown by `swap(value_, rhs.value)` or `mtx_.lock()` or `rhs_.mtx_.lock()`.]]

]

[endsect]

[section:swap_vt `swap(synchronized_value&)`]

      void swap(value_type & rhs);

[variablelist

[[Requires:] [`T` is `Swapable`.]]
[[Effects:] [Swaps the data on a scope protected by both mutex. Both mutex are acquired to avoid dead-lock. The mutexes are not swapped.]]

[[Throws:] [Any exception thrown by `swap(value_, rhs)` or `mtx_.lock()`.]]

]

[endsect]
[section:indir `operator->()`]

      strict_lock_ptr<T,Lockable> operator->();


Essentially calling a method `obj->foo(x, y, z)` calls the method `foo(x, y, z)` inside a critical section as long-lived as the call itself.

[variablelist

[[Return:] [`A strict_lock_ptr<>.`]]

[[Throws:] [Nothing.]]

]

[endsect]
[section:indir_const `operator->() const`]

      const_strict_lock_ptr<T,Lockable> operator->() const;


If the `synchronized_value` object involved is const-qualified, then you'll only be able to call const methods
through `operator->`. So, for example, `vec->push_back("xyz")` won't work if `vec` were const-qualified.
The locking mechanism capitalizes on the assumption that const methods don't modify their underlying data.

[variablelist

[[Return:] [`A const_strict_lock_ptr <>.`]]

[[Throws:] [Nothing.]]

]

[endsect]
[section:synchronize `synchronize()`]

    strict_lock_ptr<T,Lockable> synchronize();

The synchronize() factory make easier to lock on a scope. As discussed, `operator->` can only lock over the duration of a call, so it is insufficient for complex operations. With `synchronize()` you get to lock the object in a scoped and to directly access the object inside that scope.

[*Example:]

  void fun(synchronized_value<vector<int>> & vec) {
    auto vec2=vec.synchronize();
    vec2.push_back(42);
    assert(vec2.back() == 42);
  }

[variablelist

[[Return:] [`A strict_lock_ptr <>.`]]

[[Throws:] [Nothing.]]

]

[endsect]
[section:synchronize_const `synchronize() const`]

    const_strict_lock_ptr<T,Lockable> synchronize() const;

[variablelist

[[Return:] [`A const_strict_lock_ptr <>.`]]

[[Throws:] [Nothing.]]

]

[endsect]

[section:deref `operator*()`]

      deref_value operator*();;

[variablelist

[[Return:] [`A an instance of a class that locks the mutex on construction and unlocks it on destruction and provides implicit conversion to a reference to the protected value.`]]

[[Throws:] [Nothing.]]

]

[endsect]
[section:deref_const `operator*() const`]

      const_deref_value operator*() const;


[variablelist

[[Return:] [`A an instance of a class that locks the mutex on construction and unlocks it on destruction and provides implicit conversion to a constant reference to the protected value.`]]

[[Throws:] [Nothing.]]

]

[endsect]




[endsect]
[section:synchronize Non-Member Function `synchronize`]

  #include <boost/thread/synchronized_value.hpp>
  namespace boost 
  {
  #if ! defined(BOOST_THREAD_NO_SYNCHRONIZE)
    template <typename ...SV>
    std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv);
  #endif
  }

[endsect]
[endsect]

