Blame view

src/compiletimestring.h 7.17 KB
51becbde   Peter M. Groen   Committed the ent...
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
  /* Copyright (C) 2019
   *
   * This file is part of the osdev components suite
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the
   * Free Software Foundation; either version 2, or (at your option) any
   * later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
   */
  #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