Skip to content

Commit e7e97e1

Browse files
committed
array_ref replace enable_if with requires clause
1 parent a3ce5c5 commit e7e97e1

2 files changed

Lines changed: 49 additions & 66 deletions

File tree

Common.ArrayRef.h

Lines changed: 49 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,31 @@
44
//----------------------------------------------------------------------------
55
#pragma once
66

7+
// Class-specific constraint concepts.
8+
// (quite ridiculously, class-specific concepts cannot actually be declared
9+
// *inside* the pertinent class where you'd expect them)
10+
namespace array_ref_concepts
11+
{
12+
// The array/initializer_list/other type is very basic and returns pointers
13+
// directly rather than iterators. In that case, just use end() rather than
14+
// use size(), which incurs an unnecessary division and multiplication each
15+
// call.
16+
template<typename T> concept IsContiguousMemoryTypeWithBeginEnd = requires(T&& c)
17+
{
18+
std::data(c);
19+
std::begin(c);
20+
std::end(c);
21+
requires std::is_same_v<decltype(std::begin(c)), decltype(std::data(c))>;
22+
requires std::is_same_v<decltype(std::end(c)), decltype(std::data(c))>;
23+
};
24+
25+
template<typename T> concept IsContiguousMemoryTypeWithDataSize = requires(T&& c)
26+
{
27+
std::data(c);
28+
std::size(c);
29+
};
30+
}
31+
732
// View of contiguous memory, which may come from an std::vector,
833
// std::wstring, std::initializer_list, std::array, plain C array,
934
// or even raw memory.
@@ -37,27 +62,29 @@ class array_ref
3762
using size_type = size_t;
3863
using difference_type = ptrdiff_t;
3964

40-
// construct/copy
4165
constexpr array_ref() = default;
42-
constexpr array_ref(array_ref<typename T> const& other) = default;
43-
4466
constexpr array_ref(pointer array, size_t elementCount) : begin_(array), end_(array + elementCount) {}
4567
constexpr array_ref(pointer begin, pointer end) : begin_(begin), end_(end) {}
4668

69+
using ConstArrayRefType = array_ref<const typename T>;
4770
using NonConstArrayRefType = array_ref<typename std::remove_const<T>::type>;
4871

49-
#if STD_STRING_MUTABLE_DATA_IS_FIXED_CPP17
50-
51-
template<typename ContiguousContainer>
52-
constexpr array_ref(ContiguousContainer& container)
53-
: begin_(std::data(container)),
54-
end_(begin_ + std::size(container))
72+
// Constructor for copying non-const array_ref's to const array_ref's.
73+
// The default constructor handles const to const and non-const to non-const,
74+
// but not non-const to const conversion. Implement it specially rather than
75+
// using the generic constructor below to avoid pointless division and
76+
// multiplication. The enable_if prevents the template from stealing all
77+
// overload calls away from the default copy constructor.
78+
template<typename ContiguousMemoryTypeWithBeginEnd>
79+
requires(array_ref_concepts::IsContiguousMemoryTypeWithBeginEnd<ContiguousMemoryTypeWithBeginEnd>)
80+
array_ref(ContiguousMemoryTypeWithBeginEnd&& other)
81+
: begin_(std::begin(other)),
82+
end_(std::end(other))
5583
{
5684
}
5785

58-
#else
5986
// Generic constructor to accept any container which uses contiguous memory
60-
// and exposes a data() member.
87+
// and exposes data() and size() members.
6188
//
6289
// Sadly some bugs/holes in the standard complicate genericity in getting
6390
// the data pointer, including std::initializer_list missing a data() member
@@ -68,41 +95,20 @@ class array_ref
6895
// constructor when copying another array_ref of the same constness,
6996
// instead of always calling this templated copy constructor.
7097
//
71-
template<
72-
typename ContiguousContainer,
73-
typename std::enable_if<
74-
!std::is_same<ContiguousContainer, array_ref<T> >::value &&
75-
!std::is_same<ContiguousContainer, NonConstArrayRefType>::value,
76-
int
77-
>::type = 0
78-
>
79-
constexpr array_ref(ContiguousContainer& container)
80-
: begin_(get_container_pointer(container)),
98+
// Note older compilers may have an issue with std::string which lacked a proper
99+
// mutable .data() method. http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2391
100+
//
101+
template<typename ContiguousMemoryTypeWithDataSize>
102+
requires(
103+
array_ref_concepts::IsContiguousMemoryTypeWithDataSize<ContiguousMemoryTypeWithDataSize> &&
104+
!array_ref_concepts::IsContiguousMemoryTypeWithBeginEnd<ContiguousMemoryTypeWithDataSize>
105+
)
106+
constexpr array_ref(ContiguousMemoryTypeWithDataSize&& container)
107+
: begin_(std::data(container)),
81108
end_(begin_ + std::size(container))
82109
{
83110
}
84111

85-
// Constructor for copying non-const array_ref's to const array_ref's.
86-
// The default constructor handles const to const and non-const to non-const,
87-
// but not non-const to const conversion. Implement it specially rather than
88-
// using the generic constructor below to avoid pointless division and
89-
// multiplication. The enable_if prevents the template from stealing all
90-
// overload calls away from the default copy constructor.
91-
template<
92-
typename OtherArrayRef,
93-
typename std::enable_if<
94-
!std::is_same<OtherArrayRef, typename array_ref<T> >::value &&
95-
std::is_same<OtherArrayRef, NonConstArrayRefType>::value,
96-
int
97-
>::type = 0
98-
>
99-
array_ref(OtherArrayRef const& other)
100-
: begin_(other.begin()),
101-
end_(other.end())
102-
{
103-
}
104-
#endif
105-
106112
// Reset to a new range using a compatible data type, possibly differing in constness
107113
// but only from non-const to const.
108114
//
@@ -112,7 +118,7 @@ class array_ref
112118
//
113119
template<typename ContiguousContainer> void reset(ContiguousContainer& container)
114120
{
115-
begin_ = get_container_pointer(container);
121+
begin_ = std::data(container);
116122
end_ = begin_ + std::size(container);
117123
}
118124

@@ -208,27 +214,6 @@ class array_ref
208214
static inline uint8_t const* to_byte_pointer(void const* p) { return reinterpret_cast<uint8_t const*>(p); }
209215
static inline uint8_t* to_byte_pointer(void* p) { return reinterpret_cast<uint8_t*>(p); }
210216

211-
// Unwraps the data pointer from the container passed.
212-
template <typename ContiguousContainer>
213-
inline static T* get_container_pointer(ContiguousContainer& container)
214-
{
215-
// This crazy function can be deleted once std::string is fixed.
216-
// http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2391
217-
//
218-
// std::data() and std::string::data() return a const pointer for a
219-
// mutable string even when s[0] and begin() are mutable. So we have to
220-
// cast away the constness while still staying const correct in the
221-
// case of an actual const string. To get the true type, dereference an
222-
// iterator (cannot use s[0] because std::initializer_list lacks that
223-
// operator overload, despite basically being an array), then get the
224-
// address of it (but not via operator '&' because some wrapping
225-
// classes have an operator overload that returns their base type
226-
// rather than the actual type), and then finally use the type of the
227-
// address for the const_cast.
228-
229-
return const_cast<decltype(std::addressof(*std::begin(container)))>(std::data(container));
230-
}
231-
232217
protected:
233218
pointer begin_ = nullptr;
234219
pointer end_ = nullptr;

Common.ArrayRef.ixx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
#include <vector>
1616
#include <string>
1717
#include <cassert>
18-
// Set 0 if your defective std::string.data() lacks a mutable overload.
19-
// #define STD_STRING_MUTABLE_DATA_IS_FIXED_CPP17 1
2018
#include <iterator>
2119

2220
////////////////////////////////////////

0 commit comments

Comments
 (0)