Line data Source code
1 : // Copyright (c) 2026 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snapdev
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 : #pragma once
19 :
20 : /** \file
21 : * \brief Determine the length of a string literal at compile time.
22 : *
23 : * This template is used to retrieve the length of a string literal at
24 : * compile time:
25 : *
26 : * \code
27 : * if(snapdev::string_literal_length(str) > 3) ...
28 : * \endcode
29 : *
30 : * The function makes sure that the input string is a `char`, `wchar_t`,
31 : * `char8_t`, `char16_t`, and `char32_t`.
32 : *
33 : * \note
34 : * The `char8_t` type is only available since C++20.
35 : */
36 :
37 : // self
38 : //
39 : #include <snapdev/is_nonnull.h>
40 : #include <snapdev/is_string_literal.h>
41 :
42 :
43 : // C++
44 : //
45 : #include <type_traits>
46 :
47 :
48 :
49 : namespace snapdev
50 : {
51 :
52 :
53 :
54 : /** \brief Get the length of a string literal at compile time.
55 : *
56 : * This template is used to get a string literal length at compile time.
57 : * It gives the size of the character array and also verifies that the
58 : * type is indeed a character type (char, wchar_t, char8_t, char16_t,
59 : * or char32_t).
60 : *
61 : * \warning
62 : * Note that any character buffer is viewed as a "string literal".
63 : * So a definition as follow will return true even though you may
64 : * see it as a buffer rather than a string literal:
65 : * \warning
66 : * \code
67 : * constexpr std::uint8_t const g_buffer[5] = { 1, 2, 3, 4, 5 };
68 : * \endcode
69 : * \warning
70 : * Furher, a character buffer may have a size which is not the length
71 : * of the string as in:
72 : * \warning
73 : * \code
74 : * constexpr char const g_buffer[256] = { 'O', 'o', 'p', 's' };
75 : * \endcode
76 : * \warning
77 : * as a string of 4 characters in a buffer of 256 chars so this function
78 : * returns 255. In that latter case, you may want to consider using the
79 : * string_length() template function instead.
80 : *
81 : * \tparam T The type of the array element.
82 : * \tparam N The size of the array.
83 : *
84 : * \sa string_length()
85 : * \sa is_string_literal
86 : * \sa is_a_string_literal
87 : */
88 : template<typename T, std::size_t N>
89 : std::enable_if_t<is_string_literal<T[N]>::value, std::size_t>
90 10 : string_literal_length(T const (&)[N])
91 : {
92 10 : return N - 1;
93 : }
94 :
95 :
96 : /** \brief Compute the length of a string at compile time.
97 : *
98 : * This function is similar to the string_literal_length() except that
99 : * it works with a buffer of any size and works like strlen() as in,
100 : * it stops at the first `'\0'` character.
101 : *
102 : * The template also verifies that the array type is of a character
103 : * type (char, wchar_t, char8_t, char16_t, char32_t).
104 : *
105 : * \exception found_nullptr
106 : * If the input pointer is a null pointer, then this exception is raised.
107 : *
108 : * \tparam T The type of the string.
109 : */
110 : template<typename T>
111 : constexpr std::enable_if_t<std::disjunction_v<
112 : std::is_same<T, char>
113 : , std::is_same<T, wchar_t>
114 : , std::is_same<T, char8_t>
115 : , std::is_same<T, char16_t>
116 : , std::is_same<T, char32_t>>, std::size_t>
117 110 : string_length(T const * s)
118 : {
119 110 : return *is_nonnull(s) == '\0' ? 0 : 1 + string_length(s + 1);
120 : }
121 :
122 :
123 :
124 : } // namespace snapdev
125 : // vim: ts=4 sw=4 et
|