Files
utility/doc/lexicographic.html
2003-10-04 23:15:09 +00:00

303 lines
11 KiB
HTML
Raw Blame History

<!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 &lt;</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 &lt; (position const &amp;p1, position const &amp;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 &lt; (position const &amp;p1, position const &amp;p2)
{
if (p1.x == p2.x)
if (p1.y == p2.y)
return p1.z &lt; p2.z;
else
return p1.y &lt; p2.y;
else
return p1.x &lt; 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 &lt; (person const &amp;p1, person const &amp;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 &lt;typename T1, typename T2&gt;
lexicographic (T1 const &amp;a, T2 const &b);
template &lt;typename T1, typename T2, typename Cmp&gt;
lexicographic (T1 const &amp;a, T2 const &b, Cmp cmp);
template &lt;typename T1, typename T2&gt;
lexicographic &amp;operator () (T1 const &a, T2 const &b);
template &lt;typename T1, typename T2, typename Cmp&gt;
lexicographic &amp;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 &lt;typename T1, typename T2&gt;<br>
lexicographic (T1 const &amp;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 &lt;</code> for comparisions.
</p></blockquote>
<code>template &lt;typename T1, typename T2, typename Cmp&gt;<br>
lexicographic (T1 const &amp;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 &lt;typename T1, typename T2&gt;<br>
lexicographic &amp;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 &lt;</code> for
comparisions.
</p></blockquote>
<code>template &lt;typename T1, typename T2, typename Cmp&gt;<br>
lexicographic &amp;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>