Skip to content

Commit 9883576

Browse files
pdillingerfacebook-github-bot
authored andcommitted
Improve internal lossless_cast to work on pointers (facebook#13648)
Summary: I was going to use this in some code I was working on but ended up not needing it. But it's useful nonetheless and I'm using it in a few places to replace reinterpret_cast. Pull Request resolved: facebook#13648 Test Plan: existing tests, manually see compilation fail when pointed-to types are not same size integral types Reviewed By: cbi42 Differential Revision: D75576195 Pulled By: pdillinger fbshipit-source-id: e10c7a4959340f6f2b536de8088072a90e871fcf
1 parent e929bde commit 9883576

2 files changed

Lines changed: 26 additions & 14 deletions

File tree

util/cast_util.h

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,30 @@ inline std::shared_ptr<DestClass> static_cast_with_check(
3939
}
4040

4141
// A wrapper around static_cast for lossless conversion between integral
42-
// types, including enum types. For example, this can be used for converting
43-
// between signed/unsigned or enum type and underlying type without fear of
44-
// stripping away data, now or in the future.
42+
// types, including enum types, and pointers to such types. For example, this
43+
// can be used for converting between signed/unsigned or enum type and
44+
// underlying type without fear of stripping away data, now or in the future.
4545
template <typename To, typename From>
4646
inline To lossless_cast(From x) {
47-
using FromValue = typename std::remove_reference<From>::type;
48-
static_assert(
49-
std::is_integral<FromValue>::value || std::is_enum<FromValue>::value,
50-
"Only works on integral types");
51-
static_assert(std::is_integral<To>::value || std::is_enum<To>::value,
52-
"Only works on integral types");
53-
static_assert(sizeof(To) >= sizeof(FromValue), "Must be lossless");
54-
return static_cast<To>(x);
47+
using FromValue = typename std::remove_reference_t<From>;
48+
if constexpr (std::is_pointer_v<FromValue>) {
49+
static_assert(std::is_pointer_v<To>);
50+
using FromDeref = typename std::remove_pointer_t<FromValue>;
51+
using ToDeref = typename std::remove_pointer_t<To>;
52+
static_assert(std::is_integral_v<FromDeref> || std::is_enum_v<FromDeref>,
53+
"Only works on integral types");
54+
static_assert(std::is_integral_v<ToDeref> || std::is_enum_v<To>,
55+
"Only works on integral types");
56+
static_assert(sizeof(ToDeref) == sizeof(FromDeref), "Must be lossless");
57+
return reinterpret_cast<To>(x);
58+
} else {
59+
static_assert(std::is_integral_v<FromValue> || std::is_enum_v<FromValue>,
60+
"Only works on integral types");
61+
static_assert(std::is_integral_v<To> || std::is_enum_v<To>,
62+
"Only works on integral types");
63+
static_assert(sizeof(To) >= sizeof(FromValue), "Must be lossless");
64+
return static_cast<To>(x);
65+
}
5566
}
5667

5768
// For disambiguating a potentially heterogeneous aggregate as a homogeneous

util/coding.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include "port/port.h"
2323
#include "rocksdb/slice.h"
24+
#include "util/cast_util.h"
2425
#include "util/coding_lean.h"
2526

2627
// Some processors does not allow unaligned access to memory
@@ -105,7 +106,7 @@ const char* GetVarint32PtrFallback(const char* p, const char* limit,
105106
inline const char* GetVarint32Ptr(const char* p, const char* limit,
106107
uint32_t* value) {
107108
if (p < limit) {
108-
uint32_t result = *(reinterpret_cast<const unsigned char*>(p));
109+
uint32_t result = *(lossless_cast<const unsigned char*>(p));
109110
if ((result & 128) == 0) {
110111
*value = result;
111112
return p + 1;
@@ -172,13 +173,13 @@ inline void PutVarint32Varint32Varint32(std::string* dst, uint32_t v1,
172173

173174
inline char* EncodeVarint64(char* dst, uint64_t v) {
174175
static const unsigned int B = 128;
175-
unsigned char* ptr = reinterpret_cast<unsigned char*>(dst);
176+
unsigned char* ptr = lossless_cast<unsigned char*>(dst);
176177
while (v >= B) {
177178
*(ptr++) = (v & (B - 1)) | B;
178179
v >>= 7;
179180
}
180181
*(ptr++) = static_cast<unsigned char>(v);
181-
return reinterpret_cast<char*>(ptr);
182+
return lossless_cast<char*>(ptr);
182183
}
183184

184185
inline void PutVarint64(std::string* dst, uint64_t v) {

0 commit comments

Comments
 (0)