dte test coverage


Directory: ./
File: src/util/array.h
Date: 2025-02-14 16:55:22
Exec Total Coverage
Lines: 21 21 100.0%
Functions: 3 3 100.0%
Branches: 10 12 83.3%

Line Branch Exec Source
1 #ifndef UTIL_ARRAY_H
2 #define UTIL_ARRAY_H
3
4 #include <stdbool.h>
5 #include <sys/types.h>
6 #include "debug.h"
7 #include "macros.h"
8 #include "ptr-array.h"
9 #include "xstring.h"
10
11 #define static_assert_flat_string_array(a) do { \
12 static_assert_incompatible_types(a[0], const char*); \
13 static_assert_incompatible_types(a[0], char*); \
14 static_assert_compatible_types(a[0][0], char); \
15 } while(0)
16
17 #define static_assert_flat_struct_array(a, field) do { \
18 static_assert_offsetof(a[0], field, 0); \
19 static_assert_incompatible_types(a[0].field, const char*); \
20 static_assert_incompatible_types(a[0].field, char*); \
21 static_assert_compatible_types(a[0].field[0], char); \
22 } while(0)
23
24 #define CHECK_STRING_ARRAY(a) do { \
25 static_assert_flat_string_array(a); \
26 check_array(a, #a, "", ARRAYLEN(a), sizeof(a[0]), sizeof(a[0])); \
27 } while (0)
28
29 #define CHECK_STRUCT_ARRAY(a, field) do { \
30 static_assert_flat_struct_array(a, field); \
31 check_array(a, #a, "." #field, ARRAYLEN(a), sizeof(a[0]), sizeof(a[0].field)); \
32 } while (0)
33
34 #define COLLECT_STRINGS(a, ptrs, prefix) do { \
35 static_assert_flat_string_array(a); \
36 collect_strings_from_flat_array(a[0], ARRAYLEN(a), sizeof(a[0]), ptrs, prefix); \
37 } while (0)
38
39 #define COLLECT_STRING_FIELDS(a, field, ptrs, prefix) do { \
40 static_assert_flat_struct_array(a, field); \
41 collect_strings_from_flat_array(a[0].field, ARRAYLEN(a), sizeof(a[0]), ptrs, prefix); \
42 } while (0)
43
44 #define STR_TO_ENUM_WITH_OFFSET(str, a, nfval, off) \
45 str_to_enum(str, a[0], ARRAYLEN(a), sizeof(a[0]), off, nfval)
46
47 #define SSTR_TO_ENUM_WITH_OFFSET(str, a, field, nfval, off) \
48 str_to_enum(str, a[0].field, ARRAYLEN(a), sizeof(a[0]), off, nfval)
49
50 #define STR_TO_ENUM(str, a, nfval) \
51 STR_TO_ENUM_WITH_OFFSET(str, a, nfval, 0)
52
53 // This is somewhat similar to lfind(3), but returning an index
54 // instead of a pointer and specifically for arrays of type
55 // `const char[nmemb][size]`
56 834 static inline ssize_t find_str_idx (
57 const char *str,
58 const char *base,
59 size_t nmemb,
60 size_t size,
61 bool (*equal)(const char *s1, const char *s2)
62 ) {
63 834 const char *entry = base;
64
2/2
✓ Branch 0 (7→3) taken 8311 times.
✓ Branch 1 (7→8) taken 298 times.
8609 for (size_t i = 0; i < nmemb; i++, entry += size) {
65
2/2
✓ Branch 0 (4→5) taken 536 times.
✓ Branch 1 (4→6) taken 7775 times.
8311 if (equal(str, entry)) {
66 536 return i;
67 }
68 }
69 return -1;
70 }
71
72 // Attempt to find `str` in a flat array of strings starting at `base`.
73 // If found, return the index plus `return_offset`, otherwise return
74 // `not_found_val`.
75 834 static inline int str_to_enum (
76 const char *str,
77 const char *base,
78 size_t nmemb,
79 size_t size,
80 int return_offset,
81 int not_found_val
82 ) {
83 834 ssize_t idx = find_str_idx(str, base, nmemb, size, streq);
84
2/2
✓ Branch 0 (3→4) taken 536 times.
✓ Branch 1 (3→5) taken 298 times.
834 return (idx >= 0) ? idx + return_offset : not_found_val;
85 }
86
87 void collect_strings_from_flat_array (
88 const char *base,
89 size_t nr_elements,
90 size_t element_len,
91 PointerArray *a,
92 const char *prefix
93 );
94
95 504 static inline void check_array (
96 const void *base,
97 const char *array_name,
98 const char *name_field_name,
99 size_t array_len,
100 size_t elem_size,
101 size_t name_size
102 ) {
103 504 if (DEBUG < 1) {
104 return;
105 }
106
107 504 BUG_ON(!base);
108 504 BUG_ON(!array_name);
109 504 BUG_ON(!name_field_name);
110 504 BUG_ON(name_field_name[0] != '\0' && name_field_name[0] != '.');
111 504 BUG_ON(array_len == 0);
112 504 BUG_ON(elem_size == 0);
113 504 BUG_ON(name_size == 0);
114
115 const char *first_name = base;
116
2/2
✓ Branch 0 (21→16) taken 18252 times.
✓ Branch 1 (21→22) taken 504 times.
18756 for (size_t i = 0; i < array_len; i++) {
117 18252 const char *curr_name = first_name + (i * elem_size);
118 // NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult)
119
1/2
✗ Branch 0 (16→17) not taken.
✓ Branch 1 (16→18) taken 18252 times.
18252 if (curr_name[0] == '\0') {
120 BUG("Empty string at %s[%zu]%s", array_name, i, name_field_name);
121 }
122 // NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult)
123
1/2
✗ Branch 0 (18→19) not taken.
✓ Branch 1 (18→20) taken 18252 times.
18252 if (curr_name[name_size - 1] != '\0') {
124 BUG("String sentinel missing from %s[%zu]%s", array_name, i, name_field_name);
125 }
126 }
127 }
128
129 #endif
130