blob: 7ca20b4610b7c660ea44cbd69cf888195d9b5c1a [file]
// Copyright (C) 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
//
// 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 ICING_UTIL_BIT_UTIL_H_
#define ICING_UTIL_BIT_UTIL_H_
#include <cstdint>
namespace icing {
namespace lib {
namespace bit_util {
// Manipulating bit fields.
//
// value value containing the bit field(s)
// lsb_offset offset of bit field in value, starting from the least significant
// bit. for example, the '1' in '0100' has a lsb_offset of 2
// len len of bit field in value
//
// REQUIREMENTS
//
// - value is an unsigned integer <= 64 bits
// - lsb_offset + len <= sizeof(value) * 8
//
// There is no error checking so you will get garbage if you don't
// ensure the above.
// Shifting by more than the word length is undefined (on ARM it has the
// intended effect, but on Intel it shifts by % word length), so check the
// length).
inline uint64_t BitfieldMask(uint32_t len) {
return ((len == 0) ? 0U : ((~uint64_t{0}) >> (64 - (len))));
}
inline void BitfieldClear(uint32_t lsb_offset, uint32_t len,
uint8_t* value_out) {
*value_out &= ~(BitfieldMask(len) << lsb_offset);
}
inline void BitfieldClear(uint32_t lsb_offset, uint32_t len,
uint16_t* value_out) {
*value_out &= ~(BitfieldMask(len) << lsb_offset);
}
inline void BitfieldClear(uint32_t lsb_offset, uint32_t len,
uint32_t* value_out) {
*value_out &= ~(BitfieldMask(len) << lsb_offset);
}
inline void BitfieldClear(uint32_t lsb_offset, uint32_t len,
uint64_t* value_out) {
*value_out &= ~(BitfieldMask(len) << lsb_offset);
}
inline uint64_t BitfieldGet(uint64_t value, uint32_t lsb_offset, uint32_t len) {
return ((value) >> (lsb_offset)) & BitfieldMask(len);
}
inline void BitfieldSet(uint8_t new_value, uint32_t lsb_offset, uint32_t len,
uint8_t* value_out) {
BitfieldClear(lsb_offset, len, value_out);
// We conservatively mask new_value at len so value won't be corrupted if
// new_value >= (1 << len).
*value_out |= (new_value & BitfieldMask(len)) << (lsb_offset);
}
inline void BitfieldSet(uint16_t new_value, uint32_t lsb_offset, uint32_t len,
uint16_t* value_out) {
BitfieldClear(lsb_offset, len, value_out);
// We conservatively mask new_value at len so value won't be corrupted if
// new_value >= (1 << len).
*value_out |= (new_value & BitfieldMask(len)) << (lsb_offset);
}
inline void BitfieldSet(uint32_t new_value, uint32_t lsb_offset, uint32_t len,
uint32_t* value_out) {
BitfieldClear(lsb_offset, len, value_out);
// We conservatively mask new_value at len so value won't be corrupted if
// new_value >= (1 << len).
*value_out |= (new_value & BitfieldMask(len)) << (lsb_offset);
}
inline void BitfieldSet(uint64_t new_value, uint32_t lsb_offset, uint32_t len,
uint64_t* value_out) {
BitfieldClear(lsb_offset, len, value_out);
// We conservatively mask new_value at len so value won't be corrupted if
// new_value >= (1 << len).
*value_out |= (new_value & BitfieldMask(len)) << (lsb_offset);
}
} // namespace bit_util
} // namespace lib
} // namespace icing
#endif // ICING_UTIL_BIT_UTIL_H_