1 /*
2 * Copyright (c) 2009-2021, Google LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of Google LLC nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "upb/reflection/def_builder_internal.h"
29 #include "upb/reflection/def_type.h"
30 #include "upb/reflection/enum_def_internal.h"
31 #include "upb/reflection/enum_value_def_internal.h"
32 #include "upb/reflection/file_def_internal.h"
33
34 // Must be last.
35 #include "upb/port/def.inc"
36
37 struct upb_EnumValueDef {
38 const UPB_DESC(EnumValueOptions) * opts;
39 const upb_EnumDef* parent;
40 const char* full_name;
41 int32_t number;
42 };
43
_upb_EnumValueDef_At(const upb_EnumValueDef * v,int i)44 upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) {
45 return (upb_EnumValueDef*)&v[i];
46 }
47
_upb_EnumValueDef_Compare(const void * p1,const void * p2)48 static int _upb_EnumValueDef_Compare(const void* p1, const void* p2) {
49 const uint32_t v1 = (*(const upb_EnumValueDef**)p1)->number;
50 const uint32_t v2 = (*(const upb_EnumValueDef**)p2)->number;
51 return (v1 < v2) ? -1 : (v1 > v2);
52 }
53
_upb_EnumValueDefs_Sorted(const upb_EnumValueDef * v,int n,upb_Arena * a)54 const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v,
55 int n, upb_Arena* a) {
56 // TODO: Try to replace this arena alloc with a persistent scratch buffer.
57 upb_EnumValueDef** out =
58 (upb_EnumValueDef**)upb_Arena_Malloc(a, n * sizeof(void*));
59 if (!out) return NULL;
60
61 for (int i = 0; i < n; i++) {
62 out[i] = (upb_EnumValueDef*)&v[i];
63 }
64 qsort(out, n, sizeof(void*), _upb_EnumValueDef_Compare);
65
66 return (const upb_EnumValueDef**)out;
67 }
68
UPB_DESC(EnumValueOptions)69 const UPB_DESC(EnumValueOptions) *
70 upb_EnumValueDef_Options(const upb_EnumValueDef* v) {
71 return v->opts;
72 }
73
upb_EnumValueDef_HasOptions(const upb_EnumValueDef * v)74 bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v) {
75 return v->opts != (void*)kUpbDefOptDefault;
76 }
77
upb_EnumValueDef_Enum(const upb_EnumValueDef * v)78 const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v) {
79 return v->parent;
80 }
81
upb_EnumValueDef_FullName(const upb_EnumValueDef * v)82 const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v) {
83 return v->full_name;
84 }
85
upb_EnumValueDef_Name(const upb_EnumValueDef * v)86 const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v) {
87 return _upb_DefBuilder_FullToShort(v->full_name);
88 }
89
upb_EnumValueDef_Number(const upb_EnumValueDef * v)90 int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v) { return v->number; }
91
upb_EnumValueDef_Index(const upb_EnumValueDef * v)92 uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) {
93 // Compute index in our parent's array.
94 return v - upb_EnumDef_Value(v->parent, 0);
95 }
96
create_enumvaldef(upb_DefBuilder * ctx,const char * prefix,const UPB_DESC (EnumValueDescriptorProto)* val_proto,upb_EnumDef * e,upb_EnumValueDef * v)97 static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix,
98 const UPB_DESC(EnumValueDescriptorProto) *
99 val_proto,
100 upb_EnumDef* e, upb_EnumValueDef* v) {
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 UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions,
110 val_proto);
111
112 bool ok = _upb_EnumDef_Insert(e, v, ctx->arena);
113 if (!ok) _upb_DefBuilder_OomErr(ctx);
114 }
115
116 // 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,upb_EnumDef * e,bool * is_sorted)117 upb_EnumValueDef* _upb_EnumValueDefs_New(
118 upb_DefBuilder* ctx, const char* prefix, int n,
119 const UPB_DESC(EnumValueDescriptorProto) * const* protos, upb_EnumDef* e,
120 bool* is_sorted) {
121 _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef));
122
123 upb_EnumValueDef* v =
124 _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumValueDef) * n);
125
126 *is_sorted = true;
127 uint32_t previous = 0;
128 for (size_t i = 0; i < n; i++) {
129 create_enumvaldef(ctx, prefix, protos[i], e, &v[i]);
130
131 const uint32_t current = v[i].number;
132 if (previous > current) *is_sorted = false;
133 previous = current;
134 }
135
136 if (upb_FileDef_Syntax(ctx->file) == kUpb_Syntax_Proto3 && n > 0 &&
137 v[0].number != 0) {
138 _upb_DefBuilder_Errf(ctx,
139 "for proto3, the first enum value must be zero (%s)",
140 upb_EnumDef_FullName(e));
141 }
142
143 return v;
144 }
145