.. _qu_spsc_unbounded:

tmc::qu_spsc_unbounded
-----------------------------------------------------------------------------------

Async SPSC unbounded queue using purely zero-copy operation. It is linearizable / FIFO. It can be configured by overriding the Config template parameter.

Producer operations:

* :cpp:func:`post()<tmc::qu_spsc_unbounded::post>`
* :cpp:func:`post_bulk()<tmc::qu_spsc_unbounded::post_bulk>`
* :cpp:func:`close()<tmc::qu_spsc_unbounded::close>`
* :cpp:func:`close_resume_inline()<tmc::qu_spsc_unbounded::close_resume_inline>`

Consumer operations:

* ``co_await`` :cpp:func:`pull()<tmc::qu_spsc_unbounded::pull>`
* :cpp:func:`try_pull()<tmc::qu_spsc_unbounded::try_pull>`
* :cpp:func:`empty()<tmc::qu_spsc_unbounded::empty>`

Usage Examples
-----------------------------------------------------------------------------------

.. tab:: Using pull()

   :cpp:func:`pull()<tmc::qu_spsc_unbounded::pull>` suspends until data is available. It returns a scoped zero-copy handle whose ``operator bool()`` / ``has_value()`` indicates the result.

   .. code-block:: cpp

      #include "tmc/task.hpp"
      #include "tmc/spawn_tuple.hpp"
      #include "tmc/qu_spsc_unbounded.hpp"

      tmc::task<void> producer(tmc::qu_spsc_unbounded<int>& q) {
        for (int i = 0; i < 100; ++i) {
          q.post(i);
        }
        q.close();
      }

      tmc::task<void> consumer(tmc::qu_spsc_unbounded<int>& q) {
        // Loop automatically breaks once the queue drains after close()
        while (auto data = co_await q.pull()) {
          // v is a zero-copy reference to a T located in the queue storage
          int& v = data.value();
          // do something with v
        }
      }

      tmc::task<void> queue_quickstart() {
        tmc::qu_spsc_unbounded<int> q;
        co_await tmc::spawn_tuple(producer(q), consumer(q));
      }

.. tab:: Using try_pull()

   :cpp:func:`try_pull()<tmc::qu_spsc_unbounded::try_pull>` is non-suspending and
   must be polled. It returns a scoped zero-copy handle whose ``status()`` (or
   ``operator bool()``) indicates the result.

   .. code-block:: cpp

      // Drains all data currently in the queue. Returns true if the queue was empty afterward,
      // and false if the queue was closed afterward.
      tmc::task<bool> consume_all_data(tmc::qu_spsc_unbounded<int>& q) {
        while(true) {
          auto data = q.try_pull();
          switch (data.status()) {
            case tmc::qu_spsc_unbounded_err::OK: {
              // v is a zero-copy reference to a T located in the queue storage
              int& v = data.value();
              // do something with v
              break;
            }
            case tmc::qu_spsc_unbounded_err::EMPTY:
              // No data available right now. Try again later.
              co_return true;
            case tmc::qu_spsc_unbounded_err::CLOSED:
              // The queue has been closed and drained. Do not try again later.
              co_return false;
            default:
              std::unreachable();
          }
        }
      }

API Reference
-----------------------------------------------------------------------------------
.. doxygenclass:: tmc::qu_spsc_unbounded
  :members:

.. doxygenenum:: tmc::qu_spsc_unbounded_err

.. doxygenstruct:: tmc::qu_spsc_unbounded_default_config
  :members:
