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 UPB_MESSAGE_INTERNAL_ARRAY_H_
9 #define UPB_MESSAGE_INTERNAL_ARRAY_H_
10
11 #include <stdint.h>
12 #include <string.h>
13
14 #include "upb/mem/arena.h"
15
16 // Must be last.
17 #include "upb/port/def.inc"
18
19 #define _UPB_ARRAY_MASK_IMM 0x4 // Frozen/immutable bit.
20 #define _UPB_ARRAY_MASK_LG2 0x3 // Encoded elem size.
21 #define _UPB_ARRAY_MASK_ALL (_UPB_ARRAY_MASK_IMM | _UPB_ARRAY_MASK_LG2)
22
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26
27 // LINT.IfChange(struct_definition)
28 // Our internal representation for repeated fields.
29 struct upb_Array {
30 // This is a tagged pointer. Bits #0 and #1 encode the elem size as follows:
31 // 0 maps to elem size 1
32 // 1 maps to elem size 4
33 // 2 maps to elem size 8
34 // 3 maps to elem size 16
35 //
36 // Bit #2 contains the frozen/immutable flag (currently unimplemented).
37 uintptr_t UPB_ONLYBITS(data);
38
39 size_t UPB_ONLYBITS(size); // The number of elements in the array.
40 size_t UPB_PRIVATE(capacity); // Allocated storage. Measured in elements.
41 };
42
UPB_PRIVATE(_upb_Array_SetTaggedPtr)43 UPB_INLINE void UPB_PRIVATE(_upb_Array_SetTaggedPtr)(struct upb_Array* array,
44 void* data, size_t lg2) {
45 UPB_ASSERT(lg2 != 1);
46 UPB_ASSERT(lg2 <= 4);
47 const size_t bits = lg2 - (lg2 != 0);
48 array->UPB_ONLYBITS(data) = (uintptr_t)data | bits;
49 }
50
51 UPB_INLINE size_t
UPB_PRIVATE(_upb_Array_ElemSizeLg2)52 UPB_PRIVATE(_upb_Array_ElemSizeLg2)(const struct upb_Array* array) {
53 const size_t bits = array->UPB_ONLYBITS(data) & _UPB_ARRAY_MASK_LG2;
54 const size_t lg2 = bits + (bits != 0);
55 return lg2;
56 }
57
UPB_PRIVATE(_upb_Array_DataPtr)58 UPB_INLINE const void* UPB_PRIVATE(_upb_Array_DataPtr)(
59 const struct upb_Array* array) {
60 UPB_PRIVATE(_upb_Array_ElemSizeLg2)(array); // Check assertions.
61 return (void*)(array->UPB_ONLYBITS(data) & ~(uintptr_t)_UPB_ARRAY_MASK_ALL);
62 }
63
UPB_PRIVATE(_upb_Array_MutableDataPtr)64 UPB_INLINE void* UPB_PRIVATE(_upb_Array_MutableDataPtr)(
65 struct upb_Array* array) {
66 return (void*)UPB_PRIVATE(_upb_Array_DataPtr)(array);
67 }
68
UPB_PRIVATE(_upb_Array_New)69 UPB_INLINE struct upb_Array* UPB_PRIVATE(_upb_Array_New)(upb_Arena* arena,
70 size_t init_capacity,
71 int elem_size_lg2) {
72 UPB_ASSERT(elem_size_lg2 != 1);
73 UPB_ASSERT(elem_size_lg2 <= 4);
74 const size_t array_size =
75 UPB_ALIGN_UP(sizeof(struct upb_Array), UPB_MALLOC_ALIGN);
76 const size_t bytes = array_size + (init_capacity << elem_size_lg2);
77 struct upb_Array* array = (struct upb_Array*)upb_Arena_Malloc(arena, bytes);
78 if (!array) return NULL;
79 UPB_PRIVATE(_upb_Array_SetTaggedPtr)
80 (array, UPB_PTR_AT(array, array_size, void), elem_size_lg2);
81 array->UPB_ONLYBITS(size) = 0;
82 array->UPB_PRIVATE(capacity) = init_capacity;
83 return array;
84 }
85
86 // Resizes the capacity of the array to be at least min_size.
87 bool UPB_PRIVATE(_upb_Array_Realloc)(struct upb_Array* array, size_t min_size,
88 upb_Arena* arena);
89
UPB_PRIVATE(_upb_Array_Reserve)90 UPB_INLINE bool UPB_PRIVATE(_upb_Array_Reserve)(struct upb_Array* array,
91 size_t size, upb_Arena* arena) {
92 if (array->UPB_PRIVATE(capacity) < size)
93 return UPB_PRIVATE(_upb_Array_Realloc)(array, size, arena);
94 return true;
95 }
96
97 // Resize without initializing new elements.
UPB_PRIVATE(_upb_Array_ResizeUninitialized)98 UPB_INLINE bool UPB_PRIVATE(_upb_Array_ResizeUninitialized)(
99 struct upb_Array* array, size_t size, upb_Arena* arena) {
100 UPB_ASSERT(size <= array->UPB_ONLYBITS(size) ||
101 arena); // Allow NULL arena when shrinking.
102 if (!UPB_PRIVATE(_upb_Array_Reserve)(array, size, arena)) return false;
103 array->UPB_ONLYBITS(size) = size;
104 return true;
105 }
106
107 // This function is intended for situations where elem_size is compile-time
108 // constant or a known expression of the form (1 << lg2), so that the expression
109 // i*elem_size does not result in an actual multiplication.
UPB_PRIVATE(_upb_Array_Set)110 UPB_INLINE void UPB_PRIVATE(_upb_Array_Set)(struct upb_Array* array, size_t i,
111 const void* data,
112 size_t elem_size) {
113 UPB_ASSERT(i < array->UPB_ONLYBITS(size));
114 UPB_ASSERT(elem_size == 1U << UPB_PRIVATE(_upb_Array_ElemSizeLg2)(array));
115 char* arr_data = (char*)UPB_PRIVATE(_upb_Array_MutableDataPtr)(array);
116 memcpy(arr_data + (i * elem_size), data, elem_size);
117 }
118
UPB_PRIVATE(_upb_Array_Size)119 UPB_INLINE size_t UPB_PRIVATE(_upb_Array_Size)(const struct upb_Array* arr) {
120 return arr->UPB_ONLYBITS(size);
121 }
122
123 // LINT.ThenChange(
124 // GoogleInternalName1,
125 //)
126
127 #ifdef __cplusplus
128 } /* extern "C" */
129 #endif
130
131 #undef _UPB_ARRAY_MASK_IMM
132 #undef _UPB_ARRAY_MASK_LG2
133 #undef _UPB_ARRAY_MASK_ALL
134
135 #include "upb/port/undef.inc"
136
137 #endif /* UPB_MESSAGE_INTERNAL_ARRAY_H_ */
138