Skip to content

File ringbuffer.h

File List > external-docs > libDaisy > src > util > ringbuffer.h

Go to the documentation of this file

Source Code

#pragma once
#ifndef DSY_RINGBUFFER_H
#define DSY_RINGBUFFER_H

#include <algorithm>

namespace daisy
{
template <typename T, size_t size>
class RingBuffer
{
  public:
    RingBuffer() {}

    inline void Init() { read_ptr_ = write_ptr_ = 0; }

    inline size_t capacity() const { return size; }

    inline size_t writable() const
    {
        return (read_ptr_ - write_ptr_ - 1) % size;
    }

    inline size_t readable() const { return (write_ptr_ - read_ptr_) % size; }

    inline bool isEmpty() const { return write_ptr_ == read_ptr_; }

    inline void Write(T v)
    {
        while(!writable())
            ;
        Overwrite(v);
    }

    inline void Overwrite(T v)
    {
        size_t w   = write_ptr_;
        buffer_[w] = v;
        write_ptr_ = (w + 1) % size;
    }

    inline T Read()
    {
        while(!readable())
            ;
        return ImmediateRead();
    }

    inline T ImmediateRead()
    {
        size_t r      = read_ptr_;
        T      result = buffer_[r];
        read_ptr_     = (r + 1) % size;
        return result;
    }

    inline void Flush() { write_ptr_ = read_ptr_; }

    inline void Swallow(size_t n)
    {
        if(writable() >= n)
        {
            return;
        }
        read_ptr_ = (write_ptr_ + 1 + n) % size;
    }

    inline void ImmediateRead(T* destination, size_t num_elements)
    {
        size_t r    = read_ptr_;
        size_t read = num_elements;

        if(r + read > size)
        {
            read = size - r;
        }
        std::copy(&buffer_[r], &buffer_[r + read], destination);
        if(read != num_elements)
        {
            std::copy(
                &buffer_[0], &buffer_[num_elements - read], destination + read);
        }
        read_ptr_ = (r + num_elements) % size;
    }

    inline void Overwrite(const T* source, size_t num_elements)
    {
        size_t w       = write_ptr_;
        size_t written = num_elements;

        if(w + written > size)
        {
            written = size - w;
        }
        std::copy(source, source + written, &buffer_[w]);
        if(written != num_elements)
        {
            std::copy(source + written, source + num_elements, &buffer_[0]);
        }

        write_ptr_ = (w + num_elements) % size;
    }

    inline void Advance(size_t num_elements)
    {
        size_t free;
        free         = this->writable();
        num_elements = num_elements < free ? num_elements : free;
        write_ptr_   = write_ptr_ + num_elements;
        if(write_ptr_ > size)
            write_ptr_ = write_ptr_ - size;
    }

    inline T* GetMutableBuffer() { return buffer_; }

  private:
    T               buffer_[size];
    volatile size_t read_ptr_;
    volatile size_t write_ptr_;
};

template <typename T>
class RingBuffer<T, 0>
{
  public:
    RingBuffer() {}

    inline void   Init() {}                      
    inline size_t capacity() const { return 0; } 
    inline size_t writable() const { return 0; } 
    inline size_t readable() const { return 0; } 
    inline void   Write(T v) { (void)(v); } 
    inline void   Overwrite(T v)
    {
        (void)(v);
    }                                   
    inline T    Read() { return T(0); } 
    inline T    ImmediateRead() { return T(0); } 
    inline void Flush() {}                       
    inline void ImmediateRead(T* destination, size_t num_elements)
    {
        (void)(destination);
        (void)(num_elements);
    } 
    inline void Overwrite(const T* source, size_t num_elements)
    {
        (void)(source);
        (void)(num_elements);
    } 
  private:
};

} // namespace daisy

#endif