// resumable experimental header

// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

// Library support of coroutines TS, https://wg21.link/p0057

#ifndef _EXPERIMENTAL_RESUMABLE_
#define _EXPERIMENTAL_RESUMABLE_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#include <memory>
#include <new>
#if _HAS_EXCEPTIONS
#include <exception>
#endif
#include <cstdint>
#include <experimental/coroutine>
#include <type_traits>

#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

_STD_BEGIN

namespace experimental {

#ifndef __EDG__
    struct noop_coroutine_promise {};

    template <>
    struct coroutine_handle<noop_coroutine_promise> : coroutine_handle<> {
        friend coroutine_handle noop_coroutine() noexcept;
        constexpr explicit operator bool() const noexcept {
            return true;
        }
        _NODISCARD constexpr bool done() const noexcept {
            return false;
        }
        constexpr void operator()() const noexcept {}
        constexpr void resume() const noexcept {}
        constexpr void destroy() const noexcept {}

        using _Promise = noop_coroutine_promise;

        static const size_t _ALIGN_REQ = sizeof(void*) * 2;

        static const size_t _ALIGNED_SIZE =
            is_empty_v<_Promise> ? 0 : ((sizeof(_Promise) + _ALIGN_REQ - 1) & ~(_ALIGN_REQ - 1));

        _NODISCARD _Promise& promise() const noexcept {
            // Returns a reference to the associated promise.
            return *const_cast<_Promise*>(
                reinterpret_cast<const _Promise*>(reinterpret_cast<const char*>(_Ptr) - _ALIGNED_SIZE));
        }

    private:
        coroutine_handle() noexcept {
            _Ptr = reinterpret_cast<_Resumable_frame_prefix*>(__builtin_coro_noop());
        }
    };

    using noop_coroutine_handle = coroutine_handle<noop_coroutine_promise>;

    _NODISCARD inline noop_coroutine_handle noop_coroutine() noexcept {
        // Returns a handle to a coroutine that has no observable effects when resumed or destroyed.
        return noop_coroutine_handle{};
    }
#endif // ^^^ !defined(__EDG__) ^^^
} // namespace experimental

_STD_END

#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)

#endif // _STL_COMPILER_PREPROCESSOR
#endif // _EXPERIMENTAL_RESUMABLE_
