/*  Copyright (C) 2015  Povilas Kanapickas <povilas@radix.lt>

    This file is part of cppreference-doc

    This work is licensed under the Creative Commons Attribution-ShareAlike 3.0
    Unported License. To view a copy of this license, visit
    http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative
    Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.

    Permission is granted to copy, distribute and/or modify this document
    under the terms of the GNU Free Documentation License, Version 1.3 or
    any later version published by the Free Software Foundation; with no
    Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
*/

#ifndef CPPREFERENCE_FUTURE_H
#define CPPREFERENCE_FUTURE_H

#if CPPREFERENCE_STDVER>= 2011
#include <stdexcept>

namespace std {

template<class R>
class promise { // SIMPLIFIED: removed R& and void specializations
public:
    promise();
    template<class Alloc>
    promise(std::allocator_arg_t, const Alloc& alloc);
    promise(promise&& other);
    promise(const promise& other) = delete;

    ~promise();

    promise& operator=(promise&& other);
    promise& operator=(const promise& rhs) = delete;

    void swap(promise& other);

    std::future<T> get_future();

    void set_value(const R& value);
    void set_value(R&& value);
    void set_value(R& value);   // member of R& specialization
    void set_value(); // member of void specialization
    void set_value_at_thread_exit(const R& value);
    void set_value_at_thread_exit(R&& value);
    void set_value_at_thread_exit(R& value);   // member of R& specialization
    void set_value_at_thread_exit(); // member of void specialization
    void set_exception(std::exception_ptr p);
    void set_exception_at_thread_exit(std::exception_ptr p);
};

template<class R>
void swap(promise<R>& lhs, promise<R>& rhs);

template<class R, class ...Args>
class packaged_task<R(Args...)> {
public:
    packaged_task();

    template <class F>
    explicit packaged_task(F&& f);

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

    packaged_task(const packaged_task&) = delete;
    packaged_task(packaged_task&& rhs);

    ~packaged_task();

    packaged_task& operator=(const packaged_task&) = delete;
    packaged_task& operator=(packaged_task&& rhs);

    bool valid() const;

    void swap(packaged_task& other);

    std::future<R> get_future();

    void operator()(ArgTypes... args);

    void make_ready_at_thread_exit(ArgTypes... args);

    void reset();
};

template<class Function, class... Args>
void swap(packaged_task<Function(Args...)>& lhs,
          packaged_task<Function(Args...)>& rhs);

template<class T>
class future { // SIMPLIFIED: removed T& and void specializations
public:
    future();
    future(future&& other);
    future(const future& other) = delete;
    ~future();

    future& operator=(future&& other);
    future& operator=(const future& other) = delete;

    std::shared_future<T> share();

    T get(); // member only of generic specialization
    T& get(); // member only of T& specialization
    void get(); // member only of void specialization

    bool valid() const;

    void wait() const;

    template<class Rep, class Period>
    std::future_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const;

    template<class Clock, class Duration>
    std::future_status wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) const;
};

template<class T>
class shared_future { // SIMPLIFIED: removed T& and void specializations
public:
    shared_future();
    shared_future(const shared_future& other);
    shared_future(std::future<T>&& other);
    shared_future(shared_future&& other);

    ~shared_future();

    shared_future& operator=(const shared_future& other);
    shared_future& operator=(shared_future&& other);

    T get(); // member only of generic specialization
    T& get(); // member only of T& specialization
    void get(); // member only of void specialization

    bool valid() const;

    void wait() const;

    template<class Rep, class Period>
    std::future_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) const;

    template<class Clock, class Duration>
    std::future_status wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) const;
};

enum class launch {
    async,
    deferred
};

enum class future_status {
    ready,
    timeout,
    deferred
};

enum class future_errc {
    broken_promise,
    future_already_retrieved,
    promise_already_satisfied,
    no_state
};

class future_error : public logic_error {
public:
    future_error(std::error_code ec);
    const std::error_code& code() const;
};

template<class Function, class... Args>
std::future<typename std::result_of<Function(Args...)>::type>
async(Function&& f, Args&& ... args);

template<class Function, class... Args>
std::future<typename std::result_of<Function(Args...)>::type>
async(std::launch policy, Function&& f, Args&& ... args);

const std::error_category& future_category();

} // namespace std

#endif // CPPREFERENCE_STDVER>= 2011

#endif // CPPREFERENCE_FUTURE_H
