#pragma once
#include "machine.h"
#include <cstddef>
#include <cstdint>
#include <emscripten/wasm_worker.h>

class AppendOnlyBuffer {
  static constexpr size_t AOB_PAGE_SIZE = 1024 * 1024;
  static constexpr size_t AOB_PAGE_MAX_COUNT = 256;

  uint8_t *pages[AOB_PAGE_MAX_COUNT]{};

  emscripten_lock_t appenderLock;

  alignas(CACHE_LINE_SIZE) uint32_t atomicSize{};
  alignas(CACHE_LINE_SIZE) uint32_t atomicPageCount{};

  AppendOnlyBuffer(const AppendOnlyBuffer &) = delete;
  AppendOnlyBuffer &operator=(const AppendOnlyBuffer &) = delete;
  AppendOnlyBuffer(AppendOnlyBuffer &&) = delete;
  AppendOnlyBuffer &operator=(AppendOnlyBuffer &&) = delete;

public:
  AppendOnlyBuffer();
  ~AppendOnlyBuffer();

  // read() and size():
  // - may return stale values
  // - size() is a guaranteed lower bound
  //   with respect to subsequent calls to read()
  // - are lock-free and wait-free
  // - permit concurrent calls
  size_t size() const;

  size_t read(size_t offset, size_t count, uint8_t *out);

  // all calls to append() are serialized by a lock
  void append(size_t count, const uint8_t *data);
};
