Created
November 13, 2019 05:19
-
-
Save manodeep/63ef78c01c82983a69cb4a3ae56309a9 to your computer and use it in GitHub Desktop.
Concatenating two sets of distinct IDs into one combined ID
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Author: Manodeep Sinha | |
Date: 13th Nov, 2019 | |
Purpose: For the Uchuu collaboration | |
*** The code combines two distinct ids into one (32 bit or 64 bit) ID using bitshifts, and a bitwise OR *** | |
- Define the macro "USE_64BITS" to work with 64 bits for destination size of the combined ID. If "USE_64BITS" | |
is undefined, then the destination size will be 32 bits. | |
- The convention is the value for "HALOID" goes into the low "HALO_ID_NBITS", and then is followed by "FILE_ID_NBITS" | |
corresponding to the value of "FILEID". | |
- Compile with `gcc/clang -std=c99 -Wall -Wextra test_id_concat.c -Wno-unused-local-typedef -O3 -march=native`. The | |
code is reasonably safe, but not fully production-quality. | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <limits.h> | |
#include <stdint.h> | |
#include <inttypes.h> | |
#define USE_64BITS | |
#ifdef USE_64BITS | |
#define TARGET_DTYPE uint64_t | |
#define TARGET_FMT PRIu64 | |
#define HALO_ID_NBITS 51ULL | |
#define FILE_ID_NBITS 13ULL | |
#else | |
#define TARGET_DTYPE uint32_t | |
#define TARGET_FMT PRIu32 | |
#define HALO_ID_NBITS 21ULL | |
#define FILE_ID_NBITS 11ULL | |
#endif | |
#define BUILD_BUG_OR_ZERO(cond, msg) typedef volatile char assertion_on_##msg[( !!(cond) )*2-1 ] | |
#define PRINT_BINARY(name) { \ | |
fprintf(stderr, #name " in binary = "); \ | |
printBits(sizeof(name), (void *) &name); \ | |
fprintf(stderr, "\n"); \ | |
} | |
//Taken from: https://stackoverflow.com/questions/111928/is-there-a-printf-converter-to-print-in-binary-format | |
void printBits(size_t const size, void const * const ptr) | |
{ | |
unsigned char *b = (unsigned char*) ptr; | |
fprintf(stderr,"0b"); | |
for (int64_t i=size-1;i>=0;i--) { | |
for (int64_t j=7;j>=0;j--) { | |
unsigned char byte = (b[i] >> j) & 1; | |
fprintf(stderr, "%u", byte); | |
} | |
} | |
fprintf(stderr, " "); | |
} | |
TARGET_DTYPE generate_combined_id(const TARGET_DTYPE fileid, const TARGET_DTYPE haloid, const uint8_t file_id_nbits, const uint8_t halo_id_nbits) | |
{ | |
const uint8_t sum_bits = file_id_nbits + halo_id_nbits; | |
if(sum_bits > sizeof(TARGET_DTYPE) * CHAR_BIT) { | |
fprintf(stderr,"Error: (file_id_nbits=%d) + (halo_id_nbits=%d) = %d should be less than %zu\n", | |
file_id_nbits, halo_id_nbits, sum_bits, sizeof(TARGET_DTYPE)*CHAR_BIT); | |
exit(EXIT_FAILURE); | |
} | |
#define CHECK_FOR_ID_IN_RANGE(id, nbits, name) { \ | |
const TARGET_DTYPE allowed_mask = (1ULL << nbits) - 1; \ | |
if(id > allowed_mask) { \ | |
fprintf(stderr,"Error: For %sID = %"TARGET_FMT" does not fit into %u bits. Max. allowed value = %"TARGET_FMT"\n", \ | |
name, id, nbits, allowed_mask); \ | |
exit(EXIT_FAILURE); \ | |
} \ | |
} | |
CHECK_FOR_ID_IN_RANGE(fileid, file_id_nbits, "file"); | |
CHECK_FOR_ID_IN_RANGE(haloid, halo_id_nbits, "halo"); | |
#undef CHECK_FOR_ID_IN_RANGE | |
const TARGET_DTYPE fileid_zero_high_bits = fileid & ((1ULL << file_id_nbits) - 1); | |
const TARGET_DTYPE haloid_zero_high_bits = haloid & ((1ULL << halo_id_nbits) - 1); | |
const TARGET_DTYPE haloid_shifted_bits = haloid_zero_high_bits << 0; | |
const TARGET_DTYPE fileid_shifted_bits = fileid_zero_high_bits << halo_id_nbits; | |
if((haloid_shifted_bits & fileid_shifted_bits) != 0) { | |
fprintf(stderr,"Error: There seems to be common set bits between the shifted haloid and shifted fileid\n"); | |
PRINT_BINARY(haloid_shifted_bits); | |
PRINT_BINARY(fileid_shifted_bits); | |
exit(EXIT_FAILURE); | |
} | |
const TARGET_DTYPE combined_id = haloid_zero_high_bits + fileid_shifted_bits; | |
return combined_id; | |
} | |
int return_ids_from_combined_id(const TARGET_DTYPE combined_id, const uint8_t file_id_nbits, const uint8_t halo_id_nbits, TARGET_DTYPE *fileid, TARGET_DTYPE *haloid) | |
{ | |
const uint8_t sum_bits = file_id_nbits + halo_id_nbits; | |
if(sum_bits > sizeof(TARGET_DTYPE) * CHAR_BIT) { | |
fprintf(stderr,"Error: (file_id_nbits=%d) + (halo_id_nbits=%d) = %d should be less than %zu\n", | |
file_id_nbits, halo_id_nbits, sum_bits, sizeof(TARGET_DTYPE) * CHAR_BIT); | |
return EXIT_FAILURE; | |
} | |
const TARGET_DTYPE halo_id_mask = (1ULL << HALO_ID_NBITS) - 1; | |
const TARGET_DTYPE file_id_mask = ((1ULL << FILE_ID_NBITS) - 1) << HALO_ID_NBITS; | |
*fileid = (combined_id & file_id_mask) >> HALO_ID_NBITS; | |
*haloid = combined_id & halo_id_mask; | |
return EXIT_SUCCESS; | |
} | |
int test_scheme(void) | |
{ | |
const TARGET_DTYPE halo_id_mask = (1ULL << HALO_ID_NBITS) - 1; | |
const TARGET_DTYPE file_id_mask = ((1ULL << FILE_ID_NBITS) - 1) << HALO_ID_NBITS; | |
const TARGET_DTYPE tota_id_mask = halo_id_mask + file_id_mask; | |
PRINT_BINARY(halo_id_mask); | |
PRINT_BINARY(file_id_mask); | |
PRINT_BINARY(tota_id_mask); | |
const TARGET_DTYPE max_haloid = halo_id_mask; | |
const TARGET_DTYPE max_fileid = (1ULL << FILE_ID_NBITS) - 1; | |
const TARGET_DTYPE combined_id = generate_combined_id(max_fileid, max_haloid, FILE_ID_NBITS, HALO_ID_NBITS); | |
if(combined_id != (TARGET_DTYPE) (-1)) { | |
fprintf(stderr,"combined_id = %"TARGET_FMT" is not equal to %"TARGET_FMT"\n", combined_id, (TARGET_DTYPE) -1); | |
return EXIT_FAILURE; | |
} | |
fprintf(stderr,"\nTesting ALL possible fileids with max. haloid\n"); | |
for(TARGET_DTYPE fileid=0;fileid<max_fileid;fileid++) { | |
const TARGET_DTYPE combined_id = generate_combined_id(fileid, max_haloid, FILE_ID_NBITS, HALO_ID_NBITS); | |
TARGET_DTYPE recovered_fileid, recovered_haloid; | |
int status = return_ids_from_combined_id(combined_id, FILE_ID_NBITS, HALO_ID_NBITS, &recovered_fileid, &recovered_haloid); | |
if(status != EXIT_SUCCESS) { | |
return status; | |
} | |
if((recovered_fileid != fileid) || (recovered_haloid != max_haloid)) { | |
fprintf(stderr,"Error: Either, recovered_fileid = %"TARGET_FMT" is not equal to fileid = %" TARGET_FMT " or\n" | |
"recovered haloid = %"TARGET_FMT " is not equal to haloid = %" TARGET_FMT "\n", | |
recovered_fileid, fileid, | |
recovered_haloid, max_haloid); | |
return EXIT_FAILURE; | |
} | |
} | |
fprintf(stderr,"Testing ALL possible fileids with max. haloid...PASSED\n"); | |
#ifdef USE_64BITS | |
fprintf(stderr,"Not running any more tests for 64 bits\n"); | |
#else | |
fprintf(stderr,"\nTesting all possible combinations for 32 bits\n"); | |
for(TARGET_DTYPE fileid=0;fileid<=max_fileid;fileid++) { | |
for(TARGET_DTYPE haloid=0;haloid<=max_haloid;haloid++) { | |
TARGET_DTYPE combined_id = generate_combined_id(fileid, haloid, FILE_ID_NBITS, HALO_ID_NBITS); | |
TARGET_DTYPE recovered_fileid, recovered_haloid; | |
int status = return_ids_from_combined_id(combined_id, FILE_ID_NBITS, HALO_ID_NBITS, &recovered_fileid, &recovered_haloid); | |
if(status != EXIT_SUCCESS) { | |
return status; | |
} | |
if((recovered_fileid != fileid) || (recovered_haloid != haloid)) { | |
fprintf(stderr,"Error: Either, recovered_fileid = %"TARGET_FMT" is not equal to fileid = %"TARGET_FMT" or\n" | |
"recovered haloid = %"TARGET_FMT " is not equal to haloid = %"TARGET_FMT"\n", | |
recovered_fileid, fileid, | |
recovered_haloid, haloid); | |
return EXIT_FAILURE; | |
} | |
} | |
} | |
fprintf(stderr,"Testing all possible combinations for 32 bits...PASSED\n"); | |
#endif | |
return EXIT_SUCCESS; | |
} | |
int main(int argc, char **argv) | |
{ | |
(void) argc, (void) argv; | |
BUILD_BUG_OR_ZERO((HALO_ID_NBITS + FILE_ID_NBITS) <= sizeof(TARGET_DTYPE)*CHAR_BIT, sum_of_file_and_halo_id_bits_must_be_within_64_bits); | |
BUILD_BUG_OR_ZERO(HALO_ID_NBITS > 0 && HALO_ID_NBITS < 64, halo_id_bits_must_be_nonzero_and_less_than_64); | |
BUILD_BUG_OR_ZERO(FILE_ID_NBITS > 0 && FILE_ID_NBITS < 64, file_id_bits_must_be_nonzero_and_less_than_64); | |
int status = test_scheme(); | |
return status; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment