blob: 3e93f96a00b7f38cbf9a52f437cedf18d85b2f7e [file] [log] [blame]
// Copyright 2019 Google LLC
//
// 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
//
// https://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.
// This file contains various utility routines for manipulating values at a low
// level, such as byte swaps and safe casts.
#ifndef EMBOSS_RUNTIME_CPP_EMBOSS_BIT_UTIL_H_
#define EMBOSS_RUNTIME_CPP_EMBOSS_BIT_UTIL_H_
#include <cstdint>
#include <type_traits>
#include "runtime/cpp/emboss_defines.h"
namespace emboss {
namespace support {
// Where possible, it is best to use byte swap builtins, but if they are not
// available ByteSwap can fall back to portable code.
inline constexpr ::std::uint8_t ByteSwap(::std::uint8_t x) { return x; }
inline constexpr ::std::uint16_t ByteSwap(::std::uint16_t x) {
#ifdef EMBOSS_BYTESWAP16
return EMBOSS_BYTESWAP16(x);
#else
return (x << 8) | (x >> 8);
#endif
}
inline constexpr ::std::uint32_t ByteSwap(::std::uint32_t x) {
#ifdef EMBOSS_BYTESWAP32
return EMBOSS_BYTESWAP32(x);
#else
return (static_cast</**/ ::std::uint32_t>(
ByteSwap(static_cast</**/ ::std::uint16_t>(x)))
<< 16) |
ByteSwap(static_cast</**/ ::std::uint16_t>(x >> 16));
#endif
}
inline constexpr ::std::uint64_t ByteSwap(::std::uint64_t x) {
#ifdef EMBOSS_BYTESWAP64
return EMBOSS_BYTESWAP64(x);
#else
return (static_cast</**/ ::std::uint64_t>(
ByteSwap(static_cast</**/ ::std::uint32_t>(x)))
<< 32) |
ByteSwap(static_cast</**/ ::std::uint32_t>(x >> 32));
#endif
}
// Masks the given value to the given number of bits.
template <typename T>
inline constexpr T MaskToNBits(T value, unsigned bits) {
static_assert(!::std::is_signed<T>::value,
"MaskToNBits only works on unsigned values.");
return bits < sizeof value * 8 ? value & ((static_cast<T>(1) << bits) - 1)
: value;
}
template <typename T>
inline constexpr bool IsPowerOfTwo(T value) {
// This check relies on an old bit-counting trick; x & (x - 1) always has one
// fewer bit set to 1 than x (if x is nonzero), and powers of 2 always have
// exactly one 1 bit, thus x & (x - 1) == 0 if x is a power of 2.
return value > 0 && (value & (value - 1)) == 0;
}
} // namespace support
} // namespace emboss
#endif // EMBOSS_RUNTIME_CPP_EMBOSS_BIT_UTIL_H_