Added a circular_buffer object. It is like sliding_buffer except it can

have sizes which aren't powers of 2.
This commit is contained in:
Davis King 2012-03-06 20:53:37 -05:00
parent 90c897f6f0
commit cd10054144
3 changed files with 423 additions and 0 deletions

View File

@ -6,6 +6,7 @@
#include "sliding_buffer/sliding_buffer_kernel_1.h"
#include "sliding_buffer/sliding_buffer_kernel_c.h"
#include "sliding_buffer/circular_buffer.h"

View File

@ -0,0 +1,198 @@
// Copyright (C) 2012 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#ifndef DLIB_CIRCULAR_BuFFER_H__
#define DLIB_CIRCULAR_BuFFER_H__
#include "circular_buffer_abstract.h"
#include <vector>
#include "../algs.h"
#include "../serialize.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename T
>
class circular_buffer
{
public:
typedef default_memory_manager mem_manager_type;
typedef T value_type;
typedef T type;
circular_buffer()
{
offset = 0;
}
void clear (
)
{
offset = 0;
data.clear();
}
T& operator[] ( unsigned long i)
{
DLIB_ASSERT(i < size(),
"\t T& circular_buffer::operator[](i)"
<< "\n\t You have supplied an invalid index"
<< "\n\t this: " << this
<< "\n\t i: " << i
<< "\n\t size(): " << size()
);
return data[(i+offset)%data.size()];
}
const T& operator[] ( unsigned long i) const
{
DLIB_ASSERT(i < size(),
"\t const T& circular_buffer::operator[](i)"
<< "\n\t You have supplied an invalid index"
<< "\n\t this: " << this
<< "\n\t i: " << i
<< "\n\t size(): " << size()
);
return data[(i+offset)%data.size()];
}
void resize(unsigned long size, const T& value = T()) { data.resize(size,value); }
void assign(unsigned long size, const T& value) { data.assign(size,value); }
unsigned long size() const { return data.size(); }
void push_front(const T& value)
{
if (data.size() != 0)
{
offset = (offset - 1 + data.size())%data.size();
data[offset] = value;
}
}
void push_back(const T& value)
{
if (data.size() != 0)
{
data[offset] = value;
offset = (offset + 1 + data.size())%data.size();
}
}
T& front(
)
{
DLIB_CASSERT(size() > 0,
"\t T& circular_buffer::front()"
<< "\n\t You can't call front() on an empty circular_buffer"
<< "\n\t this: " << this
);
return (*this)[0];
}
const T& front(
) const
{
DLIB_CASSERT(size() > 0,
"\t const T& circular_buffer::front()"
<< "\n\t You can't call front() on an empty circular_buffer"
<< "\n\t this: " << this
);
return (*this)[0];
}
T& back(
)
{
DLIB_CASSERT(size() > 0,
"\t T& circular_buffer::back()"
<< "\n\t You can't call back() on an empty circular_buffer"
<< "\n\t this: " << this
);
return (*this)[size()-1];
}
const T& back(
) const
{
DLIB_CASSERT(size() > 0,
"\t const T& circular_buffer::back()"
<< "\n\t You can't call back() on an empty circular_buffer"
<< "\n\t this: " << this
);
return (*this)[size()-1];
}
private:
std::vector<T> data;
unsigned long offset;
};
// ----------------------------------------------------------------------------------------
template <
typename T
>
void swap (
circular_buffer<T>& a,
circular_buffer<T>& b
) { a.swap(b); }
// ----------------------------------------------------------------------------------------
template <
typename T
>
void serialize (
const circular_buffer<T>& item,
std::ostream& out
)
{
try
{
serialize(item.size(),out);
for (unsigned long i = 0; i < item.size(); ++i)
serialize(item[i],out);
}
catch (serialization_error& e)
{
throw serialization_error(e.info + "\n while serializing object of type circular_buffer");
}
}
// ----------------------------------------------------------------------------------------
template <
typename T
>
void deserialize (
circular_buffer<T>& item,
std::istream& in
)
{
try
{
unsigned long size;
deserialize(size,in);
item.resize(size);
for (unsigned long i = 0; i < size; ++i)
deserialize(item[i],in);
}
catch (serialization_error& e)
{
item.clear();
throw serialization_error(e.info + "\n while deserializing object of type circular_buffer");
}
}
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CIRCULAR_BuFFER_H__

View File

@ -0,0 +1,224 @@
// Copyright (C) 2012 Davis E. King (davis@dlib.net)
// License: Boost Software License See LICENSE.txt for the full license.
#undef DLIB_CIRCULAR_BuFFER_ABSTRACT_H__
#ifdef DLIB_CIRCULAR_BuFFER_ABSTRACT_H__
#include "../algs.h"
#include "../serialize.h"
namespace dlib
{
// ----------------------------------------------------------------------------------------
template <
typename T
>
class circular_buffer
{
/*!
REQUIREMENTS ON T
T must have a default constructor and be copyable.
POINTERS AND REFERENCES TO INTERNAL DATA
swap(), size(), front(), back(), and operator[] functions do
not invalidate pointers or references to internal data.
All other functions have no such guarantee.
INITIAL VALUE
- size() == 0
WHAT THIS OBJECT REPRESENTS
This object is a circular buffer. This means that when objects
are pushed onto one of its ends it does not grow in size. Instead,
it shifts all elements over one to make room for the new element
and the element at the opposing end falls off the buffer and is
lost.
!*/
public:
typedef default_memory_manager mem_manager_type;
typedef T value_type;
typedef T type;
circular_buffer(
);
/*!
ensures
- #size() == 0
- this object is properly initialized
!*/
void clear (
);
/*!
ensures
- this object has its initial value
- #size() == 0
!*/
T& operator[] (
unsigned long i
) const;
/*!
requires
- i < size()
ensures
- returns a non-const reference to the i-th element of this circular buffer
!*/
const T& operator[] (
unsigned long i
) const;
/*!
requires
- i < size()
ensures
- returns a const reference to the i-th element of this circular buffer
!*/
void resize(
unsigned long new_size,
const T& c = T()
);
/*!
ensures
- #size() == new_size
- any element with index between 0 and new_size - 1 which was in the
circular_buffer before the call to resize() retains its value and index.
All other elements have a value given by c.
!*/
unsigned long size(
) const;
/*!
ensures
- returns the number of elements in this circular buffer
!*/
T& front(
);
/*!
requires
- size() > 0
ensures
- returns a reference to (*this)[0]
!*/
const T& front(
) const;
/*!
requires
- size() > 0
ensures
- returns a const reference to (*this)[0]
!*/
T& back(
);
/*!
requires
- size() > 0
ensures
- returns a reference to (*this)[size()-1]
!*/
const T& back(
) const;
/*!
requires
- size() > 0
ensures
- returns a const reference to (*this)[size()-1]
!*/
void push_front(
const T& value
);
/*!
ensures
- #size() == size()
(i.e. the size of this object does not change)
- if (size() != 0) then
- #front() == value
- all items are shifted over such that,
- #(*this)[1] == (*this)[0]
- #(*this)[2] == (*this)[1]
- #(*this)[3] == (*this)[2]
- etc.
- back() is shifted out of the circular buffer
- else
- This function has no effect on this object
!*/
void push_back(
const T& value
);
/*!
ensures
- #size() == size()
(i.e. the size of this object does not change)
- if (size() != 0) then
- #back() == value
- all items are shifted over such that,
- front() is shifted out of the circular buffer
- #(*this)[0] == (*this)[1]
- #(*this)[1] == (*this)[2]
- #(*this)[2] == (*this)[3]
- etc.
- else
- This function has no effect on this object
!*/
void swap (
circular_buffer& item
);
/*!
ensures
- swaps *this with item
!*/
};
// ----------------------------------------------------------------------------------------
template <
typename T
>
void swap (
circular_buffer<T>& a,
circular_buffer<T>& b
) { a.swap(b); }
/*!
provides a global swap function
!*/
template <
typename T
>
void serialize (
const circular_buffer<T>& item,
std::ostream& out
);
/*!
provides serialization support
!*/
template <
typename T
>
void deserialize (
circular_buffer<T>& item,
std::istream& in
);
/*!
provides deserialization support
!*/
// ----------------------------------------------------------------------------------------
}
#endif // DLIB_CIRCULAR_BuFFER_ABSTRACT_H__