| 1 | |
| 2 | #include <roaring/containers/containers.h> |
| 3 | |
| 4 | extern inline const void *container_unwrap_shared( |
| 5 | const void *candidate_shared_container, uint8_t *type); |
| 6 | extern inline void *container_mutable_unwrap_shared( |
| 7 | void *candidate_shared_container, uint8_t *type); |
| 8 | |
| 9 | extern inline const char *get_container_name(uint8_t typecode); |
| 10 | |
| 11 | extern inline int container_get_cardinality(const void *container, uint8_t typecode); |
| 12 | |
| 13 | extern inline void *container_iand(void *c1, uint8_t type1, const void *c2, |
| 14 | uint8_t type2, uint8_t *result_type); |
| 15 | |
| 16 | extern inline void *container_ior(void *c1, uint8_t type1, const void *c2, |
| 17 | uint8_t type2, uint8_t *result_type); |
| 18 | |
| 19 | extern inline void *container_ixor(void *c1, uint8_t type1, const void *c2, |
| 20 | uint8_t type2, uint8_t *result_type); |
| 21 | |
| 22 | extern inline void *container_iandnot(void *c1, uint8_t type1, const void *c2, |
| 23 | uint8_t type2, uint8_t *result_type); |
| 24 | |
| 25 | void container_free(void *container, uint8_t typecode) { |
| 26 | switch (typecode) { |
| 27 | case BITSET_CONTAINER_TYPE_CODE: |
| 28 | bitset_container_free((bitset_container_t *)container); |
| 29 | break; |
| 30 | case ARRAY_CONTAINER_TYPE_CODE: |
| 31 | array_container_free((array_container_t *)container); |
| 32 | break; |
| 33 | case RUN_CONTAINER_TYPE_CODE: |
| 34 | run_container_free((run_container_t *)container); |
| 35 | break; |
| 36 | case SHARED_CONTAINER_TYPE_CODE: |
| 37 | shared_container_free((shared_container_t *)container); |
| 38 | break; |
| 39 | default: |
| 40 | assert(false); |
| 41 | __builtin_unreachable(); |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | void container_printf(const void *container, uint8_t typecode) { |
| 46 | container = container_unwrap_shared(container, &typecode); |
| 47 | switch (typecode) { |
| 48 | case BITSET_CONTAINER_TYPE_CODE: |
| 49 | bitset_container_printf((const bitset_container_t *)container); |
| 50 | return; |
| 51 | case ARRAY_CONTAINER_TYPE_CODE: |
| 52 | array_container_printf((const array_container_t *)container); |
| 53 | return; |
| 54 | case RUN_CONTAINER_TYPE_CODE: |
| 55 | run_container_printf((const run_container_t *)container); |
| 56 | return; |
| 57 | default: |
| 58 | __builtin_unreachable(); |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | void container_printf_as_uint32_array(const void *container, uint8_t typecode, |
| 63 | uint32_t base) { |
| 64 | container = container_unwrap_shared(container, &typecode); |
| 65 | switch (typecode) { |
| 66 | case BITSET_CONTAINER_TYPE_CODE: |
| 67 | bitset_container_printf_as_uint32_array( |
| 68 | (const bitset_container_t *)container, base); |
| 69 | return; |
| 70 | case ARRAY_CONTAINER_TYPE_CODE: |
| 71 | array_container_printf_as_uint32_array( |
| 72 | (const array_container_t *)container, base); |
| 73 | return; |
| 74 | case RUN_CONTAINER_TYPE_CODE: |
| 75 | run_container_printf_as_uint32_array( |
| 76 | (const run_container_t *)container, base); |
| 77 | return; |
| 78 | return; |
| 79 | default: |
| 80 | __builtin_unreachable(); |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | int32_t container_serialize(const void *container, uint8_t typecode, |
| 85 | char *buf) { |
| 86 | container = container_unwrap_shared(container, &typecode); |
| 87 | switch (typecode) { |
| 88 | case BITSET_CONTAINER_TYPE_CODE: |
| 89 | return (bitset_container_serialize((const bitset_container_t *)container, |
| 90 | buf)); |
| 91 | case ARRAY_CONTAINER_TYPE_CODE: |
| 92 | return ( |
| 93 | array_container_serialize((const array_container_t *)container, buf)); |
| 94 | case RUN_CONTAINER_TYPE_CODE: |
| 95 | return (run_container_serialize((const run_container_t *)container, buf)); |
| 96 | default: |
| 97 | assert(0); |
| 98 | __builtin_unreachable(); |
| 99 | return (-1); |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | uint32_t container_serialization_len(const void *container, uint8_t typecode) { |
| 104 | container = container_unwrap_shared(container, &typecode); |
| 105 | switch (typecode) { |
| 106 | case BITSET_CONTAINER_TYPE_CODE: |
| 107 | return bitset_container_serialization_len(); |
| 108 | case ARRAY_CONTAINER_TYPE_CODE: |
| 109 | return array_container_serialization_len( |
| 110 | (const array_container_t *)container); |
| 111 | case RUN_CONTAINER_TYPE_CODE: |
| 112 | return run_container_serialization_len( |
| 113 | (const run_container_t *)container); |
| 114 | default: |
| 115 | assert(0); |
| 116 | __builtin_unreachable(); |
| 117 | return (0); |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | void *container_deserialize(uint8_t typecode, const char *buf, size_t buf_len) { |
| 122 | switch (typecode) { |
| 123 | case BITSET_CONTAINER_TYPE_CODE: |
| 124 | return (bitset_container_deserialize(buf, buf_len)); |
| 125 | case ARRAY_CONTAINER_TYPE_CODE: |
| 126 | return (array_container_deserialize(buf, buf_len)); |
| 127 | case RUN_CONTAINER_TYPE_CODE: |
| 128 | return (run_container_deserialize(buf, buf_len)); |
| 129 | case SHARED_CONTAINER_TYPE_CODE: |
| 130 | printf("this should never happen.\n" ); |
| 131 | assert(0); |
| 132 | __builtin_unreachable(); |
| 133 | return (NULL); |
| 134 | default: |
| 135 | assert(0); |
| 136 | __builtin_unreachable(); |
| 137 | return (NULL); |
| 138 | } |
| 139 | } |
| 140 | |
| 141 | extern inline bool container_nonzero_cardinality(const void *container, |
| 142 | uint8_t typecode); |
| 143 | |
| 144 | |
| 145 | extern inline int container_to_uint32_array(uint32_t *output, const void *container, |
| 146 | uint8_t typecode, uint32_t base); |
| 147 | |
| 148 | extern inline void *container_add(void *container, uint16_t val, uint8_t typecode, |
| 149 | uint8_t *new_typecode); |
| 150 | |
| 151 | extern inline bool container_contains(const void *container, uint16_t val, |
| 152 | uint8_t typecode); |
| 153 | |
| 154 | extern inline void *container_clone(const void *container, uint8_t typecode); |
| 155 | |
| 156 | extern inline void *container_and(const void *c1, uint8_t type1, const void *c2, |
| 157 | uint8_t type2, uint8_t *result_type); |
| 158 | |
| 159 | extern inline void *container_or(const void *c1, uint8_t type1, const void *c2, |
| 160 | uint8_t type2, uint8_t *result_type); |
| 161 | |
| 162 | extern inline void *container_xor(const void *c1, uint8_t type1, const void *c2, |
| 163 | uint8_t type2, uint8_t *result_type); |
| 164 | |
| 165 | void *get_copy_of_container(void *container, uint8_t *typecode, |
| 166 | bool copy_on_write) { |
| 167 | if (copy_on_write) { |
| 168 | shared_container_t *shared_container; |
| 169 | if (*typecode == SHARED_CONTAINER_TYPE_CODE) { |
| 170 | shared_container = (shared_container_t *)container; |
| 171 | shared_container->counter += 1; |
| 172 | return shared_container; |
| 173 | } |
| 174 | assert(*typecode != SHARED_CONTAINER_TYPE_CODE); |
| 175 | |
| 176 | if ((shared_container = (shared_container_t *)malloc( |
| 177 | sizeof(shared_container_t))) == NULL) { |
| 178 | return NULL; |
| 179 | } |
| 180 | |
| 181 | shared_container->container = container; |
| 182 | shared_container->typecode = *typecode; |
| 183 | |
| 184 | shared_container->counter = 2; |
| 185 | *typecode = SHARED_CONTAINER_TYPE_CODE; |
| 186 | |
| 187 | return shared_container; |
| 188 | } // copy_on_write |
| 189 | // otherwise, no copy on write... |
| 190 | const void *actualcontainer = |
| 191 | container_unwrap_shared((const void *)container, typecode); |
| 192 | assert(*typecode != SHARED_CONTAINER_TYPE_CODE); |
| 193 | return container_clone(actualcontainer, *typecode); |
| 194 | } |
| 195 | /** |
| 196 | * Copies a container, requires a typecode. This allocates new memory, caller |
| 197 | * is responsible for deallocation. |
| 198 | */ |
| 199 | void *container_clone(const void *container, uint8_t typecode) { |
| 200 | container = container_unwrap_shared(container, &typecode); |
| 201 | switch (typecode) { |
| 202 | case BITSET_CONTAINER_TYPE_CODE: |
| 203 | return bitset_container_clone((const bitset_container_t *)container); |
| 204 | case ARRAY_CONTAINER_TYPE_CODE: |
| 205 | return array_container_clone((const array_container_t *)container); |
| 206 | case RUN_CONTAINER_TYPE_CODE: |
| 207 | return run_container_clone((const run_container_t *)container); |
| 208 | case SHARED_CONTAINER_TYPE_CODE: |
| 209 | printf("shared containers are not cloneable\n" ); |
| 210 | assert(false); |
| 211 | return NULL; |
| 212 | default: |
| 213 | assert(false); |
| 214 | __builtin_unreachable(); |
| 215 | return NULL; |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | void *(shared_container_t *container, |
| 220 | uint8_t *typecode) { |
| 221 | assert(container->counter > 0); |
| 222 | assert(container->typecode != SHARED_CONTAINER_TYPE_CODE); |
| 223 | container->counter--; |
| 224 | *typecode = container->typecode; |
| 225 | void *answer; |
| 226 | if (container->counter == 0) { |
| 227 | answer = container->container; |
| 228 | container->container = NULL; // paranoid |
| 229 | free(container); |
| 230 | } else { |
| 231 | answer = container_clone(container->container, *typecode); |
| 232 | } |
| 233 | assert(*typecode != SHARED_CONTAINER_TYPE_CODE); |
| 234 | return answer; |
| 235 | } |
| 236 | |
| 237 | void shared_container_free(shared_container_t *container) { |
| 238 | assert(container->counter > 0); |
| 239 | container->counter--; |
| 240 | if (container->counter == 0) { |
| 241 | assert(container->typecode != SHARED_CONTAINER_TYPE_CODE); |
| 242 | container_free(container->container, container->typecode); |
| 243 | container->container = NULL; // paranoid |
| 244 | free(container); |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | extern inline void *container_not(const void *c1, uint8_t type1, uint8_t *result_type); |
| 249 | |
| 250 | extern inline void *container_not_range(const void *c1, uint8_t type1, |
| 251 | uint32_t range_start, uint32_t range_end, |
| 252 | uint8_t *result_type); |
| 253 | |
| 254 | extern inline void *container_inot(void *c1, uint8_t type1, uint8_t *result_type); |
| 255 | |
| 256 | extern inline void *container_inot_range(void *c1, uint8_t type1, uint32_t range_start, |
| 257 | uint32_t range_end, uint8_t *result_type); |
| 258 | |
| 259 | extern inline void *container_range_of_ones(uint32_t range_start, uint32_t range_end, |
| 260 | uint8_t *result_type); |
| 261 | |
| 262 | // where are the correponding things for union and intersection?? |
| 263 | extern inline void *container_lazy_xor(const void *c1, uint8_t type1, const void *c2, |
| 264 | uint8_t type2, uint8_t *result_type); |
| 265 | |
| 266 | extern inline void *container_lazy_ixor(void *c1, uint8_t type1, const void *c2, |
| 267 | uint8_t type2, uint8_t *result_type); |
| 268 | |
| 269 | extern inline void *container_andnot(const void *c1, uint8_t type1, const void *c2, |
| 270 | uint8_t type2, uint8_t *result_type); |
| 271 | |