compiletimestring.h
8.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* ****************************************************************************
* Copyright 2019 Open Systems Development BV *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
* DEALINGS IN THE SOFTWARE. *
* ***************************************************************************/
#ifndef OSDEV_COMPONENTS_MQTT_COMPILETIMESTRING_H
#define OSDEV_COMPONENTS_MQTT_COMPILETIMESTRING_H
/// @file
///
/// Support for compiletime string building.
///
/// In some cases it is necessary to embed string messages as read only string literals
/// so that they can be used in low memory conditions for example.
/// This header defines two macro's that can be used to build managed string literals.
/// These managed string literals can be concatenated and searched at compiletime.
/// When the compiler is done with this code only the embedded string literal that are
/// used by normal expressions remain in the binary.
/// The implementation is a mix of meta template programming and the use of constexpr
/// expressions and is based on an idea found on <a href="http://stackoverflow.com/a/15912824">stackoverflow</a>.
/// This code is meant to handle small strings (up to say 100 characters). Larger strings can trigger the maximum
/// template recursion depth of the compiler (-ftemplate-depth). This depth is set at 900. So in principle strings
/// of 900 characters can be handled. However this is very inefficient and will prolong compiletime severly.
///
/// Here follows an example of how this code can be used.
/// @code
/// auto str1 = OSDEV_COMPONENTS_CSTRING("This is a test");
/// auto str2 = OSDEV_COMPONENTS_CSTRING(" with concatenation");
/// auto str3 = str1 + str2;
/// const char* s = str3.chars;
/// @endcode
/// str3.chars contains the compiletime concatenated string.
///
/// When examing the binary one will see that it contains the null terminated string literal
/// @code
/// This is a test with concatenation^@
/// @endcode
/// The str1 and str2 literals are discarded since they are never used in a non compiletime way.
/// @note This code is not meant to handle string literals with internal \0 characters. Beware!
#include <limits>
#include "metaprogrammingdefs.h"
/// @brief Build a managed substring string literal from a string literal input
/// The strings are build compile time.
/// The upper bound is one past the last character that the caller is interested in.
#define OSDEV_COMPONENTS_CSTRING_BOUNDED(string_literal, lower, upper) \
[] { \
constexpr std::size_t lb = (lower); \
constexpr std::size_t ub = (upper); \
static_assert(lb <= ub, "lower bound must be smaller than or equal to upper bound"); \
static_assert(ub < sizeof(string_literal), \
"upper bound must be smaller than or equal to the length of the string"); \
struct constexpr_string_type \
{ \
const char* chars = string_literal; \
}; \
return typename osdev::components::mqtt::apply_bounded_range<lb, ub, \
osdev::components::mqtt::string_builder<constexpr_string_type>::template produce>::result{}; \
}()
/// @brief Build a managed string literal from a string literal input
#define OSDEV_COMPONENTS_CSTRING(string_literal) \
OSDEV_COMPONENTS_CSTRING_BOUNDED(string_literal, 0, sizeof(string_literal) - 1)
namespace osdev {
namespace components {
namespace mqtt {
/// @brief Managed string literal.
/// This class is used to hold string literals at compile time.
template <char... str>
struct compiletime_string
{
/// @brief Declaration of the string
static constexpr const char chars[sizeof...(str) + 1] = { str..., '\0' };
};
/// @brief Definition of the string
template <char... str>
constexpr const char compiletime_string<str...>::chars[sizeof...(str) + 1];
/// @brief Managed string literal builder.
/// This class is used to build string literals at compile time.
template <typename lambda_str_type>
struct string_builder
{
/// @brief maps indices list on the char array
template <std::size_t... indices>
struct produce
{
typedef compiletime_string<lambda_str_type{}.chars[indices]...> result;
};
};
/// @brief Adapter for coupling other producers to string_builder.
/// tparam T The type of producer to adapt.
/// @note The adapter must define its return type as return_t and provide a static method produce() which produces the result.
/// The return type must be a kind of array type of chars (char[len], std::array<char,len>, etc).
template <typename T>
struct adapt_for_string_builder
{
static constexpr typename T::return_t chars = T::produce();
};
/// @brief Concatenate two managed string literals
/// The literals are packed in a variadic template.
/// These templates are formed by the MLOGIC_COMMON_CSTRING* macro's
/// The concatenation is done at compiletime.
template <char... str0, char... str1>
compiletime_string<str0..., str1...> operator+(compiletime_string<str0...>, compiletime_string<str1...>)
{
return {};
}
/// @brief Search for a character in a string literal from the right side.
/// The character index is returned relative to the left side.
/// If the character is not found a std::size_t(-1) is returned.
/// The default search starts at the end of the string. The index
/// can be given to start the search at another point in the string.
/// The index is given as nr of characters from the right end side of
/// the string. To proceed with a search see following example.
/// @code
/// constexpr const char s[] = "This is a test";
/// constexpr std::size_t index = osdev_components::mqtt::rfind(s, 'i'); // gives 5
/// static_assert(index == 5, "");
/// constexpr std::size_t index2 = osdev::components::mqtt::rfind(s, 'i', sizeof(s) - index); // gives 2
/// static_assert(index2 == 2, "");
/// @endcode
/// This function should only be used at compile time!
template <std::size_t N>
constexpr std::size_t rfind(const char (&str)[N], char c, std::size_t index = 0)
{
return index >= N ? std::numeric_limits<std::size_t>::max() : str[N - index - 1] == c ? N - index - 1 : rfind(str, c, index + 1);
}
} // End namespace mqtt
} // End namespace components
} // End namespace osdev
#endif // OSDEV_COMPONENTS_MQTT_COMPILETIMESTRING_H