object_links.hh 8.68 KB
Newer Older
1
// Copyright (C) 2009, 2010, 2011, 2013 EPITA Research and Development
2
// Laboratory (LRDE)
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//
// This file is part of Olena.
//
// 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,
// 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
// along with Olena.  If not, see <http://www.gnu.org/licenses/>.
//
// As a special exception, you may use this file as part of a free
// software project without restriction.  Specifically, if other files
// instantiate templates or use macros or inline functions from this
// 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.

#ifndef SCRIBO_CORE_OBJECT_LINKS_HH
# define SCRIBO_CORE_OBJECT_LINKS_HH

/// \file
///
/// \brief Object links representation.
33

34
35

# include <mln/util/array.hh>
36
# include <mln/util/tracked_ptr.hh>
37

38
# include <scribo/core/component_set.hh>
39

40
41
# include <scribo/core/concept/serializable.hh>

42
43
44
45
46
namespace scribo
{

  using namespace mln;

47
48
49
50
51
52
  // Forward declaration.
  template <typename L> class object_links;


  namespace internal
  {
53

54
55
56
57
58
59
60
    /// Data structure for \c scribo::object_links<I>.
    template <typename L>
    struct object_links_data
    {
      object_links_data();
      object_links_data(const component_set<L>& components, unsigned size);
      object_links_data(const component_set<L>& components,
61
			unsigned size, unsigned default_link_id);
62
63
64
65
66
67
68
69
70
71

      mln::util::array<unsigned> comp_to_link_;
      component_set<L> components_;
    };

  } // end of namespace scribo::internal




72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  /*! \brief Object links representation.

    This structure is meant to store link information between
    components. Linking components can be considered as a first step
    towards component grouping.

    It requires a component_set to be constructed. Each component
    existing in the component_set may have link in an object_link
    structure. If no component_set is used for construction, this
    object is invalid (\sa is_valid()).



    \ingroup grpstruct
  */
87
  template <typename L>
88
  class object_links : public Serializable<object_links<L> >
89
  {
90
    typedef internal::object_links_data<L> data_t;
91
92

  public:
93
    /// Default constructor. It produces an invalid structure.
Guillaume Lazzara's avatar
Guillaume Lazzara committed
94
    object_links();
95
96
97
98

    /// Construct a valid object_links. Links is enabled for each
    /// valid component but no link is set. Invalid components links
    /// are disabled.
99
    object_links(const component_set<L>& components);
100

101
102
103
104
105
106
    /// Construct a valid object_links. Links is enabled for each
    /// valid component and set by default towards component with id
    /// \p default_link_id. Invalid components links are disabled.
    object_links(const component_set<L>& components, unsigned default_link_id);

    /// Return the underlying component_set.
107
    const component_set<L>& components() const;
108

109
110
    /// Return True if this object_links structure is correctly
    /// constructed.
Guillaume Lazzara's avatar
Guillaume Lazzara committed
111
    bool is_valid() const;
112
113
114
115
116
117

    /// Return True if component \p comp_id can be linked to another
    /// component.
    bool has_linking_enabled(unsigned comp_id) const;

    /// Return True if component \p comp_id has a link starting from
118
    /// itself to another component.
119
    bool is_linked(unsigned comp_id) const;
Guillaume Lazzara's avatar
Guillaume Lazzara committed
120

121
122
    /// Return the number of links. This is equivalent to the number
    /// of components + the background.
123
124
    unsigned nelements() const;

125
126
127
128
129
130
131
132
133
    /// Link related methods.
    /// \{
    /// Set link between component \p from_id and \p to_id.
    void update(unsigned from_id, unsigned to_id);

    /// Reset link for component with id \p id. This component can be
    /// linked later.
    void clear(unsigned id);

134
135
    /// Do not allow component with id \p id to be linked to another
    /// component.
136
137
138
    void disable_linking(unsigned id);

    /// Get link id for component \p comp_id.
139
    const unsigned& operator()(unsigned comp_id) const;
140
    /// \}
141

142
143
144
    /// Returns the underlying array encoding the component
    /// links. Indexes in array correspond to component ids and the
    /// corresponding value is the component id involved in the link.
145
146
    const mln::util::array<unsigned>& comp_to_link() const;

147
148
    /// Initialize links. Each component is linked to itself (i.e. has
    /// no link). Invalid components have linking disabled.
149
    void init();
150

151
    /// Make a deep copy of this structure.
152
153
    object_links<L> duplicate() const;

154
  private:
155
    mln::util::tracked_ptr<data_t> data_;
156
157
158
  };


159
  /// \relates object_links
160
161
162
163
164
  template <typename L>
  std::ostream&
  operator<<(std::ostream& ostr, const object_links<L>& links);


165
166
# ifndef MLN_INCLUDE_ONLY

167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188

  namespace internal
  {


    /// Data structure for \c scribo::object_links<I>.
    template <typename L>
    object_links_data<L>::object_links_data()
    {
    }


    template <typename L>
    object_links_data<L>::object_links_data(const component_set<L>& components,
					    unsigned size)
      : comp_to_link_(size), components_(components)
    {
    };


    template <typename L>
    object_links_data<L>::object_links_data(const component_set<L>& components,
189
190
					    unsigned size, unsigned default_link_id)
      : comp_to_link_(size, default_link_id), components_(components)
191
192
193
194
195
196
197
198
    {
    };


  } // end of namespace scribo::internal



Guillaume Lazzara's avatar
Guillaume Lazzara committed
199
200
201
  template <typename L>
  object_links<L>::object_links()
  {
202
    data_ = new data_t();
Guillaume Lazzara's avatar
Guillaume Lazzara committed
203
204
  }

205

206
  template <typename L>
207
  object_links<L>::object_links(const component_set<L>& components)
208
  {
209
    data_ = new data_t(components, value::next(components.nelements()));
210
211
212

    // Initialize with no link.
    init();
213
214
  }

215

216
  template <typename L>
217
  object_links<L>::object_links(const component_set<L>& components,
218
				unsigned default_link_id)
219
  {
220
    data_ = new data_t(components, value::next(components.nelements()),
221
		       default_link_id);
222
223
224
225
  }


  template <typename L>
226
  const component_set<L>&
227
  object_links<L>::components() const
228
  {
229
    return data_->components_;
230
231
232
  }


Guillaume Lazzara's avatar
Guillaume Lazzara committed
233
234
235
236
  template <typename L>
  bool
  object_links<L>::is_valid() const
  {
237
238
239
240
241
    return data_->components_.is_valid()
      && data_->components_.nelements() == (this->nelements() - 1);
  }


Guillaume Lazzara's avatar
Guillaume Lazzara committed
242
243
  template <typename L>
  bool
244
  object_links<L>::has_linking_enabled(unsigned comp_id) const
Guillaume Lazzara's avatar
Guillaume Lazzara committed
245
246
247
  {
    mln_precondition(is_valid());
    mln_precondition(comp_id < data_->comp_to_link_.nelements());
248

Guillaume Lazzara's avatar
Guillaume Lazzara committed
249
250
251
    return data_->comp_to_link_(comp_id) != 0;
  }

252
253
254
255
256
257
258
259
260
261
262
  template <typename L>
  bool
  object_links<L>::is_linked(unsigned comp_id) const
  {
    mln_precondition(is_valid());
    mln_precondition(comp_id < data_->comp_to_link_.nelements());

    return has_linking_enabled(comp_id)
      && data_->comp_to_link_(comp_id) != comp_id;
  }

Guillaume Lazzara's avatar
Guillaume Lazzara committed
263

264
265
266
267
  template <typename L>
  unsigned
  object_links<L>::nelements() const
  {
268
    return data_->comp_to_link_.nelements();
269
270
271
272
  }


  template <typename L>
273
274
  const unsigned&
  object_links<L>::operator()(unsigned comp_id) const
275
276
277
278
  {
    return data_->comp_to_link_(comp_id);
  }

279
280
281
282
283
284
  template <typename L>
  void
  object_links<L>::update(unsigned from_id, unsigned to_id)
  {
    data_->comp_to_link_(from_id) = to_id;
  }
285
286

  template <typename L>
287
288
  void
  object_links<L>::clear(unsigned id)
289
  {
290
    data_->comp_to_link_(id) = id;
291
292
  }

293
294
295
296
297
298
  template <typename L>
  void
  object_links<L>::disable_linking(unsigned id)
  {
    data_->comp_to_link_(id) = 0;
  }
299
300
301
302
303
304

  template <typename L>
  const mln::util::array<unsigned>&
  object_links<L>::comp_to_link() const
  {
    return data_->comp_to_link_;
Guillaume Lazzara's avatar
Guillaume Lazzara committed
305
306
  }

307
308
309
310
311
312
  template <typename L>
  void
  object_links<L>::init()
  {
    for (unsigned i = 0; i < nelements(); ++i)
      if (data_->components_(i).tag() == component::Ignored)
313
	disable_linking(i);
314
      else
315
	clear(i);
316
317
  }

318
319
320
321
322
323
324
325
326
327
328
329
  template <typename L>
  inline
  object_links<L>
  object_links<L>::duplicate() const
  {
    object_links<L> output;
    output.data_ = new data_t();

    *(output.data_.ptr_) = *(data_.ptr_);
    return output;
  }

330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345

  template <typename L>
  std::ostream&
  operator<<(std::ostream& ostr, const object_links<L>& links)
  {
    ostr << "object_links[";

    for_all_links(l, links)
      ostr << l << "->" << links.comp_to_link()[l] << ", ";

    ostr << "]";

    return ostr;
  }


346
347
348
349
350
351
352
# endif // ! MLN_INCLUDE_ONLY


} // end of namespace scribo


#endif // ! SCRIBO_CORE_OBJECT_LINKS_HH