text: //  Copyright (c) 2017 Denis Blank
  //
  //  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)
  
  #pragma once
  
  #include <hpx/pack_traversal/detail/pack_traversal_async_impl.hpp>
  
  #include <utility>
  
  namespace hpx { namespace util {
      /// A tag which is passed to the `operator()` of the visitor
      /// if an element is visited synchronously.
      using detail::async_traverse_visit_tag;
      /// A tag which is passed to the `operator()` of the visitor
      /// if an element is visited after the traversal was detached.
      using detail::async_traverse_detach_tag;
      /// A tag which is passed to the `operator()` of the visitor
      /// if the asynchronous pack traversal was finished.
      using detail::async_traverse_complete_tag;
  
      /// A tag to identify that a mapper shall be constructed in-place
      /// from the first argument passed.
      using detail::async_traverse_in_place_tag;
  
      /// Traverses the pack with the given visitor in an asynchronous way.
      ///
      /// This function works in the same way as `traverse_pack`,
      /// however, we are able to suspend and continue the traversal at
      /// later time.
      /// Thus we require a visitor callable object which provides three
      /// `operator()` overloads as depicted by the code sample below:
      ///    ```cpp
      ///    struct my_async_visitor
      ///    {
      ///        /// The synchronous overload is called for each object,
      ///        /// it may return false to suspend the current control.
      ///        /// In that case the overload below is called.
      ///        template <typename T>
      ///        bool operator()(async_traverse_visit_tag, T&& element)
      ///        {
      ///            return true;
      ///        }
      ///
      ///        /// The asynchronous overload this is called when the
      ///        /// synchronous overload returned false.
      ///        /// In addition to the current visited element the overload is
      ///        /// called with a continuation callable object which resumes the
      ///        /// traversal when it's called later.
      ///        /// The continuation next may be stored and called later or
      ///        /// dropped completely to abort the traversal early.
      ///        template <typename T, typename N>
      ///        void operator()(async_traverse_detach_tag, T&& element, N&& next)
      ///        {
      ///        }
      ///
      ///        /// The overload is called when the traversal was finished.
      ///        /// As argument the whole pack is passed over which we
      ///        /// traversed asynchronously.
      ///        template <typename T>
      ///        void operator()(async_traverse_complete_tag, T&& pack)
      ///        {
      ///        }
      ///    };
      ///    ```
      ///
      /// \param   visitor A visitor object which provides the three `operator()`
      ///                  overloads that were described above.
      ///                  Additionally the visitor must be compatible
      ///                  for referencing it from a `hpx::intrusive_ptr`.
      ///                  The visitor should must have a virtual destructor!
      ///
      /// \param   pack    The arbitrary parameter pack which is traversed
      ///                  asynchronously. Nested objects inside containers and
      ///                  tuple like types are traversed recursively.
      ///
      /// \returns         A hpx::intrusive_ptr that references an instance of
      ///                  the given visitor object.
      ///
      /// See `traverse_pack` for a detailed description about the
      /// traversal behavior and capabilities.
      ///
      template <typename Visitor, typename... T>
      auto traverse_pack_async(Visitor&& visitor, T&&... pack)
          -> decltype(detail::apply_pack_transform_async(
              HPX_FORWARD(Visitor, visitor), HPX_FORWARD(T, pack)...))
      {
          return detail::apply_pack_transform_async(
              HPX_FORWARD(Visitor, visitor), HPX_FORWARD(T, pack)...);
      }
  
      /// Traverses the pack with the given visitor in an asynchronous way.
      ///
      /// This function works in the same way as `traverse_pack`,
      /// however, we are able to suspend and continue the traversal at
      /// later time.
      /// Thus we require a visitor callable object which provides three
      /// `operator()` overloads as depicted by the code sample below:
      ///    ```cpp
      ///    struct my_async_visitor
      ///    {
      ///        /// The synchronous overload is called for each object,
      ///        /// it may return false to suspend the current control.
      ///        /// In that case the overload below is called.
      ///        template <typename T>
      ///        bool operator()(async_traverse_visit_tag, T&& element)
      ///        {
      ///            return true;
      ///        }
      ///
      ///        /// The asynchronous overload this is called when the
      ///        /// synchronous overload returned false.
      ///        /// In addition to the current visited element the overload is
      ///        /// called with a continuation callable object which resumes the
      ///        /// traversal when it's called later.
      ///        /// The continuation next may be stored and called later or
      ///        /// dropped completely to abort the traversal early.
      ///        template <typename T, typename N>
      ///        void operator()(async_traverse_detach_tag, T&& element, N&& next)
      ///        {
      ///        }
      ///
      ///        /// The overload is called when the traversal was finished.
      ///        /// As argument the whole pack is passed over which we
      ///        /// traversed asynchronously.
      ///        template <typename T>
      ///        void operator()(async_traverse_complete_tag, T&& pack)
      ///        {
      ///        }
      ///    };
      ///    ```
      ///
      /// \param   visitor A visitor object which provides the three `operator()`
      ///                  overloads that were described above.
      ///                  Additionally the visitor must be compatible
      ///                  for referencing it from a `hpx::intrusive_ptr`.
      ///                  The visitor should must have a virtual destructor!
      ///
      /// \param   pack    The arbitrary parameter pack which is traversed
      ///                  asynchronously. Nested objects inside containers and
      ///                  tuple like types are traversed recursively.
      /// \param  alloc    Allocator instance to use to create the traversal
      ///                  frame.
      ///
      /// \returns         A hpx::intrusive_ptr that references an instance of
      ///                  the given visitor object.
      ///
      /// See `traverse_pack` for a detailed description about the
      /// traversal behavior and capabilities.
      ///
      template <typename Allocator, typename Visitor, typename... T>
      auto traverse_pack_async_allocator(
          Allocator const& alloc, Visitor&& visitor, T&&... pack)
          -> decltype(detail::apply_pack_transform_async_allocator(
              alloc, HPX_FORWARD(Visitor, visitor), HPX_FORWARD(T, pack)...))
      {
          return detail::apply_pack_transform_async_allocator(
              alloc, HPX_FORWARD(Visitor, visitor), HPX_FORWARD(T, pack)...);
      }
  }}    // namespace hpx::util
  