Boost C++ Libraries of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards


Design Topics

String Representation
Sequence Traits
Find Algorithms
Replace Algorithms
Find Iterators & Split Algorithms
Exception Safety

String Representation

As the name suggest, this library works mainly with strings. However, in the context of this library, a string is not restricted to any particular implementation (like std::basic_string), rather it is a concept. This allows the algorithms in this library to be reused for any string type, that satisfies the given requirements.

Definition: A string is a range of characters accessible in sequential ordered fashion. Character is any value type with "cheap" copying and assignment.

First requirement of string-type is that it must accessible using Boost.Range. This facility allows to access the elements inside the string in a uniform iterator-based fashion. This is sufficient for our library

Second requirement defines the way in which the characters are stored in the string. Algorithms in this library work with an assumption that copying a character is cheaper then allocating extra storage to cache results. This is a natural assumption for common character types. Algorithms will work even if this requirement is not satisfied, however at the cost of performance degradation.

In addition some algorithms have additional requirements on the string-type. Particularly, it is required that an algorithm can create a new string of the given type. In this case, it is required that the type satisfies the sequence (Std §23.1.1) requirements.

In the reference and also in the code, requirement on the string type is designated by the name of template argument. RangeT means that the basic range requirements must hold. SequenceT designates extended sequence requirements.

Sequence Traits

The major difference between std::list and std::vector is not in the interfaces they provide, but rather in the inner details of the class and the way how it performs various operations. The problem is that it is not possible to infer this difference from the definitions of classes without some special mechanism. However, some algorithms can run significantly faster with the knowledge of the properties of a particular container.

Sequence traits allow one to specify additional properties of a sequence container (see Std.§32.2). These properties are then used by algorithms to select optimized handling for some operations. The sequence traits are declared in the header boost/algorithm/string/sequence_traits.hpp.

In the table C denotes a container and c is an object of C.

Table 30.12. Sequence Traits

Trait Description
has_native_replace<C>::value Specifies that the sequence has std::string like replace method
has_stable_iterators<C>::value Specifies that the sequence has stable iterators. It means, that operations like insert/erase/replace do not invalidate iterators.
has_const_time_insert<C>::value Specifies that the insert method of the sequence has constant time complexity.
has_const_time_erase<C>::value Specifies that the erase method of the sequence has constant time complexity

Current implementation contains specializations for std::list<T> and std::basic_string<T> from the standard library and SGI's std::rope<T> and std::slist<T>.

Find Algorithms

Find algorithms have similar functionality to std::search() algorithm. They provide a different interface which is more suitable for common string operations. Instead of returning just the start of matching subsequence they return a range which is necessary when the length of the matching subsequence is not known beforehand. This feature also allows a partitioning of the input sequence into three parts: a prefix, a substring and a suffix.

Another difference is an addition of various searching methods besides find_first, including find_regex.

It the library, find algorithms are implemented in terms of Finders. Finders are used also by other facilities (replace,split). For convenience, there are also function wrappers for these finders to simplify find operations.

Currently the library contains only naive implementation of find algorithms with complexity O(n * m) where n is the size of the input sequence and m is the size of the search sequence. There are algorithms with complexity O(n), but for smaller sequence a constant overhead is rather big. For small m << n (m by magnitude smaller than n) the current implementation provides acceptable efficiency. Even the C++ standard defines the required complexity for search algorithm as O(n * m). It is possible that a future version of library will also contain algorithms with linear complexity as an option

Replace Algorithms

The implementation of replace algorithms follows the layered structure of the library. The lower layer implements generic substitution of a range in the input sequence. This layer takes a Finder object and a Formatter object as an input. These two functors define what to replace and what to replace it with. The upper layer functions are just wrapping calls to the lower layer. Finders are shared with the find and split facility.

As usual, the implementation of the lower layer is designed to work with a generic sequence while taking advantage of specific features if possible (by using Sequence traits)

Find Iterators & Split Algorithms

Find iterators are a logical extension of the find facility. Instead of searching for one match, the whole input can be iteratively searched for multiple matches. The result of the search is then used to partition the input. It depends on the algorithms which parts are returned as the result. They can be the matching parts (find_iterator) of the parts in between (split_iterator).

In addition the split algorithms like find_all() and split() can simplify the common operations. They use a find iterator to search the whole input and copy the matches they found into the supplied container.

Exception Safety

The library requires that all operations on types used as template or function arguments provide the basic exception-safety guarantee. In turn, all functions and algorithms in this library, except where stated otherwise, will provide the basic exception-safety guarantee. In other words: The library maintains its invariants and does not leak resources in the face of exceptions. Some library operations give stronger guarantees, which are documented on an individual basis.

Some functions can provide the strong exception-safety guarantee. That means that following statements are true:

  • If an exception is thrown, there are no effects other than those of the function
  • If an exception is thrown other than by the function, there are no effects

This guarantee can be provided under the condition that the operations on the types used for arguments for these functions either provide the strong exception guarantee or do not alter the global state .

In the reference, under the term strong exception-safety guarantee, we mean the guarantee as defined above.

For more information about the exception safety topics, follow this link

Last revised: April 22, 2010 at 00:00:35 +0100