• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "upb/reflection/internal/enum_value_def.h"
9 
10 #include <stdint.h>
11 
12 #include "upb/reflection/def_type.h"
13 #include "upb/reflection/enum_def.h"
14 #include "upb/reflection/enum_value_def.h"
15 #include "upb/reflection/file_def.h"
16 #include "upb/reflection/internal/def_builder.h"
17 #include "upb/reflection/internal/enum_def.h"
18 
19 // Must be last.
20 #include "upb/port/def.inc"
21 
22 struct upb_EnumValueDef {
23   const UPB_DESC(EnumValueOptions*) opts;
24   const UPB_DESC(FeatureSet*) resolved_features;
25   const upb_EnumDef* parent;
26   const char* full_name;
27   int32_t number;
28 #if UINTPTR_MAX == 0xffffffff
29   uint32_t padding;  // Increase size to a multiple of 8.
30 #endif
31 };
32 
_upb_EnumValueDef_At(const upb_EnumValueDef * v,int i)33 upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) {
34   return (upb_EnumValueDef*)&v[i];
35 }
36 
_upb_EnumValueDef_Compare(const void * p1,const void * p2)37 static int _upb_EnumValueDef_Compare(const void* p1, const void* p2) {
38   const uint32_t v1 = (*(const upb_EnumValueDef**)p1)->number;
39   const uint32_t v2 = (*(const upb_EnumValueDef**)p2)->number;
40   return (v1 < v2) ? -1 : (v1 > v2);
41 }
42 
_upb_EnumValueDefs_Sorted(const upb_EnumValueDef * v,int n,upb_Arena * a)43 const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v,
44                                                    int n, upb_Arena* a) {
45   // TODO: Try to replace this arena alloc with a persistent scratch buffer.
46   upb_EnumValueDef** out =
47       (upb_EnumValueDef**)upb_Arena_Malloc(a, n * sizeof(void*));
48   if (!out) return NULL;
49 
50   for (int i = 0; i < n; i++) {
51     out[i] = (upb_EnumValueDef*)&v[i];
52   }
53   qsort(out, n, sizeof(void*), _upb_EnumValueDef_Compare);
54 
55   return (const upb_EnumValueDef**)out;
56 }
57 
UPB_DESC(EnumValueOptions)58 const UPB_DESC(EnumValueOptions) *
59     upb_EnumValueDef_Options(const upb_EnumValueDef* v) {
60   return v->opts;
61 }
62 
upb_EnumValueDef_HasOptions(const upb_EnumValueDef * v)63 bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v) {
64   return v->opts != (void*)kUpbDefOptDefault;
65 }
66 
UPB_DESC(FeatureSet)67 const UPB_DESC(FeatureSet) *
68     upb_EnumValueDef_ResolvedFeatures(const upb_EnumValueDef* e) {
69   return e->resolved_features;
70 }
71 
upb_EnumValueDef_Enum(const upb_EnumValueDef * v)72 const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v) {
73   return v->parent;
74 }
75 
upb_EnumValueDef_FullName(const upb_EnumValueDef * v)76 const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v) {
77   return v->full_name;
78 }
79 
upb_EnumValueDef_Name(const upb_EnumValueDef * v)80 const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v) {
81   return _upb_DefBuilder_FullToShort(v->full_name);
82 }
83 
upb_EnumValueDef_Number(const upb_EnumValueDef * v)84 int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v) { return v->number; }
85 
upb_EnumValueDef_Index(const upb_EnumValueDef * v)86 uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) {
87   // Compute index in our parent's array.
88   return v - upb_EnumDef_Value(v->parent, 0);
89 }
90 
create_enumvaldef(upb_DefBuilder * ctx,const char * prefix,const UPB_DESC (EnumValueDescriptorProto *)val_proto,const UPB_DESC (FeatureSet *)parent_features,upb_EnumDef * e,upb_EnumValueDef * v)91 static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix,
92                               const UPB_DESC(EnumValueDescriptorProto*)
93                                   val_proto,
94                               const UPB_DESC(FeatureSet*) parent_features,
95                               upb_EnumDef* e, upb_EnumValueDef* v) {
96   UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions,
97                       val_proto);
98   v->resolved_features = _upb_DefBuilder_ResolveFeatures(
99       ctx, parent_features, UPB_DESC(EnumValueOptions_features)(v->opts));
100 
101   upb_StringView name = UPB_DESC(EnumValueDescriptorProto_name)(val_proto);
102 
103   v->parent = e;  // Must happen prior to _upb_DefBuilder_Add()
104   v->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name);
105   v->number = UPB_DESC(EnumValueDescriptorProto_number)(val_proto);
106   _upb_DefBuilder_Add(ctx, v->full_name,
107                       _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL));
108 
109   bool ok = _upb_EnumDef_Insert(e, v, ctx->arena);
110   if (!ok) _upb_DefBuilder_OomErr(ctx);
111 }
112 
_upb_EnumValueDef_CheckZeroValue(upb_DefBuilder * ctx,const upb_EnumDef * e,const upb_EnumValueDef * v,int n)113 static void _upb_EnumValueDef_CheckZeroValue(upb_DefBuilder* ctx,
114                                              const upb_EnumDef* e,
115                                              const upb_EnumValueDef* v, int n) {
116   // When the special UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN is enabled, we have to
117   // exempt closed enums from this check, even when we are treating them as
118   // open.
119   if (upb_EnumDef_IsSpecifiedAsClosed(e) || n == 0 || v[0].number == 0) return;
120 
121   _upb_DefBuilder_Errf(ctx, "for open enums, the first value must be zero (%s)",
122                        upb_EnumDef_FullName(e));
123 }
124 
125 // Allocate and initialize an array of |n| enum value defs owned by |e|.
_upb_EnumValueDefs_New(upb_DefBuilder * ctx,const char * prefix,int n,const UPB_DESC (EnumValueDescriptorProto *)const * protos,const UPB_DESC (FeatureSet *)parent_features,upb_EnumDef * e,bool * is_sorted)126 upb_EnumValueDef* _upb_EnumValueDefs_New(
127     upb_DefBuilder* ctx, const char* prefix, int n,
128     const UPB_DESC(EnumValueDescriptorProto*) const* protos,
129     const UPB_DESC(FeatureSet*) parent_features, upb_EnumDef* e,
130     bool* is_sorted) {
131   _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef));
132 
133   upb_EnumValueDef* v =
134       _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumValueDef) * n);
135 
136   *is_sorted = true;
137   uint32_t previous = 0;
138   for (int i = 0; i < n; i++) {
139     create_enumvaldef(ctx, prefix, protos[i], parent_features, e, &v[i]);
140 
141     const uint32_t current = v[i].number;
142     if (previous > current) *is_sorted = false;
143     previous = current;
144   }
145 
146   _upb_EnumValueDef_CheckZeroValue(ctx, e, v, n);
147 
148   return v;
149 }
150