You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

557 lines
14 KiB
C++

#pragma once
#ifndef ARX_RINGBUFFER_H
#define ARX_RINGBUFFER_H
#if __cplusplus < 201103L
#error "C++11 must be enabled in the compiler for this library to work, please check your compiler flags"
#endif
#include "ArxContainer/has_include.h"
#include "ArxContainer/has_libstdcplusplus.h"
#ifdef ARDUINO
#include <Arduino.h>
#endif
#include "ArxContainer/replace_minmax_macros.h"
#include "ArxContainer/initializer_list.h"
#if ARX_HAVE_LIBSTDCPLUSPLUS >= 201103L // Have libstdc++11
#include <vector>
#include <deque>
#include <map>
#else // Do not have libstdc++11
#ifndef ARX_VECTOR_DEFAULT_SIZE
#define ARX_VECTOR_DEFAULT_SIZE 16
#endif // ARX_VECTOR_DEFAULT_SIZE
#ifndef ARX_DEQUE_DEFAULT_SIZE
#define ARX_DEQUE_DEFAULT_SIZE 16
#endif // ARX_DEQUE_DEFAULT_SIZE
#ifndef ARX_MAP_DEFAULT_SIZE
#define ARX_MAP_DEFAULT_SIZE 16
#endif // ARX_MAP_DEFAULT_SIZE
namespace arx {
namespace container
{
namespace detail
{
template<class T>
T&& move(T& t){ return static_cast<T&&>(t); }
}
}
template<typename T, size_t N>
class RingBuffer
{
protected:
T queue_[N];
int head_ {0};
int tail_ {0};
public:
RingBuffer()
: queue_()
, head_ {0}
, tail_{0}
{
}
RingBuffer(std::initializer_list<T> lst)
: queue_()
, head_(0)
, tail_(0)
{
for (auto it = lst.begin() ; it != lst.end() ; ++it)
{
queue_[tail_] = *it;
++tail_;
}
}
// copy
explicit RingBuffer(const RingBuffer& r)
: queue_()
, head_(r.head_)
, tail_(r.tail_)
{
for (size_t i = 0; i < r.size(); ++i)
queue_[i] = r.queue_[i];
}
RingBuffer& operator= (const RingBuffer& r)
{
head_ = r.head_;
tail_ = r.tail_;
for (size_t i = 0; i < r.size(); ++i)
queue_[i] = r.queue_[i];
return *this;
}
// move
RingBuffer(RingBuffer&& r)
{
head_ = container::detail::move(r.head_);
tail_ = container::detail::move(r.tail_);
for (size_t i = 0; i < r.size(); ++i)
queue_[i] = container::detail::move(r.queue_[i]);
}
RingBuffer& operator= (RingBuffer&& r)
{
head_ = container::detail::move(r.head_);
tail_ = container::detail::move(r.tail_);
for (size_t i = 0; i < r.size(); ++i)
queue_[i] = container::detail::move(r.queue_[i]);
return *this;
}
virtual ~RingBuffer() {}
using iterator = T*;
using const_iterator = const T*;
size_t capacity() const { return N; };
size_t size() const { return tail_ - head_; }
inline const T* data() const { return &(get(head_)); }
T* data() { return &(get(head_)); }
bool empty() const { return tail_ == head_; }
void clear() { head_ = 0; tail_ = 0; }
void pop() { pop_front(); }
void pop_front()
{
if (size() == 0) return;
if (size() == 1) clear();
else head_++;
}
void pop_back()
{
if (size() == 0) return;
if (size() == 1) clear();
else tail_--;
}
void push(const T& data) { push_back(data); }
void push(T&& data) { push_back(data); }
void push_back(const T& data)
{
get(tail_++) = data;
if (size() > N) ++head_;
};
void push_back(T&& data)
{
get(tail_++) = data;
if (size() > N) ++head_;
};
void push_front(const T& data)
{
get(head_--) = data;
if (size() > N) --tail_;
};
void push_front(T&& data)
{
get(head_--) = data;
if (size() > N) --tail_;
};
void emplace(const T& data) { push(data); }
void emplace(T&& data) { push(data); }
void emplace_back(const T& data) { push_back(data); }
void emplace_back(T&& data) { push_back(data); }
const T& front() const { return get(head_); };
T& front() { return get(head_); };
const T& back() const { return get(tail_ - 1); }
T& back() { return get(tail_ - 1); }
const T& operator[] (size_t index) const { return get(head_ + (int)index); }
T& operator[] (size_t index) { return get(head_ + (int)index); }
iterator begin() { return ptr(head_); }
iterator end() { return (queue_ + tail_); }
const_iterator begin() const { return (const_iterator)ptr(head_); }
const_iterator end() const { return (const_iterator)(queue_ + tail_); }
iterator erase(iterator p)
{
if (p == end()) return p;
for (T* pos = p + 1; pos != end(); ++pos)
*(pos - 1) = *pos;
--tail_;
return p;
}
void resize(size_t sz)
{
size_t s = size();
if (sz > size())
{
for (size_t i = 0; i < sz - s; ++i) push(T());
}
else if (sz < size())
{
for (size_t i = 0; i < s - sz; ++i) pop();
}
}
void assign(const_iterator first, const_iterator end)
{
clear();
const char* p = first;
while (p != end) push(*p++);
}
void shrink_to_fit()
{
// dummy
}
void reserve(size_t n)
{
(void)n;
// dummy
}
void insert(const_iterator pos, const_iterator first, const_iterator last)
{
if (pos != end())
{
size_t sz = 0;
{
iterator it = (iterator)first;
for (; it != last; ++it) ++sz;
}
iterator it = end() + sz - 1;
for (int i = sz; i > 0; --i, --it)
{
*it = *(it - sz);
}
it = (iterator)pos;
for (size_t i = 0; i < sz; ++i)
{
*it = *(first + i);
}
}
else
{
iterator it = (iterator)first;
for (; it != last; ++it)
{
push_back(*it);
}
}
}
private:
T& get(const int i)
{
if (i >= 0) return queue_[i % N];
else return queue_[N - abs(i % N)];
}
const T& get(const int i) const
{
if (i >= 0) return queue_[i % N];
else return queue_[N - abs(i % N)];
}
T* ptr(const int i)
{
if (i >= 0) return (T*)(queue_ + i % N);
else return (T*)(queue_ + N - abs(i % N));
}
const T* ptr(const int i) const
{
if (i >= 0) return (T*)(queue_ + i % N);
else return (T*)(queue_ + N - abs(i % N));
}
};
template <typename T, size_t N>
bool operator== (const RingBuffer<T, N>& x, const RingBuffer<T, N>& y)
{
if (x.size() != y.size()) return false;
for (size_t i = 0; i < x.size(); ++i)
if (x[i] != y[i]) return false;
return true;
}
template <typename T, size_t N>
bool operator!= (const RingBuffer<T, N>& x, const RingBuffer<T, N>& y)
{
return !(x == y);
}
template <typename T, size_t N = ARX_VECTOR_DEFAULT_SIZE>
struct vector : public RingBuffer<T, N>
{
vector() : RingBuffer<T, N>() { }
vector(std::initializer_list<T> lst) : RingBuffer<T, N>(lst) { }
// copy
vector(const vector& r) : RingBuffer<T, N>(r) { }
vector& operator= (const vector& r)
{
RingBuffer<T, N>::operator=(r);
return *this;
}
// move
vector(vector&& r) : RingBuffer<T, N>(r) { }
vector& operator= (vector&& r)
{
RingBuffer<T, N>::operator=(r);
return *this;
}
virtual ~vector() {}
private:
using RingBuffer<T, N>::pop;
using RingBuffer<T, N>::pop_front;
using RingBuffer<T, N>::push;
using RingBuffer<T, N>::push_front;
using RingBuffer<T, N>::emplace;
};
template <typename T, size_t N = ARX_DEQUE_DEFAULT_SIZE>
struct deque : public RingBuffer<T, N>
{
deque() : RingBuffer<T, N>() { }
deque(std::initializer_list<T> lst) : RingBuffer<T, N>(lst) { }
// copy
deque(const deque& r) : RingBuffer<T, N>(r) { }
deque& operator= (const deque& r)
{
RingBuffer<T, N>::operator=(r);
return *this;
}
// move
deque(deque&& r) : RingBuffer<T, N>(r) { }
deque& operator= (deque&& r)
{
RingBuffer<T, N>::operator=(r);
return *this;
}
virtual ~deque() {}
private:
using RingBuffer<T, N>::capacity;
using RingBuffer<T, N>::pop;
using RingBuffer<T, N>::push;
using RingBuffer<T, N>::emplace;
using RingBuffer<T, N>::assign;
using RingBuffer<T, N>::begin;
using RingBuffer<T, N>::end;
};
template <class T1, class T2>
struct pair
{
T1 first;
T2 second;
};
template <class T1, class T2>
pair<T1, T2> make_pair(const T1& t1, const T2& t2)
{
return {t1, t2};
};
template <typename T1, typename T2>
bool operator== (const pair<T1, T2>& x, const pair<T1, T2>& y)
{
return (x.first == y.first) && (x.second == y.second);
}
template <typename T1, typename T2>
bool operator!= (const pair<T1, T2>& x, const pair<T1, T2>& y)
{
return !(x == y);
}
template <class Key, class T, size_t N = ARX_MAP_DEFAULT_SIZE>
struct map : public RingBuffer<pair<Key, T>, N>
{
using iterator = typename RingBuffer<pair<Key, T>, N>::iterator;
using const_iterator = typename RingBuffer<pair<Key, T>, N>::const_iterator;
map() : RingBuffer<pair<Key, T>, N>() { }
map(std::initializer_list<pair<Key, T>> lst) : RingBuffer<pair<Key, T>, N>(lst) { }
// copy
map(const map& r) : RingBuffer<pair<Key, T>, N>(r) { }
map& operator= (const map& r)
{
RingBuffer<pair<Key, T>, N>::operator=(r);
return *this;
}
// move
map(map&& r) : RingBuffer<T, N>(r) { }
map& operator= (map&& r)
{
RingBuffer<pair<Key, T>, N>::operator=(r);
return *this;
}
virtual ~map() {}
const_iterator find(const Key& key) const
{
for (size_t i = 0; i < this->size(); ++i)
{
const_iterator it = this->begin() + i;
if (key == it->first)
return it;
}
return this->end();
}
iterator find(const Key& key)
{
for (size_t i = 0; i < this->size(); ++i)
{
iterator it = this->begin() + i;
if (key == it->first)
return it;
}
return this->end();
}
pair<iterator, bool> insert(const Key& key, const T& t)
{
bool b {false};
iterator it = find(key);
if (it == this->end())
{
this->push(make_pair(key, t));
b = true;
it = this->end() - 1;
}
return {it, b};
}
pair<iterator, bool> insert(const pair<Key, T>& p)
{
bool b {false};
const_iterator it = find(p.first);
if (it == this->end())
{
this->push(p);
b = true;
it = this->end() - 1;
}
return {(iterator)it, b};
}
pair<iterator, bool> emplace(const Key& key, const T& t)
{
return insert(key, t);
}
pair<iterator, bool> emplace(const pair<Key, T>& p)
{
return insert(p);
}
const T& at(const Key& key) const
{
// iterator it = find(key);
// if (it != this->end()) return it->second;
// return T();
return find(key)->second;
}
T& at(const Key& key)
{
// iterator it = find(key);
// if (it != this->end()) return it->second;
// return T();
return find(key)->second;
}
iterator erase(const iterator it)
{
iterator i = (iterator)find(it->first);
if (i != this->end())
{
return this->erase(i);
}
return this->end();
}
iterator erase(const size_t index)
{
if (index < this->size())
{
iterator it = this->begin() + index;
return this->erase(it);
}
return this->end();
}
T& operator[] (const Key& key)
{
iterator it = find(key);
if (it != this->end()) return it->second;
insert(::arx::make_pair(key, T()));
return this->back().second;
}
private:
using RingBuffer<pair<Key, T>, N>::capacity;
using RingBuffer<pair<Key, T>, N>::data;
using RingBuffer<pair<Key, T>, N>::pop;
using RingBuffer<pair<Key, T>, N>::pop_front;
using RingBuffer<pair<Key, T>, N>::pop_back;
using RingBuffer<pair<Key, T>, N>::push;
using RingBuffer<pair<Key, T>, N>::push_back;
using RingBuffer<pair<Key, T>, N>::push_front;
using RingBuffer<pair<Key, T>, N>::emplace_back;
using RingBuffer<pair<Key, T>, N>::front;
using RingBuffer<pair<Key, T>, N>::back;
using RingBuffer<pair<Key, T>, N>::resize;
using RingBuffer<pair<Key, T>, N>::assign;
using RingBuffer<pair<Key, T>, N>::shrink_to_fit;
};
} // namespace arx
template<typename T, size_t N>
using ArxRingBuffer = arx::RingBuffer<T, N>;
#endif // Do not have libstdc++11
#endif // ARX_RINGBUFFER_H