polymorphism.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #ifndef POLYMORPHISM_H
  2. #define POLYMORPHISM_H
  3. /* Macros to declare inheriting types, and to (down-)cast and up-cast. */
  4. #define DERIVE_FROM_TYPE(t) t t##_parent
  5. #define STATIC_CAST(to, obj) (&(obj)->to##_parent)
  6. #ifdef __GNUC__
  7. #define STATIC_UPCAST(to, from, obj) __extension__({ \
  8. static_assert(__builtin_types_compatible_p(from, __typeof(*(obj))), \
  9. "Invalid upcast object from type"); \
  10. (to*)((char*)(obj) - offsetof(to, from##_parent)); \
  11. })
  12. #else
  13. #define STATIC_UPCAST(to, from, obj) ((to*)((char*)(obj) - offsetof(to, from##_parent)))
  14. #endif
  15. /* Defines method forwards, which call the given parent's (T2's) implementation. */
  16. #define DECLARE_FORWARD(T1, T2, rettype, func) \
  17. rettype T1##_##func(T1 *obj) \
  18. { return T2##_##func(STATIC_CAST(T2, obj)); }
  19. #define DECLARE_FORWARD1(T1, T2, rettype, func, argtype1) \
  20. rettype T1##_##func(T1 *obj, argtype1 a) \
  21. { return T2##_##func(STATIC_CAST(T2, obj), a); }
  22. #define DECLARE_FORWARD2(T1, T2, rettype, func, argtype1, argtype2) \
  23. rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b) \
  24. { return T2##_##func(STATIC_CAST(T2, obj), a, b); }
  25. #define DECLARE_FORWARD3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \
  26. rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b, argtype3 c) \
  27. { return T2##_##func(STATIC_CAST(T2, obj), a, b, c); }
  28. /* Defines method thunks, functions that call to the child's method. */
  29. #define DECLARE_THUNK(T1, T2, rettype, func) \
  30. static rettype T1##_##T2##_##func(T2 *obj) \
  31. { return T1##_##func(STATIC_UPCAST(T1, T2, obj)); }
  32. #define DECLARE_THUNK1(T1, T2, rettype, func, argtype1) \
  33. static rettype T1##_##T2##_##func(T2 *obj, argtype1 a) \
  34. { return T1##_##func(STATIC_UPCAST(T1, T2, obj), a); }
  35. #define DECLARE_THUNK2(T1, T2, rettype, func, argtype1, argtype2) \
  36. static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b) \
  37. { return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b); }
  38. #define DECLARE_THUNK3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \
  39. static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c) \
  40. { return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c); }
  41. #define DECLARE_THUNK4(T1, T2, rettype, func, argtype1, argtype2, argtype3, argtype4) \
  42. static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c, argtype4 d) \
  43. { return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c, d); }
  44. /* Defines the default functions used to (de)allocate a polymorphic object. */
  45. #define DECLARE_DEFAULT_ALLOCATORS(T) \
  46. static void* T##_New(size_t size) { return al_malloc(16, size); } \
  47. static void T##_Delete(void *ptr) { al_free(ptr); }
  48. /* Helper to extract an argument list for virtual method calls. */
  49. #define EXTRACT_VCALL_ARGS(...) __VA_ARGS__))
  50. /* Call a "virtual" method on an object, with arguments. */
  51. #define V(obj, func) ((obj)->vtbl->func((obj), EXTRACT_VCALL_ARGS
  52. /* Call a "virtual" method on an object, with no arguments. */
  53. #define V0(obj, func) ((obj)->vtbl->func((obj) EXTRACT_VCALL_ARGS
  54. /* Helper to extract an argument list for NEW_OBJ calls. */
  55. #define EXTRACT_NEW_ARGS(...) __VA_ARGS__); \
  56. } \
  57. } while(0)
  58. /* Allocate and construct an object, with arguments. */
  59. #define NEW_OBJ(_res, T) do { \
  60. _res = T##_New(sizeof(T)); \
  61. if(_res) \
  62. { \
  63. memset(_res, 0, sizeof(T)); \
  64. T##_Construct(_res, EXTRACT_NEW_ARGS
  65. /* Allocate and construct an object, with no arguments. */
  66. #define NEW_OBJ0(_res, T) do { \
  67. _res = T##_New(sizeof(T)); \
  68. if(_res) \
  69. { \
  70. memset(_res, 0, sizeof(T)); \
  71. T##_Construct(_res EXTRACT_NEW_ARGS
  72. /* Destructs and deallocate an object. */
  73. #define DELETE_OBJ(obj) do { \
  74. if((obj) != NULL) \
  75. { \
  76. V0((obj),Destruct)(); \
  77. V0((obj),Delete)(); \
  78. } \
  79. } while(0)
  80. /* Helper to get a type's vtable thunk for a child type. */
  81. #define GET_VTABLE2(T1, T2) (&(T1##_##T2##_vtable))
  82. /* Helper to set an object's vtable thunk for a child type. Used when constructing an object. */
  83. #define SET_VTABLE2(T1, T2, obj) (STATIC_CAST(T2, obj)->vtbl = GET_VTABLE2(T1, T2))
  84. #endif /* POLYMORPHISM_H */