Spatial C++ Library
Generic Multi-Dimensional Containers and Spatial Operations
spatial_region.hpp
1 // -*- C++ -*-
2 //
3 // Copyright Sylvain Bougerel 2009 - 2013.
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file COPYING or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 
15 #ifndef SPATIAL_REGION_HPP
16 #define SPATIAL_REGION_HPP
17 
18 #include <utility> // std::pair<> and std::make_pair()
19 #include "../traits.hpp"
20 #include "spatial_bidirectional.hpp"
21 #include "spatial_rank.hpp"
22 #include "spatial_except.hpp"
23 
24 namespace spatial
25 {
45  template <typename Key, typename Compare>
46  class bounds
47  : private Compare // empty member optimization
48  {
49  public:
54  : Compare(), _lower(), _upper() { }
55 
60  bounds(const Compare& compare, const Key& lower, const Key& upper)
61  : Compare(compare), _lower(lower), _upper(upper)
62  { }
63 
69  operator()(dimension_type dim, dimension_type, const Key& key) const
70  {
71  return (Compare::operator()(dim, key, _lower)
72  ? below
73  : (Compare::operator()(dim, key, _upper)
74  ? matching
75  : above));
76  }
77 
78  private:
82  Key _lower;
83 
87  Key _upper;
88  };
89 
108  template <typename Tp>
112  (const Tp& container,
113  const typename container_traits<Tp>::key_type& lower,
114  const typename container_traits<Tp>::key_type& upper)
115  {
116  except::check_bounds(container, lower, upper);
117  return bounds
120  (container.key_comp(), lower, upper);
121  }
122 
137  template <typename Ct, typename Predicate
138  = bounds<typename container_traits<Ct>::key_type,
142  <typename container_traits<Ct>::mode_type,
143  typename container_traits<Ct>::rank_type>
144  {
145  private:
146  typedef typename details::Bidirectional_iterator
149 
150  public:
153 
168  region_iterator(Ct& container, const Predicate& pred,
169  typename container_traits<Ct>::iterator iter)
170  : Base(container.rank(), iter.node, modulo(iter.node, container.rank())),
171  _pred(pred) { }
172 
191  (Ct& container, const Predicate& pred, dimension_type dim,
193  : Base(container.rank(), ptr, dim), _pred(pred) { }
194 
198  { return increment_region(*this); }
199 
203  {
205  increment_region(*this);
206  return x;
207  }
208 
212  { return decrement_region(*this); }
213 
217  {
219  decrement_region(*this);
220  return x;
221  }
222 
224  Predicate predicate() const { return _pred; }
225 
226  private:
228  Predicate _pred;
229  };
230 
245  template <typename Ct, typename Predicate>
246  class region_iterator<const Ct, Predicate>
248  <typename container_traits<Ct>::mode_type,
249  typename container_traits<Ct>::rank_type>
250  {
251  private:
253  <typename container_traits<Ct>::mode_type,
255 
256  public:
259 
274  region_iterator(const Ct& container, const Predicate& pred,
276  : Base(container.rank(), iter.node, modulo(iter.node, container.rank())),
277  _pred(pred) { }
278 
298  (const Ct& container, const Predicate& pred, dimension_type dim,
300  : Base(container.rank(), ptr, dim), _pred(pred) { }
301 
304  : Base(iter.rank(), iter.node, iter.node_dim), _pred(iter.predicate()) { }
305 
309  { return increment_region(*this); }
310 
314  {
316  increment_region(*this);
317  return x;
318  }
319 
323  { return decrement_region(*this); }
324 
328  {
330  decrement_region(*this);
331  return x;
332  }
333 
335  Predicate predicate() const { return _pred; }
336 
337  private:
339  Predicate _pred;
340  };
341 
342  namespace details
343  {
353  template <typename Ct, typename Predicate>
356 
369  template <typename Ct, typename Predicate>
372 
383  template <typename Ct, typename Predicate>
386 
397  template <typename Ct, typename Predicate>
400 
401  } // namespace details
402 
403  template <typename Ct, typename Predicate>
404  inline region_iterator<Ct, Predicate>
405  region_end(Ct& container, const Predicate& pred)
406  {
408  (container, pred, container.dimension() - 1,
409  container.end().node); // At header, dim = rank - 1
410  }
411 
412  template <typename Ct, typename Predicate>
413  inline region_iterator<const Ct, Predicate>
414  region_end(const Ct& container, const Predicate& pred)
415  {
417  (container, pred, container.dimension() - 1,
418  container.end().node); // At header, dim = rank - 1
419  }
420 
421  template <typename Ct, typename Predicate>
422  inline region_iterator<const Ct, Predicate>
423  region_cend(const Ct& container, const Predicate& pred)
424  { return region_end(container, pred); }
425 
426  template <typename Ct>
427  inline region_iterator<Ct>
428  region_end(Ct& container,
429  const typename container_traits<Ct>::key_type& lower,
430  const typename container_traits<Ct>::key_type& upper)
431  { return region_end(container, make_bounds(container, lower, upper)); }
432 
433  template <typename Ct>
434  inline region_iterator<const Ct>
435  region_end(const Ct& container,
436  const typename container_traits<Ct>::key_type& lower,
437  const typename container_traits<Ct>::key_type& upper)
438  { return region_end(container, make_bounds(container, lower, upper)); }
439 
440  template <typename Ct>
441  inline region_iterator<const Ct>
442  region_cend(const Ct& container,
443  const typename container_traits<Ct>::key_type& lower,
444  const typename container_traits<Ct>::key_type& upper)
445  { return region_cend(container, make_bounds(container, lower, upper)); }
446 
447  template <typename Ct, typename Predicate>
448  inline region_iterator<Ct, Predicate>
449  region_begin(Ct& container, const Predicate& pred)
450  {
451  if (container.empty()) return region_end(container, pred);
453  it(container, pred, 0, container.end().node->parent); // At root, dim = 0
454  return details::minimum_region(it);
455  }
456 
457  template <typename Ct, typename Predicate>
458  inline region_iterator<const Ct, Predicate>
459  region_begin(const Ct& container, const Predicate& pred)
460  {
461  if (container.empty()) return region_end(container, pred);
463  it(container, pred, 0, container.end().node->parent); // At root, dim = 0
464  return details::minimum_region(it);
465  }
466 
467  template <typename Ct, typename Predicate>
468  inline region_iterator<const Ct, Predicate>
469  region_cbegin(const Ct& container, const Predicate& pred)
470  { return region_begin(container, pred); }
471 
472  template <typename Ct>
473  inline region_iterator<Ct>
474  region_begin(Ct& container,
475  const typename container_traits<Ct>::key_type& lower,
476  const typename container_traits<Ct>::key_type& upper)
477  { return region_begin(container, make_bounds(container, lower, upper)); }
478 
479  template <typename Ct>
480  inline region_iterator<const Ct>
481  region_begin(const Ct& container,
482  const typename container_traits<Ct>::key_type& lower,
483  const typename container_traits<Ct>::key_type& upper)
484  { return region_begin(container, make_bounds(container, lower, upper)); }
485 
486  template <typename Ct>
487  inline region_iterator<const Ct>
488  region_cbegin(const Ct& container,
489  const typename container_traits<Ct>::key_type& lower,
490  const typename container_traits<Ct>::key_type& upper)
491  { return region_cbegin(container, make_bounds(container, lower, upper)); }
492 
499  template <typename Ct, typename Predicate
500  = bounds<typename container_traits<Ct>::key_type,
503  : std::pair<region_iterator<Ct, Predicate>,
504  region_iterator<Ct, Predicate> >
505  {
510  typedef std::pair<region_iterator<Ct, Predicate>,
512 
515 
520  : Base(a, b) { }
521  };
522 
529  template <typename Ct, typename Predicate>
530  struct region_iterator_pair<const Ct, Predicate>
531  : std::pair<region_iterator<const Ct, Predicate>,
532  region_iterator<const Ct, Predicate> >
533  {
538  typedef std::pair<region_iterator<const Ct, Predicate>,
540 
543 
548  : Base(a, b) { }
549 
553  : Base(p.first, p.second) { }
554  };
555 
567  template <typename Ct, typename Predicate>
569  inline region_iterator_pair<Ct, Predicate>
570  region_range(Ct& container, const Predicate& pred)
571  {
573  (region_begin(container, pred), region_end(container, pred));
574  }
575 
579  template <typename Ct, typename Predicate>
580  inline region_iterator_pair<const Ct, Predicate>
581  region_range(const Ct& container, const Predicate& pred)
582  {
584  (region_begin(container, pred), region_end(container, pred));
585  }
586 
590  template <typename Ct, typename Predicate>
591  inline region_iterator_pair<const Ct, Predicate>
592  region_crange(const Ct& container, const Predicate& pred)
593  {
595  (region_begin(container, pred), region_end(container, pred));
596  }
598 
599  template <typename Ct>
600  inline region_iterator_pair<Ct>
601  region_range(Ct& container,
602  const typename container_traits<Ct>::key_type& lower,
603  const typename container_traits<Ct>::key_type& upper)
604  { return region_range(container, make_bounds(container, lower, upper)); }
605 
606  template <typename Ct>
607  inline region_iterator_pair<const Ct>
608  region_range(const Ct& container,
609  const typename container_traits<Ct>::key_type& lower,
610  const typename container_traits<Ct>::key_type& upper)
611  { return region_range(container, make_bounds(container, lower, upper)); }
612 
613  template <typename Ct>
614  inline region_iterator_pair<const Ct>
615  region_crange(const Ct& container,
616  const typename container_traits<Ct>::key_type& lower,
617  const typename container_traits<Ct>::key_type& upper)
618  { return region_crange(container, make_bounds(container, lower, upper)); }
619 
620  namespace details
621  {
636  template <typename Rank, typename Key, typename Predicate>
637  inline bool
638  match_all(const Rank& rank, const Key& key, const Predicate& predicate)
639  {
640  for (dimension_type i = 0; i < rank(); ++i)
641  { if (predicate(i, rank(), key) != matching) { return false; } }
642  return true;
643  }
644 
645  template <typename Container, typename Predicate>
648  {
649  const typename container_traits<Container>::rank_type rank(iter.rank());
650  const Predicate pred(iter.predicate());
651  SPATIAL_ASSERT_CHECK(!header(iter.node));
652  SPATIAL_ASSERT_CHECK(iter.node != 0);
653  SPATIAL_ASSERT_CHECK(iter.node_dim < rank());
654  do
655  {
656  if (iter.node->right != 0
657  && pred(iter.node_dim, rank(), const_key(iter.node)) != above)
658  {
659  iter.node = iter.node->right;
660  iter.node_dim = incr_dim(rank, iter.node_dim);
661  while (iter.node->left != 0
662  && pred(iter.node_dim, rank(),
663  const_key(iter.node)) != below)
664  {
665  iter.node = iter.node->left;
666  iter.node_dim = incr_dim(rank, iter.node_dim);
667  }
668  }
669  else
670  {
672  = iter.node->parent;
673  while (!header(p) && iter.node == p->right)
674  {
675  iter.node = p;
676  iter.node_dim = decr_dim(rank, iter.node_dim);
677  p = iter.node->parent;
678  }
679  iter.node = p;
680  iter.node_dim = decr_dim(rank, iter.node_dim);
681  }
682  }
683  while (!header(iter.node)
684  && match_all(rank, const_key(iter.node), pred) == false);
685  SPATIAL_ASSERT_CHECK(iter.node_dim < rank());
686  SPATIAL_ASSERT_CHECK(iter.node != 0);
687  return iter;
688  }
689 
690  template <typename Container, typename Predicate>
693  {
694  const typename container_traits<Container>::rank_type rank(iter.rank());
695  const Predicate pred(iter.predicate());
696  SPATIAL_ASSERT_CHECK(iter.node != 0);
697  SPATIAL_ASSERT_CHECK(iter.node_dim < rank());
698  if (header(iter.node))
699  {
700  iter.node = iter.node->parent;
701  iter.node_dim = 0; // root is always compared on dimension 0
702  return maximum_region(iter);
703  }
704  do
705  {
706  if (iter.node->left != 0
707  && pred(iter.node_dim, rank(), const_key(iter.node)) != below)
708  {
709  iter.node = iter.node->left;
710  iter.node_dim = incr_dim(rank, iter.node_dim);
711  while (iter.node->right != 0
712  && pred(iter.node_dim, rank(),
713  const_key(iter.node)) != above)
714  {
715  iter.node = iter.node->right;
716  iter.node_dim = incr_dim(rank, iter.node_dim);
717  }
718  }
719  else
720  {
722  = iter.node->parent;
723  while (!header(p) && iter.node == p->left)
724  {
725  iter.node = p;
726  iter.node_dim = decr_dim(rank, iter.node_dim);
727  p = iter.node->parent;
728  }
729  iter.node = p;
730  iter.node_dim = decr_dim(rank, iter.node_dim);
731  }
732  }
733  while (!header(iter.node)
734  && match_all(rank, const_key(iter.node), pred) == false);
735  SPATIAL_ASSERT_CHECK(iter.node_dim < rank());
736  SPATIAL_ASSERT_CHECK(iter.node != 0);
737  return iter;
738  }
739 
740  template <typename Container, typename Predicate>
743  {
744  const typename container_traits<Container>::rank_type rank(iter.rank());
745  const Predicate pred(iter.predicate());
746  SPATIAL_ASSERT_CHECK(iter.node_dim < rank());
747  SPATIAL_ASSERT_CHECK(!header(iter.node));
748  SPATIAL_ASSERT_CHECK(iter.node != 0);
750  = iter.node->parent;
751  // Quick positioning according to in-order transversal.
752  while(iter.node->right != 0
753  && pred(iter.node_dim, rank(), const_key(iter.node)) == below)
754  {
755  iter.node = iter.node->right;
756  iter.node_dim = incr_dim(rank, iter.node_dim);
757  }
758  while(iter.node->left != 0
759  && pred(iter.node_dim, rank(), const_key(iter.node)) != below)
760  {
761  iter.node = iter.node->left;
762  iter.node_dim = incr_dim(rank, iter.node_dim);
763  }
764  // Start algorithm.
765  do
766  {
767  if (match_all(rank, const_key(iter.node), pred) == true) { break; }
768  if (iter.node->right != 0
769  && pred(iter.node_dim, rank(),
770  const_key(iter.node)) != above)
771  {
772  iter.node = iter.node->right;
773  iter.node_dim = incr_dim(rank, iter.node_dim);
774  while (iter.node->left != 0
775  && pred(iter.node_dim, rank(),
776  const_key(iter.node)) != below)
777  {
778  iter.node = iter.node->left;
779  iter.node_dim = incr_dim(rank, iter.node_dim);
780  }
781  }
782  else
783  {
785  = iter.node->parent;
786  while (p != end && iter.node == p->right)
787  {
788  iter.node = p;
789  iter.node_dim = decr_dim(rank, iter.node_dim);
790  p = iter.node->parent;
791  }
792  iter.node = p;
793  iter.node_dim = decr_dim(rank, iter.node_dim);
794  }
795  }
796  while (iter.node != end);
797  SPATIAL_ASSERT_CHECK(iter.node_dim < rank());
798  SPATIAL_ASSERT_CHECK(iter.node != 0);
799  return iter;
800  }
801 
802  template <typename Container, typename Predicate>
805  {
806  const typename container_traits<Container>::rank_type rank(iter.rank());
807  const Predicate pred(iter.predicate());
808  SPATIAL_ASSERT_CHECK(iter.node != 0);
809  SPATIAL_ASSERT_CHECK(iter.node_dim < rank());
810  SPATIAL_ASSERT_CHECK(!header(iter.node));
812  = iter.node->parent;
813  // Quick positioning according to in-order transversal.
814  while (iter.node->left != 0
815  && pred(iter.node_dim, rank(), const_key(iter.node)) == above)
816  {
817  iter.node = iter.node->left;
818  iter.node_dim = incr_dim(rank, iter.node_dim);
819  }
820  while (iter.node->right != 0
821  && pred(iter.node_dim, rank(), const_key(iter.node)) != above)
822  {
823  iter.node = iter.node->right;
824  iter.node_dim = incr_dim(rank, iter.node_dim);
825  }
826  // Start algorithm.
827  do
828  {
829  if (match_all(rank, const_key(iter.node), pred) == true) { break; }
830  if (iter.node->left != 0
831  && pred(iter.node_dim, rank(), const_key(iter.node)) != below)
832  {
833  iter.node = iter.node->left;
834  iter.node_dim = incr_dim(rank, iter.node_dim);
835  while (iter.node->right != 0
836  && pred(iter.node_dim, rank(),
837  const_key(iter.node)) != above)
838  {
839  iter.node = iter.node->right;
840  iter.node_dim = incr_dim(rank, iter.node_dim);
841  }
842  }
843  else
844  {
846  = iter.node->parent;
847  while (p != end && iter.node == p->left)
848  {
849  iter.node = p;
850  iter.node_dim = decr_dim(rank, iter.node_dim);
851  p = iter.node->parent;
852  }
853  iter.node = p;
854  iter.node_dim = decr_dim(rank, iter.node_dim);
855  }
856  }
857  while (iter.node != end);
858  SPATIAL_ASSERT_CHECK(iter.node_dim < rank());
859  SPATIAL_ASSERT_CHECK(iter.node != 0);
860  return iter;
861  }
862 
863  } // namespace details
864 } // namespace spatial
865 
866 #endif // SPATIAL_REGION_HPP
relative_order operator()(dimension_type dim, dimension_type, const Key &key) const
The operator that returns true if the key is within the boundaries, false if it isn't.
region_iterator(const Ct &container, const Predicate &pred, typename container_traits< Ct >::const_iterator iter)
Build a region iterator from a container's iterator type.
region_iterator< Ct, Predicate > & decrement_region(region_iterator< Ct, Predicate > &iter)
From iter, returns the previous matching iterator in the region delimited by Predicate, using in-order transversal.
This structure defines a pair of constant region iterator.
Key _upper
The upper bound for the orthogonal region.
region_iterator_pair(const region_iterator_pair< Ct, Predicate > &p)
Convert a mutable region iterator pair into a const region iterator pair.
This type provides both an iterator and a constant iterator to iterate through all elements of a tree...
region_iterator< const Ct, Predicate > operator--(int)
Decrements the iterator but returns the value of the iterator before the decrement.
void check_bounds(const Tp &container, const typename container_traits< Tp >::key_type &lower, const typename container_traits< Tp >::key_type &upper)
Checks if all coordinates of lower are strictly less than these of higher along the same dimensions...
region_iterator_pair()
Empty constructor.
region_iterator< Ct, Predicate > & maximum_region(region_iterator< Ct, Predicate > &iter)
In the children of the node pointed to by iter, find the last matching iterator in the region delimit...
region_iterator(const region_iterator< Ct, Predicate > &iter)
Convertion of an iterator into a const_iterator is permitted.
Tp::key_compare key_compare
Comparison functor used to compare two instances of key_type.
Definition: traits.hpp:98
Predicate _pred
The related data for the iterator.
This type provides both an iterator and a constant iterator to iterate through all elements of a tree...
region_iterator< Ct, Predicate > & minimum_region(region_iterator< Ct, Predicate > &iter)
In the children of the node pointed to by iter, find the first matching iterator in the region delimi...
bounds()
The default constructor leaves everything un-initialized.
region_iterator< const Ct, Predicate > region_cend(const Ct &container, const Predicate &pred)
This structure defines a pair of mutable region iterator.
bounds(const Compare &compare, const Key &lower, const Key &upper)
Set the lower and upper boundary for the orthogonal region search.
Tp::key_type key_type
The type representing the key managed by the container.
Definition: traits.hpp:48
std::pair< region_iterator< const Ct, Predicate >, region_iterator< const Ct, Predicate > > Base
A pair of iterators that represents a range (that is: a range of elements to iterate, and not an orthogonal range).
const Kdtree_link< Value, Value >::key_type & const_key(const Node< Kdtree_link< Value, Value > > *node)
This function converts a pointer on a node into a key for a Kdtree_link type.
region_iterator_pair(const region_iterator< Ct, Predicate > &a, const region_iterator< Ct, Predicate > &b)
Regular constructor that builds a region_iterator_pair out of 2 region_iterators. ...
bool header(const Node< Link > *x)
Check if node is a header node.
region_iterator< const Ct, Predicate > & operator++()
Increments the iterator and returns the incremented value.
Predicate predicate() const
Return the key_comparator used by the iterator.
std::pair< region_iterator< Ct, Predicate >, region_iterator< Ct, Predicate > > Base
A pair of iterators that represents a range (that is: a range of elements to iterate, and not an orthogonal range).
region_iterator< Ct, Predicate > region_begin(Ct &container, const Predicate &pred)
region_iterator_pair< Ct, Predicate > region_range(Ct &container, const Predicate &pred)
Returns a spatial::region_iterator_pair where first points to the first element matching the predicat...
region_iterator_pair(const region_iterator< const Ct, Predicate > &a, const region_iterator< const Ct, Predicate > &b)
Regular constructor that builds a region_iterator_pair out of 2 region_iterators. ...
The traits type for all containers in the spatial namespace.
Definition: traits.hpp:42
Predicate predicate() const
Return the key_comparator used by the iterator.
region_iterator< const Ct, Predicate > region_cbegin(const Ct &container, const Predicate &pred)
relative_order
Defines values for relative ordering.
Definition: spatial.hpp:81
std::size_t dimension_type
Defines the type for the dimension as being a size.
Definition: spatial.hpp:71
region_iterator< Ct, Predicate > region_end(Ct &container, const Predicate &pred)
region_iterator< const Ct, Predicate > operator++(int)
Increments the iterator but returns the value of the iterator before the increment.
region_iterator< Ct, Predicate > & operator--()
Decrements the iterator and returns the decremented value.
Tp::rank_type rank_type
The type used to represent the rank of the container.
Definition: traits.hpp:111
details::Const_bidirectional_iterator< typename container_traits< Ct >::mode_type, typename container_traits< Ct >::rank_type > Base
region_iterator(Ct &container, const Predicate &pred, typename container_traits< Ct >::iterator iter)
Build a region iterator from a container's iterator type.
The main namespace used in the library.
Definition: algorithm.hpp:23
region_iterator_pair< const Ct, Predicate > region_crange(const Ct &container, const Predicate &pred)
This overload works only on constant containers and will return a set of constant iterators...
region_iterator()
Uninitialized iterator.
dimension_type decr_dim(Rank rank, dimension_type node_dim)
Decrement dimension node_dim, given rank.
region_iterator< const Ct, Predicate > & operator--()
Decrements the iterator and returns the decremented value.
region_iterator< Ct, Predicate > operator++(int)
Increments the iterator but returns the value of the iterator before the increment.
region_iterator< Ct, Predicate > & operator++()
Increments the iterator and returns the incremented value.
A common template for constant bidirectional iterators that work on identical modes of linking...
A common template for bidirectional iterators that work on identical modes of linking.
details::Bidirectional_iterator< typename container_traits< Ct >::mode_type, typename container_traits< Ct >::rank_type > Base
Predicate _pred
The related data for the iterator.
bool match_all(const Rank &rank, const Key &key, const Predicate &predicate)
Return a boolean indicating whether all of key's coordinates are within range or not.
region_iterator()
Constructs an empty, uninitialized object.
region_iterator< Ct, Predicate > & increment_region(region_iterator< Ct, Predicate > &iter)
From iter, returns the next matching iterator in the region delimited by Predicate, using in-order transversal.
region_iterator< Ct, Predicate > operator--(int)
Decrements the iterator but returns the value of the iterator before the decrement.
A model of Region Predicate that defines an orthogonal region and checks if a value of type Key is co...
Key _lower
The lower bound for the orthogonal region.
dimension_type incr_dim(Rank rank, dimension_type node_dim)
Increment dimension node_dim, given rank.
bounds< typename container_traits< Tp >::key_type, typename container_traits< Tp >::key_compare > make_bounds(const Tp &container, const typename container_traits< Tp >::key_type &lower, const typename container_traits< Tp >::key_type &upper)
A bounds factory that takes in a container, 2 arguments lower and upper, and returns a fully construc...