Move iteration APIs to headers, so they're inlined in loop calls
PiperOrigin-RevId: 698497070
diff --git a/upb/message/compare.c b/upb/message/compare.c
index 49ee33e..6963ea5 100644
--- a/upb/message/compare.c
+++ b/upb/message/compare.c
@@ -142,8 +142,8 @@
upb_MessageValue val1;
// Iterate over all extensions for msg1, and search msg2 for each extension.
- size_t iter1 = kUpb_Extension_Begin;
- while (UPB_PRIVATE(_upb_Message_NextExtension)(msg1, m, &e, &val1, &iter1)) {
+ size_t iter1 = kUpb_Message_ExtensionBegin;
+ while (upb_Message_NextExtension(msg1, &e, &val1, &iter1)) {
const upb_Extension* ext2 = UPB_PRIVATE(_upb_Message_Getext)(msg2, e);
if (!ext2) return false;
diff --git a/upb/message/compat.c b/upb/message/compat.c
index 1bb2adc..0d79887 100644
--- a/upb/message/compat.c
+++ b/upb/message/compat.c
@@ -10,36 +10,27 @@
#include <stddef.h>
#include <stdint.h>
-#include "upb/message/internal/extension.h"
#include "upb/message/message.h"
+#include "upb/message/value.h"
#include "upb/mini_table/extension.h"
// Must be last.
#include "upb/port/def.inc"
-bool upb_Message_NextExtension(const upb_Message* msg,
- const upb_MiniTableExtension** result,
- uintptr_t* iter) {
- size_t count;
- const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(msg, &count);
- size_t i = *iter;
- if (i >= count) {
- return false;
- *result = NULL;
- }
- *result = ext[i].ext;
- *iter = i + 1;
- return true;
+bool upb_Message_NextExtensionReverse(const upb_Message* msg,
+ const upb_MiniTableExtension** result,
+ uintptr_t* iter) {
+ upb_MessageValue val;
+ return UPB_PRIVATE(_upb_Message_NextExtensionReverse)(msg, result, &val,
+ iter);
}
const upb_MiniTableExtension* upb_Message_FindExtensionByNumber(
const upb_Message* msg, uint32_t field_number) {
- size_t count;
- const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(msg, &count);
-
- for (; count--; ext++) {
- const upb_MiniTableExtension* e = ext->ext;
- if (upb_MiniTableExtension_Number(e) == field_number) return e;
+ uintptr_t iter = kUpb_Message_ExtensionBegin;
+ const upb_MiniTableExtension* result;
+ while (upb_Message_NextExtensionReverse(msg, &result, &iter)) {
+ if (upb_MiniTableExtension_Number(result) == field_number) return result;
}
return NULL;
}
diff --git a/upb/message/compat.h b/upb/message/compat.h
index 14ed2fe..7600ffa 100644
--- a/upb/message/compat.h
+++ b/upb/message/compat.h
@@ -25,11 +25,10 @@
extern "C" {
#endif
-#define kUpb_Message_ExtensionBegin 0;
-
-bool upb_Message_NextExtension(const upb_Message* msg,
- const upb_MiniTableExtension** result,
- uintptr_t* iter);
+// Same as upb_Message_NextExtension but iterates in reverse wire order
+bool upb_Message_NextExtensionReverse(const upb_Message* msg,
+ const upb_MiniTableExtension** result,
+ uintptr_t* iter);
// Returns the minitable with the given field number, or NULL on failure.
const upb_MiniTableExtension* upb_Message_FindExtensionByNumber(
const upb_Message* msg, uint32_t field_number);
diff --git a/upb/message/internal/extension.c b/upb/message/internal/extension.c
index f55253d..5eb41c4 100644
--- a/upb/message/internal/extension.c
+++ b/upb/message/internal/extension.c
@@ -40,7 +40,7 @@
upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
if (in) {
*count = (in->size - in->ext_begin) / sizeof(upb_Extension);
- return UPB_PTR_AT(in, in->ext_begin, void);
+ return UPB_PTR_AT(in, in->ext_begin, const upb_Extension);
} else {
*count = 0;
return NULL;
diff --git a/upb/message/internal/iterator.c b/upb/message/internal/iterator.c
index 82f2b37..b3ad76c 100644
--- a/upb/message/internal/iterator.c
+++ b/upb/message/internal/iterator.c
@@ -12,10 +12,8 @@
#include "upb/message/accessors.h"
#include "upb/message/array.h"
#include "upb/message/internal/accessors.h"
-#include "upb/message/internal/extension.h"
#include "upb/message/map.h"
#include "upb/message/message.h"
-#include "upb/mini_table/extension.h"
#include "upb/mini_table/field.h"
#include "upb/mini_table/message.h"
@@ -58,21 +56,3 @@
return false;
}
-
-bool UPB_PRIVATE(_upb_Message_NextExtension)(
- const upb_Message* msg, const upb_MiniTable* m,
- const upb_MiniTableExtension** out_e, upb_MessageValue* out_v,
- size_t* iter) {
- size_t count;
- const upb_Extension* exts = UPB_PRIVATE(_upb_Message_Getexts)(msg, &count);
- size_t i = *iter;
-
- if (++i < count) {
- *out_e = exts[i].ext;
- *out_v = exts[i].data;
- *iter = i;
- return true;
- }
-
- return false;
-}
\ No newline at end of file
diff --git a/upb/message/internal/iterator.h b/upb/message/internal/iterator.h
index ad080db..484762d 100644
--- a/upb/message/internal/iterator.h
+++ b/upb/message/internal/iterator.h
@@ -9,10 +9,10 @@
#define THIRD_PARTY_UPB_UPB_MESSAGE_INTERNAL_ITERATOR_H_
#include <stddef.h>
+#include <stdint.h>
#include "upb/message/message.h"
#include "upb/message/value.h"
-#include "upb/mini_table/extension.h"
#include "upb/mini_table/field.h"
#include "upb/mini_table/message.h"
@@ -20,16 +20,10 @@
#include "upb/port/def.inc"
#define kUpb_BaseField_Begin ((size_t)-1)
-#define kUpb_Extension_Begin ((size_t)-1)
-
bool UPB_PRIVATE(_upb_Message_NextBaseField)(const upb_Message* msg,
const upb_MiniTable* m,
const upb_MiniTableField** out_f,
upb_MessageValue* out_v,
- size_t* iter);
+ uintptr_t* iter);
-bool UPB_PRIVATE(_upb_Message_NextExtension)(
- const upb_Message* msg, const upb_MiniTable* m,
- const upb_MiniTableExtension** out_e, upb_MessageValue* out_v,
- size_t* iter);
#endif // THIRD_PARTY_UPB_UPB_MESSAGE_INTERNAL_ITERATOR_H_
diff --git a/upb/message/internal/map_sorter.h b/upb/message/internal/map_sorter.h
index 33474d1..bd997bc 100644
--- a/upb/message/internal/map_sorter.h
+++ b/upb/message/internal/map_sorter.h
@@ -18,6 +18,7 @@
#include "upb/message/internal/extension.h"
#include "upb/message/internal/map.h"
#include "upb/message/internal/map_entry.h"
+#include "upb/message/internal/message.h"
// Must be last.
#include "upb/port/def.inc"
@@ -80,7 +81,7 @@
bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type,
const struct upb_Map* map, _upb_sortedmap* sorted);
-bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Extension* exts,
+bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Message_Internal* in,
size_t count, _upb_sortedmap* sorted);
#ifdef __cplusplus
diff --git a/upb/message/internal/message.h b/upb/message/internal/message.h
index 2f7f0fa..c00b911 100644
--- a/upb/message/internal/message.h
+++ b/upb/message/internal/message.h
@@ -15,11 +15,15 @@
#ifndef UPB_MESSAGE_INTERNAL_MESSAGE_H_
#define UPB_MESSAGE_INTERNAL_MESSAGE_H_
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include "upb/base/string_view.h"
#include "upb/mem/arena.h"
#include "upb/message/internal/extension.h"
+#include "upb/message/internal/types.h"
+#include "upb/mini_table/extension.h"
#include "upb/mini_table/message.h"
// Must be last.
@@ -101,6 +105,68 @@
bool UPB_PRIVATE(_upb_Message_Realloc)(struct upb_Message* msg, size_t need,
upb_Arena* arena);
+#define kUpb_Message_UnknownBegin 0
+#define kUpb_Message_ExtensionBegin 0
+
+UPB_INLINE bool upb_Message_NextUnknown(const struct upb_Message* msg,
+ upb_StringView* data, uintptr_t* iter) {
+ const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
+ if (in && *iter == kUpb_Message_UnknownBegin) {
+ size_t len = in->unknown_end - sizeof(upb_Message_Internal);
+ if (len != 0) {
+ data->size = len;
+ data->data = (const char*)(in + 1);
+ (*iter)++;
+ return true;
+ }
+ }
+ data->size = 0;
+ data->data = NULL;
+ return false;
+}
+
+UPB_INLINE bool upb_Message_HasUnknown(const struct upb_Message* msg) {
+ upb_StringView data;
+ uintptr_t iter = kUpb_Message_UnknownBegin;
+ return upb_Message_NextUnknown(msg, &data, &iter);
+}
+
+UPB_INLINE bool upb_Message_NextExtension(const struct upb_Message* msg,
+ const upb_MiniTableExtension** out_e,
+ upb_MessageValue* out_v,
+ uintptr_t* iter) {
+ size_t count;
+ const upb_Extension* exts = UPB_PRIVATE(_upb_Message_Getexts)(msg, &count);
+ size_t i = *iter;
+ if (i < count) {
+ // Extensions are stored in reverse wire order, so to iterate in wire order,
+ // we need to iterate backwards.
+ *out_e = exts[count - 1 - i].ext;
+ *out_v = exts[count - 1 - i].data;
+ *iter = i + 1;
+ return true;
+ }
+
+ return false;
+}
+
+UPB_INLINE bool UPB_PRIVATE(_upb_Message_NextExtensionReverse)(
+ const struct upb_Message* msg, const upb_MiniTableExtension** out_e,
+ upb_MessageValue* out_v, uintptr_t* iter) {
+ size_t count;
+ const upb_Extension* exts = UPB_PRIVATE(_upb_Message_Getexts)(msg, &count);
+ size_t i = *iter;
+ if (i < count) {
+ // Extensions are stored in reverse wire order
+ *out_e = exts[i].ext;
+ *out_v = exts[i].data;
+ *iter = i + 1;
+ return true;
+ }
+
+ return false;
+}
+
#ifdef __cplusplus
} /* extern "C" */
#endif
diff --git a/upb/message/map_sorter.c b/upb/message/map_sorter.c
index f0a4865..f0836ca 100644
--- a/upb/message/map_sorter.c
+++ b/upb/message/map_sorter.c
@@ -14,8 +14,9 @@
#include "upb/base/internal/log2.h"
#include "upb/base/string_view.h"
#include "upb/mem/alloc.h"
+#include "upb/message/internal/extension.h"
+#include "upb/message/internal/message.h"
#include "upb/message/map.h"
-#include "upb/message/message.h"
#include "upb/mini_table/extension.h"
// Must be last.
@@ -144,14 +145,15 @@
return a_num < b_num ? -1 : 1;
}
-bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Extension* exts,
+bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Message_Internal* in,
size_t count, _upb_sortedmap* sorted) {
if (!_upb_mapsorter_resize(s, sorted, count)) return false;
+ const upb_Extension* exts =
+ UPB_PTR_AT(in, in->ext_begin, const upb_Extension);
for (size_t i = 0; i < count; i++) {
s->entries[sorted->start + i] = &exts[i];
}
-
qsort(&s->entries[sorted->start], count, sizeof(*s->entries),
_upb_mapsorter_cmpext);
return true;
diff --git a/upb/message/message.c b/upb/message/message.c
index 6ac5788..3a2d8e5 100644
--- a/upb/message/message.c
+++ b/upb/message/message.c
@@ -30,8 +30,6 @@
// Must be last.
#include "upb/port/def.inc"
-static const size_t message_overhead = sizeof(upb_Message_Internal);
-
upb_Message* upb_Message_New(const upb_MiniTable* m, upb_Arena* a) {
return _upb_Message_New(m, a);
}
@@ -75,39 +73,14 @@
UPB_ASSERT(!upb_Message_IsFrozen(msg));
upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
if (in) {
- in->unknown_end = message_overhead;
+ in->unknown_end = sizeof(upb_Message_Internal);
}
}
-bool upb_Message_NextUnknown(const upb_Message* msg, upb_StringView* data,
- uintptr_t* iter) {
- const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
- if (in && *iter == kUpb_Message_UnknownBegin) {
- size_t len = in->unknown_end - message_overhead;
- if (len != 0) {
- data->size = len;
- data->data = (const char*)(in + 1);
- (*iter)++;
- return true;
- }
- }
- data->size = 0;
- data->data = NULL;
- return false;
-}
-
-bool upb_Message_HasUnknown(const upb_Message* msg) {
- const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
- if (in) {
- return in->unknown_end > message_overhead;
- }
- return false;
-}
-
const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) {
upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
if (in) {
- *len = in->unknown_end - message_overhead;
+ *len = in->unknown_end - sizeof(upb_Message_Internal);
return (char*)(in + 1);
} else {
*len = 0;
@@ -185,17 +158,13 @@
}
// Extensions.
- size_t ext_count;
- const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(msg, &ext_count);
-
- for (size_t i = 0; i < ext_count; i++) {
- const upb_MiniTableExtension* e = ext[i].ext;
+ uintptr_t iter = kUpb_Message_ExtensionBegin;
+ const upb_MiniTableExtension* e;
+ upb_MessageValue val;
+ while (upb_Message_NextExtension(msg, &e, &val, &iter)) {
const upb_MiniTableField* f = &e->UPB_PRIVATE(field);
const upb_MiniTable* m2 = upb_MiniTableExtension_GetSubMessage(e);
- upb_MessageValue val;
- memcpy(&val, &ext[i].data, sizeof(upb_MessageValue));
-
switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) {
case kUpb_FieldMode_Array: {
upb_Array* arr = (upb_Array*)val.array_val;
diff --git a/upb/message/message.h b/upb/message/message.h
index a33cf32..f50cadb 100644
--- a/upb/message/message.h
+++ b/upb/message/message.h
@@ -17,8 +17,11 @@
#include "upb/base/string_view.h"
#include "upb/mem/arena.h"
+#include "upb/message/array.h"
+#include "upb/message/internal/extension.h"
#include "upb/message/internal/message.h"
#include "upb/message/internal/types.h"
+#include "upb/mini_table/extension.h"
#include "upb/mini_table/message.h"
// Must be last.
@@ -42,13 +45,15 @@
// while (upb_Message_NextUnknown(msg, &data, &iter)) {
// // Use data
// }
+// Iterates in the order unknown fields were parsed.
#define kUpb_Message_UnknownBegin 0
+#define kUpb_Message_ExtensionBegin 0
-bool upb_Message_NextUnknown(const upb_Message* msg, upb_StringView* data,
- uintptr_t* iter);
+UPB_INLINE bool upb_Message_NextUnknown(const upb_Message* msg,
+ upb_StringView* data, uintptr_t* iter);
-bool upb_Message_HasUnknown(const upb_Message* msg);
+UPB_INLINE bool upb_Message_HasUnknown(const upb_Message* msg);
// Returns a reference to the message's unknown data.
const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len);
@@ -80,6 +85,17 @@
// Returns the number of extensions present in this message.
size_t upb_Message_ExtensionCount(const upb_Message* msg);
+// Iterates extensions in wire order
+UPB_INLINE bool upb_Message_NextExtension(const upb_Message* msg,
+ const upb_MiniTableExtension** out_e,
+ upb_MessageValue* out_v,
+ uintptr_t* iter);
+
+// Iterates extensions in reverse wire order
+UPB_INLINE bool UPB_PRIVATE(_upb_Message_NextExtensionReverse)(
+ const struct upb_Message* msg, const upb_MiniTableExtension** out_e,
+ upb_MessageValue* out_v, uintptr_t* iter);
+
// Mark a message and all of its descendents as frozen/immutable.
UPB_API void upb_Message_Freeze(upb_Message* msg, const upb_MiniTable* m);
diff --git a/upb/text/debug_string.c b/upb/text/debug_string.c
index eebf79e..c4b6609 100644
--- a/upb/text/debug_string.c
+++ b/upb/text/debug_string.c
@@ -184,9 +184,9 @@
const upb_MiniTableExtension* ext;
upb_MessageValue val_ext;
- iter = kUpb_Extension_Begin;
- while (
- UPB_PRIVATE(_upb_Message_NextExtension)(msg, mt, &ext, &val_ext, &iter)) {
+ iter = kUpb_Message_ExtensionBegin;
+ while (UPB_PRIVATE(_upb_Message_NextExtensionReverse)(msg, &ext, &val_ext,
+ &iter)) {
const upb_MiniTableField* f = &ext->UPB_PRIVATE(field);
// It is not sufficient to only pass |f| as we lose valuable information
// about sub-messages. It is required that we pass |ext|.
diff --git a/upb/wire/encode.c b/upb/wire/encode.c
index d3e68f1..b68ddc6 100644
--- a/upb/wire/encode.c
+++ b/upb/wire/encode.c
@@ -12,6 +12,7 @@
#include <setjmp.h>
#include <stdbool.h>
#include <stdint.h>
+#include <stdlib.h>
#include <string.h>
#include "upb/base/descriptor_constants.h"
@@ -27,6 +28,7 @@
#include "upb/message/internal/map.h"
#include "upb/message/internal/map_entry.h"
#include "upb/message/internal/map_sorter.h"
+#include "upb/message/internal/message.h"
#include "upb/message/internal/tagged_ptr.h"
#include "upb/message/map.h"
#include "upb/message/message.h"
@@ -523,32 +525,33 @@
}
}
-static void encode_msgset_item(upb_encstate* e, const upb_Extension* ext) {
+static void encode_msgset_item(upb_encstate* e,
+ const upb_MiniTableExtension* ext,
+ const upb_MessageValue ext_val) {
size_t size;
encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_EndGroup);
- encode_message(e, ext->data.msg_val,
- upb_MiniTableExtension_GetSubMessage(ext->ext), &size);
+ encode_message(e, ext_val.msg_val, upb_MiniTableExtension_GetSubMessage(ext),
+ &size);
encode_varint(e, size);
encode_tag(e, kUpb_MsgSet_Message, kUpb_WireType_Delimited);
- encode_varint(e, upb_MiniTableExtension_Number(ext->ext));
+ encode_varint(e, upb_MiniTableExtension_Number(ext));
encode_tag(e, kUpb_MsgSet_TypeId, kUpb_WireType_Varint);
encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_StartGroup);
}
-static void encode_ext(upb_encstate* e, const upb_Extension* ext,
- bool is_message_set) {
+static void encode_ext(upb_encstate* e, const upb_MiniTableExtension* ext,
+ upb_MessageValue ext_val, bool is_message_set) {
if (UPB_UNLIKELY(is_message_set)) {
- encode_msgset_item(e, ext);
+ encode_msgset_item(e, ext, ext_val);
} else {
upb_MiniTableSubInternal sub;
- if (upb_MiniTableField_IsSubMessage(&ext->ext->UPB_PRIVATE(field))) {
- sub.UPB_PRIVATE(submsg) = &ext->ext->UPB_PRIVATE(sub).UPB_PRIVATE(submsg);
+ if (upb_MiniTableField_IsSubMessage(&ext->UPB_PRIVATE(field))) {
+ sub.UPB_PRIVATE(submsg) = &ext->UPB_PRIVATE(sub).UPB_PRIVATE(submsg);
} else {
- sub.UPB_PRIVATE(subenum) =
- ext->ext->UPB_PRIVATE(sub).UPB_PRIVATE(subenum);
+ sub.UPB_PRIVATE(subenum) = ext->UPB_PRIVATE(sub).UPB_PRIVATE(subenum);
}
- encode_field(e, &ext->data.UPB_PRIVATE(ext_msg_val), &sub,
- &ext->ext->UPB_PRIVATE(field));
+ encode_field(e, &ext_val.UPB_PRIVATE(ext_msg_val), &sub,
+ &ext->UPB_PRIVATE(field));
}
}
@@ -568,7 +571,7 @@
size_t unknown_size = 0;
uintptr_t iter = kUpb_Message_UnknownBegin;
upb_StringView unknown;
- // Need to write in reverse order, but list is single-linked; scan to
+ // Need to write in reverse order, but iteration is in-order; scan to
// reserve capacity up front, then write in-order
while (upb_Message_NextUnknown(msg, &unknown, &iter)) {
unknown_size += unknown.size;
@@ -585,24 +588,33 @@
}
if (m->UPB_PRIVATE(ext) != kUpb_ExtMode_NonExtendable) {
- /* Encode all extensions together. Unlike C++, we do not attempt to keep
- * these in field number order relative to normal fields or even to each
- * other. */
- size_t ext_count;
- const upb_Extension* ext =
- UPB_PRIVATE(_upb_Message_Getexts)(msg, &ext_count);
- if (ext_count) {
- if (e->options & kUpb_EncodeOption_Deterministic) {
- _upb_sortedmap sorted;
- _upb_mapsorter_pushexts(&e->sorter, ext, ext_count, &sorted);
- while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) {
- encode_ext(e, ext, m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet);
- }
- _upb_mapsorter_popmap(&e->sorter, &sorted);
- } else {
- const upb_Extension* end = ext + ext_count;
- for (; ext != end; ext++) {
- encode_ext(e, ext, m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet);
+ upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg);
+ if (in) {
+ /* Encode all extensions together. Unlike C++, we do not attempt to keep
+ * these in field number order relative to normal fields or even to each
+ * other. */
+ size_t ext_count = upb_Message_ExtensionCount(msg);
+ if (ext_count) {
+ if (e->options & kUpb_EncodeOption_Deterministic) {
+ _upb_sortedmap sorted;
+ if (!_upb_mapsorter_pushexts(&e->sorter, in, ext_count, &sorted)) {
+ // TODO: b/378744096 - handle alloc failure
+ }
+ const upb_Extension* ext;
+ while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) {
+ encode_ext(e, ext->ext, ext->data,
+ m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet);
+ }
+ _upb_mapsorter_popmap(&e->sorter, &sorted);
+ } else {
+ const upb_MiniTableExtension* ext;
+ upb_MessageValue ext_val;
+ uintptr_t iter = kUpb_Message_ExtensionBegin;
+ while (UPB_PRIVATE(_upb_Message_NextExtensionReverse)(
+ msg, &ext, &ext_val, &iter)) {
+ encode_ext(e, ext, ext_val,
+ m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet);
+ }
}
}
}