mirror of
https://github.com/boostorg/utility.git
synced 2025-07-31 21:34:46 +02:00
This commit was manufactured by cvs2svn to create branch
'unlabeled-1.4.2'. [SVN r9366]
This commit is contained in:
96
.gitattributes
vendored
Normal file
96
.gitattributes
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
* text=auto !eol svneol=native#text/plain
|
||||
*.gitattributes text svneol=native#text/plain
|
||||
|
||||
# Scriptish formats
|
||||
*.bat text svneol=native#text/plain
|
||||
*.bsh text svneol=native#text/x-beanshell
|
||||
*.cgi text svneol=native#text/plain
|
||||
*.cmd text svneol=native#text/plain
|
||||
*.js text svneol=native#text/javascript
|
||||
*.php text svneol=native#text/x-php
|
||||
*.pl text svneol=native#text/x-perl
|
||||
*.pm text svneol=native#text/x-perl
|
||||
*.py text svneol=native#text/x-python
|
||||
*.sh eol=lf svneol=LF#text/x-sh
|
||||
configure eol=lf svneol=LF#text/x-sh
|
||||
|
||||
# Image formats
|
||||
*.bmp binary svneol=unset#image/bmp
|
||||
*.gif binary svneol=unset#image/gif
|
||||
*.ico binary svneol=unset#image/ico
|
||||
*.jpeg binary svneol=unset#image/jpeg
|
||||
*.jpg binary svneol=unset#image/jpeg
|
||||
*.png binary svneol=unset#image/png
|
||||
*.tif binary svneol=unset#image/tiff
|
||||
*.tiff binary svneol=unset#image/tiff
|
||||
*.svg text svneol=native#image/svg%2Bxml
|
||||
|
||||
# Data formats
|
||||
*.pdf binary svneol=unset#application/pdf
|
||||
*.avi binary svneol=unset#video/avi
|
||||
*.doc binary svneol=unset#application/msword
|
||||
*.dsp text svneol=crlf#text/plain
|
||||
*.dsw text svneol=crlf#text/plain
|
||||
*.eps binary svneol=unset#application/postscript
|
||||
*.gz binary svneol=unset#application/gzip
|
||||
*.mov binary svneol=unset#video/quicktime
|
||||
*.mp3 binary svneol=unset#audio/mpeg
|
||||
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
|
||||
*.ps binary svneol=unset#application/postscript
|
||||
*.psd binary svneol=unset#application/photoshop
|
||||
*.rdf binary svneol=unset#text/rdf
|
||||
*.rss text svneol=unset#text/xml
|
||||
*.rtf binary svneol=unset#text/rtf
|
||||
*.sln text svneol=native#text/plain
|
||||
*.swf binary svneol=unset#application/x-shockwave-flash
|
||||
*.tgz binary svneol=unset#application/gzip
|
||||
*.vcproj text svneol=native#text/xml
|
||||
*.vcxproj text svneol=native#text/xml
|
||||
*.vsprops text svneol=native#text/xml
|
||||
*.wav binary svneol=unset#audio/wav
|
||||
*.xls binary svneol=unset#application/vnd.ms-excel
|
||||
*.zip binary svneol=unset#application/zip
|
||||
|
||||
# Text formats
|
||||
.htaccess text svneol=native#text/plain
|
||||
*.bbk text svneol=native#text/xml
|
||||
*.cmake text svneol=native#text/plain
|
||||
*.css text svneol=native#text/css
|
||||
*.dtd text svneol=native#text/xml
|
||||
*.htm text svneol=native#text/html
|
||||
*.html text svneol=native#text/html
|
||||
*.ini text svneol=native#text/plain
|
||||
*.log text svneol=native#text/plain
|
||||
*.mak text svneol=native#text/plain
|
||||
*.qbk text svneol=native#text/plain
|
||||
*.rst text svneol=native#text/plain
|
||||
*.sql text svneol=native#text/x-sql
|
||||
*.txt text svneol=native#text/plain
|
||||
*.xhtml text svneol=native#text/xhtml%2Bxml
|
||||
*.xml text svneol=native#text/xml
|
||||
*.xsd text svneol=native#text/xml
|
||||
*.xsl text svneol=native#text/xml
|
||||
*.xslt text svneol=native#text/xml
|
||||
*.xul text svneol=native#text/xul
|
||||
*.yml text svneol=native#text/plain
|
||||
boost-no-inspect text svneol=native#text/plain
|
||||
CHANGES text svneol=native#text/plain
|
||||
COPYING text svneol=native#text/plain
|
||||
INSTALL text svneol=native#text/plain
|
||||
Jamfile text svneol=native#text/plain
|
||||
Jamroot text svneol=native#text/plain
|
||||
Jamfile.v2 text svneol=native#text/plain
|
||||
Jamrules text svneol=native#text/plain
|
||||
Makefile* text svneol=native#text/plain
|
||||
README text svneol=native#text/plain
|
||||
TODO text svneol=native#text/plain
|
||||
|
||||
# Code formats
|
||||
*.c text svneol=native#text/plain
|
||||
*.cpp text svneol=native#text/plain
|
||||
*.h text svneol=native#text/plain
|
||||
*.hpp text svneol=native#text/plain
|
||||
*.ipp text svneol=native#text/plain
|
||||
*.tpp text svneol=native#text/plain
|
||||
*.jam text svneol=native#text/plain
|
||||
*.java text svneol=native#text/plain
|
424
algo_opt_examples.cpp
Normal file
424
algo_opt_examples.cpp
Normal file
@@ -0,0 +1,424 @@
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1999
|
||||
* Dr John Maddock
|
||||
*
|
||||
* Permission to use, copy, modify, distribute and sell this software
|
||||
* and its documentation for any purpose is hereby granted without fee,
|
||||
* provided that the above copyright notice appear in all copies and
|
||||
* that both that copyright notice and this permission notice appear
|
||||
* in supporting documentation. Dr John Maddock makes no representations
|
||||
* about the suitability of this software for any purpose.
|
||||
* It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* This file provides some example of type_traits usage -
|
||||
* by "optimising" various algorithms:
|
||||
*
|
||||
* opt::copy - optimised for trivial copy (cf std::copy)
|
||||
* opt::fill - optimised for trivial copy/small types (cf std::fill)
|
||||
* opt::destroy_array - an example of optimisation based upon omitted destructor calls
|
||||
* opt::iter_swap - uses type_traits to determine whether the iterator is a proxy
|
||||
* in which case it uses a "safe" approach, otherwise calls swap
|
||||
* on the assumption that swap may be specialised for the pointed-to type.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Release notes:
|
||||
23rd July 2000:
|
||||
Added explicit failure for broken compilers that don't support these examples.
|
||||
Fixed broken gcc support (broken using directive).
|
||||
Reordered tests slightly.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <boost/timer.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/call_traits.hpp>
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::cin;
|
||||
|
||||
#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
|
||||
#error "Sorry, without template partial specialisation support there isn't anything to test here..."
|
||||
#endif
|
||||
|
||||
namespace opt{
|
||||
|
||||
//
|
||||
// algorithm destroy_array:
|
||||
// The reverse of std::unitialized_copy, takes a block of
|
||||
// unitialized memory and calls destructors on all objects therein.
|
||||
//
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <bool>
|
||||
struct array_destroyer
|
||||
{
|
||||
template <class T>
|
||||
static void destroy_array(T* i, T* j){ do_destroy_array(i, j); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct array_destroyer<true>
|
||||
{
|
||||
template <class T>
|
||||
static void destroy_array(T*, T*){}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void do_destroy_array(T* first, T* last)
|
||||
{
|
||||
while(first != last)
|
||||
{
|
||||
first->~T();
|
||||
++first;
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace detail
|
||||
|
||||
template <class T>
|
||||
inline void destroy_array(T* p1, T* p2)
|
||||
{
|
||||
detail::array_destroyer<boost::has_trivial_destructor<T>::value>::destroy_array(p1, p2);
|
||||
}
|
||||
|
||||
//
|
||||
// unoptimised versions of destroy_array:
|
||||
//
|
||||
template <class T>
|
||||
void destroy_array1(T* first, T* last)
|
||||
{
|
||||
while(first != last)
|
||||
{
|
||||
first->~T();
|
||||
++first;
|
||||
}
|
||||
}
|
||||
template <class T>
|
||||
void destroy_array2(T* first, T* last)
|
||||
{
|
||||
for(; first != last; ++first) first->~T();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// opt::copy
|
||||
// same semantics as std::copy
|
||||
// calls memcpy where appropiate.
|
||||
//
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <bool b>
|
||||
struct copier
|
||||
{
|
||||
template<typename I1, typename I2>
|
||||
static I2 do_copy(I1 first, I1 last, I2 out);
|
||||
};
|
||||
|
||||
template <bool b>
|
||||
template<typename I1, typename I2>
|
||||
I2 copier<b>::do_copy(I1 first, I1 last, I2 out)
|
||||
{
|
||||
while(first != last)
|
||||
{
|
||||
*out = *first;
|
||||
++out;
|
||||
++first;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct copier<true>
|
||||
{
|
||||
template<typename I1, typename I2>
|
||||
static I2* do_copy(I1* first, I1* last, I2* out)
|
||||
{
|
||||
memcpy(out, first, (last-first)*sizeof(I2));
|
||||
return out+(last-first);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
template<typename I1, typename I2>
|
||||
inline I2 copy(I1 first, I1 last, I2 out)
|
||||
{
|
||||
typedef typename boost::remove_cv<typename std::iterator_traits<I1>::value_type>::type v1_t;
|
||||
typedef typename boost::remove_cv<typename std::iterator_traits<I2>::value_type>::type v2_t;
|
||||
enum{ can_opt = boost::is_same<v1_t, v2_t>::value
|
||||
&& boost::is_pointer<I1>::value
|
||||
&& boost::is_pointer<I2>::value
|
||||
&& boost::has_trivial_assign<v1_t>::value };
|
||||
return detail::copier<can_opt>::do_copy(first, last, out);
|
||||
}
|
||||
|
||||
//
|
||||
// fill
|
||||
// same as std::fill, uses memset where appropriate, along with call_traits
|
||||
// to "optimise" parameter passing.
|
||||
//
|
||||
namespace detail{
|
||||
|
||||
template <bool opt>
|
||||
struct filler
|
||||
{
|
||||
template <typename I, typename T>
|
||||
static void do_fill(I first, I last, typename boost::call_traits<T>::param_type val);
|
||||
};
|
||||
|
||||
template <bool b>
|
||||
template <typename I, typename T>
|
||||
void filler<b>::do_fill(I first, I last, typename boost::call_traits<T>::param_type val)
|
||||
{
|
||||
while(first != last)
|
||||
{
|
||||
*first = val;
|
||||
++first;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
struct filler<true>
|
||||
{
|
||||
template <typename I, typename T>
|
||||
static void do_fill(I first, I last, T val)
|
||||
{
|
||||
std::memset(first, val, last-first);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class I, class T>
|
||||
inline void fill(I first, I last, const T& val)
|
||||
{
|
||||
enum{ can_opt = boost::is_pointer<I>::value
|
||||
&& boost::is_arithmetic<T>::value
|
||||
&& (sizeof(T) == 1) };
|
||||
typedef detail::filler<can_opt> filler_t;
|
||||
filler_t::template do_fill<I,T>(first, last, val);
|
||||
}
|
||||
|
||||
//
|
||||
// iter_swap:
|
||||
// tests whether iterator is a proxying iterator or not, and
|
||||
// uses optimal form accordingly:
|
||||
//
|
||||
namespace detail{
|
||||
|
||||
template <bool b>
|
||||
struct swapper
|
||||
{
|
||||
template <typename I>
|
||||
static void do_swap(I one, I two)
|
||||
{
|
||||
typedef typename std::iterator_traits<I>::value_type v_t;
|
||||
v_t v = *one;
|
||||
*one = *two;
|
||||
*two = v;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
using std::swap;
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct swapper<true>
|
||||
{
|
||||
template <typename I>
|
||||
static void do_swap(I one, I two)
|
||||
{
|
||||
using std::swap;
|
||||
swap(*one, *two);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <typename I1, typename I2>
|
||||
inline void iter_swap(I1 one, I2 two)
|
||||
{
|
||||
typedef typename std::iterator_traits<I1>::reference r1_t;
|
||||
typedef typename std::iterator_traits<I2>::reference r2_t;
|
||||
enum{ can_opt = boost::is_reference<r1_t>::value && boost::is_reference<r2_t>::value && boost::is_same<r1_t, r2_t>::value };
|
||||
detail::swapper<can_opt>::do_swap(one, two);
|
||||
}
|
||||
|
||||
|
||||
}; // namespace opt
|
||||
|
||||
//
|
||||
// define some global data:
|
||||
//
|
||||
const int array_size = 1000;
|
||||
int i_array[array_size] = {0,};
|
||||
const int ci_array[array_size] = {0,};
|
||||
char c_array[array_size] = {0,};
|
||||
const char cc_array[array_size] = { 0,};
|
||||
|
||||
const int iter_count = 1000000;
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
//
|
||||
// test destroy_array,
|
||||
// compare destruction time of an array of ints
|
||||
// with unoptimised form.
|
||||
//
|
||||
cout << "Measuring times in micro-seconds per 1000 elements processed" << endl << endl;
|
||||
cout << "testing destroy_array...\n"
|
||||
"[Some compilers may be able to optimise the \"unoptimised\"\n versions as well as type_traits does.]" << endl;
|
||||
/*cache load*/ opt::destroy_array(i_array, i_array + array_size);
|
||||
boost::timer t;
|
||||
double result;
|
||||
int i;
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::destroy_array(i_array, i_array + array_size);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "destroy_array<int>: " << result << endl;
|
||||
/*cache load*/ opt::destroy_array1(i_array, i_array + array_size);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::destroy_array1(i_array, i_array + array_size);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "destroy_array<int>(unoptimised#1): " << result << endl;
|
||||
/*cache load*/ opt::destroy_array2(i_array, i_array + array_size);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::destroy_array2(i_array, i_array + array_size);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "destroy_array<int>(unoptimised#2): " << result << endl << endl;
|
||||
|
||||
cout << "testing fill(char)...\n"
|
||||
"[Some standard library versions may already perform this optimisation.]" << endl;
|
||||
/*cache load*/ opt::fill<char*, char>(c_array, c_array + array_size, (char)3);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::fill<char*, char>(c_array, c_array + array_size, (char)3);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "opt::fill<char*, char>: " << result << endl;
|
||||
/*cache load*/ std::fill(c_array, c_array + array_size, (char)3);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
std::fill(c_array, c_array + array_size, (char)3);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "std::fill<char*, char>: " << result << endl << endl;
|
||||
|
||||
cout << "testing fill(int)...\n"
|
||||
"[Tests the effect of call_traits pass-by-value optimisation -\nthe value of this optimisation may depend upon hardware characteristics.]" << endl;
|
||||
/*cache load*/ opt::fill<int*, int>(i_array, i_array + array_size, 3);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::fill<int*, int>(i_array, i_array + array_size, 3);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "opt::fill<int*, int>: " << result << endl;
|
||||
/*cache load*/ std::fill(i_array, i_array + array_size, 3);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
std::fill(i_array, i_array + array_size, 3);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "std::fill<int*, int>: " << result << endl << endl;
|
||||
|
||||
cout << "testing copy...\n"
|
||||
"[Some standard library versions may already perform this optimisation.]" << endl;
|
||||
/*cache load*/ opt::copy<const int*, int*>(ci_array, ci_array + array_size, i_array);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::copy<const int*, int*>(ci_array, ci_array + array_size, i_array);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "opt::copy<const int*, int*>: " << result << endl;
|
||||
/*cache load*/ std::copy<const int*, int*>(ci_array, ci_array + array_size, i_array);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
std::copy<const int*, int*>(ci_array, ci_array + array_size, i_array);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "std::copy<const int*, int*>: " << result << endl;
|
||||
/*cache load*/ opt::detail::copier<false>::template do_copy<const int*, int*>(ci_array, ci_array + array_size, i_array);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::detail::copier<false>::template do_copy<const int*, int*>(ci_array, ci_array + array_size, i_array);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "standard \"unoptimised\" copy: " << result << endl << endl;
|
||||
|
||||
/*cache load*/ opt::copy<const char*, char*>(cc_array, cc_array + array_size, c_array);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::copy<const char*, char*>(cc_array, cc_array + array_size, c_array);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "opt::copy<const char*, char*>: " << result << endl;
|
||||
/*cache load*/ std::copy<const char*, char*>(cc_array, cc_array + array_size, c_array);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
std::copy<const char*, char*>(cc_array, cc_array + array_size, c_array);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "std::copy<const char*, char*>: " << result << endl;
|
||||
/*cache load*/ opt::detail::copier<false>::template do_copy<const char*, char*>(cc_array, cc_array + array_size, c_array);
|
||||
t.restart();
|
||||
for(i = 0; i < iter_count; ++i)
|
||||
{
|
||||
opt::detail::copier<false>::template do_copy<const char*, char*>(cc_array, cc_array + array_size, c_array);
|
||||
}
|
||||
result = t.elapsed();
|
||||
cout << "standard \"unoptimised\" copy: " << result << endl << endl;
|
||||
|
||||
|
||||
//
|
||||
// testing iter_swap
|
||||
// really just a check that it does in fact compile...
|
||||
std::vector<int> v1;
|
||||
v1.push_back(0);
|
||||
v1.push_back(1);
|
||||
std::vector<bool> v2;
|
||||
v2.push_back(0);
|
||||
v2.push_back(1);
|
||||
opt::iter_swap(v1.begin(), v1.begin()+1);
|
||||
opt::iter_swap(v2.begin(), v2.begin()+1);
|
||||
|
||||
cout << "Press any key to exit...";
|
||||
cin.get();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
53
filter_iterator_example.cpp
Normal file
53
filter_iterator_example.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Example of using the filter iterator adaptor from
|
||||
// boost/iterator_adaptors.hpp.
|
||||
|
||||
// (C) Copyright Jeremy Siek 1999. Permission to copy, use, modify,
|
||||
// sell and distribute this software is granted provided this
|
||||
// copyright notice appears in all copies. This software is provided
|
||||
// "as is" without express or implied warranty, and with no claim as
|
||||
// to its suitability for any purpose.
|
||||
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
struct is_positive_number {
|
||||
bool operator()(int x) { return 0 < x; }
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
int numbers[] = { 0, -1, 4, -3, 5, 8, -2 };
|
||||
const int N = sizeof(numbers)/sizeof(int);
|
||||
|
||||
// Example using make_filter_iterator()
|
||||
std::copy(boost::make_filter_iterator<is_positive_number>(numbers, numbers + N),
|
||||
boost::make_filter_iterator<is_positive_number>(numbers + N, numbers + N),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
// Example using filter_iterator_generator
|
||||
typedef boost::filter_iterator_generator<is_positive_number, int*, int>::type
|
||||
FilterIter;
|
||||
is_positive_number predicate;
|
||||
FilterIter::policies_type policies(predicate, numbers + N);
|
||||
FilterIter filter_iter_first(numbers, policies);
|
||||
FilterIter filter_iter_last(numbers + N, policies);
|
||||
|
||||
std::copy(filter_iter_first, filter_iter_last, std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
// Another example using make_filter_iterator()
|
||||
std::copy(boost::make_filter_iterator(numbers, numbers + N,
|
||||
std::bind2nd(std::greater<int>(), -2)),
|
||||
boost::make_filter_iterator(numbers + N, numbers + N,
|
||||
std::bind2nd(std::greater<int>(), -2)),
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
385
numeric_traits_test.cpp
Normal file
385
numeric_traits_test.cpp
Normal file
@@ -0,0 +1,385 @@
|
||||
// (C) Copyright David Abrahams 2001. Permission to copy, use, modify,
|
||||
// sell and distribute this software is granted provided this
|
||||
// copyright notice appears in all copies. This software is provided
|
||||
// "as is" without express or implied warranty, and with no claim as
|
||||
// to its suitability for any purpose.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
// Revision History
|
||||
// 23 Jan 2001 Added test for wchar_t (David Abrahams)
|
||||
// 23 Jan 2001 Now statically selecting a test for signed numbers to avoid
|
||||
// warnings with fancy compilers. Added commentary and
|
||||
// additional dumping of traits data for tested types (David
|
||||
// Abrahams).
|
||||
// 21 Jan 2001 Initial version (David Abrahams)
|
||||
|
||||
#include <boost/detail/numeric_traits.hpp>
|
||||
#include <cassert>
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <climits>
|
||||
#include <typeinfo>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#ifndef BOOST_NO_LIMITS
|
||||
# include <limits>
|
||||
#endif
|
||||
|
||||
// A macro for declaring class compile-time constants.
|
||||
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
|
||||
# define DECLARE_CLASS_CONST(type, init) static const type init
|
||||
#else
|
||||
# define DECLARE_CLASS_CONST(type, init) enum { init }
|
||||
#endif
|
||||
|
||||
// =================================================================================
|
||||
// template class complement_traits<Number> --
|
||||
//
|
||||
// statically computes the max and min for 1s and 2s-complement binary
|
||||
// numbers. This helps on platforms without <limits> support. It also shows
|
||||
// an example of a recursive template that works with MSVC!
|
||||
//
|
||||
|
||||
template <unsigned size> struct complement; // forward
|
||||
|
||||
// The template complement, below, does all the real work, using "poor man's
|
||||
// partial specialization". We need complement_traits_aux<> so that MSVC doesn't
|
||||
// complain about undefined min/max as we're trying to recursively define them.
|
||||
template <class Number, unsigned size>
|
||||
struct complement_traits_aux
|
||||
{
|
||||
DECLARE_CLASS_CONST(Number, max = complement<size>::template traits<Number>::max);
|
||||
DECLARE_CLASS_CONST(Number, min = complement<size>::template traits<Number>::min);
|
||||
};
|
||||
|
||||
template <unsigned size>
|
||||
struct complement
|
||||
{
|
||||
template <class Number>
|
||||
struct traits
|
||||
{
|
||||
private:
|
||||
// indirection through complement_traits_aux neccessary to keep MSVC happy
|
||||
typedef complement_traits_aux<Number, size - 1> prev;
|
||||
public:
|
||||
DECLARE_CLASS_CONST(Number, max =
|
||||
Number(Number(prev::max) << CHAR_BIT)
|
||||
+ Number(UCHAR_MAX));
|
||||
|
||||
DECLARE_CLASS_CONST(Number, min = Number(Number(prev::min) << CHAR_BIT));
|
||||
};
|
||||
};
|
||||
|
||||
// Template class complement_base<> -- defines values for min and max for
|
||||
// complement<1>, at the deepest level of recursion. Uses "poor man's partial
|
||||
// specialization" again.
|
||||
template <bool is_signed> struct complement_base;
|
||||
|
||||
template <> struct complement_base<false>
|
||||
{
|
||||
template <class Number>
|
||||
struct values
|
||||
{
|
||||
DECLARE_CLASS_CONST(Number, min = 0);
|
||||
DECLARE_CLASS_CONST(Number, max = UCHAR_MAX);
|
||||
};
|
||||
};
|
||||
|
||||
template <> struct complement_base<true>
|
||||
{
|
||||
template <class Number>
|
||||
struct values
|
||||
{
|
||||
DECLARE_CLASS_CONST(Number, min = SCHAR_MIN);
|
||||
DECLARE_CLASS_CONST(Number, max = SCHAR_MAX);
|
||||
};
|
||||
};
|
||||
|
||||
// Base specialization of complement, puts an end to the recursion.
|
||||
template <>
|
||||
struct complement<1>
|
||||
{
|
||||
template <class Number>
|
||||
struct traits
|
||||
{
|
||||
DECLARE_CLASS_CONST(bool, is_signed = boost::detail::is_signed<Number>::value);
|
||||
DECLARE_CLASS_CONST(Number, min =
|
||||
complement_base<is_signed>::template values<Number>::min);
|
||||
DECLARE_CLASS_CONST(Number, max =
|
||||
complement_base<is_signed>::template values<Number>::max);
|
||||
};
|
||||
};
|
||||
|
||||
// Now here's the "pretty" template you're intended to actually use.
|
||||
// complement_traits<Number>::min, complement_traits<Number>::max are the
|
||||
// minimum and maximum values of Number if Number is a built-in integer type.
|
||||
template <class Number>
|
||||
struct complement_traits
|
||||
{
|
||||
DECLARE_CLASS_CONST(Number, max = (complement_traits_aux<Number, sizeof(Number)>::max));
|
||||
DECLARE_CLASS_CONST(Number, min = (complement_traits_aux<Number, sizeof(Number)>::min));
|
||||
};
|
||||
|
||||
// =================================================================================
|
||||
|
||||
// Support for streaming various numeric types in exactly the format I want. I
|
||||
// needed this in addition to all the assertions so that I could see exactly
|
||||
// what was going on.
|
||||
//
|
||||
// Numbers go through a 2-stage conversion process (by default, though, no real
|
||||
// conversion).
|
||||
//
|
||||
template <class T> struct stream_as {
|
||||
typedef T t1;
|
||||
typedef T t2;
|
||||
};
|
||||
|
||||
// char types first get converted to unsigned char, then to unsigned.
|
||||
template <> struct stream_as<char> {
|
||||
typedef unsigned char t1;
|
||||
typedef unsigned t2;
|
||||
};
|
||||
template <> struct stream_as<unsigned char> {
|
||||
typedef unsigned char t1; typedef unsigned t2;
|
||||
};
|
||||
template <> struct stream_as<signed char> {
|
||||
typedef unsigned char t1; typedef unsigned t2;
|
||||
};
|
||||
|
||||
#if defined(BOOST_MSVC) // No intmax streaming built-in
|
||||
|
||||
// On this platform, __int64 and __uint64 get streamed as strings
|
||||
template <> struct stream_as<boost::uintmax_t> {
|
||||
typedef std::string t1;
|
||||
typedef std::string t2;
|
||||
};
|
||||
|
||||
template <> struct stream_as<boost::intmax_t> {
|
||||
typedef std::string t1;
|
||||
typedef std::string t2;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Standard promotion process for streaming
|
||||
template <class T> struct promote
|
||||
{
|
||||
static typename stream_as<T>::t1 from(T x) {
|
||||
typedef typename stream_as<T>::t1 t1;
|
||||
return t1(x);
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(BOOST_MSVC) // No intmax streaming built-in
|
||||
|
||||
// On this platform, stream them as long/unsigned long if they fit.
|
||||
// Otherwise, write a string.
|
||||
template <> struct promote<boost::uintmax_t> {
|
||||
std::string static from(const boost::uintmax_t x) {
|
||||
if (x > ULONG_MAX)
|
||||
return std::string("large unsigned value");
|
||||
else
|
||||
return boost::lexical_cast<std::string>((unsigned long)x);
|
||||
}
|
||||
};
|
||||
template <> struct promote<boost::intmax_t> {
|
||||
std::string static from(const boost::intmax_t x) {
|
||||
if (x > boost::intmax_t(ULONG_MAX))
|
||||
return std::string("large positive signed value");
|
||||
else if (x >= 0)
|
||||
return boost::lexical_cast<std::string>((unsigned long)x);
|
||||
|
||||
if (x < boost::intmax_t(LONG_MIN))
|
||||
return std::string("large negative signed value");
|
||||
else
|
||||
return boost::lexical_cast<std::string>((long)x);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
// This is the function which converts types to the form I want to stream them in.
|
||||
template <class T>
|
||||
typename stream_as<T>::t2 stream_number(T x)
|
||||
{
|
||||
return promote<T>::from(x);
|
||||
}
|
||||
// =================================================================================
|
||||
|
||||
//
|
||||
// Tests for built-in signed and unsigned types
|
||||
//
|
||||
|
||||
// Tag types for selecting tests
|
||||
struct unsigned_tag {};
|
||||
struct signed_tag {};
|
||||
|
||||
// Tests for unsigned numbers. The extra default Number parameter works around
|
||||
// an MSVC bug.
|
||||
template <class Number>
|
||||
void test_aux(unsigned_tag, Number* = 0)
|
||||
{
|
||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
||||
BOOST_STATIC_ASSERT(!boost::detail::is_signed<Number>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
(sizeof(Number) < sizeof(boost::intmax_t))
|
||||
| (boost::is_same<difference_type, boost::intmax_t>::value));
|
||||
|
||||
// Force casting to Number here to work around the fact that it's an enum on MSVC
|
||||
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::max) > Number(0));
|
||||
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::min) == Number(0));
|
||||
|
||||
const Number max = complement_traits<Number>::max;
|
||||
const Number min = complement_traits<Number>::min;
|
||||
|
||||
const Number test_max = (sizeof(Number) < sizeof(boost::intmax_t))
|
||||
? max
|
||||
: max / 2 - 1;
|
||||
|
||||
std::cout << std::hex << "(unsigned) min = " << stream_number(min) << ", max = "
|
||||
<< stream_number(max) << "..." << std::flush;
|
||||
std::cout << "difference_type = " << typeid(difference_type).name() << "..."
|
||||
<< std::flush;
|
||||
|
||||
difference_type d1 = boost::detail::numeric_distance(Number(0), test_max);
|
||||
difference_type d2 = boost::detail::numeric_distance(test_max, Number(0));
|
||||
|
||||
std::cout << "0->" << stream_number(test_max) << "==" << std::dec << stream_number(d1) << "; "
|
||||
<< std::hex << stream_number(test_max) << "->0==" << std::dec << stream_number(d2) << "..." << std::flush;
|
||||
|
||||
assert(d1 == difference_type(test_max));
|
||||
assert(d2 == -difference_type(test_max));
|
||||
}
|
||||
|
||||
// Tests for signed numbers. The extra default Number parameter works around an
|
||||
// MSVC bug.
|
||||
struct out_of_range_tag {};
|
||||
struct in_range_tag {};
|
||||
|
||||
// This test morsel gets executed for numbers whose difference will always be
|
||||
// representable in intmax_t
|
||||
template <class Number>
|
||||
void signed_test(in_range_tag, Number* = 0)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
|
||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
||||
const Number max = complement_traits<Number>::max;
|
||||
const Number min = complement_traits<Number>::min;
|
||||
|
||||
difference_type d1 = boost::detail::numeric_distance(min, max);
|
||||
difference_type d2 = boost::detail::numeric_distance(max, min);
|
||||
|
||||
std::cout << stream_number(min) << "->" << stream_number(max) << "==";
|
||||
std::cout << std::dec << stream_number(d1) << "; ";
|
||||
std::cout << std::hex << stream_number(max) << "->" << stream_number(min)
|
||||
<< "==" << std::dec << stream_number(d2) << "..." << std::flush;
|
||||
assert(d1 == difference_type(max) - difference_type(min));
|
||||
assert(d2 == difference_type(min) - difference_type(max));
|
||||
}
|
||||
|
||||
// This test morsel gets executed for numbers whose difference may exceed the
|
||||
// capacity of intmax_t.
|
||||
template <class Number>
|
||||
void signed_test(out_of_range_tag, Number* = 0)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
|
||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
||||
const Number max = complement_traits<Number>::max;
|
||||
const Number min = complement_traits<Number>::min;
|
||||
|
||||
difference_type min_distance = complement_traits<difference_type>::min;
|
||||
difference_type max_distance = complement_traits<difference_type>::max;
|
||||
|
||||
const Number n1 = Number(min + max_distance);
|
||||
const Number n2 = Number(max + min_distance);
|
||||
difference_type d1 = boost::detail::numeric_distance(min, n1);
|
||||
difference_type d2 = boost::detail::numeric_distance(max, n2);
|
||||
|
||||
std::cout << stream_number(min) << "->" << stream_number(n1) << "==";
|
||||
std::cout << std::dec << stream_number(d1) << "; ";
|
||||
std::cout << std::hex << stream_number(max) << "->" << stream_number(n2)
|
||||
<< "==" << std::dec << stream_number(d2) << "..." << std::flush;
|
||||
assert(d1 == max_distance);
|
||||
assert(d2 == min_distance);
|
||||
}
|
||||
|
||||
template <class Number>
|
||||
void test_aux(signed_tag, Number* = 0)
|
||||
{
|
||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
||||
BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
|
||||
BOOST_STATIC_ASSERT(
|
||||
(sizeof(Number) < sizeof(boost::intmax_t))
|
||||
| (boost::is_same<difference_type, Number>::value));
|
||||
|
||||
// Force casting to Number here to work around the fact that it's an enum on MSVC
|
||||
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::max) > Number(0));
|
||||
BOOST_STATIC_ASSERT(Number(complement_traits<Number>::min) < Number(0));
|
||||
|
||||
const Number max = complement_traits<Number>::max;
|
||||
const Number min = complement_traits<Number>::min;
|
||||
|
||||
std::cout << std::hex << "min = " << stream_number(min) << ", max = "
|
||||
<< stream_number(max) << "..." << std::flush;
|
||||
std::cout << "difference_type = " << typeid(difference_type).name() << "..."
|
||||
<< std::flush;
|
||||
|
||||
typedef typename boost::detail::if_true<
|
||||
(sizeof(Number) < sizeof(boost::intmax_t))>
|
||||
::template then<
|
||||
in_range_tag,
|
||||
out_of_range_tag
|
||||
>::type
|
||||
range_tag;
|
||||
signed_test<Number>(range_tag());
|
||||
}
|
||||
|
||||
|
||||
// Test for all numbers. The extra default Number parameter works around an MSVC
|
||||
// bug.
|
||||
template <class Number>
|
||||
void test(Number* = 0)
|
||||
{
|
||||
std::cout << "testing " << typeid(Number).name() << ":\n"
|
||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
<< "is_signed: " << (std::numeric_limits<Number>::is_signed ? "true\n" : "false\n")
|
||||
<< "is_bounded: " << (std::numeric_limits<Number>::is_bounded ? "true\n" : "false\n")
|
||||
<< "digits: " << std::numeric_limits<Number>::digits << "\n"
|
||||
#endif
|
||||
<< "..." << std::flush;
|
||||
typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
|
||||
BOOST_STATIC_ASSERT(boost::detail::is_signed<difference_type>::value);
|
||||
|
||||
typedef typename boost::detail::if_true<
|
||||
boost::detail::is_signed<Number>::value
|
||||
>::template then<signed_tag, unsigned_tag>::type signedness;
|
||||
|
||||
test_aux<Number>(signedness());
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test<char>();
|
||||
test<unsigned char>();
|
||||
test<signed char>();
|
||||
test<wchar_t>();
|
||||
test<short>();
|
||||
test<unsigned short>();
|
||||
test<int>();
|
||||
test<unsigned int>();
|
||||
test<long>();
|
||||
test<unsigned long>();
|
||||
#if defined(ULLONG_MAX) || defined(ULONG_LONG_MAX)
|
||||
test<long long>();
|
||||
test<unsigned long long>();
|
||||
#elif defined(BOOST_MSVC)
|
||||
// The problem of not having compile-time static class constants other than
|
||||
// enums prevents this from working, since values get truncated.
|
||||
// test<boost::uintmax_t>();
|
||||
// test<boost::intmax_t>();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
391
projection_iterator.htm
Normal file
391
projection_iterator.htm
Normal file
@@ -0,0 +1,391 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<title>Projection Iterator Adaptor Documentation</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF" text="#000000">
|
||||
|
||||
<img src="../../c++boost.gif" alt="c++boost.gif (8819 bytes)"
|
||||
align="center" width="277" height="86">
|
||||
|
||||
<h1>Projection Iterator Adaptor</h1>
|
||||
|
||||
Defined in header
|
||||
<a href="../../boost/iterator_adaptors.hpp">boost/iterator_adaptors.hpp</a>
|
||||
|
||||
<p>
|
||||
The projection iterator adaptor is similar to the <a
|
||||
href="./transform_iterator.htm">transform iterator adaptor</a> in that
|
||||
its <tt>operator*()</tt> applies some function to the result of
|
||||
dereferencing the base iterator and then returns the result. The
|
||||
difference is that the function must return a reference to some
|
||||
existing object (for example, a data member within the
|
||||
<tt>value_type</tt> of the base iterator). The following
|
||||
<b>pseudo-code</b> gives the basic idea. The data member <tt>p</tt> is
|
||||
the function object.
|
||||
|
||||
<pre>
|
||||
reference projection_iterator::operator*() const {
|
||||
return this->p(*this->base_iterator);
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2>Synopsis</h2>
|
||||
|
||||
<pre>
|
||||
namespace boost {
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator>
|
||||
struct projection_iterator_generator;
|
||||
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>,
|
||||
class BaseIterator, class ConstBaseIterator>
|
||||
struct projection_iterator_pair_generator;
|
||||
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator>
|
||||
typename projection_iterator_generator<AdaptableUnaryFunction, BaseIterator>::type
|
||||
make_projection_iterator(BaseIterator base,
|
||||
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
|
||||
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class ConstBaseIterator>
|
||||
typename projection_iterator_generator<AdaptableUnaryFunction, ConstBaseIterator>::type
|
||||
make_const_projection_iterator(ConstBaseIterator base,
|
||||
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
|
||||
}
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2><a name="projection_iterator_generator">The Projection Iterator Type
|
||||
Generator</a></h2>
|
||||
|
||||
The class <tt>projection_iterator_generator</tt> is a helper class
|
||||
whose purpose is to construct an projection iterator type. The main
|
||||
template parameter for this class is the <a
|
||||
href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a>
|
||||
function object type and the <tt>BaseIterator</tt> type that is being
|
||||
wrapped.
|
||||
|
||||
<pre>
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator>
|
||||
class projection_iterator_generator
|
||||
{
|
||||
public:
|
||||
typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> type; // the resulting projection iterator type
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
In the following example we have a list of personnel records. Each
|
||||
record has an employee's name and ID number. We want to be able to
|
||||
traverse through the list accessing either the name or the ID numbers
|
||||
of the employees using the projection iterator so we create the
|
||||
function object classes <tt>select_name</tt> and
|
||||
<tt>select_ID</tt>. We then use the
|
||||
<tt>projection_iterator_generator</tt> class to create a projection
|
||||
iterator and use it to print out the names of the employees.
|
||||
|
||||
<pre>
|
||||
#include <boost/config.hpp>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
struct personnel_record {
|
||||
personnel_record(std::string n, int id) : m_name(n), m_ID(id) { }
|
||||
std::string m_name;
|
||||
int m_ID;
|
||||
};
|
||||
|
||||
struct select_name {
|
||||
typedef personnel_record argument_type;
|
||||
typedef std::string result_type;
|
||||
const std::string& operator()(const personnel_record& r) const {
|
||||
return r.m_name;
|
||||
}
|
||||
std::string& operator()(personnel_record& r) const {
|
||||
return r.m_name;
|
||||
}
|
||||
};
|
||||
|
||||
struct select_ID {
|
||||
typedef personnel_record argument_type;
|
||||
typedef int result_type;
|
||||
const int& operator()(const personnel_record& r) const {
|
||||
return r.m_ID;
|
||||
}
|
||||
int& operator()(personnel_record& r) const {
|
||||
return r.m_ID;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
std::list<personnel_record> personnel_list;
|
||||
|
||||
personnel_list.push_back(personnel_record("Barney", 13423));
|
||||
personnel_list.push_back(personnel_record("Fred", 12343));
|
||||
personnel_list.push_back(personnel_record("Wilma", 62454));
|
||||
personnel_list.push_back(personnel_record("Betty", 20490));
|
||||
|
||||
// Example of using projection_iterator_generator
|
||||
// to print out the names in the personnel list.
|
||||
|
||||
boost::projection_iterator_generator<select_name,
|
||||
std::list<personnel_record>::iterator>::type
|
||||
personnel_first(personnel_list.begin()),
|
||||
personnel_last(personnel_list.end());
|
||||
|
||||
std::copy(personnel_first, personnel_last,
|
||||
std::ostream_iterator<std::string>(std::cout, "\n"));
|
||||
std::cout << std::endl;
|
||||
|
||||
// to be continued...
|
||||
</pre>
|
||||
The output for this part is:
|
||||
<pre>
|
||||
Barney
|
||||
Fred
|
||||
Wilma
|
||||
Betty
|
||||
</pre>
|
||||
|
||||
<h3>Template Parameters</h3>
|
||||
|
||||
<Table border>
|
||||
<TR>
|
||||
<TH>Parameter</TH><TH>Description</TH>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a></TD>
|
||||
<TD>The type of the function object. The <tt>argument_type</tt> of the
|
||||
function must match the value type of the base iterator. The function
|
||||
should return a reference to the function's <tt>result_type</tt>.
|
||||
The <tt>result_type</tt> will be the resulting iterator's <tt>value_type</tt>.
|
||||
</TD>
|
||||
</TD>
|
||||
|
||||
<TR>
|
||||
<TD><tt>BaseIterator</tt></TD>
|
||||
<TD>The iterator type being wrapped.</TD>
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
</Table>
|
||||
|
||||
<h3>Model of</h3>
|
||||
|
||||
If the base iterator is a model of <a
|
||||
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||
Access Iterator</a> then so is the resulting projection iterator. If
|
||||
the base iterator supports less functionality than this the resulting
|
||||
projection iterator will also support less functionality.
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
The projection iterator type implements the member functions and
|
||||
operators required of the <a
|
||||
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||
Access Iterator</a> concept.
|
||||
In addition it has the following constructor:
|
||||
|
||||
<pre>
|
||||
projection_iterator_generator::type(const BaseIterator& it,
|
||||
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<hr>
|
||||
<p>
|
||||
|
||||
<h2><a name="projection_iterator_pair_generator">The Projection Iterator Pair
|
||||
Generator</a></h2>
|
||||
|
||||
Sometimes a mutable/const pair of iterator types is needed, such as
|
||||
when implementing a container type. The
|
||||
<tt>projection_iterator_pair_generator</tt> class makes it more
|
||||
convenient to create this pair of iterator types.
|
||||
|
||||
<pre>
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator, class ConstBaseIterator>
|
||||
class projection_iterator_pair_generator
|
||||
{
|
||||
public:
|
||||
typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> iterator; // the mutable projection iterator type
|
||||
typedef <tt><a href="./iterator_adaptors.htm#iterator_adaptor">iterator_adaptor</a><...></tt> const_iterator; // the immutable projection iterator type
|
||||
};
|
||||
</pre>
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
In this part of the example we use the
|
||||
<tt>projection_iterator_pair_generator</tt> to create a mutable/const
|
||||
pair of projection iterators that access the ID numbers of the
|
||||
personnel. We use the mutable iterator to re-index the ID numbers from
|
||||
zero. We then use the constant iterator to print the ID numbers out.
|
||||
|
||||
<pre>
|
||||
// continuing from the last example...
|
||||
|
||||
typedef boost::projection_iterator_pair_generator<select_ID,
|
||||
std::list<personnel_record>::iterator,
|
||||
std::list<personnel_record>::const_iterator> PairGen;
|
||||
|
||||
PairGen::iterator ID_first(personnel_list.begin()),
|
||||
ID_last(personnel_list.end());
|
||||
|
||||
int new_id = 0;
|
||||
while (ID_first != ID_last) {
|
||||
*ID_first = new_id++;
|
||||
++ID_first;
|
||||
}
|
||||
|
||||
PairGen::const_iterator const_ID_first(personnel_list.begin()),
|
||||
const_ID_last(personnel_list.end());
|
||||
|
||||
std::copy(const_ID_first, const_ID_last,
|
||||
std::ostream_iterator<int>(std::cout, " "));
|
||||
std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
|
||||
// to be continued...
|
||||
</pre>
|
||||
The output is:
|
||||
<pre>
|
||||
0 1 2 3
|
||||
</pre>
|
||||
|
||||
<h3>Template Parameters</h3>
|
||||
|
||||
<Table border>
|
||||
<TR>
|
||||
<TH>Parameter</TH><TH>Description</TH>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html"><tt>AdaptableUnaryFunction</tt></a></TD>
|
||||
<TD>The type of the function object. The <tt>argument_type</tt> of the
|
||||
function must match the value type of the base iterator. The function
|
||||
should return a true reference to the function's <tt>result_type</tt>.
|
||||
The <tt>result_type</tt> will be the resulting iterator's <tt>value_type</tt>.
|
||||
</TD>
|
||||
</TD>
|
||||
|
||||
<TR>
|
||||
<TD><tt>BaseIterator</tt></TD>
|
||||
<TD>The mutable iterator type being wrapped.</TD>
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
<TR>
|
||||
<TD><tt>ConstBaseIterator</tt></TD>
|
||||
<TD>The constant iterator type being wrapped.</TD>
|
||||
</TD>
|
||||
</TR>
|
||||
|
||||
</Table>
|
||||
|
||||
<h3>Model of</h3>
|
||||
|
||||
If the base iterator types model the <a
|
||||
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||
Access Iterator</a> then so do the resulting projection iterator
|
||||
types. If the base iterators support less functionality the
|
||||
resulting projection iterator types will also support less
|
||||
functionality. The resulting <tt>iterator</tt> type is mutable, and
|
||||
the resulting <tt>const_iterator</tt> type is constant.
|
||||
|
||||
<h3>Members</h3>
|
||||
|
||||
The resulting <tt>iterator</tt> and <tt>const_iterator</tt> types
|
||||
implements the member functions and operators required of the <a
|
||||
href="http://www.sgi.com/tech/stl/RandomAccessIterator.html">Random
|
||||
Access Iterator</a> concept. In addition they support the following
|
||||
constructors:
|
||||
|
||||
<pre>
|
||||
projection_iterator_pair_generator::iterator(const BaseIterator& it,
|
||||
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())</pre>
|
||||
|
||||
<pre>
|
||||
projection_iterator_pair_generator::const_iterator(const BaseIterator& it,
|
||||
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<hr>
|
||||
<p>
|
||||
|
||||
<h2><a name="make_projection_iterator">The Projection Iterator Object Generators</a></h2>
|
||||
|
||||
The <tt>make_projection_iterator()</tt> and
|
||||
<tt>make_const_projection_iterator()</tt> functions provide a more
|
||||
convenient way to create projection iterator objects. The functions
|
||||
save the user the trouble of explicitly writing out the iterator
|
||||
types.
|
||||
|
||||
<pre>
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class BaseIterator>
|
||||
typename projection_iterator_generator<AdaptableUnaryFunction, BaseIterator>::type
|
||||
make_projection_iterator(BaseIterator base,
|
||||
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
|
||||
|
||||
template <class <a href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">AdaptableUnaryFunction</a>, class ConstBaseIterator>
|
||||
typename projection_iterator_generator<AdaptableUnaryFunction, ConstBaseIterator>::type
|
||||
make_const_projection_iterator(ConstBaseIterator base,
|
||||
const AdaptableUnaryFunction& p = AdaptableUnaryFunction())
|
||||
</pre>
|
||||
|
||||
|
||||
<h3>Example</h3>
|
||||
|
||||
In this part of the example, we again print out the names of the
|
||||
personnel, but this time we use the
|
||||
<tt>make_const_projection_iterator()</tt> function to save some typing.
|
||||
|
||||
<pre>
|
||||
// continuing from the last example...
|
||||
|
||||
std::copy
|
||||
(boost::make_const_projection_iterator<select_name>(personnel_list.begin()),
|
||||
boost::make_const_projection_iterator<select_name>(personnel_list.end()),
|
||||
std::ostream_iterator<std::string>(std::cout, "\n"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
</pre>
|
||||
The output is:
|
||||
<pre>
|
||||
Barney
|
||||
Fred
|
||||
Wilma
|
||||
Betty
|
||||
</pre>
|
||||
|
||||
<hr>
|
||||
<p>Revised <!--webbot bot="Timestamp" s-type="EDITED" s-format="%d %b %Y" startspan -->16 Feb 2001<!--webbot bot="Timestamp" endspan i-checksum="14385" --></p>
|
||||
<p><EFBFBD> Copyright Jeremy Siek 2000. 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>
|
||||
<!-- LocalWords: html charset alt gif hpp BaseIterator const namespace struct
|
||||
-->
|
||||
<!-- LocalWords: ConstPointer ConstReference typename iostream int abcdefg
|
||||
-->
|
||||
<!-- LocalWords: sizeof PairGen pre Siek htm AdaptableUnaryFunction
|
||||
-->
|
||||
<!-- LocalWords: ConstBaseIterator
|
||||
-->
|
Reference in New Issue
Block a user