blob: 30e629ba5c121da3141257abe4111dcdd78398d0 [file] [log] [blame]
/*
* This code is in public domain.
* Implementation and its platform dependent issues discussed in
* https://kjellkod.wordpress.com/2012/11/28/c-debt-paid-in-full-wait-free-lock-free-queue/
*/
#ifndef INCLUDE_CMN_CIRCULARFIFO_H_
#define INCLUDE_CMN_CIRCULARFIFO_H_
#include <atomic>
#include <cstddef>
namespace cmn {
namespace utils {
template<typename Element, size_t Size>
class CircularFifo
{
public:
enum { Capacity = Size + 1 };
CircularFifo() : _tail(0), _head(0){}
virtual ~CircularFifo() {}
bool push(Element* item);
bool pop(Element*& item);
bool wasEmpty() const;
bool wasFull() const;
bool isLockFree() const;
private:
size_t increment(size_t idx) const;
std::atomic <size_t> _tail;
Element* _array[Capacity];
std::atomic<size_t> _head;
};
template<typename Element, size_t Size>
bool CircularFifo<Element, Size>::push(Element* item)
{
const auto current_tail = _tail.load(std::memory_order_relaxed);
const auto next_tail = increment(current_tail);
if(next_tail != _head.load(std::memory_order_acquire))
{
_array[current_tail] = item;
_tail.store(next_tail, std::memory_order_release);
return true;
}
return false;
}
template<typename Element, size_t Size>
bool CircularFifo<Element, Size>::pop(Element*& item)
{
const auto current_head = _head.load(std::memory_order_relaxed);
if(current_head == _tail.load(std::memory_order_acquire))
return false;
item = _array[current_head];
_head.store(increment(current_head), std::memory_order_release);
return true;
}
template<typename Element, size_t Size>
bool CircularFifo<Element, Size>::wasEmpty() const
{
return (_head.load() == _tail.load());
}
template<typename Element, size_t Size>
bool CircularFifo<Element, Size>::wasFull() const
{
const auto next_tail = increment(_tail.load());
return (next_tail == _head.load());
}
template<typename Element, size_t Size>
bool CircularFifo<Element, Size>::isLockFree() const
{
return (_tail.is_lock_free() && _head.is_lock_free());
}
template<typename Element, size_t Size>
size_t CircularFifo<Element, Size>::increment(size_t idx) const
{
return (idx + 1) % Capacity;
}
}
}
#endif /* INCLUDE_CMN_CIRCULARFIFO_H_ */