mirror of
https://github.com/boostorg/utility.git
synced 2025-11-03 09:51:56 +01:00
303 lines
11 KiB
HTML
303 lines
11 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||
"http://www.w3.org/TR/html4/strict.dtd">
|
||
<html>
|
||
<head>
|
||
|
||
<!-- TODO:
|
||
- lambda interaction
|
||
-->
|
||
|
||
<title>Boost.Utility - lexicographic documentation</title>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||
</head>
|
||
<body bgcolor="#ffffff">
|
||
<h1>
|
||
<img border="0" src="../../../c++boost.gif" align="center" alt="c++ boost">
|
||
Utility - Lexicographic
|
||
</h1>
|
||
|
||
<p>
|
||
The class <code>boost::lexicographic</code> provides an easy way
|
||
to avoid complex and errorprone if-else cascades to do lexicographic
|
||
comparisions on certain different criteria. The class is in the header
|
||
<a href="../../../boost/utility/lexicographic.hpp"
|
||
>boost/utility/lexicographic.hpp</a> and depends on no others headers.
|
||
The test code is in
|
||
<a href="../../../libs/utility/test/lexicographic_test.cpp"
|
||
>lexicographic_test.cpp</a>.
|
||
</p>
|
||
|
||
<h2>Contents</h2>
|
||
<ul>
|
||
<li><a href="#introduction">Introduction</a></li>
|
||
<li><a href="#examples">Examples</a></li>
|
||
<li><a href="#synopsis">Synopsis</a></li>
|
||
<li><a href="#members">Members</a></li>
|
||
<li><a href="#free_functions">Free Functions</a></li>
|
||
<li><a href="#credits">Credits</a></li>
|
||
</ul>
|
||
|
||
<h2><a name="introduction">Introduction</a></h2>
|
||
<p>
|
||
Often one has to write comparisions which give an ordering between
|
||
various kinds of data. When they look in a certain
|
||
specified order at one relation between two data items at a time and
|
||
result in a lexicographic comparision of all these relations the
|
||
programmer often has to write long if-else cascades. These cascades
|
||
are often complex and difficult to maintain. The class
|
||
<code>boost::lexicographic</code> helps in this scenario. Its constructor
|
||
and function call operator takes two data items which need to be
|
||
compared as arguments and performs to comparision. The order in which
|
||
the function call operators are called determine the lexicographic order
|
||
of the relations. Since the result of all further comparisions might not
|
||
be needed after a certain step, they are not executed.<br>
|
||
The logic of the class assumes an ascending order as implied by the
|
||
<code>operator <</code>. If a descending order needs to be obtained
|
||
one can just switch the order of the arguments. Additionally, both the
|
||
constructor and the function call operator provide also a three argument
|
||
form which takes a functor for comparisions as a third argument.
|
||
</p>
|
||
|
||
<h3>Relation to <code>std::lexicographic_compare</code></h3>
|
||
<p>
|
||
The standard C++ algorithm <code>std::lexicographic_compare</code>
|
||
does essentially the same thing but in a different situation. It compares
|
||
sequences of data items of equal type. Whereas <code>boost::lexicographic</code>
|
||
compares individual data items of different type, and every comparison
|
||
must be specified explicitly by using the function call operator of the class.
|
||
</p>
|
||
|
||
<h3>Relation to if-else-cascades</h3>
|
||
<p>
|
||
<b>Advantages</b><br>
|
||
<ul>
|
||
<li>The order of comparisons can easily be changed.
|
||
<li>Single comparisons can be added or removed in one line.
|
||
<li>Comparisons can be split up to be computed partly in one
|
||
function and partly in another by using
|
||
<code>boost::lexicographic</code> as a functor.
|
||
<li>It documents the code in a better fashion and expresses
|
||
the users intention directly.
|
||
<li>If the comparison arguments do not need computation, there is in
|
||
theory no performance overhead.
|
||
</ul>
|
||
<b>Disadvantages</b><br>
|
||
<ul>
|
||
<li>There is no short-circuiting. All arguments will be
|
||
evaluated, also if
|
||
an earlier comparison step already gave the final result. As long as the
|
||
arguments are trivial there should be no performance overhead. The only
|
||
way to avoid evaluation of arguments is to place every comparison step
|
||
in an if-statement like:
|
||
<blockquote>
|
||
<pre>boost::lexicographic cmp (complex_computation (a), complex_computation (b));
|
||
if (cmp.result () == lexicographic::equivalent)
|
||
{
|
||
cmp (complex_computation (c), complex_computation (d));
|
||
if (cmp.result () == lexicographic::equivalent)
|
||
{
|
||
cmp (complex_computation (e), complex_computation (f));
|
||
}
|
||
}
|
||
// do something with cmp
|
||
</pre>
|
||
</blockquote>
|
||
But this construct eats up many of the advantages of using
|
||
<code>boost::lexicographic</code>.
|
||
<li>
|
||
The performance of using <code>boost::lexicographic</code>, besides
|
||
the lack of short-circuiting, is not negligible.
|
||
Tests with gcc 3.2.2 showed, that the algorithmic overhead
|
||
is about 40% in comparison to according to if-else-cascades.
|
||
Additionally gcc failed to inline everything properly, so that the
|
||
resulting performance overhead was about a factor two.
|
||
</ul>
|
||
</p>
|
||
|
||
<h2><a name="examples">Examples</a></h2>
|
||
<p>
|
||
An example usage are special sorting operators, such as the lexicographic
|
||
ordering of tuples:
|
||
<blockquote>
|
||
<pre>struct position
|
||
{
|
||
double x, y, z;
|
||
};
|
||
|
||
bool operator < (position const &p1, position const &p2)
|
||
{
|
||
return boost::lexicographic (p1.x, p2.x)
|
||
(p1.y, p2.y)
|
||
(p1.z, p2.z);
|
||
}</pre>
|
||
</blockquote>
|
||
An alternative form of writing this without <code>boost::lexicographic</code>
|
||
would be this:
|
||
<blockquote>
|
||
<pre>bool operator < (position const &p1, position const &p2)
|
||
{
|
||
if (p1.x == p2.x)
|
||
if (p1.y == p2.y)
|
||
return p1.z < p2.z;
|
||
else
|
||
return p1.y < p2.y;
|
||
else
|
||
return p1.x < p2.x;
|
||
}</pre>
|
||
</blockquote>
|
||
It is also easy to use different functor such as a case insensitive
|
||
comparision function object in the next example.
|
||
<blockquote>
|
||
<pre>struct person
|
||
{
|
||
std::string firstname, lastname;
|
||
};
|
||
|
||
bool operator < (person const &p1, person const &p2)
|
||
{
|
||
return boost::lexicographic
|
||
(p1.lastname, p2.lastname, cmp_case_insensitive)
|
||
(p1.firstname, p2.firstname, cmp_case_insensitive);
|
||
}</pre>
|
||
</blockquote>
|
||
</p>
|
||
|
||
<h2><a name="synopsis">Synopsis</a></h2>
|
||
<blockquote>
|
||
<pre>namespace boost
|
||
{
|
||
|
||
class lexicographic
|
||
{
|
||
public:
|
||
enum result_type { minus = -1, equivalent, plus };
|
||
|
||
template <typename T1, typename T2>
|
||
lexicographic (T1 const &a, T2 const &b);
|
||
|
||
template <typename T1, typename T2, typename Cmp>
|
||
lexicographic (T1 const &a, T2 const &b, Cmp cmp);
|
||
|
||
template <typename T1, typename T2>
|
||
lexicographic &operator () (T1 const &a, T2 const &b);
|
||
|
||
template <typename T1, typename T2, typename Cmp>
|
||
lexicographic &operator () (T1 const &a, T2 const &b, Cmp cmp);
|
||
|
||
result_type result () const;
|
||
operator <i>unspecified_bool_type</i> () const;
|
||
};
|
||
|
||
bool operator == (lexicographic l1, lexicographic l2);
|
||
bool operator != (lexicographic l1, lexicographic l2);
|
||
|
||
}</pre>
|
||
</blockquote>
|
||
|
||
<h2><a name="members">Members</a></h2>
|
||
<h3>result_type</h3>
|
||
<code>enum result_type { minus = -1, equivalent = 0, plus = +1 };</code>
|
||
<blockquote><p>
|
||
Defines the result type of the class. It is kept as internal state
|
||
and is returned by <code>result ()</code>.
|
||
The integer representation of it is equivalent to the one
|
||
returned by <code>std::strcmp</code>.
|
||
<ul>
|
||
<li><code>minus</code> - the sequence of the first arguments
|
||
of constructor and function call operators
|
||
is lexicographically less than the according
|
||
sequence of the second arguments.
|
||
<li><code>equivalent</code> - all elements of the sequences
|
||
of the first and the second arguments are identical.
|
||
<li><code>plus</code> - the sequence of the first arguments
|
||
of constructor and function call operators
|
||
is lexicographically greater than the according
|
||
sequence of the second arguments.
|
||
</ul>
|
||
</p></blockquote>
|
||
|
||
<h3>constructors</h3>
|
||
<code>template <typename T1, typename T2><br>
|
||
lexicographic (T1 const &a, T2 const &b);</code>
|
||
<blockquote><p>
|
||
Constructs new object and does the first comparision
|
||
step between <code>a</code> and <code>b</code>. It uses
|
||
<code>operator <</code> for comparisions.
|
||
</p></blockquote>
|
||
|
||
<code>template <typename T1, typename T2, typename Cmp><br>
|
||
lexicographic (T1 const &a, T2 const &b, Cmp cmp);</code>
|
||
<blockquote><p>
|
||
Constructs new object and does the first comparision
|
||
step between <code>a</code> and <code>b</code>. It uses
|
||
<code>cmp</code> for comparisions.
|
||
</p></blockquote>
|
||
|
||
<h3>function call operators</h3>
|
||
<code>template <typename T1, typename T2><br>
|
||
lexicographic &operator () (T1 const &a, T2 const &b);</code>
|
||
<blockquote><p>
|
||
Does next comparision step on object between <code>a</code>
|
||
and <code>b</code>. It uses <code>operator <</code> for
|
||
comparisions.
|
||
</p></blockquote>
|
||
|
||
<code>template <typename T1, typename T2, typename Cmp><br>
|
||
lexicographic &operator () (T1 const &a, T2 const &b, Cmp cmp);</code>
|
||
<blockquote><p>
|
||
Does next comparision step on object between <code>a</code>
|
||
and <code>b</code>. It uses <code>cmp</code> for
|
||
comparisions.
|
||
</p></blockquote>
|
||
|
||
<h3>result</h3>
|
||
<code>result_type result () const;</code>
|
||
<blockquote><p>
|
||
Gives result of already done comparision steps.
|
||
</p></blockquote>
|
||
|
||
<h3>conversions</h3>
|
||
<code>operator <i>unspecified_bool_type</i> () const;</code>
|
||
<blockquote><p>
|
||
This conversion operator allows objects to be used in boolean
|
||
contexts, like <code>if (lexicographic (a, b)) {}</code>. The
|
||
actual target type is typically a pointer to a member function,
|
||
avoiding many of the implicit conversion pitfalls.<br>
|
||
It evaluates to <code>true</code> if <code>result () == minus</code>,
|
||
otherwise to <code>false</code>.
|
||
</p></blockquote>
|
||
|
||
<h2><a name="free_functions">Free Functions</a></h2>
|
||
<h3>comparision</h3>
|
||
<code>bool operator == (lexicographic l1, lexicographic l2);</code>
|
||
<blockquote><p>
|
||
Returns <code>l1.result () == l2.result ()</code>.
|
||
That means it returns <code>true</code> if both
|
||
objects are in the same state.
|
||
</p></blockquote>
|
||
|
||
<code>bool operator != (lexicographic l1, lexicographic l2);</code>
|
||
<blockquote><p>
|
||
Returns <code>l1.result () != l2.result ()</code>.
|
||
That means it returns <code>true</code> if the two
|
||
objects are in the a different state.
|
||
</p></blockquote>
|
||
|
||
<h2><a name="credits">Credits</a></h2>
|
||
<p>
|
||
The author of <code>boost::lexicographic</code> is Jan Langer (jan@langernetz.de).
|
||
Ideas and suggestions from Steve Cleary, David Abrahams, Gennaro Proata, Paul Bristow, Daniel Frey, Daryle Walker and Brian McNamara were used.
|
||
</p>
|
||
<hr>
|
||
<p>
|
||
October 5, 2003<br>
|
||
<br>
|
||
<09> Copyright Jan Langer 2003<br>
|
||
Use, modification, and distribution is subject to the Boost Software
|
||
License, Version 1.0. (See accompanying file
|
||
<a href="../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy at
|
||
<a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)
|
||
</p>
|
||
</body>
|
||
</html>
|