Rename: field type -> field class
[babeltrace.git] / lib / trace-ir / resolve-field-path.c
CommitLineData
44c440bc
PP
1/*
2 * Copyright 2018 Philippe Proulx <pproulx@efficios.com>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23#define BT_LOG_TAG "RESOLVE-FIELD-PATH"
24#include <babeltrace/lib-logging-internal.h>
25
26#include <babeltrace/assert-pre-internal.h>
27#include <babeltrace/assert-internal.h>
5cd6d0e5 28#include <babeltrace/trace-ir/field-classes-internal.h>
56e18c4c
PP
29#include <babeltrace/trace-ir/field-path-internal.h>
30#include <babeltrace/trace-ir/field-path.h>
31#include <babeltrace/trace-ir/resolve-field-path-internal.h>
44c440bc
PP
32#include <limits.h>
33#include <stdint.h>
34#include <inttypes.h>
35#include <glib.h>
36
37static
5cd6d0e5
PP
38bool find_field_class_recursive(struct bt_field_class *fc,
39 struct bt_field_class *tgt_fc, struct bt_field_path *field_path)
44c440bc
PP
40{
41 bool found = false;
42
5cd6d0e5 43 if (tgt_fc == fc) {
44c440bc
PP
44 found = true;
45 goto end;
46 }
47
5cd6d0e5
PP
48 switch (fc->id) {
49 case BT_FIELD_CLASS_ID_STRUCTURE:
50 case BT_FIELD_CLASS_ID_VARIANT:
44c440bc 51 {
5cd6d0e5
PP
52 struct bt_field_class_named_field_class_container *container_fc =
53 (void *) fc;
44c440bc
PP
54 uint64_t i;
55
5cd6d0e5
PP
56 for (i = 0; i < container_fc->named_fcs->len; i++) {
57 struct bt_named_field_class *named_fc =
58 BT_FIELD_CLASS_NAMED_FC_AT_INDEX(
59 container_fc, i);
44c440bc
PP
60
61 g_array_append_val(field_path->indexes, i);
5cd6d0e5
PP
62 found = find_field_class_recursive(named_fc->fc,
63 tgt_fc, field_path);
44c440bc
PP
64 if (found) {
65 goto end;
66 }
67
68 g_array_set_size(field_path->indexes,
69 field_path->indexes->len - 1);
70 }
71
72 break;
73 }
5cd6d0e5
PP
74 case BT_FIELD_CLASS_ID_STATIC_ARRAY:
75 case BT_FIELD_CLASS_ID_DYNAMIC_ARRAY:
44c440bc 76 {
5cd6d0e5 77 struct bt_field_class_array *array_fc = (void *) fc;
44c440bc 78
5cd6d0e5
PP
79 found = find_field_class_recursive(array_fc->element_fc,
80 tgt_fc, field_path);
44c440bc
PP
81 break;
82 }
83 default:
84 break;
85 }
86
87end:
88 return found;
89}
90
91static
5cd6d0e5
PP
92int find_field_class(struct bt_field_class *root_fc,
93 enum bt_scope root_scope, struct bt_field_class *tgt_fc,
44c440bc
PP
94 struct bt_field_path **ret_field_path)
95{
96 int ret = 0;
97 struct bt_field_path *field_path = NULL;
98
5cd6d0e5 99 if (!root_fc) {
44c440bc
PP
100 goto end;
101 }
102
103 field_path = bt_field_path_create();
104 if (!field_path) {
105 ret = -1;
106 goto end;
107 }
108
109 field_path->root = root_scope;
5cd6d0e5 110 if (!find_field_class_recursive(root_fc, tgt_fc, field_path)) {
44c440bc
PP
111 /* Not found here */
112 BT_PUT(field_path);
113 }
114
115end:
116 *ret_field_path = field_path;
117 return ret;
118}
119
120static
5cd6d0e5 121struct bt_field_path *find_field_class_in_ctx(struct bt_field_class *fc,
44c440bc
PP
122 struct bt_resolve_field_path_context *ctx)
123{
124 struct bt_field_path *field_path = NULL;
125 int ret;
126
5cd6d0e5
PP
127 ret = find_field_class(ctx->packet_header, BT_SCOPE_PACKET_HEADER,
128 fc, &field_path);
44c440bc
PP
129 if (ret || field_path) {
130 goto end;
131 }
132
5cd6d0e5
PP
133 ret = find_field_class(ctx->packet_context, BT_SCOPE_PACKET_CONTEXT,
134 fc, &field_path);
44c440bc
PP
135 if (ret || field_path) {
136 goto end;
137 }
138
5cd6d0e5
PP
139 ret = find_field_class(ctx->event_header, BT_SCOPE_EVENT_HEADER,
140 fc, &field_path);
44c440bc
PP
141 if (ret || field_path) {
142 goto end;
143 }
144
5cd6d0e5
PP
145 ret = find_field_class(ctx->event_common_context,
146 BT_SCOPE_EVENT_COMMON_CONTEXT, fc, &field_path);
44c440bc
PP
147 if (ret || field_path) {
148 goto end;
149 }
150
5cd6d0e5
PP
151 ret = find_field_class(ctx->event_specific_context,
152 BT_SCOPE_EVENT_SPECIFIC_CONTEXT, fc, &field_path);
44c440bc
PP
153 if (ret || field_path) {
154 goto end;
155 }
156
5cd6d0e5
PP
157 ret = find_field_class(ctx->event_payload, BT_SCOPE_EVENT_PAYLOAD,
158 fc, &field_path);
44c440bc
PP
159 if (ret || field_path) {
160 goto end;
161 }
162
163end:
164 return field_path;
165}
166
167BT_ASSERT_PRE_FUNC
168static inline
169bool target_is_before_source(struct bt_field_path *src_field_path,
170 struct bt_field_path *tgt_field_path)
171{
172 bool is_valid = true;
173 uint64_t src_i = 0, tgt_i = 0;
174
175 if (tgt_field_path->root < src_field_path->root) {
176 goto end;
177 }
178
179 if (tgt_field_path->root > src_field_path->root) {
180 is_valid = false;
181 goto end;
182 }
183
184 BT_ASSERT(tgt_field_path->root == src_field_path->root);
185
186 while (src_i < src_field_path->indexes->len &&
187 tgt_i < tgt_field_path->indexes->len) {
188 uint64_t src_index = bt_field_path_get_index_by_index_inline(
189 src_field_path, src_i);
190 uint64_t tgt_index = bt_field_path_get_index_by_index_inline(
191 tgt_field_path, tgt_i);
192
193 if (tgt_index > src_index) {
194 is_valid = false;
195 goto end;
196 }
197
198 src_i++;
199 tgt_i++;
200 }
201
202end:
203 return is_valid;
204}
205
206BT_ASSERT_PRE_FUNC
207static inline
5cd6d0e5 208struct bt_field_class *borrow_root_field_class(
44c440bc
PP
209 struct bt_resolve_field_path_context *ctx, enum bt_scope scope)
210{
211 switch (scope) {
212 case BT_SCOPE_PACKET_HEADER:
213 return ctx->packet_header;
214 case BT_SCOPE_PACKET_CONTEXT:
215 return ctx->packet_context;
216 case BT_SCOPE_EVENT_HEADER:
217 return ctx->event_header;
218 case BT_SCOPE_EVENT_COMMON_CONTEXT:
219 return ctx->event_common_context;
220 case BT_SCOPE_EVENT_SPECIFIC_CONTEXT:
221 return ctx->event_specific_context;
222 case BT_SCOPE_EVENT_PAYLOAD:
223 return ctx->event_payload;
224 default:
225 abort();
226 }
227
228 return NULL;
229}
230
231BT_ASSERT_PRE_FUNC
232static inline
5cd6d0e5 233struct bt_field_class *borrow_child_field_class(struct bt_field_class *parent_fc,
44c440bc
PP
234 uint64_t index, bool *advance)
235{
5cd6d0e5 236 struct bt_field_class *child_fc = NULL;
44c440bc 237
5cd6d0e5
PP
238 switch (parent_fc->id) {
239 case BT_FIELD_CLASS_ID_STRUCTURE:
240 case BT_FIELD_CLASS_ID_VARIANT:
44c440bc 241 {
5cd6d0e5
PP
242 struct bt_named_field_class *named_fc =
243 BT_FIELD_CLASS_NAMED_FC_AT_INDEX(parent_fc, index);
44c440bc 244
5cd6d0e5 245 child_fc = named_fc->fc;
44c440bc
PP
246 *advance = true;
247 break;
248 }
5cd6d0e5
PP
249 case BT_FIELD_CLASS_ID_STATIC_ARRAY:
250 case BT_FIELD_CLASS_ID_DYNAMIC_ARRAY:
44c440bc 251 {
5cd6d0e5 252 struct bt_field_class_array *array_fc = (void *) parent_fc;
44c440bc 253
5cd6d0e5 254 child_fc = array_fc->element_fc;
44c440bc
PP
255 *advance = false;
256 break;
257 }
258 default:
259 break;
260 }
261
5cd6d0e5 262 return child_fc;
44c440bc
PP
263}
264
265BT_ASSERT_PRE_FUNC
266static inline
5cd6d0e5 267bool target_field_path_in_different_scope_has_struct_fc_only(
44c440bc
PP
268 struct bt_field_path *src_field_path,
269 struct bt_field_path *tgt_field_path,
270 struct bt_resolve_field_path_context *ctx)
271{
272 bool is_valid = true;
273 uint64_t i = 0;
5cd6d0e5 274 struct bt_field_class *fc;
44c440bc
PP
275
276 if (src_field_path->root == tgt_field_path->root) {
277 goto end;
278 }
279
5cd6d0e5 280 fc = borrow_root_field_class(ctx, tgt_field_path->root);
44c440bc
PP
281
282 while (i < tgt_field_path->indexes->len) {
283 uint64_t index = bt_field_path_get_index_by_index_inline(
284 tgt_field_path, i);
285 bool advance;
286
5cd6d0e5
PP
287 if (fc->id == BT_FIELD_CLASS_ID_STATIC_ARRAY ||
288 fc->id == BT_FIELD_CLASS_ID_DYNAMIC_ARRAY ||
289 fc->id == BT_FIELD_CLASS_ID_VARIANT) {
44c440bc
PP
290 is_valid = false;
291 goto end;
292 }
293
5cd6d0e5 294 fc = borrow_child_field_class(fc, index, &advance);
44c440bc
PP
295
296 if (advance) {
297 i++;
298 }
299 }
300
301end:
302 return is_valid;
303}
304
305BT_ASSERT_PRE_FUNC
306static inline
5cd6d0e5 307bool lca_is_structure_field_class(struct bt_field_path *src_field_path,
44c440bc
PP
308 struct bt_field_path *tgt_field_path,
309 struct bt_resolve_field_path_context *ctx)
310{
311 bool is_valid = true;
5cd6d0e5
PP
312 struct bt_field_class *src_fc;
313 struct bt_field_class *tgt_fc;
314 struct bt_field_class *prev_fc = NULL;
44c440bc
PP
315 uint64_t src_i = 0, tgt_i = 0;
316
317 if (src_field_path->root != tgt_field_path->root) {
318 goto end;
319 }
320
5cd6d0e5
PP
321 src_fc = borrow_root_field_class(ctx, src_field_path->root);
322 tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root);
323 BT_ASSERT(src_fc);
324 BT_ASSERT(tgt_fc);
44c440bc
PP
325
326 while (src_i < src_field_path->indexes->len &&
327 tgt_i < tgt_field_path->indexes->len) {
328 bool advance;
329 uint64_t src_index = bt_field_path_get_index_by_index_inline(
330 src_field_path, src_i);
331 uint64_t tgt_index = bt_field_path_get_index_by_index_inline(
332 tgt_field_path, tgt_i);
333
5cd6d0e5
PP
334 if (src_fc != tgt_fc) {
335 if (!prev_fc) {
44c440bc
PP
336 /*
337 * This is correct: the LCA is the root
5cd6d0e5
PP
338 * scope field classe, which must be a
339 * structure field classe.
44c440bc
PP
340 */
341 break;
342 }
343
5cd6d0e5 344 if (prev_fc->id != BT_FIELD_CLASS_ID_STRUCTURE) {
44c440bc
PP
345 is_valid = false;
346 }
347
348 break;
349 }
350
5cd6d0e5
PP
351 prev_fc = src_fc;
352 src_fc = borrow_child_field_class(src_fc, src_index, &advance);
44c440bc
PP
353
354 if (advance) {
355 src_i++;
356 }
357
5cd6d0e5 358 tgt_fc = borrow_child_field_class(tgt_fc, tgt_index, &advance);
44c440bc
PP
359
360 if (advance) {
361 tgt_i++;
362 }
363 }
364
365end:
366 return is_valid;
367}
368
369BT_ASSERT_PRE_FUNC
370static inline
5cd6d0e5 371bool lca_to_target_has_struct_fc_only(struct bt_field_path *src_field_path,
44c440bc
PP
372 struct bt_field_path *tgt_field_path,
373 struct bt_resolve_field_path_context *ctx)
374{
375 bool is_valid = true;
5cd6d0e5
PP
376 struct bt_field_class *src_fc;
377 struct bt_field_class *tgt_fc;
44c440bc
PP
378 uint64_t src_i = 0, tgt_i = 0;
379
380 if (src_field_path->root != tgt_field_path->root) {
381 goto end;
382 }
383
5cd6d0e5
PP
384 src_fc = borrow_root_field_class(ctx, src_field_path->root);
385 tgt_fc = borrow_root_field_class(ctx, tgt_field_path->root);
386 BT_ASSERT(src_fc);
387 BT_ASSERT(tgt_fc);
388 BT_ASSERT(src_fc == tgt_fc);
44c440bc
PP
389
390 /* Find LCA */
391 while (src_i < src_field_path->indexes->len &&
392 tgt_i < tgt_field_path->indexes->len) {
393 bool advance;
394 uint64_t src_index = bt_field_path_get_index_by_index_inline(
395 src_field_path, src_i);
396 uint64_t tgt_index = bt_field_path_get_index_by_index_inline(
397 tgt_field_path, tgt_i);
398
399 if (src_i != tgt_i) {
5cd6d0e5 400 /* Next field class is different: LCA is `tgt_fc` */
44c440bc
PP
401 break;
402 }
403
5cd6d0e5 404 src_fc = borrow_child_field_class(src_fc, src_index, &advance);
44c440bc
PP
405
406 if (advance) {
407 src_i++;
408 }
409
5cd6d0e5 410 tgt_fc = borrow_child_field_class(tgt_fc, tgt_index, &advance);
44c440bc
PP
411
412 if (advance) {
413 tgt_i++;
414 }
415 }
416
5cd6d0e5 417 /* Only structure field classes to the target */
44c440bc
PP
418 while (tgt_i < tgt_field_path->indexes->len) {
419 bool advance;
420 uint64_t tgt_index = bt_field_path_get_index_by_index_inline(
421 tgt_field_path, tgt_i);
422
5cd6d0e5
PP
423 if (tgt_fc->id == BT_FIELD_CLASS_ID_STATIC_ARRAY ||
424 tgt_fc->id == BT_FIELD_CLASS_ID_DYNAMIC_ARRAY ||
425 tgt_fc->id == BT_FIELD_CLASS_ID_VARIANT) {
44c440bc
PP
426 is_valid = false;
427 goto end;
428 }
429
5cd6d0e5 430 tgt_fc = borrow_child_field_class(tgt_fc, tgt_index, &advance);
44c440bc
PP
431
432 if (advance) {
433 tgt_i++;
434 }
435 }
436
437end:
438 return is_valid;
439}
440
441BT_ASSERT_PRE_FUNC
442static inline
5cd6d0e5
PP
443bool field_path_is_valid(struct bt_field_class *src_fc,
444 struct bt_field_class *tgt_fc,
44c440bc
PP
445 struct bt_resolve_field_path_context *ctx)
446{
447 bool is_valid = true;
5cd6d0e5
PP
448 struct bt_field_path *src_field_path = find_field_class_in_ctx(
449 src_fc, ctx);
450 struct bt_field_path *tgt_field_path = find_field_class_in_ctx(
451 tgt_fc, ctx);
44c440bc
PP
452
453 if (!src_field_path) {
5cd6d0e5
PP
454 BT_ASSERT_PRE_MSG("Cannot find requesting field classe in "
455 "resolving context: %!+F", src_fc);
44c440bc
PP
456 is_valid = false;
457 goto end;
458 }
459
460 if (!tgt_field_path) {
5cd6d0e5
PP
461 BT_ASSERT_PRE_MSG("Cannot find target field classe in "
462 "resolving context: %!+F", tgt_fc);
44c440bc
PP
463 is_valid = false;
464 goto end;
465 }
466
467 /* Target must be before source */
468 if (!target_is_before_source(src_field_path, tgt_field_path)) {
5cd6d0e5
PP
469 BT_ASSERT_PRE_MSG("Target field classe is located after "
470 "requesting field classe: %![req-fc-]+F, %![tgt-fc-]+F",
471 src_fc, tgt_fc);
44c440bc
PP
472 is_valid = false;
473 goto end;
474 }
475
476 /*
477 * If target is in a different scope than source, there are no
5cd6d0e5 478 * array or variant field classes on the way to the target.
44c440bc 479 */
5cd6d0e5 480 if (!target_field_path_in_different_scope_has_struct_fc_only(
44c440bc 481 src_field_path, tgt_field_path, ctx)) {
5cd6d0e5
PP
482 BT_ASSERT_PRE_MSG("Target field classe is located in a "
483 "different scope than requesting field classe, "
484 "but within an array or a variant field classe: "
485 "%![req-fc-]+F, %![tgt-fc-]+F",
486 src_fc, tgt_fc);
44c440bc
PP
487 is_valid = false;
488 goto end;
489 }
490
5cd6d0e5
PP
491 /* Same scope: LCA must be a structure field classe */
492 if (!lca_is_structure_field_class(src_field_path, tgt_field_path, ctx)) {
44c440bc 493 BT_ASSERT_PRE_MSG("Lowest common ancestor of target and "
5cd6d0e5
PP
494 "requesting field classes is not a structure field classe: "
495 "%![req-fc-]+F, %![tgt-fc-]+F",
496 src_fc, tgt_fc);
44c440bc
PP
497 is_valid = false;
498 goto end;
499 }
500
501 /* Same scope: path from LCA to target has no array/variant FTs */
5cd6d0e5 502 if (!lca_to_target_has_struct_fc_only(src_field_path, tgt_field_path,
44c440bc
PP
503 ctx)) {
504 BT_ASSERT_PRE_MSG("Path from lowest common ancestor of target "
5cd6d0e5
PP
505 "and requesting field classes to target field classe "
506 "contains an array or a variant field classe: "
507 "%![req-fc-]+F, %![tgt-fc-]+F", src_fc, tgt_fc);
44c440bc
PP
508 is_valid = false;
509 goto end;
510 }
511
512end:
513 bt_put(src_field_path);
514 bt_put(tgt_field_path);
515 return is_valid;
516}
517
518static
5cd6d0e5
PP
519struct bt_field_path *resolve_field_path(struct bt_field_class *src_fc,
520 struct bt_field_class *tgt_fc,
44c440bc
PP
521 struct bt_resolve_field_path_context *ctx)
522{
5cd6d0e5
PP
523 BT_ASSERT_PRE(field_path_is_valid(src_fc, tgt_fc, ctx),
524 "Invalid target field classe: %![req-fc-]+F, %![tgt-fc-]+F",
525 src_fc, tgt_fc);
526 return find_field_class_in_ctx(tgt_fc, ctx);
44c440bc
PP
527}
528
529BT_HIDDEN
5cd6d0e5 530int bt_resolve_field_paths(struct bt_field_class *fc,
44c440bc
PP
531 struct bt_resolve_field_path_context *ctx)
532{
533 int ret = 0;
534
5cd6d0e5 535 BT_ASSERT(fc);
44c440bc 536
5cd6d0e5
PP
537 /* Resolving part for dynamic array and variant field classes */
538 switch (fc->id) {
539 case BT_FIELD_CLASS_ID_DYNAMIC_ARRAY:
44c440bc 540 {
5cd6d0e5 541 struct bt_field_class_dynamic_array *dyn_array_fc = (void *) fc;
44c440bc 542
5cd6d0e5
PP
543 if (dyn_array_fc->length_fc) {
544 BT_ASSERT(!dyn_array_fc->length_field_path);
545 dyn_array_fc->length_field_path = resolve_field_path(
546 fc, dyn_array_fc->length_fc, ctx);
547 if (!dyn_array_fc->length_field_path) {
44c440bc
PP
548 ret = -1;
549 goto end;
550 }
551 }
552
553 break;
554 }
5cd6d0e5 555 case BT_FIELD_CLASS_ID_VARIANT:
44c440bc 556 {
5cd6d0e5
PP
557 struct bt_field_class_variant *var_fc = (void *) fc;
558
559 if (var_fc->selector_fc) {
560 BT_ASSERT(!var_fc->selector_field_path);
561 var_fc->selector_field_path =
562 resolve_field_path(fc,
563 var_fc->selector_fc, ctx);
564 if (!var_fc->selector_field_path) {
44c440bc
PP
565 ret = -1;
566 goto end;
567 }
568 }
569 }
570 default:
571 break;
572 }
573
574 /* Recursive part */
5cd6d0e5
PP
575 switch (fc->id) {
576 case BT_FIELD_CLASS_ID_STRUCTURE:
577 case BT_FIELD_CLASS_ID_VARIANT:
44c440bc 578 {
5cd6d0e5
PP
579 struct bt_field_class_named_field_class_container *container_fc =
580 (void *) fc;
44c440bc
PP
581 uint64_t i;
582
5cd6d0e5
PP
583 for (i = 0; i < container_fc->named_fcs->len; i++) {
584 struct bt_named_field_class *named_fc =
585 BT_FIELD_CLASS_NAMED_FC_AT_INDEX(
586 container_fc, i);
44c440bc 587
5cd6d0e5 588 ret = bt_resolve_field_paths(named_fc->fc, ctx);
44c440bc
PP
589 if (ret) {
590 goto end;
591 }
592 }
593
594 break;
595 }
5cd6d0e5
PP
596 case BT_FIELD_CLASS_ID_STATIC_ARRAY:
597 case BT_FIELD_CLASS_ID_DYNAMIC_ARRAY:
44c440bc 598 {
5cd6d0e5 599 struct bt_field_class_array *array_fc = (void *) fc;
44c440bc 600
5cd6d0e5 601 ret = bt_resolve_field_paths(array_fc->element_fc, ctx);
44c440bc
PP
602 break;
603 }
604 default:
605 break;
606 }
607
608end:
609 return ret;
610}
This page took 0.049517 seconds and 4 git commands to generate.