BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bslstl_iteratorutil.h
Go to the documentation of this file.
1/// @file bslstl_iteratorutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslstl_iteratorutil.h -*-C++-*-
8#ifndef INCLUDED_BSLSTL_ITERATORUTIL
9#define INCLUDED_BSLSTL_ITERATORUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslstl_iteratorutil bslstl_iteratorutil
15/// @brief Provide utilities operating on iterators and iterator ranges.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslstl
19/// @{
20/// @addtogroup bslstl_iteratorutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslstl_iteratorutil-purpose"> Purpose</a>
25/// * <a href="#bslstl_iteratorutil-classes"> Classes </a>
26/// * <a href="#bslstl_iteratorutil-description"> Description </a>
27/// * <a href="#bslstl_iteratorutil-usage"> Usage </a>
28/// * <a href="#bslstl_iteratorutil-example-1-finding-the-distance-between-two-random-access-iterators"> Example 1: Finding the Distance Between Two Random Access Iterators </a>
29///
30/// # Purpose {#bslstl_iteratorutil-purpose}
31/// Provide utilities operating on iterators and iterator ranges.
32///
33/// # Classes {#bslstl_iteratorutil-classes}
34///
35/// - bslstl::IteratorUtil:
36///
37/// @see bslstl_hashtable
38///
39/// # Description {#bslstl_iteratorutil-description}
40/// This component provides a namespace, `bslstl::IteratorUtil`,
41/// containing utility functions for iterator types. In particular, this
42/// component includes a function `insertDistance` that returns the number of
43/// elements that should be accounted for when range-inserting in a container,
44/// given a pair of iterators `a` and `b` describing a half-open range
45/// `[a .. b)`.
46///
47/// ## Usage {#bslstl_iteratorutil-usage}
48///
49///
50/// This section illustrates intended use of this component.
51///
52/// ### Example 1: Finding the Distance Between Two Random Access Iterators {#bslstl_iteratorutil-example-1-finding-the-distance-between-two-random-access-iterators}
53///
54///
55/// Suppose we want to find the number of elements between two random access
56/// iterators.
57///
58/// First, we create an array of integer values and two pointers (which are
59/// considered random access iterators) referring to the beginning and end of a
60/// range within that array:
61/// @code
62/// int values[] = { 1, 2, 3, 4, 5 };
63/// int *begin = &values[0];
64/// int *end = &values[3];
65/// @endcode
66/// Now, we use the `IteratorUtil::insertDistance` class method to calculate the
67/// distance of the open range `[begin .. end)`:
68/// @code
69/// std::size_t distance = IteratorUtil::insertDistance(begin, end);
70/// assert(3 == distance);
71/// @endcode
72/// @}
73/** @} */
74/** @} */
75
76/** @addtogroup bsl
77 * @{
78 */
79/** @addtogroup bslstl
80 * @{
81 */
82/** @addtogroup bslstl_iteratorutil
83 * @{
84 */
85
86#include <bslscm_version.h>
87
88#include <bslstl_iterator.h> // iterator tags, distance
89#include <bslstl_pair.h> // pair
90#include <bslstl_ranges.h>
91
92#include <bslmf_addconst.h>
93#include <bslmf_removeconst.h>
94
95#include <bsls_keyword.h>
96#include <bsls_platform.h>
97
98#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
99#include <bsls_nativestd.h>
100#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
101
102
103namespace bslstl {
104
105#if defined(BSLS_LIBRARYFEATURES_HAS_CPP20_RANGES)
106 template <typename t_ITERATOR>
107 concept IteratorUtil_ModernIterator =
108 requires { typename t_ITERATOR::iterator_concept; };
109#endif // BSLS_LIBRARYFEATURES_HAS_CPP20_RANGES
110
111 // ========================================
112 // struct IteratorUtil_LegacyInsertDistance
113 // ========================================
114
115/// This supporting utility type is used for type-based dispatch as part of the
116/// implementation of the similarly structured functions `insertDistance` and
117/// `canCalculateInsertDistance` from `IteratorUtil`. Selection between the
118/// primary template and secondary (much simpler) one is performed based on the
119/// defaulted third parameter that checks if the (template parameter) type
120/// `t_SENTINEL` is convertible to the (template parameter) type
121/// `t_INPUT_ITERATOR`. When the primary template is selected, the decision
122/// to delegate distance calculation to `bsl::distance` is performed using
123/// tag dispatch.
124template <class t_INPUT_ITERATOR,
125 class t_SENTINEL,
126 bool t_MATCHING_SENTINEL =
129{
130private:
131 // PRIVATE CLASS METHODS
132
133 /// Return `0` if the last (unnamed) parameter indicates that the
134 /// iterator category is not a forward iterator, otherwise return
135 /// `bsl::distance(first, last)`.
136 static
137 typename bsl::iterator_traits<t_INPUT_ITERATOR>::difference_type
138 doCalc(const t_INPUT_ITERATOR&,
139 const t_INPUT_ITERATOR&,
140 const std::input_iterator_tag&);
141 static
142 typename bsl::iterator_traits<t_INPUT_ITERATOR>::difference_type
143 doCalc(const t_INPUT_ITERATOR& first,
144 const t_INPUT_ITERATOR& last,
145 const std::forward_iterator_tag&);
146
147public:
148 // CLASS METHODS
149
150 /// Return `true` if the (template parameter) type `t_INPUT_ITERATOR` has
151 /// a forward iterator category and the (template parameter) type
152 /// `t_SENTINEL` is convertible to `t_INPUT_ITERATOR`.
154
155 /// Return the number of elements in the range `[first, last)` if
156 /// the (template parameter) type `t_SENTINEL` is convertible to the
157 /// (template parameter) type `t_INPUT_ITERATOR` and `t_INPUT_ITERATOR`
158 /// has a forward iterator category; otherwise return 0.
159 static
160 typename bsl::iterator_traits<t_INPUT_ITERATOR>::difference_type
161 insertDistance(const t_INPUT_ITERATOR& first, const t_SENTINEL& last);
162};
163
164/// This partial specialization handles the case where the sentinel type is not
165/// convertible to the iterator type and thus we do not support distance calculation.
166///
167/// \note Note that this choice primarily applies on legacy platforms
168/// or when iterators do not properly model the modern iterator concepts.
169template <class t_INPUT_ITERATOR, class t_SENTINEL>
170struct IteratorUtil_LegacyInsertDistance<t_INPUT_ITERATOR, t_SENTINEL, false>
171{
172public:
173 // CLASS METHODS
174
176
177 static
178 typename bsl::iterator_traits<t_INPUT_ITERATOR>::difference_type
179 insertDistance(const t_INPUT_ITERATOR& first, const t_SENTINEL& last);
180};
181
182 // ===================
183 // struct IteratorUtil
184 // ===================
185
186/// This utility struct provides a namespace for functions on iterators and
187/// iterator ranges.
188///
189/// See @ref bslstl_iteratorutil
191 /// Return `true` if the calculation of `insertDistance` is supported for
192 /// iterators of the specified types, `false` otherwise.
193 template <class t_INPUT_ITERATOR, class t_SENTINEL>
195
196 /// Return 0 if the (template parameter) type `t_INPUT_ITERATOR` is limited
197 /// to the standard input-iterator category, otherwise return the number
198 /// of elements reachable from the specified `first` to (but not including)
199 /// the specified `last`. This function has a constant-time complexity
200 /// if the iterator category of `t_INPUT_ITERATOR` is strictly a standard
201 /// input iterator, or is a random access iterator, otherwise it is linear
202 /// in the length of the range `[first .. last)`.
203 ///
204 /// \pre The behavior is undefined unless `last` is reachable from `first`.
205 template <class t_INPUT_ITERATOR, class t_SENTINEL>
206 static typename bsl::iterator_traits<t_INPUT_ITERATOR>::difference_type
207 insertDistance(const t_INPUT_ITERATOR& first,
208 const t_SENTINEL& last);
209
210#ifdef BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
211 // These template aliases are "convenience aliases" defined in the standard
212 // as "exposition-only" to simplify the specification of the deduction
213 // guides for the associative containers.
214
215 /// Return the `value_type` of the specified iterator type.
216 template <class INPUT_ITER> // aka iter-val-type
217 using IterVal_t = typename bsl::iterator_traits<INPUT_ITER>::value_type;
218
219 /// Return the `key-type` of the specified iterator type, which is
220 /// expected to refer to a `pair<KEY_TYPE, MAPPED_TYPE>`.
221 template <class INPUT_ITER> // aka iter-key-type
222 using IterKey_t = bsl::remove_const_t<
223 typename bsl::iterator_traits<INPUT_ITER>::value_type::first_type>;
224
225 /// Return the `mapped-type` of the specified iterator type, which is
226 /// expected to refer to a `pair<KEY_TYPE, MAPPED_TYPE>`.
227 template <class INPUT_ITER> // aka iter-mapped-type
228 using IterMapped_t =
229 typename bsl::iterator_traits<INPUT_ITER>::value_type::second_type;
230
231 /// Return the type that is actually stored in a map. The supplied
232 /// iterator type is expected to refer to a
233 /// `pair<KEY_TYPE, MAPPED_TYPE>`.
234 template <class INPUT_ITER> // aka iter-to-alloc-type
235 using IterToAlloc_t = bsl::pair<
236 bsl::add_const_t<
237 typename bsl::iterator_traits<INPUT_ITER>::value_type::first_type>,
238 typename bsl::iterator_traits<INPUT_ITER>::value_type::second_type
239 >;
240#endif // BSLS_COMPILERFEATURES_SUPPORT_ALIAS_TEMPLATES
241};
242
243// ============================================================================
244// TEMPLATE AND INLINE FUNCTION DEFINITIONS
245// ============================================================================
246
247 // ---------------------------------------
248 // class IteratorUtil_LegacyInsertDistance
249 // ---------------------------------------
250
251template <class t_INPUT_ITERATOR,
252 class t_SENTINEL,
253 bool t_MATCHING_SENTINEL>
255IteratorUtil_LegacyInsertDistance<t_INPUT_ITERATOR,
256 t_SENTINEL,
257 t_MATCHING_SENTINEL>::canCalculate()
258{
259 return bsl::is_convertible<
260 typename bsl::iterator_traits<t_INPUT_ITERATOR>::iterator_category,
261 bsl::forward_iterator_tag>::value;
262}
263
264template <class t_INPUT_ITERATOR,
265 class t_SENTINEL,
266 bool t_MATCHING_SENTINEL>
267typename bsl::iterator_traits<t_INPUT_ITERATOR>::difference_type
268IteratorUtil_LegacyInsertDistance<t_INPUT_ITERATOR,
269 t_SENTINEL,
270 t_MATCHING_SENTINEL>::doCalc(
271 const t_INPUT_ITERATOR&,
272 const t_INPUT_ITERATOR&,
273 const std::input_iterator_tag&)
274{
275 return 0;
276}
277
278template <class t_INPUT_ITERATOR,
279 class t_SENTINEL,
280 bool t_MATCHING_SENTINEL>
281typename bsl::iterator_traits<t_INPUT_ITERATOR>::difference_type
282IteratorUtil_LegacyInsertDistance<t_INPUT_ITERATOR,
283 t_SENTINEL,
284 t_MATCHING_SENTINEL>::doCalc(
285 const t_INPUT_ITERATOR& first,
286 const t_INPUT_ITERATOR& last,
287 const std::forward_iterator_tag&)
288{
289 return bsl::distance(first, last);
290}
291
292template <class t_INPUT_ITERATOR,
293 class t_SENTINEL,
294 bool t_MATCHING_SENTINEL>
295typename bsl::iterator_traits<t_INPUT_ITERATOR>::difference_type
296IteratorUtil_LegacyInsertDistance<t_INPUT_ITERATOR,
297 t_SENTINEL,
298 t_MATCHING_SENTINEL>::insertDistance(
299 const t_INPUT_ITERATOR& first,
300 const t_SENTINEL& last)
301{
302 typedef typename bsl::iterator_traits<t_INPUT_ITERATOR>::iterator_category
303 IterCategory;
304 return doCalc(first,
305 static_cast<const t_INPUT_ITERATOR&>(last),
306 IterCategory()); // RETURN
307}
308
309template <class t_INPUT_ITERATOR,
310 class t_SENTINEL>
312IteratorUtil_LegacyInsertDistance<t_INPUT_ITERATOR,
313 t_SENTINEL,
314 false>::canCalculate()
315{
316 return false; // RETURN
317}
318
319template <class t_INPUT_ITERATOR,
320 class t_SENTINEL>
321typename bsl::iterator_traits<t_INPUT_ITERATOR>::difference_type
322IteratorUtil_LegacyInsertDistance<t_INPUT_ITERATOR,
323 t_SENTINEL,
324 false>::insertDistance(
325 const t_INPUT_ITERATOR&,
326 const t_SENTINEL&)
327{
328 return 0; // RETURN
329}
330
331 // ------------------
332 // class IteratorUtil
333 // ------------------
334
335template <class t_INPUT_ITERATOR, class t_SENTINEL>
337{
338 // Note that this function, `insertDistance`, and the test function
339 // `insertDistanceClassification` should all have the same structure
340 // for both correctness and maintainability.
341
342#if defined(BSLS_LIBRARYFEATURES_HAS_CPP20_RANGES)
343 typedef typename bsl::iterator_traits<t_INPUT_ITERATOR>::iterator_category
344 IterCategory;
345
346 // If we look like a modern iterator, or if the iterator and sentinel
347 // types are different, we should see if `ranges::distance` is usable
348 // before falling back to legacy approaches.
349 if constexpr (IteratorUtil_ModernIterator<t_INPUT_ITERATOR>
350 || !bsl::is_convertible_v<t_SENTINEL, t_INPUT_ITERATOR>)
351 {
352 if constexpr (bsl::input_iterator<t_INPUT_ITERATOR>
353 && bsl::sentinel_for<t_SENTINEL, t_INPUT_ITERATOR>)
354 {
355 if constexpr (bsl::forward_iterator<t_INPUT_ITERATOR>
356 && bsl::is_convertible_v<IterCategory,
357 bsl::forward_iterator_tag>) {
358 return true; // RETURN
359 }
360 else {
361 return false; // RETURN
362 }
363 }
364 else {
365 return false; // RETURN
366 }
367 }
368 else {
369#endif
370
372 t_INPUT_ITERATOR,
373 t_SENTINEL>::canCalculate(); // RETURN
374
375#if defined(BSLS_LIBRARYFEATURES_HAS_CPP20_RANGES)
376 } // close of `if constexpr`
377#endif // BSLS_LIBRARYFEATURES_HAS_CPP20_RANGES
378}
379
380template <class t_INPUT_ITERATOR, class t_SENTINEL>
381typename bsl::iterator_traits<t_INPUT_ITERATOR>::difference_type
382IteratorUtil::insertDistance(const t_INPUT_ITERATOR& first,
383 const t_SENTINEL& last)
384{
385 // Note that this function, `canCalculateInsertDistance`, and the test
386 // function `insertDistanceClassification` should all have the same
387 // structure for both correctness and maintainability.
388
389#if defined(BSLS_LIBRARYFEATURES_HAS_CPP20_RANGES)
390 typedef typename bsl::iterator_traits<t_INPUT_ITERATOR>::iterator_category
391 IterCategory;
392
393 if constexpr (IteratorUtil_ModernIterator<t_INPUT_ITERATOR>
394 || !bsl::is_convertible_v<t_SENTINEL, t_INPUT_ITERATOR>)
395 {
396 // If we can use `ranges::distance` we should.
397 if constexpr (bsl::input_iterator<t_INPUT_ITERATOR>
398 && bsl::sentinel_for<t_SENTINEL, t_INPUT_ITERATOR>)
399 {
400 // The iterator meets the requirements for calling
401 // `bsl::ranges::distance`, but we only want to check that distance
402 // if the iterator in question is a forward iterator. A C++20
403 // iterator will have an iterator category that looks like a
404 // forward iterator if it is copyable, even if its
405 // @ref iterator_concept is @ref input_iterator_tag . A classic C++17
406 // forward iterator might not meet the requirements of being a
407 // C++20 forward iterator for seemingly silly reasons like a
408 // mismatched return type on `operator++`. To minimize impact on
409 // legacy iterators, we therefore fall back to `bsl::distance` as
410 // long as the iterator doesn't have a nested @ref iterator_concept
411 // member.
412 if constexpr (bsl::forward_iterator<t_INPUT_ITERATOR>
413 && bsl::is_convertible_v<IterCategory,
414 bsl::forward_iterator_tag>) {
415 return bsl::ranges::distance(first, last); // RETURN
416 }
417 else {
418 return 0; // RETURN
419 }
420 }
421 else {
422 return 0; // RETURN
423 }
424 }
425 else {
426#endif // BSLS_LIBRARYFEATURES_HAS_CPP20_RANGES
427
429 t_INPUT_ITERATOR,
430 t_SENTINEL>::insertDistance(first, last); // RETURN
431
432#if defined(BSLS_LIBRARYFEATURES_HAS_CPP20_RANGES)
433 } // close of `if constexpr`
434#endif // BSLS_LIBRARYFEATURES_HAS_CPP20_RANGES
435}
436
437} // close package namespace
438
439
440#endif
441
442// ----------------------------------------------------------------------------
443// Copyright 2013 Bloomberg Finance L.P.
444//
445// Licensed under the Apache License, Version 2.0 (the "License");
446// you may not use this file except in compliance with the License.
447// You may obtain a copy of the License at
448//
449// http://www.apache.org/licenses/LICENSE-2.0
450//
451// Unless required by applicable law or agreed to in writing, software
452// distributed under the License is distributed on an "AS IS" BASIS,
453// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
454// See the License for the specific language governing permissions and
455// limitations under the License.
456// ----------------------------- END-OF-FILE ----------------------------------
457
458/** @} */
459/** @} */
460/** @} */
Definition bslstl_pair.h:1280
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_CONSTEXPR
Definition bsls_keyword.h:624
Definition bslstl_algorithm.h:84
Definition bslmf_isconvertible.h:875
Definition bslstl_iteratorutil.h:129
static BSLS_KEYWORD_CONSTEXPR bool canCalculate()
Definition bslstl_iteratorutil.h:257
static bsl::iterator_traits< t_INPUT_ITERATOR >::difference_type insertDistance(const t_INPUT_ITERATOR &first, const t_SENTINEL &last)
Definition bslstl_iteratorutil.h:298
Definition bslstl_iteratorutil.h:190
static BSLS_KEYWORD_CONSTEXPR bool canCalculateInsertDistance()
Definition bslstl_iteratorutil.h:336
static bsl::iterator_traits< t_INPUT_ITERATOR >::difference_type insertDistance(const t_INPUT_ITERATOR &first, const t_SENTINEL &last)
Definition bslstl_iteratorutil.h:382