Skip to content

Commit fc492e3

Browse files
committed
✨ unwrapped_iterator / unwrapped_iterator_value
1 parent 8d53c8d commit fc492e3

File tree

5 files changed

+81
-17
lines changed

5 files changed

+81
-17
lines changed

documentation/source/api/unwrap.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@
2828
..
2929
.. =============================================================================>
3030
31-
unwrap / unwrap_iterator
31+
unwrap / unwrap_iterator_value
3232
========================
3333

3434
Utility extension points to transform a potentially wrapped value (like :doc:`ztd::uninit <uninit>`) so that the "real" value an be used. Often used in the guts of generic code rather than anywhere truly important, but a useful little utility nonetheless.
3535

36+
.. doxygenvariable:: ztd::unwrap_iterator_value
37+
3638
.. doxygenvariable:: ztd::unwrap_iterator
3739

3840
.. doxygenvariable:: ztd::unwrap

include/ztd/idk/unwrap.hpp

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ namespace ztd {
5252
using __is_unwrappable_value_test = decltype(unwrap(::std::declval<_Type>()));
5353

5454
template <typename _Type>
55-
using __is_unwrappable_iter_value_test = decltype(unwrap_iterator(::std::declval<_Type>()));
55+
using __is_unwrappable_iter_value_test = decltype(unwrap_iterator_value(::std::declval<_Type>()));
56+
57+
template <typename _Type>
58+
using __is_unwrappable_iter_test = decltype(unwrap_iterator(::std::declval<_Type>()));
5659
} // namespace __idk_detail
5760

5861
//////
@@ -62,11 +65,17 @@ namespace ztd {
6265
= ztd::is_detected_v<__idk_detail::__is_unwrappable_value_test, _Type>;
6366

6467
//////
65-
/// @brief Test whether a type can have `unwrap_iterator(...)` called on it.
68+
/// @brief Test whether a type can have `unwrap_iterator_value(...)` called on it.
6669
template <typename _Type>
6770
inline constexpr bool is_unwrappable_iterator_value_v
6871
= ztd::is_detected_v<__idk_detail::__is_unwrappable_iter_value_test, _Type>;
6972

73+
//////
74+
/// @brief Test whether a type can have `unwrap_iterator(...)` called on it.
75+
template <typename _Type>
76+
inline constexpr bool is_unwrappable_iterator_v
77+
= ztd::is_detected_v<__idk_detail::__is_unwrappable_iter_test, _Type>;
78+
7079
namespace __idk_detail {
7180
class __unwrap_fn : public ::ztd::hijack::token<__unwrap_fn>, public ::ztd_hijack_global_token<__unwrap_fn> {
7281
public:
@@ -99,13 +108,13 @@ namespace ztd {
99108

100109

101110
namespace __idk_detail {
102-
class __unwrap_iterator_fn : public ::ztd::hijack::token<__unwrap_iterator_fn>,
103-
public ::ztd_hijack_global_token<__unwrap_iterator_fn> {
111+
class __unwrap_iterator_value_fn : public ::ztd::hijack::token<__unwrap_iterator_value_fn>,
112+
public ::ztd_hijack_global_token<__unwrap_iterator_value_fn> {
104113
public:
105114
template <typename _Type>
106115
constexpr decltype(auto) operator()(_Type&& __value) const noexcept {
107116
if constexpr (is_unwrappable_iterator_value_v<_Type>) {
108-
return unwrap_iterator(::std::forward<_Type>(__value));
117+
return unwrap_iterator_value(::std::forward<_Type>(__value));
109118
}
110119
else {
111120
return ::ztd::unwrap(*::std::forward<_Type>(__value));
@@ -120,6 +129,37 @@ namespace ztd {
120129
/// value through.
121130
///
122131
/// @returns The iterator's unwrapped value.
132+
inline constexpr __idk_detail::__unwrap_iterator_value_fn unwrap_iterator_value = {};
133+
} // namespace __fn
134+
135+
136+
namespace __idk_detail {
137+
class __unwrap_iterator_fn : public ::ztd::hijack::token<__unwrap_iterator_fn>,
138+
public ::ztd_hijack_global_token<__unwrap_iterator_fn> {
139+
public:
140+
template <typename _Type>
141+
constexpr decltype(auto) operator()(_Type&& __value) const noexcept {
142+
#if ZTD_IS_ON(ZTD_STD_LIBRARY_RANGES_BASIC_CONST_ITERATOR)
143+
if constexpr (::ztd::is_specialization_of_v<::ztd::remove_cvref_t<_Type>,
144+
::std::basic_const_iterator>) {
145+
// peel off the const iterator where possible
146+
return ::std::forward<_Type>(__value).base();
147+
}
148+
else
149+
#endif
150+
{
151+
return ::std::forward<_Type>(__value);
152+
}
153+
}
154+
};
155+
} // namespace __idk_detail
156+
157+
inline namespace __fn {
158+
//////
159+
/// @brief Peels layers off of an iterator that may be wrapped in implementation-defined and standards-defined
160+
/// abstraction layers.
161+
///
162+
/// @returns The iterator's unwrapped value.
123163
inline constexpr __idk_detail::__unwrap_iterator_fn unwrap_iterator = {};
124164
} // namespace __fn
125165

@@ -131,9 +171,18 @@ namespace ztd {
131171
using unwrap_t = decltype(::ztd::unwrap(::std::declval<_Type>()));
132172

133173
//////
134-
/// @brief Retrives the unwrapped type if the object were put through a call to ztd::unwrap.
174+
/// @brief Retrives the unwrapped type if the object were put through a call to ztd::unwrap_iterator_value.
135175
///
136-
/// @remarks Typically used to get the type underlying a `std::reference_wrapper` or similar.
176+
/// @remarks Typically used to get the type underlying an iterator whose value may be wrapped up in certain
177+
/// abstractions.
178+
template <typename _Type>
179+
using unwrap_iterator_value_t = decltype(::ztd::unwrap_iterator_value(::std::declval<_Type>()));
180+
181+
//////
182+
/// @brief Retrives the unwrapped type if the object were put through a call to ztd::unwrap_iterator.
183+
///
184+
/// @remarks Typically used to peel off various layers of implementation-defiend and other boilerplate around
185+
/// iterator types.
137186
template <typename _Type>
138187
using unwrap_iterator_t = decltype(::ztd::unwrap_iterator(::std::declval<_Type>()));
139188

include/ztd/ranges/word_iterator.hpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,9 @@ namespace ztd { namespace ranges {
126126
using __base_reference = iterator_reference_t<__base_iterator>;
127127
using __maybe_void_base_value_type = iterator_value_type_t<__base_iterator>;
128128
using __base_value_type = ::std::conditional_t<::std::is_void_v<__maybe_void_base_value_type> // cf
129-
|| (!::std::is_arithmetic_v<__maybe_void_base_value_type> // cf
129+
|| (!::std::is_arithmetic_v<__maybe_void_base_value_type> // cf
130130
&& !::std::is_same_v<__maybe_void_base_value_type, ::std::byte>), // cf
131-
unsigned char, __maybe_void_base_value_type>;
131+
unsigned char, __maybe_void_base_value_type>;
132132
using __difference_type = iterator_difference_type_t<__base_iterator>;
133133
using __size_type = iterator_size_type_t<__base_iterator>;
134134
using __value_type = _Word;
@@ -145,10 +145,8 @@ namespace ztd { namespace ranges {
145145

146146
static inline constexpr __size_type __base_values_per_word = sizeof(__value_type) / sizeof(__base_value_type);
147147

148-
template <bool _IsConst>
149148
class __word_reference {
150149
private:
151-
using __cv_value_type = ::std::conditional_t<_IsConst, const _Word, _Word>;
152150
using __underlying_base_value_type
153151
= decltype(::ztd::any_enum_or_char_to_underlying(__base_value_type {}));
154152
using __underlying_word_type
@@ -161,8 +159,11 @@ namespace ztd { namespace ranges {
161159
public:
162160
constexpr __word_reference(_URange& __range) noexcept : _M_base_range_ref(__range) {
163161
}
162+
constexpr __word_reference(const _URange& __range) noexcept
163+
: _M_base_range_ref(const_cast<_URange&>(__range)) {
164+
}
164165

165-
template <typename _Value, ::std::enable_if_t<::ztd::always_true_v<_Value> && !_IsConst>* = nullptr>
166+
template <typename _Value, ::std::enable_if_t<!::std::is_same_v<_Value, __word_reference>>* = nullptr>
166167
constexpr __word_reference& operator=(_Value __maybe_val) noexcept {
167168
if constexpr (_Endian == endian::native
168169
&& (endian::native != endian::big && endian::native != endian::little)) {
@@ -324,10 +325,10 @@ namespace ztd { namespace ranges {
324325
using value_type = __value_type;
325326
//////
326327
///@brief The non-const-qualified reference type.
327-
using reference = ::std::conditional_t<_IsInputOrOutput, value_type&, __word_reference<false>>;
328+
using reference = ::std::conditional_t<_IsInputOrOutput, value_type&, __word_reference>;
328329
//////
329330
///@brief The const-qualified reference type.
330-
using const_reference = ::std::conditional_t<_IsInputOrOutput, const value_type&, __word_reference<true>>;
331+
using const_reference = ::std::conditional_t<_IsInputOrOutput, const value_type&, __word_reference>;
331332

332333
private:
333334
static constexpr bool _S_deref_noexcept() noexcept {
@@ -655,7 +656,7 @@ namespace ztd { namespace ranges {
655656
private:
656657
constexpr void _M_read_one() noexcept(_S_deref_noexcept()) {
657658
if constexpr (_IsInputOrOutput) {
658-
_Word __read_word = __word_reference<true>(this->__base_storage_t::get_value());
659+
_Word __read_word = __word_reference(this->__base_storage_t::get_value());
659660
this->__base_storage_t::_M_val = ::std::optional<_Word>(__read_word);
660661
}
661662
}

include/ztd/ranges/wrapped_pointer.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ namespace ztd { namespace ranges {
148148
}
149149

150150
friend constexpr pointer to_address(const wrapped_pointer& __wrapped) noexcept {
151-
return ztd::unwrap_iterator(__wrapped._M_ptr);
151+
return ztd::unwrap_iterator_value(__wrapped._M_ptr);
152152
}
153153

154154
private:

include/ztd/version/detail/version.c++.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,18 @@
279279
#define ZTD_STD_LIBRARY_RANGES_I_ ZTD_DEFAULT_OFF
280280
#endif
281281

282+
#if defined(ZTD_STD_LIBRARY_RANGES_BASIC_CONST_ITERATOR)
283+
#if (ZTD_STD_LIBRARY_RANGES_BASIC_CONST_ITERATOR != 0)
284+
#define ZTD_STD_LIBRARY_RANGES_BASIC_CONST_ITERATOR_I_ ZTD_ON
285+
#else
286+
#define ZTD_STD_LIBRARY_RANGES_BASIC_CONST_ITERATOR_I_ ZTD_OFF
287+
#endif
288+
#elif defined(__cpp_lib_ranges_as_const) && __cpp_lib_ranges_as_const >= 202207L
289+
#define ZTD_STD_LIBRARY_RANGES_BASIC_CONST_ITERATOR_I_ ZTD_DEFAULT_ON
290+
#else
291+
#define ZTD_STD_LIBRARY_RANGES_BASIC_CONST_ITERATOR_I_ ZTD_DEFAULT_OFF
292+
#endif
293+
282294
#if defined(ZTD_STD_LIBRARY_ENDIAN)
283295
#if (ZTD_STD_LIBRARY_ENDIAN != 0)
284296
#define ZTD_STD_LIBRARY_ENDIAN_I_ ZTD_ON

0 commit comments

Comments
 (0)