// test/manifold-link/include/memory — extends libc++'s <memory> with
// the std::atomic_*(shared_ptr*) free function family.
//
// libc++ gates these free functions behind `#if _LIBCPP_HAS_THREADS`,
// which the shim's __config_site sets to 0. Manifold v3.5.0 attaches
// an ExecutionContext via `std::shared_ptr<ExecutionContext> ctx_`
// and accesses it through `std::atomic_load/store(&ctx_, ...)`.
// Without these stubs, the build fails with "no matching function
// for call to atomic_load".
//
// Single-threaded freestanding code is correct without atomicity —
// these stubs mirror what libc++ would do under
// `_LIBCPP_HAS_THREADS=1` but without the __sp_mut lock. The
// upstream-friendly fix is a MANIFOLD_NO_THREADS flag on manifold
// that gates the atomic_*(&ctx_) usage; until then, stub here.
//
// ---
//
// Include-order requirement: this directory MUST come before libc++'s
// header dir on the -isystem chain. We use `#include_next <memory>`
// to chain to libc++'s real <memory>; if libc++'s <memory> sits
// earlier on the chain, our `#include_next` either re-enters this
// file (defeated by the include guard) or finds nothing, and the
// atomic_*(shared_ptr*) declarations never participate. Mind this
// when copying these stubs into a downstream consumer tree.
//
// Asymmetric with the sibling `<mutex>` stub, which fully shadows
// libc++ (provides a self-contained set of types and never includes
// libc++'s real `<mutex>`). The shadow approach isn't practical for
// `<memory>` — libc++'s real `<memory>` has thousands of lines of
// allocator / unique_ptr / shared_ptr machinery that consumers need.
// Smoke-test-companion only; consumers building with full threads
// support use libc++'s real shared_ptr atomic family.
#ifndef _WASM_CXX_SHIM_MANIFOLD_LINK_MEMORY
#define _WASM_CXX_SHIM_MANIFOLD_LINK_MEMORY

#include_next <memory>
#include <__atomic/memory_order.h>  // just the memory_order enum, not all of <atomic>
#include <utility>                  // for std::move

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Tp>
inline shared_ptr<_Tp> atomic_load(const shared_ptr<_Tp>* __p) {
    return *__p;
}

template <class _Tp>
inline shared_ptr<_Tp> atomic_load_explicit(const shared_ptr<_Tp>* __p,
                                            memory_order) {
    return *__p;
}

template <class _Tp>
inline void atomic_store(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r) {
    *__p = std::move(__r);
}

template <class _Tp>
inline void atomic_store_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r,
                                  memory_order) {
    *__p = std::move(__r);
}

template <class _Tp>
inline shared_ptr<_Tp> atomic_exchange(shared_ptr<_Tp>* __p,
                                       shared_ptr<_Tp> __r) {
    // Swap-based to match libc++'s refcount semantics: __r ends up
    // owning the old value; return __r without an extra refcount
    // bump. Matters for consumers that observe use_count() across
    // an exchange.
    __p->swap(__r);
    return __r;
}

template <class _Tp>
inline shared_ptr<_Tp> atomic_exchange_explicit(shared_ptr<_Tp>* __p,
                                                shared_ptr<_Tp> __r,
                                                memory_order) {
    __p->swap(__r);
    return __r;
}

template <class _Tp>
inline bool atomic_compare_exchange_strong(shared_ptr<_Tp>* __p,
                                           shared_ptr<_Tp>* __v,
                                           shared_ptr<_Tp> __w) {
    if (__p->get() == __v->get() && __p->use_count() == __v->use_count()) {
        *__p = std::move(__w);
        return true;
    }
    *__v = *__p;
    return false;
}

template <class _Tp>
inline bool atomic_compare_exchange_weak(shared_ptr<_Tp>* __p,
                                         shared_ptr<_Tp>* __v,
                                         shared_ptr<_Tp> __w) {
    return std::atomic_compare_exchange_strong(__p, __v, std::move(__w));
}

template <class _Tp>
inline bool atomic_compare_exchange_strong_explicit(shared_ptr<_Tp>* __p,
                                                    shared_ptr<_Tp>* __v,
                                                    shared_ptr<_Tp> __w,
                                                    memory_order,
                                                    memory_order) {
    return std::atomic_compare_exchange_strong(__p, __v, std::move(__w));
}

template <class _Tp>
inline bool atomic_compare_exchange_weak_explicit(shared_ptr<_Tp>* __p,
                                                  shared_ptr<_Tp>* __v,
                                                  shared_ptr<_Tp> __w,
                                                  memory_order,
                                                  memory_order) {
    return std::atomic_compare_exchange_strong(__p, __v, std::move(__w));
}

template <class _Tp>
inline bool atomic_is_lock_free(const shared_ptr<_Tp>*) {
    return false;
}

_LIBCPP_END_NAMESPACE_STD

#endif
