Boost logo

Boost Users :

Subject: Re: [Boost-users] circular_buffer::erase in constant time
From: Luca Cappa (luca.cappa_at_[hidden])
Date: 2009-09-25 04:12:59


Hi Gaspar,

Thanks for your answer.

On Thu, 24 Sep 2009 23:01:44 +0200, Jan Gaspar <jano_gaspar_at_[hidden]>
wrote:
>> /// Erase the first pCount element from the buffer
>> void begin_erase (size_t pCount)
>> {
>> BOOST_ASSERT(pCount <= size ());
>> circular_buffer<Type>::add (m_first, pCount);
>> m_size -= pCount;;
>> }
> What you are suggesting here is linear in pCount.

No, it is not linear, it is constant. Basically there are two additions
which modify the value of m_first and m_size,
and not loop whatsoever. Of course, one line of code should be

m_first = circular_buffer<Type>::add (m_first, pCount);

to really modify the m_first value.

Basically, if you have a circular buffer of 'int's, with capacity 4:

1) the empy buffer looks like this

| first/last _ | _ | _ | _ |

where 'first' is the pointer (or call it index) to the first busy bucket,
and 'last' is the 'after the last occupied' bucket. '_' are free buckets.

2) after inserting the items (1,2,3) the buffer looks like:

| first 1 | 2 | 3 | last |

3) after inserting the item '4' (now the buffer is full):

| first/last 1 | 2 | 3 | 4 |

4) now if you erase the first three elements:

| last _ | _ | _ | first 4 |

This is what happen with my own circular buffer class. With
boost::circular_buffer instead the result of erasing the first three
elements is:

| first 4 | last | _ | _ |

> It is actually equivalent of erase(begin(), begin() + pCount).

As shown above, it is not the same: in fact erase(begin(), begin
()+pCount) does this:

iterator erase(iterator first, iterator last)
{
[...]
         pointer p = first.m_it;
/// Replace the elements in the range [first, last) with the elements in
the range [last, last - first + last)
         while (last.m_it != 0)
             replace((first++).m_it, *last++);
/// Destroy the elements in the range [last, last - first + last) (i.e.
destroy the just moved elements).
         do {
             decrement(m_last);
             destroy_item(m_last);
             --m_size;
         } while(m_last != first.m_it);
[...]
}

In my case, the elements are primitive type (int/float/double), or some
class which does not need any destruction, so that loop is completely
useless. The erasing could be simply done moving forward (and wrapping if
needed) the m_first pointer.

I hope this is more clearly explained now.

Greetings,
Luca


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net