// (C) 2020-2026 Philip Endecott.
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENCE.txt or copy at https://www.boost.org/LICENSE_1_0.txt

#ifndef buffer_hh
#define buffer_hh

#include <cstddef>

// Simple fixed-capacity buffer.
// This is not suitable for types with non-trivial ctors and dtors, as
// the underlying array is default-initialised and popped items are not
// destroyed.
// This is not lock-free.
// This can be instantiated as volatile.


template <typename T, size_t N>
class buffer
{
  T data[N];
  size_t back_ix;

public:
  using value_type = T;  // Or volatile T?

  buffer():
    back_ix(0)
  {}

  // Note all the volatile/non-volatile variants could be re-done using 
  // "self" if we wanted. It may not be more concise though.

  size_t capacity() const          { return N; }
  size_t capacity() const volatile { return N; }
  size_t size()     const          { return back_ix; }
  size_t size()     const volatile { return back_ix; }
  bool   empty()    const          { return size() == 0; }
  bool   empty()    const volatile { return size() == 0; }
  bool   full()     const          { return size() == capacity(); }
  bool   full()     const volatile { return size() == capacity(); }

  void push_back(T value)  // Precondition: !full()
  {
    data[back_ix] = value;
    ++back_ix;
  }

  void push_back(T value) volatile // Precondition: !full()
  {
    data[back_ix] = value;
    back_ix = back_ix + 1;
  }

  const          T& operator[](size_t i) const          { return data[i]; }
  const volatile T& operator[](size_t i) const volatile { return data[i]; }

  void clear()          { back_ix = 0; }
  void clear() volatile { back_ix = 0; }

  using const_volatile_iterator = const volatile T*;
  const_volatile_iterator begin() const volatile { return data; }
  const_volatile_iterator end()   const volatile { return data + back_ix; }

};


#endif

