1 /***********************************************************************************************************************************
2 Represent Short Strings as Integers
3 
4 It is often useful to represent identifiers as strings when they cannot easily be represented as an enum/integer, e.g. because they
5 are distributed among a number of unrelated modules or need to be passed to remote processes. Strings are also more helpful in
6 debugging since they can be recognized without cross-referencing the source. However, strings are awkward to work with in C since
7 they cannot be directly used in switch statements leading to less efficient if-else structures.
8 
9 A StringId encodes a short string into an integer so it can be used in switch statements but may also be readily converted back into
10 a string for debugging purposes. StringIds may also be suitable for matching user input providing the strings are short enough.
11 
12 strIdFromStr("mytest0123a") will return the StringId 0x7de75c51315464d5. Using the value, the string representation can be retrieved
13 strIdToStr(0x7de75c51315464d5) which returns "mytest0123+" where the plus at the end signals that the original string was equal to
14 or longer than the maximum allowed.
15 
16 When assigning a StringId to an enum, it will be necessary to cast the StringId to the enum type if the enum contains all 32-bit
17 values, since some compilers will complain about the implicit conversion without a cast. The enum will be 32-bit if all values of
18 the enum are <= 0xffffffff.
19 
20 See bldStrId() for information on generating StringId constants.
21 ***********************************************************************************************************************************/
22 #ifndef COMMON_TYPE_STRINGID_H
23 #define COMMON_TYPE_STRINGID_H
24 
25 #include <stddef.h>
26 #include <stdint.h>
27 #include <string.h>
28 
29 #include "common/type/string.h"
30 
31 /***********************************************************************************************************************************
32 Maximum number of characters in the string representation of a StringId. When the string representation is equal to or greater than
33 the MAX, then a plus sign + will be assigned as the last (MAX) character in the string representation. This is a safe buffer size
34 when calling strIdToZN. If the buffer needs to be zero-terminated then an extra byte should be added.
35 ***********************************************************************************************************************************/
36 // Maximum for specific encodings (e.g. 5-bit, 6-bit)
37 #define STRID5_MAX                                                  13
38 #define STRID6_MAX                                                  11
39 
40 // Maximum for any encoding
41 #define STRID_MAX                                                   STRID5_MAX
42 
43 /***********************************************************************************************************************************
44 Constants used to extract information from the header
45 ***********************************************************************************************************************************/
46 #define STRING_ID_BIT_MASK                                          3
47 
48 /***********************************************************************************************************************************
49 StringId typedef to make them more recognizable in the code
50 ***********************************************************************************************************************************/
51 typedef uint64_t StringId;
52 
53 /***********************************************************************************************************************************
54 Number of bits to use for encoding. The number of bits affects the character set that can be encoded.
55 ***********************************************************************************************************************************/
56 typedef enum
57 {
58     stringIdBit5 = 0,                                               // 5-bit encoding for a-z, 2, 5, 6, and - characters
59     stringIdBit6 = 1,                                               // 6-bit encoding for a-z, 0-9, A-Z, and - characters
60 } StringIdBit;
61 
62 /***********************************************************************************************************************************
63 Macros to define constant StringIds. ALWAYS use bldStrId() to create these macros. The parameters in the macros are not verified
64 against each other so the str parameter is included only for documentation purposes.
65 ***********************************************************************************************************************************/
66 #define STRID5(str, strId)                                          strId
67 #define STRID6(str, strId)                                          strId
68 
69 /***********************************************************************************************************************************
70 Functions
71 ***********************************************************************************************************************************/
72 // Convert N chars to StringId, If the string is longer than the allowable length for the selected encoding then the StringID will
73 // be marked as "partial" and will have a '+' appended whenever it is converted back to a string. This is to distiguish it from a
74 // string with the same number of encoded characters that did not overflow.
75 StringId strIdFromZN(const StringIdBit bit, const char *const buffer, const size_t size);
76 
77 // Convert String to StringId using strIdFromZN()
78 __attribute__((always_inline)) static inline StringId
strIdFromStr(const StringIdBit bit,const String * const str)79 strIdFromStr(const StringIdBit bit, const String *const str)
80 {
81     return strIdFromZN(bit, strZ(str), strSize(str));
82 }
83 
84 // Convert zero-terminted string to StringId using strIdFromZN()
85 __attribute__((always_inline)) static inline StringId
strIdFromZ(const StringIdBit bit,const char * const str)86 strIdFromZ(const StringIdBit bit, const char *const str)
87 {
88     return strIdFromZN(bit, str, strlen(str));
89 }
90 
91 // Write StringId to characters without zero-terminating. The buffer at ptr must have enough space to write the entire StringId,
92 // which could be eight characters. However, the caller may know the exact (or max length) in advance and act accordingly. The
93 // actual number of bytes written is returned.
94 size_t strIdToZN(StringId strId, char *const buffer);
95 
96 // Convert StringId to String
97 String *strIdToStr(const StringId strId);
98 
99 // Convert StringId to zero-terminated string. See strIdToZN() for buffer sizing and return value.
100 size_t strIdToZ(const StringId strId, char *const buffer);
101 
102 /***********************************************************************************************************************************
103 Macros for function logging
104 ***********************************************************************************************************************************/
105 size_t strIdToLog(const StringId strId, char *const buffer, const size_t bufferSize);
106 
107 #define FUNCTION_LOG_STRING_ID_TYPE                                                                                                \
108     StringId
109 #define FUNCTION_LOG_STRING_ID_FORMAT(value, buffer, bufferSize)                                                                   \
110     strIdToLog(value, buffer, bufferSize)
111 
112 #endif
113