//---------------------------------------------------------------------------- /// @file circular_buffer.hpp /// @brief This file contains the implementation of the circular buffer /// /// @author Copyright (c) 2010 2015 Francisco José Tapia (fjtapia@gmail.com )\n /// Distributed under the Boost Software License, Version 1.0.\n /// ( See accompanyingfile LICENSE_1_0.txt or copy at /// http://www.boost.org/LICENSE_1_0.txt ) /// @version 0.1 /// /// @remarks //----------------------------------------------------------------------------- #ifndef __BOOST_SORT_COMMON_UTIL_CIRCULAR_BUFFER_HPP #define __BOOST_SORT_COMMON_UTIL_CIRCULAR_BUFFER_HPP #include #include #include #include #include namespace boost { namespace sort { namespace common { namespace util { //--------------------------------------------------------------------------- /// @class circular_buffer /// @brief This class implement a circular buffer /// @remarks //--------------------------------------------------------------------------- template struct circular_buffer { //------------------------------------------------------------------------ // STATIC CHECK //------------------------------------------------------------------------ static_assert ( Power2 != 0, "Wrong Power2"); //------------------------------------------------------------------------ // DEFINITIONS //------------------------------------------------------------------------ typedef Value_t value_t; //------------------------------------------------------------------------ // VARIABLES //------------------------------------------------------------------------ const size_t NMAX = (size_t) 1 << Power2; const size_t MASK = (NMAX - 1); const size_t BLOCK_SIZE = NMAX >> 1; const size_t LOG_BLOCK = Power2 - 1; Value_t * ptr = nullptr; //------------------------------------------------------------------------ // first and last are the position of the first and last elements // always are in the range [0, NMAX - 1] //------------------------------------------------------------------------ size_t nelem, first_pos; bool initialized; // //------------------------------------------------------------------------ // function : circular_buffer /// @brief constructor of the class //----------------------------------------------------------------------- circular_buffer(void) : ptr(nullptr), nelem(0), first_pos(0), initialized(false) { ptr = std::get_temporary_buffer < Value_t > (NMAX).first; if (ptr == nullptr) throw std::bad_alloc(); }; // //------------------------------------------------------------------------ // function : ~circular_buffer /// @brief destructor of the class //----------------------------------------------------------------------- ~circular_buffer() { if (initialized) { for (size_t i = 0; i < NMAX; ++i) (ptr + i)->~Value_t(); initialized = false; }; std::return_temporary_buffer(ptr); } ; // //------------------------------------------------------------------------ // function : initialize /// @brief : initialize the memory of the buffer from the uninitialize // memory obtained from the temporary buffer /// @param val : value used to initialize the memory //----------------------------------------------------------------------- void initialize(Value_t & val) { assert (initialized == false); ::new (static_cast(ptr)) Value_t(std::move(val)); for (size_t i = 1; i < NMAX; ++i) ::new (static_cast(ptr + i)) Value_t(std::move(ptr[i - 1])); val = std::move(ptr[NMAX - 1]); initialized = true; }; // //------------------------------------------------------------------------ // function : destroy_all /// @brief : destroy all the objects in the internal memory //----------------------------------------------------------------------- void destroy_all(void) { destroy(ptr, ptr + NMAX); }; // //------------------------------------------------------------------------ // function : get_buffer /// @brief return the internal memory of the circular buffer /// @return pointer to the internal memory of the buffer //----------------------------------------------------------------------- Value_t * get_buffer(void) { return ptr; }; // //------------------------------------------------------------------------ // function : empty /// @brief return if the buffer is empty /// @return true : empty //----------------------------------------------------------------------- bool empty(void) const {return (nelem == 0); }; // //------------------------------------------------------------------------ // function : full /// @brief return if the buffer is full /// @return true : full //----------------------------------------------------------------------- bool full(void) const { return (nelem == NMAX); }; // //------------------------------------------------------------------------ // function : size /// @brief return the number of elements stored in the buffer /// @return number of elements stored //----------------------------------------------------------------------- size_t size(void) const { return nelem;}; // //------------------------------------------------------------------------ // function : capacity /// @brief : return the maximun capacity of the buffer /// @return number of elements //----------------------------------------------------------------------- size_t capacity(void) const { return NMAX;}; // //------------------------------------------------------------------------ // function : free_size /// @brief return the free positions in the buffer /// @return number of elements //----------------------------------------------------------------------- size_t free_size(void) const { return (NMAX - nelem); }; // //------------------------------------------------------------------------ // function : clear /// @brief clear the buffer //----------------------------------------------------------------------- void clear(void) { nelem = first_pos = 0; }; // //------------------------------------------------------------------------ // function : front /// @brief return the first element of the buffer /// @return reference to the first value //----------------------------------------------------------------------- Value_t & front(void) { #ifdef __BS_DEBUG assert (nelem > 0); #endif return (ptr[first_pos]); }; // //------------------------------------------------------------------------ // function :front /// @brief return the first element of the buffer /// @return const reference to the first value //----------------------------------------------------------------------- const Value_t & front(void) const { #ifdef __BS_DEBUG assert ( nelem > 0 ); #endif return (ptr[first_pos]); }; // //------------------------------------------------------------------------ // function : back /// @brief reference to the last value of the buffer /// @return reference to the last value //----------------------------------------------------------------------- Value_t & back(void) { #ifdef __BS_DEBUG assert ( nelem > 0 ); #endif return (ptr[(first_pos + nelem - 1) & MASK]); }; // //------------------------------------------------------------------------ // function : back /// @brief reference to the last value of the buffer /// @return const reference to the last value //----------------------------------------------------------------------- const Value_t & back(void) const { #ifdef __BS_DEBUG assert ( nelem > 0 ); #endif return (ptr[(first_pos + nelem - 1) & MASK]); }; // //------------------------------------------------------------------------ // function : operator [] /// @brief positional access to the elements /// @param pos rquested /// @return reference to the element //----------------------------------------------------------------------- Value_t & operator[](uint32_t pos) { #ifdef __BS_DEBUG assert ( nelem > 0 ); #endif return ptr[(first_pos + pos) & MASK]; }; // //------------------------------------------------------------------------ // function : operator [] /// @brief positional access to the elements /// @param pos rquested /// @return const reference to the element //----------------------------------------------------------------------- const Value_t & operator[](uint32_t pos) const { #ifdef __BS_DEBUG assert ( nelem > 0 ); #endif return ptr[(first_pos + pos) & MASK]; }; // //------------------------------------------------------------------------ // function : push_front /// @brief insert an element in the first position of the buffer /// @param val : const value to insert //----------------------------------------------------------------------- void push_front(const Value_t & val) { #ifdef __BS_DEBUG assert ( nelem != NMAX); #endif ++nelem; first_pos = ((first_pos + MASK) & MASK); ptr[first_pos] = val; }; // //------------------------------------------------------------------------ // function : push_front /// @brief insert an element in the first position of the buffer /// @param val : rvalue to insert //----------------------------------------------------------------------- void push_front(Value_t && val) { #ifdef __BS_DEBUG assert ( nelem != NMAX); #endif ++nelem; first_pos = ((first_pos + MASK) & MASK); ptr[first_pos] = val; }; // //------------------------------------------------------------------------ // function : push_back /// @brief insert an element in the last position of the buffer /// @param val : value to insert //----------------------------------------------------------------------- void push_back(const Value_t & val) { #ifdef __BS_DEBUG assert ( nelem != NMAX); #endif ptr[(first_pos + (nelem++)) & MASK] = val; }; // //------------------------------------------------------------------------ // function : push_back /// @brief insert an element in the last position of the buffer /// @param val : value to insert //----------------------------------------------------------------------- void push_back(Value_t && val) { #ifdef __BS_DEBUG assert ( nelem != NMAX); #endif ptr[(first_pos + (nelem++)) & MASK] = std::move(val); }; // //------------------------------------------------------------------------ // function : pop_front /// @brief remove the first element of the buffer //----------------------------------------------------------------------- void pop_front(void) { #ifdef __BS_DEBUG assert ( nelem > 0 ); #endif --nelem; (++first_pos) &= MASK; }; // //------------------------------------------------------------------------ // function : pop_back /// @brief remove the last element of the buffer //----------------------------------------------------------------------- void pop_back(void) { #ifdef __BS_DEBUG assert ( nelem > 0 ); #endif --nelem; }; template void pop_copy_front(iter_t it_dest, size_t num); template void pop_move_front(iter_t it_dest, size_t num); template void pop_copy_back(iter_t it_dest, size_t num); template void pop_move_back(iter_t it_dest, size_t num); template void push_copy_front(iter_t it_src, size_t num); template void push_move_front(iter_t it_src, size_t num); template void push_copy_back(iter_t it_src, size_t num); template void push_move_back(iter_t it_src, size_t num); //--------------------------------------------------------------------------- };// End of class circular_buffer //--------------------------------------------------------------------------- // // //############################################################################ // ## // N O N I N L I N E F U N C T I O N S ## // ## //############################################################################ // //------------------------------------------------------------------------ // function : pop_copy_front /// @brief copy and delete num elements from the front of the buffer /// @param it_dest : iterator to the first position where copy the elements /// @param num : number of elements to copy //----------------------------------------------------------------------- template template void circular_buffer ::pop_copy_front(iter_t it_dest, size_t num) { static_assert ( std::is_same , Value_t>::value, "Incompatible iterator"); if (num == 0) return; #ifdef __BS_DEBUG assert ( num <= nelem); #endif nelem -= num; size_t pos = first_pos; first_pos = (first_pos + num) & MASK; for (size_t i = 0; i < num; ++i) { *(it_dest++) = ptr[pos++ & MASK]; }; first_pos &= MASK; }; // //------------------------------------------------------------------------ // function : pop_move_front /// @brief move num elements from the front of the buffer to the place // pointed by it_dest /// @param it_dest : iterator to the first position where move the elements /// @param num : number of elements to move //----------------------------------------------------------------------- template template void circular_buffer :: pop_move_front(iter_t it_dest, size_t num) { static_assert ( std::is_same , Value_t>::value, "Incompatible iterator"); if (num == 0) return; #ifdef __BS_DEBUG assert ( num <= nelem); #endif nelem -= num; size_t pos = first_pos; first_pos = (first_pos + num) & MASK; for (size_t i = 0; i < num; ++i) { *(it_dest++) = std::move(ptr[pos++ & MASK]); }; first_pos &= MASK; }; // //------------------------------------------------------------------------ // function : pop_copy_back /// @brief copy and delete num elements from the back of the buffer /// @param p1 : iterator where begin to copy the elements /// @param num : number of elements to copy //----------------------------------------------------------------------- template template void circular_buffer ::pop_copy_back(iter_t it_dest, size_t num) { static_assert ( std::is_same , Value_t>::value, "Incompatible iterator"); if (num == 0) return; #ifdef __BS_DEBUG assert ( num <= nelem); #endif nelem -= num; size_t pos = (first_pos + nelem) & MASK; for (size_t i = 0; i < num; ++i) { *(it_dest++) = ptr[pos++ & MASK]; }; }; // //------------------------------------------------------------------------ // function : pop_move_back /// @brief move and delete num elements from the back of the buffer /// @param p1 : iterator where begin to move the elements /// @param num : number of elements to move //----------------------------------------------------------------------- template template void circular_buffer ::pop_move_back(iter_t it_dest, size_t num) { static_assert ( std::is_same , Value_t>::value, "Incompatible iterator"); if (num == 0) return; #ifdef __BS_DEBUG assert ( num <= nelem); #endif nelem -= num; size_t pos = (first_pos + nelem) & MASK; for (size_t i = 0; i < num; ++i) { *(it_dest++) = std::move(ptr[pos++ & MASK]); }; }; // //------------------------------------------------------------------------ // function : push_copy_front /// @brief copy num elements in the front of the buffer /// @param it_src : iterator from where begin to copy the elements /// @param mun : number of element to copy //----------------------------------------------------------------------- template template void circular_buffer ::push_copy_front(iter_t it_src, size_t num) { static_assert ( std::is_same , Value_t>::value, "Incompatible iterator"); if (num == 0) return; #ifdef __BS_DEBUG assert ( free_size() >= num); #endif nelem += num; first_pos = (first_pos + NMAX - num) & MASK; size_t pos = first_pos; for (size_t i = 0; i < num; ++i) { ptr[(pos++) & MASK] = *(it_src++); }; }; // //------------------------------------------------------------------------ // function : push_move_front /// @brief move num elements in the front of the buffer /// @param p1 : iterator from where begin to move the elements /// @param mun : number of element to move //----------------------------------------------------------------------- template template void circular_buffer ::push_move_front(iter_t it_src, size_t num) { static_assert ( std::is_same , Value_t>::value, "Incompatible iterator"); if (num == 0) return; #ifdef __BS_DEBUG assert ( free_size() >= num); #endif nelem += num; size_t pos = first_pos; for (size_t i = 0; i < num; ++i) { ptr[(pos++) & MASK] = std::move(*(it_src++)); }; }; // //------------------------------------------------------------------------ // function : push_copy_back /// @brief copy num elements in the back of the buffer /// @param p1 : iterator from where begin to copy the elements /// @param mun : number of element to copy //----------------------------------------------------------------------- template template void circular_buffer ::push_copy_back(iter_t it_src, size_t num) { static_assert ( std::is_same , Value_t>::value, "Incompatible iterator"); if (num == 0) return; #ifdef __BS_DEBUG assert ( free_size() >= num); #endif size_t pos = first_pos + nelem; nelem += num; for (size_t i = 0; i < num; ++i) { ptr[(pos++) & MASK] = *(it_src++); }; }; // //------------------------------------------------------------------------ // function : push_move_back /// @brief move num elements in the back of the buffer /// @param p1 : iterator from where begin to move the elements /// @param mun : number of element to move //----------------------------------------------------------------------- template template void circular_buffer ::push_move_back(iter_t it_src, size_t num) { static_assert ( std::is_same , Value_t>::value, "Incompatible iterator"); if (num == 0) return; #ifdef __BS_DEBUG assert ( free_size() >= num); #endif size_t pos = first_pos + nelem; nelem += num; for (size_t i = 0; i < num; ++i) { ptr[(pos++) & MASK] = std::move(*(it_src++)); }; }; //**************************************************************************** };// End namespace util };// End namespace common };// End namespace sort };// End namespace boost //**************************************************************************** #endif