|
|
|
// Protocol Buffers - Google's data interchange format
|
|
|
|
// Copyright 2023 Google LLC. All rights reserved.
|
|
|
|
//
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file or at
|
|
|
|
// https://developers.google.com/open-source/licenses/bsd
|
|
|
|
|
|
|
|
#ifndef UPB_PROTOS_REPEATED_FIELD_ITERATOR_H_
|
|
|
|
#define UPB_PROTOS_REPEATED_FIELD_ITERATOR_H_
|
|
|
|
|
|
|
|
#include <cstddef>
|
|
|
|
#include <cstring>
|
|
|
|
#include <iterator>
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
|
|
#include "absl/strings/string_view.h"
|
|
|
|
#include "protos/protos.h"
|
|
|
|
#include "upb/base/string_view.h"
|
|
|
|
#include "upb/mem/arena.h"
|
|
|
|
#include "upb/message/array.h"
|
|
|
|
#include "upb/message/message.h"
|
|
|
|
|
|
|
|
namespace protos {
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
// TODO: Implement std iterator for messages
|
|
|
|
template <typename T>
|
|
|
|
class RepeatedFieldScalarProxy;
|
|
|
|
template <typename T>
|
|
|
|
class RepeatedFieldStringProxy;
|
|
|
|
|
|
|
|
struct IteratorTestPeer;
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
class Iterator;
|
|
|
|
|
|
|
|
template <typename PolicyT>
|
|
|
|
class ReferenceProxy;
|
|
|
|
|
|
|
|
template <typename PolicyT>
|
|
|
|
class InjectedRelationalsImpl {
|
|
|
|
using RP = ReferenceProxy<PolicyT>;
|
|
|
|
using V = typename PolicyT::value_type;
|
|
|
|
friend bool operator==(RP a, V b) { return static_cast<V>(a) == b; }
|
|
|
|
friend bool operator==(V a, RP b) { return a == static_cast<V>(b); }
|
|
|
|
friend bool operator==(RP a, RP b) {
|
|
|
|
return static_cast<V>(a) == static_cast<V>(b);
|
|
|
|
}
|
|
|
|
friend bool operator!=(RP a, V b) { return static_cast<V>(a) != b; }
|
|
|
|
friend bool operator!=(V a, RP b) { return a != static_cast<V>(b); }
|
|
|
|
friend bool operator!=(RP a, RP b) {
|
|
|
|
return static_cast<V>(a) != static_cast<V>(b);
|
|
|
|
}
|
|
|
|
friend bool operator<(RP a, V b) { return static_cast<V>(a) < b; }
|
|
|
|
friend bool operator<(V a, RP b) { return a < static_cast<V>(b); }
|
|
|
|
friend bool operator<(RP a, RP b) {
|
|
|
|
return static_cast<V>(a) < static_cast<V>(b);
|
|
|
|
}
|
|
|
|
friend bool operator<=(RP a, V b) { return static_cast<V>(a) <= b; }
|
|
|
|
friend bool operator<=(V a, RP b) { return a <= static_cast<V>(b); }
|
|
|
|
friend bool operator<=(RP a, RP b) {
|
|
|
|
return static_cast<V>(a) <= static_cast<V>(b);
|
|
|
|
}
|
|
|
|
friend bool operator>(RP a, V b) { return static_cast<V>(a) > b; }
|
|
|
|
friend bool operator>(V a, RP b) { return a > static_cast<V>(b); }
|
|
|
|
friend bool operator>(RP a, RP b) {
|
|
|
|
return static_cast<V>(a) > static_cast<V>(b);
|
|
|
|
}
|
|
|
|
friend bool operator>=(RP a, V b) { return static_cast<V>(a) >= b; }
|
|
|
|
friend bool operator>=(V a, RP b) { return a >= static_cast<V>(b); }
|
|
|
|
friend bool operator>=(RP a, RP b) {
|
|
|
|
return static_cast<V>(a) >= static_cast<V>(b);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
class NoInjectedRelationalsImpl {};
|
|
|
|
|
|
|
|
// We need to inject relationals for the string references because the
|
|
|
|
// relationals for string_view are templates and won't allow for implicit
|
|
|
|
// conversions from ReferenceProxy to string_view before deduction.
|
|
|
|
template <typename PolicyT>
|
|
|
|
using InjectedRelationals = std::conditional_t<
|
|
|
|
std::is_same_v<std::remove_const_t<typename PolicyT::value_type>,
|
|
|
|
absl::string_view>,
|
|
|
|
InjectedRelationalsImpl<PolicyT>, NoInjectedRelationalsImpl>;
|
|
|
|
|
|
|
|
template <typename PolicyT>
|
|
|
|
class ReferenceProxy : InjectedRelationals<PolicyT> {
|
|
|
|
using value_type = typename PolicyT::value_type;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ReferenceProxy(const ReferenceProxy&) = default;
|
|
|
|
ReferenceProxy& operator=(const ReferenceProxy& other) {
|
|
|
|
// Assign through the references
|
|
|
|
// TODO: Make this better for strings to avoid the copy.
|
|
|
|
it_.Set(other.it_.Get());
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
friend void swap(ReferenceProxy a, ReferenceProxy b) { a.it_.swap(b.it_); }
|
|
|
|
|
|
|
|
operator value_type() const { return it_.Get(); }
|
|
|
|
void operator=(const value_type& value) const { it_.Set(value); }
|
|
|
|
void operator=(value_type&& value) const { it_.Set(std::move(value)); }
|
|
|
|
Iterator<PolicyT> operator&() const { return Iterator<PolicyT>(it_); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend IteratorTestPeer;
|
|
|
|
friend ReferenceProxy<typename PolicyT::AddConst>;
|
|
|
|
friend Iterator<PolicyT>;
|
|
|
|
|
|
|
|
explicit ReferenceProxy(typename PolicyT::Payload elem) : it_(elem) {}
|
|
|
|
typename PolicyT::Payload it_;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <template <typename> class PolicyTemplate, typename T>
|
|
|
|
class ReferenceProxy<PolicyTemplate<const T>>
|
|
|
|
: InjectedRelationals<PolicyTemplate<const T>> {
|
|
|
|
using PolicyT = PolicyTemplate<const T>;
|
|
|
|
using value_type = typename PolicyT::value_type;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ReferenceProxy(ReferenceProxy<PolicyTemplate<T>> p) : it_(p.it_) {}
|
|
|
|
ReferenceProxy(const ReferenceProxy&) = default;
|
|
|
|
ReferenceProxy& operator=(const ReferenceProxy&) = delete;
|
|
|
|
|
|
|
|
operator value_type() const { return it_.Get(); }
|
|
|
|
Iterator<PolicyT> operator&() const { return Iterator<PolicyT>(it_); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend IteratorTestPeer;
|
|
|
|
friend Iterator<PolicyT>;
|
|
|
|
|
|
|
|
explicit ReferenceProxy(typename PolicyT::Payload elem) : it_(elem) {}
|
|
|
|
typename PolicyT::Payload it_;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename PolicyT>
|
|
|
|
class Iterator {
|
|
|
|
public:
|
|
|
|
using iterator_category = std::random_access_iterator_tag;
|
|
|
|
using value_type = std::remove_const_t<typename PolicyT::value_type>;
|
|
|
|
using difference_type = std::ptrdiff_t;
|
|
|
|
using pointer = Iterator;
|
|
|
|
using reference =
|
|
|
|
std::conditional_t<PolicyT::kUseReferenceProxy, ReferenceProxy<PolicyT>,
|
|
|
|
typename PolicyT::value_type>;
|
|
|
|
|
|
|
|
constexpr Iterator() noexcept : it_(nullptr) {}
|
|
|
|
Iterator(const Iterator& other) = default;
|
|
|
|
Iterator& operator=(const Iterator& other) = default;
|
|
|
|
template <
|
|
|
|
typename P = PolicyT,
|
|
|
|
typename = std::enable_if_t<std::is_const<typename P::value_type>::value>>
|
|
|
|
Iterator(const Iterator<typename P::RemoveConst>& other) : it_(other.it_) {}
|
|
|
|
|
|
|
|
constexpr reference operator*() const noexcept {
|
|
|
|
if constexpr (PolicyT::kUseReferenceProxy) {
|
|
|
|
return reference(it_);
|
|
|
|
} else {
|
|
|
|
return it_.Get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// No operator-> needed because T is a scalar.
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Hide the internal type.
|
|
|
|
using iterator = Iterator;
|
|
|
|
|
|
|
|
public:
|
|
|
|
// {inc,dec}rementable
|
|
|
|
constexpr iterator& operator++() noexcept {
|
|
|
|
it_.AddOffset(1);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
constexpr iterator operator++(int) noexcept {
|
|
|
|
auto copy = *this;
|
|
|
|
++*this;
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
constexpr iterator& operator--() noexcept {
|
|
|
|
it_.AddOffset(-1);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
constexpr iterator operator--(int) noexcept {
|
|
|
|
auto copy = *this;
|
|
|
|
--*this;
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
// equality_comparable
|
|
|
|
friend constexpr bool operator==(const iterator& x,
|
|
|
|
const iterator& y) noexcept {
|
|
|
|
return x.it_.Index() == y.it_.Index();
|
|
|
|
}
|
|
|
|
friend constexpr bool operator!=(const iterator& x,
|
|
|
|
const iterator& y) noexcept {
|
|
|
|
return !(x == y);
|
|
|
|
}
|
|
|
|
|
|
|
|
// less_than_comparable
|
|
|
|
friend constexpr bool operator<(const iterator& x,
|
|
|
|
const iterator& y) noexcept {
|
|
|
|
return x.it_.Index() < y.it_.Index();
|
|
|
|
}
|
|
|
|
friend constexpr bool operator<=(const iterator& x,
|
|
|
|
const iterator& y) noexcept {
|
|
|
|
return !(y < x);
|
|
|
|
}
|
|
|
|
friend constexpr bool operator>(const iterator& x,
|
|
|
|
const iterator& y) noexcept {
|
|
|
|
return y < x;
|
|
|
|
}
|
|
|
|
friend constexpr bool operator>=(const iterator& x,
|
|
|
|
const iterator& y) noexcept {
|
|
|
|
return !(x < y);
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr iterator& operator+=(difference_type d) noexcept {
|
|
|
|
it_.AddOffset(d);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
constexpr iterator operator+(difference_type d) const noexcept {
|
|
|
|
auto copy = *this;
|
|
|
|
copy += d;
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
friend constexpr iterator operator+(const difference_type d,
|
|
|
|
iterator it) noexcept {
|
|
|
|
return it + d;
|
|
|
|
}
|
|
|
|
|
|
|
|
constexpr iterator& operator-=(difference_type d) noexcept {
|
|
|
|
it_.AddOffset(-d);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
constexpr iterator operator-(difference_type d) const noexcept {
|
|
|
|
auto copy = *this;
|
|
|
|
copy -= d;
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
// indexable
|
|
|
|
constexpr reference operator[](difference_type d) const noexcept {
|
|
|
|
auto copy = *this;
|
|
|
|
copy += d;
|
|
|
|
return *copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
// random access iterator
|
|
|
|
friend constexpr difference_type operator-(iterator x, iterator y) noexcept {
|
|
|
|
return x.it_.Index() - y.it_.Index();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend IteratorTestPeer;
|
|
|
|
friend ReferenceProxy<PolicyT>;
|
|
|
|
friend Iterator<typename PolicyT::AddConst>;
|
|
|
|
template <typename U>
|
|
|
|
friend class RepeatedFieldScalarProxy;
|
|
|
|
template <typename U>
|
|
|
|
friend class RepeatedFieldStringProxy;
|
|
|
|
template <typename U>
|
|
|
|
friend class RepeatedFieldProxy;
|
|
|
|
|
|
|
|
// Create from internal::RepeatedFieldScalarProxy.
|
|
|
|
explicit Iterator(typename PolicyT::Payload it) noexcept : it_(it) {}
|
|
|
|
|
|
|
|
// The internal iterator.
|
|
|
|
typename PolicyT::Payload it_;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct ScalarIteratorPolicy {
|
|
|
|
static constexpr bool kUseReferenceProxy = true;
|
|
|
|
using value_type = T;
|
|
|
|
using RemoveConst = ScalarIteratorPolicy<std::remove_const_t<T>>;
|
|
|
|
using AddConst = ScalarIteratorPolicy<const T>;
|
|
|
|
|
|
|
|
struct Payload {
|
|
|
|
T* value;
|
|
|
|
void AddOffset(ptrdiff_t offset) { value += offset; }
|
|
|
|
T Get() const { return *value; }
|
|
|
|
void Set(T new_value) const { *value = new_value; }
|
|
|
|
T* Index() const { return value; }
|
|
|
|
|
|
|
|
void swap(Payload& other) {
|
|
|
|
using std::swap;
|
|
|
|
swap(*value, *other.value);
|
|
|
|
}
|
|
|
|
|
|
|
|
operator typename ScalarIteratorPolicy<const T>::Payload() const {
|
|
|
|
return {value};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct StringIteratorPolicy {
|
|
|
|
static constexpr bool kUseReferenceProxy = true;
|
|
|
|
using value_type = T;
|
|
|
|
using RemoveConst = StringIteratorPolicy<std::remove_const_t<T>>;
|
|
|
|
using AddConst = StringIteratorPolicy<const T>;
|
|
|
|
|
|
|
|
struct Payload {
|
|
|
|
using Array =
|
|
|
|
std::conditional_t<std::is_const_v<T>, const upb_Array, upb_Array>;
|
|
|
|
Array* arr;
|
|
|
|
upb_Arena* arena;
|
|
|
|
size_t index;
|
|
|
|
|
|
|
|
void AddOffset(ptrdiff_t offset) { index += offset; }
|
|
|
|
absl::string_view Get() const {
|
|
|
|
upb_MessageValue message_value = upb_Array_Get(arr, index);
|
|
|
|
return absl::string_view(message_value.str_val.data,
|
|
|
|
message_value.str_val.size);
|
|
|
|
}
|
|
|
|
void Set(absl::string_view new_value) const {
|
|
|
|
char* data =
|
|
|
|
static_cast<char*>(upb_Arena_Malloc(arena, new_value.size()));
|
|
|
|
memcpy(data, new_value.data(), new_value.size());
|
|
|
|
upb_MessageValue message_value;
|
|
|
|
message_value.str_val =
|
|
|
|
upb_StringView_FromDataAndSize(data, new_value.size());
|
|
|
|
upb_Array_Set(arr, index, message_value);
|
|
|
|
}
|
|
|
|
size_t Index() const { return index; }
|
|
|
|
|
|
|
|
void swap(Payload& other) {
|
|
|
|
upb_MessageValue a = upb_Array_Get(this->arr, this->index);
|
|
|
|
upb_MessageValue b = upb_Array_Get(other.arr, other.index);
|
|
|
|
upb_Array_Set(this->arr, this->index, b);
|
|
|
|
upb_Array_Set(other.arr, other.index, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
operator typename StringIteratorPolicy<const T>::Payload() const {
|
|
|
|
return {arr, arena, index};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
struct MessageIteratorPolicy {
|
|
|
|
static constexpr bool kUseReferenceProxy = false;
|
|
|
|
using value_type = std::conditional_t<std::is_const_v<T>, typename T::CProxy,
|
|
|
|
typename T::Proxy>;
|
|
|
|
using RemoveConst = MessageIteratorPolicy<std::remove_const_t<T>>;
|
|
|
|
using AddConst = MessageIteratorPolicy<const T>;
|
|
|
|
|
|
|
|
struct Payload {
|
|
|
|
using Array =
|
|
|
|
std::conditional_t<std::is_const_v<T>, const upb_Array, upb_Array>;
|
|
|
|
upb_Message** arr;
|
|
|
|
upb_Arena* arena;
|
|
|
|
|
|
|
|
void AddOffset(ptrdiff_t offset) { arr += offset; }
|
|
|
|
auto Get() const {
|
|
|
|
if constexpr (std::is_const_v<T>) {
|
|
|
|
return ::protos::internal::CreateMessage<
|
|
|
|
typename std::remove_const_t<T>>(*arr, arena);
|
|
|
|
} else {
|
|
|
|
return ::protos::internal::CreateMessageProxy<T>(*arr, arena);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
auto Index() const { return arr; }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace protos
|
|
|
|
|
|
|
|
#endif // UPB_PROTOS_REPEATED_FIELD_ITERATOR_H_
|