/**
 * =========================================================================
 * File        : bits.h
 * Project     : 0 A.D.
 * Description : bit-twiddling.
 * =========================================================================
 */

// license: GPL; see lib/license.txt

#ifndef INCLUDED_BITS
#define INCLUDED_BITS

/**
 * value of bit number <n> as unsigned long.
 *
 * @param n bit index (0..CHAR_BIT*sizeof(int)-1)
 **/
#define BIT(n) (1ul << (n))

/**
 * value of bit number <n> as unsigned long long.
 *
 * @param n bit index (0..CHAR_BIT*sizeof(int)-1)
 **/
#define BIT64(n) (1ull << (n))


// these are declared in the header and inlined to aid compiler optimizations
// (they can easily end up being time-critical).
// note: GCC can't inline extern functions, while VC's "Whole Program
// Optimization" can.

/**
 * a mask that includes the lowest N bits
 *
 * @param num_bits number of bits in mask
 **/
inline uint bit_mask(uint num_bits)
{
    return (1u << num_bits)-1;
}

inline u64 bit_mask64(uint num_bits)
{
    return (1ull << num_bits)-1;
}

/**
 * extract the value of bits hi_idx:lo_idx within num
 *
 * example: bits(0x69, 2, 5) == 0x0A
 *
 * @param num number whose bits are to be extracted
 * @param lo_idx bit index of lowest  bit to include
 * @param hi_idx bit index of highest bit to include
 * @return value of extracted bits.
 **/
inline uint bits(uint num, uint lo_idx, uint hi_idx)
{
    const uint count = (hi_idx -lo_idx)+1;  // # bits to return
    uint result = num >> lo_idx;
    result &= bit_mask(count);
    return result;
}

inline u64 bits64(u64 num, uint lo_idx, uint hi_idx)
{
    const uint count = (hi_idx -lo_idx)+1;  // # bits to return
    u64  result = num >> lo_idx;
    result &= bit_mask64(count);
    return result;
}

/**
 * @return whether the given number is a power of two.
 **/
extern bool is_pow2(uint n);

/**
 * @return the (integral) base 2 logarithm, or -1 if the number
 * is not a power-of-two.
 **/
extern int log2_of_pow2(uint n);

/**
 * ceil(log2(n))
 *
 * @param n (integer) input; MUST be > 0, else results are undefined.
 * @return ceiling of the base-2 logarithm (i.e. rounded up).
 **/
extern uint ceil_log2(uint x);

/**
 * floor(log2(f))
 * fast, uses the FPU normalization hardware.
 *
 * @param f (float) input; MUST be > 0, else results are undefined.
 * @return floor of the base-2 logarithm (i.e. rounded down).
 **/
extern int floor_log2(const float x);

/**
 * round up to next larger power of two.
 **/
extern uint round_up_to_pow2(uint x);

/**
 * round number up/down to the next given multiple.
 *
 * @param multiple: must be a power of two.
 **/
extern uintptr_t round_up  (uintptr_t n, uintptr_t multiple);
extern uintptr_t round_down(uintptr_t n, uintptr_t multiple);

#endif  // #ifndef INCLUDED_BITS