Bridges-C++  3.1.1
Bridges(C++API)
GraphAdjList.h
Go to the documentation of this file.
1 #ifndef GRAPH_ADJ_LIST
2 #define GRAPH_ADJ_LIST
3 
4 #include <stdexcept>
5 #include <sstream>
6 #include <unordered_map>
7 #include <JSONutil.h>
8 
9 using namespace std;
10 
11 #include "SLelement.h"
12 #include "Edge.h"
13 
14 namespace bridges {
15  namespace datastructure {
33  template<typename K, typename E1 = K, typename E2 = E1>
34  class GraphAdjList : public DataStructure {
35  private:
36  // list of graph vertices
37  // maintained as a map to accommodate strings
38  unordered_map<K, Element<E1>* > vertices;
39  // adjacency lists
40  unordered_map<K, SLelement<Edge<K, E2> >*> adj_list;
41 
42  // large graph related
43  static const int LargeGraphVertSize = 2000;
44 
45  bool forceLargeViz = false;
46  bool forceSmallViz = false;
47 
48 
49  GraphAdjList(const GraphAdjList& gr) = delete; //would not be correct
50  const GraphAdjList& operator= (const GraphAdjList& gr) = delete; //would not be correct
51  public:
52 
53  GraphAdjList() = default;
54  GraphAdjList(GraphAdjList&& gr) = default;
55 
56  virtual ~GraphAdjList() override {
57  for (auto& v : vertices) {
58  if (adj_list[v.first]) {
59  // discard the edges in the adj. list
61  for (SLelement<Edge<K, E2>> *sle =
62  adj_list[v.first]; sle != nullptr; ) {
63  tmp = sle;
64  sle = sle->getNext();
65  delete tmp;
66  }
67  adj_list[v.first] = nullptr;
68  }
69  delete vertices[v.first]; // free the element at v
70  vertices[v.first] = nullptr;
71 
72  }
73  }
77  virtual const string getDStype() const override {
78  if (forceLargeViz || (!forceSmallViz &&
79  vertices.size() > LargeGraphVertSize &&
80  areAllVerticesLocated())) {
81  return "largegraph";
82  }
83  return "GraphAdjacencyList";
84  }
85 
96  void addVertex(const K& k, const E1& e = E1()) {
97  stringstream conv;
98  conv << k;
99  if (vertices.find(k) == vertices.end()) {
100  // vertex does not exist, create one
101  vertices[k] = new Element<E1>(e, conv.str());
102  adj_list[k] = nullptr;
103  }
104  }
119  void addEdge(const K& src, const K& dest, const E2& data = E2()) {
120  try {
121  vertices.at(src);
122  vertices.at(dest);
123  // links structure is redundant and needs
124  // to be removed in future implementations!
125  vertices[src]->links[vertices.at(dest)]; //In C++ this creates the linkvisualizer
126 
127  stringstream conv;
128  conv << dest;
129  // add the edge
130  adj_list.at(src) =
131  new SLelement<Edge<K, E2> > (adj_list.at(src),
132  Edge<K, E2> (src, dest, &(vertices[src]->links[vertices.at(dest)]), data), conv.str());
133 
134  }
135  catch ( const out_of_range& ) {
136  cerr << "addEdge(): Nonexistent vertex?" << endl <<
137  "Create vertices first prior to adding edges that use that vertex" << endl
138  << "Cannot add edge between non-existent verticies"
139  << endl;
140  throw;
141  }
142  }
150  const E1& getVertexData (const K& src)& {
151  try {
152  Element<E1> *el = vertices.at(src);
153  return (vertices.at(src))->getValue();
154  }
155  catch ( const out_of_range& ) {
156  cerr << "getVertexData(): vertex not found" << endl;
157  throw;
158  }
159  // should never reach here
160  throw "getVertexData(): vertex not found";
161  }
169  void setVertexData (const K& vertID, E1 const & data) {
170  try {
171  Element<E1> *el = vertices.at(vertID);
172  el->setValue (data);
173  }
174  catch ( const out_of_range& ) {
175  cerr << "setVertexData(): Nonexistent vertex" << endl;
176  throw;
177  }
178  catch (const char* msg) {
179  cerr << msg << endl;
180  }
181  }
190  E2& getEdgeData (const K& src, const K& dest) {
191  try {
192  vertices.at(src);
193  vertices.at(dest);
194  SLelement<Edge<K, E2> > *sle = adj_list.at(src);
195  while (sle) {
196  Edge<K, E2> ed = sle->getValue();
197  if (ed.getVertex() == dest) { //edge exists
198  return ed.getEdgeData();
199  }
200  sle = sle->getNext();
201  }
202  throw "Edge not found!";
203  }
204  catch ( const out_of_range& ) {
205  cerr << "getEdgeData(): Edge not found" << endl;
206  throw;
207  }
208  catch (const char* msg) {
209  cerr << msg << endl;
210  }
211  // should never reach here
212  throw "getEdgeData(): Edge not found";
213  }
222  E2 const& getEdgeData (const K& src, const K& dest) const {
223  try {
224  vertices.at(src);
225  vertices.at(dest);
226  SLelement<Edge<K, E2> > *sle = adj_list.at(src);
227  while (sle) {
228  Edge<K, E2> ed = sle->getValue();
229  if (ed.getVertex() == dest) { //edge exists
230  return ed.getEdgeData();
231  }
232  sle = sle->getNext();
233  }
234  throw "Edge not found!";
235  }
236  catch ( const out_of_range& ) {
237  cerr << "getEdgeData(): Edge not found" << endl;
238  throw;
239  }
240  catch (const char* msg) {
241  cerr << msg << endl;
242  }
243  // should never reach here
244  throw "getEdgeData(): Edge not found";
245  }
246 
247 
257  void setEdgeData (const K& src, const K& dest, E2& data) {
258  try {
259  vertices.at(src);
260  vertices.at(dest);
261  SLelement<Edge<K, E2> > *sle = adj_list.at(src);
262  while (sle) {
263  Edge<K, E2> ed = sle->getValue();
264  if (ed.getVertex() == dest) { //edge exists
265  ed.setEdgeData(data); //change edge data
266  sle->setValue(ed); //change slelement data
267  return;
268  }
269  sle = sle->getNext();
270  }
271  throw "getEdgeData(): Edge not found!";
272  }
273  catch ( const out_of_range& ) {
274  cerr << "setEdgeData(): Nonexistent vertices or " <<
275  " edge not found" << endl;
276  throw;
277  }
278  catch (const char* msg) {
279  cerr << msg << endl;
280  }
281  // will never reach here, but avoids compiler warnings
282  throw "getEdgeData(): Edge not found";
283  }
289  unordered_map<K, Element<E1>*>* getVertices() {
290  return &vertices;
291  }
292 
298  const unordered_map<K, Element<E1>*>* getVertices() const {
299  return &vertices;
300  }
305  const Element<E1>* getVertex(const K& key) const {
306  try {
307  return vertices.at(key);
308  }
309  catch (const std::out_of_range& oor) {
310  /* std::cerr << "Out of Range error: " << oor.what() */
311  /* << "returning null pointer\n"; */
312  return nullptr;
313  }
314  }
315 
316 
322  Element<E1>* getVertex(const K& key) {
323  try {
324  return vertices.at(key);
325  }
326  catch (const std::out_of_range& oor) {
327  /* std::cerr << "Out of Range error: " << oor.what() */
328  /* << "returning null pointer\n"; */
329  return nullptr;
330  }
331  }
332 
333 
338  const unordered_map<K, SLelement<Edge<K, E2> >*>&
340  return adj_list;
341  }
342 
352  try {
353  return adj_list.at(k);
354  }
355  catch (const out_of_range& ) {
356  cerr << "Cannot getAdjacencyList() of a non-existent vertex!"
357  << endl;
358  throw;
359  }
360  }
361 
370  const SLelement<Edge<K, E2> >* getAdjacencyList(const K& k) const {
371  try {
372  return adj_list.at(k);
373  }
374  catch (const out_of_range& ) {
375  cerr << "Cannot getAdjacencyList() of a non-existent vertex!"
376  << endl;
377  throw;
378  }
379  }
380 
381 
391  try {
392  Element<E1> *el = vertices.at(k);
393 
394  return el->getVisualizer();
395  }
396  catch (const out_of_range& ) {
397  cerr << "Graph vertex " << k << " not found in graph!" << endl;
398  throw;
399  }
400  }
410  LinkVisualizer *getLinkVisualizer (const K& k1, const K& k2) {
411  try {
412  Element<E1> *el1 = vertices.at(k1);
413  Element<E1> *el2 = vertices.at(k2);
414 
415  return el1->getLinkVisualizer(el2);
416  }
417  catch (const out_of_range& ) {
418  cerr << "Either source or destination node not found in graph!"
419  << endl;
420  throw;
421  }
422  }
423  private:
429  virtual const string getDataStructureRepresentation() const override {
431 
432  // map the nodes to a sequence of ids, 0...N-1
433  // then get the JSON string for nodes placeholder
434  // nullptr prevents insertion of other nullptrs
435 
436  // check for large graph
437  if (forceLargeViz ||
438  (!forceSmallViz &&
439  vertices.size() > LargeGraphVertSize &&
440  areAllVerticesLocated())) {
441  return getDataStructureRepresentationLargeGraph();
442  }
443 
444  unordered_map<K, int> node_map;
445  int i = 0;
446  string nodes_JSON = "", links_JSON = "";
447 
448  for (const auto& v : vertices) {
449  if (node_map.emplace(v.first, i).second) {
450  i++;
451  nodes_JSON += v.second->getElementRepresentation() + COMMA;
452  }
453  }
454 
455  //Remove trailing comma and nullptr entry
456 
457  if (nodes_JSON.size()) {
458  nodes_JSON = nodes_JSON.erase(nodes_JSON.size() - 1);
459  }
460 
461  // iterate through the vertices and form the links JSON
462 
463  for (const auto& v : vertices) {
464  // get adj. list
465  Element<E1>* src_vert = vertices.at(v.first);
466  // iterate through list and form links
467  for (SLelement<Edge<K, E2>>* it = adj_list.at(v.first); it != nullptr;
468  it = it->getNext()) {
469  Element<E1>* dest_vert = vertices.at(it->getValue().to() );
470  links_JSON += src_vert->getLinkRepresentation(
471  *(src_vert->getLinkVisualizer(dest_vert)),
472  JSONencode(node_map.at(v.first)),
473  JSONencode(node_map.at(it->getValue().to())) ) + COMMA;
474  }
475  }
476 
477  //Remove trailing comma
478  if (links_JSON.size()) {
479  links_JSON = links_JSON.erase(links_JSON.size() - 1);
480  }
481 
482  string graph_alist_json =
483  QUOTE + "nodes" + QUOTE + COLON +
484  OPEN_BOX + nodes_JSON + CLOSE_BOX + COMMA +
485  QUOTE + "links" + QUOTE + COLON + OPEN_BOX +
486  links_JSON + CLOSE_BOX +
487  CLOSE_CURLY;
488 
489 
490  return graph_alist_json;
491  }
502  string getDataStructureRepresentationLargeGraph () const {
503 
505  // map the nodes to a sequence of ids, 0...N-1
506  // then get the JSON string for nodes placeholder
507  // nullptr prevents insertion of other nullptrs
508 
509  unordered_map<K, int> node_map;
510  int i = 0;
511  string nodes_JSON = "";
512 
513  for (const auto& v : vertices) {
514  if (node_map.emplace(v.first, i).second) {
515  i++;
516  const ElementVisualizer *elvis =
517  vertices.at(v.first)->getVisualizer();
518  string loc_str = "";
519  if ( (elvis->getLocationX() != INFINITY) &&
520  (elvis->getLocationY() != INFINITY) ) {
521  loc_str =
522  OPEN_BOX +
523  JSONencode(elvis->getLocationX()) + COMMA +
524  JSONencode(elvis->getLocationY()) +
525  CLOSE_BOX + COMMA;
526  }
527  nodes_JSON += OPEN_BOX + loc_str +
528  elvis->getColor().getCSSRepresentation() +
529  CLOSE_BOX + COMMA;
530  }
531  }
532 
533  //Remove trailing comma and nullptr entry
534 
535  if (nodes_JSON.size()) {
536  nodes_JSON = nodes_JSON.erase(nodes_JSON.size() - 1);
537  }
538 
539  // next link information
540  string links_JSON = "";
541  for (const auto& v : vertices) {
542  // get adj. list
543  Element<E1>* src_vert = vertices.at(v.first);
544  // iterate through list and form links
545  for (SLelement<Edge<K, E2>>* it = adj_list.at(v.first); it != nullptr;
546  it = it->getNext()) {
547  Element<E1>* dest_vert = vertices.at(it->getValue().to() );
548  LinkVisualizer *lv = src_vert->getLinkVisualizer(dest_vert);
549  string src = JSONencode(node_map.at(v.first));
550  string dest = JSONencode(node_map.at(it->getValue().to()));
551  links_JSON += OPEN_BOX +
552  src + COMMA +
553  dest + COMMA +
555  CLOSE_BOX + COMMA;
556 
557  }
558  }
559  //Remove trailing comma
560  if (links_JSON.size())
561  links_JSON = links_JSON.erase(links_JSON.size() - 1);
562 
563  string graph_alist_json =
564  QUOTE + "nodes" + QUOTE + COLON +
565  OPEN_BOX + nodes_JSON + CLOSE_BOX + COMMA +
566  QUOTE + "links" + QUOTE + COLON +
567  OPEN_BOX + links_JSON + CLOSE_BOX +
568  CLOSE_CURLY;
569 
570  return graph_alist_json;
571 
572  }
576  bool areAllVerticesLocated() const {
577  for (const auto& v : vertices) {
578  ElementVisualizer *elvis = v.second->getVisualizer();
579  if (elvis->getLocationX() == INFINITY
580  || elvis->getLocationY() == INFINITY)
581  return false;
582  }
583  return true;
584  }
585 
586 
587  public:
588 
589  void forceLargeVisualization(bool f) {
590  if (f) {
591  forceLargeViz = true;
592  forceSmallViz = false;
593  }
594  else {
595  forceLargeViz = false;
596  }
597  }
598 
599  void forceSmallVisualization(bool f) {
600  if (f) {
601  forceSmallViz = true;
602  forceLargeViz = false;
603  }
604  else {
605  forceSmallViz = false;
606  }
607  }
608 
611  std::unordered_map<K, Element<E1>* > const & underlying_map;
612 
613  public:
614  KeySet_helper (std::unordered_map<K, Element<E1>* > const & um)
615  : underlying_map(um)
616  {}
617 
619  typename std::unordered_map<K, Element<E1>* >::const_iterator it;
620  public:
621  const_iterator(typename std::unordered_map<K, Element<E1>* >::const_iterator i )
622  : it(i)
623  {}
624 
625  bool operator!=(const const_iterator& it) const {
626  return this->it != it.it;
627  }
628 
629  const K& operator*() const {
630  return it->first;
631  }
632 
634  it ++;
635  return *this;
636  }
637  };
638 
640  return const_iterator(underlying_map.begin());
641  }
642 
643  const_iterator end() const {
644  return const_iterator(underlying_map.end());
645  }
646  };
647 
651  return KeySet_helper(this->vertices);
652  }
653 
654  typename SLelement<Edge<K, E2>>::SLelement_listhelper outgoingEdgeSetOf(K const & k) {
655  return typename SLelement<Edge<K, E2>>::SLelement_listhelper(getAdjacencyList(k));
656  }
657 
658  typename SLelement<Edge<K, E2>>::SLelement_constlisthelper outgoingEdgeSetOf(K const & k) const {
659  return typename SLelement<Edge<K, E2>>::SLelement_constlisthelper(getAdjacencyList(k));
660  }
661 
662 
665  typename std::unordered_map<K, Element<E1>* > & underlying_map;
666 
667  public:
668  VertexElementSet_listhelper (std::unordered_map<K, Element<E1>* > & um)
669  : underlying_map(um)
670  {}
671 
673  class iterator {
674  typename std::unordered_map<K, Element<E1>* >::iterator it;
675  public:
676  iterator(typename std::unordered_map<K, Element<E1>* >::iterator i )
677  : it(i)
678  {}
679 
680  bool operator!=(const iterator& it) const {
681  return this->it != it.it;
682  }
683 
685  return it->second;
686  }
687 
689  it ++;
690  return *this;
691  }
692  };
693 
696  typename std::unordered_map<K, Element<E1>* >::const_iterator it;
697  public:
698  const_iterator(typename std::unordered_map<K, Element<E1>* >::const_iterator i )
699  : it(i)
700  {}
701 
702  bool operator!=(const const_iterator& it) const {
703  return this->it != it.it;
704  }
705 
706  Element<E1> const* operator*() const {
707  return it->second;
708  }
709 
711  it ++;
712  return *this;
713  }
714  };
715 
716 
718  return iterator(underlying_map.begin());
719  }
720 
722  return iterator(underlying_map.end());
723  }
724 
726  return const_iterator(underlying_map.begin());
727  }
728 
729  const_iterator end() const {
730  return const_iterator(underlying_map.end());
731  }
732 
733  };
734 
737  return VertexElementSet_listhelper(vertices);
738  }
739 
740 
743  typename std::unordered_map<K, Element<E1>* > const & underlying_map;
744 
745  public:
746  constVertexElementSet_listhelper (std::unordered_map<K, Element<E1>* > const& um)
747  : underlying_map(um)
748  {}
749 
752  typename std::unordered_map<K, Element<E1>* >::const_iterator it;
753  public:
754  const_iterator(typename std::unordered_map<K, Element<E1>* >::const_iterator i )
755  : it(i)
756  {}
757 
758  bool operator!=(const const_iterator& it) const {
759  return this->it != it.it;
760  }
761 
762  Element<E1> const* operator*() const {
763  return it->second;
764  }
765 
767  it ++;
768  return *this;
769  }
770  };
771 
773  return const_iterator(underlying_map.begin());
774  }
775 
776  const_iterator end() const {
777  return const_iterator(underlying_map.begin());
778  }
779  };
782  return constVertexElementSet_listhelper(vertices);
783  }
784  };
785 
786  //end of GraphAdjList class
787  }
788 }//end of bridges namespace
789 #endif
VertexElementSet_listhelper vertexSet()
returns a set of vertices (Element<E>) that conforms to STL list interface. That means we can use ran...
Definition: GraphAdjList.h:736
void forceSmallVisualization(bool f)
Definition: GraphAdjList.h:599
This is a helper class to return sets of vertices in a way that are iterable with range for loops...
Definition: GraphAdjList.h:673
double getLocationY() const
Definition: ElementVisualizer.h:153
double getLocationX() const
Definition: ElementVisualizer.h:147
void setValue(const E &val)
Definition: Element.h:212
static const string getLinkRepresentation(const LinkVisualizer &lv, const string &src, const string &dest)
Definition: Element.h:256
This is a helper class to return sets of vertices ina way that are iterable with range for loops...
Definition: GraphAdjList.h:751
void setEdgeData(const E2 &data)
Definition: Edge.h:89
ElementVisualizer * getVisualizer(const K &k)
Definition: GraphAdjList.h:390
bool operator!=(const const_iterator &it) const
Definition: GraphAdjList.h:702
E2 & getEdgeData(const K &src, const K &dest)
Definition: GraphAdjList.h:190
SLelement< Edge< K, E2 > > * getAdjacencyList(const K &k)
Definition: GraphAdjList.h:351
const string COLON
Definition: DataStructure.h:51
STL namespace.
E const & getValue() const
Definition: Element.h:195
iterator(typename std::unordered_map< K, Element< E1 > * >::iterator i)
Definition: GraphAdjList.h:676
constVertexElementSet_listhelper(std::unordered_map< K, Element< E1 > * > const &um)
Definition: GraphAdjList.h:746
SLelement< Edge< K, E2 > >::SLelement_listhelper outgoingEdgeSetOf(K const &k)
Definition: GraphAdjList.h:654
This class maintains the visual properties of the a Bridges element.
Definition: ElementVisualizer.h:28
const string OPEN_BOX
Definition: DataStructure.h:54
const_iterator end() const
Definition: GraphAdjList.h:776
Element< E1 > const * operator*() const
Definition: GraphAdjList.h:706
const_iterator(typename std::unordered_map< K, Element< E1 > * >::const_iterator i)
Definition: GraphAdjList.h:754
const_iterator begin() const
Definition: GraphAdjList.h:639
const_iterator(typename std::unordered_map< K, Element< E1 > * >::const_iterator i)
Definition: GraphAdjList.h:698
const string CLOSE_CURLY
Definition: DataStructure.h:53
This is a helper class to return sets of vertices ina way that are iterable with range for loops...
Definition: GraphAdjList.h:610
const Element< E1 > * getVertex(const K &key) const
Definition: GraphAdjList.h:305
const E1 & getVertexData(const K &src) &
Definition: GraphAdjList.h:150
const_iterator end() const
Definition: GraphAdjList.h:643
Element< E1 > * getVertex(const K &key)
Definition: GraphAdjList.h:322
The singly linked list element, derived from Element.
Definition: SLelement.h:27
This is a helper class to return sets of vertices in a way that are iterable with range for loops...
Definition: GraphAdjList.h:695
const_iterator end() const
Definition: GraphAdjList.h:729
void forceLargeVisualization(bool f)
Definition: GraphAdjList.h:589
void addVertex(const K &k, const E1 &e=E1())
Definition: GraphAdjList.h:96
const_iterator(typename std::unordered_map< K, Element< E1 > * >::const_iterator i)
Definition: GraphAdjList.h:621
bool operator!=(const iterator &it) const
Definition: GraphAdjList.h:680
these methods convert byte arrays in to base64 codes and are used in BRIDGES to represent the color a...
Definition: alltypes.h:4
const_iterator begin() const
Definition: GraphAdjList.h:772
virtual const string getDStype() const override
Definition: GraphAdjList.h:77
const string CLOSE_BOX
Definition: DataStructure.h:55
bool operator!=(const const_iterator &it) const
Definition: GraphAdjList.h:758
const E2 & getEdgeData() const
Definition: Edge.h:97
const string getCSSRepresentation() const
Definition: Color.h:404
bool operator!=(const const_iterator &it) const
Definition: GraphAdjList.h:625
This is a helper class to return sets of vertices ina way that are iterable with range for loops...
Definition: GraphAdjList.h:742
const_iterator begin() const
Definition: GraphAdjList.h:725
KeySet_helper(std::unordered_map< K, Element< E1 > * > const &um)
Definition: GraphAdjList.h:614
unordered_map< K, Element< E1 > * > * getVertices()
Definition: GraphAdjList.h:289
constVertexElementSet_listhelper vertexSet() const
returns a set of vertices (Element<E>) that conforms to STL list interface. That means we can use ran...
Definition: GraphAdjList.h:781
const_iterator & operator++()
Definition: GraphAdjList.h:633
void setVertexData(const K &vertID, E1 const &data)
Definition: GraphAdjList.h:169
virtual SLelement * getNext()
Definition: SLelement.h:70
const unordered_map< K, Element< E1 > * > * getVertices() const
Definition: GraphAdjList.h:298
const K & operator*() const
Definition: GraphAdjList.h:629
This is a helper class to return sets of vertices in a way that are iterable with range for loops...
Definition: GraphAdjList.h:664
Element< E1 > const * operator*() const
Definition: GraphAdjList.h:762
const SLelement< Edge< K, E2 > > * getAdjacencyList(const K &k) const
Definition: GraphAdjList.h:370
VertexElementSet_listhelper(std::unordered_map< K, Element< E1 > * > &um)
Definition: GraphAdjList.h:668
KeySet_helper keySet() const
Definition: GraphAdjList.h:650
Color getColor() const
Definition: ElementVisualizer.h:95
virtual ~GraphAdjList() override
Definition: GraphAdjList.h:56
ElementVisualizer * getVisualizer()
Definition: Element.h:136
const string COMMA
Definition: DataStructure.h:50
const string QUOTE
Definition: DataStructure.h:49
const unordered_map< K, SLelement< Edge< K, E2 > > * > & getAdjacencyList() const
Definition: GraphAdjList.h:339
LinkVisualizer * getLinkVisualizer(const K &k1, const K &k2)
Definition: GraphAdjList.h:410
SLelement< Edge< K, E2 > >::SLelement_constlisthelper outgoingEdgeSetOf(K const &k) const
Definition: GraphAdjList.h:658
E2 const & getEdgeData(const K &src, const K &dest) const
Definition: GraphAdjList.h:222
void addEdge(const K &src, const K &dest, const E2 &data=E2())
add an edge with data.
Definition: GraphAdjList.h:119
This helper class is used by the graph classes - GraphAdjList , GraphAdjMatrix - to keep track of edg...
Definition: Edge.h:34
void setEdgeData(const K &src, const K &dest, E2 &data)
Definition: GraphAdjList.h:257
std::string JSONencode(const T &d)
Definition: JSONutil.h:37
LinkVisualizer * getLinkVisualizer(const Element *el)
Definition: Element.h:154