123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- /**
- * @file
- * @ingroup cgraph_core
- */
- /*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: Details at https://graphviz.org
- *************************************************************************/
- #include <assert.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <cgraph/cghdr.h>
- #include <inttypes.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <util/alloc.h>
- /* a default ID allocator that works off the shared string lib */
- /// information the ID allocator needs to do its job
- typedef struct {
- IDTYPE counter; ///< base to derive next identifier from
- Agraph_t *g; ///< graph in use
- } state_t;
- static void *idopen(Agraph_t * g, Agdisc_t* disc)
- {
- (void)disc;
- state_t *s = gv_alloc(sizeof(state_t));
- *s = (state_t){.g = g};
- return s;
- }
- static long idmap(void *state, int objtype, char *str, IDTYPE *id,
- int createflag)
- {
- char *s;
- state_t *st = state;
- (void)objtype;
- if (str) {
- if (createflag)
- s = agstrdup(st->g, str);
- else
- s = agstrbind(st->g, str);
- // The scheme of using pointers as the IDs of named objects and odd
- // numbers as the IDs of unnamed objects relies on heap pointers being
- // even, to avoid collisions. So the low bit had better be unset.
- assert((uintptr_t)s % 2 == 0 &&
- "heap pointer with low bit set will collide with anonymous IDs");
- *id = (IDTYPE)(uintptr_t)s;
- } else {
- *id = st->counter * 2 + 1;
- ++st->counter;
- }
- return 1;
- }
- /* we don't allow users to explicitly set IDs, either */
- static long idalloc(void *state, int objtype, IDTYPE request)
- {
- (void)state;
- (void)objtype;
- (void)request;
- return 0;
- }
- static void idfree(void *state, int objtype, IDTYPE id)
- {
- (void)objtype;
- state_t *st = state;
- if (id % 2 == 0)
- agstrfree(st->g, (char *)(uintptr_t)id);
- }
- static char *idprint(void *state, int objtype, IDTYPE id)
- {
- (void)state;
- (void)objtype;
- if (id % 2 == 0)
- return (char *)(uintptr_t)id;
- else
- return NULL;
- }
- static void idregister(void *state, int objtype, void *obj)
- {
- (void)state;
- (void)objtype;
- (void)obj;
- }
- Agiddisc_t AgIdDisc = {
- idopen,
- idmap,
- idalloc,
- idfree,
- idprint,
- free,
- idregister
- };
- /* aux functions incl. support for disciplines with anonymous IDs */
- int agmapnametoid(Agraph_t * g, int objtype, char *str,
- IDTYPE *result, bool createflag) {
- int rv;
- if (str && str[0] != LOCALNAMEPREFIX) {
- rv = (int) AGDISC(g, id)->map(AGCLOS(g, id), objtype, str, result,
- createflag);
- if (rv)
- return rv;
- }
- /* either an internal ID, or disc. can't map strings */
- if (str) {
- rv = aginternalmaplookup(g, objtype, str, result);
- if (rv)
- return rv;
- } else
- rv = 0;
- if (createflag) {
- /* get a new anonymous ID, and store in the internal map */
- rv = (int) AGDISC(g, id)->map(AGCLOS(g, id), objtype, NULL, result,
- createflag);
- if (rv && str)
- aginternalmapinsert(g, objtype, str, *result);
- }
- return rv;
- }
- int agallocid(Agraph_t * g, int objtype, IDTYPE request)
- {
- return (int) AGDISC(g, id)->alloc(AGCLOS(g, id), objtype, request);
- }
- void agfreeid(Agraph_t * g, int objtype, IDTYPE id)
- {
- (void) aginternalmapdelete(g, objtype, id);
- (AGDISC(g, id)->free) (AGCLOS(g, id), objtype, id);
- }
- /**
- * Return string representation of object.
- * In general, returns the name of node or graph,
- * and the key of an edge. If edge is anonymous, returns NULL.
- * Uses static buffer for anonymous graphs.
- */
- char *agnameof(void *obj)
- {
- Agraph_t *g;
- char *rv;
- /* perform internal lookup first */
- g = agraphof(obj);
- rv = aginternalmapprint(g, AGTYPE(obj), AGID(obj));
- if (rv != NULL)
- return rv;
- if (AGDISC(g, id)->print) {
- rv = AGDISC(g, id)->print(AGCLOS(g, id), AGTYPE(obj), AGID(obj));
- if (rv != NULL)
- return rv;
- }
- if (AGTYPE(obj) != AGEDGE) {
- static char buf[32];
- snprintf(buf, sizeof(buf), "%c%" PRIu64, LOCALNAMEPREFIX, AGID(obj));
- rv = buf;
- }
- else
- rv = 0;
- return rv;
- }
- /* register a graph object in an external namespace */
- void agregister(Agraph_t * g, int objtype, void *obj)
- {
- AGDISC(g, id)->idregister(AGCLOS(g, id), objtype, obj);
- }
|