為了實驗起見,讓我們有一個函式,它接受位掩碼和偏移量并回傳偏移后的掩碼。確定操作是否不會將位掩碼的任何部分移位超過資料型別的寬度的性能友好方法是什么?這是我到目前為止嘗試過的,但也許有更優化的方法來檢查這個?
示例程式:(注意:我正在尋找適用于所有資料型別的解決方案,而不僅僅是 16 位整數)
#include <iostream>
using namespace std;
uint16_t TestFunc(uint16_t offset, uint16_t mask)
{
if (offset >= sizeof(uint16_t) * 8)
throw std::exception("Offset outside bounds");
// find the index of the left-most bit in the mask
int16_t maskLeftBitIndex = 0;
uint16_t maskCopy = mask;
while (maskCopy >>= 1)
maskLeftBitIndex ;
// check if the said left-most bit will be shifted past the width of uint16_t
if (offset maskLeftBitIndex >= sizeof(uint16_t) * 8)
throw std::exception("Mask will end up outside bounds");
return mask << offset;
}
int main()
{
try
{
uint16_t test = TestFunc(15, 2);
cout << "Bitmask value: " << test;
}
catch (std::exception& e)
{
cout << "Exception encountered: " << e.what();
}
return 0;
}
uj5u.com熱心網友回復:
不確定這會更快,但您可以檢查之前和結束值是否設定了相同的位數
uint16_t TestFunc(uint16_t offset, uint16_t mask)
{
if (offset >= std::numeric_limits<uint16_t>::digits)
throw "Offset outside bounds (Possible Undefined Behavior)";
uint16_t result = mask << offset;
if(std::popcount(mask)!=std::popcount(result))
throw "Offset outside bounds";
return result;
}
uj5u.com熱心網友回復:
這是我制作的示例(未測驗有符號整數)的開始。
#include <cassert>
#include <cstdint>
#include <utility>
#include <stdexcept>
// instead of "real" exceptions, use return based exceptions
// kind of in the spirit of what Herb Sutter wants to do
// with exceptions in the future too
enum class shift_result_exception
{
none,
invalid_arg,
out_of_range
};
// struct to hold a return value and an "exception"
template<typename type_t>
struct shift_result_t
{
shift_result_exception exception{ shift_result_exception::invalid_arg };
type_t value{};
operator type_t()
{
return value;
}
};
// the actual shift logic.
template<typename type_t>
auto shift_left(const type_t value, const std::size_t shift)
{
shift_result_t<type_t> result;
// if caller wants to shift more places then the size of the type
// this will be an invalid_arg result
std::size_t type_size = sizeof(type_t) << 3; // = *8
if (shift >= type_size) return result;
// number of bits at front of value to check
type_t mask = (1 << shift) - 1;
std::size_t mask_shift = (type_size - shift);
// shift ones to the front of the type if any of the ones
mask <<= mask_shift;
// overlaps with a one of the value then the value cannnot be shifted
// and the shifted value would go out of range
if ((mask & value) != 0)
{
result.exception = shift_result_exception::out_of_range;
return result;
}
// it is safe to shift.
result.value = value << shift;
result.exception = shift_result_exception::none;
return result;
}
int main()
{
assert(shift_left<int>(1, 1) == 2);
assert(shift_left<std::uint8_t>(1, 7) == 128);
assert(shift_left<std::uint8_t>(2, 7).exception == shift_result_exception::out_of_range);
assert(shift_left<std::uint8_t>(1, 8).exception == shift_result_exception::invalid_arg);
assert(shift_left<std::uint8_t>(3, 5) == 96);
assert(shift_left<std::uint32_t>(1, 31).exception == shift_result_exception::none);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/325451.html
