container_defs.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /*
  2. * container_defs.h
  3. *
  4. * Unlike containers.h (which is a file aggregating all the container includes,
  5. * like array.h, bitset.h, and run.h) this is a file included BY those headers
  6. * to do things like define the container base class `container_t`.
  7. */
  8. #ifndef INCLUDE_CONTAINERS_CONTAINER_DEFS_H_
  9. #define INCLUDE_CONTAINERS_CONTAINER_DEFS_H_
  10. #ifdef __cplusplus
  11. #include <type_traits> // used by casting helper for compile-time check
  12. #endif
  13. // The preferences are a separate file to separate out tweakable parameters
  14. #include <roaring/containers/perfparameters.h>
  15. #ifdef __cplusplus
  16. namespace roaring {
  17. namespace internal { // No extern "C" (contains template)
  18. #endif
  19. /*
  20. * Since roaring_array_t's definition is not opaque, the container type is
  21. * part of the API. If it's not going to be `void*` then it needs a name, and
  22. * expectations are to prefix C library-exported names with `roaring_` etc.
  23. *
  24. * Rather than force the whole codebase to use the name `roaring_container_t`,
  25. * the few API appearances use the macro ROARING_CONTAINER_T. Those includes
  26. * are prior to containers.h, so make a short private alias of `container_t`.
  27. * Then undefine the awkward macro so it's not used any more than it has to be.
  28. */
  29. typedef ROARING_CONTAINER_T container_t;
  30. #undef ROARING_CONTAINER_T
  31. /*
  32. * See ROARING_CONTAINER_T for notes on using container_t as a base class.
  33. * This macro helps make the following pattern look nicer:
  34. *
  35. * #ifdef __cplusplus
  36. * struct roaring_array_s : public container_t {
  37. * #else
  38. * struct roaring_array_s {
  39. * #endif
  40. * int32_t cardinality;
  41. * int32_t capacity;
  42. * uint16_t *array;
  43. * }
  44. */
  45. #if defined(__cplusplus)
  46. #define STRUCT_CONTAINER(name) struct name : public container_t /* { ... } */
  47. #else
  48. #define STRUCT_CONTAINER(name) struct name /* { ... } */
  49. #endif
  50. /**
  51. * Since container_t* is not void* in C++, "dangerous" casts are not needed to
  52. * downcast; only a static_cast<> is needed. Define a macro for static casting
  53. * which helps make casts more visible, and catches problems at compile-time
  54. * when building the C sources in C++ mode:
  55. *
  56. * void some_func(container_t **c, ...) { // double pointer, not single
  57. * array_container_t *ac1 = (array_container_t *)(c); // uncaught!!
  58. *
  59. * array_container_t *ac2 = CAST(array_container_t *, c) // C++ errors
  60. * array_container_t *ac3 = CAST_array(c); // shorthand for #2, errors
  61. * }
  62. *
  63. * Trickier to do is a cast from `container**` to `array_container_t**`. This
  64. * needs a reinterpret_cast<>, which sacrifices safety...so a template is used
  65. * leveraging <type_traits> to make sure it's legal in the C++ build.
  66. */
  67. #ifdef __cplusplus
  68. #define CAST(type, value) static_cast<type>(value)
  69. #define movable_CAST(type, value) movable_CAST_HELPER<type>(value)
  70. template <typename PPDerived, typename Base>
  71. PPDerived movable_CAST_HELPER(Base **ptr_to_ptr) {
  72. typedef typename std::remove_pointer<PPDerived>::type PDerived;
  73. typedef typename std::remove_pointer<PDerived>::type Derived;
  74. static_assert(std::is_base_of<Base, Derived>::value,
  75. "use movable_CAST() for container_t** => xxx_container_t**");
  76. return reinterpret_cast<Derived **>(ptr_to_ptr);
  77. }
  78. #else
  79. #define CAST(type, value) ((type)value)
  80. #define movable_CAST(type, value) ((type)value)
  81. #endif
  82. // Use for converting e.g. an `array_container_t**` to a `container_t**`
  83. //
  84. #define movable_CAST_base(c) movable_CAST(container_t **, c)
  85. #ifdef __cplusplus
  86. }
  87. } // namespace roaring { namespace internal {
  88. #endif
  89. #endif /* INCLUDE_CONTAINERS_CONTAINER_DEFS_H_ */