Skip to content

Commit ee09f85

Browse files
committed
fix universal: make enumerate consistent with respect to const
1 parent 6dce31c commit ee09f85

2 files changed

Lines changed: 39 additions & 16 deletions

File tree

universal/include/userver/utils/enumerate.hpp

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,26 +49,22 @@ struct IteratorWrapper {
4949
}
5050
};
5151

52-
template <typename Range>
53-
using IteratorTypeOf = decltype(std::begin(std::declval<Range&>()));
54-
55-
template <typename Range>
56-
using SentinelTypeOf = decltype(std::end(std::declval<Range&>()));
57-
5852
template <typename Container>
5953
struct ContainerWrapper {
60-
constexpr IteratorWrapper<IteratorTypeOf<Container>> begin() {
61-
return {.iterator = std::begin(container), .pos = 0};
54+
constexpr auto begin() {
55+
return IteratorWrapper{.iterator = std::begin(container), .pos = 0};
6256
}
6357

64-
constexpr IteratorWrapper<SentinelTypeOf<Container>> end() { return {.iterator = std::end(container), .pos = 0}; }
58+
constexpr auto end() {
59+
return IteratorWrapper{.iterator = std::end(container), .pos = 0};
60+
}
6561

66-
constexpr IteratorWrapper<IteratorTypeOf<const Container>> begin() const {
67-
return {.iterator = std::begin(container), .pos = 0};
62+
constexpr auto begin() const {
63+
return IteratorWrapper{.iterator = std::begin(std::as_const(container)), .pos = 0};
6864
}
6965

70-
constexpr IteratorWrapper<SentinelTypeOf<const Container>> end() const {
71-
return {.iterator = std::end(container), .pos = 0};
66+
constexpr auto end() const {
67+
return IteratorWrapper{.iterator = std::end(std::as_const(container)), .pos = 0};
7268
}
7369

7470
Container container;
@@ -81,9 +77,9 @@ namespace utils {
8177
/// @brief Implementation of python-style enumerate function for range-for loops
8278
/// @param iterable: Container to iterate
8379
/// @returns ContainerWrapper, which iterator after dereference returns pair
84-
/// of index and (!!!)non-const reference to element(it seems impossible to make
85-
/// this reference const). It can be used in "range based for loop" with
86-
/// "structured binding" like this
80+
/// of index and reference to element. The reference is const-qualified if either
81+
/// the wrapper itself or the underlying container is const; otherwise, it is non-const.
82+
/// It can be used in "range based for loop" with "structured binding" like this
8783
/// @code
8884
/// for (auto [pos, elem] : enumerate(someContainer)) {...}
8985
/// @endcode

universal/src/utils/enumerate_test.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#include <array>
2+
#include <type_traits>
3+
#include <utility>
24

35
#include <gmock/gmock.h>
46
#include <gtest/gtest.h>
@@ -9,6 +11,31 @@ USERVER_NAMESPACE_BEGIN
911

1012
namespace {
1113

14+
template <typename Container>
15+
using EnumerateImpl = decltype(utils::enumerate(std::declval<Container>()));
16+
17+
template <typename Container, bool ConstWrapper>
18+
using Enumerate = std::conditional_t<ConstWrapper, const EnumerateImpl<Container>, EnumerateImpl<Container>>;
19+
20+
template <typename Container, bool ConstWrapper>
21+
using EnumerateElem = decltype(*std::begin(std::declval<Enumerate<Container, ConstWrapper>&>()))::second_type;
22+
23+
static_assert(std::is_same_v<int&, EnumerateElem<std::vector<int>, false>>);
24+
static_assert(std::is_same_v<int&, EnumerateElem<std::vector<int>&, false>>);
25+
static_assert(std::is_same_v<int&, EnumerateElem<std::vector<int>&&, false>>);
26+
27+
static_assert(std::is_same_v<const int&, EnumerateElem<const std::vector<int>, false>>);
28+
static_assert(std::is_same_v<const int&, EnumerateElem<const std::vector<int>&, false>>);
29+
static_assert(std::is_same_v<const int&, EnumerateElem<const std::vector<int>&&, false>>);
30+
31+
static_assert(std::is_same_v<const int&, EnumerateElem<std::vector<int>, true>>);
32+
static_assert(std::is_same_v<const int&, EnumerateElem<std::vector<int>&, true>>);
33+
static_assert(std::is_same_v<const int&, EnumerateElem<std::vector<int>&&, true>>);
34+
35+
static_assert(std::is_same_v<const int&, EnumerateElem<const std::vector<int>, true>>);
36+
static_assert(std::is_same_v<const int&, EnumerateElem<const std::vector<int>&, true>>);
37+
static_assert(std::is_same_v<const int&, EnumerateElem<const std::vector<int>&&, true>>);
38+
1239
constexpr int ConstexprTest(std::array<int, 2> data) {
1340
int result = 0;
1441
for (auto [pos, elem] : utils::enumerate(data)) {

0 commit comments

Comments
 (0)