In article <[EMAIL PROTECTED]>, Alisdair Meredith <[EMAIL PROTECTED]> wrote:
| "The one true circular buffer template" is a nigh impossible goal, | because it means so many things to different people. <snip> | I would certainly like the documentation to explain the tradeoffs made | in the implementation, and why this particular variation was chosen as | most appropriate for the general case. Indeed! Excellent post! Perhaps container adaptors could be applied to a sufficiently generalized circular buffer. What is the one true queue? There isn't one. It is best a container adaptor (policy based if you prefer). I suspect that a more general circular buffer, restricted by various adaptors, might serve more uses with less code. The circular buffer I've needed (and coded) fits none of aforementioned descriptions. But it is a circular buffer nonetheless. For my money, the general circular buffer is one that exists in a contiguous array, but with an arbitrary begin and end within that array, capable of wrapping around the end of the physical memory: +---+---+---+---+---+---+---+---+---+---+ | 4 | 5 | | | | | 0 | 1 | 2 | 3 | +---+---+---+---+---+---+---+---+---+---+ ^ ^ | | end begin Constant time push/pop_front, constant time push/pop_back. When begin and end collide, reallocation automatically happens vector-like. This data structure can be efficiently coded with a 4-word data structure. For example: data_ptr, capacity, size, begin_ptr (there are other variations that also only take 4 words). >From this you can write adaptors to constrain capacity, have push_back overwrite front(), throw an exception on size() exceeding capacity(), or whatever else you need to do. You can't adapt any other std::container to do this job because vector is the only one with capacity, but vector doesn't have a constant time push/pop_front. But I believe you can adapt the above described container to meet the needs of other "circular buffer" requirements. For example: template <class T, class Container = general_cyclic_buffer<T> > class my_cyclic_buffer { public: // typedefs ... my_cyclic_buffer(size_type cap) {c.reserve(cap);} reference operator[](size_type n) {return c[n];} // etc. void push_back(const value_type& x) { if (capacity() != 0) { if (c.size() == c.capacity()) c.pop_front(); c.push_back(x); } } change_capacity(size_type new_cap) { if (new_cap > c.capacity()) c.reserve(new_cap); else if (new_cap < c.capacity()) { c.erase(c.begin(), c.begin() + c.size() - new_cap); Container tmp(c); // assumes tmp.capacity() == c.size() c.swap(tmp); } } // etc. private: Container c; }; -- Howard Hinnant Metrowerks _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost