The Assimilation Project
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
proj_classes.c
Go to the documentation of this file.
1 
24 #include <projectcommon.h>
25 #include <assimobj.h>
26 
27 #undef NULL_FOR_BAD_CAST
28 #ifdef NULL_FOR_BAD_CAST
29 # define BADCASTMSG g_critical
30 #else
31 # define BADCASTMSG g_error
32 #endif
33 
35 
40 /*
41  * This code depends pretty heavily on Glib hash tables and Glib Quarks.
42  *
43  * Quarks are a litle odd, and a little confusing at first - but handy.
44  * A Quark is an object which is an integer which uniquely identifies a particular collection of characters
45  * making up a C-style string.
46  * That is, if you have the string "abc" in your code in three places,
47  * all places will see the quark as being the same.
48  *
49  * Two strings which have the same quark have the same content.
50  * The quark which has the value zero is the non-existent quark (goes with NULL pointer).
51  *
52  * Our type system then is just two sets of associations (or mappings):
53  * The first is the object -> class-quark mapping
54  * which is keyed by object _addresses_ (ObjectClassAssociation) - not the objects pointed to
55  * The associated values are the quarks of the classes of the objects at those addresses.
56  * {object-address, object class quark}, keyed by object-address
57  *
58  *
59  * The second is the subclass-quark -> superclass-quark mapping,
60  * which is keyed by quarks of classes.
61  * Each associated value is the quark of a superclass.
62  * {subclass-quark, superclass-quark}, keyed by subclass-quark
63  */
64 
65 
66 static GHashTable* ObjectClassAssociation= NULL;
67 static GHashTable* SuperClassAssociation = NULL;
68 static GHashTable* DebugClassAssociation = NULL;
69 static GHashTable* FreedClassAssociation = NULL;
70 static guint32 proj_class_obj_count = 0;
71 static guint32 proj_class_max_obj_count = 0;
72 gboolean badfree = FALSE;
73 
75 FSTATIC void proj_class_change_debug(const char * Cclass, gint incr);
76 
78 FSTATIC void
80 {
81  ObjectClassAssociation = g_hash_table_new(NULL, NULL); // same as g_direct_hash(), g_direct_equal().
82  FreedClassAssociation = g_hash_table_new(NULL, NULL); // same as g_direct_hash(), g_direct_equal().
83  SuperClassAssociation = g_hash_table_new(NULL, NULL); // same as g_direct_hash(), g_direct_equal().
84  DebugClassAssociation = g_hash_table_new(g_str_hash, g_str_equal);
85 }
87 void
89 {
90  g_hash_table_destroy(ObjectClassAssociation); ObjectClassAssociation = NULL;
91  g_hash_table_destroy(FreedClassAssociation); FreedClassAssociation = NULL;
92  g_hash_table_destroy(SuperClassAssociation); SuperClassAssociation = NULL;
93  g_hash_table_destroy(DebugClassAssociation); DebugClassAssociation = NULL;
94 }
95 
99 void
100 proj_class_register_object(gpointer object,
101  const char * static_classname)
102 {
103 
104  GQuark classquark = g_quark_from_static_string(static_classname); // Quark for the given classname
105 
106  if (NULL == ObjectClassAssociation) {
108  }
109  if (NULL != g_hash_table_lookup(ObjectClassAssociation, object)) {
110  g_error("Attempt to re-allocate memory already allocated at address %p", object);
111  }
112  g_hash_table_insert(ObjectClassAssociation, object, GUINT_TO_POINTER(classquark));
113  ++ proj_class_obj_count;
114  if (proj_class_obj_count > proj_class_max_obj_count) {
115  proj_class_max_obj_count = proj_class_obj_count;
116  }
117 }
118 
119 static guint global_debug_counter = 0;
120 
121 void
122 proj_class_register_debug_counter(const char * classname, guint * debugcount)
123 {
124  if (NULL == ObjectClassAssociation) {
126  }
127  if (*debugcount == 0) {
128  *debugcount = global_debug_counter;
129  }
130  // Sleazy - the double cast is to make the 'const' go away - but safe
131  // since we we never modify the strings we were given - we expect them to be constants
132  // and we just point at them.
133  g_hash_table_replace(DebugClassAssociation, (gpointer)((guintptr)classname), debugcount);
134 }
135 
136 
139 void
140 proj_class_incr_debug(const char * Cclass)
141 {
142  proj_class_change_debug(Cclass, +1);
143 }
144 
147 void
148 proj_class_decr_debug(const char * Cclass)
149 {
150  proj_class_change_debug(Cclass, -1);
151 }
152 
155 FSTATIC void
156 proj_class_change_debug(const char * Cclass, gint incr)
157 {
158  GHashTableIter iter;
159  gpointer classname;
160  gpointer gdebugptr;
161  GQuark CclassQuark = g_quark_from_static_string(Cclass);
162 
163  if (DebugClassAssociation) {
164  g_hash_table_iter_init(&iter, DebugClassAssociation);
165 
166  // Search through all our debug pointers.
167  // Modify (+/-) the debug variables for each class that 'is_a' Cclass object.
168  while (g_hash_table_iter_next(&iter, &classname, &gdebugptr)) {
169  guint* debug = gdebugptr;
170  GQuark classQ = g_quark_from_static_string(classname);
171  if (Cclass == NULL || proj_class_quark_is_a(classQ, CclassQuark)) {
172  if (incr < 0 && (guint)-incr >= *debug) {
173  *debug = 0;
174  }else{
175  *debug += incr;
176  }
177  }
178  }
179  }
180  if (Cclass == NULL) {
181  if (incr < 0 && (guint)-incr >= global_debug_counter) {
182  global_debug_counter = 0;
183  }else{
184  global_debug_counter += incr;
185  }
186  }
187 }
188 
191 gpointer
193  const char * static_subclassname)
194 {
195 
196  GQuark subclassquark = g_quark_from_static_string(static_subclassname); // Quark for the given classname
197  GQuark superclassquark;
198 
199  if (NULL == ObjectClassAssociation) {
201  }
202  superclassquark = GPOINTER_TO_INT(g_hash_table_lookup(ObjectClassAssociation, object));
203  if (0 == superclassquark) {
204  g_error("Attempt to subclass an object that's not a class object %p", object);
205  }
207  proj_class_quark_add_superclass_relationship(superclassquark, subclassquark);
208  g_hash_table_replace(ObjectClassAssociation, object, GUINT_TO_POINTER(subclassquark));
209  return object;
210 }
211 
213 gpointer
214 proj_class_new(gsize objsize,
215  const char * static_classname)
216 {
217  gpointer ret = MALLOC0(objsize);
218 
219  if (ret != NULL) {
220  proj_class_register_object(ret, static_classname);
221  }
222  return ret;
223 }
227 void
228 proj_class_dissociate(gpointer object)
229 {
230  GQuark objquark = GPOINTER_TO_INT(g_hash_table_lookup(ObjectClassAssociation, object));
231  -- proj_class_obj_count;
232  if (objquark == 0) {
233  GQuark freedquark = GPOINTER_TO_INT(g_hash_table_lookup(FreedClassAssociation, object));
234  const char * oldclass = (freedquark == 0 ? "(unknown class)" : g_quark_to_string(freedquark));
235  BADCASTMSG("Attempt to free memory not currently shown as allocated to a class object - former class: %s"
236  , oldclass);
237  badfree = TRUE;
238  }else{
239  //g_warning("Freeing object %p of type %s", object, proj_class_classname(object));
240  g_hash_table_insert(FreedClassAssociation, object, GUINT_TO_POINTER(objquark));
241  g_hash_table_remove(ObjectClassAssociation, object);
242  }
243 }
244 
248 void
249 proj_class_free(gpointer object)
250 {
251  proj_class_dissociate(object);
252  FREE(object);
253 }
254 
256 gboolean
257 proj_class_is_a(gconstpointer object,
258  const char * Cclass)
259 {
260  GQuark objquark;
261  GQuark classquark;
262 
263  if (NULL == object) {
264  return TRUE;
265  }
266 
267  objquark = GPOINTER_TO_INT(g_hash_table_lookup(ObjectClassAssociation, object));
268  classquark = g_quark_from_static_string(Cclass);
269 
270  if (objquark != classquark || classquark == 0) {
271  if (!proj_class_quark_is_a(objquark, classquark)) {
272  return FALSE;
273  }
274  }
275  return TRUE;
276 }
277 
279 
284 gpointer
285 proj_class_castas(gpointer object,
286  const char * castclass)
287 {
288  if (!OBJ_IS_A(object, castclass)) {
289  const char * objclass = proj_class_classname(object);
290  GQuark freedquark = GPOINTER_TO_INT(g_hash_table_lookup(FreedClassAssociation, object));
291  const char * oldclass = (freedquark == 0 ? "(unknown class)" : g_quark_to_string(freedquark));
292  BADCASTMSG("Attempt to cast %s pointer at address %p to %s (formerly a %s)", objclass, object, castclass
293  , oldclass);
294  object = NULL;
295  badfree = TRUE;
296  }
297  return object;
298 }
299 
304 gconstpointer
305 proj_class_castasconst(gconstpointer object,
306  const char * castclass)
307 {
308  if (!proj_class_is_a(object, castclass)) {
309  const char * objclass = proj_class_classname(object);
310  GQuark freedquark = GPOINTER_TO_INT(g_hash_table_lookup(FreedClassAssociation, object));
311  const char * oldclass = (freedquark == 0 ? "(unknown class)" : g_quark_to_string(freedquark));
312  BADCASTMSG("Attempt to cast %s pointer at address %p to a const %s (formerly a %s)", objclass, object, castclass
313  , oldclass);
314  object = NULL;
315  badfree = TRUE;
316  }
317  return object;
318 }
319 
321 
323 const char *
324 proj_class_classname(gconstpointer object)
325 {
326  GQuark objquark = GPOINTER_TO_INT(g_hash_table_lookup(ObjectClassAssociation, object));
327  return (objquark == 0 ? "(unknown class)" : g_quark_to_string(objquark));
328 
329 }
330 
332 void
334  GQuark subclass)
335 {
336  g_hash_table_insert(SuperClassAssociation, GUINT_TO_POINTER(subclass), GUINT_TO_POINTER(superclass));
337 
338 }
341 gboolean
342 proj_class_quark_is_a(GQuark objectclass,
343  GQuark testclass)
344 {
345  while (objectclass != 0) {
346  if (objectclass == testclass) {
347  return TRUE;
348  }
349  objectclass = GPOINTER_TO_INT(g_hash_table_lookup(SuperClassAssociation, GUINT_TO_POINTER(objectclass)));
350  }
351  return FALSE;
352 }
353 
355 void
357 {
358  GHashTableIter iter;
359  gpointer object;
360  gpointer quarkp;
361 
362  g_debug("START of live C Class object dump:");
363  if (ObjectClassAssociation) {
364  g_hash_table_iter_init(&iter, ObjectClassAssociation);
365  while (g_hash_table_iter_next(&iter, &object, &quarkp)) {
366  if (OBJ_IS_A(object, "AssimObj")) {
367  AssimObj* obj = CASTTOCLASS(AssimObj, object);
368  char * str = obj->toString(obj);
369  g_debug(" %s object %s at %p ref count %d"
370  , proj_class_classname(obj), str, obj, obj->_refcount);
371  g_free(str);
372  }else{
373  g_debug(" %s object at %p", proj_class_classname(object), object);
374  }
375  }
376  }
377  g_debug("END of live C Class object dump.");
378 }
379 
381 void
382 proj_class_debug_dump(const char * prefix, const AssimObj* obj, const char *suffix)
383 {
384  char * objstr = NULL;
385  const char * pad = "";
386 
387  if (prefix != NULL) {
388  pad = ": ";
389  }
390  if (obj) {
391  objstr = obj->toString(obj);
392  }
393  g_debug("%s%s%s%s"
394  , (prefix == NULL ? "" : prefix)
395  , pad
396  , (obj == NULL ? "<NULL OBJECT>" : objstr)
397  , (suffix == NULL ? "" : suffix));
398  if (objstr) {
399  g_free(objstr); objstr = NULL;
400  }
401 }
402 
403 
405 guint32
407 {
408  GHashTableIter iter;
409  gpointer object;
410  gpointer quarkp;
411  guint32 count = 0;
412 
413 
414  if (ObjectClassAssociation) {
415  g_hash_table_iter_init(&iter, ObjectClassAssociation);
416  while (g_hash_table_iter_next(&iter, &object, &quarkp)) {
417  count += 1;
418  }
419  }
420  g_assert(count == proj_class_obj_count);
421  return count;
422 }
423 
425 guint32
427 {
428  return proj_class_max_obj_count;
429 }
430 
#define MALLOC0(nbytes)
should it just call g_malloc?
Definition: projectcommon.h:25
gboolean proj_class_quark_is_a(GQuark objectclass, GQuark testclass)
Determine whether an 'objectclass' ISA member of 'testclass' - with quarks of types as arguments Sinc...
Definition: proj_classes.c:342
FSTATIC void _init_proj_class_module(void)
Initialize our object system tables.
Definition: proj_classes.c:79
gconstpointer proj_class_castasconst(gconstpointer object, const char *castclass)
"Safely" cast an object to a const object of the given C-class.
Definition: proj_classes.c:305
void proj_class_finalize_sys(void)
Shut down (finalize) our object class system. Only do on shutdown to make valgrind happy :-D...
Definition: proj_classes.c:88
guint32 proj_class_max_object_count(void)
Return the maximum number of live C class objects that we've ever had.
Definition: proj_classes.c:426
gboolean badfree
Definition: proj_classes.c:72
#define FSTATIC
Definition: projectcommon.h:31
int _refcount
Reference count (private)
Definition: assimobj.h:53
This file defines our base object class: AssimObj.
FSTATIC void proj_class_change_debug(const char *Cclass, gint incr)
Change debug level for this class and all its subclasses by 'incr'.
Definition: proj_classes.c:156
void proj_class_decr_debug(const char *Cclass)
Decrement debug level for this class and all its subclasses by one.
Definition: proj_classes.c:148
void proj_class_register_debug_counter(const char *classname, guint *debugcount)
Definition: proj_classes.c:122
void proj_class_register_object(gpointer object, const char *static_classname)
Log the creation of a new object, and its association with a given type.
Definition: proj_classes.c:100
#define BADCASTMSG
Definition: proj_classes.c:31
gpointer proj_class_register_subclassed(gpointer object, const char *static_subclassname)
Log the creation of a subclassed object from a superclassed object.
Definition: proj_classes.c:192
#define OBJ_IS_A(obj, Cclass)
Definition: proj_classes.h:72
#define FREE(m)
Our interface to free.
Definition: projectcommon.h:29
guint32 proj_class_live_object_count(void)
Return the count of live C class objects.
Definition: proj_classes.c:406
Project common header file.
gpointer proj_class_castas(gpointer object, const char *castclass)
"Safely" cast an object to a const object of the given C-class.
Definition: proj_classes.c:285
gboolean proj_class_is_a(gconstpointer object, const char *Cclass)
Return TRUE if the given object ISA castclass object.
Definition: proj_classes.c:257
void proj_class_incr_debug(const char *Cclass)
Increment debug level for this class and all its subclasses by one.
Definition: proj_classes.c:140
const char * proj_class_classname(gconstpointer object)
Return the class name of one of our managed objects.
Definition: proj_classes.c:324
const char * classname
Definition: resourcecmd.c:44
void proj_class_dissociate(gpointer object)
Dissociate an object from the C class system (typically coupled with freeing it). ...
Definition: proj_classes.c:228
void proj_class_free(gpointer object)
Free a registered object from our class system.
Definition: proj_classes.c:249
gchar *(* toString)(gconstpointer)
Produce malloc-ed string representation.
Definition: assimobj.h:58
void proj_class_dump_live_objects(void)
Dump all live C class objects (address and Class)
Definition: proj_classes.c:356
gpointer proj_class_new(gsize objsize, const char *static_classname)
Malloc a new object and register it in our class system.
Definition: proj_classes.c:214
#define CASTTOCLASS(Cclass, obj)
Safely cast 'obj' to C-class 'class' - verifying that it was registerd as being of type class ...
Definition: proj_classes.h:66
void proj_class_debug_dump(const char *prefix, const AssimObj *obj, const char *suffix)
Send the object in question to g_debug() for printing...
Definition: proj_classes.c:382
void proj_class_quark_add_superclass_relationship(GQuark superclass, GQuark subclass)
Register a superclass/subclass relationship in our type system (using Quarks of the classes)) ...
Definition: proj_classes.c:333