1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2023 Google LLC. All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file or at 6 // https://developers.google.com/open-source/licenses/bsd 7 8 #ifndef PROTOBUF_HPB_REPEATED_FIELD_ITERATOR_H_ 9 #define PROTOBUF_HPB_REPEATED_FIELD_ITERATOR_H_ 10 11 #include <cstddef> 12 #include <cstring> 13 #include <iterator> 14 #include <type_traits> 15 16 #include "absl/strings/string_view.h" 17 #include "google/protobuf/hpb/backend/upb/interop.h" 18 #include "google/protobuf/hpb/hpb.h" 19 #include "upb/base/string_view.h" 20 #include "upb/mem/arena.h" 21 #include "upb/message/array.h" 22 #include "upb/message/message.h" 23 24 namespace hpb { 25 namespace internal { 26 27 // TODO: Implement std iterator for messages 28 template <typename T> 29 class RepeatedFieldScalarProxy; 30 template <typename T> 31 class RepeatedFieldStringProxy; 32 33 struct IteratorTestPeer; 34 35 template <typename T> 36 class Iterator; 37 38 template <typename PolicyT> 39 class ReferenceProxy; 40 41 template <typename PolicyT> 42 class InjectedRelationalsImpl { 43 using RP = ReferenceProxy<PolicyT>; 44 using V = typename PolicyT::value_type; 45 friend bool operator==(RP a, V b) { return static_cast<V>(a) == b; } 46 friend bool operator==(V a, RP b) { return a == static_cast<V>(b); } 47 friend bool operator==(RP a, RP b) { 48 return static_cast<V>(a) == static_cast<V>(b); 49 } 50 friend bool operator!=(RP a, V b) { return static_cast<V>(a) != b; } 51 friend bool operator!=(V a, RP b) { return a != static_cast<V>(b); } 52 friend bool operator!=(RP a, RP b) { 53 return static_cast<V>(a) != static_cast<V>(b); 54 } 55 friend bool operator<(RP a, V b) { return static_cast<V>(a) < b; } 56 friend bool operator<(V a, RP b) { return a < static_cast<V>(b); } 57 friend bool operator<(RP a, RP b) { 58 return static_cast<V>(a) < static_cast<V>(b); 59 } 60 friend bool operator<=(RP a, V b) { return static_cast<V>(a) <= b; } 61 friend bool operator<=(V a, RP b) { return a <= static_cast<V>(b); } 62 friend bool operator<=(RP a, RP b) { 63 return static_cast<V>(a) <= static_cast<V>(b); 64 } 65 friend bool operator>(RP a, V b) { return static_cast<V>(a) > b; } 66 friend bool operator>(V a, RP b) { return a > static_cast<V>(b); } 67 friend bool operator>(RP a, RP b) { 68 return static_cast<V>(a) > static_cast<V>(b); 69 } 70 friend bool operator>=(RP a, V b) { return static_cast<V>(a) >= b; } 71 friend bool operator>=(V a, RP b) { return a >= static_cast<V>(b); } 72 friend bool operator>=(RP a, RP b) { 73 return static_cast<V>(a) >= static_cast<V>(b); 74 } 75 }; 76 class NoInjectedRelationalsImpl {}; 77 78 // We need to inject relationals for the string references because the 79 // relationals for string_view are templates and won't allow for implicit 80 // conversions from ReferenceProxy to string_view before deduction. 81 template <typename PolicyT> 82 using InjectedRelationals = std::conditional_t< 83 std::is_same_v<std::remove_const_t<typename PolicyT::value_type>, 84 absl::string_view>, 85 InjectedRelationalsImpl<PolicyT>, NoInjectedRelationalsImpl>; 86 87 template <typename PolicyT> 88 class ReferenceProxy : InjectedRelationals<PolicyT> { 89 using value_type = typename PolicyT::value_type; 90 91 public: 92 ReferenceProxy(const ReferenceProxy&) = default; 93 ReferenceProxy& operator=(const ReferenceProxy& other) { 94 // Assign through the references 95 // TODO: Make this better for strings to avoid the copy. 96 it_.Set(other.it_.Get()); 97 return *this; 98 } swap(ReferenceProxy a,ReferenceProxy b)99 friend void swap(ReferenceProxy a, ReferenceProxy b) { a.it_.swap(b.it_); } 100 value_type()101 operator value_type() const { return it_.Get(); } 102 void operator=(const value_type& value) const { it_.Set(value); } 103 void operator=(value_type&& value) const { it_.Set(std::move(value)); } 104 Iterator<PolicyT> operator&() const { return Iterator<PolicyT>(it_); } 105 106 private: 107 friend IteratorTestPeer; 108 friend ReferenceProxy<typename PolicyT::AddConst>; 109 friend Iterator<PolicyT>; 110 ReferenceProxy(typename PolicyT::Payload elem)111 explicit ReferenceProxy(typename PolicyT::Payload elem) : it_(elem) {} 112 typename PolicyT::Payload it_; 113 }; 114 115 template <template <typename> class PolicyTemplate, typename T> 116 class ReferenceProxy<PolicyTemplate<const T>> 117 : InjectedRelationals<PolicyTemplate<const T>> { 118 using PolicyT = PolicyTemplate<const T>; 119 using value_type = typename PolicyT::value_type; 120 121 public: ReferenceProxy(ReferenceProxy<PolicyTemplate<T>> p)122 ReferenceProxy(ReferenceProxy<PolicyTemplate<T>> p) : it_(p.it_) {} 123 ReferenceProxy(const ReferenceProxy&) = default; 124 ReferenceProxy& operator=(const ReferenceProxy&) = delete; 125 value_type()126 operator value_type() const { return it_.Get(); } 127 Iterator<PolicyT> operator&() const { return Iterator<PolicyT>(it_); } 128 129 private: 130 friend IteratorTestPeer; 131 friend Iterator<PolicyT>; 132 ReferenceProxy(typename PolicyT::Payload elem)133 explicit ReferenceProxy(typename PolicyT::Payload elem) : it_(elem) {} 134 typename PolicyT::Payload it_; 135 }; 136 137 template <typename PolicyT> 138 class Iterator { 139 public: 140 using iterator_category = std::random_access_iterator_tag; 141 using value_type = std::remove_const_t<typename PolicyT::value_type>; 142 using difference_type = std::ptrdiff_t; 143 using pointer = Iterator; 144 using reference = 145 std::conditional_t<PolicyT::kUseReferenceProxy, ReferenceProxy<PolicyT>, 146 typename PolicyT::value_type>; 147 Iterator()148 constexpr Iterator() noexcept : it_(nullptr) {} 149 Iterator(const Iterator& other) = default; 150 Iterator& operator=(const Iterator& other) = default; 151 template < 152 typename P = PolicyT, 153 typename = std::enable_if_t<std::is_const<typename P::value_type>::value>> Iterator(const Iterator<typename P::RemoveConst> & other)154 Iterator(const Iterator<typename P::RemoveConst>& other) : it_(other.it_) {} 155 156 constexpr reference operator*() const noexcept { 157 if constexpr (PolicyT::kUseReferenceProxy) { 158 return reference(it_); 159 } else { 160 return it_.Get(); 161 } 162 } 163 // No operator-> needed because T is a scalar. 164 165 private: 166 // Hide the internal type. 167 using iterator = Iterator; 168 169 public: 170 // {inc,dec}rementable 171 constexpr iterator& operator++() noexcept { 172 it_.AddOffset(1); 173 return *this; 174 } 175 constexpr iterator operator++(int) noexcept { 176 auto copy = *this; 177 ++*this; 178 return copy; 179 } 180 constexpr iterator& operator--() noexcept { 181 it_.AddOffset(-1); 182 return *this; 183 } 184 constexpr iterator operator--(int) noexcept { 185 auto copy = *this; 186 --*this; 187 return copy; 188 } 189 190 // equality_comparable 191 friend constexpr bool operator==(const iterator& x, 192 const iterator& y) noexcept { 193 return x.it_.Index() == y.it_.Index(); 194 } 195 friend constexpr bool operator!=(const iterator& x, 196 const iterator& y) noexcept { 197 return !(x == y); 198 } 199 200 // less_than_comparable 201 friend constexpr bool operator<(const iterator& x, 202 const iterator& y) noexcept { 203 return x.it_.Index() < y.it_.Index(); 204 } 205 friend constexpr bool operator<=(const iterator& x, 206 const iterator& y) noexcept { 207 return !(y < x); 208 } 209 friend constexpr bool operator>(const iterator& x, 210 const iterator& y) noexcept { 211 return y < x; 212 } 213 friend constexpr bool operator>=(const iterator& x, 214 const iterator& y) noexcept { 215 return !(x < y); 216 } 217 218 constexpr iterator& operator+=(difference_type d) noexcept { 219 it_.AddOffset(d); 220 return *this; 221 } 222 constexpr iterator operator+(difference_type d) const noexcept { 223 auto copy = *this; 224 copy += d; 225 return copy; 226 } 227 friend constexpr iterator operator+(const difference_type d, 228 iterator it) noexcept { 229 return it + d; 230 } 231 232 constexpr iterator& operator-=(difference_type d) noexcept { 233 it_.AddOffset(-d); 234 return *this; 235 } 236 constexpr iterator operator-(difference_type d) const noexcept { 237 auto copy = *this; 238 copy -= d; 239 return copy; 240 } 241 242 // indexable 243 constexpr reference operator[](difference_type d) const noexcept { 244 auto copy = *this; 245 copy += d; 246 return *copy; 247 } 248 249 // random access iterator 250 friend constexpr difference_type operator-(iterator x, iterator y) noexcept { 251 return x.it_.Index() - y.it_.Index(); 252 } 253 254 private: 255 friend IteratorTestPeer; 256 friend ReferenceProxy<PolicyT>; 257 friend Iterator<typename PolicyT::AddConst>; 258 template <typename U> 259 friend class RepeatedFieldScalarProxy; 260 template <typename U> 261 friend class RepeatedFieldStringProxy; 262 template <typename U> 263 friend class RepeatedFieldProxy; 264 265 // Create from internal::RepeatedFieldScalarProxy. Iterator(typename PolicyT::Payload it)266 explicit Iterator(typename PolicyT::Payload it) noexcept : it_(it) {} 267 268 // The internal iterator. 269 typename PolicyT::Payload it_; 270 }; 271 272 template <typename T> 273 struct ScalarIteratorPolicy { 274 static constexpr bool kUseReferenceProxy = true; 275 using value_type = T; 276 using RemoveConst = ScalarIteratorPolicy<std::remove_const_t<T>>; 277 using AddConst = ScalarIteratorPolicy<const T>; 278 279 struct Payload { 280 T* value; AddOffsetScalarIteratorPolicy::Payload281 void AddOffset(ptrdiff_t offset) { value += offset; } GetScalarIteratorPolicy::Payload282 T Get() const { return *value; } SetScalarIteratorPolicy::Payload283 void Set(T new_value) const { *value = new_value; } IndexScalarIteratorPolicy::Payload284 T* Index() const { return value; } 285 swapScalarIteratorPolicy::Payload286 void swap(Payload& other) { 287 using std::swap; 288 swap(*value, *other.value); 289 } 290 PayloadScalarIteratorPolicy::Payload291 operator typename ScalarIteratorPolicy<const T>::Payload() const { 292 return {value}; 293 } 294 }; 295 }; 296 297 template <typename T> 298 struct StringIteratorPolicy { 299 static constexpr bool kUseReferenceProxy = true; 300 using value_type = T; 301 using RemoveConst = StringIteratorPolicy<std::remove_const_t<T>>; 302 using AddConst = StringIteratorPolicy<const T>; 303 304 struct Payload { 305 using Array = 306 std::conditional_t<std::is_const_v<T>, const upb_Array, upb_Array>; 307 Array* arr; 308 upb_Arena* arena; 309 size_t index; 310 AddOffsetStringIteratorPolicy::Payload311 void AddOffset(ptrdiff_t offset) { index += offset; } GetStringIteratorPolicy::Payload312 absl::string_view Get() const { 313 upb_MessageValue message_value = upb_Array_Get(arr, index); 314 return absl::string_view(message_value.str_val.data, 315 message_value.str_val.size); 316 } SetStringIteratorPolicy::Payload317 void Set(absl::string_view new_value) const { 318 char* data = 319 static_cast<char*>(upb_Arena_Malloc(arena, new_value.size())); 320 memcpy(data, new_value.data(), new_value.size()); 321 upb_MessageValue message_value; 322 message_value.str_val = 323 upb_StringView_FromDataAndSize(data, new_value.size()); 324 upb_Array_Set(arr, index, message_value); 325 } IndexStringIteratorPolicy::Payload326 size_t Index() const { return index; } 327 swapStringIteratorPolicy::Payload328 void swap(Payload& other) { 329 upb_MessageValue a = upb_Array_Get(this->arr, this->index); 330 upb_MessageValue b = upb_Array_Get(other.arr, other.index); 331 upb_Array_Set(this->arr, this->index, b); 332 upb_Array_Set(other.arr, other.index, a); 333 } 334 PayloadStringIteratorPolicy::Payload335 operator typename StringIteratorPolicy<const T>::Payload() const { 336 return {arr, arena, index}; 337 } 338 }; 339 }; 340 341 template <typename T> 342 struct MessageIteratorPolicy { 343 static constexpr bool kUseReferenceProxy = false; 344 using value_type = std::conditional_t<std::is_const_v<T>, typename T::CProxy, 345 typename T::Proxy>; 346 using RemoveConst = MessageIteratorPolicy<std::remove_const_t<T>>; 347 using AddConst = MessageIteratorPolicy<const T>; 348 349 struct Payload { 350 using Array = 351 std::conditional_t<std::is_const_v<T>, const upb_Array, upb_Array>; 352 upb_Message** arr; 353 upb_Arena* arena; 354 AddOffsetMessageIteratorPolicy::Payload355 void AddOffset(ptrdiff_t offset) { arr += offset; } GetMessageIteratorPolicy::Payload356 auto Get() const { 357 if constexpr (std::is_const_v<T>) { 358 return ::hpb::interop::upb::MakeCHandle< 359 typename std::remove_const_t<T>>(*arr, arena); 360 } else { 361 return hpb::interop::upb::MakeHandle<T>(*arr, arena); 362 } 363 } IndexMessageIteratorPolicy::Payload364 auto Index() const { return arr; } 365 }; 366 }; 367 368 } // namespace internal 369 } // namespace hpb 370 371 #endif // PROTOBUF_HPB_REPEATED_FIELD_ITERATOR_H_ 372