1 /**
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef LIBPANDAFILE_FIELD_DATA_ACCESSOR_INL_H_
17 #define LIBPANDAFILE_FIELD_DATA_ACCESSOR_INL_H_
18
19 #include "field_data_accessor.h"
20 #include "helpers.h"
21
22 #include "utils/bit_utils.h"
23
24 #include <type_traits>
25
26 namespace ark::panda_file {
27
28 // static
GetTypeId(const File & pandaFile,File::EntityId fieldId)29 inline File::EntityId FieldDataAccessor::GetTypeId(const File &pandaFile, File::EntityId fieldId)
30 {
31 auto sp = pandaFile.GetSpanFromId(fieldId).SubSpan(IDX_SIZE); // skip class_idx
32 auto typeIdx = helpers::Read<panda_file::IDX_SIZE>(&sp);
33 return pandaFile.ResolveClassIndex(fieldId, typeIdx);
34 }
35
36 // static
GetNameId(const File & pandaFile,File::EntityId fieldId)37 inline File::EntityId FieldDataAccessor::GetNameId(const File &pandaFile, File::EntityId fieldId)
38 {
39 auto sp = pandaFile.GetSpanFromId(fieldId).SubSpan(IDX_SIZE * 2); // skip class_idx, type_idx
40 return File::EntityId(helpers::Read<panda_file::ID_SIZE>(&sp));
41 }
42
43 template <class T>
GetValueIntegral(FieldValue & fieldValue)44 inline T FieldDataAccessor::GetValueIntegral(FieldValue &fieldValue)
45 {
46 // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
47 if constexpr (sizeof(T) <= sizeof(uint32_t)) {
48 return static_cast<T>(std::get<uint32_t>(fieldValue));
49 // NOLINTNEXTLINE(readability-misleading-indentation)
50 } else {
51 return static_cast<T>(std::get<uint64_t>(fieldValue));
52 }
53 }
54
55 template <class T>
GetValueNonIntegral(FieldValue & fieldValue)56 inline T FieldDataAccessor::GetValueNonIntegral(FieldValue &fieldValue)
57 {
58 // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
59 if constexpr (sizeof(T) <= sizeof(uint32_t)) {
60 return bit_cast<T, uint32_t>(std::get<uint32_t>(fieldValue));
61 // NOLINTNEXTLINE(readability-misleading-indentation)
62 } else {
63 return bit_cast<T, uint64_t>(std::get<uint64_t>(fieldValue));
64 }
65 }
66
67 template <class T>
GetValueImpl(FieldValue & fieldValue)68 inline T FieldDataAccessor::GetValueImpl(FieldValue &fieldValue)
69 {
70 // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
71 // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
72 if constexpr (std::is_integral_v<T>) {
73 return GetValueIntegral<T>(fieldValue);
74 } else {
75 return GetValueNonIntegral<T>(fieldValue);
76 }
77 }
78
79 template <class T>
GetValue()80 inline std::optional<T> FieldDataAccessor::GetValue()
81 {
82 if (isExternal_) {
83 // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
84 // which fails Release builds for GCC 8 and 9.
85 std::optional<T> novalue = {};
86 return novalue;
87 }
88
89 auto v = GetValueInternal();
90 if (!v.has_value()) {
91 // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
92 // which fails Release builds for GCC 8 and 9.
93 std::optional<T> novalue = {};
94 return novalue;
95 }
96
97 return GetValueImpl<T>(*v);
98 }
99
100 template <>
GetValue()101 inline std::optional<File::EntityId> FieldDataAccessor::GetValue()
102 {
103 if (isExternal_) {
104 return {};
105 }
106
107 auto v = GetValueInternal();
108 if (!v.has_value()) {
109 return {};
110 }
111
112 FieldValue fieldValue = *v;
113
114 return File::EntityId(std::get<uint32_t>(fieldValue));
115 }
116
SkipValue()117 inline void FieldDataAccessor::SkipValue()
118 {
119 GetValueInternal();
120 }
121
SkipRuntimeAnnotations()122 inline void FieldDataAccessor::SkipRuntimeAnnotations()
123 {
124 EnumerateRuntimeAnnotations([](File::EntityId /* unused */) {});
125 }
126
SkipAnnotations()127 inline void FieldDataAccessor::SkipAnnotations()
128 {
129 EnumerateAnnotations([](File::EntityId /* unused */) {});
130 }
131
SkipRuntimeTypeAnnotations()132 inline void FieldDataAccessor::SkipRuntimeTypeAnnotations()
133 {
134 EnumerateRuntimeTypeAnnotations([](File::EntityId /* unused */) {});
135 }
136
SkipTypeAnnotations()137 inline void FieldDataAccessor::SkipTypeAnnotations()
138 {
139 EnumerateTypeAnnotations([](File::EntityId /* unused */) {});
140 }
141
142 template <class Callback>
EnumerateRuntimeAnnotations(const Callback & cb)143 inline void FieldDataAccessor::EnumerateRuntimeAnnotations(const Callback &cb)
144 {
145 if (isExternal_) {
146 return;
147 }
148
149 if (runtimeAnnotationsSp_.data() == nullptr) {
150 SkipValue();
151 }
152
153 helpers::EnumerateTaggedValues<File::EntityId, FieldTag, Callback>(
154 runtimeAnnotationsSp_, FieldTag::RUNTIME_ANNOTATION, cb, &annotationsSp_);
155 }
156
157 template <class Callback>
EnumerateAnnotations(const Callback & cb)158 inline void FieldDataAccessor::EnumerateAnnotations(const Callback &cb)
159 {
160 if (isExternal_) {
161 return;
162 }
163
164 if (annotationsSp_.data() == nullptr) {
165 SkipRuntimeAnnotations();
166 }
167
168 helpers::EnumerateTaggedValues<File::EntityId, FieldTag, Callback>(annotationsSp_, FieldTag::ANNOTATION, cb,
169 &runtimeTypeAnnotationsSp_);
170 }
171
172 template <class Callback>
EnumerateRuntimeTypeAnnotations(const Callback & cb)173 inline void FieldDataAccessor::EnumerateRuntimeTypeAnnotations(const Callback &cb)
174 {
175 if (isExternal_) {
176 return;
177 }
178
179 if (runtimeTypeAnnotationsSp_.data() == nullptr) {
180 SkipAnnotations();
181 }
182
183 helpers::EnumerateTaggedValues<File::EntityId, FieldTag, Callback>(runtimeTypeAnnotationsSp_, FieldTag::ANNOTATION,
184 cb, &typeAnnotationsSp_);
185 }
186
187 template <class Callback>
EnumerateTypeAnnotations(const Callback & cb)188 inline void FieldDataAccessor::EnumerateTypeAnnotations(const Callback &cb)
189 {
190 if (isExternal_) {
191 return;
192 }
193
194 if (typeAnnotationsSp_.data() == nullptr) {
195 SkipRuntimeTypeAnnotations();
196 }
197
198 Span<const uint8_t> sp {nullptr, nullptr};
199 helpers::EnumerateTaggedValues<File::EntityId, FieldTag, Callback>(typeAnnotationsSp_, FieldTag::ANNOTATION, cb,
200 &sp);
201
202 size_ = pandaFile_.GetIdFromPointer(sp.data()).GetOffset() - fieldId_.GetOffset() + 1; // + 1 for NOTHING tag
203 }
204
205 template <class Callback>
EnumerateRuntimeAnnotationsWithEarlyStop(const Callback & cb)206 inline bool FieldDataAccessor::EnumerateRuntimeAnnotationsWithEarlyStop(const Callback &cb)
207 {
208 if (isExternal_) {
209 return false;
210 }
211
212 if (runtimeAnnotationsSp_.data() == nullptr) {
213 SkipValue();
214 }
215
216 return helpers::EnumerateTaggedValuesWithEarlyStop<File::EntityId, FieldTag, Callback>(
217 runtimeAnnotationsSp_, FieldTag::RUNTIME_ANNOTATION, cb);
218 }
219
220 template <class Callback>
EnumerateAnnotationsWithEarlyStop(const Callback & cb)221 inline bool FieldDataAccessor::EnumerateAnnotationsWithEarlyStop(const Callback &cb)
222 {
223 if (isExternal_) {
224 return false;
225 }
226
227 if (annotationsSp_.data() == nullptr) {
228 SkipRuntimeAnnotations();
229 }
230
231 return helpers::EnumerateTaggedValuesWithEarlyStop<File::EntityId, FieldTag, Callback>(annotationsSp_,
232 FieldTag::ANNOTATION, cb);
233 }
234
GetAnnotationsNumber()235 inline uint32_t FieldDataAccessor::GetAnnotationsNumber()
236 {
237 size_t n = 0;
238 EnumerateRuntimeAnnotations([&n](File::EntityId /* unused */) { n++; });
239 return n;
240 }
241
GetRuntimeAnnotationsNumber()242 inline uint32_t FieldDataAccessor::GetRuntimeAnnotationsNumber()
243 {
244 size_t n = 0;
245 EnumerateRuntimeAnnotations([&n](File::EntityId /* unused */) { n++; });
246 return n;
247 }
248
GetRuntimeTypeAnnotationsNumber()249 inline uint32_t FieldDataAccessor::GetRuntimeTypeAnnotationsNumber()
250 {
251 size_t n = 0;
252 EnumerateRuntimeTypeAnnotations([&n](File::EntityId /* unused */) { n++; });
253 return n;
254 }
255
GetTypeAnnotationsNumber()256 inline uint32_t FieldDataAccessor::GetTypeAnnotationsNumber()
257 {
258 size_t n = 0;
259 EnumerateTypeAnnotations([&n](File::EntityId /* unused */) { n++; });
260 return n;
261 }
262
263 } // namespace ark::panda_file
264
265 #endif // LIBPANDAFILE_FIELD_DATA_ACCESSOR_INL_H_
266