xref: /aosp_15_r20/external/pigweed/pw_tokenizer/public/pw_tokenizer/internal/argument_types.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://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, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 // This header provides internal macros used by the tokenizer module.
16 #pragma once
17 
18 #include <stdint.h>
19 
20 #include "pw_preprocessor/arguments.h"
21 #include "pw_tokenizer/config.h"
22 
23 // The size of the argument types variable determines the number of arguments
24 // supported in tokenized strings.
25 #if PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES == 4
26 
27 #include "pw_tokenizer/internal/argument_types_macro_4_byte.h"
28 
29 // Encoding types in a uint32_t supports 14 arguments with 2 bits per argument.
30 #define PW_TOKENIZER_MAX_SUPPORTED_ARGS 14
31 #define PW_TOKENIZER_TYPE_COUNT_SIZE_BITS 4u
32 #define PW_TOKENIZER_TYPE_COUNT_MASK 0x0Fu
33 
34 typedef uint32_t pw_tokenizer_ArgTypes;
35 
36 #elif PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES == 8
37 
38 #include "pw_tokenizer/internal/argument_types_macro_8_byte.h"
39 
40 // Encoding types in a uint64_t supports 29 arguments with 2 bits per argument.
41 #define PW_TOKENIZER_MAX_SUPPORTED_ARGS 29
42 #define PW_TOKENIZER_TYPE_COUNT_SIZE_BITS 6u
43 #define PW_TOKENIZER_TYPE_COUNT_MASK 0x1Fu  // only 5 bits will be needed
44 
45 typedef uint64_t pw_tokenizer_ArgTypes;
46 
47 #else
48 
49 #error "Unsupported value for PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES"
50 
51 #endif  // PW_TOKENIZER_CFG_ARG_TYPES_SIZE_BYTES
52 
53 // The tokenized string encoding function is a variadic function that works
54 // similarly to printf. Instead of a format string, however, the argument types
55 // are packed into a pw_tokenizer_ArgTypes.
56 //
57 // The four supported argument types are represented by two-bit argument codes.
58 // Just four types are required because only printf-compatible arguments are
59 // supported, and variadic arguments are further converted to a more limited set
60 // of types.
61 //
62 // char* values cannot be printed as pointers with %p. These arguments are
63 // always encoded as strings. To format a char* as an address, cast it to void*
64 // or an integer.
65 #define PW_TOKENIZER_ARG_TYPE_INT ((pw_tokenizer_ArgTypes)0)
66 #define PW_TOKENIZER_ARG_TYPE_INT64 ((pw_tokenizer_ArgTypes)1)
67 #define PW_TOKENIZER_ARG_TYPE_DOUBLE ((pw_tokenizer_ArgTypes)2)
68 #define PW_TOKENIZER_ARG_TYPE_STRING ((pw_tokenizer_ArgTypes)3)
69 
70 // Select the int argument type based on the size of the type. Values smaller
71 // than int are promoted to int.
72 #define _PW_TOKENIZER_SELECT_INT_TYPE(type)                \
73   (sizeof(type) <= sizeof(int) ? PW_TOKENIZER_ARG_TYPE_INT \
74                                : PW_TOKENIZER_ARG_TYPE_INT64)
75 
76 // The _PW_VARARGS_TYPE macro selects the varargs-promoted type at compile time.
77 // The macro has to be different for C and C++ because C doesn't support
78 // templates and C++ doesn't support _Generic.
79 #ifdef __cplusplus
80 
81 #include <type_traits>
82 
83 #define _PW_VARARGS_TYPE(arg) ::pw::tokenizer::VarargsType<decltype(arg)>()
84 
85 namespace pw::tokenizer {
86 
87 // This function selects the matching type enum for supported argument types.
88 template <typename T>
VarargsType()89 constexpr pw_tokenizer_ArgTypes VarargsType() {
90   using ArgType = std::decay_t<T>;
91 
92   if constexpr (std::is_floating_point<ArgType>()) {
93     return PW_TOKENIZER_ARG_TYPE_DOUBLE;
94   } else if constexpr (!std::is_null_pointer<ArgType>() &&
95                        std::is_convertible<ArgType, const char*>()) {
96     return PW_TOKENIZER_ARG_TYPE_STRING;
97   } else if constexpr (sizeof(ArgType) == sizeof(int64_t)) {
98     return PW_TOKENIZER_ARG_TYPE_INT64;
99   } else {
100     static_assert(sizeof(ArgType) <= sizeof(int));
101     return PW_TOKENIZER_ARG_TYPE_INT;
102   }
103 }
104 
105 }  // namespace pw::tokenizer
106 
107 #else  // C version
108 
109 // This uses a C11 _Generic to select the matching enum value for each supported
110 // argument type. _Generic evaluates to the expression matching the type of the
111 // provided expression at compile time.
112 // clang-format off
113 #define _PW_VARARGS_TYPE(arg)                                            \
114   _Generic((arg),                                                        \
115                _Bool:  PW_TOKENIZER_ARG_TYPE_INT,                        \
116                 char:  PW_TOKENIZER_ARG_TYPE_INT,                        \
117          signed char:  PW_TOKENIZER_ARG_TYPE_INT,                        \
118        unsigned char:  PW_TOKENIZER_ARG_TYPE_INT,                        \
119         signed short:  PW_TOKENIZER_ARG_TYPE_INT,                        \
120       unsigned short:  PW_TOKENIZER_ARG_TYPE_INT,                        \
121           signed int:  PW_TOKENIZER_ARG_TYPE_INT,                        \
122         unsigned int:  PW_TOKENIZER_ARG_TYPE_INT,                        \
123          signed long: _PW_TOKENIZER_SELECT_INT_TYPE(signed long),        \
124        unsigned long: _PW_TOKENIZER_SELECT_INT_TYPE(unsigned long),      \
125     signed long long: _PW_TOKENIZER_SELECT_INT_TYPE(signed long long),   \
126   unsigned long long: _PW_TOKENIZER_SELECT_INT_TYPE(unsigned long long), \
127                float:  PW_TOKENIZER_ARG_TYPE_DOUBLE,                     \
128               double:  PW_TOKENIZER_ARG_TYPE_DOUBLE,                     \
129          long double:  PW_TOKENIZER_ARG_TYPE_DOUBLE,                     \
130                char*:  PW_TOKENIZER_ARG_TYPE_STRING,                     \
131          const char*:  PW_TOKENIZER_ARG_TYPE_STRING,                     \
132              default: _PW_TOKENIZER_SELECT_INT_TYPE(void*))
133 // clang-format on
134 
135 #endif  // __cplusplus
136 
137 #define _PW_TOKENIZER_TYPES_0() ((pw_tokenizer_ArgTypes)0)
138