blob: 0c9c32d5500c3b11416f5b75fb288dd5b2e98595 [file] [log] [blame]
// Copyright 2012 Cloudera Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef IMPALA_BIT_UTIL_H
#define IMPALA_BIT_UTIL_H
#include <endian.h>
#include "impala/compiler-util.h"
#include "impala/logging.h"
namespace impala {
// Utility class to do standard bit tricks
// TODO: is this in boost or something else like that?
class BitUtil {
public:
// Returns the ceil of value/divisor
static inline int Ceil(int value, int divisor) {
return value / divisor + (value % divisor != 0);
}
// Returns 'value' rounded up to the nearest multiple of 'factor'
static inline int RoundUp(int value, int factor) {
return (value + (factor - 1)) / factor * factor;
}
// Returns 'value' rounded down to the nearest multiple of 'factor'
static inline int RoundDown(int value, int factor) {
return (value / factor) * factor;
}
// Returns the number of set bits in x
static inline int Popcount(uint64_t x) {
int count = 0;
for (; x != 0; ++count) x &= x-1;
return count;
}
// Returns the 'num_bits' least-significant bits of 'v'.
static inline uint64_t TrailingBits(uint64_t v, int num_bits) {
if (UNLIKELY(num_bits == 0)) return 0;
if (UNLIKELY(num_bits >= 64)) return v;
int n = 64 - num_bits;
return (v << n) >> n;
}
// Returns ceil(log2(x)).
// TODO: this could be faster if we use __builtin_clz. Fix this if this ever shows up
// in a hot path.
static inline int Log2(uint64_t x) {
if (x == 0) return 0;
// Compute result = ceil(log2(x))
// = floor(log2(x - 1)) + 1, for x > 1
// by finding the position of the most significant bit (1-indexed) of x - 1
// (floor(log2(n)) = MSB(n) (0-indexed))
--x;
int result = 1;
while (x >>= 1) ++result;
return result;
}
// Returns the minimum number of bits needed to represent the value of 'x'
static inline int NumRequiredBits(uint64_t x) {
for (int i = 63; i >= 0; --i) {
if (x & 1L << i) return i + 1;
}
return 0;
}
// Swaps the byte order (i.e. endianess)
static inline int64_t ByteSwap(int64_t value) {
return __builtin_bswap64(value);
}
static inline uint64_t ByteSwap(uint64_t value) {
return static_cast<uint64_t>(__builtin_bswap64(value));
}
static inline int32_t ByteSwap(int32_t value) {
return __builtin_bswap32(value);
}
static inline uint32_t ByteSwap(uint32_t value) {
return static_cast<uint32_t>(__builtin_bswap32(value));
}
static inline int16_t ByteSwap(int16_t value) {
return (((value >> 8) & 0xff) | ((value & 0xff) << 8));
}
static inline uint16_t ByteSwap(uint16_t value) {
return static_cast<uint16_t>(ByteSwap(static_cast<int16_t>(value)));
}
// Write the swapped bytes into dst. Src and st cannot overlap.
static inline void ByteSwap(void* dst, const void* src, int len) {
switch (len) {
case 1:
*reinterpret_cast<int8_t*>(dst) = *reinterpret_cast<const int8_t*>(src);
return;
case 2:
*reinterpret_cast<int16_t*>(dst) =
ByteSwap(*reinterpret_cast<const int16_t*>(src));
return;
case 4:
*reinterpret_cast<int32_t*>(dst) =
ByteSwap(*reinterpret_cast<const int32_t*>(src));
return;
case 8:
*reinterpret_cast<int64_t*>(dst) =
ByteSwap(*reinterpret_cast<const int64_t*>(src));
return;
default: break;
}
uint8_t* d = reinterpret_cast<uint8_t*>(dst);
const uint8_t* s = reinterpret_cast<const uint8_t*>(src);
for (int i = 0; i < len; ++i) {
d[i] = s[len - i - 1];
}
}
// Converts to big endian format (if not already in big endian) from the
// machine's native endian format.
#if __BYTE_ORDER == __LITTLE_ENDIAN
static inline int64_t ToBigEndian(int64_t value) { return ByteSwap(value); }
static inline uint64_t ToBigEndian(uint64_t value) { return ByteSwap(value); }
static inline int32_t ToBigEndian(int32_t value) { return ByteSwap(value); }
static inline uint32_t ToBigEndian(uint32_t value) { return ByteSwap(value); }
static inline int16_t ToBigEndian(int16_t value) { return ByteSwap(value); }
static inline uint16_t ToBigEndian(uint16_t value) { return ByteSwap(value); }
#else
static inline int64_t ToBigEndian(int64_t val) { return val; }
static inline uint64_t ToBigEndian(uint64_t val) { return val; }
static inline int32_t ToBigEndian(int32_t val) { return val; }
static inline uint32_t ToBigEndian(uint32_t val) { return val; }
static inline int16_t ToBigEndian(int16_t val) { return val; }
static inline uint16_t ToBigEndian(uint16_t val) { return val; }
#endif
// Converts from big endian format to the machine's native endian format.
#if __BYTE_ORDER == __LITTLE_ENDIAN
static inline int64_t FromBigEndian(int64_t value) { return ByteSwap(value); }
static inline uint64_t FromBigEndian(uint64_t value) { return ByteSwap(value); }
static inline int32_t FromBigEndian(int32_t value) { return ByteSwap(value); }
static inline uint32_t FromBigEndian(uint32_t value) { return ByteSwap(value); }
static inline int16_t FromBigEndian(int16_t value) { return ByteSwap(value); }
static inline uint16_t FromBigEndian(uint16_t value) { return ByteSwap(value); }
#else
static inline int64_t FromBigEndian(int64_t val) { return val; }
static inline uint64_t FromBigEndian(uint64_t val) { return val; }
static inline int32_t FromBigEndian(int32_t val) { return val; }
static inline uint32_t FromBigEndian(uint32_t val) { return val; }
static inline int16_t FromBigEndian(int16_t val) { return val; }
static inline uint16_t FromBigEndian(uint16_t val) { return val; }
#endif
};
}
#endif