mirror of
https://github.com/protocolbuffers/protobuf
synced 2026-08-26 02:23:14 -04:00
[ObjC] Adapt the varint size calculation from C++
The C++ has a version that is mostly branchless and also very short, so just use that. However, don't bother with also doing the Intel version as that won't likely matter for Apple platforms for much longer. We've seen cases where folks use clang flags to aggressively inline things and so this could actual shrink things depending on how many times it gets inlined within CodedOutputStream. PiperOrigin-RevId: 831826052
This commit is contained in:
parent
7ebcd88e66
commit
1bf47797fb
1 changed files with 29 additions and 0 deletions
|
|
@ -1094,12 +1094,26 @@ size_t GPBComputeWireFormatTagSize(int field_number, GPBDataType dataType) {
|
|||
}
|
||||
|
||||
size_t GPBComputeRawVarint32Size(int32_t value) {
|
||||
#if __has_builtin(__builtin_clz) && !(defined(__x86__) || defined(__x86_64__) || defined(__i386__))
|
||||
// This logic comes from the C++ for CodedOutputStream::VarintSize32(uint32_t), it provides a
|
||||
// branchless calculation of the size. ObjC/C doesn't have some of the nicer C++ things do this so
|
||||
// model it simply. Also don't bother with the Intel specific version since that likely won't be
|
||||
// needed for Apple platforms for much longer.
|
||||
|
||||
// Ensure the correct `__builtin_clz*` be being used for the compiled architecture.
|
||||
GPBInternalCompileAssert(sizeof(unsigned int) == sizeof(uint32_t), __builtin_clz_not_32_bits);
|
||||
const int uint32_digits = sizeof(uint32_t) * 8; // std::numeric_limits<uint32_t>::digits
|
||||
int clz = (value == 0) ? uint32_digits : __builtin_clz((uint32_t)value);
|
||||
return (size_t)(((uint32_digits * 9 + 64) - (clz * 9)) / 64);
|
||||
#else
|
||||
|
||||
// value is treated as unsigned, so it won't be sign-extended if negative.
|
||||
if ((value & (0xffffffff << 7)) == 0) return 1;
|
||||
if ((value & (0xffffffff << 14)) == 0) return 2;
|
||||
if ((value & (0xffffffff << 21)) == 0) return 3;
|
||||
if ((value & (0xffffffff << 28)) == 0) return 4;
|
||||
return 5;
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t GPBComputeRawVarint32SizeForInteger(NSInteger value) {
|
||||
|
|
@ -1108,6 +1122,20 @@ size_t GPBComputeRawVarint32SizeForInteger(NSInteger value) {
|
|||
}
|
||||
|
||||
size_t GPBComputeRawVarint64Size(int64_t value) {
|
||||
#if __has_builtin(__builtin_clzll) && \
|
||||
!(defined(__x86__) || defined(__x86_64__) || defined(__i386__))
|
||||
// This logic comes from the C++ for CodedOutputStream::VarintSize64(uint64_t), it provides a
|
||||
// branchless calculation of the size. ObjC/C doesn't have some of the nicer C++ things do this so
|
||||
// model it simply. Also don't bother with the Intel specific version since that likely won't be
|
||||
// needed for Apple platforms for much longer.
|
||||
|
||||
// Ensure the correct `__builtin_clz*` be being used for the compiled architecture.
|
||||
GPBInternalCompileAssert(sizeof(unsigned long long) == sizeof(uint64_t),
|
||||
__builtin_clzll_not_64_bits);
|
||||
const int uint64_digits = sizeof(uint64_t) * 8; // std::numeric_limits<uint64_t>::digits
|
||||
int clz = (value == 0) ? uint64_digits : __builtin_clzll((uint64_t)value);
|
||||
return (size_t)(((uint64_digits * 9 + 64) - (clz * 9)) / 64);
|
||||
#else
|
||||
if ((value & (0xffffffffffffffffL << 7)) == 0) return 1;
|
||||
if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
|
||||
if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
|
||||
|
|
@ -1118,4 +1146,5 @@ size_t GPBComputeRawVarint64Size(int64_t value) {
|
|||
if ((value & (0xffffffffffffffffL << 56)) == 0) return 8;
|
||||
if ((value & (0xffffffffffffffffL << 63)) == 0) return 9;
|
||||
return 10;
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue