//  (C) Copyright 2008 Anthony Williams 
//
//  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 N2561_FUTURE_HPP
#define N2561_FUTURE_HPP
#include <stdexcept>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/exception_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/type_traits/is_fundamental.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/mpl/if.hpp>
#include <boost/config.hpp>
#include <algorithm>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <boost/scoped_array.hpp>
#include <boost/utility/enable_if.hpp>
#include <list>
#include <boost/next_prior.hpp>

namespace jss
{
    class future_uninitialized:
        public std::logic_error
    {
    public:
        future_uninitialized():
            std::logic_error("Future Uninitialized")
        {}
    };
    class broken_promise:
        public std::logic_error
    {
    public:
        broken_promise():
            std::logic_error("Broken promise")
        {}
    };
    class future_already_retrieved:
        public std::logic_error
    {
    public:
        future_already_retrieved():
            std::logic_error("Future already retrieved")
        {}
    };
    class promise_already_satisfied:
        public std::logic_error
    {
    public:
        promise_already_satisfied():
            std::logic_error("Promise already satisfied")
        {}
    };

    class task_already_started:
        public std::logic_error
    {
    public:
        task_already_started():
            std::logic_error("Task already started")
        {}
    };

    class task_moved:
        public std::logic_error
    {
    public:
        task_moved():
            std::logic_error("Task moved")
        {}
    };

    namespace future_state
    {
        enum state { uninitialized, waiting, ready, moved };
    }

    namespace detail
    {
        struct future_object_base
        {
            boost::exception_ptr exception;
            bool done;
            boost::mutex mutex;
            boost::condition_variable waiters;
            typedef std::list<boost::condition_variable_any*> waiter_list;
            waiter_list external_waiters;
            boost::function<void()> callback;

            future_object_base():
                done(false)
            {}
            virtual ~future_object_base()
            {}

            waiter_list::iterator register_external_waiter(boost::condition_variable_any& cv)
            {
                boost::unique_lock<boost::mutex> lock(mutex);
                do_callback(lock);
                return external_waiters.insert(external_waiters.end(),&cv);
            }
            
            void remove_external_waiter(waiter_list::iterator it)
            {
                boost::lock_guard<boost::mutex> lock(mutex);
                external_waiters.erase(it);
            }

            void mark_finished_internal()
            {
                done=true;
                waiters.notify_all();
                for(waiter_list::const_iterator it=external_waiters.begin(),
                        end=external_waiters.end();it!=end;++it)
                {
                    (*it)->notify_all();
                }
            }

            struct relocker
            {
                boost::unique_lock<boost::mutex>& lock;
                
                relocker(boost::unique_lock<boost::mutex>& lock_):
                    lock(lock_)
                {
                    lock.unlock();
                }
                ~relocker()
                {
                    lock.lock();
                }
            };

            void do_callback(boost::unique_lock<boost::mutex>& lock)
            {
                if(callback && !done)
                {
                    boost::function<void()> local_callback=callback;
                    relocker relock(lock);
                    local_callback();
                }
            }
            

            void wait(bool rethrow=true)
            {
                boost::unique_lock<boost::mutex> lock(mutex);
                do_callback(lock);
                while(!done)
                {
                    waiters.wait(lock);
                }
                if(rethrow && exception)
                {
                    boost::rethrow_exception(exception);
                }
            }

            bool timed_wait_until(boost::system_time const& target_time)
            {
                boost::unique_lock<boost::mutex> lock(mutex);
                do_callback(lock);
                while(!done)
                {
                    bool const success=waiters.timed_wait(lock,target_time);
                    if(!success && !done)
                    {
                        return false;
                    }
                }
                return true;
            }
            
            void mark_exceptional_finish_internal(boost::exception_ptr const& e)
            {
                exception=e;
                mark_finished_internal();
            }
            void mark_exceptional_finish()
            {
                boost::lock_guard<boost::mutex> lock(mutex);
                mark_exceptional_finish_internal(boost::current_exception());
            }

            bool has_value()
            {
                boost::lock_guard<boost::mutex> lock(mutex);
                return done && !exception;
            }
            bool has_exception()
            {
                boost::lock_guard<boost::mutex> lock(mutex);
                return done && exception;
            }

            template<typename F,typename U>
            void set_wait_callback(F f,U* u)
            {
                callback=boost::bind(f,boost::ref(*u));
            }
            
        private:
            future_object_base(future_object_base const&);
            future_object_base& operator=(future_object_base const&);
        };

        template<typename T>
        struct future_traits
        {
            typedef boost::scoped_ptr<T> storage_type;
#ifdef BOOST_HAS_RVALUE_REFS
            typedef T const& source_reference_type;
            struct dummy;
            typedef typename boost::mpl::if_<boost::is_fundamental<T>,dummy&,T&&>::type rvalue_source_type;
            typedef typename boost::mpl::if_<boost::is_fundamental<T>,T,T&&>::type move_dest_type;
#else
            typedef T& source_reference_type;
            typedef typename boost::mpl::if_<boost::is_convertible<T&,boost::detail::thread_move_t<T> >,boost::detail::thread_move_t<T>,T const&>::type rvalue_source_type;
            typedef typename boost::mpl::if_<boost::is_convertible<T&,boost::detail::thread_move_t<T> >,boost::detail::thread_move_t<T>,T>::type move_dest_type;
#endif

            static void init(storage_type& storage,source_reference_type t)
            {
                storage.reset(new T(t));
            }
            
            static void init(storage_type& storage,rvalue_source_type t)
            {
                storage.reset(new T(static_cast<rvalue_source_type>(t)));
            }

            static void cleanup(storage_type& storage)
            {
                storage.reset();
            }
        };
        
        template<typename T>
        struct future_traits<T&>
        {
            typedef T* storage_type;
            typedef T& source_reference_type;
            struct rvalue_source_type
            {};
            typedef T& move_dest_type;

            static void init(storage_type& storage,T& t)
            {
                storage=&t;
            }

            static void cleanup(storage_type& storage)
            {
                storage=0;
            }
        };

        template<>
        struct future_traits<void>
        {
            typedef bool storage_type;
            typedef void move_dest_type;

            static void init(storage_type& storage)
            {
                storage=true;
            }

            static void cleanup(storage_type& storage)
            {
                storage=false;
            }

        };

        template<typename T>
        struct future_object:
            detail::future_object_base
        {
            typedef typename future_traits<T>::storage_type storage_type;
            typedef typename future_traits<T>::source_reference_type source_reference_type;
            typedef typename future_traits<T>::rvalue_source_type rvalue_source_type;
            typedef typename future_traits<T>::move_dest_type move_dest_type;
            
            storage_type result;

            future_object():
                result(0)
            {}

            void mark_finished_with_result_internal(source_reference_type result_)
            {
                future_traits<T>::init(result,result_);
                mark_finished_internal();
            }
            void mark_finished_with_result_internal(rvalue_source_type result_)
            {
                future_traits<T>::init(result,static_cast<rvalue_source_type>(result_));
                mark_finished_internal();
            }

            void mark_finished_with_result(source_reference_type result_)
            {
                boost::lock_guard<boost::mutex> lock(mutex);
                mark_finished_with_result_internal(result_);
            }
            void mark_finished_with_result(rvalue_source_type result_)
            {
                boost::lock_guard<boost::mutex> lock(mutex);
                mark_finished_with_result_internal(result_);
            }

            move_dest_type get()
            {
                wait();
                return *result;
            }

            future_state::state get_state()
            {
                boost::lock_guard<boost::mutex> guard(mutex);
                if(!done)
                {
                    return future_state::waiting;
                }
                else
                {
                    return future_state::ready;
                }
            }

        private:
            future_object(future_object const&);
            future_object& operator=(future_object const&);
        };

        template<>
        struct future_object<void>:
            detail::future_object_base
        {
            future_object()
            {}

            void mark_finished_with_result_internal()
            {
                mark_finished_internal();
            }

            void mark_finished_with_result()
            {
                boost::lock_guard<boost::mutex> lock(mutex);
                mark_finished_with_result_internal();
            }

            void get()
            {
                wait();
            }
            
            future_state::state get_state()
            {
                boost::lock_guard<boost::mutex> guard(mutex);
                if(!done)
                {
                    return future_state::waiting;
                }
                else
                {
                    return future_state::ready;
                }
            }

        private:
            future_object(future_object const&);
            future_object& operator=(future_object const&);
        };

        class future_waiter
        {
            struct registered_waiter
            {
                boost::shared_ptr<detail::future_object_base> future;
                detail::future_object_base::waiter_list::iterator wait_iterator;
                unsigned index;

                registered_waiter(boost::shared_ptr<detail::future_object_base> const& future_,
                                  detail::future_object_base::waiter_list::iterator wait_iterator_,
                                  unsigned index_):
                    future(future_),wait_iterator(wait_iterator_),index(index_)
                {}

            };
            
            struct all_futures_lock
            {
                unsigned count;
                boost::scoped_array<boost::unique_lock<boost::mutex> > locks;
                
                all_futures_lock(std::vector<registered_waiter>& futures):
                    count(futures.size()),locks(new boost::unique_lock<boost::mutex>[count])
                {
                    for(unsigned i=0;i<count;++i)
                    {
                        locks[i]=boost::unique_lock<boost::mutex>(futures[i].future->mutex);
                    }
                }
                
                void lock()
                {
                    boost::lock(locks.get(),locks.get()+count);
                }
                
                void unlock()
                {
                    for(unsigned i=0;i<count;++i)
                    {
                        locks[i].unlock();
                    }
                }
            };
            
            boost::condition_variable_any cv;
            std::vector<registered_waiter> futures;
            unsigned future_count;
            
        public:
            future_waiter():
                future_count(0)
            {}
            
            template<typename F>
            void add(F& f)
            {
                if(f.future)
                {
                    futures.push_back(registered_waiter(f.future,f.future->register_external_waiter(cv),future_count));
                }
                ++future_count;
            }

            unsigned wait()
            {
                all_futures_lock lk(futures);
                for(;;)
                {
                    for(unsigned i=0;i<futures.size();++i)
                    {
                        if(futures[i].future->done)
                        {
                            return futures[i].index;
                        }
                    }
                    cv.wait(lk);
                }
            }
            
            ~future_waiter()
            {
                for(unsigned i=0;i<futures.size();++i)
                {
                    futures[i].future->remove_external_waiter(futures[i].wait_iterator);
                }
            }
            
        };
        
    }

    template <typename R>
    class unique_future;

    template <typename R>
    class shared_future;

    template<typename T>
    struct is_future_type
    {
        BOOST_STATIC_CONSTANT(bool, value=false);
    };
    
    template<typename T>
    struct is_future_type<unique_future<T> >
    {
        BOOST_STATIC_CONSTANT(bool, value=true);
    };
    
    template<typename T>
    struct is_future_type<shared_future<T> >
    {
        BOOST_STATIC_CONSTANT(bool, value=true);
    };

    template<typename Iterator>
    typename boost::disable_if<is_future_type<Iterator>,void>::type wait_for_all(Iterator begin,Iterator end)
    {
        for(Iterator current=begin;current!=end;++current)
        {
            current->wait();
        }
    }

    template<typename F1,typename F2>
    typename boost::enable_if<is_future_type<F1>,void>::type wait_for_all(F1& f1,F2& f2)
    {
        f1.wait();
        f2.wait();
    }

    template<typename F1,typename F2,typename F3>
    void wait_for_all(F1& f1,F2& f2,F3& f3)
    {
        f1.wait();
        f2.wait();
        f3.wait();
    }
    
    template<typename F1,typename F2,typename F3,typename F4>
    void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4)
    {
        f1.wait();
        f2.wait();
        f3.wait();
        f4.wait();
    }

    template<typename F1,typename F2,typename F3,typename F4,typename F5>
    void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5)
    {
        f1.wait();
        f2.wait();
        f3.wait();
        f4.wait();
        f5.wait();
    }

    template<typename Iterator>
    typename boost::disable_if<is_future_type<Iterator>,Iterator>::type wait_for_any(Iterator begin,Iterator end)
    {
        detail::future_waiter waiter;
        for(Iterator current=begin;current!=end;++current)
        {
            waiter.add(*current);
        }
        return boost::next(begin,waiter.wait());
    }

    template<typename F1,typename F2>
    typename boost::enable_if<is_future_type<F1>,unsigned>::type wait_for_any(F1& f1,F2& f2)
    {
        detail::future_waiter waiter;
        waiter.add(f1);
        waiter.add(f2);
        return waiter.wait();
    }

    template<typename F1,typename F2,typename F3>
    unsigned wait_for_any(F1& f1,F2& f2,F3& f3)
    {
        detail::future_waiter waiter;
        waiter.add(f1);
        waiter.add(f2);
        waiter.add(f3);
        return waiter.wait();
    }
    
    template<typename F1,typename F2,typename F3,typename F4>
    unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4)
    {
        detail::future_waiter waiter;
        waiter.add(f1);
        waiter.add(f2);
        waiter.add(f3);
        waiter.add(f4);
        return waiter.wait();
    }

    template<typename F1,typename F2,typename F3,typename F4,typename F5>
    unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5)
    {
        detail::future_waiter waiter;
        waiter.add(f1);
        waiter.add(f2);
        waiter.add(f3);
        waiter.add(f4);
        waiter.add(f5);
        return waiter.wait();
    }
    
    template <typename R>
    class promise;

    template <typename R>
    class packaged_task;

    template <typename R>
    class unique_future
    {
        unique_future(unique_future & rhs);// = delete;
        unique_future& operator=(unique_future& rhs);// = delete;

        typedef boost::shared_ptr<detail::future_object<R> > future_ptr;
        
        future_ptr future;

        friend class shared_future<R>;
        friend class promise<R>;
        friend class packaged_task<R>;
        friend class detail::future_waiter;

        typedef typename detail::future_traits<R>::move_dest_type move_dest_type;

        unique_future(future_ptr future_):
            future(future_)
        {}

    public:
        typedef future_state::state state;

        unique_future()
        {}
       
        ~unique_future()
        {}

#ifdef BOOST_HAS_RVALUE_REFS
        unique_future(unique_future && other)
        {
            future.swap(other.future);
        }
        unique_future& operator=(unique_future && other)
        {
            future=other.future;
            other.future.reset();
            return *this;
        }
#else
        unique_future(boost::detail::thread_move_t<unique_future> other):
            future(other->future)
        {
            other->future.reset();
        }

        unique_future& operator=(boost::detail::thread_move_t<unique_future> other)
        {
            future=other->future;
            other->future.reset();
            return *this;
        }

        operator boost::detail::thread_move_t<unique_future>()
        {
            return boost::detail::thread_move_t<unique_future>(*this);
        }
#endif

        void swap(unique_future& other)
        {
            future.swap(other.future);
        }

        // retrieving the value
        move_dest_type get()
        {
            if(!future)
            {
                throw future_uninitialized();
            }

            return future->get();
        }
        
        // functions to check state, and wait for ready
        state get_state() const
        {
            if(!future)
            {
                return future_state::uninitialized;
            }
            return future->get_state();
        }
        

        bool is_ready() const
        {
            return get_state()==future_state::ready;
        }
        
        bool has_exception() const
        {
            return future && future->has_exception();
        }
        
        bool has_value() const
        {
            return future && future->has_value();
        }
        
        void wait() const
        {
            if(!future)
            {
                throw future_uninitialized();
            }
            future->wait(false);
        }
        
        template<typename Duration>
        bool timed_wait(Duration const& rel_time) const
        {
            return timed_wait_until(boost::get_system_time()+rel_time);
        }
        
        bool timed_wait_until(boost::system_time const& abs_time) const
        {
            if(!future)
            {
                throw future_uninitialized();
            }
            return future->timed_wait_until(abs_time);
        }
        
    };

    template <typename R>
    class shared_future
    {
        typedef boost::shared_ptr<detail::future_object<R> > future_ptr;
        
        future_ptr future;

//         shared_future(const unique_future<R>& other);
//         shared_future& operator=(const unique_future<R>& other);

        friend class detail::future_waiter;
        friend class promise<R>;
        friend class packaged_task<R>;
        
        shared_future(future_ptr future_):
            future(future_)
        {}

    public:
        shared_future(shared_future const& other):
            future(other.future)
        {}

        typedef future_state::state state;

        shared_future()
        {}

        ~shared_future()
        {}

        shared_future& operator=(shared_future const& other)
        {
            future=other.future;
            return *this;
        }
#ifdef BOOST_HAS_RVALUE_REFS
        shared_future(shared_future && other)
        {
            future.swap(other.future);
        }
        shared_future(unique_future<R> && other)
        {
            future.swap(other.future);
        }
        shared_future& operator=(shared_future && other)
        {
            future.swap(other.future);
            other.future.reset();
            return *this;
        }
        shared_future& operator=(unique_future<R> && other)
        {
            future.swap(other.future);
            other.future.reset();
            return *this;
        }
#else            
        shared_future(boost::detail::thread_move_t<shared_future> other):
            future(other->future)
        {
            other->future.reset();
        }
//         shared_future(const unique_future<R> &) = delete;
        shared_future(boost::detail::thread_move_t<unique_future<R> > other):
            future(other->future)
        {
            other->future.reset();
        }
        shared_future& operator=(boost::detail::thread_move_t<shared_future> other)
        {
            future.swap(other->future);
            other->future.reset();
            return *this;
        }
        shared_future& operator=(boost::detail::thread_move_t<unique_future<R> > other)
        {
            future.swap(other->future);
            other->future.reset();
            return *this;
        }

        operator boost::detail::thread_move_t<shared_future>()
        {
            return boost::detail::thread_move_t<shared_future>(*this);
        }

#endif

        void swap(shared_future& other)
        {
            future.swap(other.future);
        }

        // retrieving the value
        R get()
        {
            if(!future)
            {
                throw future_uninitialized();
            }

            return future->get();
        }
        
        // functions to check state, and wait for ready
        state get_state() const
        {
            if(!future)
            {
                return future_state::uninitialized;
            }
            return future->get_state();
        }
        

        bool is_ready() const
        {
            return get_state()==future_state::ready;
        }
        
        bool has_exception() const
        {
            return future && future->has_exception();
        }
        
        bool has_value() const
        {
            return future && future->has_value();
        }

        void wait() const
        {
            if(!future)
            {
                throw future_uninitialized();
            }
            future->wait(false);
        }
        
        template<typename Duration>
        bool timed_wait(Duration const& rel_time) const
        {
            return timed_wait_until(boost::get_system_time()+rel_time);
        }
        
        bool timed_wait_until(boost::system_time const& abs_time) const
        {
            if(!future)
            {
                throw future_uninitialized();
            }
            return future->timed_wait_until(abs_time);
        }
        
    };

    template <typename R>
    class promise
    {
        typedef boost::shared_ptr<detail::future_object<R> > future_ptr;
        
        future_ptr future;
        bool future_obtained;
        
        promise(promise & rhs);// = delete;
        promise & operator=(promise & rhs);// = delete;

        void lazy_init()
        {
            if(!future)
            {
                future_obtained=false;
                future.reset(new detail::future_object<R>);
            }
        }
        
    public:
//         template <class Allocator> explicit promise(Allocator a);

        promise():
            future(),future_obtained(false)
        {}
        
        ~promise()
        {
            if(future)
            {
                boost::lock_guard<boost::mutex> lock(future->mutex);

                if(!future->done)
                {
                    future->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()));
                }
            }
        }

        // Assignment
#ifdef BOOST_HAS_RVALUE_REFS
        promise(promise && rhs):
            future_obtained(rhs.future_obtained)
        {
            future.swap(rhs.future);
        }
        promise & operator=(promise&& rhs)
        {
            future.swap(rhs.future);
            future_obtained=rhs.future_obtained;
            rhs.future.reset();
            return *this;
        }
#else
        promise(boost::detail::thread_move_t<promise> rhs):
            future(rhs->future),future_obtained(rhs->future_obtained)
        {
            rhs->future.reset();
        }
        promise & operator=(boost::detail::thread_move_t<promise> rhs)
        {
            future=rhs->future;
            future_obtained=rhs->future_obtained;
            rhs->future.reset();
            return *this;
        }

        operator boost::detail::thread_move_t<promise>()
        {
            return boost::detail::thread_move_t<promise>(*this);
        }
#endif   
        
        void swap(promise& other)
        {
            future.swap(other.future);
            std::swap(future_obtained,other.future_obtained);
        }

        // Result retrieval
        unique_future<R> get_future()
        {
            lazy_init();
            if(future_obtained)
            {
                throw future_already_retrieved();
            }
            future_obtained=true;
            return unique_future<R>(future);
        }

        void set_value(typename detail::future_traits<R>::source_reference_type r)
        {
            lazy_init();
            boost::lock_guard<boost::mutex> lock(future->mutex);
            if(future->done)
            {
                throw promise_already_satisfied();
            }
            future->mark_finished_with_result_internal(r);
        }

//         void set_value(R && r);
        void set_value(typename detail::future_traits<R>::rvalue_source_type r)
        {
            lazy_init();
            boost::lock_guard<boost::mutex> lock(future->mutex);
            if(future->done)
            {
                throw promise_already_satisfied();
            }
            future->mark_finished_with_result_internal(static_cast<typename detail::future_traits<R>::rvalue_source_type>(r));
        }

        void set_exception(boost::exception_ptr p)
        {
            lazy_init();
            boost::lock_guard<boost::mutex> lock(future->mutex);
            if(future->done)
            {
                throw promise_already_satisfied();
            }
            future->mark_exceptional_finish_internal(p);
        }

        template<typename F>
        void set_wait_callback(F f)
        {
            lazy_init();
            future->set_wait_callback(f,this);
        }
        
    };

    template <>
    class promise<void>
    {
        typedef boost::shared_ptr<detail::future_object<void> > future_ptr;
        
        future_ptr future;
        bool future_obtained;
        
        promise(promise & rhs);// = delete;
        promise & operator=(promise & rhs);// = delete;

        void lazy_init()
        {
            if(!future)
            {
                future_obtained=false;
                future.reset(new detail::future_object<void>);
            }
        }
    public:
//         template <class Allocator> explicit promise(Allocator a);

        promise():
            future(),future_obtained(false)
        {}
        
        ~promise()
        {
            if(future)
            {
                boost::lock_guard<boost::mutex> lock(future->mutex);

                if(!future->done)
                {
                    future->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()));
                }
            }
        }

        // Assignment
#ifdef BOOST_HAS_RVALUE_REFS
        promise(promise && rhs):
            future_obtained(rhs.future_obtained)
        {
            future.swap(rhs.future);
        }
        promise & operator=(promise&& rhs)
        {
            future.swap(rhs.future);
            future_obtained=rhs.future_obtained;
            rhs.future.reset();
            return *this;
        }
#else
        promise(boost::detail::thread_move_t<promise> rhs):
            future(rhs->future),future_obtained(rhs->future_obtained)
        {
            rhs->future.reset();
        }
        promise & operator=(boost::detail::thread_move_t<promise> rhs)
        {
            future=rhs->future;
            future_obtained=rhs->future_obtained;
            rhs->future.reset();
            return *this;
        }

        operator boost::detail::thread_move_t<promise>()
        {
            return boost::detail::thread_move_t<promise>(*this);
        }
#endif
        
        void swap(promise& other)
        {
            future.swap(other.future);
            std::swap(future_obtained,other.future_obtained);
        }

        // Result retrieval
        unique_future<void> get_future()
        {
            lazy_init();
            
            if(future_obtained)
            {
                throw future_already_retrieved();
            }
            future_obtained=true;
            return unique_future<void>(future);
        }

        void set_value()
        {
            lazy_init();
            boost::lock_guard<boost::mutex> lock(future->mutex);
            if(future->done)
            {
                throw promise_already_satisfied();
            }
            future->mark_finished_with_result_internal();
        }

        void set_exception(boost::exception_ptr p)
        {
            lazy_init();
            boost::lock_guard<boost::mutex> lock(future->mutex);
            if(future->done)
            {
                throw promise_already_satisfied();
            }
            future->mark_exceptional_finish_internal(p);
        }

        template<typename F>
        void set_wait_callback(F f)
        {
            lazy_init();
            future->set_wait_callback(f,this);
        }
        
    };

    namespace detail
    {
        template<typename R>
        struct task_base:
            detail::future_object<R>
        {
            bool started;

            task_base():
                started(false)
            {}

            void run()
            {
                {
                    boost::lock_guard<boost::mutex> lk(this->mutex);
                    if(started)
                    {
                        throw task_already_started();
                    }
                    started=true;
                }
                do_run();
            }

            void owner_destroyed()
            {
                boost::lock_guard<boost::mutex> lk(this->mutex);
                if(!started)
                {
                    started=true;
                    this->mark_exceptional_finish_internal(boost::copy_exception(jss::broken_promise()));
                }
            }
            
            
            virtual void do_run()=0;
        };
        
        
        template<typename R,typename F>
        struct task_object:
            task_base<R>
        {
            F f;
            task_object(F const& f_):
                f(f_)
            {}
            task_object(boost::detail::thread_move_t<F> f_):
                f(f_)
            {}
            
            void do_run()
            {
                try
                {
                    this->mark_finished_with_result(f());
                }
                catch(...)
                {
                    this->mark_exceptional_finish();
                }
            }
        };

        template<typename F>
        struct task_object<void,F>:
            task_base<void>
        {
            F f;
            task_object(F const& f_):
                f(f_)
            {}
            task_object(boost::detail::thread_move_t<F> f_):
                f(f_)
            {}
            
            void do_run()
            {
                try
                {
                    f();
                    this->mark_finished_with_result();
                }
                catch(...)
                {
                    this->mark_exceptional_finish();
                }
            }
        };

    }
    

    template<typename R>
    class packaged_task
    {
        boost::shared_ptr<detail::task_base<R> > task;
        bool future_obtained;

        packaged_task(packaged_task&);// = delete;
        packaged_task& operator=(packaged_task&);// = delete;
        
    public:
        packaged_task():
            future_obtained(false)
        {}
        
        // construction and destruction
        template <class F>
        explicit packaged_task(F const& f):
            task(new detail::task_object<R,F>(f)),future_obtained(false)
        {}
        explicit packaged_task(R(*f)()):
            task(new detail::task_object<R,R(*)()>(f)),future_obtained(false)
        {}
        
        template <class F>
        explicit packaged_task(boost::detail::thread_move_t<F> f):
            task(new detail::task_object<R,F>(f)),future_obtained(false)
        {}

//         template <class F, class Allocator>
//         explicit packaged_task(F const& f, Allocator a);
//         template <class F, class Allocator>
//         explicit packaged_task(F&& f, Allocator a);


        ~packaged_task()
        {
            if(task)
            {
                task->owner_destroyed();
            }
        }

        // assignment
#ifdef BOOST_HAS_RVALUE_REFS
        packaged_task(packaged_task&& other):
            future_obtained(other.future_obtained)
        {
            task.swap(other.task);
            other.future_obtained=false;
        }
        packaged_task& operator=(packaged_task&& other)
        {
            packaged_task temp(static_cast<packaged_task&&>(other));
            swap(temp);
            return *this;
        }
#else
        packaged_task(boost::detail::thread_move_t<packaged_task> other):
            future_obtained(other->future_obtained)
        {
            task.swap(other->task);
            other->future_obtained=false;
        }
        packaged_task& operator=(boost::detail::thread_move_t<packaged_task> other)
        {
            packaged_task temp(other);
            swap(temp);
            return *this;
        }
        operator boost::detail::thread_move_t<packaged_task>()
        {
            return boost::detail::thread_move_t<packaged_task>(*this);
        }
#endif

        void swap(packaged_task& other)
        {
            task.swap(other.task);
            std::swap(future_obtained,other.future_obtained);
        }

        // result retrieval
        unique_future<R> get_future()
        {
            if(!task)
            {
                throw task_moved();
            }
            else if(!future_obtained)
            {
                future_obtained=true;
                return unique_future<R>(task);
            }
            else
            {
                throw future_already_retrieved();
            }
        }
        

        // execution
        void operator()()
        {
            if(!task)
            {
                throw task_moved();
            }
            task->run();
        }

        template<typename F>
        void set_wait_callback(F f)
        {
            task->set_wait_callback(f,this);
        }
        
    };

}


#endif
