Milena (Olena)  User documentation 2.0a Id
 All Classes Namespaces Functions Variables Typedefs Enumerator Groups Pages
complex.hh
1 // Copyright (C) 2008, 2009, 2010 EPITA Research and Development
2 // Laboratory (LRDE)
3 //
4 // This file is part of Olena.
5 //
6 // Olena is free software: you can redistribute it and/or modify it under
7 // the terms of the GNU General Public License as published by the Free
8 // Software Foundation, version 2 of the License.
9 //
10 // Olena is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Olena. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // As a special exception, you may use this file as part of a free
19 // software project without restriction. Specifically, if other files
20 // instantiate templates or use macros or inline functions from this
21 // file, or you compile this file and link it with other files to produce
22 // an executable, this file does not by itself cause the resulting
23 // executable to be covered by the GNU General Public License. This
24 // exception does not however invalidate any other reasons why the
25 // executable file might be covered by the GNU General Public License.
26 
27 #ifndef MLN_TOPO_COMPLEX_HH
28 # define MLN_TOPO_COMPLEX_HH
29 
36 
37 # include <cstddef>
38 
39 # include <iosfwd>
40 
41 # include <mln/metal/bool.hh>
42 
43 # include <mln/util/tracked_ptr.hh>
44 
45 # include <mln/topo/face_data.hh>
46 # include <mln/topo/algebraic_face.hh>
47 # include <mln/topo/algebraic_n_face.hh>
48 # include <mln/topo/n_faces_set.hh>
49 
50 # include <mln/topo/complex_iterators.hh>
51 
52 
53 namespace mln
54 {
55 
56  namespace topo
57  {
58 
59  // Forward declarations (external).
60  template <unsigned N, unsigned D> class n_faces_set;
61  template <unsigned D> class face_fwd_iter;
62  template <unsigned D> class face_bkd_iter;
63 // FIXME: Disabled (moved to the attic).
64 # if 0
65  template <unsigned N, unsigned D> class faces_fwd_iter_;
66  template <unsigned N, unsigned D> class faces_bkd_iter_;
67 #endif
68 
69  // Forward declarations (internal).
70  namespace internal
71  {
72  template <unsigned D>
73  struct complex_data;
74 
75  template <unsigned N, unsigned D>
76  struct faces_set_mixin;
77  }
78 
79 
80  /*----------.
81  | Complex. |
82  `----------*/
83 
85  //
86  template <unsigned D>
87  class complex
88  {
89  public:
94 
95 // FIXME: Disabled (moved to the attic).
96 # if 0
97 
98  template <unsigned N>
99  struct fwd_fiter { typedef faces_fwd_iter_<N, D> ret; };
101  template <unsigned N>
102  struct bkd_fiter { typedef faces_bkd_iter_<N, D> ret; };
103 #endif
104 
108  complex();
109 
111  n_face<0u, D> add_face();
112 
117  template <unsigned N>
118  n_face<N + 1, D> add_face(const n_faces_set<N, D>& adjacent_faces);
120 
127  unsigned nfaces() const;
128 
130  template <unsigned N>
131  unsigned nfaces_of_static_dim() const;
133 
144  unsigned nfaces_of_dim(unsigned n) const;
146 
150  void print(std::ostream& ostr) const;
152  template <unsigned N>
153  void print_faces(std::ostream& ostr) const;
155 
160  const void* addr() const;
161 
162  private:
165 
166  template <unsigned D_>
167  friend bool operator==(const complex<D_>& lhs, const complex<D_>& rhs);
168 
171  template <unsigned N, unsigned D_> friend class n_face;
172  template <unsigned D_> friend class face;
173 
174  template <unsigned N>
175  face_data<N, D>& face_data_(unsigned face_id);
176 
177  template <unsigned N>
178  const face_data<N, D>& face_data_(unsigned face_id) const;
180 
183  /* FIXME: Use something more constraining than the STL's
184  UnaryFunction/BinaryFunction. Use Function or Function_v2v?
185  Or a new subclass of Function? */
186 
187  /* FIXME: Replace F and ACCU by a Milena accumulator? */
188 
198  template <typename BinaryFunction, typename T>
199  T fold_left_(const BinaryFunction& f, const T& accu) const;
200 
202  template <typename UnaryFunction>
203  typename UnaryFunction::result_type
204  apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const;
206 
213  template <unsigned N>
214  void connect_(const algebraic_n_face<N, D>& f1,
215  const n_face<N + 1, D>& f2);
216  };
217 
218 
220  template <unsigned D>
221  bool
222  operator==(const complex<D>& lhs, const complex<D>& rhs);
223 
224 
226  template <unsigned D>
227  std::ostream&
228  operator<<(std::ostream& ostr, const complex<D>& c);
229 
230 
231  /*---------------.
232  | Complex data. |
233  `---------------*/
234 
289  /*---------------------.
290  | Faces of a complex. |
291  `---------------------*/
292 
295  namespace internal
296  {
297 
298  // Forward declarations.
299  template <unsigned N, unsigned D> struct lower_dim_faces_set_mixin;
300  template <unsigned N, unsigned D> struct higher_dim_faces_set_mixin;
301 
302  // -------------------------------------- //
303  // mln::topo::internal::faces_set_mixin. //
304  // -------------------------------------- //
305 
308 
309  template <unsigned N, unsigned D> struct faces_set_mixin;
310 
311 
313  template <unsigned N, unsigned D>
314  struct faces_set_mixin : public faces_set_mixin<N - 1, D>,
315  public lower_dim_faces_set_mixin<N, D>,
316  public higher_dim_faces_set_mixin<N, D>
317  {
318  std::vector< face_data<N, D> > faces_;
319 
323  void print(std::ostream& ostr) const;
326  void print_rec_asc(std::ostream& ostr) const;
328 
333  template <typename BinaryFunction, typename T>
334  T fold_left_(const BinaryFunction& f, const T& accu) const;
337  template <typename UnaryFunction>
338  typename UnaryFunction::result_type
339  apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const;
341  };
342 
344  template <unsigned D>
345  struct faces_set_mixin<D, D> : public faces_set_mixin<D - 1, D>,
346  public lower_dim_faces_set_mixin<D, D>
347  {
348  std::vector< face_data<D, D> > faces_;
349 
353  void print(std::ostream& ostr) const;
354  void print_rec_asc(std::ostream& ostr) const;
356 
361  template <typename BinaryFunction, typename T>
362  T fold_left_(const BinaryFunction& f, const T& accu) const;
365  template <typename UnaryFunction>
366  typename UnaryFunction::result_type
367  apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const;
369  };
370 
372  template <unsigned D>
373  struct faces_set_mixin<0u, D> : public higher_dim_faces_set_mixin<0u, D>
374  {
375  std::vector< face_data<0u, D> > faces_;
376 
380  void print(std::ostream& ostr) const;
381  void print_rec_asc(std::ostream& ostr) const;
383 
388  template <typename BinaryFunction, typename T>
389  T fold_left_(const BinaryFunction& f, const T& accu) const;
392  template <typename UnaryFunction>
393  typename UnaryFunction::result_type
394  apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const;
396  };
397 
399  template <>
400  struct faces_set_mixin<0u, 0u>
401  {
402  std::vector< face_data<0u, 0u> > faces_;
403 
407  void print(std::ostream& ostr) const;
408  void print_rec_asc(std::ostream& ostr) const;
410 
415  template <typename BinaryFunction, typename T>
416  T fold_left_(const BinaryFunction& f, const T& accu) const;
419  template <typename UnaryFunction>
420  typename UnaryFunction::result_type
421  apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const;
423  };
425 
426 
427  // Tech note: g++-2.95 highly prefers to have the complex_data
428  // class to be defined after the specializations of
429  // 'faces_set_mixin'.
430 
432  template <unsigned D>
433  struct complex_data : public faces_set_mixin<D, D>
434  {
435  // Data is contained in super classes.
436  };
437 
438 
439  // ------------------------------------------------- //
440  // mln::topo::internal::lower_dim_faces_set_mixin. //
441  // mln::topo::internal::higher_dim_faces_set_mixin. //
442  // ------------------------------------------------- //
443 
446  template <unsigned N, unsigned D>
447  struct lower_dim_faces_set_mixin
448  {
449  void print(std::ostream& ostr, const face_data<N, D>& f) const;
450  };
451 
452  template <unsigned N, unsigned D>
453  struct higher_dim_faces_set_mixin
454  {
455  void print(std::ostream& ostr, const face_data<N, D>& f) const;
456  };
458 
459  } // end of namespace mln::topo::internal
460 
461 
462 
463 # ifndef MLN_INCLUDE_ONLY
464 
465  /*-----------------------.
466  | Complex construction. |
467  `-----------------------*/
468 
469  template <unsigned D>
470  inline
472  // Allocate data for this complex.
473  : data_(new internal::complex_data<D>())
474  {
475  }
476 
477  template <unsigned D>
478  inline
481  {
482  /* FIXME: This is not thread-proof (these two lines should
483  form an atomic section). */
484  data_->internal::faces_set_mixin<0u, D>::faces_.push_back(face_data<0u, D>());
485  unsigned id = nfaces_of_static_dim<0u>() - 1;
486  return n_face<0u, D>(*this, id);
487  }
488 
489  template <unsigned D>
490  template <unsigned N>
491  inline
494  {
495  typedef typename std::vector< algebraic_n_face<N, D> >::const_iterator
496  iter_t;
497 
498  // Ensure ADJACENT_FACES are already part of the complex.
499  if (!HAS_NDEBUG)
500  for (iter_t a = adjacent_faces.faces().begin();
501  a != adjacent_faces.faces().end(); ++a)
502  {
503  mln_precondition(a->cplx() == *this);
504  mln_precondition(a->is_valid());
505  }
506 
507  face_data<N + 1, D> f;
508  /* FIXME: This is not thread-proof (these two lines should
509  form an atomic section). */
510  data_->internal::faces_set_mixin<N + 1, D>::faces_.push_back(f);
511  unsigned id = nfaces_of_static_dim<N + 1>() - 1;
512 
513  n_face<N + 1, D> fh(*this, id);
514  // Connect F and its ADJACENT_FACES.
515  for (iter_t a = adjacent_faces.faces().begin();
516  a != adjacent_faces.faces().end(); ++a)
517  /* Connect
518  - algebraic n-face *A,
519  - and an (n+1)-algebraic face based on FH and having the
520  sign of *A. */
521  connect_(*a, fh);
522  return fh;
523  }
524 
525 
526  /*-------.
527  | Misc. |
528  `-------*/
529 
530  namespace internal
531  {
532 
541  struct add_size
542  {
543  template <typename T, typename Container>
544  T operator()(const T& x, const Container& c) const
545  {
546  return x + c.size();
547  }
548  };
549 
558  struct get_size
559  {
560  typedef std::size_t result_type;
561 
562  template <typename Container>
563  typename Container::size_type operator()(const Container& c) const
564  {
565  return c.size();
566  }
567  };
568 
569  } // end of namespace mln::topo::internal
570 
571 
572  /*----------------------.
573  | Static manipulators. |
574  `----------------------*/
575 
576  template <unsigned D>
577  inline
578  unsigned
580  {
581  return fold_left_(internal::add_size(), 0);
582  }
583 
584  template <unsigned D>
585  template <unsigned N>
586  inline
587  unsigned
589  {
590  return data_->internal::faces_set_mixin<N, D>::faces_.size();
591  }
592 
593 
594  /*-----------------------.
595  | Dynamic manipulators. |
596  `-----------------------*/
597 
598  template <unsigned D>
599  inline
600  unsigned
601  complex<D>::nfaces_of_dim(unsigned n) const
602  {
603  // Ensure N is compatible with D.
604  mln_precondition(n <= D);
605  return apply_if_dim_matches_(n, internal::get_size());
606  }
607 
608 
609  /*-------------------.
610  | Internal methods. |
611  `-------------------*/
612 
613  template <unsigned D>
614  template <unsigned N>
615  inline
616  face_data<N, D>&
617  complex<D>::face_data_(unsigned face_id)
618  {
619  return data_->internal::faces_set_mixin<N, D>::faces_[face_id];
620  }
621 
622  template <unsigned D>
623  template <unsigned N>
624  inline
625  const face_data<N, D>&
626  complex<D>::face_data_(unsigned face_id) const
627  {
628  return data_->internal::faces_set_mixin<N, D>::faces_[face_id];
629  }
630 
631  template <unsigned D>
632  template <unsigned N>
633  inline
634  void
635  complex<D>::connect_(const algebraic_n_face<N, D>& f1,
636  const n_face<N + 1, D>& f2)
637  {
638  // Ensure N is compatible with D.
639  metal::bool_< N <= D >::check();
640 
641  /* Connect
642  - F1, an algebraic n-face,
643  - and AF2, an algebraic (n+1)-face based on F2 and having the
644  sign of F1. */
645  f1.data().connect_higher_dim_face(make_algebraic_n_face(f2, f1.sign()));
646  f2.data().connect_lower_dim_face(f1);
647  }
648 
649 
650  /*-------------.
651  | Comparison. |
652  `-------------*/
653 
654  template <unsigned D>
655  inline
656  bool
657  operator==(const complex<D>& lhs, const complex<D>& rhs)
658  {
659  return lhs.data_.ptr_ == rhs.data_.ptr_;
660  }
661 
662 
663  /*------------------.
664  | Pretty-printing. |
665  `------------------*/
666 
667  template <unsigned D>
668  inline
669  std::ostream&
670  operator<<(std::ostream& ostr, const complex<D>& c)
671  {
672  c.print(ostr);
673  return ostr;
674  }
675 
676  template <unsigned D>
677  inline
678  void
679  complex<D>::print(std::ostream& ostr) const
680  {
681  data_->internal::faces_set_mixin<D, D>::print_rec_asc(ostr);
682  }
683 
684  template <unsigned D>
685  template <unsigned N>
686  inline
687  void
688  complex<D>::print_faces(std::ostream& ostr) const
689  {
690  // Ensure N is compatible with D.
691  metal::bool_< N <= D >::check();
692 
693  data_->internal::faces_set_mixin<N, D>::print(ostr);
694  }
695 
696  template <unsigned D>
697  inline
698  const void*
700  {
701  return data_.ptr_;
702  }
703 
704 
705  namespace internal
706  {
707 
708  template <unsigned N, unsigned D>
709  inline
710  void
711  faces_set_mixin<N, D>::print_rec_asc(std::ostream& ostr) const
712  {
713  faces_set_mixin<N - 1, D>::print_rec_asc(ostr);
714  print(ostr);
715  }
716 
717  template <unsigned D>
718  inline
719  void
720  faces_set_mixin<0u, D>::print_rec_asc(std::ostream& ostr) const
721  {
722  print(ostr);
723  }
724 
725  template <unsigned D>
726  inline
727  void
728  faces_set_mixin<D, D>::print_rec_asc(std::ostream& ostr) const
729  {
730  faces_set_mixin<D - 1, D>::print_rec_asc(ostr);
731  print(ostr);
732  }
733 
734  inline
735  void
736  faces_set_mixin<0u, 0u>::print_rec_asc(std::ostream& ostr) const
737  {
738  print(ostr);
739  }
740 
741 
742  template <unsigned N, unsigned D>
743  inline
744  void
745  faces_set_mixin<N, D>::print(std::ostream& ostr) const
746  {
747  ostr << "Faces of dimension " << N
748  << " and their ajacent faces of dimension "
749  << N - 1 << " and "
750  << N + 1 << std::endl;
751  for (unsigned f = 0; f < faces_.size(); ++f)
752  {
753  ostr << " " << f << ": dim " << N - 1 << ": { ";
754  lower_dim_faces_set_mixin<N, D>::print(ostr, faces_[f]);
755  ostr << "}, dim " << N + 1 << ": { ";
756  higher_dim_faces_set_mixin<N, D>::print(ostr, faces_[f]);
757  ostr << "}" << std::endl;
758  }
759  }
760 
761  template <unsigned D>
762  inline
763  void
764  faces_set_mixin<0u, D>::print(std::ostream& ostr) const
765  {
766  const unsigned N = 0u;
767  ostr << "Faces of dimension " << N
768  << " and their ajacent faces of dimension "
769  << N + 1 << std::endl;
770  for (unsigned f = 0; f < faces_.size(); ++f)
771  {
772  ostr << " " << f << ": dim " << N + 1 << ": { ";
773  higher_dim_faces_set_mixin<N, D>::print(ostr, faces_[f]);
774  ostr << "}" << std::endl;
775  }
776  }
777 
778  template <unsigned D>
779  inline
780  void
781  faces_set_mixin<D, D>::print(std::ostream& ostr) const
782  {
783  const unsigned N = D;
784  ostr << "Faces of dimension " << N
785  << " and their ajacent faces of dimension "
786  << N - 1 << std::endl;
787  for (unsigned f = 0; f < faces_.size(); ++f)
788  {
789  ostr << " " << f << ": dim " << N - 1 << ": { ";
790  lower_dim_faces_set_mixin<N, D>::print(ostr, faces_[f]);
791  ostr << "}" << std::endl;
792  }
793  }
794 
795  inline
796  void
797  faces_set_mixin<0u, 0u>::print(std::ostream& ostr) const
798  {
799  const unsigned N = 0u;
800  ostr << "Faces of dimension " << N << std::endl;
801  for (unsigned f = 0; f < faces_.size(); ++f)
802  ostr << " " << f << std::endl;
803  }
804 
805 
806  template <unsigned N, unsigned D>
807  inline
808  void
809  lower_dim_faces_set_mixin<N, D>::print(std::ostream& ostr,
810  const face_data<N, D>& f) const
811  {
812  for (typename std::vector< algebraic_n_face<N - 1, D> >::const_iterator l =
813  f.lower_dim_faces_.begin(); l != f.lower_dim_faces_.end(); ++l)
814  ostr << l->face_id() << " ";
815  }
816 
817  template <unsigned N, unsigned D>
818  inline
819  void
820  higher_dim_faces_set_mixin<N, D>::print(std::ostream& ostr,
821  const face_data<N, D>& f) const
822  {
823  for (typename std::vector< algebraic_n_face<N + 1, D> >::const_iterator h =
824  f.higher_dim_faces_.begin(); h != f.higher_dim_faces_.end(); ++h)
825  ostr << h->face_id() << " ";
826  }
827 
828  } // end of namespace mln::topo::internal
829 
830 
831  /*-------------------------------.
832  | Functional meta-manipulators. |
833  `-------------------------------*/
834 
835  /* ------------------------------- */
836  /* ``Static Fold Left'' Operator. */
837  /* ------------------------------- */
838 
839  template <unsigned D>
840  template <typename BinaryFunction, typename T>
841  inline
842  T
843  complex<D>::fold_left_(const BinaryFunction& f, const T& accu) const
844  {
845  return data_->internal::faces_set_mixin<D, D>::fold_left_(f, accu);
846  }
847 
848  namespace internal
849  {
850 
851  // FIXME: Try to factor.
852 
853  template <unsigned D>
854  template <typename BinaryFunction, typename T>
855  inline
856  T
857  faces_set_mixin<D, D>::fold_left_(const BinaryFunction& f,
858  const T& accu) const
859  {
860  return faces_set_mixin<D - 1, D>::fold_left_(f, f(accu, faces_));
861  }
862 
863  template <unsigned N, unsigned D>
864  template <typename BinaryFunction, typename T>
865  inline
866  T
867  faces_set_mixin<N, D>::fold_left_(const BinaryFunction& f,
868  const T& accu) const
869  {
870  return faces_set_mixin<N - 1, D>::fold_left_(f, f(accu, faces_));
871  }
872 
873  template <unsigned D>
874  template <typename BinaryFunction, typename T>
875  inline
876  T
877  faces_set_mixin<0u, D>::fold_left_(const BinaryFunction& f,
878  const T& accu) const
879  {
880  return f(accu, faces_);
881  }
882 
883  template <typename BinaryFunction, typename T>
884  inline
885  T
886  faces_set_mixin<0u, 0u>::fold_left_(const BinaryFunction& f,
887  const T& accu) const
888  {
889  return f(accu, faces_);
890  }
891 
892  } // end of namespace mln::topo::internal
893 
894 
895  /* ------------------------------------------------ */
896  /* ``Static Apply-If-Dimension-Matches'' Operator. */
897  /* ------------------------------------------------ */
898 
899  template <unsigned D>
900  template <typename UnaryFunction>
901  inline
902  typename UnaryFunction::result_type
903  complex<D>::apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const
904  {
905  // Ensure N is compatible with D.
906  mln_precondition(n <= D);
907  return data_->internal::faces_set_mixin<D, D>::apply_if_dim_matches_(n, f);
908  }
909 
910  namespace internal
911  {
912 
913  // FIXME: Try to factor.
914 
915  template <unsigned D>
916  template <typename UnaryFunction>
917  inline
918  typename UnaryFunction::result_type
919  faces_set_mixin<D, D>::apply_if_dim_matches_(unsigned n,
920  const UnaryFunction& f) const
921  {
922  // Ensure N and D are compatible.
923  mln_precondition(n <= D);
924  return n == D ?
925  f(faces_) :
926  faces_set_mixin<D - 1, D>::apply_if_dim_matches_(n, f);
927  }
928 
929  template <unsigned N, unsigned D>
930  template <typename UnaryFunction>
931  inline
932  typename UnaryFunction::result_type
933  faces_set_mixin<N, D>::apply_if_dim_matches_(unsigned n,
934  const UnaryFunction& f) const
935  {
936  // Ensure N and D are compatible.
937  mln_precondition(n <= D);
938  return n == N ?
939  f(faces_) :
940  faces_set_mixin<N - 1, D>::apply_if_dim_matches_(n, f);
941  }
942 
943  template <unsigned D>
944  template <typename UnaryFunction>
945  inline
946  typename UnaryFunction::result_type
947  faces_set_mixin<0u, D>::apply_if_dim_matches_(unsigned n,
948  const UnaryFunction& f) const
949  {
950  // If we reached this method, then N should be 0.
951  mln_precondition(n == 0);
952  // Prevent ``unused variable'' warnings when NDEBUG is defined.
953  (void) n;
954  return f(faces_);
955  }
956 
957  template <typename UnaryFunction>
958  inline
959  typename UnaryFunction::result_type
960  faces_set_mixin<0u, 0u>::apply_if_dim_matches_(unsigned n,
961  const UnaryFunction& f) const
962  {
963  // If we reached this method, then N should be 0.
964  mln_precondition(n == 0);
965  // Prevent ``unused variable'' warnings when NDEBUG is defined.
966  (void) n;
967  return f(faces_);
968  }
969 
970  } // end of namespace mln::topo::internal
971 
972 # endif // ! MLN_INCLUDE_ONLY
973 
974  } // end of namespace mln::topo
975 
976 } // end of namespace mln
977 
978 #endif // ! MLN_TOPO_COMPLEX_HH