Skip to content

Commit 9c8cd71

Browse files
committed
Implement 0-sized array with a direct specialization. This avoids putting [[no_unique_address]] on the array member, which avoids a memory usage + massive compile time bug on clang.
1 parent cd14715 commit 9c8cd71

File tree

2 files changed

+53
-32
lines changed

2 files changed

+53
-32
lines changed

source/containers/array.cpp

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -34,27 +34,6 @@ struct array_value_type<T> {
3434
using type = T;
3535
};
3636

37-
struct monostate {
38-
// Cannot be a hidden friend to work around
39-
// https://github.com/llvm/llvm-project/issues/123815
40-
auto operator<=>(monostate const &) const & = default;
41-
};
42-
43-
template<std::size_t size>
44-
struct array_trait {
45-
template<typename T>
46-
using type = T[size];
47-
};
48-
49-
template<>
50-
struct array_trait<0> {
51-
template<typename>
52-
using type = monostate;
53-
};
54-
55-
template<typename T, std::size_t size>
56-
using array_type = typename array_trait<size>::template type<T>;
57-
5837
export template<typename T, array_size_type<T> size_, array_size_type<T>... sizes>
5938
struct array {
6039
using value_type = typename array_value_type<T, sizes...>::type;
@@ -63,18 +42,10 @@ struct array {
6342
return bounded::constant<size_>;
6443
}
6544
constexpr auto data() const -> value_type const * {
66-
if constexpr (size() != 0) {
67-
return m_value;
68-
} else {
69-
return nullptr;
70-
}
45+
return m_value;
7146
}
7247
constexpr auto data() -> value_type * {
73-
if constexpr (size() != 0) {
74-
return m_value;
75-
} else {
76-
return nullptr;
77-
}
48+
return m_value;
7849
}
7950

8051
OPERATORS_BRACKET_SEQUENCE_RANGE_DEFINITIONS
@@ -96,7 +67,46 @@ struct array {
9667

9768
// Consider this private. It must be public for the class to be an
9869
// aggregate
99-
[[no_unique_address]] array_type<value_type, static_cast<std::size_t>(size_)> m_value;
70+
c_array<value_type, static_cast<std::size_t>(size_)> m_value;
71+
};
72+
73+
template<typename T, array_size_type<T> size_> requires(size_ == 0_bi)
74+
struct array<T, size_> {
75+
private:
76+
struct monostate {
77+
friend auto operator<=>(monostate, monostate) = default;
78+
};
79+
public:
80+
using value_type = T;
81+
82+
static constexpr auto size() -> bounded::constant_t<0> {
83+
return 0_bi;
84+
}
85+
constexpr auto data() const -> value_type const * {
86+
return nullptr;
87+
}
88+
constexpr auto data() -> value_type * {
89+
return nullptr;
90+
}
91+
92+
friend auto operator<=>(array, array) = default;
93+
94+
constexpr operator std::span<T const>() const {
95+
return std::span<T const>(data(), 0);
96+
}
97+
constexpr operator std::span<T>() {
98+
return std::span<T const>(data(), 0);
99+
}
100+
constexpr operator std::span<T const, 0>() const {
101+
return std::span<T const, 0>(data(), 0);
102+
}
103+
constexpr operator std::span<T, 0>() {
104+
return std::span<T const, 0>(data(), 0);
105+
}
106+
107+
// Consider this private. It must be public for the class to be an
108+
// aggregate
109+
[[no_unique_address]] monostate m_value;
100110
};
101111

102112
template<typename... Args>

source/containers/test/array.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@ static_assert(qualifiers_are_contiguous_ranges<containers::array<int, 5_bi>>);
3939
static_assert(containers::is_container<containers::array<int, 0_bi>>);
4040
static_assert(containers::is_container<containers::array<int, 1_bi>>);
4141

42+
static_assert(bounded::convertible_to<containers::array<int, 0_bi> const &, std::span<int const>>);
43+
static_assert(std::span<int const>(containers::array<int, 0_bi>()).size() == 0);
44+
static_assert(!bounded::convertible_to<containers::array<int, 0_bi> const &, std::span<int>>);
45+
static_assert(bounded::convertible_to<containers::array<int, 0_bi> &, std::span<int const>>);
46+
static_assert(bounded::convertible_to<containers::array<int, 0_bi> &, std::span<int>>);
47+
48+
static_assert(bounded::convertible_to<containers::array<int, 0_bi> const &, std::span<int const, 0>>);
49+
static_assert(!bounded::convertible_to<containers::array<int, 0_bi> const &, std::span<int, 0>>);
50+
static_assert(bounded::convertible_to<containers::array<int, 0_bi> &, std::span<int const, 0>>);
51+
static_assert(bounded::convertible_to<containers::array<int, 0_bi> &, std::span<int, 0>>);
52+
4253
static_assert(bounded::convertible_to<containers::array<int, 3_bi> const &, std::span<int const>>);
4354
static_assert(!bounded::convertible_to<containers::array<int, 3_bi> const &, std::span<int>>);
4455
static_assert(bounded::convertible_to<containers::array<int, 3_bi> &, std::span<int const>>);

0 commit comments

Comments
 (0)