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