| 1 | /* $Id$ $Revision$ */ |
| 2 | /* vim:set shiftwidth=4 ts=8: */ |
| 3 | |
| 4 | /************************************************************************* |
| 5 | * Copyright (c) 2011 AT&T Intellectual Property |
| 6 | * All rights reserved. This program and the accompanying materials |
| 7 | * are made available under the terms of the Eclipse Public License v1.0 |
| 8 | * which accompanies this distribution, and is available at |
| 9 | * http://www.eclipse.org/legal/epl-v10.html |
| 10 | * |
| 11 | * Contributors: See CVS logs. Details at http://www.graphviz.org/ |
| 12 | *************************************************************************/ |
| 13 | |
| 14 | #ifndef ATT_GRAPH_H |
| 15 | #define ATT_GRAPH_H |
| 16 | |
| 17 | #include <inttypes.h> |
| 18 | #include "cdt.h" |
| 19 | |
| 20 | #ifdef __cplusplus |
| 21 | extern "C" { |
| 22 | #endif |
| 23 | |
| 24 | #ifdef _WIN32 |
| 25 | # ifdef EXPORT_CGRAPH |
| 26 | # define CGRAPH_API __declspec(dllexport) |
| 27 | # else |
| 28 | # define CGRAPH_API __declspec(dllimport) |
| 29 | # endif |
| 30 | #else |
| 31 | # define CGRAPH_API extern |
| 32 | #endif |
| 33 | |
| 34 | #ifndef FALSE |
| 35 | #define FALSE (0) |
| 36 | #endif |
| 37 | #ifndef TRUE |
| 38 | #define TRUE (!FALSE) |
| 39 | #endif |
| 40 | #ifndef NOT |
| 41 | #define NOT(x) (!(x)) |
| 42 | #endif |
| 43 | #ifndef NIL |
| 44 | #define NIL(type) ((type)0) |
| 45 | #endif |
| 46 | #define NILgraph NIL(Agraph_t*) |
| 47 | #define NILnode NIL(Agnode_t*) |
| 48 | #define NILedge NIL(Agedge_t*) |
| 49 | #define NILsym NIL(Agsym_t*) |
| 50 | |
| 51 | typedef uint64_t IDTYPE; |
| 52 | |
| 53 | /* forward struct type declarations */ |
| 54 | typedef struct Agtag_s Agtag_t; |
| 55 | typedef struct Agobj_s Agobj_t; /* generic object header */ |
| 56 | typedef struct Agraph_s Agraph_t; /* graph, subgraph (or hyperedge) */ |
| 57 | typedef struct Agnode_s Agnode_t; /* node (atom) */ |
| 58 | typedef struct Agedge_s Agedge_t; /* node pair */ |
| 59 | typedef struct Agdesc_s Agdesc_t; /* graph descriptor */ |
| 60 | typedef struct Agmemdisc_s Agmemdisc_t; /* memory allocator */ |
| 61 | typedef struct Agiddisc_s Agiddisc_t; /* object ID allocator */ |
| 62 | typedef struct Agiodisc_s Agiodisc_t; /* IO services */ |
| 63 | typedef struct Agdisc_s Agdisc_t; /* union of client discipline methods */ |
| 64 | typedef struct Agdstate_s Agdstate_t; /* client state (closures) */ |
| 65 | typedef struct Agsym_s Agsym_t; /* string attribute descriptors */ |
| 66 | typedef struct Agattr_s Agattr_t; /* string attribute container */ |
| 67 | typedef struct Agcbdisc_s Agcbdisc_t; /* client event callbacks */ |
| 68 | typedef struct Agcbstack_s Agcbstack_t; /* enclosing state for cbdisc */ |
| 69 | typedef struct Agclos_s Agclos_t; /* common fields for graph/subgs */ |
| 70 | typedef struct Agrec_s Agrec_t; /* generic runtime record */ |
| 71 | typedef struct Agdatadict_s Agdatadict_t; /* set of dictionaries per graph */ |
| 72 | typedef struct Agedgepair_s Agedgepair_t; /* the edge object */ |
| 73 | typedef struct Agsubnode_s Agsubnode_t; |
| 74 | |
| 75 | /* Header of a user record. These records are attached by client programs |
| 76 | dynamically at runtime. A unique string ID must be given to each record |
| 77 | attached to the same object. Cgraph has functions to create, search for, |
| 78 | and delete these records. The records are maintained in a circular list, |
| 79 | with obj->data pointing somewhere in the list. The search function has |
| 80 | an option to lock this pointer on a given record. The application must |
| 81 | be written so only one such lock is outstanding at a time. */ |
| 82 | |
| 83 | struct Agrec_s { |
| 84 | char *name; |
| 85 | Agrec_t *next; |
| 86 | /* following this would be any programmer-defined data */ |
| 87 | }; |
| 88 | |
| 89 | /* Object tag for graphs, nodes, and edges. While there may be several structs |
| 90 | for a given node or edges, there is only one unique ID (per main graph). */ |
| 91 | struct Agtag_s { |
| 92 | unsigned objtype:2; /* see literal tags below */ |
| 93 | unsigned mtflock:1; /* move-to-front lock, see above */ |
| 94 | unsigned attrwf:1; /* attrs written (parity, write.c) */ |
| 95 | unsigned seq:(sizeof(unsigned) * 8 - 4); /* sequence no. */ |
| 96 | IDTYPE id; /* client ID */ |
| 97 | }; |
| 98 | |
| 99 | /* object tags */ |
| 100 | #define AGRAPH 0 /* can't exceed 2 bits. see Agtag_t. */ |
| 101 | #define AGNODE 1 |
| 102 | #define AGOUTEDGE 2 |
| 103 | #define AGINEDGE 3 /* (1 << 1) indicates an edge tag. */ |
| 104 | #define AGEDGE AGOUTEDGE /* synonym in object kind args */ |
| 105 | |
| 106 | /* a generic graph/node/edge header */ |
| 107 | struct Agobj_s { |
| 108 | Agtag_t tag; |
| 109 | Agrec_t *data; |
| 110 | }; |
| 111 | |
| 112 | #define AGTAG(obj) (((Agobj_t*)(obj))->tag) |
| 113 | #define AGTYPE(obj) (AGTAG(obj).objtype) |
| 114 | #define AGID(obj) (AGTAG(obj).id) |
| 115 | #define AGSEQ(obj) (AGTAG(obj).seq) |
| 116 | #define AGATTRWF(obj) (AGTAG(obj).attrwf) |
| 117 | #define AGDATA(obj) (((Agobj_t*)(obj))->data) |
| 118 | |
| 119 | /* This is the node struct allocated per graph (or subgraph). It resides |
| 120 | in the n_dict of the graph. The node set is maintained by libdict, but |
| 121 | transparently to libgraph callers. Every node may be given an optional |
| 122 | string name at its time of creation, or it is permissible to pass NIL(char*) |
| 123 | for the name. */ |
| 124 | |
| 125 | struct Agsubnode_s { /* the node-per-graph-or-subgraph record */ |
| 126 | Dtlink_t seq_link; /* must be first */ |
| 127 | Dtlink_t id_link; |
| 128 | Agnode_t *node; /* the object */ |
| 129 | Dtlink_t *in_id, *out_id; /* by node/ID for random access */ |
| 130 | Dtlink_t *in_seq, *out_seq; /* by node/sequence for serial access */ |
| 131 | }; |
| 132 | |
| 133 | struct Agnode_s { |
| 134 | Agobj_t base; |
| 135 | Agraph_t *root; |
| 136 | Agsubnode_t mainsub; /* embedded for main graph */ |
| 137 | }; |
| 138 | |
| 139 | struct Agedge_s { |
| 140 | Agobj_t base; |
| 141 | Dtlink_t id_link; /* main graph only */ |
| 142 | Dtlink_t seq_link; |
| 143 | Agnode_t *node; /* the endpoint node */ |
| 144 | }; |
| 145 | |
| 146 | struct Agedgepair_s { |
| 147 | Agedge_t out, in; |
| 148 | }; |
| 149 | |
| 150 | struct Agdesc_s { /* graph descriptor */ |
| 151 | unsigned directed:1; /* if edges are asymmetric */ |
| 152 | unsigned strict:1; /* if multi-edges forbidden */ |
| 153 | unsigned no_loop:1; /* if no loops */ |
| 154 | unsigned maingraph:1; /* if this is the top level graph */ |
| 155 | unsigned flatlock:1; /* if sets are flattened into lists in cdt */ |
| 156 | unsigned no_write:1; /* if a temporary subgraph */ |
| 157 | unsigned has_attrs:1; /* if string attr tables should be initialized */ |
| 158 | unsigned has_cmpnd:1; /* if may contain collapsed nodes */ |
| 159 | }; |
| 160 | |
| 161 | /* disciplines for external resources needed by libgraph */ |
| 162 | |
| 163 | struct Agmemdisc_s { /* memory allocator */ |
| 164 | void *(*open) (Agdisc_t*); /* independent of other resources */ |
| 165 | void *(*alloc) (void *state, size_t req); |
| 166 | void *(*resize) (void *state, void *ptr, size_t old, size_t req); |
| 167 | void (*free) (void *state, void *ptr); |
| 168 | void (*close) (void *state); |
| 169 | }; |
| 170 | |
| 171 | struct Agiddisc_s { /* object ID allocator */ |
| 172 | void *(*open) (Agraph_t * g, Agdisc_t*); /* associated with a graph */ |
| 173 | long (*map) (void *state, int objtype, char *str, IDTYPE *id, |
| 174 | int createflag); |
| 175 | long (*alloc) (void *state, int objtype, IDTYPE id); |
| 176 | void (*free) (void *state, int objtype, IDTYPE id); |
| 177 | char *(*print) (void *state, int objtype, IDTYPE id); |
| 178 | void (*close) (void *state); |
| 179 | void (*idregister) (void *state, int objtype, void *obj); |
| 180 | }; |
| 181 | |
| 182 | struct Agiodisc_s { |
| 183 | int (*afread) (void *chan, char *buf, int bufsize); |
| 184 | int (*putstr) (void *chan, const char *str); |
| 185 | int (*flush) (void *chan); /* sync */ |
| 186 | /* error messages? */ |
| 187 | }; |
| 188 | |
| 189 | struct Agdisc_s { /* user's discipline */ |
| 190 | Agmemdisc_t *mem; |
| 191 | Agiddisc_t *id; |
| 192 | Agiodisc_t *io; |
| 193 | }; |
| 194 | |
| 195 | /* default resource disciplines */ |
| 196 | |
| 197 | CGRAPH_API Agmemdisc_t AgMemDisc; |
| 198 | CGRAPH_API Agiddisc_t AgIdDisc; |
| 199 | CGRAPH_API Agiodisc_t AgIoDisc; |
| 200 | |
| 201 | CGRAPH_API Agdisc_t AgDefaultDisc; |
| 202 | |
| 203 | struct Agdstate_s { |
| 204 | void *mem; |
| 205 | void *id; |
| 206 | /* IO must be initialized and finalized outside Cgraph, |
| 207 | * and channels (FILES) are passed as void* arguments. */ |
| 208 | }; |
| 209 | |
| 210 | typedef void (*agobjfn_t) (Agraph_t * g, Agobj_t * obj, void *arg); |
| 211 | typedef void (*agobjupdfn_t) (Agraph_t * g, Agobj_t * obj, void *arg, |
| 212 | Agsym_t * sym); |
| 213 | |
| 214 | struct Agcbdisc_s { |
| 215 | struct { |
| 216 | agobjfn_t ins; |
| 217 | agobjupdfn_t mod; |
| 218 | agobjfn_t del; |
| 219 | } graph, node, edge; |
| 220 | }; |
| 221 | |
| 222 | struct Agcbstack_s { /* object event callbacks */ |
| 223 | Agcbdisc_t *f; /* methods */ |
| 224 | void *state; /* closure */ |
| 225 | Agcbstack_t *prev; /* kept in a stack, unlike other disciplines */ |
| 226 | }; |
| 227 | |
| 228 | struct Agclos_s { |
| 229 | Agdisc_t disc; /* resource discipline functions */ |
| 230 | Agdstate_t state; /* resource closures */ |
| 231 | Dict_t *strdict; /* shared string dict */ |
| 232 | uint64_t seq[3]; /* local object sequence number counter */ |
| 233 | Agcbstack_t *cb; /* user and system callback function stacks */ |
| 234 | unsigned char callbacks_enabled; /* issue user callbacks or hold them? */ |
| 235 | Dict_t *lookup_by_name[3]; |
| 236 | Dict_t *lookup_by_id[3]; |
| 237 | }; |
| 238 | |
| 239 | struct Agraph_s { |
| 240 | Agobj_t base; |
| 241 | Agdesc_t desc; |
| 242 | Dtlink_t link; |
| 243 | Dict_t *n_seq; /* the node set in sequence */ |
| 244 | Dict_t *n_id; /* the node set indexed by ID */ |
| 245 | Dict_t *e_seq, *e_id; /* holders for edge sets */ |
| 246 | Dict_t *g_dict; /* subgraphs - descendants */ |
| 247 | Agraph_t *parent, *root; /* subgraphs - ancestors */ |
| 248 | Agclos_t *clos; /* shared resources */ |
| 249 | }; |
| 250 | |
| 251 | CGRAPH_API void agpushdisc(Agraph_t * g, Agcbdisc_t * disc, void *state); |
| 252 | CGRAPH_API int agpopdisc(Agraph_t * g, Agcbdisc_t * disc); |
| 253 | CGRAPH_API int agcallbacks(Agraph_t * g, int flag); /* return prev value */ |
| 254 | |
| 255 | /* graphs */ |
| 256 | CGRAPH_API Agraph_t *agopen(char *name, Agdesc_t desc, Agdisc_t * disc); |
| 257 | CGRAPH_API int agclose(Agraph_t * g); |
| 258 | CGRAPH_API Agraph_t *agread(void *chan, Agdisc_t * disc); |
| 259 | CGRAPH_API Agraph_t *agmemread(const char *cp); |
| 260 | CGRAPH_API void agreadline(int); |
| 261 | CGRAPH_API void agsetfile(char *); |
| 262 | CGRAPH_API Agraph_t *agconcat(Agraph_t * g, void *chan, Agdisc_t * disc); |
| 263 | CGRAPH_API int agwrite(Agraph_t * g, void *chan); |
| 264 | CGRAPH_API int agisdirected(Agraph_t * g); |
| 265 | CGRAPH_API int agisundirected(Agraph_t * g); |
| 266 | CGRAPH_API int agisstrict(Agraph_t * g); |
| 267 | CGRAPH_API int agissimple(Agraph_t * g); |
| 268 | |
| 269 | /* nodes */ |
| 270 | CGRAPH_API Agnode_t *agnode(Agraph_t * g, char *name, int createflag); |
| 271 | CGRAPH_API Agnode_t *agidnode(Agraph_t * g, IDTYPE id, int createflag); |
| 272 | CGRAPH_API Agnode_t *agsubnode(Agraph_t * g, Agnode_t * n, int createflag); |
| 273 | CGRAPH_API Agnode_t *agfstnode(Agraph_t * g); |
| 274 | CGRAPH_API Agnode_t *agnxtnode(Agraph_t * g, Agnode_t * n); |
| 275 | CGRAPH_API Agnode_t *aglstnode(Agraph_t * g); |
| 276 | CGRAPH_API Agnode_t *agprvnode(Agraph_t * g, Agnode_t * n); |
| 277 | |
| 278 | CGRAPH_API Agsubnode_t *agsubrep(Agraph_t * g, Agnode_t * n); |
| 279 | CGRAPH_API int agnodebefore(Agnode_t *u, Agnode_t *v); /* we have no shame */ |
| 280 | |
| 281 | /* edges */ |
| 282 | CGRAPH_API Agedge_t *agedge(Agraph_t * g, Agnode_t * t, Agnode_t * h, |
| 283 | char *name, int createflag); |
| 284 | CGRAPH_API Agedge_t *agidedge(Agraph_t * g, Agnode_t * t, Agnode_t * h, |
| 285 | IDTYPE id, int createflag); |
| 286 | CGRAPH_API Agedge_t *agsubedge(Agraph_t * g, Agedge_t * e, int createflag); |
| 287 | CGRAPH_API Agedge_t *agfstin(Agraph_t * g, Agnode_t * n); |
| 288 | CGRAPH_API Agedge_t *agnxtin(Agraph_t * g, Agedge_t * e); |
| 289 | CGRAPH_API Agedge_t *agfstout(Agraph_t * g, Agnode_t * n); |
| 290 | CGRAPH_API Agedge_t *agnxtout(Agraph_t * g, Agedge_t * e); |
| 291 | CGRAPH_API Agedge_t *agfstedge(Agraph_t * g, Agnode_t * n); |
| 292 | CGRAPH_API Agedge_t *agnxtedge(Agraph_t * g, Agedge_t * e, Agnode_t * n); |
| 293 | |
| 294 | /* generic */ |
| 295 | CGRAPH_API Agraph_t *agraphof(void* obj); |
| 296 | CGRAPH_API Agraph_t *agroot(void* obj); |
| 297 | CGRAPH_API int agcontains(Agraph_t *, void *); |
| 298 | CGRAPH_API char *agnameof(void *); |
| 299 | CGRAPH_API int agrelabel(void *obj, char *name); /* scary */ |
| 300 | CGRAPH_API int agrelabel_node(Agnode_t * n, char *newname); |
| 301 | CGRAPH_API int agdelete(Agraph_t * g, void *obj); |
| 302 | CGRAPH_API long agdelsubg(Agraph_t * g, Agraph_t * sub); /* could be agclose */ |
| 303 | CGRAPH_API int agdelnode(Agraph_t * g, Agnode_t * arg_n); |
| 304 | CGRAPH_API int agdeledge(Agraph_t * g, Agedge_t * arg_e); |
| 305 | CGRAPH_API int agobjkind(void *); |
| 306 | |
| 307 | /* strings */ |
| 308 | CGRAPH_API char *agstrdup(Agraph_t *, char *); |
| 309 | CGRAPH_API char *agstrdup_html(Agraph_t *, char *); |
| 310 | CGRAPH_API int aghtmlstr(char *); |
| 311 | CGRAPH_API char *agstrbind(Agraph_t * g, char *); |
| 312 | CGRAPH_API int agstrfree(Agraph_t *, char *); |
| 313 | CGRAPH_API char *agcanon(char *, int); |
| 314 | CGRAPH_API char *agstrcanon(char *, char *); |
| 315 | CGRAPH_API char *agcanonStr(char *str); /* manages its own buf */ |
| 316 | |
| 317 | /* definitions for dynamic string attributes */ |
| 318 | struct Agattr_s { /* dynamic string attributes */ |
| 319 | Agrec_t h; /* common data header */ |
| 320 | Dict_t *dict; /* shared dict to interpret attr field */ |
| 321 | char **str; /* the attribute string values */ |
| 322 | }; |
| 323 | |
| 324 | struct Agsym_s { /* symbol in one of the above dictionaries */ |
| 325 | Dtlink_t link; |
| 326 | char *name; /* attribute's name */ |
| 327 | char *defval; /* its default value for initialization */ |
| 328 | int id; /* its index in attr[] */ |
| 329 | unsigned char kind; /* referent object type */ |
| 330 | unsigned char fixed; /* immutable value */ |
| 331 | unsigned char print; /* always print */ |
| 332 | }; |
| 333 | |
| 334 | struct Agdatadict_s { /* set of dictionaries per graph */ |
| 335 | Agrec_t h; /* installed in list of graph recs */ |
| 336 | struct { |
| 337 | Dict_t *n, *e, *g; |
| 338 | } dict; |
| 339 | }; |
| 340 | |
| 341 | CGRAPH_API Agsym_t *agattr(Agraph_t * g, int kind, char *name, char *value); |
| 342 | CGRAPH_API Agsym_t *agattrsym(void *obj, char *name); |
| 343 | CGRAPH_API Agsym_t *agnxtattr(Agraph_t * g, int kind, Agsym_t * attr); |
| 344 | CGRAPH_API int agcopyattr(void *oldobj, void *newobj); |
| 345 | |
| 346 | CGRAPH_API void *agbindrec(void *obj, char *name, unsigned int size, |
| 347 | int move_to_front); |
| 348 | CGRAPH_API Agrec_t *aggetrec(void *obj, char *name, int move_to_front); |
| 349 | CGRAPH_API int agdelrec(void *obj, char *name); |
| 350 | CGRAPH_API void aginit(Agraph_t * g, int kind, char *rec_name, int rec_size, |
| 351 | int move_to_front); |
| 352 | CGRAPH_API void agclean(Agraph_t * g, int kind, char *rec_name); |
| 353 | |
| 354 | CGRAPH_API char *agget(void *obj, char *name); |
| 355 | CGRAPH_API char *agxget(void *obj, Agsym_t * sym); |
| 356 | CGRAPH_API int agset(void *obj, char *name, char *value); |
| 357 | CGRAPH_API int agxset(void *obj, Agsym_t * sym, char *value); |
| 358 | CGRAPH_API int agsafeset(void* obj, char* name, char* value, char* def); |
| 359 | |
| 360 | /* defintions for subgraphs */ |
| 361 | CGRAPH_API Agraph_t *agsubg(Agraph_t * g, char *name, int cflag); /* constructor */ |
| 362 | CGRAPH_API Agraph_t *agidsubg(Agraph_t * g, IDTYPE id, int cflag); /* constructor */ |
| 363 | CGRAPH_API Agraph_t *agfstsubg(Agraph_t * g); |
| 364 | CGRAPH_API Agraph_t *agnxtsubg(Agraph_t * subg); |
| 365 | CGRAPH_API Agraph_t *agparent(Agraph_t * g); |
| 366 | |
| 367 | /* set cardinality */ |
| 368 | CGRAPH_API int agnnodes(Agraph_t * g); |
| 369 | CGRAPH_API int agnedges(Agraph_t * g); |
| 370 | CGRAPH_API int agnsubg(Agraph_t * g); |
| 371 | CGRAPH_API int agdegree(Agraph_t * g, Agnode_t * n, int in, int out); |
| 372 | CGRAPH_API int agcountuniqedges(Agraph_t * g, Agnode_t * n, int in, int out); |
| 373 | |
| 374 | /* memory */ |
| 375 | CGRAPH_API void *agalloc(Agraph_t * g, size_t size); |
| 376 | CGRAPH_API void *agrealloc(Agraph_t * g, void *ptr, size_t oldsize, |
| 377 | size_t size); |
| 378 | CGRAPH_API void agfree(Agraph_t * g, void *ptr); |
| 379 | CGRAPH_API struct _vmalloc_s *agheap(Agraph_t * g); |
| 380 | |
| 381 | /* an engineering compromise is a joy forever */ |
| 382 | CGRAPH_API void aginternalmapclearlocalnames(Agraph_t * g); |
| 383 | |
| 384 | #define agnew(g,t) ((t*)agalloc(g,sizeof(t))) |
| 385 | #define agnnew(g,n,t) ((t*)agalloc(g,(n)*sizeof(t))) |
| 386 | |
| 387 | /* error handling */ |
| 388 | typedef enum { AGWARN, AGERR, AGMAX, AGPREV } agerrlevel_t; |
| 389 | typedef int (*agusererrf) (char*); |
| 390 | CGRAPH_API agerrlevel_t agseterr(agerrlevel_t); |
| 391 | CGRAPH_API char *aglasterr(void); |
| 392 | CGRAPH_API int agerr(agerrlevel_t level, const char *fmt, ...); |
| 393 | CGRAPH_API void agerrorf(const char *fmt, ...); |
| 394 | CGRAPH_API void agwarningf(const char *fmt, ...); |
| 395 | CGRAPH_API int agerrors(void); |
| 396 | CGRAPH_API int agreseterrors(void); |
| 397 | CGRAPH_API agusererrf agseterrf(agusererrf); |
| 398 | |
| 399 | /* data access macros */ |
| 400 | /* this assumes that e[0] is out and e[1] is inedge, see edgepair in edge.c */ |
| 401 | #define AGIN2OUT(e) ((e)-1) |
| 402 | #define AGOUT2IN(e) ((e)+1) |
| 403 | #define AGOPP(e) ((AGTYPE(e)==AGINEDGE)?AGIN2OUT(e):AGOUT2IN(e)) |
| 404 | #define AGMKOUT(e) (AGTYPE(e) == AGOUTEDGE? (e): AGIN2OUT(e)) |
| 405 | #define AGMKIN(e) (AGTYPE(e) == AGINEDGE? (e): AGOUT2IN(e)) |
| 406 | #define AGTAIL(e) (AGMKIN(e)->node) |
| 407 | #define AGHEAD(e) (AGMKOUT(e)->node) |
| 408 | #define AGEQEDGE(e,f) (AGMKOUT(e) == AGMKOUT(f)) |
| 409 | /* These macros are also exposed as functions, so they can be linked against. */ |
| 410 | #define agtail(e) AGTAIL(e) |
| 411 | #define aghead(e) AGHEAD(e) |
| 412 | #define agopp(e) AGOPP(e) |
| 413 | #define ageqedge(e,f) AGEQEDGE(e,f) |
| 414 | |
| 415 | #define TAILPORT_ID "tailport" |
| 416 | #define HEADPORT_ID "headport" |
| 417 | |
| 418 | CGRAPH_API Agdesc_t Agdirected; |
| 419 | CGRAPH_API Agdesc_t Agstrictdirected; |
| 420 | CGRAPH_API Agdesc_t Agundirected; |
| 421 | CGRAPH_API Agdesc_t Agstrictundirected; |
| 422 | |
| 423 | /* fast graphs */ |
| 424 | void agflatten(Agraph_t * g, int flag); |
| 425 | typedef Agsubnode_t Agnoderef_t; |
| 426 | typedef Dtlink_t Agedgeref_t; |
| 427 | |
| 428 | #define AGHEADPOINTER(g) ((Agnoderef_t*)(g->n_seq->data->hh._head)) |
| 429 | #define AGRIGHTPOINTER(rep) ((Agnoderef_t*)((rep)->seq_link.right?((void*)((rep)->seq_link.right) - offsetof(Agsubnode_t,seq_link)):0)) |
| 430 | #define AGLEFTPOINTER(rep) ((Agnoderef_t*)((rep)->seq_link.hl._left?((void*)((rep)->seq_link.hl._left) - offsetof(Agsubnode_t,seq_link)):0)) |
| 431 | |
| 432 | #define FIRSTNREF(g) (agflatten(g,1), AGHEADPOINTER(g)) |
| 433 | |
| 434 | #define NEXTNREF(g,rep) (AGRIGHTPOINTER(rep) == AGHEADPOINTER(g)?0:AGRIGHTPOINTER(rep)) |
| 435 | |
| 436 | #define PREVNREF(g,rep) (((rep)==AGHEADPOINTER(g))?0:(AGLEFTPOINTER(rep))) |
| 437 | |
| 438 | #define LASTNREF(g) (agflatten(g,1), AGHEADPOINTER(g)?AGLEFTPOINTER(AGHEADPOINTER(g)):0) |
| 439 | #define NODEOF(rep) ((rep)->node) |
| 440 | |
| 441 | #define FIRSTOUTREF(g,sn) (agflatten(g,1), (sn)->out_seq) |
| 442 | #define LASTOUTREF(g,sn) (agflatten(g,1), (Agedgeref_t*)dtlast(sn->out_seq)) |
| 443 | #define FIRSTINREF(g,sn) (agflatten(g,1), (sn)->in_seq) |
| 444 | #define NEXTEREF(g,rep) ((rep)->right) |
| 445 | #define PREVEREF(g,rep) ((rep)->hl._left) |
| 446 | /* this is expedient but a bit slimey because it "knows" that dict entries of both nodes |
| 447 | and edges are embedded in main graph objects but allocated separately in subgraphs */ |
| 448 | #define AGSNMAIN(sn) ((sn)==(&((sn)->node->mainsub))) |
| 449 | #define EDGEOF(sn,rep) (AGSNMAIN(sn)?((Agedge_t*)((unsigned char*)(rep) - offsetof(Agedge_t,seq_link))) : ((Dthold_t*)(rep))->obj) |
| 450 | |
| 451 | #ifdef __cplusplus |
| 452 | } |
| 453 | #endif |
| 454 | #endif |
| 455 | |