Refactor circulators a little

Give a name proper name to meta-functions that are not used outside
Circulator and enable conversion between circulator tags.
This commit is contained in:
Philipp Möller 2012-11-17 02:05:19 +01:00
parent f15cf44e06
commit e623040728
3 changed files with 112 additions and 127 deletions

View File

@ -26,11 +26,15 @@
#define CGAL_CIRCULATOR_H #define CGAL_CIRCULATOR_H
#include <CGAL/basic.h> #include <CGAL/basic.h>
#include <CGAL/circulator_bases.h>
#include <CGAL/use.h>
#include <cstddef> #include <cstddef>
#include <functional> #include <functional>
#include <iterator> #include <iterator>
#include <CGAL/circulator_bases.h>
#include <CGAL/use.h> #include <boost/type_traits/is_convertible.hpp>
#include <boost/static_assert.hpp>
// These are name redefinitions for backwards compatibility // These are name redefinitions for backwards compatibility
// with the pre iterator-traits style adaptors. // with the pre iterator-traits style adaptors.
@ -73,25 +77,27 @@
namespace CGAL { namespace CGAL {
template <class C> namespace internal {
struct I_Circulator_traits {
typedef Iterator_tag category;
};
template <> // default to Iterator_tag, special case Circulator tags
struct I_Circulator_traits<Forward_circulator_tag> { template<typename Tag>
typedef Circulator_tag category; struct Get_category
}; { typedef Iterator_tag type; };
template <> template<>
struct I_Circulator_traits<Bidirectional_circulator_tag> { struct Get_category<CGAL::Forward_circulator_tag>
typedef Circulator_tag category; { typedef Circulator_tag type; };
};
template<>
struct Get_category<CGAL::Bidirectional_circulator_tag>
{ typedef Circulator_tag type; };
template<>
struct Get_category<CGAL::Random_access_circulator_tag>
{ typedef Circulator_tag type; };
} // internal
template <>
struct I_Circulator_traits<Random_access_circulator_tag> {
typedef Circulator_tag category;
};
// Circulator_size_traits are used by general adaptors for // Circulator_size_traits are used by general adaptors for
// iterators and circulators. For example the N_step_adaptor // iterators and circulators. For example the N_step_adaptor
@ -163,16 +169,24 @@ struct I_Circulator_from_iterator_traits<std::random_access_iterator_tag> {
template <class C> template <class C>
struct Circulator_traits { struct Circulator_traits {
typedef std::iterator_traits<C> traits; private:
typedef typename traits::iterator_category ICAT; typedef std::iterator_traits<C> iterator_traits;
typedef I_Circulator_traits<ICAT> C_traits; public:
typedef typename C_traits::category category; // the ardent reader might wonder: why redirect through
// iterator_traits? That way we don't miss specializations and
// can save us our own specializations.
typedef typename internal::Get_category<
typename iterator_traits::iterator_category
>::type category;
typedef I_Iterator_from_circulator_traits<ICAT> Ic_traits; typedef typename iterator_traits::value_type value_type;
typedef typename Ic_traits::iterator_category iterator_category; typedef typename iterator_traits::reference reference;
typedef typename iterator_traits::pointer pointer;
typedef typename iterator_traits::difference_type difference_type;
typedef typename iterator_traits::iterator_category iterator_category;
typedef I_Circulator_from_iterator_traits<ICAT> Ci_traits; typedef typename I_Circulator_size_traits<
typedef typename Ci_traits::iterator_category circulator_category; category, C>::size_type size_type;
}; };
template <class C> template <class C>
@ -181,64 +195,44 @@ query_circulator_or_iterator( const C&) {
typedef typename Circulator_traits<C>::category category; typedef typename Circulator_traits<C>::category category;
return category(); return category();
} }
/* A function that asserts a specific compile time tag */
/* forcing its two arguments to have equal type. */
/* It is encapsulated with #ifdef since it will be defined also elsewhere. */
#ifndef CGAL_ASSERT_COMPILE_TIME_TAG
#define CGAL_ASSERT_COMPILE_TIME_TAG 1
template <class Base>
struct I_Assert_tag_class {
void match_compile_time_tag( const Base&) const {}
};
template< class Tag, class Derived>
inline void Assert_compile_time_tag( const Tag&, const Derived& b) {
I_Assert_tag_class<Tag> x;
x.match_compile_time_tag(b);
}
#endif
template <class C> inline template <class C> inline
void Assert_circulator( const C &) { void Assert_circulator( const C &) {
typedef typename Circulator_traits<C>::category category; typedef typename Circulator_traits<C>::category category;
Assert_compile_time_tag( Circulator_tag(), category()); BOOST_STATIC_ASSERT((boost::is_convertible<category, Circulator_tag>::value));
} }
template <class I> inline template <class I> inline
void Assert_iterator( const I &) { void Assert_iterator( const I &) {
typedef typename Circulator_traits<I>::category category; typedef typename Circulator_traits<I>::category category;
Assert_compile_time_tag( Iterator_tag(), category()); BOOST_STATIC_ASSERT((boost::is_convertible<category, Iterator_tag>::value));
} }
template <class I> inline template <class I> inline
void Assert_input_category( const I &/*i*/) { void Assert_input_category( const I &/*i*/) {
typedef typename std::iterator_traits<I>::iterator_category category; typedef typename std::iterator_traits<I>::iterator_category category;
Assert_compile_time_tag( std::input_iterator_tag(), BOOST_STATIC_ASSERT((boost::is_convertible<category, std::input_iterator_tag>::value));
category());
} }
template <class I> inline template <class I> inline
void Assert_output_category( const I &/*i*/) { void Assert_output_category( const I &/*i*/) {
typedef typename std::iterator_traits<I>::iterator_category category; typedef typename std::iterator_traits<I>::iterator_category category;
Assert_compile_time_tag( std::output_iterator_tag(), BOOST_STATIC_ASSERT((boost::is_convertible<category, std::output_iterator_tag>::value));
category());
} }
template <class IC> inline template <class IC> inline
void Assert_forward_category( const IC &/*ic*/) { void Assert_forward_category( const IC &/*ic*/) {
typedef typename std::iterator_traits<IC>::iterator_category category; typedef typename std::iterator_traits<IC>::iterator_category category;
Assert_compile_time_tag( std::forward_iterator_tag(), BOOST_STATIC_ASSERT((boost::is_convertible<category, std::forward_iterator_tag>::value));
category());
} }
template <class IC> inline template <class IC> inline
void Assert_bidirectional_category( const IC &/*ic*/) { void Assert_bidirectional_category( const IC &/*ic*/) {
typedef typename std::iterator_traits<IC>::iterator_category category; typedef typename std::iterator_traits<IC>::iterator_category category;
Assert_compile_time_tag( std::bidirectional_iterator_tag(), BOOST_STATIC_ASSERT((boost::is_convertible<category, std::bidirectional_iterator_tag>::value));
category());
} }
template <class IC> inline template <class IC> inline
void Assert_random_access_category( const IC &/*ic*/) { void Assert_random_access_category( const IC &/*ic*/) {
typedef typename std::iterator_traits<IC>::iterator_category category; typedef typename std::iterator_traits<IC>::iterator_category category;
Assert_compile_time_tag( std::random_access_iterator_tag(), BOOST_STATIC_ASSERT((boost::is_convertible<category, std::random_access_iterator_tag>::value));
category());
} }
// The assert at-least-category functions use the following // The assert at-least-category functions use the following
// functions to resolve properly. Note the proper order of the // functions to resolve properly. Note the proper order of the
// arguments: 1st is the to be type, 2nd is the actual type. // arguments: 1st is the to be type, 2nd is the actual type.
@ -704,35 +698,32 @@ typedef Iterator_from_circulator< C, const_reference, const_pointer>
: const_iterator( &anchor, 1); : const_iterator( &anchor, 1);
} }
}; };
template < class Ctnr> template <class Container>
class Circulator_from_container { class Circulator_from_container {
typedef Circulator_from_container<Container> Self;
typedef typename Container::iterator iterator;
typedef std::iterator_traits<iterator> iterator_traits;
public: public:
// TYPES typedef typename iterator_traits::value_type value_type;
typedef typename iterator_traits::reference reference;
typedef typename iterator_traits::pointer pointer;
typedef typename iterator_traits::difference_type difference_type;
typedef Circulator_from_container<Ctnr> Self; typedef typename I_Circulator_from_iterator_traits<
typedef Ctnr Container; typename iterator_traits::iterator_category
typedef typename Ctnr::iterator iterator; >::iterator_category iterator_category;
typedef typename Ctnr::value_type value_type;
typedef typename Ctnr::reference reference;
typedef value_type* pointer;
typedef typename Ctnr::size_type size_type;
typedef typename Ctnr::difference_type difference_type;
typedef std::iterator_traits<iterator> ITraits;
typedef typename ITraits::iterator_category Icategory;
typedef I_Circulator_from_iterator_traits<Icategory> CTraits;
typedef typename CTraits::iterator_category iterator_category;
typedef typename Container::size_type size_type;
private: private:
Ctnr* ctnr; Container* ctnr;
iterator i; iterator i;
public: public:
// CREATION // CREATION
Circulator_from_container() : ctnr(NULL) {} Circulator_from_container() : ctnr(NULL) {}
Circulator_from_container( Ctnr* c) : ctnr(c), i(c->begin()) {} Circulator_from_container( Container* c) : ctnr(c), i(c->begin()) {}
Circulator_from_container( Ctnr* c, iterator j) : ctnr(c), i(j) {} Circulator_from_container( Container* c, iterator j) : ctnr(c), i(j) {}
// Gnu-bug workaround: define operator= explicitly. // Gnu-bug workaround: define operator= explicitly.
Self& operator=( const Self& c) { Self& operator=( const Self& c) {
@ -790,8 +781,8 @@ public:
Self& operator+=( difference_type n) { Self& operator+=( difference_type n) {
CGAL_assertion( ctnr != NULL); CGAL_assertion( ctnr != NULL);
CGAL_assertion( i != ctnr->end()); CGAL_assertion( i != ctnr->end());
typename Ctnr::difference_type j = i - ctnr->begin(); typename Container::difference_type j = i - ctnr->begin();
typename Ctnr::difference_type size = ctnr->size(); typename Container::difference_type size = ctnr->size();
CGAL_assertion( j >= 0); CGAL_assertion( j >= 0);
CGAL_assertion( size >= 0); CGAL_assertion( size >= 0);
j = non_negative_mod( j + n, size); j = non_negative_mod( j + n, size);
@ -821,7 +812,7 @@ public:
} }
iterator current_iterator() const { return i;} iterator current_iterator() const { return i;}
Self min_circulator() const { return Self(ctnr); } Self min_circulator() const { return Self(ctnr); }
Ctnr* container() const { return ctnr; } Container* container() const { return ctnr; }
}; };
template <class Ctnr> template <class Ctnr>

View File

@ -33,54 +33,53 @@ namespace CGAL {
struct Circulator_tag {}; // any circulator. struct Circulator_tag {}; // any circulator.
struct Iterator_tag {}; // any iterator. struct Iterator_tag {}; // any iterator.
// conversion operators instead of inheritance to avoid ambiguous
// bases. we have to repeat all possible conversion so we don't run
// into a multiple user-defined conversions, problem.
struct Forward_circulator_tag struct Forward_circulator_tag
: public std::forward_iterator_tag {}; : public std::forward_iterator_tag
{};
struct Bidirectional_circulator_tag struct Bidirectional_circulator_tag
: public std::bidirectional_iterator_tag {}; : public std::bidirectional_iterator_tag
{
operator Forward_circulator_tag() const {}
};
struct Random_access_circulator_tag struct Random_access_circulator_tag
: public std::random_access_iterator_tag {}; : public std::random_access_iterator_tag
template <class T, class Dist = std::ptrdiff_t, class Size = std::size_t> {
struct Forward_circulator_base { operator Bidirectional_circulator_tag() const {}
typedef T value_type; operator Forward_circulator_tag() const {}
typedef Dist difference_type;
typedef Size size_type;
typedef T* pointer;
typedef T& reference;
typedef Forward_circulator_tag iterator_category;
}; };
template <class T, class Dist = std::ptrdiff_t, class Size = std::size_t>
struct Bidirectional_circulator_base { template <typename Tag, typename T, typename Distance = std::ptrdiff_t,
typedef T value_type; /* size is so awkwardly placed to faciliate using the
typedef Dist difference_type; * default arguments from the derived classes */
typedef Size size_type; typename Size = std::size_t, typename Pointer = T*,
typedef T* pointer; typename Reference = T&>
typedef T& reference;
typedef Bidirectional_circulator_tag iterator_category;
};
template <class T, class Dist = std::ptrdiff_t, class Size = std::size_t>
struct Random_access_circulator_base {
typedef T value_type;
typedef Dist difference_type;
typedef Size size_type;
typedef T* pointer;
typedef T& reference;
typedef Random_access_circulator_tag iterator_category;
};
template < class Category,
class T,
class Distance = std::ptrdiff_t,
class Size = std::size_t,
class Pointer = T*,
class Reference = T&>
struct Circulator_base { struct Circulator_base {
typedef Category iterator_category; typedef Tag iterator_category;
typedef T value_type; typedef T value_type;
typedef Distance difference_type; typedef Distance difference_type;
typedef Size size_type; typedef Pointer pointer;
typedef Pointer pointer; typedef Reference reference;
typedef Reference reference; typedef Size size_type;
}; };
template <class T, class Dist = std::ptrdiff_t, class Size = std::size_t>
struct Forward_circulator_base
: Circulator_base<Forward_circulator_tag, T, Dist, Size> {};
template <class T, class Dist = std::ptrdiff_t, class Size = std::size_t>
struct Bidirectional_circulator_base
: Circulator_base<Bidirectional_circulator_tag, T, Dist, Size> {};
template <class T, class Dist = std::ptrdiff_t, class Size = std::size_t>
struct Random_access_circulator_base
: Circulator_base<Random_access_circulator_tag, T, Dist, Size> {};
// variant base classes // variant base classes
// --------------------- // ---------------------
template <class T, class Dist = std::ptrdiff_t, class Size = std::size_t> template <class T, class Dist = std::ptrdiff_t, class Size = std::size_t>

View File

@ -12,21 +12,16 @@ int main()
typedef CGAL::Circulator_from_container< std::vector<int> > Circulator_from_vec; typedef CGAL::Circulator_from_container< std::vector<int> > Circulator_from_vec;
typedef CGAL::Circulator_from_container< std::list<int> > Circulator_from_list; typedef CGAL::Circulator_from_container< std::list<int> > Circulator_from_list;
// neither of the container adaptors passes the checks for tag BOOST_CONCEPT_ASSERT((CGAL::Concepts::RandomAccessCirculator<Circulator_from_vec>));
// convertibility BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator<Circulator_from_list>));
// BOOST_CONCEPT_ASSERT((CGAL::Concepts::RandomAccessCirculator<Circulator_from_vec>));
// BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator<Circulator_from_list>));
typedef CGAL::Circulator_from_iterator<int*> Circulator_from_intp; typedef CGAL::Circulator_from_iterator<int*> Circulator_from_intp;
typedef CGAL::Circulator_from_iterator<std::vector<int>::iterator> Circulator_from_veci; typedef CGAL::Circulator_from_iterator<std::vector<int>::iterator> Circulator_from_veci;
typedef CGAL::Circulator_from_iterator<std::list<int>::iterator> Circulator_from_listi; typedef CGAL::Circulator_from_iterator<std::list<int>::iterator> Circulator_from_listi;
// same as above BOOST_CONCEPT_ASSERT((CGAL::Concepts::RandomAccessCirculator<Circulator_from_intp>));
// BOOST_CONCEPT_ASSERT((CGAL::Concepts::RandomAccessCirculator<Circulator_from_intp>)); BOOST_CONCEPT_ASSERT((CGAL::Concepts::RandomAccessCirculator<Circulator_from_veci>));
// BOOST_CONCEPT_ASSERT((CGAL::Concepts::RandomAccessCirculator<Circulator_from_veci>)); BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator<Circulator_from_listi>));
// BOOST_CONCEPT_ASSERT((CGAL::Concepts::BidirectionalCirculator<Circulator_from_listi>));
return 0; return 0;
} }