#ifndef CircularBuffer_h
#define CircularBuffer_h

// Macros for defining dirt simple circular buffers to use for
// passing info between a single writer (interrupt code for instance)
// and a single reader (normal program level for instance) with
// no need for locking operations.
//
// Lots of restrictions: No more than 254 items in buffer (so index
// can be a single byte for access via atomic read and write).
//
// Really does only work for single reader and single writer. Only
// reader should Pop(), only writer should Push().
//
// No error checking is done - you need to make sure !IsFull() before
// calling Push() and !IsEmpty() before calling Pop().

#define DECLARE_CIRCULAR_BUFFER(CLASS_NAME, ELEMENT_TYPE, BUFFER_SIZE) \
class CLASS_NAME { \
public: \
 \
   CLASS_NAME(); \
 \
   ~CLASS_NAME(); \
 \
   bool \
   IsEmpty() const; \
 \
   bool \
   IsFull() const; \
 \
   void \
   Push(ELEMENT_TYPE next_val); \
 \
   ELEMENT_TYPE \
   Pop(); \
 \
   void \
   MakeEmpty(); \
 \
private: \
 \
   byte \
   NextIndex(byte index) const; \
 \
   volatile byte tail; \
   ELEMENT_TYPE buffer[BUFFER_SIZE+1]; \
   volatile byte head; \
};

#define IMPLEMENT_CIRCULAR_BUFFER(CLASS_NAME, ELEMENT_TYPE, BUFFER_SIZE) \
CLASS_NAME::CLASS_NAME() : tail(0), head(0) { \
} \
 \
CLASS_NAME::~CLASS_NAME() { \
} \
 \
bool \
CLASS_NAME::IsEmpty() const { \
   return (head == tail); \
} \
 \
bool \
CLASS_NAME::IsFull() const { \
   byte next_tail = NextIndex(tail); \
   return (head == next_tail); \
} \
 \
void \
CLASS_NAME::Push(ELEMENT_TYPE next_val) { \
   byte next_tail = NextIndex(tail); \
   buffer[tail] = next_val; \
   tail = next_tail; \
} \
 \
ELEMENT_TYPE \
CLASS_NAME::Pop() { \
   ELEMENT_TYPE rval = buffer[head]; \
   head = NextIndex(head); \
   return rval; \
} \
 \
void \
CLASS_NAME::MakeEmpty() { \
   head = tail; \
} \
 \
byte \
CLASS_NAME::NextIndex(byte index) const { \
   index++; \
   if (index == BUFFER_SIZE+1) { \
      index = 0; \
   } \
   return index; \
}

#endif // CircularBuffer_h
