My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
nodelist.cpp
Go to the documentation of this file.
1 /*
2  * nodelist.cpp - node list class implementation
3  *
4  * Copyright (C) 2003, 2004, 2006, 2008 Stefan Jahn <stefan@lkcc.org>
5  *
6  * This is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This software is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this package; see the file COPYING. If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  * $Id: nodelist.cpp 1825 2011-03-11 20:42:14Z ela $
22  *
23  */
24 
25 #if HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33 
34 #include "logging.h"
35 #include "object.h"
36 #include "node.h"
37 #include "complex.h"
38 #include "circuit.h"
39 #include "net.h"
40 #include "nodelist.h"
41 
42 // Constructor creates an instance of the nodelist class.
44  root = last = NULL;
45  narray = NULL;
46  txt = NULL;
47  sorting = 0;
48 }
49 
50 /* The function creates a nodelist for the given netlist. The
51  nodelist is based on the circuit list and consists of unique nodes
52  inside the circuit list only. Each node in the list has references
53  to their actual circuit nodes and thereby to the circuits it is
54  connected to. */
55 nodelist::nodelist (net * subnet) {
56  root = last = NULL;
57  narray = NULL;
58  txt = NULL;
59  sorting = 0;
60 
61  circuit * c;
62  // go through circuit list and find unique nodes
63  for (c = subnet->getRoot (); c != NULL; c = (circuit *) c->getNext ()) {
64  for (int i = 0; i < c->getSize (); i++) {
65  node * n = c->getNode (i);
66  if (contains (n->getName ()) == 0) {
67  add (n->getName (), n->getInternal ());
68  }
69  }
70  }
71  // add circuit nodes to each unique node in the list
72  for (struct nodelist_t * n = getRoot (); n != NULL; n = n->next) {
73  for (c = subnet->getRoot (); c != NULL; c = (circuit *) c->getNext ()) {
74  for (int i = 0; i < c->getSize (); i++) {
75  assert (n->name != NULL);
76  assert (c->getNode(i)->getName () != NULL);
77  if (!strcmp (n->name, c->getNode(i)->getName ())) {
78  addCircuitNode (n, c->getNode (i));
79  }
80  }
81  }
82  }
83 }
84 
85 /* This copy constructor creates a instance of the nodelist class
86  based on the given nodelist. */
88  struct nodelist_t * n;
89  root = last = NULL;
90  narray = NULL;
91  for (n = o.root; n != NULL; n = n->next) append (copy (n));
92  txt = o.txt ? strdup (o.txt) : NULL;
93  sorting = o.sorting;
94 }
95 
96 // Destructor deletes an instance of the nodelist class.
98  struct nodelist_t * next;
99  while (root) {
100  next = root->next;
101  release (root);
102  root = next;
103  }
104  if (txt) free (txt);
105  if (narray) free (narray);
106 }
107 
108 // The function copies the given node with all its properties.
109 struct nodelist_t * nodelist::copy (struct nodelist_t * n) {
110  struct nodelist_t * copy = create (n->name, n->internal);
111  copy->n = n->n;
112  copy->nNodes = n->nNodes;
113  copy->nAlloc = n->nAlloc;
114  if (copy->nAlloc) {
115  copy->nodes = (node **) malloc (sizeof (node *) * n->nAlloc);
116  if (copy->nNodes) {
117  memcpy (copy->nodes, n->nodes, sizeof (node *) * n->nNodes);
118  }
119  }
120  return copy;
121 }
122 
123 // This function adds a node name to the list and saves the internal flag.
124 void nodelist::add (char * str, int intern) {
125  add (create (str, intern));
126 }
127 
128 // The function creates a node based upon the given arguments.
129 struct nodelist_t * nodelist::create (char * str, int intern) {
130  struct nodelist_t * n;
131  n = (struct nodelist_t *) calloc (sizeof (struct nodelist_t), 1);
132  n->internal = intern;
133  n->name = str ? strdup (str) : NULL;
134  return n;
135 }
136 
137 // This function adds a node to the list.
138 void nodelist::add (struct nodelist_t * n) {
139  n->next = root;
140  if (root == NULL) last = n;
141  root = n;
142 }
143 
144 // This function appends a node name to the list.
145 void nodelist::append (char * str, int intern) {
146  append (create (str, intern));
147 }
148 
149 // This function appends the given node to the list.
150 void nodelist::append (struct nodelist_t * n) {
151  n->next = NULL;
152  if (root)
153  last->next = n;
154  else
155  root = n;
156  last = n;
157 }
158 
159 // This function removes the node with the given name from the list.
160 void nodelist::remove (char * name) {
161  remove (getNode (name));
162 }
163 
164 // The function removes the given node from the list.
165 void nodelist::remove (struct nodelist_t * del, int keep) {
166  struct nodelist_t * prev, * n;
167  // go through the list
168  for (prev = NULL, n = root; n != NULL; prev = n, n = n->next) {
169  if (n == del) {
170  // adjust the chain properly
171  if (prev == NULL)
172  root = n->next;
173  else
174  prev->next = n->next;
175  if (n == last) last = prev;
176  // delete node if requested and return
177  if (!keep) release (n);
178  return;
179  }
180  }
181 }
182 
183 // This function free()'s the given node.
184 void nodelist::release (struct nodelist_t * n) {
185  if (n->name) free (n->name);
186  if (n->nodes) free (n->nodes);
187  free (n);
188 }
189 
190 // This function counts the node names in the list.
191 int nodelist::length (void) {
192  int res = 0;
193  for (struct nodelist_t * n = root; n != NULL; n = n->next) res++;
194  return res;
195 }
196 
197 // This function finds the specified node name in the list.
198 int nodelist::contains (char * str) {
199  int res = 0;
200  for (struct nodelist_t * n = root; n != NULL; n = n->next) {
201  if (n->name != NULL && str != NULL && !strcmp (n->name, str))
202  res++;
203  }
204  return res;
205 }
206 
207 // Returns the node number of the give node name.
208 int nodelist::getNodeNr (char * str) {
209  for (struct nodelist_t * n = root; n != NULL; n = n->next) {
210  if (n->name != NULL && str != NULL && !strcmp (n->name, str))
211  return n->n;
212  }
213  return -1;
214 }
215 
216 /* This function returns the node name positioned at the specified
217  location in the node name list. */
218 char * nodelist::get (int nr) {
219  return narray[nr + 1]->name;
220 }
221 
222 /* This function returns non-zero if the node positioned at the
223  specified location in the node name list is marked internal and
224  zero otherwise. */
225 int nodelist::isInternal (int nr) {
226  return narray[nr + 1]->internal;
227 }
228 
229 /* The function returns the nodelist structure at the specified
230  location in the node name list. */
231 struct nodelist_t * nodelist::getNode (int nr) {
232  return narray[nr + 1];
233 }
234 
235 /* The function returns the nodelist structure with the given name in
236  the node name list. It returns NULL if there is no such node. */
237 struct nodelist_t * nodelist::getNode (char * name) {
238  for (struct nodelist_t * n = root; n != NULL; n = n->next)
239  if (!strcmp (name, n->name)) return n;
240  return NULL;
241 }
242 
243 /* Returns a comma separated list of the circuits connected to the
244  node specified by the given number. */
245 char * nodelist::getNodeString (int nr) {
246  if (txt) free (txt); txt = NULL;
247  // find the specified node
248  struct nodelist_t * n = getNode (nr);
249  // append circuit names connected to the node
250  int len = (n->nNodes - 1) + 1;
251  txt = (char *) malloc (len); txt[0] = '\0';
252  for (int i = 0; i < n->nNodes; i++) {
253  char * str = n->nodes[i]->getCircuit()->getName ();
254  len += strlen (str);
255  txt = (char *) realloc (txt, len);
256  strcat (txt, str);
257  if (i != n->nNodes - 1) strcat (txt, ",");
258  }
259  return txt;
260 }
261 
262 /* The function returns the nodelist structure at the end of the node
263  name list. */
265  return last;
266 }
267 
268 // This function enumerates the nodes in the node name list.
270  int i = 1;
271 
272  // create fast array access possibility
273  if (narray) free (narray);
274  narray = (struct nodelist_t **)
275  malloc (sizeof (struct nodelist_t *) * length ());
276 
277  for (struct nodelist_t * n = root; n != NULL; n = n->next) {
278  // ground node gets a zero counter
279  if (!strcmp (n->name, "gnd")) {
280  n->n = 0;
281  narray[0] = n;
282  }
283  // others get a unique number greater than zero
284  else {
285  narray[i] = n;
286  n->n = i++;
287  }
288  }
289 }
290 
291 /* The function appends a node pointer to the given nodelist
292  structure. */
293 void nodelist::addCircuitNode (struct nodelist_t * nl, node * n) {
294  if (nl->nNodes >= nl->nAlloc) { // ensure capacity
295  if (nl->nAlloc == 0) {
296  nl->nAlloc = 2;
297  nl->nodes = (node **) malloc (sizeof (node *) * nl->nAlloc);
298  }
299  else {
300  nl->nAlloc *= 2;
301  nl->nodes = (node **) realloc (nl->nodes, sizeof (node *) * nl->nAlloc);
302  }
303  }
304  nl->nodes[nl->nNodes++] = n;
305  if (n->getInternal ()) nl->internal = n->getInternal ();
306 }
307 
308 /* This function deletes the given node from the nodelist
309  structure. */
310 void nodelist::delCircuitNode (struct nodelist_t * nl, node * n) {
311  assert (nl->nNodes > 0);
312  if (nl->nNodes > 1) {
313  int i, j;
314  // copy nodelist except the given one
315  for (j = i = 0; j < nl->nNodes - 1; i++, j++) {
316  if (nl->nodes[i] == n) i++;
317  nl->nodes[j] = nl->nodes[i];
318  }
319  }
320  else {
321  // no more nodes in the list
322  free (nl->nodes);
323  nl->nodes = NULL;
324  nl->nAlloc = 0;
325  }
326  nl->nNodes--;
327 }
328 
329 /* This function is used as sorting criteria for the S-parameter
330  analysis. It returns the number of nodes a join of the two
331  circuits connected to the given node would yield. */
332 static int sortfunc (struct nodelist_t * n) {
333  int p;
334  circuit * c1 = n->nodes[0]->getCircuit ();
335  circuit * c2 = n->nNodes > 1 ? n->nodes[1]->getCircuit () : NULL;
336  if (c1->getPort () || (c2 && c2->getPort ())) return -1;
337  if (c1 == c2) { // interconnect
338  p = c1->getSize () - 2;
339  } else { // connect
340  p = c1->getSize () + (c2 ? c2->getSize () - 2 : 0);
341  }
342  return p;
343 }
344 
345 /* The function evaluates the sorting criteria of the given two nodes.
346  It returns non-zero if 'n1' should be inserted before 'n2'. */
347 static int insfunc (struct nodelist_t * n1, struct nodelist_t * n2) {
348  int p1 = sortfunc (n1);
349  int p2 = sortfunc (n2);
350  return p1 >= 0 && (p1 <= p2 || p2 < 0);
351 }
352 
353 /* The function inserts the given node structure into the node list.
354  If the nodelist is sorted then the node gets inserted at a certain
355  position. */
356 void nodelist::insert (struct nodelist_t * n) {
357  // first node at all
358  if (root == NULL) {
359  last = root = n;
360  return;
361  }
362 
363  // sorted node list
364  if (sorting) {
365  int added = 0;
366  struct nodelist_t * nl, * prev;
367  for (prev = NULL, nl = root; nl != NULL; prev = nl, nl = nl->next) {
368  if (insfunc (n, nl)) {
369  if (prev == NULL) {
370  n->next = root;
371  root = n;
372  } else {
373  n->next = nl;
374  prev->next = n;
375  }
376  added++;
377  break;
378  }
379  }
380  if (!added) append (n);
381  return;
382  }
383 
384  // unsorted node list
385  add (n);
386 }
387 
388 /* This function removes the nodes associated with the given circuit
389  from the node list. If the node list is sorted then the order gets
390  rearranged properly. */
392  // go through each node of the circuit
393  for (int i = 0; i < c->getSize (); i++) {
394  node * n = c->getNode (i);
395  struct nodelist_t * nl;
396  if ((nl = getNode (n->getName ())) != NULL) {
397  // remove node from node structure
398  delCircuitNode (nl, n);
399  if (nl->nNodes <= 0) {
400  // completely remove the node structure
401  remove (nl);
402  }
403  else if (sorting && sortfunc (nl) > 0) {
404  // rearrange sorting
405  remove (nl, 1);
406  insert (nl);
407  }
408  }
409  }
410 }
411 
412 /* The following function can be used to insert a new circuit to the
413  node list. It goes through each node of the circuit and rearranges
414  the node list appropriately. */
416  // go through each node of the circuit
417  for (int i = 0; i < c->getSize (); i++) {
418  struct nodelist_t * nl;
419  node * n = c->getNode (i);
420  // is this node already in the nodelist?
421  if (contains (n->getName ()) == 0) {
422  // no, create new node and put it into the list
423  nl = create (n->getName (), n->getInternal ());
424  addCircuitNode (nl, n);
425  if (sorting) {
426  if (c->getPort ())
427  append (nl);
428  else
429  insert (nl);
430  }
431  else add (nl);
432  }
433  else {
434  // yes, put additional node into nodelist structure
435  if ((nl = getNode (n->getName ())) != NULL) {
436  addCircuitNode (nl, n);
437  if (sorting && sortfunc (nl) > 0) {
438  // rearrange sorting
439  remove (nl, 1);
440  insert (nl);
441  }
442  }
443  }
444  }
445 }
446 
447 /* The function completely rebuilds the nodelist. Once sort()'ed it
448  keeps being sorted when removing or inserting new circuits. */
449 void nodelist::sort (void) {
450  nodelist * nodes = new nodelist ();
451  struct nodelist_t * nl, * cand;
452  int p, i, ports, MaxPorts, len = length ();
453 
454  // go through the list until there is no node left
455  for (i = 0; i < len; i++) {
456  // find last order node
457  cand = NULL;
458  for (MaxPorts = -1, p = 0, nl = root; nl != NULL; nl = nl->next) {
459  ports = sortfunc (nl);
460  if (ports > MaxPorts || MaxPorts < 0 || ports == -1) {
461  cand = nl;
462  MaxPorts = ports;
463  }
464  if (ports == -1) break;
465  }
466  // add last order node
467  remove (cand, 1);
468  nodes->add (cand);
469  }
470 
471  // store sorted node list in current object
472  root = nodes->getRoot ();
473  last = nodes->getLastNode ();
474  nodes->root = NULL;
475  sorting = 1;
476 
477  // delete temporary node list
478  delete nodes;
479 }
480 
481 // The function returns the first two nodes of the sorted list.
482 void nodelist::sortedNodes (node ** node1, node ** node2) {
483  assert (root->nNodes == 2);
484  *node1 = root->nodes[0];
485  *node2 = root->nodes[1];
486 }
487 
488 #if DEBUG
489 // Debug function: Prints the entire nodelist.
490 void nodelist::print (void) {
491  for (struct nodelist_t * n = root; n != NULL; n = n->next) {
492  logprint (LOG_STATUS, "DEBUG: node %s-%d [", n->name, n->n);
493  for (int i = 0; i < n->nNodes; i++) {
494  logprint (LOG_STATUS, "%s", n->nodes[i]->getCircuit()->getName ());
495  if (i != n->nNodes - 1) logprint (LOG_STATUS, ",");
496  }
497  logprint (LOG_STATUS, "]\n");
498  }
499 }
500 #endif /* DEBUG */