id.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /**
  2. * @file
  3. * @ingroup cgraph_core
  4. */
  5. /*************************************************************************
  6. * Copyright (c) 2011 AT&T Intellectual Property
  7. * All rights reserved. This program and the accompanying materials
  8. * are made available under the terms of the Eclipse Public License v1.0
  9. * which accompanies this distribution, and is available at
  10. * https://www.eclipse.org/legal/epl-v10.html
  11. *
  12. * Contributors: Details at https://graphviz.org
  13. *************************************************************************/
  14. #include <assert.h>
  15. #include <stdbool.h>
  16. #include <stdio.h>
  17. #include <cgraph/cghdr.h>
  18. #include <inttypes.h>
  19. #include <stdint.h>
  20. #include <stdlib.h>
  21. #include <util/alloc.h>
  22. /* a default ID allocator that works off the shared string lib */
  23. /// information the ID allocator needs to do its job
  24. typedef struct {
  25. IDTYPE counter; ///< base to derive next identifier from
  26. Agraph_t *g; ///< graph in use
  27. } state_t;
  28. static void *idopen(Agraph_t * g, Agdisc_t* disc)
  29. {
  30. (void)disc;
  31. state_t *s = gv_alloc(sizeof(state_t));
  32. *s = (state_t){.g = g};
  33. return s;
  34. }
  35. static long idmap(void *state, int objtype, char *str, IDTYPE *id,
  36. int createflag)
  37. {
  38. char *s;
  39. state_t *st = state;
  40. (void)objtype;
  41. if (str) {
  42. if (createflag)
  43. s = agstrdup(st->g, str);
  44. else
  45. s = agstrbind(st->g, str);
  46. // The scheme of using pointers as the IDs of named objects and odd
  47. // numbers as the IDs of unnamed objects relies on heap pointers being
  48. // even, to avoid collisions. So the low bit had better be unset.
  49. assert((uintptr_t)s % 2 == 0 &&
  50. "heap pointer with low bit set will collide with anonymous IDs");
  51. *id = (IDTYPE)(uintptr_t)s;
  52. } else {
  53. *id = st->counter * 2 + 1;
  54. ++st->counter;
  55. }
  56. return 1;
  57. }
  58. /* we don't allow users to explicitly set IDs, either */
  59. static long idalloc(void *state, int objtype, IDTYPE request)
  60. {
  61. (void)state;
  62. (void)objtype;
  63. (void)request;
  64. return 0;
  65. }
  66. static void idfree(void *state, int objtype, IDTYPE id)
  67. {
  68. (void)objtype;
  69. state_t *st = state;
  70. if (id % 2 == 0)
  71. agstrfree(st->g, (char *)(uintptr_t)id);
  72. }
  73. static char *idprint(void *state, int objtype, IDTYPE id)
  74. {
  75. (void)state;
  76. (void)objtype;
  77. if (id % 2 == 0)
  78. return (char *)(uintptr_t)id;
  79. else
  80. return NULL;
  81. }
  82. static void idregister(void *state, int objtype, void *obj)
  83. {
  84. (void)state;
  85. (void)objtype;
  86. (void)obj;
  87. }
  88. Agiddisc_t AgIdDisc = {
  89. idopen,
  90. idmap,
  91. idalloc,
  92. idfree,
  93. idprint,
  94. free,
  95. idregister
  96. };
  97. /* aux functions incl. support for disciplines with anonymous IDs */
  98. int agmapnametoid(Agraph_t * g, int objtype, char *str,
  99. IDTYPE *result, bool createflag) {
  100. int rv;
  101. if (str && str[0] != LOCALNAMEPREFIX) {
  102. rv = (int) AGDISC(g, id)->map(AGCLOS(g, id), objtype, str, result,
  103. createflag);
  104. if (rv)
  105. return rv;
  106. }
  107. /* either an internal ID, or disc. can't map strings */
  108. if (str) {
  109. rv = aginternalmaplookup(g, objtype, str, result);
  110. if (rv)
  111. return rv;
  112. } else
  113. rv = 0;
  114. if (createflag) {
  115. /* get a new anonymous ID, and store in the internal map */
  116. rv = (int) AGDISC(g, id)->map(AGCLOS(g, id), objtype, NULL, result,
  117. createflag);
  118. if (rv && str)
  119. aginternalmapinsert(g, objtype, str, *result);
  120. }
  121. return rv;
  122. }
  123. int agallocid(Agraph_t * g, int objtype, IDTYPE request)
  124. {
  125. return (int) AGDISC(g, id)->alloc(AGCLOS(g, id), objtype, request);
  126. }
  127. void agfreeid(Agraph_t * g, int objtype, IDTYPE id)
  128. {
  129. (void) aginternalmapdelete(g, objtype, id);
  130. (AGDISC(g, id)->free) (AGCLOS(g, id), objtype, id);
  131. }
  132. /**
  133. * Return string representation of object.
  134. * In general, returns the name of node or graph,
  135. * and the key of an edge. If edge is anonymous, returns NULL.
  136. * Uses static buffer for anonymous graphs.
  137. */
  138. char *agnameof(void *obj)
  139. {
  140. Agraph_t *g;
  141. char *rv;
  142. /* perform internal lookup first */
  143. g = agraphof(obj);
  144. rv = aginternalmapprint(g, AGTYPE(obj), AGID(obj));
  145. if (rv != NULL)
  146. return rv;
  147. if (AGDISC(g, id)->print) {
  148. rv = AGDISC(g, id)->print(AGCLOS(g, id), AGTYPE(obj), AGID(obj));
  149. if (rv != NULL)
  150. return rv;
  151. }
  152. if (AGTYPE(obj) != AGEDGE) {
  153. static char buf[32];
  154. snprintf(buf, sizeof(buf), "%c%" PRIu64, LOCALNAMEPREFIX, AGID(obj));
  155. rv = buf;
  156. }
  157. else
  158. rv = 0;
  159. return rv;
  160. }
  161. /* register a graph object in an external namespace */
  162. void agregister(Agraph_t * g, int objtype, void *obj)
  163. {
  164. AGDISC(g, id)->idregister(AGCLOS(g, id), objtype, obj);
  165. }