//  Copyright (c) 2014-2017 Hartmut Kaiser
//  Copyright (c) 2017 Igor Krivenko
//
//  SPDX-License-Identifier: BSL-1.0
//  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)

#include <hpx/config.hpp>
#if !defined(HPX_COMPUTE_DEVICE_CODE)
#include <hpx/hpx_main.hpp>
#include <hpx/include/actions.hpp>
#include <hpx/include/components.hpp>
#include <hpx/include/lcos.hpp>
#include <hpx/include/runtime.hpp>
#include <hpx/modules/testing.hpp>

#include <cstddef>
#include <vector>

struct non_default_ctor
{
    int i;

    non_default_ctor() = delete;
    non_default_ctor(int i)
      : i(i)
    {
    }

    template <typename Archive>
    void serialize(Archive& ar, const unsigned int)
    {
        // clang-format off
        ar & i;
        // clang-format on
    }

    template <class Archive>
    void friend load_construct_data(
        Archive&, non_default_ctor* p, const unsigned int)
    {
        ::new (p) non_default_ctor(0);
    }
};

hpx::future<non_default_ctor> plain_future_non_default_ctor()
{
    return hpx::make_ready_future(non_default_ctor(42));
}

HPX_PLAIN_ACTION(
    plain_future_non_default_ctor, plain_future_non_default_ctor_action)

void test_plain_call_future_non_default_ctor(hpx::id_type id)
{
    // test apply
    for (std::size_t i = 0; i != 100; ++i)
    {
        hpx::post<plain_future_non_default_ctor_action>(id);
    }

    // test async
    std::vector<hpx::future<non_default_ctor>> calls;
    for (std::size_t i = 0; i != 100; ++i)
    {
        calls.push_back(hpx::async<plain_future_non_default_ctor_action>(id));
    }
    hpx::wait_all(calls);

    for (auto&& f : calls)
    {
        HPX_TEST_EQ(f.get().i, 42);
    }
}

///////////////////////////////////////////////////////////////////////////////
int main()
{
    for (hpx::id_type id : hpx::find_all_localities())
    {
        test_plain_call_future_non_default_ctor(id);
    }
    return hpx::util::report_errors();
}
#endif
