Thing.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. #ifndef _Thing_h_
  2. #define _Thing_h_
  3. /* Thing.h
  4. *
  5. * Copyright (C) 1992-2009,2011-2018 Paul Boersma
  6. *
  7. * This code is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or (at
  10. * your option) any later version.
  11. *
  12. * This code is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. * See the GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. /* The root class of all objects. */
  21. /* Anyone who uses Thing can also use: */
  22. #include "melder.h"
  23. /* The macros for struct and class definitions: */
  24. #include "oo.h"
  25. #define _Thing_auto_DEBUG 0
  26. typedef struct structClassInfo *ClassInfo;
  27. struct structClassInfo {
  28. /*
  29. * The following five fields are statically initialized by the Thing_implement() macro.
  30. */
  31. conststring32 className;
  32. ClassInfo semanticParent;
  33. integer size;
  34. Thing (* _new) (); // objects have to be constructed via this function, because it calls C++ "new", which initializes the C++ class pointer
  35. integer version;
  36. /*
  37. * The following field is initialized by Thing_recognizeClassesByName, only for classes that have to be read (usually from disk).
  38. */
  39. integer sequentialUniqueIdOfReadableClass;
  40. /*
  41. * The following field is initialized by Thing_dummyObject(), which is used only rarely.
  42. */
  43. Thing dummyObject;
  44. };
  45. #define Thing_declare(klas) \
  46. typedef struct struct##klas *klas; \
  47. typedef autoSomeThing <struct##klas> auto##klas; \
  48. extern struct structClassInfo theClassInfo_##klas; \
  49. extern ClassInfo class##klas
  50. #define Thing_define(klas,syntacticParentKlas) \
  51. Thing_declare (klas); \
  52. typedef struct##syntacticParentKlas klas##_Parent; \
  53. struct struct##klas : public struct##syntacticParentKlas
  54. #define Thing_implement(klas,semanticParentKlas,version) \
  55. static Thing _##klas##_new () { return new struct##klas; } \
  56. struct structClassInfo theClassInfo_##klas = { U"" #klas, & theClassInfo_##semanticParentKlas, sizeof (class struct##klas), _##klas##_new, version, 0, nullptr}; \
  57. ClassInfo class##klas = & theClassInfo_##klas
  58. /*
  59. * Thing has no parent class, so instead of using the Thing_define macro
  60. * we write out the stuff that does exist.
  61. */
  62. typedef struct structThing *Thing;
  63. extern ClassInfo classThing;
  64. extern struct structClassInfo theClassInfo_Thing;
  65. struct structThing {
  66. ClassInfo classInfo; // the Praat class pointer (every object also has a C++ class pointer initialized by C++ "new")
  67. autostring32 name;
  68. void * operator new (size_t size) { return Melder_calloc (char, (int64) size); }
  69. void operator delete (void *ptr, size_t /* size */) { Melder_free (ptr); }
  70. /*
  71. * If a Thing has members of type autoThing,
  72. * then we want the destructors of autoThing to be called automatically whenever a Thing is `delete`d.
  73. * For this to happen, it is necessary that every Thing itself has a destructor.
  74. * We therefore define a destructor here,
  75. * and we make it virtual to ensure that every subclass has its own automatic version.
  76. */
  77. virtual ~structThing () noexcept { }
  78. virtual void v_destroy () noexcept { };
  79. /*
  80. * derived::v_destroy calls base::v_destroy at end
  81. */
  82. virtual void v_info ();
  83. /*
  84. * Implement as follows: call a set of MelderInfo_writeXXX describing your data.
  85. *
  86. * Thing::v_info writes object id, object name, and date;
  87. * derived::v_info often calls base::v_info at start and then writes information on the new data,
  88. * but a few ancestors can be skipped if their data have new meanings.
  89. */
  90. virtual void v_checkConstraints () { };
  91. /*
  92. * derived::v_checkConstraints typically calls base::v_checkConstraints at start
  93. */
  94. virtual void v_nameChanged () { };
  95. /*
  96. * derived::v_nameChanged may call base::_nameChanged at start, middle or end
  97. */
  98. virtual void v_copyPreferencesToInstance () { };
  99. /*
  100. * derived::v_copyPreferencesToInstance calls base::v_copyPreferencesToInstance at start
  101. */
  102. };
  103. #define forget(thing) do { _Thing_forget (thing); thing = nullptr; } while (false)
  104. /*
  105. Function:
  106. free all memory associated with 'thing'.
  107. Postcondition:
  108. thing == nullptr;
  109. */
  110. #define forget_nozero(thing) do { _Thing_forget_nozero (thing); delete thing; } while (false)
  111. /*
  112. Function:
  113. free all memory associated with 'thing'.
  114. */
  115. /* All functions with 'Thing me' as the first argument assume that it is not null. */
  116. conststring32 Thing_className (Thing me);
  117. /* Return your class name. */
  118. bool Thing_isa (Thing me, ClassInfo klas);
  119. /*
  120. return true if you are a 'klas',
  121. i.e., if you are an object of the class 'klas' or of one of the classes derived from 'klas'.
  122. E.g., Thing_isa (object, classThing) will always return true.
  123. */
  124. bool Thing_isSubclass (ClassInfo klas, ClassInfo ancestor);
  125. /*
  126. return true if <klas> is a subclass of <ancestor>,
  127. i.e., if <klas> equals <ancestor>, or if the parent class of <klas> is a subclass of <ancestor>.
  128. E.g., Thing_isSubclass (classX, classThing) will always return true.
  129. */
  130. void Thing_info (Thing me);
  131. void Thing_infoWithIdAndFile (Thing me, integer id, MelderFile file);
  132. void Thing_recognizeClassesByName (ClassInfo readableClass, ...);
  133. /*
  134. Function:
  135. make Thing_classFromClassName () and Thing_newFromClassName ()
  136. recognize a class from its name (a string).
  137. Arguments:
  138. as many classes as you want; finish with a nullptr.
  139. It is not an error if a class occurs more than once in the list.
  140. Behaviour:
  141. calling this routine more than once, each time for different classes,
  142. has the same result as calling it once for all these classes together.
  143. Thing can remember up to 1000 string-readable classes.
  144. Usage:
  145. you should call this routine for all classes that you want to read by name,
  146. e.g., with Data_readFromTextFile () or Data_readFromBinaryFile (),
  147. or with Data_readText () or Data_readBinary () if the object is a Collection.
  148. Calls to this routine should preferably be put in the beginning of main ().
  149. */
  150. void Thing_recognizeClassByOtherName (ClassInfo readableClass, conststring32 otherName);
  151. integer Thing_listReadableClasses ();
  152. ClassInfo Thing_classFromClassName (conststring32 className, int *formatVersion);
  153. /*
  154. Function:
  155. Return the class info table of class 'className', or null if it is not recognized.
  156. E.g. the value returned from Thing_classFromClassName (U"PietjePuk")
  157. will be equal to classPietjePuk.
  158. Side effect:
  159. If 'className' equals U"PietjePuk 300", the value returned will be classPietjePuk,
  160. and formatVersion (if not null) will be set to 300.
  161. */
  162. #define Thing_dummyObject(klas) \
  163. ((klas) _Thing_dummyObject (class##klas))
  164. Thing _Thing_dummyObject (ClassInfo classInfo);
  165. conststring32 Thing_getName (Thing me);
  166. /* Return a pointer to your internal name (which can be null). */
  167. conststring32 Thing_messageName (Thing me);
  168. void Thing_setName (Thing me, conststring32 name /* cattable */);
  169. /*
  170. Function:
  171. remember that you are called 'name'.
  172. Postconditions:
  173. my name *and* my name are copies of 'name'.
  174. */
  175. #define Thing_cast(Klas,var,expr) \
  176. Klas var = static_cast <Klas> (expr); /* The compiler checks this. */ \
  177. Melder_assert (! var || Thing_isa (var, class##Klas));
  178. void Thing_swap (Thing me, Thing thee);
  179. /*
  180. Function:
  181. Swap my and thy contents.
  182. Precondition:
  183. my classInfo == thy classInfo;
  184. Postconditions:
  185. my xxx == thy old xxx;
  186. thy xxx == my old xxx;
  187. Usage:
  188. Swap two objects without changing any references to them.
  189. */
  190. /* For the macros. */
  191. void _Thing_forget (Thing me);
  192. void _Thing_forget_nozero (Thing me);
  193. /* For debugging. */
  194. extern integer theTotalNumberOfThings;
  195. /* This number is 0 initially, increments at every successful `new', and decrements at every `forget'. */
  196. template <class T>
  197. class autoSomeThing {
  198. T *ptr;
  199. public:
  200. /*
  201. A default constructor, as in
  202. autoPitch pitch;
  203. should initialize the pointer to null.
  204. */
  205. autoSomeThing () : ptr (nullptr) {
  206. #if _Thing_auto_DEBUG
  207. fprintf (stderr, "default constructor\n");
  208. #endif
  209. }
  210. autoSomeThing (ClassInfo classInfo) {
  211. our ptr = classInfo -> _new ();
  212. }
  213. /*
  214. After
  215. autoPitch pitch1 = Pitch_create ();
  216. pitch1 should be destroyed when going out of scope,
  217. either at the end of the try block or whenever a throw occurs.
  218. */
  219. ~autoSomeThing () noexcept {
  220. #if _Thing_auto_DEBUG
  221. fprintf (stderr, "destructor %p %s\n",
  222. our ptr, our ptr ? Melder_peek32to8 (our ptr -> classInfo -> className) : "(class unknown)");
  223. #endif
  224. if (our ptr) {
  225. _Thing_forget (our ptr);
  226. our ptr = nullptr;
  227. }
  228. }
  229. T* get () const noexcept {
  230. return our ptr;
  231. }
  232. #if 0
  233. operator T* () const noexcept {
  234. return our ptr;
  235. }
  236. #endif
  237. /*
  238. The expression
  239. pitch.d_ptr -> xmin
  240. should be abbreviatable by
  241. pitch -> xmin
  242. */
  243. T* operator-> () const noexcept { // as r-value
  244. return our ptr;
  245. }
  246. /*
  247. T& operator* () const noexcept { // as l-value
  248. return *our ptr;
  249. }*/
  250. /*
  251. * After construction, there are two ways to access the pointer: with and without transfer of ownership.
  252. *
  253. * Without transfer:
  254. * Pitch_draw (pitch.get());
  255. *
  256. * With transfer:
  257. * return thee;
  258. * and
  259. * *out_pitch = pitch.move();
  260. * *out_pulses = pulses.move();
  261. * and
  262. * my addItem_move (pitch.move());
  263. * and
  264. * praat_new (pitch.move(), my name);
  265. */
  266. void releaseToUser () noexcept {
  267. our ptr = nullptr; // make the pointer non-automatic again
  268. }
  269. /*
  270. Sometimes ownership is determined by a flag such as _ownItems or _ownData or _ownSound.
  271. In that case, the autoThing has be adopted from a raw Thing pointer from the ambiguous owner,
  272. or released as a raw Thing pointer making the ambiguous owner responsible for destroying the object.
  273. In Praat, this happens with Collection items and with some editors.
  274. */
  275. void adoptFromAmbiguousOwner (T* newPtr) noexcept {
  276. our reset();
  277. our ptr = newPtr;
  278. }
  279. T* releaseToAmbiguousOwner () noexcept {
  280. T* temp = our ptr;
  281. our ptr = nullptr; // make the pointer non-automatic again
  282. return temp;
  283. }
  284. void reset () noexcept {
  285. _Thing_forget (our ptr);
  286. our ptr = nullptr;
  287. }
  288. void _zero () noexcept {
  289. our ptr = nullptr;
  290. }
  291. explicit operator bool () const noexcept {
  292. return !! our ptr;
  293. }
  294. bool operator== (autoSomeThing<T> other) const noexcept {
  295. return other. ptr == our ptr;
  296. }
  297. bool operator!= (autoSomeThing<T> other) const noexcept {
  298. return other. ptr != our ptr;
  299. }
  300. /*
  301. * The compiler should prevent initializations from autoSomeThing l-values, as in
  302. * autoPitch pitch2 = pitch;
  303. * This is because the syntax of this statement is *copy* syntax,
  304. * but the semantics of this statement has to be, confusingly, *move* semantics
  305. * (i.e., pitch.ptr should be set to null),
  306. * because if the semantics were copy semantics instead,
  307. * a destructor would be called at some point for both pitch and pitch2,
  308. * twice deleting the same object, which is a run-time error.
  309. */
  310. autoSomeThing<T> (const autoSomeThing<T>&) = delete; // disable copy constructor from an l-value of class T*
  311. template <class Y> autoSomeThing<T> (const autoSomeThing<Y>&) = delete; // disable copy constructor from an l-value of a descendant class of T*
  312. /*
  313. * The compiler should prevent assignments from autoSomeThing l-values, as in
  314. * pitch2 = pitch;
  315. * This is because the syntax of this statement is *copy* syntax,
  316. * but the semantics of this statement has to be, confusingly, *move* semantics
  317. * (i.e., pitch.ptr should be set to null),
  318. * because if the semantics were copy semantics instead,
  319. * a destructor would be called at some point for both pitch and pitch2,
  320. * twice deleting the same object, which is a run-time error.
  321. */
  322. autoSomeThing<T>& operator= (const autoSomeThing<T>&) = delete; // disable copy assignment from an l-value of class T*
  323. template <class Y> autoSomeThing<T>& operator= (const autoSomeThing<Y>&) = delete; // disable copy assignment from an l-value of a descendant class of T*
  324. /*
  325. * The compiler should treat initializations from autoSomeThing r-values, as in
  326. * extern autoPitch Pitch_create (...);
  327. * autoPitch pitch = Pitch_create (...);
  328. * as move constructors.
  329. */
  330. autoSomeThing<T> (autoSomeThing<T>&& other) noexcept : ptr (other. ptr) {
  331. #if _Thing_auto_DEBUG
  332. if (our ptr)
  333. fprintf (stderr, "move constructor %p from same class %s\n",
  334. our ptr, Melder_peek32to8 (our ptr -> classInfo -> className));
  335. #endif
  336. other. ptr = nullptr;
  337. }
  338. template <class Y> autoSomeThing<T> (autoSomeThing<Y>&& other) noexcept : ptr (other.get()) {
  339. #if _Thing_auto_DEBUG
  340. if (our ptr)
  341. fprintf (stderr, "move constructor %p from other class %s\n",
  342. our ptr, Melder_peek32to8 (our ptr -> classInfo -> className));
  343. #endif
  344. other. _zero();
  345. }
  346. /*
  347. * The compiler should treat assignments from autoSomeThing r-values, as in
  348. * extern autoPitch Pitch_create (...);
  349. * autoPitch pitch;
  350. * pitch = Pitch_create (...);
  351. * as move assignments.
  352. */
  353. autoSomeThing<T>& operator= (autoSomeThing<T>&& other) noexcept {
  354. if (other. ptr != our ptr) {
  355. #if _Thing_auto_DEBUG
  356. fprintf (stderr, "move assignment before %p from same class %s\n",
  357. our ptr, our ptr ? Melder_peek32to8 (our ptr -> classInfo -> className) : "(class unknown)");
  358. #endif
  359. if (our ptr) _Thing_forget (our ptr);
  360. our ptr = other. ptr;
  361. #if _Thing_auto_DEBUG
  362. fprintf (stderr, "move assignment after %p from same class %s\n",
  363. our ptr, our ptr ? Melder_peek32to8 (our ptr -> classInfo -> className) : "(class unknown)");
  364. #endif
  365. other. ptr = nullptr;
  366. }
  367. return *this;
  368. }
  369. template <class Y> autoSomeThing<T>& operator= (autoSomeThing<Y>&& other) noexcept {
  370. if (other.get() != our ptr) {
  371. #if _Thing_auto_DEBUG
  372. fprintf (stderr, "move assignment before %p from other class %s\n",
  373. our ptr, our ptr ? Melder_peek32to8 (our ptr -> classInfo -> className) : "(class unknown)");
  374. #endif
  375. if (our ptr) _Thing_forget (our ptr);
  376. our ptr = other.get();
  377. #if _Thing_auto_DEBUG
  378. fprintf (stderr, "move assignment after %p from other class %s\n",
  379. our ptr, our ptr ? Melder_peek32to8 (our ptr -> classInfo -> className) : "(class unknown)");
  380. #endif
  381. other. _zero();
  382. }
  383. return *this;
  384. }
  385. /*
  386. * Move semantics from l-values can be achieved with move syntax:
  387. * autoPitch pitch2 = pitch1.move(); // calls the move constructor and therefore nullifies pitch1
  388. *
  389. * pitch2 = pitch1.move(); // performs move assignment and therefore nullifies pitch1
  390. */
  391. autoSomeThing<T>&& move () noexcept { return static_cast <autoSomeThing<T>&&> (*this); }
  392. /*
  393. * Returning autoSomeThing from a function works as hoped for:
  394. * autoPitch Sound_to_Pitch (Sound me) {
  395. * autoPitch thee = Pitch_create (...);
  396. * ...
  397. * return thee;
  398. * }
  399. * autoPitch pitch = Sound_to_Pitch (sound);
  400. * returns a moved `thee` in `pitch`. This works because return values from automatic (i.e. non-static) variables are r-values.
  401. *
  402. * In function arguments, transfer of ownership works only explicitly:
  403. * autoPitch pitch = Pitch_create (...);
  404. * collection -> addItem_move (pitch.move()); // compiler error if you don't call move()
  405. */
  406. /*
  407. The C++ language does allow us to do
  408. Sampled sampled;
  409. Pitch pitch = static_cast <Pitch> (sampled);
  410. but not
  411. autoSampled sampled;
  412. autoPitch pitch = static_cast <autoPitch> (sampled.move());
  413. or anything like that.
  414. So we create a method that casts and moves at the same time:
  415. autoPitch pitch = sampled. static_cast_move <structPitch> ();
  416. */
  417. template <class Y> autoSomeThing<Y> static_cast_move () noexcept {
  418. T* nakedPointer_oldType = our releaseToAmbiguousOwner(); // throw the object in the air...
  419. Y* nakedPointer_newType = static_cast<Y*> (nakedPointer_oldType);
  420. autoSomeThing<Y> newObject;
  421. newObject. adoptFromAmbiguousOwner (nakedPointer_newType); // ...and catch it
  422. return newObject;
  423. }
  424. };
  425. typedef autoSomeThing<structThing> autoThing;
  426. #define Thing_new(Klas) Thing_newFromClass (class##Klas).static_cast_move<struct##Klas>()
  427. /*
  428. Function:
  429. return a new object of class 'klas'.
  430. Postconditions:
  431. result -> classInfo == class'klas';
  432. other members are 0.
  433. */
  434. autoThing Thing_newFromClass (ClassInfo klas);
  435. /*
  436. Function:
  437. return a new object of class 'klas'.
  438. Postconditions:
  439. result -> classInfo == 'klas';
  440. other members are 0.
  441. */
  442. autoThing Thing_newFromClassName (conststring32 className, int *out_formatVersion);
  443. /*
  444. Function:
  445. return a new object of class 'className', or null if the class name is not recognized.
  446. Postconditions:
  447. result -> classInfo == class'className';
  448. other members are 0.
  449. Side effect:
  450. see Thing_classFromClassName.
  451. */
  452. template <class T>
  453. class autoThingVector {
  454. autoSomeThing<T> *d_ptr;
  455. integer d_from, d_to;
  456. public:
  457. autoThingVector<T> (integer from, integer to) : d_from (from), d_to (to) {
  458. //d_ptr = reinterpret_cast <autoSomeThing<T>*> (NUMvector_ (sizeof (autoSomeThing<T>), from, to, true));
  459. d_ptr = NUMvector <autoSomeThing<T>> (from, to, true);
  460. }
  461. autoThingVector (autoSomeThing<T> *ptr, integer from, integer to) : d_ptr (ptr), d_from (from), d_to (to) {
  462. }
  463. autoThingVector () : d_ptr (nullptr), d_from (1), d_to (0) {
  464. }
  465. ~autoThingVector<T> () {
  466. if (d_ptr) {
  467. for (integer i = d_from; i <= d_to; i ++)
  468. d_ptr [i].reset();
  469. NUMvector_free (d_ptr, d_from);
  470. }
  471. }
  472. autoSomeThing<T>& operator[] (integer i) {
  473. return d_ptr [i];
  474. }
  475. autoSomeThing<T>* peek () const {
  476. return d_ptr;
  477. }
  478. /*
  479. T* transfer () {
  480. T* temp = d_ptr;
  481. d_ptr = nullptr; // make the pointer non-automatic again
  482. return temp;
  483. }
  484. void reset (integer from, integer to) {
  485. if (d_ptr) {
  486. for (integer i = d_from; i <= d_to; i ++)
  487. forget (d_ptr [i]);
  488. NUMvector_free (sizeof (T), d_ptr, d_from);
  489. d_ptr = nullptr;
  490. }
  491. d_from = from; // this assignment is safe, because d_ptr is null
  492. d_to = to;
  493. d_ptr = static_cast <T*> (NUMvector (sizeof (T), from, to));
  494. }
  495. */
  496. };
  497. /* End of file Thing.h */
  498. #endif