Thing.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /* Thing.cpp
  2. *
  3. * Copyright (C) 1992-2012,2015,2017,2018 Paul Boersma
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <stdarg.h>
  19. #include <time.h>
  20. #include "Thing.h"
  21. integer theTotalNumberOfThings;
  22. void structThing :: v_info ()
  23. {
  24. MelderInfo_writeLine (U"Object type: ", Thing_className (this));
  25. MelderInfo_writeLine (U"Object name: ", this -> name ? this -> name.get() : U"<no name>");
  26. time_t today = time (nullptr);
  27. MelderInfo_writeLine (U"Date: ", Melder_peek8to32 (ctime (& today))); // includes a newline
  28. }
  29. /*
  30. * Instead of the Thing_implement macro.
  31. */
  32. struct structClassInfo theClassInfo_Thing = {
  33. U"Thing",
  34. nullptr, // no parent class
  35. sizeof (class structThing),
  36. nullptr, // no _new function (not needed, because Thing is never instantiated)
  37. 0, // version
  38. 0, // sequentialUniqueIdOfReadableClass
  39. nullptr // dummyObject
  40. };
  41. ClassInfo classThing = & theClassInfo_Thing;
  42. conststring32 Thing_className (Thing me) { return my classInfo -> className; }
  43. autoThing Thing_newFromClass (ClassInfo classInfo) {
  44. autoThing me { classInfo };
  45. trace (U"created ", classInfo -> className);
  46. theTotalNumberOfThings += 1;
  47. my classInfo = classInfo;
  48. Melder_assert (! my name); // confirm that _new called calloc, so that we see null pointers
  49. if (Melder_debug == 40)
  50. Melder_casual (U"created ", classInfo -> className, U" (", Melder_pointer (classInfo), U", ", me.get(), U")");
  51. return me;
  52. }
  53. static integer theNumberOfReadableClasses = 0;
  54. static ClassInfo theReadableClasses [1 + 1000];
  55. static void _Thing_addOneReadableClass (ClassInfo readableClass) {
  56. if (++ theNumberOfReadableClasses > 1000)
  57. Melder_fatal (U"(Thing_recognizeClassesByName:) Too many (1001) readable classes.");
  58. theReadableClasses [theNumberOfReadableClasses] = readableClass;
  59. readableClass -> sequentialUniqueIdOfReadableClass = theNumberOfReadableClasses;
  60. }
  61. void Thing_recognizeClassesByName (ClassInfo readableClass, ...) {
  62. va_list arg;
  63. if (! readableClass) return;
  64. va_start (arg, readableClass);
  65. _Thing_addOneReadableClass (readableClass);
  66. ClassInfo klas;
  67. while ((klas = va_arg (arg, ClassInfo)) != nullptr) {
  68. _Thing_addOneReadableClass (klas);
  69. }
  70. va_end (arg);
  71. }
  72. integer Thing_listReadableClasses () {
  73. Melder_clearInfo ();
  74. MelderInfo_open ();
  75. for (integer iclass = 1; iclass <= theNumberOfReadableClasses; iclass ++) {
  76. ClassInfo klas = theReadableClasses [iclass];
  77. MelderInfo_writeLine (klas -> sequentialUniqueIdOfReadableClass, U"\t", klas -> className);
  78. }
  79. MelderInfo_close ();
  80. return theNumberOfReadableClasses;
  81. }
  82. static integer theNumberOfAliases = 0;
  83. static struct {
  84. ClassInfo readableClass;
  85. conststring32 otherName;
  86. } theAliases [1 + 100];
  87. void Thing_recognizeClassByOtherName (ClassInfo readableClass, conststring32 otherName) {
  88. theAliases [++ theNumberOfAliases]. readableClass = readableClass;
  89. theAliases [theNumberOfAliases]. otherName = otherName;
  90. }
  91. ClassInfo Thing_classFromClassName (conststring32 klas, int *out_formatVersion) {
  92. static char32 buffer [1+100];
  93. str32ncpy (buffer, klas ? klas : U"", 100);
  94. buffer [100] = U'\0';
  95. char32 *space = str32chr (buffer, U' ');
  96. if (space) {
  97. *space = U'\0'; // strip version number
  98. if (out_formatVersion) *out_formatVersion = Melder_atoi (space + 1);
  99. } else {
  100. if (out_formatVersion) *out_formatVersion = 0;
  101. }
  102. /*
  103. * First try the class names that were registered with Thing_recognizeClassesByName.
  104. */
  105. for (integer i = 1; i <= theNumberOfReadableClasses; i ++) {
  106. ClassInfo classInfo = theReadableClasses [i];
  107. if (str32equ (buffer, classInfo -> className)) {
  108. return classInfo;
  109. }
  110. }
  111. /*
  112. * Then try the aliases that were registered with Thing_recognizeClassByOtherName.
  113. */
  114. for (integer i = 1; i <= theNumberOfAliases; i ++) {
  115. if (str32equ (buffer, theAliases [i]. otherName)) {
  116. ClassInfo classInfo = theAliases [i]. readableClass;
  117. return classInfo;
  118. }
  119. }
  120. Melder_throw (U"Class \"", buffer, U"\" not recognized.");
  121. }
  122. autoThing Thing_newFromClassName (conststring32 className, int *out_formatVersion) {
  123. try {
  124. ClassInfo classInfo = Thing_classFromClassName (className, out_formatVersion);
  125. return Thing_newFromClass (classInfo);
  126. } catch (MelderError) {
  127. Melder_throw (className, U" not created.");
  128. }
  129. }
  130. Thing _Thing_dummyObject (ClassInfo classInfo) {
  131. if (! classInfo -> dummyObject) {
  132. classInfo -> dummyObject = classInfo -> _new ();
  133. }
  134. Melder_assert (classInfo -> dummyObject);
  135. return classInfo -> dummyObject;
  136. }
  137. void _Thing_forget_nozero (Thing me) {
  138. if (! me) return;
  139. if (Melder_debug == 40) Melder_casual (U"destroying ", my classInfo -> className);
  140. //Melder_casual (U"_Thing_forget_nozero before");
  141. my v_destroy ();
  142. //Melder_casual (U"_Thing_forget_nozero after");
  143. theTotalNumberOfThings -= 1;
  144. }
  145. void _Thing_forget (Thing me) {
  146. if (! me) return;
  147. if (Melder_debug == 40) Melder_casual (U"destroying ", my classInfo -> className);
  148. my v_destroy ();
  149. trace (U"destroyed ", my classInfo -> className, U" ", Melder_pointer (me));
  150. //Melder_free (me);
  151. delete me;
  152. trace (U"deleted");
  153. theTotalNumberOfThings -= 1;
  154. }
  155. bool Thing_isSubclass (ClassInfo klas, ClassInfo ancestor) {
  156. while (klas != ancestor && klas) klas = klas -> semanticParent;
  157. return !! klas;
  158. }
  159. bool Thing_isa (Thing me, ClassInfo klas) {
  160. if (! me) Melder_fatal (U"(Thing_isa:) Found null object.");
  161. return Thing_isSubclass (my classInfo, klas);
  162. }
  163. void Thing_infoWithIdAndFile (Thing me, integer id, MelderFile file) {
  164. //Melder_assert (me);
  165. Melder_clearInfo ();
  166. MelderInfo_open ();
  167. if (id != 0) MelderInfo_writeLine (U"Object id: ", id);
  168. if (! MelderFile_isNull (file)) MelderInfo_writeLine (U"Associated file: ", Melder_fileToPath (file));
  169. my v_info ();
  170. MelderInfo_close ();
  171. }
  172. void Thing_info (Thing me) {
  173. Thing_infoWithIdAndFile (me, 0, nullptr);
  174. }
  175. conststring32 Thing_getName (Thing me) { return my name.get(); }
  176. conststring32 Thing_messageName (Thing me) {
  177. static MelderString buffers [19] { };
  178. static int ibuffer = 0;
  179. if (++ ibuffer == 19) ibuffer = 0;
  180. if (my name) {
  181. MelderString_copy (& buffers [ibuffer], my classInfo -> className, U" \"", my name.get(), U"\"");
  182. } else {
  183. MelderString_copy (& buffers [ibuffer], my classInfo -> className);
  184. }
  185. return buffers [ibuffer]. string;
  186. }
  187. void Thing_setName (Thing me, conststring32 name /* cattable */) {
  188. my name = Melder_dup (name);
  189. my v_nameChanged ();
  190. }
  191. void Thing_swap (Thing me, Thing thee) {
  192. Melder_assert (my classInfo == thy classInfo);
  193. integer n = my classInfo -> size;
  194. char *p, *q;
  195. integer i;
  196. for (p = (char *) me, q = (char *) thee, i = n; i > 0; i --, p ++, q ++) {
  197. char tmp = *p;
  198. *p = *q;
  199. *q = tmp;
  200. }
  201. }
  202. /* End of file Thing.cpp */