Skip to content

Instantly share code, notes, and snippets.

@manodeep
Created November 13, 2019 05:19
Show Gist options
  • Save manodeep/63ef78c01c82983a69cb4a3ae56309a9 to your computer and use it in GitHub Desktop.
Save manodeep/63ef78c01c82983a69cb4a3ae56309a9 to your computer and use it in GitHub Desktop.
Concatenating two sets of distinct IDs into one combined ID
/*
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