
#ifndef CONTEXT_SWITCHER_CONTINUATION_H_
#define CONTEXT_SWITCHER_CONTINUATION_H_

#include "context.h"

#include <cstdlib>
#include <cstdio>

namespace context_switcher {

/**
 * One-Shot continuation. Represents the paused state of an execution thread.
 * Can be used exactly once to jump back to that state.
 *
 * Move only to ensure semantics of one time use.
 */
struct continuation {
 public:
  continuation() = default;
#ifdef THREAD_SANITIZER
  continuation(continuation_t cont_pointer, void *tsan_fiber) : cont_pointer_{cont_pointer}, tsan_fiber_{tsan_fiber} {};
#else
  explicit continuation(continuation_t cont_pointer) : cont_pointer_{cont_pointer} {};
#endif

  // Move-Only Semantics
  continuation(const continuation &other) = delete;
  continuation(continuation &&other) noexcept {
    cont_pointer_ = other.cont_pointer_;
    other.cont_pointer_ = nullptr;
#ifdef THREAD_SANITIZER
    tsan_fiber_ = other.tsan_fiber_;
#endif
  }

  continuation &operator=(const continuation &other) = delete;
  continuation &operator=(continuation &&other) noexcept {
    cont_pointer_ = other.cont_pointer_;
    other.cont_pointer_ = nullptr;
#ifdef THREAD_SANITIZER
    tsan_fiber_ = other.tsan_fiber_;
#endif
    return *this;
  }

  // Semantics as 'one time use'
  bool valid() const {
    return cont_pointer_ != nullptr;
  }

  continuation_t consume() {
    auto tmp = cont_pointer_;
    cont_pointer_ = nullptr;
    return tmp;
  }

#ifdef THREAD_SANITIZER
  void *get_tsan_fiber() {
    return tsan_fiber_;
  }
#endif

 private:
  continuation_t cont_pointer_{nullptr};
#ifdef THREAD_SANITIZER
  void *tsan_fiber_{nullptr};
#endif
};

}

#endif //CONTEXT_SWITCHER_CONTINUATION_H_
