complex.hh 28.1 KB
Newer Older
Roland Levillain's avatar
Roland Levillain committed
1
2
// Copyright (C) 2008, 2009, 2010 EPITA Research and Development
// Laboratory (LRDE)
3
//
4
// This file is part of Olena.
5
//
6
7
8
9
10
// Olena is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation, version 2 of the License.
//
// Olena is distributed in the hope that it will be useful,
11
12
13
14
15
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// 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
22
23
24
25
// file, or you compile this file and link it with other files to produce
// an executable, this file does not by itself cause the resulting
// executable to be covered by the GNU General Public License.  This
// exception does not however invalidate any other reasons why the
// executable file might be covered by the GNU General Public License.
26
27
28
29

#ifndef MLN_TOPO_COMPLEX_HH
# define MLN_TOPO_COMPLEX_HH

30
/// \file
31
32
///
/// \brief Structures for general complexes.
33
34
35
36
37
38
39
40
41
42
43
44
///
/// A complex defines a topological space which can be used as a
/// support for an image (i.e., as site sets).

# include <cstddef>

# include <iosfwd>

# include <mln/metal/bool.hh>

# include <mln/util/tracked_ptr.hh>

Roland Levillain's avatar
Roland Levillain committed
45
# include <mln/topo/face_data.hh>
46
47
# include <mln/topo/algebraic_face.hh>
# include <mln/topo/algebraic_n_face.hh>
Roland Levillain's avatar
Roland Levillain committed
48
# include <mln/topo/n_faces_set.hh>
49

50
# include <mln/topo/complex_iterators.hh>
51
52


53
54
55
56
57
58
namespace mln
{

  namespace topo
  {

Roland Levillain's avatar
Roland Levillain committed
59
60
    // Forward declarations (external).
    template <unsigned N, unsigned D> class n_faces_set;
61
62
    template <unsigned D> class face_fwd_iter;
    template <unsigned D> class face_bkd_iter;
63
64
// FIXME: Disabled (moved to the attic).
# if 0
Roland Levillain's avatar
Roland Levillain committed
65
66
    template <unsigned N, unsigned D> class faces_fwd_iter_;
    template <unsigned N, unsigned D> class faces_bkd_iter_;
67
#endif
Roland Levillain's avatar
Roland Levillain committed
68
69

    // Forward declarations (internal).
70
71
72
73
74
75
76
77
78
79
80
81
82
83
    namespace internal
    {
      template <unsigned D>
      struct complex_data;

      template <unsigned N, unsigned D>
      struct faces_set_mixin;
    }


    /*----------.
    | Complex.  |
    `----------*/

84
85
    /// \brief General complex of dimension \p D.
    //
86
87
88
89
90
    template <unsigned D>
    class complex
    {
    public:
      /// Forward mln::Iterator type iterating on all faces.
91
      typedef face_fwd_iter<D> fwd_citer;
92
      /// Backward mln::Iterator type iterating on all faces.
93
      typedef face_bkd_iter<D> bkd_citer;
94

95
96
// FIXME: Disabled (moved to the attic).
# if 0
97
98
99
100
101
102
      /// Forward mln::Iterator type iterating on \p N-faces.
      template <unsigned N>
      struct fwd_fiter { typedef faces_fwd_iter_<N, D> ret; };
      /// Backward mln::Iterator type iterating on \p N-faces.
      template <unsigned N>
      struct bkd_fiter { typedef faces_bkd_iter_<N, D> ret; };
103
#endif
104
105
106
107
108
109

      /// Complex construction.
      /// \{
      /// Create a new \p D-complex.
      complex();

Guillaume Lazzara's avatar
Guillaume Lazzara committed
110
      /// Add a 0-face to the complex.
111
      n_face<0u, D> add_face();
112

Guillaume Lazzara's avatar
Guillaume Lazzara committed
113
      /// Add a \p (N+1)-face to the complex (with \p N >= 0).
114
115
116
117
      ///
      /// \param adjacent_faces The (\p N-1)-faces adjacent to the new
      /// \p N-face.
      template <unsigned N>
118
      n_face<N + 1, D> add_face(const n_faces_set<N, D>& adjacent_faces);
119
120
      /// \}

Guillaume Lazzara's avatar
Guillaume Lazzara committed
121
      /// Static manipulators.
122
123
124
      ///
      /// These methods use statically-known input.
      /// \{
Guillaume Lazzara's avatar
Guillaume Lazzara committed
125
      /// Return the total number of faces, whatever their
126
      /// dimension.
127
      unsigned nfaces() const;
128

Guillaume Lazzara's avatar
Guillaume Lazzara committed
129
      /// Return the number of \p N-faces.
130
      template <unsigned N>
131
      unsigned nfaces_of_static_dim() const;
132
133
      /// \}

Guillaume Lazzara's avatar
Guillaume Lazzara committed
134
      /// Dynamic manipulators.
135
136
137
      ///
      /// These methods use input know as run time.
      /// \{
Guillaume Lazzara's avatar
Guillaume Lazzara committed
138
      /// Return the number of \a n-faces.
139
140
      ///
      /// Warning, this function has a complexity linear in term of N,
141
142
      /// since each n_faces_set is checked (the present implementation
      /// does not provide a direct access to n_faces_set through a
143
      /// dynamic value of the dimension).
144
      unsigned nfaces_of_dim(unsigned n) const;
145
146
147
148
149
150
151
152
153
154
155
      /// \}

      /// Pretty-printing.
      /// \{
      /// Print the complex.
      void print(std::ostream& ostr) const;
      /// Print the faces of dimension \p N.
      template <unsigned N>
      void print_faces(std::ostream& ostr) const;
      /// \}

Guillaume Lazzara's avatar
Guillaume Lazzara committed
156
      /// Get the address of the data of this complex.
157
158
159
160
161
      ///
      /// This address is a concise and useful information to print
      /// and track the actual content of this complex.
      const void* addr() const;

162
163
164
165
166
167
168
169
170
    private:
      /// The actual data of the complex.
      util::tracked_ptr< internal::complex_data<D> > data_;

      template <unsigned D_>
      friend bool operator==(const complex<D_>& lhs, const complex<D_>& rhs);

      /// Accessors.
      /// \{
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;
179
180
181
182
183
184
185
186
187
188
      /// \}

      /// Functional meta-manipulators.
      /// \{
      /* FIXME: Use something more constraining than the STL's
	 UnaryFunction/BinaryFunction.  Use Function or Function_v2v?
	 Or a new subclass of Function?  */

      /* FIXME: Replace F and ACCU by a Milena accumulator?  */

Guillaume Lazzara's avatar
Guillaume Lazzara committed
189
      /** Apply a kind of static fold left operator to the
190
	  implicit list of n_faces_set using a functor \a f and a value \a
191
192
193
194
195
196
197
198
199
200
	  accu.

	  Argument \a is called an "accumulator", but with a slightly
	  different meaning than mln:accu members.

	  We might want to use TypeLists or something similar, is they
	  provide an explicit static fold left operator.  */
      template <typename BinaryFunction, typename T>
      T fold_left_(const BinaryFunction& f, const T& accu) const;

Guillaume Lazzara's avatar
Guillaume Lazzara committed
201
      /// Apply a functor \a f to this list of \a n-faces.
202
203
204
205
206
      template <typename UnaryFunction>
      typename UnaryFunction::result_type
      apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const;
      /// \}

Guillaume Lazzara's avatar
Guillaume Lazzara committed
207
      /// Connect two algebraic faces.
208
      ///
209
      /// \param f1 An algebraic face of dimension \p N
210
211
212
213
      /// \param f2 A face of dimension \p N + 1
      ///
      /// \pre \p N must be lower or equal to \p D.
      template <unsigned N>
214
215
      void connect_(const algebraic_n_face<N, D>& f1,
		    const n_face<N + 1, D>& f2);
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
    };


    /// Compare two complexes for equality.
    template <unsigned D>
    bool
    operator==(const complex<D>& lhs, const complex<D>& rhs);


    /// Pretty print a complex.
    template <unsigned D>
    std::ostream&
    operator<<(std::ostream& ostr, const complex<D>& c);


    /*---------------.
    | Complex data.  |
    `---------------*/

Guillaume Lazzara's avatar
Guillaume Lazzara committed
235
    /** Complex data.
236
237
238
239
240

	Data is aggregated as follows in an mln::topo::complex<D>:

        \verbatim

241
                   ,-----------> higher_dim_faces_set_mixin<0, D>
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
                   |
        faces_set_mixin<0, D> 
                 ^
                 |
                 | ,-----------> higher_dim_faces_set_mixin<1, D>
                 | | ,--------->  lower_dim_faces_set_mixin<1, D>
                 | | |           
        faces_set_mixin<1, D>
                 ^
                 |
                 |

                ...

                 ^
                 |
                 | ,-----------> higher_dim_faces_set_mixin<D - 1, D>
                 | | ,--------->  lower_dim_faces_set_mixin<D - 1, D>
                 | | |           
        faces_set_mixin<D - 1, D>
                 ^
                 |              
                 |   ,--------->  lower_dim_faces_set_mixin<D, D>
                 |   |           
        faces_set_mixin<D, D> 
                 ^
                 |
                 |
           complex_data<D> ----.  (shared data)
                               |
                               |
                ,--------------'
                |
                |
                `----<> tracked_ptr< complex_data<D> > ----<> complex<D>

        \endverbatim


	An instance of mln::topo::internal::faces_set_mixin<N, D>
	stores the \p N-faces of a \p D-complex.

	Classes mln::topo::internal::lower_dim_faces_set_mixin<N, D>
	are implementation classes factoring services related to
	complex data.  */
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305


    /*---------------------.
    | Faces of a complex.  |
    `---------------------*/

    /// The sets of n-faces of a complex are recursively aggregated as
    /// mixins.
    namespace internal
    {

      // Forward declarations.
      template <unsigned N, unsigned D> struct lower_dim_faces_set_mixin;
      template <unsigned N, unsigned D> struct higher_dim_faces_set_mixin;

      // -------------------------------------- //
      // mln::topo::internal::faces_set_mixin.  //
      // -------------------------------------- //

Guillaume Lazzara's avatar
Guillaume Lazzara committed
306
      /// Recursive mixins of set of faces.
307
      /// \{
308

309
310
      template <unsigned N, unsigned D> struct faces_set_mixin;

311
312
313
314
315
316

      /// Faces of intermediate dimension (greater than 0, lower than \p D).
      template <unsigned N, unsigned D>
      struct faces_set_mixin : public faces_set_mixin<N - 1, D>,
			       public lower_dim_faces_set_mixin<N, D>,
			       public higher_dim_faces_set_mixin<N, D>
317
      {
318
	std::vector< face_data<N, D> > faces_;
319
320
321

	/// Pretty-printing.
	/// \{
322
	/// Print the faces of dimension \p N.
323
	void print(std::ostream& ostr) const;
324
325
	/// Recursively print the faces of dimensions 0 to \p N
	/// (in ascending dimension).
326
327
328
329
330
	void print_rec_asc(std::ostream& ostr) const;
	/// \}

	/// Functional meta-manipulators.
	/// \{
Guillaume Lazzara's avatar
Guillaume Lazzara committed
331
	/// Fold left.
332
333
334
	/// \see mln::complex<D>::fold_left_.
	template <typename BinaryFunction, typename T>
	T fold_left_(const BinaryFunction& f, const T& accu) const;
335
	/// Apply a functor \a f to the list of faces if \a n == \p N.
336
337
338
339
340
341
342
	/// \see mln::complex<D>::apply_if_dim_matches_.
	template <typename UnaryFunction>
	typename UnaryFunction::result_type
	apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const;
	/// \}
      };

343
344
345
346
      /// Faces of highest dimension (\p D).
      template <unsigned D>
      struct faces_set_mixin<D, D> : public faces_set_mixin<D - 1, D>,
				     public lower_dim_faces_set_mixin<D, D>
347
      {
348
	std::vector< face_data<D, D> > faces_;
349
350
351

	/// Pretty-printing.
	/// \{
352
	/// Print the faces of dimension \p D.
353
354
355
356
357
358
	void print(std::ostream& ostr) const;
	void print_rec_asc(std::ostream& ostr) const;
	/// \}

	/// Functional meta-manipulators.
	/// \{
Guillaume Lazzara's avatar
Guillaume Lazzara committed
359
	/// Fold left.
360
361
362
	/// \see mln::complex<D>::fold_left_.
	template <typename BinaryFunction, typename T>
	T fold_left_(const BinaryFunction& f, const T& accu) const;
363
	/// Apply a functor \a f to the list of faces if \a n == \p D.
364
365
366
367
368
369
370
371
372
373
374
	/// \see mln::complex<D>::apply_if_dim_matches_.
	template <typename UnaryFunction>
	typename UnaryFunction::result_type
	apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const;
	/// \}
      };

      /// Faces of lowest dimension (0).
      template <unsigned D>
      struct faces_set_mixin<0u, D> : public higher_dim_faces_set_mixin<0u, D>
      {
375
	std::vector< face_data<0u, D> > faces_;
376
377
378
379
380
381
382
383
384
385

	/// Pretty-printing.
	/// \{
	/// Print the faces of dimension 0.
	void print(std::ostream& ostr) const;
	void print_rec_asc(std::ostream& ostr) const;
	/// \}

	/// Functional meta-manipulators.
	/// \{
Guillaume Lazzara's avatar
Guillaume Lazzara committed
386
	/// Fold left.
387
388
389
	/// \see mln::complex<D>::fold_left_.
	template <typename BinaryFunction, typename T>
	T fold_left_(const BinaryFunction& f, const T& accu) const;
Guillaume Lazzara's avatar
Guillaume Lazzara committed
390
	/// Apply a functor \a f to the list of faces if \a n == 0.
391
392
393
394
395
396
397
398
399
400
401
	/// \see mln::complex<D>::apply_if_dim_matches_.
	template <typename UnaryFunction>
	typename UnaryFunction::result_type
	apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const;
	/// \}
      };

      /// Faces of a 0-complex.
      template <>
      struct faces_set_mixin<0u, 0u>
      {
402
	std::vector< face_data<0u, 0u> > faces_;
403
404
405
406
407
408
409
410
411
412

	/// Pretty-printing.
	/// \{
	/// Print the faces of dimension \p D.
	void print(std::ostream& ostr) const;
	void print_rec_asc(std::ostream& ostr) const;
	/// \}

	/// Functional meta-manipulators.
	/// \{
Guillaume Lazzara's avatar
Guillaume Lazzara committed
413
	/// Fold left.
414
415
416
	/// \see mln::complex<D>::fold_left_.
	template <typename BinaryFunction, typename T>
	T fold_left_(const BinaryFunction& f, const T& accu) const;
Guillaume Lazzara's avatar
Guillaume Lazzara committed
417
	/// Apply a functor \a f to the list of faces if \a n == 0.
418
419
420
421
422
423
424
425
426
	/// \see mln::complex<D>::apply_if_dim_matches_.
	template <typename UnaryFunction>
	typename UnaryFunction::result_type
	apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const;
	/// \}
      };
      /// \}


427
428
429
430
431
432
433
434
435
436
437
438
      // Tech note: g++-2.95 highly prefers to have the complex_data
      // class to be defined after the specializations of
      // 'faces_set_mixin'.

      /// Complex data.
      template <unsigned D>
      struct complex_data : public faces_set_mixin<D, D>
      {
	// Data is contained in super classes.
      };


439
440
441
442
443
444
445
446
447
448
      // ------------------------------------------------- //
      // mln::topo::internal::lower_dim_faces_set_mixin.   //
      // mln::topo::internal::higher_dim_faces_set_mixin.  //
      // ------------------------------------------------- //

      /// Mixins of mixin mln::faces_set_mixin.
      /// \{
      template <unsigned N, unsigned D>
      struct lower_dim_faces_set_mixin
      {
449
	void print(std::ostream& ostr, const face_data<N, D>& f) const;
450
451
452
453
454
      };

      template <unsigned N, unsigned D>
      struct higher_dim_faces_set_mixin
      {
455
	void print(std::ostream& ostr, const face_data<N, D>& f) const;
456
457
458
459
460
461
462
463
464
465
466
467
468
469
      };
      /// \}

    } // end of namespace mln::topo::internal



# ifndef MLN_INCLUDE_ONLY

    /*-----------------------.
    | Complex construction.  |
    `-----------------------*/

    template <unsigned D>
470
    inline
471
472
473
474
475
476
477
    complex<D>::complex()
      // Allocate data for this complex.
      : data_(new internal::complex_data<D>())
    {
    }

    template <unsigned D>
478
    inline
479
    n_face<0u, D>
480
481
    complex<D>::add_face()
    {
482
483
484
485
      // Upcast `data_' to get access to the field `faces_' of its
      // base class `internal::faces_set_mixin<0u, D>'.
      std::vector< face_data<0u, D> >& faces_0 =
	static_cast< internal::faces_set_mixin<0u, D>& >(*data_).faces_;
486
487
      /* FIXME: This is not thread-proof (these two lines should
	 form an atomic section).  */
488
      faces_0.push_back(face_data<0u, D>());
489
      unsigned id = nfaces_of_static_dim<0u>() - 1;
490
      return n_face<0u, D>(*this, id);
491
492
493
494
    }

    template <unsigned D>
    template <unsigned N>
495
    inline
496
    n_face<N + 1, D>
497
    complex<D>::add_face(const n_faces_set<N, D>& adjacent_faces)
498
    {
499
500
      typedef typename std::vector< algebraic_n_face<N, D> >::const_iterator
	iter_t;
501
502
503
504
505
506

      // Ensure ADJACENT_FACES are already part of the complex.
      if (!HAS_NDEBUG)
	for (iter_t a = adjacent_faces.faces().begin();
	     a != adjacent_faces.faces().end(); ++a)
	  {
507
	    mln_precondition(a->cplx() == *this);
508
509
510
	    mln_precondition(a->is_valid());
	  }

511
      face_data<N + 1, D> f;
512
513
514
515
      // Upcast `data_' to get access to the field `faces_' of its
      // base class `internal::faces_set_mixin<N + 1, D>'.
      std::vector< face_data<N + 1, D> >& faces_n_plus_1 =
	static_cast< internal::faces_set_mixin<N + 1, D>& >(*data_).faces_;
516
517
      /* FIXME: This is not thread-proof (these two lines should
	 form an atomic section).  */
518
      faces_n_plus_1.push_back(f);
519
      unsigned id = nfaces_of_static_dim<N + 1>() - 1;
520

521
      n_face<N + 1, D> fh(*this, id);
522
523
524
      // Connect F and its ADJACENT_FACES.
      for (iter_t a = adjacent_faces.faces().begin();
	   a != adjacent_faces.faces().end(); ++a)
525
526
527
528
	/* Connect
	   - algebraic n-face *A,
	   - and an (n+1)-algebraic face based on FH and having the
             sign of *A.  */
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
	connect_(*a, fh);
      return fh;
    }


    /*-------.
    | Misc.  |
    `-------*/

    namespace internal
    {

      /// A binary meta-functor defined by:
      ///
      /// \code
      /// add_size : x, c -> x + c.size()
      /// \endcode
      ///
547
      /// \see mln::complex<D>::nfaces_of_static_dim<N> (static version).
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
      /// \see mln::complex<D>::fold_left_.
      struct add_size
      {
	template <typename T, typename Container>
	T operator()(const T& x, const Container& c) const
	{
	  return x + c.size();
	}
      };

      /// An unary meta-functor defined by:
      ///
      /// \code
      /// add_size : c -> c.size()
      /// \endcode
      ///
564
      /// \see mln::complex<D>::nfaces_of_dim (dynamic version).
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
      /// \see mln::complex<D>::apply_if_dim_matches_.
      struct get_size
      {
	typedef std::size_t result_type;

	template <typename Container>
	typename Container::size_type operator()(const Container& c) const
	{
	  return c.size();
	}
      };

    } // end of namespace mln::topo::internal


    /*----------------------.
    | Static manipulators.  |
    `----------------------*/

    template <unsigned D>
585
    inline
586
    unsigned
587
588
589
590
591
592
593
    complex<D>::nfaces() const
    {
      return fold_left_(internal::add_size(), 0);
    }

    template <unsigned D>
    template <unsigned N>
594
    inline
595
    unsigned
596
    complex<D>::nfaces_of_static_dim() const
597
    {
598
599
600
601
602
      // Upcast `data_' to get access to the field `faces_' of its
      // base class `internal::faces_set_mixin<N, D>'.
      const std::vector< face_data<N, D> >& faces_n =
	static_cast< const internal::faces_set_mixin<N, D>& >(*data_).faces_;
      return faces_n.size();
603
604
605
606
607
608
609
610
    }


    /*-----------------------.
    | Dynamic manipulators.  |
    `-----------------------*/

    template <unsigned D>
611
    inline
612
    unsigned
613
    complex<D>::nfaces_of_dim(unsigned n) const
614
615
616
617
618
619
620
621
622
623
624
625
626
    {
      // Ensure N is compatible with D.
      mln_precondition(n <= D);
      return apply_if_dim_matches_(n, internal::get_size());
    }


    /*-------------------.
    | Internal methods.  |
    `-------------------*/

    template <unsigned D>
    template <unsigned N>
627
    inline
628
629
    face_data<N, D>&
    complex<D>::face_data_(unsigned face_id)
630
    {
631
632
633
634
635
      // Upcast `data_' to get access to the field `faces_' of its
      // base class `internal::faces_set_mixin<N, D>'.
      std::vector< face_data<N, D> >& faces_n =
	static_cast< internal::faces_set_mixin<N, D>& >(*data_).faces_;
      return faces_n[face_id];
636
637
638
639
    }

    template <unsigned D>
    template <unsigned N>
640
    inline
641
642
    const face_data<N, D>&
    complex<D>::face_data_(unsigned face_id) const
643
    {
644
645
646
647
648
      // Upcast `data_' to get access to the field `faces_' of its
      // base class `internal::faces_set_mixin<N, D>'.
      const std::vector< face_data<N, D> >& faces_n =
	static_cast< const internal::faces_set_mixin<N, D>& >(*data_).faces_;
      return faces_n[face_id];
649
650
651
652
    }

    template <unsigned D>
    template <unsigned N>
653
    inline
654
    void
655
656
    complex<D>::connect_(const algebraic_n_face<N, D>& f1,
			 const n_face<N + 1, D>& f2)
657
658
659
660
    {
      // Ensure N is compatible with D.
      metal::bool_< N <= D >::check();

661
662
663
664
665
      /* Connect
	 - F1, an algebraic n-face,
	 - and AF2, an algebraic (n+1)-face based on F2 and having the
	   sign of F1.  */
      f1.data().connect_higher_dim_face(make_algebraic_n_face(f2, f1.sign()));
666
      f2.data().connect_lower_dim_face(f1);
667
668
669
670
671
672
673
674
    }


    /*-------------.
    | Comparison.  |
    `-------------*/

    template <unsigned D>
675
    inline
676
677
678
679
680
681
682
683
684
685
686
687
    bool
    operator==(const complex<D>& lhs, const complex<D>& rhs)
    {
      return lhs.data_.ptr_ == rhs.data_.ptr_;
    }


    /*------------------.
    | Pretty-printing.  |
    `------------------*/

    template <unsigned D>
688
    inline
689
690
691
692
693
694
695
696
    std::ostream&
    operator<<(std::ostream& ostr, const complex<D>& c)
    {
      c.print(ostr);
      return ostr;
    }

    template <unsigned D>
697
    inline
698
699
700
    void
    complex<D>::print(std::ostream& ostr) const
    {
701
702
703
      // Upcast `data_' to get access to the method `print_rec_asc' of
      // its base class `internal::faces_set_mixin<D, D>'.
      static_cast< const internal::faces_set_mixin<D, D>& >(*data_).print_rec_asc(ostr);
704
705
706
707
    }

    template <unsigned D>
    template <unsigned N>
708
    inline
709
710
711
712
713
714
    void
    complex<D>::print_faces(std::ostream& ostr) const
    {
      // Ensure N is compatible with D.
      metal::bool_< N <= D >::check();

715
716
717
      // Upcast `data_' to get access to the method `print' of its
      // base class `internal::faces_set_mixin<N, D>'.
      static_cast< const internal::faces_set_mixin<N, D>& >(*data_).print(ostr);
718
719
    }

720
721
722
723
724
725
726
727
    template <unsigned D>
    inline
    const void* 
    complex<D>::addr() const
    {
      return data_.ptr_;
    }

728
729
730
731
732

    namespace internal
    {

      template <unsigned N, unsigned D>
733
      inline
734
735
736
737
738
739
740
741
      void
      faces_set_mixin<N, D>::print_rec_asc(std::ostream& ostr) const
      {
	faces_set_mixin<N - 1, D>::print_rec_asc(ostr);
	print(ostr);
      }

      template <unsigned D>
742
      inline
743
744
745
746
747
748
749
      void
      faces_set_mixin<0u, D>::print_rec_asc(std::ostream& ostr) const
      {
	print(ostr);
      }

      template <unsigned D>
750
      inline
751
752
753
754
755
756
757
      void
      faces_set_mixin<D, D>::print_rec_asc(std::ostream& ostr) const
      {
	faces_set_mixin<D - 1, D>::print_rec_asc(ostr);
	print(ostr);
      }

758
      inline
759
760
761
762
763
764
765
766
      void
      faces_set_mixin<0u, 0u>::print_rec_asc(std::ostream& ostr) const
      {
	print(ostr);
      }


      template <unsigned N, unsigned D>
767
      inline
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
      void
      faces_set_mixin<N, D>::print(std::ostream& ostr) const
      {
	ostr << "Faces of dimension " << N
	     << " and their ajacent faces of dimension "
	     << N - 1 << " and "
	     << N + 1 << std::endl;
	for (unsigned f = 0; f < faces_.size(); ++f)
	  {
	    ostr << "  " << f << ":  dim " << N - 1 << ": { ";
	    lower_dim_faces_set_mixin<N, D>::print(ostr, faces_[f]);
	    ostr << "},  dim " << N + 1 << ": { ";
	    higher_dim_faces_set_mixin<N, D>::print(ostr, faces_[f]);
	    ostr << "}" << std::endl;
	  }
      }

      template <unsigned D>
786
      inline
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
      void
      faces_set_mixin<0u, D>::print(std::ostream& ostr) const
      {
	const unsigned N = 0u;
	ostr << "Faces of dimension " << N
	     << " and their ajacent faces of dimension "
	     << N + 1 << std::endl;
	for (unsigned f = 0; f < faces_.size(); ++f)
	  {
	    ostr << "  " << f << ":  dim " << N + 1 << ": { ";
	    higher_dim_faces_set_mixin<N, D>::print(ostr, faces_[f]);
	    ostr << "}" << std::endl;
	  }
      }

      template <unsigned D>
803
      inline
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
      void
      faces_set_mixin<D, D>::print(std::ostream& ostr) const
      {
	const unsigned N = D;
	ostr << "Faces of dimension " << N
	     << " and their ajacent faces of dimension "
	     << N - 1 << std::endl;
	for (unsigned f = 0; f < faces_.size(); ++f)
	  {
	    ostr << "  " << f << ":  dim " << N - 1 << ": { ";
	    lower_dim_faces_set_mixin<N, D>::print(ostr, faces_[f]);
	    ostr << "}" << std::endl;
	  }
      }

819
      inline
820
821
822
823
824
825
826
827
828
829
830
      void
      faces_set_mixin<0u, 0u>::print(std::ostream& ostr) const
      {
	const unsigned N = 0u;
	ostr << "Faces of dimension " << N << std::endl;
	for (unsigned f = 0; f < faces_.size(); ++f)
	  ostr << "  " << f << std::endl;
      }


      template <unsigned N, unsigned D>
831
      inline
832
833
      void
      lower_dim_faces_set_mixin<N, D>::print(std::ostream& ostr,
834
					     const face_data<N, D>& f) const
835
      {
836
	for (typename std::vector< algebraic_n_face<N - 1, D> >::const_iterator l =
837
838
839
840
841
	       f.lower_dim_faces_.begin(); l != f.lower_dim_faces_.end(); ++l)
	  ostr << l->face_id() << " ";
      }

      template <unsigned N, unsigned D>
842
      inline
843
844
      void
      higher_dim_faces_set_mixin<N, D>::print(std::ostream& ostr,
845
					      const face_data<N, D>& f) const
846
      {
847
	for (typename std::vector< algebraic_n_face<N + 1, D> >::const_iterator h =
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
	       f.higher_dim_faces_.begin(); h != f.higher_dim_faces_.end(); ++h)
	  ostr << h->face_id() << " ";
      }

    } // end of namespace mln::topo::internal


    /*-------------------------------.
    | Functional meta-manipulators.  |
    `-------------------------------*/

    /* ------------------------------- */
    /* ``Static Fold Left'' Operator.  */
    /* ------------------------------- */

    template <unsigned D>
    template <typename BinaryFunction, typename T>
865
    inline
866
867
868
    T
    complex<D>::fold_left_(const BinaryFunction& f, const T& accu) const
    {
869
870
871
      // Upcast `data_' to get access to the method `fold_left_' of
      // its base class `internal::faces_set_mixin<D, D>'.
      return static_cast< const internal::faces_set_mixin<D, D>& >(*data_).fold_left_(f, accu);
872
873
874
875
876
877
878
879
880
    }

    namespace internal
    {

      // FIXME: Try to factor.

      template <unsigned D>
      template <typename BinaryFunction, typename T>
881
      inline
882
883
884
885
      T
      faces_set_mixin<D, D>::fold_left_(const BinaryFunction& f,
					const T& accu) const
      {
886
887
888
	// Upcast `data_' to get access to the method `fold_left_' of
	// its base class `internal::faces_set_mixin<D - 1, D>'.
	return static_cast< const faces_set_mixin<D - 1, D>& >(*this).fold_left_(f, f(accu, faces_));
889
890
891
892
      }

      template <unsigned N, unsigned D>
      template <typename BinaryFunction, typename T>
893
      inline
894
895
896
897
      T
      faces_set_mixin<N, D>::fold_left_(const BinaryFunction& f,
					const T& accu) const
      {
898
899
900
	// Upcast `data_' to get access to the method `fold_left_' of
	// its base class `internal::faces_set_mixin<N - 1, D>'.
	return static_cast< const faces_set_mixin<N - 1, D>& >(*this).fold_left_(f, f(accu, faces_));
901
902
903
904
      }

      template <unsigned D>
      template <typename BinaryFunction, typename T>
905
      inline
906
907
908
909
910
911
912
913
      T
      faces_set_mixin<0u, D>::fold_left_(const BinaryFunction& f,
					 const T& accu) const
      {
	return f(accu, faces_);
      }

      template <typename BinaryFunction, typename T>
914
      inline
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
      T
      faces_set_mixin<0u, 0u>::fold_left_(const BinaryFunction& f,
					  const T& accu) const
      {
	return f(accu, faces_);
      }

    } // end of namespace mln::topo::internal


    /* ------------------------------------------------ */
    /* ``Static Apply-If-Dimension-Matches'' Operator.  */
    /* ------------------------------------------------ */

    template <unsigned D>
    template <typename UnaryFunction>
931
    inline
932
933
934
935
936
    typename UnaryFunction::result_type
    complex<D>::apply_if_dim_matches_(unsigned n, const UnaryFunction& f) const
    {
      // Ensure N is compatible with D.
      mln_precondition(n <= D);
937
938
939
      // Upcast `data_' to get access to the method `apply_if_dim_matches_' of
      // its base class `internal::faces_set_mixin<D, D>'.
      return static_cast< const internal::faces_set_mixin<D, D>& >(*data_).apply_if_dim_matches_(n, f);
940
941
942
943
944
945
946
947
948
    }

    namespace internal
    {

      // FIXME: Try to factor.

      template <unsigned D>
      template <typename UnaryFunction>
949
      inline
950
951
952
953
954
955
956
957
958
959
960
961
962
      typename UnaryFunction::result_type
      faces_set_mixin<D, D>::apply_if_dim_matches_(unsigned n,
						   const UnaryFunction& f) const
      {
	// Ensure N and D are compatible.
	mln_precondition(n <= D);
	return n == D ?
	  f(faces_) :
	  faces_set_mixin<D - 1, D>::apply_if_dim_matches_(n, f);
      }

      template <unsigned N, unsigned D>
      template <typename UnaryFunction>
963
      inline
964
965
966
967
968
969
970
971
972
973
974
975
976
      typename UnaryFunction::result_type
      faces_set_mixin<N, D>::apply_if_dim_matches_(unsigned n,
						   const UnaryFunction& f) const
      {
	// Ensure N and D are compatible.
	mln_precondition(n <= D);
	return n == N ?
	  f(faces_) :
	  faces_set_mixin<N - 1, D>::apply_if_dim_matches_(n, f);
      }

      template <unsigned D>
      template <typename UnaryFunction>
977
      inline
978
979
980
981
982
983
      typename UnaryFunction::result_type
      faces_set_mixin<0u, D>::apply_if_dim_matches_(unsigned n,
						    const UnaryFunction& f) const
      {
	// If we reached this method, then N should be 0.
	mln_precondition(n == 0);
984
985
	// Prevent ``unused variable'' warnings when NDEBUG is defined.
	(void) n;
986
987
988
989
	return f(faces_);
      }

      template <typename UnaryFunction>
990
      inline
991
992
993
994
995
996
      typename UnaryFunction::result_type
      faces_set_mixin<0u, 0u>::apply_if_dim_matches_(unsigned n,
						     const UnaryFunction& f) const
      {
	// If we reached this method, then N should be 0.
	mln_precondition(n == 0);
Roland Levillain's avatar
Roland Levillain committed
997
998
	// Prevent ``unused variable'' warnings when NDEBUG is defined.
	(void) n;
999
1000
	return f(faces_);
      }