Skip to content

Commit 6b939fc

Browse files
committed
fix: linux compatible
1 parent bf66bfc commit 6b939fc

File tree

3 files changed

+149
-127
lines changed

3 files changed

+149
-127
lines changed

bundle-utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ add_library(${PROJECT_NAME} STATIC
1616
src/JetTime.h
1717
src/JetJSON.h
1818
src/JetJSON.cpp
19+
src/JetNumeric.h
1920
src/Path.h
2021
src/Utils.h
2122
src/Utils.cpp)

bundle-utils/src/JetNumeric.h

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
//
2+
// Created by Duzhong Chen on 2021/4/7.
3+
//
4+
5+
#ifndef ROCKET_BUNDLE_JETNUMERIC_H
6+
#define ROCKET_BUNDLE_JETNUMERIC_H
7+
8+
#if defined(_WIN32)
9+
10+
#include <intrin.h>
11+
#include <float.h>
12+
#define J_UMULH(v1, v2) __umulh(v1, v2);
13+
#define J_SMULH(v1, v2) __mulh(v1, v2);
14+
#pragma intrinsic(__umulh)
15+
#pragma intrinsic(__mulh)
16+
17+
#else
18+
19+
typedef unsigned __int128 uint128_t;
20+
typedef __int128 int128_t;
21+
22+
inline int64_t J_UMULH(int64_t v1, int64_t v2) {
23+
return uint128_t(v1) * uint128_t(v2) >> 64;
24+
}
25+
26+
inline int64_t J_SMULH(int64_t v1, int64_t v2) {
27+
return int128_t(v1) * int128_t(v2) >> 64;
28+
}
29+
30+
#endif
31+
32+
template <typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type
33+
add_overflow(T v1, T v2, T* r)
34+
{
35+
// unsigned additions are well-defined
36+
*r = v1 + v2;
37+
return v1 > T(v1 + v2);
38+
}
39+
40+
template <typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type
41+
add_overflow(T v1, T v2, T* r)
42+
{
43+
// Here's how we calculate the overflow:
44+
// 1) unsigned addition is well-defined, so we can always execute it
45+
// 2) conversion from unsigned back to signed is implementation-
46+
// defined and in the implementations we use, it's a no-op.
47+
// 3) signed integer overflow happens if the sign of the two input operands
48+
// is the same but the sign of the result is different. In other words,
49+
// the sign of the result must be the same as the sign of either
50+
// operand.
51+
52+
using U = typename std::make_unsigned<T>::type;
53+
*r = T(U(v1) + U(v2));
54+
55+
// If int is two's complement, assume all integer types are too.
56+
if (std::is_same<int32_t, int>::value) {
57+
// Two's complement equivalent (generates slightly shorter code):
58+
// x ^ y is negative if x and y have different signs
59+
// x & y is negative if x and y are negative
60+
// (x ^ z) & (y ^ z) is negative if x and z have different signs
61+
// AND y and z have different signs
62+
return ((v1 ^ *r) & (v2 ^ *r)) < 0;
63+
}
64+
65+
bool s1 = (v1 < 0);
66+
bool s2 = (v2 < 0);
67+
bool sr = (*r < 0);
68+
return s1 != sr && s2 != sr;
69+
// also: return s1 == s2 && s1 != sr;
70+
}
71+
72+
template <typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type
73+
sub_overflow(T v1, T v2, T* r)
74+
{
75+
// unsigned subtractions are well-defined
76+
*r = v1 - v2;
77+
return v1 < v2;
78+
}
79+
80+
template <typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type
81+
sub_overflow(T v1, T v2, T* r)
82+
{
83+
// See above for explanation. This is the same with some signs reversed.
84+
// We can't use add_overflow(v1, -v2, r) because it would be UB if
85+
// v2 == std::numeric_limits<T>::min().
86+
87+
using U = typename std::make_unsigned<T>::type;
88+
*r = T(U(v1) - U(v2));
89+
90+
if (std::is_same<int32_t, int>::value)
91+
return ((v1 ^ *r) & (~v2 ^ *r)) < 0;
92+
93+
bool s1 = (v1 < 0);
94+
bool s2 = !(v2 < 0);
95+
bool sr = (*r < 0);
96+
return s1 != sr && s2 != sr;
97+
// also: return s1 == s2 && s1 != sr;
98+
}
99+
100+
template <int> struct JetIntegerForSize;
101+
template <> struct JetIntegerForSize<1> { typedef uint8_t Unsigned; typedef int8_t Signed; };
102+
template <> struct JetIntegerForSize<2> { typedef uint16_t Unsigned; typedef int16_t Signed; };
103+
template <> struct JetIntegerForSize<4> { typedef uint32_t Unsigned; typedef int32_t Signed; };
104+
template <> struct JetIntegerForSize<8> { typedef uint64_t Unsigned; typedef int64_t Signed; };
105+
106+
template <typename T> inline
107+
typename std::enable_if<std::is_unsigned<T>::value || std::is_signed<T>::value, bool>::type
108+
mul_overflow(T v1, T v2, T *r)
109+
{
110+
// use the next biggest type
111+
// Note: for 64-bit systems where __int128 isn't supported, this will cause an error.
112+
using LargerInt = JetIntegerForSize<sizeof(T) * 2>;
113+
using Larger = typename std::conditional<std::is_signed<T>::value,
114+
typename LargerInt::Signed, typename LargerInt::Unsigned>::type;
115+
Larger lr = Larger(v1) * Larger(v2);
116+
*r = T(lr);
117+
return lr > std::numeric_limits<T>::max() || lr < std::numeric_limits<T>::min();
118+
}
119+
120+
template <uint64_t>
121+
inline bool mul_overflow(uint64_t v1, uint64_t v2, uint64_t* r)
122+
{
123+
*r = v1 * v2;
124+
return J_UMULH(v1, v2);
125+
}
126+
127+
template <int64_t>
128+
inline bool mul_overflow(int64_t v1, int64_t v2, int64_t* r)
129+
{
130+
// This is slightly more complex than the unsigned case above: the sign bit
131+
// of 'low' must be replicated as the entire 'high', so the only valid
132+
// values for 'high' are 0 and -1. Use unsigned multiply since it's the same
133+
// as signed for the low bits and use a signed right shift to verify that
134+
// 'high' is nothing but sign bits that match the sign of 'low'.
135+
136+
int64_t high = J_SMULH(v1, v2);
137+
*r = int64_t(uint64_t(v1) * uint64_t(v2));
138+
return (*r >> 63) != high;
139+
}
140+
141+
#endif //ROCKET_BUNDLE_JETNUMERIC_H

bundle-utils/src/string/UStringData.cpp

Lines changed: 7 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -7,148 +7,28 @@
77
#include <algorithm>
88
#include <cassert>
99
#include <cstdlib>
10-
#include <numeric>
11-
12-
#if defined(_WIN32)
13-
14-
#include <intrin.h>
15-
#include <float.h>
16-
#define Q_INTRINSIC_MUL_OVERFLOW64
17-
#define Q_UMULH(v1, v2) __umulh(v1, v2);
18-
#define Q_SMULH(v1, v2) __mulh(v1, v2);
19-
#pragma intrinsic(__umulh)
20-
#pragma intrinsic(__mulh)
21-
22-
23-
#endif
10+
#include "../JetNumeric.h"
2411

2512
struct CalculateGrowingBlockSizeResult
2613
{
2714
uint32_t size;
2815
uint32_t elementCount;
2916
};
3017

31-
#if ((defined(Q_CC_INTEL) ? (Q_CC_INTEL >= 1800 && !defined(Q_OS_WIN)) : defined(Q_CC_GNU)) \
32-
&& Q_CC_GNU >= 500) || __has_builtin(__builtin_add_overflow)
33-
34-
template <typename T> inline
35-
typename std::enable_if<std::is_unsigned<T>::value || std::is_signed<T>::value, bool>::type
36-
add_overflow(T v1, T v2, T *r)
37-
{ return __builtin_add_overflow(v1, v2, r); }
38-
39-
template <typename T> inline
40-
typename std::enable_if<std::is_unsigned<T>::value || std::is_signed<T>::value, bool>::type
41-
sub_overflow(T v1, T v2, T *r)
42-
{ return __builtin_sub_overflow(v1, v2, r); }
43-
44-
template <typename T> inline
45-
typename std::enable_if<std::is_unsigned<T>::value || std::is_signed<T>::value, bool>::type
46-
mul_overflow(T v1, T v2, T *r)
47-
{ return __builtin_mul_overflow(v1, v2, r); }
48-
49-
#else
50-
51-
template <typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type
52-
add_overflow(T v1, T v2, T* r)
53-
{
54-
// unsigned additions are well-defined
55-
*r = v1 + v2;
56-
return v1 > T(v1 + v2);
57-
}
58-
59-
template <typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type
60-
add_overflow(T v1, T v2, T* r)
61-
{
62-
// Here's how we calculate the overflow:
63-
// 1) unsigned addition is well-defined, so we can always execute it
64-
// 2) conversion from unsigned back to signed is implementation-
65-
// defined and in the implementations we use, it's a no-op.
66-
// 3) signed integer overflow happens if the sign of the two input operands
67-
// is the same but the sign of the result is different. In other words,
68-
// the sign of the result must be the same as the sign of either
69-
// operand.
70-
71-
using U = typename std::make_unsigned<T>::type;
72-
*r = T(U(v1) + U(v2));
73-
74-
// If int is two's complement, assume all integer types are too.
75-
if (std::is_same<int32_t, int>::value) {
76-
// Two's complement equivalent (generates slightly shorter code):
77-
// x ^ y is negative if x and y have different signs
78-
// x & y is negative if x and y are negative
79-
// (x ^ z) & (y ^ z) is negative if x and z have different signs
80-
// AND y and z have different signs
81-
return ((v1 ^ *r) & (v2 ^ *r)) < 0;
82-
}
83-
84-
bool s1 = (v1 < 0);
85-
bool s2 = (v2 < 0);
86-
bool sr = (*r < 0);
87-
return s1 != sr && s2 != sr;
88-
// also: return s1 == s2 && s1 != sr;
89-
}
90-
91-
template <typename T> inline typename std::enable_if<std::is_unsigned<T>::value, bool>::type
92-
sub_overflow(T v1, T v2, T* r)
93-
{
94-
// unsigned subtractions are well-defined
95-
*r = v1 - v2;
96-
return v1 < v2;
97-
}
98-
99-
template <typename T> inline typename std::enable_if<std::is_signed<T>::value, bool>::type
100-
sub_overflow(T v1, T v2, T* r)
101-
{
102-
// See above for explanation. This is the same with some signs reversed.
103-
// We can't use add_overflow(v1, -v2, r) because it would be UB if
104-
// v2 == std::numeric_limits<T>::min().
105-
106-
using U = typename std::make_unsigned<T>::type;
107-
*r = T(U(v1) - U(v2));
108-
109-
if (std::is_same<int32_t, int>::value)
110-
return ((v1 ^ *r) & (~v2 ^ *r)) < 0;
111-
112-
bool s1 = (v1 < 0);
113-
bool s2 = !(v2 < 0);
114-
bool sr = (*r < 0);
115-
return s1 != sr && s2 != sr;
116-
// also: return s1 == s2 && s1 != sr;
117-
}
118-
119-
inline bool mul_overflow(uint64_t v1, uint64_t v2, uint64_t* r)
120-
{
121-
*r = v1 * v2;
122-
return Q_UMULH(v1, v2);
123-
}
124-
125-
inline bool mul_overflow(int64_t v1, int64_t v2, int64_t* r)
126-
{
127-
// This is slightly more complex than the unsigned case above: the sign bit
128-
// of 'low' must be replicated as the entire 'high', so the only valid
129-
// values for 'high' are 0 and -1. Use unsigned multiply since it's the same
130-
// as signed for the low bits and use a signed right shift to verify that
131-
// 'high' is nothing but sign bits that match the sign of 'low'.
132-
133-
int64_t high = Q_SMULH(v1, v2);
134-
*r = int64_t(uint64_t(v1) * uint64_t(v2));
135-
return (*r >> 63) != high;
136-
}
137-
138-
#endif
139-
14018
uint32_t qCalculateBlockSize(uint32_t elementCount, uint32_t elementSize, uint32_t headerSize) noexcept
14119
{
14220
J_ASSERT(elementSize);
14321

144-
size_t bytes;
145-
if (unlikely(mul_overflow(size_t(elementSize), size_t(elementCount), &bytes)) ||
146-
unlikely(add_overflow(bytes, size_t(headerSize), &bytes)))
22+
uint32_t bytes;
23+
static_assert(sizeof(size_t) == 8, "");
24+
25+
if (unlikely(mul_overflow(uint32_t(elementSize), uint32_t(elementCount), &bytes)) ||
26+
unlikely(add_overflow(bytes, uint32_t(headerSize), &bytes)))
14727
return -1;
14828
if (unlikely(uint32_t(bytes) < 0))
14929
return -1;
15030

151-
return uint32_t(bytes);
31+
return bytes;
15232
}
15333

15434
constexpr inline uint64_t qNextPowerOfTwo(uint64_t v)

0 commit comments

Comments
 (0)