forked from boostorg/utility
initial checkin
[SVN r1155]
This commit is contained in:
234
doc/lexicographic.html
Normal file
234
doc/lexicographic.html
Normal file
@@ -0,0 +1,234 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<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.hpp"
|
||||
>lexicographic_test.hpp</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>
|
||||
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 cpomplex 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.
|
||||
|
||||
<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, plus };</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 and Gennaro Proata
|
||||
were used.
|
||||
</p>
|
||||
<hr>
|
||||
<p>April 17, 2003<br><br>
|
||||
<09> Copyright Jan Langer 2003. Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
109
include/boost/utility/lexicographic.hpp
Normal file
109
include/boost/utility/lexicographic.hpp
Normal file
@@ -0,0 +1,109 @@
|
||||
// (C) 2003, Jan Langer (jan@langernetz.de).
|
||||
//
|
||||
// This material is provided "as is", with absolutely no warranty expressed
|
||||
// or implied. Any use is at your own risk.
|
||||
//
|
||||
// Permission to use or copy this software for any purpose is hereby granted
|
||||
// without fee, provided the above notices are retained on all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted,
|
||||
// provided the above notices are retained, and a notice that the code was
|
||||
// modified is included with the above copyright notice.
|
||||
|
||||
#ifndef BOOST_UTILITY_LEXICOGRAPHIC_HPP
|
||||
#define BOOST_UTILITY_LEXICOGRAPHIC_HPP
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
class lexicographic
|
||||
{
|
||||
public:
|
||||
enum result_type { minus = -1, equivalent, plus };
|
||||
|
||||
private:
|
||||
typedef void (lexicographic::*unspecified_bool_type) ();
|
||||
void safe_bool_conversion () {}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
result_type do_compare (T1 const &a, T2 const &b) const
|
||||
{
|
||||
if (a < b)
|
||||
return minus;
|
||||
else if (b < a)
|
||||
return plus;
|
||||
else
|
||||
return equivalent;
|
||||
}
|
||||
template <typename T1, typename T2, typename Cmp>
|
||||
result_type do_compare (T1 const &a, T2 const &b, Cmp cmp) const
|
||||
{
|
||||
if (cmp (a, b))
|
||||
return minus;
|
||||
else if (cmp (b, a))
|
||||
return plus;
|
||||
else
|
||||
return equivalent;
|
||||
}
|
||||
|
||||
public:
|
||||
lexicographic () : m_value (equivalent) {}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
lexicographic (T1 const &a, T2 const &b)
|
||||
: m_value (do_compare (a, b))
|
||||
{}
|
||||
template <typename T1, typename T2, typename Cmp>
|
||||
lexicographic (T1 const &a, T2 const &b, Cmp cmp)
|
||||
: m_value (do_compare (a, b, cmp))
|
||||
{}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
lexicographic &operator () (T1 const &a, T2 const &b)
|
||||
{
|
||||
if (m_value == equivalent)
|
||||
m_value = do_compare (a, b);
|
||||
return *this;
|
||||
}
|
||||
template <typename T1, typename T2, typename Cmp>
|
||||
lexicographic &operator () (T1 const &a, T2 const &b, Cmp cmp)
|
||||
{
|
||||
if (m_value == equivalent)
|
||||
m_value = do_compare (a, b, cmp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
result_type result () const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
operator unspecified_bool_type () const
|
||||
{
|
||||
return (m_value == minus)
|
||||
? &lexicographic::safe_bool_conversion
|
||||
: 0;
|
||||
}
|
||||
|
||||
// somehow only needed old compilers
|
||||
bool operator ! () const
|
||||
{
|
||||
return m_value != minus;
|
||||
}
|
||||
|
||||
private:
|
||||
result_type m_value;
|
||||
};
|
||||
|
||||
bool operator == (lexicographic l1, lexicographic l2)
|
||||
{
|
||||
return l1.result () == l2.result ();
|
||||
}
|
||||
|
||||
bool operator != (lexicographic l1, lexicographic l2)
|
||||
{
|
||||
return l1.result () != l2.result ();
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_UTILITY_LEXICOGRAPHIC_HPP
|
70
test/lexicographic_test.cpp
Normal file
70
test/lexicographic_test.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
// (C) 2003, Jan Langer (jan@langernetz.de).
|
||||
//
|
||||
// This material is provided "as is", with absolutely no warranty expressed
|
||||
// or implied. Any use is at your own risk.
|
||||
//
|
||||
// Permission to use or copy this software for any purpose is hereby granted
|
||||
// without fee, provided the above notices are retained on all copies.
|
||||
// Permission to modify the code and to distribute modified code is granted,
|
||||
// provided the above notices are retained, and a notice that the code was
|
||||
// modified is included with the above copyright notice.
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
|
||||
#include <boost/utility/lexicographic.hpp>
|
||||
|
||||
int main ()
|
||||
{
|
||||
using boost::lexicographic;
|
||||
|
||||
lexicographic l1; // equivalent
|
||||
assert (!l1);
|
||||
|
||||
lexicographic l2 (l1); // equivalent
|
||||
assert (!l2);
|
||||
|
||||
l2 = l1;
|
||||
assert (!l2);
|
||||
|
||||
l2 (3, 6); // less
|
||||
assert (l2);
|
||||
assert (l2.result () == lexicographic::minus);
|
||||
assert (lexicographic::equivalent != l2.result ());
|
||||
|
||||
lexicographic l3 (3.0, 1.0); // greater
|
||||
assert (!l3);
|
||||
|
||||
for (int i = 1; i <= 3; ++i)
|
||||
for (int j = 1; j <= 3; ++j)
|
||||
for (int k = 1; k <= 3; ++k)
|
||||
{
|
||||
lexicographic l4;
|
||||
l4 (i, 2) (j, 2) (k, 2);
|
||||
|
||||
if (i < 2)
|
||||
assert (l4);
|
||||
else if (i > 2)
|
||||
assert (!l4);
|
||||
else if (j < 2)
|
||||
assert (l4);
|
||||
else if (j > 2)
|
||||
assert (!l4);
|
||||
else if (k < 2)
|
||||
assert (l4);
|
||||
else
|
||||
assert (!l4);
|
||||
}
|
||||
|
||||
lexicographic l5;
|
||||
l5 (1, 1, std::greater <int> ()) (2, 3);
|
||||
assert (l5);
|
||||
|
||||
lexicographic l6;
|
||||
l6 (1, 1, std::greater <int> ()) (2, 3, std::greater <int> ());
|
||||
assert (!l6);
|
||||
|
||||
lexicographic l7;
|
||||
l7 (1, 1) (2, 3, std::greater <int> ());
|
||||
assert (!l7);
|
||||
}
|
Reference in New Issue
Block a user