Skip to content

Commit 7d2377a

Browse files
authored
Merge pull request #61 from thecppzoo/em/msvc-fixes
Fixes to building in MSVC
2 parents b92ae39 + 9ffd4c7 commit 7d2377a

File tree

16 files changed

+284
-138
lines changed

16 files changed

+284
-138
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Vscode does not like to build outside of the source tree
2+
# (multiple glitches)
3+
4+
.vscode
5+
test/.vscode

compiler_bugs/msvc/sfinae.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include <type_traits>
2+
#include <new>
3+
#include <utility>
4+
5+
template<typename T, typename... Args>
6+
constexpr auto Constructible_v = std::is_constructible_v<T, Args...>;
7+
8+
template<typename Q>
9+
struct ATemplate {
10+
alignas(alignof(Q)) char space_[sizeof(Q)];
11+
12+
template<typename T>
13+
constexpr static auto FitsInSpace_v = sizeof(T) <= sizeof(Q);
14+
15+
template<typename T, typename... Args>
16+
std::enable_if_t<
17+
FitsInSpace_v<T>
18+
&&
19+
#ifndef TRIGGER_MSVC_SFINAE_BUG
20+
bool(
21+
#endif
22+
Constructible_v<T, Args...>
23+
#ifndef TRIGGER_MSVC_SFINAE_BUG
24+
)
25+
#endif
26+
,
27+
T *
28+
>
29+
sfinaeFunction(Args &&...args) {
30+
T *rv = new(static_cast<void *>(space_)) T(std::forward<Args>(args)...);
31+
return rv;
32+
}
33+
34+
};
35+
36+
auto triggerError(ATemplate<void *[2]> &m) {
37+
return m.sfinaeFunction<void *>(nullptr);
38+
}
39+
40+
int main(int, const char *[]) { return 0; }

inc/zoo/AlignedStorage.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,21 @@ struct AlignedStorage {
122122

123123
template<typename T, typename... Args>
124124
#define PP_ZOO_BUILD_EXPRESSION \
125-
impl::build(*as<T>(), std::forward<Args>(args)...)
126-
auto build(Args &&...args) noexcept(noexcept(PP_ZOO_BUILD_EXPRESSION)) ->
125+
impl::build(*this->as<T>(), std::forward<Args>(args)...)
127126
std::enable_if_t<
128127
SuitableType<T>() &&
129-
impl::Constructible_v<T, Args...>,
128+
#ifdef _MSC_VER
129+
bool(
130+
#endif
131+
impl::Constructible_v<T, Args...>
132+
#ifdef _MSC_VER
133+
)
134+
#endif
135+
,
136+
130137
T *
131138
>
139+
build(Args &&...args) noexcept(noexcept(PP_ZOO_BUILD_EXPRESSION))
132140
{
133141
PP_ZOO_BUILD_EXPRESSION;
134142
#undef PP_ZOO_BUILD_EXPRESSION

inc/zoo/algorithm/cfs.h

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,27 @@
11
#ifndef ZOO_CFS_CACHE_FRIENDLY_SEARCH
22
#define ZOO_CFS_CACHE_FRIENDLY_SEARCH
33

4-
#include <zoo/algorithm/less.h>
4+
#include "zoo/algorithm/less.h"
5+
#include "zoo/meta/log.h"
56

67
#ifndef SIMPLIFY_INCLUDES
78
// because of std::declval needed to default comparator
89
#include <utility>
910
// because of std::decay needed to decay deferenced iterator
1011
#include <type_traits>
11-
#endif
1212

13-
namespace zoo {
13+
#ifdef _MSC_VER
14+
#include <iso646.h>
15+
#endif
1416

15-
constexpr unsigned long long log2Floor(unsigned long long arg) {
16-
return 63 - __builtin_clzll(arg);
17-
}
17+
#endif
1818

19-
constexpr unsigned long long log2Ceiling(unsigned long long arg) {
20-
return 63 - __builtin_clzll(2*arg - 1);
21-
}
19+
namespace zoo {
2220

2321
template<typename Output, typename Input>
2422
void transformToCFS(Output output, Input base, Input end) {
2523
auto s = end - base;
26-
auto logP = log2Floor(s + 1); // n
24+
auto logP = meta::logFloor(s + 1); // n
2725
auto power2 = 1ul << logP;
2826
auto fullSubtreeSize = power2 - 1;
2927
// Full tree has (2^n) - 1 elements
@@ -52,7 +50,8 @@ void transformToCFS(Output output, Input base, Input end) {
5250
}
5351

5452
// now just write the excess leaves
55-
for(auto ndx = 0ul, top = 2*excess; ndx < top; ndx += 2) {
53+
auto top = 2*excess;
54+
for(auto ndx = 0ll; ndx < top; ndx += 2) {
5655
*output++ = *(base + ndx);
5756
}
5857
}
@@ -167,7 +166,7 @@ struct ValidResult {
167166

168167
template<typename I, typename Comparator = Less>
169168
auto validHeap(
170-
I base, int current, int max, Comparator c = Comparator{}
169+
I base, long current, long max, Comparator c = Comparator{}
171170
) -> ValidResult {
172171
for(;;) {
173172
auto higherSubtree = current*2 + 2;

inc/zoo/algorithm/quicksort.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
#include <array> // for temporary storage
99
#include <stdexcept>
1010

11+
#ifdef _MSC_VER
12+
#include <iso646.h>
13+
#endif
14+
1115
namespace zoo {
1216

1317
template<typename FI>

inc/zoo/meta/log.h

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,39 @@
55

66
namespace zoo { namespace meta {
77

8-
constexpr int logFloor(uint64_t arg) {
9-
return 63 - __builtin_clzll(arg);
10-
}
11-
12-
constexpr int logCeiling(uint64_t arg) {
13-
auto floorLog = logFloor(arg);
14-
return floorLog + ((arg ^ (1ull << floorLog)) ? 1 : 0);
15-
}
16-
178
/// The algorithm is, from the perspective of the most significant bit set, to copy it
189
/// downward to all positions.
1910
/// First copy it once, meaning a group of two copies of the two most significant bit
2011
/// Then copy it again, making a group of four copies, then 8 copies...
2112
template<typename T>
22-
constexpr int logCeiling_WithoutIntrinsic(T value) {
13+
constexpr int logFloor_WithoutIntrinsic(T value) {
2314
constexpr auto NBitsTotal = sizeof(T) * 8;
2415
for(auto groupSize = 1; groupSize < NBitsTotal; groupSize <<= 1) {
2516
value |= (value >> groupSize);
2617
}
2718
return PopcountLogic<detail::BitWidthLog<T>, T>::execute(value) - 1;
2819
}
29-
20+
21+
#ifdef _MSC_VER
22+
// change to use the relevant functions in C++ 20's <bit> header
23+
// when bumping to C++ 20
24+
constexpr int logFloor(uint64_t arg) {
25+
return logFloor_WithoutIntrinsic(arg);
26+
}
27+
#else
28+
constexpr int logFloor(uint64_t arg) {
29+
return 63 - __builtin_clzll(arg);
30+
}
31+
#endif
32+
33+
constexpr int logCeiling(uint64_t arg) {
34+
auto floorLog = logFloor(arg);
35+
return
36+
floorLog +
37+
// turn off the most significant bit and convert to 1 or 0
38+
((arg ^ (1ull << floorLog)) ? 1 : 0);
39+
}
40+
3041
}}
3142

3243
#endif

inc/zoo/meta/popcount.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ constexpr T PopcountLogic<LogarithmOfGroupSize, T>::execute(T input) {
6969
Recursion::execute((input >> HalvedGroupSize) & CombiningMask);
7070
}
7171

72+
#ifdef _MSC_VER
73+
template<int LogarithmOfGroupSize, typename T = uint64_t>
74+
using PopcountIntrinsic = PopcountLogic<LogarithmOfGroupSize, T>;
75+
#else
7276
template<int LogarithmOfGroupSize, typename T = uint64_t>
7377
struct PopcountIntrinsic {
7478
constexpr static T execute(T input) {
@@ -84,6 +88,7 @@ struct PopcountIntrinsic {
8488
return rv;
8589
}
8690
};
91+
#endif
8792

8893
}}
8994

inc/zoo/swar/SWAR.h

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
#include <type_traits>
88

9+
#ifdef _MSC_VER
10+
#include <iso646.h>
11+
#endif
12+
913
namespace zoo { namespace swar {
1014

1115
using u64 = uint64_t;
@@ -27,13 +31,14 @@ constexpr uint64_t popcount(uint64_t a) noexcept {
2731
/// Index into the bits of the type T that contains the MSB.
2832
template<typename T>
2933
constexpr std::make_unsigned_t<T> msbIndex(T v) noexcept {
30-
return 8*sizeof(T) - 1 - __builtin_clzll(v);
34+
return meta::logFloor(v);
3135
}
3236

3337
/// Index into the bits of the type T that contains the LSB.
3438
template<typename T>
3539
constexpr std::make_unsigned_t<T> lsbIndex(T v) noexcept {
36-
return __builtin_ctzll(v) + 1;
40+
// ~v & (v - 1) turns on all trailing zeroes, zeroes the rest
41+
return meta::logFloor(1 + (~v & (v - 1)));
3742
}
3843

3944
/// Core abstraction around SIMD Within A Register (SWAR). Specifies 'lanes'
@@ -44,12 +49,14 @@ constexpr std::make_unsigned_t<T> lsbIndex(T v) noexcept {
4449
template<int NBits_, typename T = uint64_t>
4550
struct SWAR {
4651
using type = T;
47-
constexpr static inline auto NBits = NBits_;
48-
constexpr static inline auto Lanes = sizeof(T) * 8 / NBits;
49-
constexpr static inline auto NSlots = Lanes;
50-
constexpr static T BitMod = sizeof(T)*8 % NBits;
51-
constexpr static T ValidBitsCount = sizeof(T)*8 - BitMod;
52-
constexpr static T AllOnes = (BitMod == 0) ? ~(T(0)) : ((T(1) << ValidBitsCount) -1);
52+
constexpr static inline std::make_unsigned_t<T>
53+
NBits = NBits_,
54+
BitWidth = sizeof(T) * 8,
55+
Lanes = BitWidth / NBits,
56+
NSlots = Lanes,
57+
PaddingBitsCount = BitWidth % NBits,
58+
SignificantBitsCount = BitWidth - PaddingBitsCount,
59+
AllOnes = ~std::make_unsigned_t<T>{0} >> PaddingBitsCount;
5360

5461
SWAR() = default;
5562
constexpr explicit SWAR(T v): m_v(v) {}
@@ -92,13 +99,21 @@ struct SWAR {
9299

93100
/// The SWAR lane index that contains the MSB. It is not the bit index of the MSB.
94101
/// IE: 4 bit wide 32 bit SWAR: 0x0040'0000 will return 5, not 22 (0 indexed).
95-
constexpr int top() const noexcept { return msbIndex(m_v) / NBits; }
96-
constexpr int lsbIndex() const noexcept { return __builtin_ctzll(m_v) / NBits; }
102+
constexpr auto top() const noexcept { return msbIndex(m_v) / NBits; }
103+
constexpr auto lsbIndex() const noexcept { return swar::lsbIndex(m_v) / NBits; }
97104

98105
constexpr SWAR setBit(int index, int bit) const noexcept {
99106
return SWAR(m_v | (T(1) << (index * NBits + bit)));
100107
}
101108

109+
constexpr SWAR shiftLanesLeft(int laneCount) const noexcept {
110+
return SWAR(value() << (NBits * laneCount));
111+
}
112+
113+
constexpr SWAR shiftLanesRight(int laneCount) const noexcept {
114+
return SWAR(value() >> (NBits * laneCount));
115+
}
116+
102117
constexpr auto blitElement(int index, T value) const noexcept {
103118
auto elementMask = ((T(1) << NBits) - 1) << (index * NBits);
104119
return SWAR((m_v & ~elementMask) | (value << (index * NBits)));
@@ -110,14 +125,6 @@ struct SWAR {
110125
return (*this & ~IsolationMask) | (other & IsolationMask);
111126
}
112127

113-
constexpr SWAR shiftLanesLeft(int laneCount) const noexcept {
114-
return SWAR(value() << (NBits * laneCount));
115-
}
116-
117-
constexpr SWAR shiftLanesRight(int laneCount) const noexcept {
118-
return SWAR(value() >> (NBits * laneCount));
119-
}
120-
121128
T m_v;
122129
};
123130

inc/zoo/traits/is_container.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33

44
#ifndef SIMPLIFY_INCLUDES
55
#include <type_traits>
6+
7+
#ifdef _MSC_VER
8+
#include <iso646.h>
9+
#endif
10+
611
#endif
712

813
namespace zoo {

inc/zoo/util/range_equivalence.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ namespace zoo {
88
template<typename C1, typename C2>
99
auto operator==(const C1 &l, const C2 &r)
1010
-> std::enable_if_t<
11-
zoo::is_container_v<C1> and
12-
zoo::is_container_v<C2>,
11+
bool(zoo::is_container_v<C1>) and
12+
bool(zoo::is_container_v<C2>),
1313
bool
1414
>
1515
{

0 commit comments

Comments
 (0)