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-
232217protected:
233218 pointer begin_ = nullptr ;
234219 pointer end_ = nullptr ;
0 commit comments