Line data Source code
1 : /* Declare a header-only API for fast manipulation of versioned offsets. 2 : These are useful building blocks of interprocess lockfree algorithms. 3 : The (ver,off) pair itself is represented in an atomic operation 4 : friendly primitive unsigned integer type. Example: 5 : 6 : #define VOFF_NAME my_voff 7 : #include "util/tmpl/fd_voff.c" 8 : 9 : will declare the following in the compile unit: 10 : 11 : typedef ulong my_voff_t; 12 : 13 : enum { 14 : my_voff_VER_WIDTH = 20, 15 : my_voff_OFF_WIDTH = 44 16 : }; 17 : 18 : int my_voff_ver_width( void ); // return the version bit width (20) 19 : int my_voff_off_width( void ); // return the offset bit width (44) 20 : ulong my_voff_ver_max ( void ); // return the maximum version number (2^20-1) 21 : ulong my_voff_off_max ( void ); // return the maximum offset (2^44-1) 22 : my_voff_t my_voff ( ulong ver, ulong off ); // pack the least significant bits of ver and off into a my_voff_t. 23 : ulong my_voff_ver ( my_voff_t voff ); // unpack the version from a my_voff_t, will be in [0,my_voff_ver_max()] 24 : ulong my_voff_off ( my_voff_t voff ); // unpack the version from a my_voff_t, will be in [0,my_voff_off_max()] 25 : 26 : This is safe for multiple inclusion and other options exist for fine 27 : tuning described below. */ 28 : 29 : #ifndef VOFF_NAME 30 : #error "Define VOFF_NAME" 31 : #endif 32 : 33 : /* VOFF_TYPE is a type that behaves like a primitive integral type, is 34 : efficient to pass around by value and is ideally atomic operation 35 : friendly. Defaults to ulong. */ 36 : 37 : #ifndef VOFF_TYPE 38 : #define VOFF_TYPE ulong 39 : #endif 40 : 41 : /* VOFF_VER_WIDTH is the bit width to use for versions. All other 42 : bytes in the VOFF_TYPE will be used for offsets. As such, this 43 : should be in [1,width_type) */ 44 : 45 : #ifndef VOFF_VER_WIDTH 46 180000000 : #define VOFF_VER_WIDTH (20) 47 : #endif 48 : 49 : #define VOFF_(x)FD_EXPAND_THEN_CONCAT3(VOFF_NAME,_,x) 50 : 51 : typedef VOFF_TYPE VOFF_(t); 52 : 53 : enum { 54 : VOFF_(VER_WIDTH) = VOFF_VER_WIDTH, 55 : VOFF_(OFF_WIDTH) = 8*(int)sizeof(VOFF_TYPE) - VOFF_VER_WIDTH 56 : }; 57 : 58 : FD_PROTOTYPES_BEGIN 59 : 60 0 : FD_FN_CONST static inline int VOFF_(ver_width)( void ) { return VOFF_VER_WIDTH; } 61 0 : FD_FN_CONST static inline int VOFF_(off_width)( void ) { return 8*(int)sizeof(VOFF_TYPE) - VOFF_VER_WIDTH; } 62 0 : FD_FN_CONST static inline VOFF_TYPE VOFF_(ver_max) ( void ) { return (((VOFF_TYPE)1) << VOFF_VER_WIDTH) - (VOFF_TYPE)1; } 63 0 : FD_FN_CONST static inline VOFF_TYPE VOFF_(off_max) ( void ) { return (~(VOFF_TYPE)0) >> VOFF_VER_WIDTH; } 64 : 65 : FD_FN_CONST static inline VOFF_(t) 66 : VOFF_NAME( VOFF_TYPE ver, 67 122782647 : VOFF_TYPE off) { 68 122782647 : return (ver & ((((VOFF_TYPE)1)<<VOFF_VER_WIDTH) - (VOFF_TYPE)1)) | (off << VOFF_VER_WIDTH); 69 122782647 : } 70 : 71 62733885 : FD_FN_CONST static inline VOFF_TYPE VOFF_(ver)( VOFF_(t) voff ) { return voff & ((((VOFF_TYPE)1)<<VOFF_VER_WIDTH) - (VOFF_TYPE)1); } 72 201543807 : FD_FN_CONST static inline VOFF_TYPE VOFF_(off)( VOFF_(t) voff ) { return voff >> VOFF_VER_WIDTH; } 73 : 74 : FD_PROTOTYPES_END 75 : 76 : #undef VOFF_ 77 : 78 : #undef VOFF_VER_WIDTH 79 : #undef VOFF_TYPE 80 : #undef VOFF_NAME 81 :