// 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 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_