#include <cassert>
#include <chrono>
#include <cstddef>
#include <emscripten/atomic.h>

constexpr uintptr_t WAIT_FREE_SENTINEL = ~uintptr_t(0);

template <size_t Size = sizeof(uintptr_t)> struct intptr_ops;

template <> struct intptr_ops<4> {
  static uintptr_t load(void *ptr) { return emscripten_atomic_load_u32(ptr); }
  static uintptr_t compare_and_swap(void *ptr, uintptr_t expected,
                                    uintptr_t new_value) {
    return emscripten_atomic_cas_u32(ptr, expected, new_value);
  }
};

template <> struct intptr_ops<8> {
  static uintptr_t load(void *ptr) { return emscripten_atomic_load_u64(ptr); }
  static uintptr_t compare_and_swap(void *ptr, uintptr_t expected,
                                    uintptr_t new_value) {
    return emscripten_atomic_cas_u64(ptr, expected, new_value);
  }
};

template <typename T> class WaitFreeGuard;

template <typename T> class WaitFreeWrap {
private:
  T *value;

  T *swapUnconditional(T *new_value) {
    while (true) {
      uintptr_t current = intptr_ops<>::load(&value);
      if (current ==
          intptr_ops<>::compare_and_swap(
              &value, current, reinterpret_cast<uintptr_t>(new_value))) {
        return reinterpret_cast<T *>(current);
      }
    }
  }

  friend class WaitFreeGuard<T>;

public:
  WaitFreeWrap(T *value) : value(value) {}

  std::pair<T *, bool> swap(T *new_value, uint32_t timeoutMs = 0) {
    const auto start = std::chrono::steady_clock::now();
    while (timeoutMs == 0 || std::chrono::steady_clock::now() - start <
                                 std::chrono::milliseconds(timeoutMs)) {
      uintptr_t current = intptr_ops<>::load(&value);
      if (current == WAIT_FREE_SENTINEL) {
        continue;
      }
      if (current ==
          intptr_ops<>::compare_and_swap(
              &value, current, reinterpret_cast<uintptr_t>(new_value))) {
        return {reinterpret_cast<T *>(current), true};
      }
    }
    return {nullptr, false};
  }
};

template <typename T> class WaitFreeGuard {
private:
  T *heldValue;
  WaitFreeWrap<T> &wrap;

public:
  WaitFreeGuard(WaitFreeWrap<T> &wrap) : wrap(wrap) {
    heldValue =
        wrap.swapUnconditional(reinterpret_cast<T *>(WAIT_FREE_SENTINEL));
  }

  ~WaitFreeGuard() { wrap.swapUnconditional(heldValue); }

  T *operator->() { return heldValue; }

  T *operator*() { return heldValue; }

  T *get() { return heldValue; }
};