dependencysorter.h
1 /********************************************************************************
2  * FARSA Utilities Library *
3  * Copyright (C) 2007-2011 Gianluca Massera <emmegian@yahoo.it> *
4  * Stefano Nolfi <stefano.nolfi@istc.cnr.it> *
5  * Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it> *
6  * *
7  * This program is free software; you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation; either version 2 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program; if not, write to the Free Software *
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
20  ********************************************************************************/
21 
22 #ifndef DEPENDENCYSORTER_H
23 #define DEPENDENCYSORTER_H
24 
25 #include "utilitiesconfig.h"
26 #include "utilitiesexceptions.h"
27 #include <QMap>
28 #include <QSet>
29 #include <QList>
30 #include <QVector>
31 
32 namespace farsa {
33 
52 template <class ElementType_t>
54 {
55 public:
59  typedef ElementType_t ElementType;
60 
69  {
76  ElementAndDepencies(ElementType e, QList<ElementType> d) :
77  element(e),
78  dependencies(d)
79  {
80  }
81 
85  ElementType element;
86 
90  QList<ElementType> dependencies;
91  };
92 
96  typedef QList<ElementAndDepencies> ElementAndDepenciesList;
97 public:
102  m_elements()
103  {
104  }
105 
112  m_elements(other.m_elements)
113  {
114  }
115 
123  {
124  if (&other == this) {
125  return *this;
126  }
127 
128  m_elements = other.m_elements;
129 
130  return *this;
131  }
132 
137  {
138  }
139 
146  const QMap<ElementType, QSet<ElementType> > elements() const
147  {
148  return m_elements;
149  }
150 
157  void add(ElementType e, ElementType d)
158  {
159  m_elements[e].insert(d);
160  }
161 
168  void add(ElementType e, QList<ElementType> d)
169  {
170  m_elements[e].unite(QSet<ElementType>::fromList(d));
171  }
172 
179  void add(ElementType e, QSet<ElementType> d)
180  {
181  m_elements[e].unite(d);
182  }
183 
189  QList<ElementType> sort() const
190  {
191  // If there are no elements in the map, returning an empty list
192  if (m_elements.empty()) {
193  return QList<ElementType>();
194  }
195 
196  // We copy the map of elements because we remove from the map elements that
197  // have been analyzed
198  QMap<ElementType, QSet<ElementType> > e = m_elements;
199 
200  // The sorted list
201  QList<ElementType> sortedList;
202  // The set with elements we are analyzing (this is needed to check whether cycles exist)
203  QSet<ElementType> elementsBeingAnalyzed;
204  // The stack of elements being analyzed (this is used to prevent restarting from scratch every cycle)
205  QList<ElementType> stackElementsBeingAnalyzed;
206 
207  // Now we keep cycling until the map with elements contains something
208  ElementType nextToTake = e.keys()[0];
209  elementsBeingAnalyzed.insert(nextToTake);
210  while (!e.empty()) {
211  // Checking whether the element to register has any dependency which is present
212  // in the list of elements
213  bool dependencyInList = false;
214  foreach(ElementType d, e[nextToTake]) {
215  if (e.contains(d)) {
216  // We have to add the dependency first
217  stackElementsBeingAnalyzed.push_back(nextToTake);
218  nextToTake = d;
219  dependencyInList = true;
220 
221  // Checking if there is a cycle
222  if (elementsBeingAnalyzed.contains(nextToTake)) {
224  } else {
225  elementsBeingAnalyzed.insert(nextToTake);
226  }
227  }
228  }
229 
230  if (!dependencyInList) {
231  // We can add the element to the sorted list and remove it from the map
232  sortedList.append(nextToTake);
233  e.remove(nextToTake);
234  elementsBeingAnalyzed.remove(nextToTake);
235  if (!stackElementsBeingAnalyzed.empty()) {
236  ElementType tmp = nextToTake;
237  nextToTake = stackElementsBeingAnalyzed.takeLast();
238 
239  // Also removing the element just added to the list from the list of dependencies
240  // (to avoid checking it in the next cycles)
241  e[nextToTake].remove(tmp);
242  } else if (!e.empty()) {
243  nextToTake = e.keys()[0];
244  }
245  }
246  }
247 
248  return sortedList;
249  }
250 
256  ElementAndDepenciesList sortWithDependencies() const
257  {
258  // We first use sort() and then fill the list to return
259  QList<ElementType> s = sort();
260 
261  ElementAndDepenciesList r;
262  for (int i = 0; i < s.size(); i++) {
263  r.append(ElementAndDepencies(s[i], m_elements[s[i]].toList()));
264  }
265 
266  return r;
267  }
268 
269 private:
274  QMap<ElementType, QSet<ElementType> > m_elements;
275 };
276 
277 } // end namespace farsa
278 
279 #endif
This file contains the common type defitions used on the whole framework.
QList< ElementType > dependencies
The list of dependencies.
A structure containing an element and the list of its dependencies.
DependencySorter(const DependencySorter< ElementType > &other)
Copy constructor.
const QMap< ElementType, QSet< ElementType > > elements() const
Returns the list of elements and their dependencies.
ElementAndDepenciesList sortWithDependencies() const
Returns the sorted list of elements with dependencies.
A class to return data sorted by dependency.
ElementAndDepencies(ElementType e, QList< ElementType > d)
Constructor.
A macro to deprecate functions.
~DependencySorter()
Destructor.
DependencySorter & operator=(const DependencySorter< ElementType > &other)
Copy operator.
DependencySorter()
Constructor.
void add(ElementType e, QList< ElementType > d)
Adds an element with a list of dependencies.
void add(ElementType e, ElementType d)
Adds an element with a single dependency.
QList< ElementAndDepencies > ElementAndDepenciesList
The type for the list of elements and dependencies.
The exception thrown when DependencySorter finds a circular dependency.
ElementType_t ElementType
The type of elements used in the class.
QList< ElementType > sort() const
Returns the sorted list of elements.
void add(ElementType e, QSet< ElementType > d)
Adds an element with a list of dependencies.