1 /**
2 * Copyright (c) 2021-2022 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 panda::panda_file {
27
28 // static
GetTypeId(const File & panda_file,File::EntityId field_id)29 inline File::EntityId FieldDataAccessor::GetTypeId(const File &panda_file, File::EntityId field_id)
30 {
31 auto sp = panda_file.GetSpanFromId(field_id).SubSpan(IDX_SIZE); // skip class_idx
32 auto type_idx = helpers::Read<panda_file::IDX_SIZE>(&sp);
33 return panda_file.ResolveClassIndex(field_id, type_idx);
34 }
35
36 // static
GetNameId(const File & panda_file,File::EntityId field_id)37 inline File::EntityId FieldDataAccessor::GetNameId(const File &panda_file, File::EntityId field_id)
38 {
39 auto sp = panda_file.GetSpanFromId(field_id).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>
GetValue()44 inline std::optional<T> FieldDataAccessor::GetValue()
45 {
46 if (is_external_) {
47 // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
48 // which fails Release builds for GCC 8 and 9.
49 std::optional<T> novalue = {};
50 return novalue;
51 }
52
53 auto v = GetValueInternal();
54
55 if (!v.has_value()) {
56 // NB! This is a workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80635
57 // which fails Release builds for GCC 8 and 9.
58 std::optional<T> novalue = {};
59 return novalue;
60 }
61
62 FieldValue field_value = *v;
63
64 // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
65 // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
66 if constexpr (std::is_integral_v<T>) {
67 // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
68 if constexpr (sizeof(T) <= sizeof(uint32_t)) {
69 return static_cast<T>(std::get<uint32_t>(field_value));
70 // NOLINTNEXTLINE(readability-misleading-indentation)
71 } else {
72 return static_cast<T>(std::get<uint64_t>(field_value));
73 }
74 // NOLINTNEXTLINE(readability-misleading-indentation)
75 } else {
76 // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
77 if constexpr (sizeof(T) <= sizeof(uint32_t)) {
78 return bit_cast<T, uint32_t>(std::get<uint32_t>(field_value));
79 // NOLINTNEXTLINE(readability-misleading-indentation)
80 } else {
81 return bit_cast<T, uint64_t>(std::get<uint64_t>(field_value));
82 }
83 }
84 }
85
86 template <>
GetValue()87 inline std::optional<File::EntityId> FieldDataAccessor::GetValue()
88 {
89 if (is_external_) {
90 return {};
91 }
92
93 auto v = GetValueInternal();
94
95 if (!v.has_value()) {
96 return {};
97 }
98
99 FieldValue field_value = *v;
100
101 return File::EntityId(std::get<uint32_t>(field_value));
102 }
103
SkipValue()104 inline void FieldDataAccessor::SkipValue()
105 {
106 GetValueInternal();
107 }
108
SkipRuntimeAnnotations()109 inline void FieldDataAccessor::SkipRuntimeAnnotations()
110 {
111 EnumerateRuntimeAnnotations([](File::EntityId /* unused */) {});
112 }
113
SkipAnnotations()114 inline void FieldDataAccessor::SkipAnnotations()
115 {
116 EnumerateAnnotations([](File::EntityId /* unused */) {});
117 }
118
SkipRuntimeTypeAnnotations()119 inline void FieldDataAccessor::SkipRuntimeTypeAnnotations()
120 {
121 EnumerateRuntimeTypeAnnotations([](File::EntityId /* unused */) {});
122 }
123
SkipTypeAnnotations()124 inline void FieldDataAccessor::SkipTypeAnnotations()
125 {
126 EnumerateTypeAnnotations([](File::EntityId /* unused */) {});
127 }
128
129 template <class Callback>
EnumerateRuntimeAnnotations(const Callback & cb)130 inline void FieldDataAccessor::EnumerateRuntimeAnnotations(const Callback &cb)
131 {
132 if (is_external_) {
133 return;
134 }
135
136 if (runtime_annotations_sp_.data() == nullptr) {
137 SkipValue();
138 }
139
140 helpers::EnumerateTaggedValues<File::EntityId, FieldTag, Callback>(
141 runtime_annotations_sp_, FieldTag::RUNTIME_ANNOTATION, cb, &annotations_sp_);
142 }
143
144 template <class Callback>
EnumerateAnnotations(const Callback & cb)145 inline void FieldDataAccessor::EnumerateAnnotations(const Callback &cb)
146 {
147 if (is_external_) {
148 return;
149 }
150
151 if (annotations_sp_.data() == nullptr) {
152 SkipRuntimeAnnotations();
153 }
154
155 helpers::EnumerateTaggedValues<File::EntityId, FieldTag, Callback>(annotations_sp_, FieldTag::ANNOTATION, cb,
156 &runtime_type_annotations_sp_);
157 }
158
159 template <class Callback>
EnumerateRuntimeTypeAnnotations(const Callback & cb)160 inline void FieldDataAccessor::EnumerateRuntimeTypeAnnotations(const Callback &cb)
161 {
162 if (is_external_) {
163 return;
164 }
165
166 if (runtime_type_annotations_sp_.data() == nullptr) {
167 SkipAnnotations();
168 }
169
170 helpers::EnumerateTaggedValues<File::EntityId, FieldTag, Callback>(runtime_type_annotations_sp_,
171 FieldTag::ANNOTATION, cb, &type_annotations_sp_);
172 }
173
174 template <class Callback>
EnumerateTypeAnnotations(const Callback & cb)175 inline void FieldDataAccessor::EnumerateTypeAnnotations(const Callback &cb)
176 {
177 if (is_external_) {
178 return;
179 }
180
181 if (type_annotations_sp_.data() == nullptr) {
182 SkipRuntimeTypeAnnotations();
183 }
184
185 Span<const uint8_t> sp {nullptr, nullptr};
186 helpers::EnumerateTaggedValues<File::EntityId, FieldTag, Callback>(type_annotations_sp_, FieldTag::ANNOTATION, cb,
187 &sp);
188
189 size_ = panda_file_.GetIdFromPointer(sp.data()).GetOffset() - field_id_.GetOffset() + 1; // + 1 for NOTHING tag
190 }
191
192 template <class Callback>
EnumerateRuntimeAnnotationsWithEarlyStop(const Callback & cb)193 inline bool FieldDataAccessor::EnumerateRuntimeAnnotationsWithEarlyStop(const Callback &cb)
194 {
195 if (is_external_) {
196 return false;
197 }
198
199 if (runtime_annotations_sp_.data() == nullptr) {
200 SkipValue();
201 }
202
203 return helpers::EnumerateTaggedValuesWithEarlyStop<File::EntityId, FieldTag, Callback>(
204 runtime_annotations_sp_, FieldTag::RUNTIME_ANNOTATION, cb);
205 }
206
207 template <class Callback>
EnumerateAnnotationsWithEarlyStop(const Callback & cb)208 inline bool FieldDataAccessor::EnumerateAnnotationsWithEarlyStop(const Callback &cb)
209 {
210 if (is_external_) {
211 return false;
212 }
213
214 if (annotations_sp_.data() == nullptr) {
215 SkipRuntimeAnnotations();
216 }
217
218 return helpers::EnumerateTaggedValuesWithEarlyStop<File::EntityId, FieldTag, Callback>(annotations_sp_,
219 FieldTag::ANNOTATION, cb);
220 }
221
GetAnnotationsNumber()222 inline uint32_t FieldDataAccessor::GetAnnotationsNumber()
223 {
224 size_t n = 0;
225 EnumerateRuntimeAnnotations([&n](File::EntityId /* unused */) { n++; });
226 return n;
227 }
228
GetRuntimeAnnotationsNumber()229 inline uint32_t FieldDataAccessor::GetRuntimeAnnotationsNumber()
230 {
231 size_t n = 0;
232 EnumerateRuntimeAnnotations([&n](File::EntityId /* unused */) { n++; });
233 return n;
234 }
235
GetRuntimeTypeAnnotationsNumber()236 inline uint32_t FieldDataAccessor::GetRuntimeTypeAnnotationsNumber()
237 {
238 size_t n = 0;
239 EnumerateRuntimeTypeAnnotations([&n](File::EntityId /* unused */) { n++; });
240 return n;
241 }
242
GetTypeAnnotationsNumber()243 inline uint32_t FieldDataAccessor::GetTypeAnnotationsNumber()
244 {
245 size_t n = 0;
246 EnumerateTypeAnnotations([&n](File::EntityId /* unused */) { n++; });
247 return n;
248 }
249
250 } // namespace panda::panda_file
251
252 #endif // LIBPANDAFILE_FIELD_DATA_ACCESSOR_INL_H
253