diff --git a/doc/circular_buffer.html b/doc/circular_buffer.html index 64966e3..c01040f 100644 --- a/doc/circular_buffer.html +++ b/doc/circular_buffer.html @@ -1,8 +1,7 @@ - +
- +- In general the term circular buffer refers to an area in memory which is used to store incoming data. When the buffer is filled, new data is written starting at the beginning - of the buffer and overwriting the old. [1] (Also see the Figure.) + In general the term circular buffer refers to an area in memory which is used to store incoming data. When + the buffer is filled, new data is written starting at the beginning of the buffer and overwriting the old. + [1] (Also see the Figure.)
- The circular_buffer is a STL compliant container. It is a kind of sequence similar to std::vector or std::deque. It supports random access
- iterators, constant time insert and erase operations at the beginning or the end of the buffer and interoperability with std algorithms. The circular_buffer
- is especially designed to provide fixed capacity storage. When its capacity is exhausted, newly inserted elements will cause elements either at the beginning or end of the buffer
+ The circular_buffer is a STL compliant container. It is a kind of sequence similar to
+ std::vector or std::deque. It supports random access iterators, constant time insert
+ and erase operations at the beginning or the end of the buffer and interoperability with std
+ algorithms. The circular_buffer is especially designed to provide fixed capacity storage. When its
+ capacity is exhausted, newly inserted elements will cause elements either at the beginning or end of the buffer
(depending on what insert operation is used) to be overwritten.
- The circular_buffer only allocates memory when created, when the capacity is adjusted explicitly, or as necessary to accommodate resizing or assign operations. On the
- other hand, there is also a circular_buffer_space_optimized available. It is an adaptor of the
- circular_buffer which does not allocate memory at once when created, rather it allocates memory as needed.
+ The circular_buffer only allocates memory when created, when the capacity is adjusted explicitly, or
+ as necessary to accommodate resizing or assign operations. On the other hand, there is also a circular_buffer_space_optimized available. It is an adaptor of
+ the circular_buffer which does not allocate memory at once when created, rather it allocates memory
+ as needed.
A brief example using the circular_buffer:
@@ -131,7 +135,7 @@
}
- The basic motivation behind the circular_buffer was to create a container which would work seamlessly with STL. Additionally, the design of the
- circular_buffer was guided by the following principles:
+ The basic motivation behind the circular_buffer was to create a container which would work
+ seamlessly with STL. Additionally, the design of the circular_buffer was guided by the following
+ principles:
circular_buffer_space_optimized is such an example of
- the adaptor.)
+ Suitable for specialization by means of adaptors. (The circular_buffer_space_optimized is such an example of the
+ adaptor.)
- In order to achieve maximum efficiency, the circular_buffer stores its elements in a contiguous region of memory, which then enables:
+ In order to achieve maximum efficiency, the circular_buffer stores its elements in a contiguous
+ region of memory, which then enables:
- The following paragraphs describe issues that had to be considered during the implemenation of the circular_buffer:
+ The following paragraphs describe issues that had to be considered during the implemenation of the
+ circular_buffer:
- The thread-safety of the circular_buffer is the same as the thread-safety of containers in most STL implementations. This means the circular_buffer is
- thread-safe only in the sense that simultaneous accesses to distinct instances of the circular_buffer are safe, and simultaneous read accesses to a shared
- circular_buffer are safe.
+ The thread-safety of the circular_buffer is the same as the thread-safety of containers in most STL
+ implementations. This means the circular_buffer is thread-safe only in the sense that simultaneous
+ accesses to distinct instances of the circular_buffer are safe, and simultaneous read accesses to a
+ shared circular_buffer are safe.
- If multiple threads access a single circular_buffer, and at least one of the threads may potentially write, then the user is responsible for ensuring mutual exclusion
- between the threads during the container accesses. The mutual exclusion between the threads can be achieved by wrapping operations of the underlying circular_buffer with
- a lock acquisition and release. (See the Bounded Buffer Example.)
+ If multiple threads access a single circular_buffer, and at least one of the threads may potentially
+ write, then the user is responsible for ensuring mutual exclusion between the threads during the container
+ accesses. The mutual exclusion between the threads can be achieved by wrapping operations of the underlying
+ circular_buffer with a lock acquisition and release. (See the Bounded
+ Buffer Example.)
- Overwrite operation occurs when an element is inserted into a full circular_buffer - the old element is being overwriten by the new one. There was a discussion what
- exactly "overwriting of an element" means during the formal review. It may be either a destruction of the original element and a consequent inplace construction of a new element or it
- may be an assignment of a new element into an old one. The circular_buffer implements assignment because it is more effective.
+ Overwrite operation occurs when an element is inserted into a full circular_buffer - the old element
+ is being overwriten by the new one. There was a discussion what exactly "overwriting of an element"
+ means during the formal review. It may be either a destruction of the original element and a consequent inplace
+ construction of a new element or it may be an assignment of a new element into an old one. The
+ circular_buffer implements assignment because it is more effective.
- From the point of business logic of a stored element, the destruction/construction operation and assignment usually mean the same. However, in very rare cases (if in any) they may - differ. If there is a requirement for elements to be destructed/constructed instead of being assigned, consider implementing a wrapper of the element which would implement the assign - operator, and store the wrappers instead. It is necessary to note that storing such wrappers has a drawback. The destruction/construction will be invoked on every assignment of the - wrapper - not only when a wrapper is being overwritten (when the buffer is full) but also when the stored wrappers are being shifted (e.g. as a result of insertion into the middle of - container). + From the point of business logic of a stored element, the destruction/construction operation and assignment + usually mean the same. However, in very rare cases (if in any) they may differ. If there is a requirement for + elements to be destructed/constructed instead of being assigned, consider implementing a wrapper of the element + which would implement the assign operator, and store the wrappers instead. It is necessary to note that storing + such wrappers has a drawback. The destruction/construction will be invoked on every assignment of the wrapper - + not only when a wrapper is being overwritten (when the buffer is full) but also when the stored wrappers are + being shifted (e.g. as a result of insertion into the middle of container).
- There are several options how to cope with the case if a data source produces more data than can fit in the fixed-sized buffer: + There are several options how to cope with the case if a data source produces more data than can fit in the + fixed-sized buffer:
- It is apparent that the circular_buffer implements the third option. But it may be less apparent it does not implement any other option - especially the first two.
- One can get an impression that the circular_buffer should implement first three options and offer a mechanism of choosing among them. This impression is wrong. The
- circular_buffer was designed and optimized to be circular (which means overwriting the oldest data when full). If such a controlling mechanism had been enabled, it would
- just complicate the matters and the usage of the circular_buffer would be probably less straightforward.
+ It is apparent that the circular_buffer implements the third option. But it may be less apparent it
+ does not implement any other option - especially the first two. One can get an impression that the
+ circular_buffer should implement first three options and offer a mechanism of choosing among them.
+ This impression is wrong. The circular_buffer was designed and optimized to be circular (which means
+ overwriting the oldest data when full). If such a controlling mechanism had been enabled, it would just
+ complicate the matters and the usage of the circular_buffer would be probably less straightforward.
- Moreover, the first two options (and the fouth option as well) do not require the buffer to be circular at all. If there is a need for the first or second option, consider
- implementing an adaptor of e.g. std::vector. In this case the circular_buffer is not suitable for adapting, because, in contrary to std::vector,
- it bears an overhead for its circular behavior.
+ Moreover, the first two options (and the fouth option as well) do not require the buffer to be circular at all.
+ If there is a need for the first or second option, consider implementing an adaptor of e.g.
+ std::vector. In this case the circular_buffer is not suitable for adapting, because, in
+ contrary to std::vector, it bears an overhead for its circular behavior.
- When reading or removing an element from an empty buffer, the buffer should be able to notify the data consumer (e.g. by throwing underflow exception) that there are no elements
- stored in it. The circular_buffer does not implement such a behaviour for two reasons:
+ When reading or removing an element from an empty buffer, the buffer should be able to notify the data consumer
+ (e.g. by throwing underflow exception) that there are no elements stored in it. The circular_buffer
+ does not implement such a behaviour for two reasons:
- It is considered to be a bug to read or remove an element (e.g. by calling front() or pop_back()) from an empty std container and from an emtpy
- circular_buffer as well. The data consumer has to test if the container is not empty before reading/removing from it. However, when reading from the
- circular_buffer, there is an option to rely on the at() method which throws an exception when the index is out of range.
+ It is considered to be a bug to read or remove an element (e.g. by calling front() or
+ pop_back()) from an empty std container and from an emtpy circular_buffer
+ as well. The data consumer has to test if the container is not empty before reading/removing from it. However,
+ when reading from the circular_buffer, there is an option to rely on the at() method
+ which throws an exception when the index is out of range.
- An iterator is usually considered to be invalidated if an element, the iterator pointed to, had been removed or overwritten by an another element. This definition is enforced by the
- Debug Support and refered as strict in the source code documentation. However, some applications utilizing circular_buffer may require less
- strict definition: an iterator is invalid only if it points to an uninitialized memory. Consider following example:
+ An iterator is usually considered to be invalidated if an element, the iterator pointed to, had been removed or
+ overwritten by an another element. This definition is enforced by the Debug Support and
+ refered as strict in the source code documentation. However, some applications utilizing
+ circular_buffer may require less strict definition: an iterator is invalid only if it points to an
+ uninitialized memory. Consider following example:
#define BOOST_CB_DISABLE_DEBUG // The Debug Support has to be disabled, otherwise the code produces a runtime error.
@@ -435,27 +477,31 @@ template <class T, class Alloc>
}
- The iterator does not point to the original element any more (and is considered to be invalid from the "strict" point of view) but it still points to the same valid place in - the memory. This meaning of iterator invalidation is then marked as loose in the source code documentation. + The iterator does not point to the original element any more (and is considered to be invalid from the + "strict" point of view) but it still points to the same valid place in the memory. This + meaning of iterator invalidation is then marked as loose in the source code documentation.
- The circular_buffer is defined in the file boost/circular_buffer.hpp . There is also a forward declaration
- for the circular_buffer in the header file boost/circular_buffer_fwd.hpp .
+ The circular_buffer is defined in the file boost/circular_buffer.hpp . There is also a forward declaration
+ for the circular_buffer in the header file boost/circular_buffer_fwd.hpp .
- Random AccessContainer, Front Insertion - Sequence and Back Insertion Sequence. + Random AccessContainer, Front Insertion Sequence and Back Insertion Sequence.
- T
+ T
|
The type of the elements stored in the circular buffer. @@ -481,7 +527,7 @@ template <class T, class Alloc> | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- Alloc
+ Alloc
|
The allocator type used for all internal memory management.
@@ -494,7 +540,7 @@ template <class T, class Alloc>
- Public Types + Public Types
|