cgal/STL_Extension/doc/STL_Extension/STL_Extension.txt

428 lines
18 KiB
Plaintext

namespace CGAL {
/*!
\mainpage User Manual
\anchor Chapter_STL_Extensions_for_CGAL
\cgalAutoToc
\authors Michael Hoffmann, Clément Jamin, Lutz Kettner, Sylvain Pion, and Ron Wein
\section stl_intro Introduction
\cgal is designed in the spirit of the generic programming paradigm
to work together with the Standard Template Library (\stl)
\cgalCite{cgal:ansi-is14882-98}, \cgalCite{cgal:a-gps-98}. This chapter documents non-geometric
\stl-like components that are not provided in the \stl standard but
in \cgal: a doubly-connected list managing items in place (where
inserted items are not copied), a compact container, a multi-set class that
uses three-valued comparisons and offers additional functionality,
generic algorithms, iterators, functor adaptors for binding and swapping
arguments and for composition, functors for projection and creation and
adaptor classes around iterators and circulators. See also circulators in
Chapter \ref Chapter_Handles_Ranges_and_Circulators "Handles and Circulators".
A class storing polymorphic objects
is also provided, as well as a class to manage the uncertainty of some values.
Finally, tags and policy classes to specify complexity trade-offs of data-structures,
and a class which helps specifying that the default types in template
parameter lists are desired is also provided.
\section stl_doubly Doubly-Connected List Managing Items in Place
The class `In_place_list<T,bool>` manages a
sequence of items in place in a doubly-connected list. Its goals are
the flexible handling of memory management and performance
optimization. The item type has to provide the two necessary
pointers `&T::next_link` and `&T::prev_link`. One possibility
to obtain these pointers is to inherit them from the base class
`In_place_list_base<T>`.
The class `In_place_list<T,bool>` is a container quite similar
to \stl containers, with the advantage that it is able to handle the
stored elements by reference instead of copying them. It is possible
to delete an element only knowing its address and no iterator to it.
This used to simplify mutually pointed data structures like a halfedge
data structure for planar maps or polyhedral surfaces (the current design
does not need this anymore). The usual iterators are also available.
\section stl_compact Compact Containers
The class `Compact_container<T, Allocator>` is an \stl like container
which provides a very compact storage for its elements. It achieves this goal
by requiring `T` to provide access to a pointer in it, which is going to be
used by `Compact_container<T, Allocator>` for its internal management.
The traits class `Compact_container_traits<T>` specifies the way to
access that pointer. The class `Compact_container_base` can be
used as a base class to provide the pointer, although in this case you do not
get the most compact representation. The values that this pointer can have
during valid use of the object are valid pointer values to 4 bytes aligned
objects (i.e., the two least significant bits of the pointer need to be zero
when the object is constructed). Another interesting property of this
container is that iterators are not invalidated during `insert` or
`erase` operations.
The main deviation from the \stl container concept is that the `++` and
`--` operators of the iterator do not have a constant time complexity in
all cases. The actual complexity is related to the maximum size that the
container has had during its life time compared to its current size, because
the iterator has to go over the "erased" elements as well, so the bad case is
when the container used to contain lots of elements, but now has far less. In
this case, we suggest to do a copy of the container in order to "defragment"
the internal representation.
The objects stored in this container can optionally store an
"erase counter". If it exists, i.e.\ if the object is a model of the
`ObjectWithEraseCounter` concept, each time an object is erased from the
container, the erase counter of the object will be incremented.
For example, this erase counter can be exploited using the `CC_safe_handle`
helper class, so that one can know if a handle is still pointing to the same
element.
Note that this is meaningful only because the container doesn't
deallocate elements until the destruction or clear() of the container.
For example, this counter is used by
the parallel 3D mesh generation engine to lazily manage the queues of bad cells:
an element in the queue is a pair containing a cell iterator and the
erase counter value of the cell when it has been inserted. When an element
is popped from the queue, the algorithm checks if the current value of
the erase counter matches the stored value. If it doesn't match, it means
the cell has been destroyed in the meantime and the algorithm ignores it. Without this
lazy management, each time a cell is destroyed, the algorithm has to look
for it in the queue and remove it. This mechanism is even more useful for the parallel
version of the meshing process, since each thread has its own queue and looking
for a cell in all the queues would be very slow.
This container has been developed in order to efficiently handle large data
structures like the triangulation and halfedge data structures. It can
probably be useful for other kinds of graphs as well.
The class `Concurrent_compact_container<T, Allocator>`
provides the same features, but enables concurrency-safe
`insert` and `erase` operations. Other operations are not concurrency-safe.
It requires the program to be linked against
the <a href="https://github.com/oneapi-src/oneTBB">Intel TBB library</a>.
\section stl_multi Multiset with Extended Functionality
The class `Multiset<Type,Compare,Allocator>` represents a
multi-set of elements of type `Type`, represented as a red-black tree
(see \cgalCite{clrs-ia-01} for an excellent introduction to red-black
trees). It differs from the \stl's `multiset` class-template mainly due
to the fact that it is parameterized by a comparison functor `Compare`
that returns the three-valued `Comparison_result` (namely it returns
either `SMALLER`, `EQUAL`, or `LARGER`), rather than a <I>less</I>
functor returning `bool`. Thus, it is possible to maintain
the underlying red-black tree with less invocations of the comparison functor,
which can considerably decrease running times, especially when comparing
elements of type `Type` is an expensive operation.
`Multiset<Type,Compare,Allocator>` also guarantees that the order of
elements sent to the comparison functor is fixed. For example, if we insert
a new element `x` into the set (or erase an element from the set), then
we always invoke `Compare()(x, y)` (and never `Compare()(y, x)`),
where `y` is an element already stored in the set. This behavior, not
supported by `std::multiset`, is sometimes crucial for designing more
efficient comparison predicates.
The interface of `Multiset<Type,Compare,Allocator>` is in general
derived from `std::multiset`. However, it extends the interface by
offering some additional operations, such as: inserting of an element into
the set given its <I>exact</I> position (and not just using an insertion hint);
looking up keys whose type may differ from `Type`, as long as users supply
a comparison functor `CompareKey`, between the keys and set elements;
and catenating and splitting sets.
\section stl_hash Hashing
For handles and indices of vertices, halfedges, faces, etc., we provide specializations of `boost::hash<T>` and `std::hash<T>`, so that they can be used with classes such as `boost::unordered_map`.
\cgalExample{STL_Extension/unordered_map.cpp}
\section stl_polyobject Polymorphic Object
The class `Object` can store an object of whatever other type.
It can be used by a function to return objects of different types.
A mechanism to extract the stored object based on its type is also provided.
This class is similar to `std::any`.
\section stl_uncertainty Uncertainty Management
The class `Uncertain<T>` represents a range of values of type `T`.
`T` is allowed to stand for `bool`, or \cgal's enumeration types
`Sign`, `Comparison_result`, `Orientation`, `Oriented_side`,
`Bounded_side` and `Angle`.
The idea is that sometimes you are not sure of the result of a function,
and you would like to communicate that to the caller. `Uncertain<T>`
allows just that. It also provides functions to naturally extend the
Boolean operations for `Uncertain<bool>` for example.
`Uncertain<T>` is used in \cgal as the return type of geometric predicates
when the number type used is interval arithmetic like `Interval_nt`.
End users typically do not see it as it is hidden in the implementation
of the filtered predicates provided by the various filtered kernels,
but it is important that providers of predicates that are meant to be
filtered by `Filtered_predicate`, know about it.
It can also be used in other contexts as well, as it is a general tool.
\section stl_complexity Complexity Tags and Policies
Some data structures and algorithms can be implemented with different
complexity trade-offs between memory usage and time complexity. \cgal provides
the tags `Fast` and `Compact` which can be used to select between those
variants. For example, the `Location_policy` class is parameterized by
these tags and allows to specify the complexity of point location (currently in
`Delaunay_triangulation_3` only). Convenient typedefs `Fast_location`
and `Compact_location` are also provided.
\section stl_defaults Default Arguments in Template Parameter Lists
In \cpp, it is possible to specify defaults at the end of a template parameter
list. Specifying that one wishes to use the default is simply done by omitting
it. This is however possible only at the end of the list. `Default`
provides a simple mechanism that performs something equivalent anywhere in the
sequence.
\section secchecks Checks
Much of the \cgal code contains checks.
For example, all checks used in the kernel code are prefixed by
`CGAL_KERNEL`.
Other packages have their own prefixes, as documented in the corresponding
chapters.
Some are there to check if the kernel behaves correctly, others are there to
check if the user calls kernel routines in an acceptable manner.
There are five types of checks.
The first three are errors and lead to a halt of the program if they fail.
The fourth only leads to a warning, and the last one is compile-time only.
<DL>
<DT>Preconditions</DT>
<DD>
check if the caller of a routine has called it in a proper fashion.
If such a check fails it is the responsibility of the caller (usually the user of the library).
</DD>
<DT>Postconditions</DT>
<DD>
check if a routine does what it promises to do.
If such a check fails it is the fault of this routine, so of the library.
</DD>
<DT>Assertions</DT>
<DD>
are other checks that do not fit in the above two
categories.
</DD>
<DT>Warnings</DT>
<DD>
are checks for which it is not so severe if they fail.
</DD>
<DT>Static assertions</DT>
<DD>
are compile-time assertions, used e.g. to verify
the values of compile-time constants or compare types for (in)equality.
</DD>
</DL>
By default, all of these checks are performed.
It is however possible to turn them off through the use of compile time
switches.
For example, for the checks in the kernel code, these switches are the
following:
`CGAL_KERNEL_NO_PRECONDITIONS`,
`CGAL_KERNEL_NO_POSTCONDITIONS`,
`CGAL_KERNEL_NO_ASSERTIONS` and
`CGAL_KERNEL_NO_WARNINGS`.
So, in order to compile the file `foo.cpp` with the postcondition checks
off, you can do:
`CC -DCGAL_KERNEL_NO_POSTCONDITIONS foo.cpp`
This is also preferably done by modifying your makefile by adding
`-DCGAL_KERNEL_NO_POSTCONDITIONS` to the `CXXFLAGS` variable.
The name `KERNEL` in the macro name can be replaced by a package
specific name in order to control assertions done in a given package.
This name is given in the documentation of the corresponding package,
in case it exists.
Note that global macros can also be used to control the behavior over the
whole \cgal library:
- `CGAL_NO_PRECONDITIONS`,
- `CGAL_NO_POSTCONDITIONS`,
- `CGAL_NO_ASSERTIONS`,
- `CGAL_NO_WARNINGS` and
- `CGAL_NDEBUG`.
Setting the macro `CGAL_NDEBUG` disables all checks. This way, adding
`-DCGAL_NDEBUG` to your compilation flags removes absolutely all checks.
This is the default recommended setup for performing timing benchmarks for
example.
Note that the setting of the standard macro `NDEBUG` sets `CGAL_NDEBUG`,
unless `CGAL_DEBUG` is also defined. If both `NDEBUG` and `CGAL_DEBUG` are
defined, then the standard `assert` macro is disabled, but not the CGAL
assertions and preconditions.
Not all checks are on by default.
The first four types of checks can be marked as expensive or exactness checks
(or both).
These checks need to be turned on explicitly by supplying one or both of
the compile time switches `CGAL_KERNEL_CHECK_EXPENSIVE` and
`CGAL_KERNEL_CHECK_EXACTNESS`.
Expensive checks are, as the word says, checks that take a considerable
time to compute.
Considerable is an imprecise phrase.
Checks that add less than 10 percent to the execution time of the routine
they are in are not expensive.
Checks that can double the execution time are.
Somewhere in between lies the border line.
Checks that increase the asymptotic running time of an algorithm are always
considered expensive.
Exactness checks are checks that rely on exact arithmetic.
For example, if the intersection of two lines is computed, the postcondition
of this routine may state that the intersection point lies on both lines.
However, if the computation is done with doubles as number type, this may not
be the case, due to round off errors.
So, exactness checks should only be turned on if the computation is done
with some exact number type.
By definition, static assertions are both inexpensive and unaffected by precision
management. Thus, the categories do not apply for static assertions.
\subsection stl_alteriung Altering the Failure Behavior
As stated above, if a postcondition, precondition or assertion is
violated, an exception is thrown, and if nothing is done to catch it,
the program will abort.
This behavior can be changed by means of the function `set_error_behaviour()`
and the enum `Failure_behaviour`.
The `THROW_EXCEPTION` value is the default, which throws an exception.
If the `EXIT` value is set, the program will stop and return a value
indicating failure, but not dump the core.
The `CONTINUE` value tells the checks to go on after diagnosing the error.
Note that since \cgal 3.4, `CONTINUE` has the same effect as
`THROW_EXCEPTION` for errors (but it keeps its meaning for warnings), it is
not possible anymore to let assertion failures simply continue (except by
totally disabling them).
\cgalAdvancedBegin
If the `EXIT_WITH_SUCCESS` value is set, the program will stop and
return a value corresponding to successful execution and not dump the core.
\cgalAdvancedEnd
The value that is returned by `set_error_behaviour()` is the value that was in use before.
For warnings we provide `set_warning_behaviour()` which works in the same way.
The only difference is that for warnings the default value is
`CONTINUE`.
Setting the error and warning behavior is not thead safe.
\subsection stl_control Control at a Finer Granularity
The compile time flags as described up to now all operate on the whole
library.
Sometimes you may want to have a finer control.
\cgal offers the possibility to turn checks on and off with a bit finer
granularity, namely the module in which the routines are defined.
The name of the module is to be appended directly after the \cgal prefix.
So, the flag `CGAL_KERNEL_NO_ASSERTIONS` switches off assertions in
the kernel only, the flag `CGAL_CH_CHECK_EXPENSIVE` turns on
expensive checks in the convex hull module.
The name of a particular module is documented with that module.
\subsection stl_customizing Customizing how Errors are Reported
Normally, error messages are written to the standard error output.
It is possible to do something different with them.
To that end you can register your own handler using
`set_error_handler(Failure_function handler)`
This function should be declared as follows.
There are several things that you can do with your own handler.
You can display a diagnostic message in a different way, for instance in
a pop up window or to a log file (or a combination).
You can also implement a different policy on what to do after an error.
For instance, you can throw an exception or ask the user in a dialog
whether to abort or to continue.
If you do this, it is best to set the error behavior to
`CONTINUE`, so that it does not interfere with your policy.
You can register two handlers, one for warnings and one for errors.
Of course, you can use the same function for both if you want.
When you set a handler, the previous handler is returned, so you can restore
it if you want.
\subsubsection stl_failure_example Example
\code{.cpp}
#include <CGAL/assertions.h>
void my_failure_handler(
const char *type,
const char *expr,
const char* file,
int line,
const char* msg)
{
// report the error in some way.
}
void foo()
{
CGAL::Failure_function prev;
prev = CGAL::set_error_handler(my_failure_handler);
// call some routines.
CGAL::set_error_handler(prev);
}
\endcode
*/
} /* namespace CGAL */
/*!
\page FromBoostNPtoCGALNP Upgrading Code using \boost Parameters to \cgal Named Function Parameters
Prior to \cgal 5.6, some packages were using Boost parameters to provide a user friendly
way to set parameters of classes and functions. In an attempt to remove a dependency and
to get a more uniform API across packages, these packages have been updated to now use
\cgal \ref bgl_namedparameters inspired by the function named parameters from
the \boost graph library. In practice this means that the following call:
\code
Mesh_criteria criteria(edge_size = 8,
facet_angle = 25,
facet_size = 8,
facet_distance = 0.2,
cell_radius_edge_ratio = 3,
cell_size = 10);
\endcode
should now be written as follows:
\code
Mesh_criteria criteria(edge_size(8).
facet_angle(25).
facet_size(8).
facet_distance(0.2).
cell_radius_edge_ratio(3).
cell_size(10));
\endcode
Note that we have tried to preserve the backward compatibility by allowing previous API
to remain valid. However, if new parameters are introduced for those functions, there is
no guarantee that they will be ported to the old API. So we strongly encourage users to
upgrade to the new API. Additionally, passing parameters without names is deprecated
and even removed for some functions.
*/