|
16 | 16 | #ifndef GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__ |
17 | 17 | #define GOOGLE_PROTOBUF_GENERATED_ENUM_REFLECTION_H__ |
18 | 18 |
|
| 19 | +#include <cstddef> |
| 20 | +#include <iterator> |
19 | 21 | #include <string> |
| 22 | +#include <type_traits> |
20 | 23 |
|
| 24 | +#include "absl/log/absl_check.h" |
21 | 25 | #include "absl/strings/string_view.h" |
22 | 26 | #include "google/protobuf/generated_enum_util.h" |
23 | 27 | #include "google/protobuf/port.h" |
@@ -72,7 +76,79 @@ PROTOBUF_FUTURE_ADD_EARLY_NODISCARD |
72 | 76 | PROTOBUF_EXPORT const std::string& NameOfEnum( |
73 | 77 | const EnumDescriptor* PROTOBUF_NONNULL descriptor, int value); |
74 | 78 |
|
| 79 | +template <typename Enum> |
| 80 | +class EnumeratedEnumView { |
| 81 | + // Make the type dependent to avoid eager instantiations. |
| 82 | + // EnumDescriptor is incomplete at this point, but will be complete when this |
| 83 | + // template is instantiated. |
| 84 | + using Desc = std::enable_if_t<sizeof(Enum) != 0, EnumDescriptor>; |
| 85 | + |
| 86 | + public: |
| 87 | + using value_type = Enum; |
| 88 | + class iterator { |
| 89 | + public: |
| 90 | + using difference_type = ptrdiff_t; |
| 91 | + using value_type = Enum; |
| 92 | + using pointer = value_type*; |
| 93 | + using reference = value_type&; |
| 94 | + using iterator_category = std::input_iterator_tag; |
| 95 | + |
| 96 | + iterator() : desc_(nullptr), index_(0) {} |
| 97 | + iterator(const iterator&) = default; |
| 98 | + iterator& operator=(const iterator&) = default; |
| 99 | + |
| 100 | + friend bool operator==(iterator a, iterator b) { |
| 101 | + ABSL_DCHECK_EQ(a.desc_, b.desc_); |
| 102 | + return a.index_ == b.index_; |
| 103 | + } |
| 104 | + friend bool operator!=(iterator a, iterator b) { return !(a == b); } |
| 105 | + |
| 106 | + Enum operator*() const { |
| 107 | + return static_cast<Enum>(desc_->value(index_)->number()); |
| 108 | + } |
| 109 | + iterator& operator++() { |
| 110 | + ++index_; |
| 111 | + return *this; |
| 112 | + } |
| 113 | + iterator operator++(int) { |
| 114 | + auto copy = *this; |
| 115 | + ++*this; |
| 116 | + return copy; |
| 117 | + } |
| 118 | + |
| 119 | + private: |
| 120 | + friend EnumeratedEnumView; |
| 121 | + iterator(const Desc* PROTOBUF_NONNULL desc, int index) |
| 122 | + : desc_(desc), index_(index) {} |
| 123 | + const Desc* PROTOBUF_NONNULL desc_; |
| 124 | + int index_; |
| 125 | + }; |
| 126 | + using const_iterator = iterator; |
| 127 | + |
| 128 | + // Proto enums are never empty. |
| 129 | + bool empty() const { return false; } |
| 130 | + |
| 131 | + size_t size() const { return desc_->value_count(); } |
| 132 | + |
| 133 | + iterator begin() const { return iterator(desc_, 0); } |
| 134 | + iterator end() const { return iterator(desc_, size()); } |
| 135 | + iterator cbegin() const { return begin(); } |
| 136 | + iterator cend() const { return end(); } |
| 137 | + |
| 138 | + private: |
| 139 | + const Desc* PROTOBUF_NONNULL desc_ = GetEnumDescriptor<Enum>(); |
| 140 | +}; |
| 141 | + |
75 | 142 | } // namespace internal |
| 143 | + |
| 144 | +// Returns an iterable object that will yield all the enum labels for `Enum` in |
| 145 | +// the same order as specified in their EnumDescriptor. |
| 146 | +// The returned type is unspecified. |
| 147 | +template <typename Enum> |
| 148 | +auto EnumerateEnumValues() { |
| 149 | + return internal::EnumeratedEnumView<Enum>{}; |
| 150 | +} |
| 151 | + |
76 | 152 | } // namespace protobuf |
77 | 153 | } // namespace google |
78 | 154 |
|
|
0 commit comments