SmartSpectra C++ SDK
Measure human vitals from video with SmartSpectra C++ SDK.
Loading...
Searching...
No Matches
compile_time_string_concatenation.hpp
1// ================================================================
2// Created by nitronoid (https://stackoverflow.com/users/7878485/nitronoid?tab=profile)
3// Copyright (c) 2020 nitronoid
4// Source: https://stackoverflow.com/questions/38955940/how-to-concatenate-static-strings-at-compile-time/62823211#62823211
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8
9// http://www.apache.org/licenses/LICENSE-2.0
10
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16// ================================================================
17#pragma once
18#ifndef STRING_CONSTANT_H
19#define STRING_CONSTANT_H
20
21#include <cstddef>
22
23#include <stdexcept>
24#include <string>
25#include <type_traits>
26#include <utility>
27
28
29namespace presage::smartspectra::test{
30
31// Recursive comparison of each individual character in a string
32// The last bit with std::enable_if uses SFINAE (Substitution Failure Is Not An Error)
33// to rule this function out and switch to the base case for the recursion when the Index == Length
34template <std::size_t Length, std::size_t Index, typename Left, typename Right>
35constexpr auto CompareCharacters( const Left& lhs, const Right& rhs ) -> typename std::enable_if<Index != Length, bool>::type
36{
37return lhs[Index] == rhs[Index] ? CompareCharacters<Length, Index + 1>( lhs, rhs ) : false;
38}
39
40// Recursion base case. If you run past the last index of
41template <std::size_t Length, std::size_t Index, typename Left, typename Right, typename std::enable_if<Index == Length, bool>::type = 0>
42constexpr bool CompareCharacters( const Left& lhs, const Right& rhs )
43{
44 return true;
45}
46
47
48// Helper type traits to determine the length of either
49// a string literal or a StringConstant (specialized below)
50template <typename T>
52{
53 static_assert( std::is_void<T>::value, "Unsupported type for length_of" );
54
55 static constexpr std::size_t value = 1;
56};
57
58template <std::size_t N>
59struct length_of< const char(&)[N] >
60{
61 static constexpr std::size_t value = N - 1;
62};
63
64template <std::size_t N>
65struct length_of< char[N] >
66{
67 static constexpr std::size_t value = N - 1;
68};
69
70template <std::size_t N>
71struct length_of< const char[N] >
72{
73 static constexpr std::size_t value = N - 1;
74};
75
76
77// This small class is the heart of the constant string implementation.
78// It has constructors for string literals and individual chars, as well
79// as operators to interact with string literals or other instances. This
80// allows for it to have a very natural interface, and it's all constexpr
81// Inspired heavily by a class described in a presentation by Scott Schurr
82// at Boostcon:
83// https://github.com/boostcon/cppnow_presentations_2012/blob/master/wed/schurr_cpp11_tools_for_class_authors.pdf
84template <std::size_t N>
85class StringConstant
86{
87public:
88 // Constructor which takes individual chars. Allows for unpacking
89 // parameter packs directly into the constructor
90 template <typename... Characters>
91 constexpr StringConstant( Characters... characters )
92 : m_value{ characters..., '\0' }
93 {
94 }
95
96 // Copy constructor
97 template <std::size_t... Indexes>
98 constexpr StringConstant( const StringConstant<N>& rhs, std::index_sequence<Indexes...> dummy = StringConstant::g_indexes )
99 : m_value{ rhs[Indexes]..., '\0' }
100 {
101 }
102
103 template <std::size_t X, std::size_t... Indexes>
104 constexpr StringConstant( const StringConstant<X>& rhs, std::index_sequence<Indexes...> dummy )
105 : m_value{ rhs[Indexes]..., '\0' }
106 {
107 }
108
109 template <std::size_t... Indexes>
110 constexpr StringConstant( const char(&value)[N + 1], std::index_sequence<Indexes...> dummy )
111 : StringConstant( value[Indexes]... )
112 {
113 }
114
115 constexpr StringConstant( const char(&value)[N + 1] )
116 : StringConstant( value, std::make_index_sequence<N>{} )
117 {
118 }
119
120 // Array subscript operator, with some basic range checking
121 constexpr char operator[]( const std::size_t index ) const
122 {
123 return index < N ? m_value[index] : throw std::out_of_range("Index out of range");
124 }
125
126 constexpr const char* Get( ) const { return m_value; }
127 constexpr std::size_t Length( ) const { return N; }
128
129 std::string ToString( ) const { return std::string( m_value ); }
130
131protected:
132 const char m_value[N + 1];
133
134 static constexpr auto g_indexes = typename std::make_index_sequence<N>{};
135};
136
137// Specialize the length_of trait for the StringConstant class
138template <std::size_t N>
140{
141 static constexpr std::size_t value = N;
142};
143
144template <std::size_t N>
145struct length_of< const StringConstant<N> >
146{
147 static constexpr std::size_t value = N;
148};
149
150template <std::size_t N>
151struct length_of< const StringConstant<N>& >
152{
153 static constexpr std::size_t value = N;
154};
155
156// A helper trait for checking if something is a StringConstant
157// without having to know the length of the string it contains
158template <typename T>
160{
161 static constexpr bool value = false;
162};
163
164template <std::size_t N>
166{
167 static constexpr bool value = true;
168};
169
170template <std::size_t N>
172{
173 static constexpr bool value = true;
174};
175
176template <std::size_t N>
178{
179 static constexpr bool value = true;
180};
181
182template <std::size_t N>
184{
185 static constexpr bool value = true;
186};
187
188
189// A helper function for concatenating StringConstants
190
191// Less than human friendly concat function, wrapped by a huamn friendly one below
192template <typename Left, typename Right, std::size_t... IndexesLeft, std::size_t... IndexesRight>
193constexpr StringConstant<sizeof...(IndexesLeft) + sizeof...(IndexesRight)> ConcatStrings( const Left& lhs, const Right& rhs, std::index_sequence<IndexesLeft...> dummy1, std::index_sequence<IndexesRight...> dummy2 )
194{
195 return StringConstant<sizeof...(IndexesLeft) + sizeof...(IndexesRight)>( lhs[IndexesLeft]..., rhs[IndexesRight]... );
196}
197
198// Human friendly concat function for string literals
199template <typename Left, typename Right>
200constexpr StringConstant<length_of<Left>::value + length_of<Right>::value> ConcatStrings( const Left& lhs, const Right& rhs )
201{
202 return ConcatStrings( lhs, rhs, typename std::make_index_sequence<length_of<decltype(lhs)>::value>{}, typename std::make_index_sequence<length_of<decltype(rhs)>::value>{} );
203}
204
205
206// Finally, operators for dealing with a string literal LHS and StringConstant RHS
207
208// Addition operator
209template <std::size_t N, typename Right>
210constexpr StringConstant<N + length_of<Right>::value> operator+( const StringConstant<N>& lhs, const Right& rhs )
211{
212 return ConcatStrings( lhs, rhs );
213}
214
215template <typename Left, std::size_t N>
216constexpr StringConstant<length_of<Left>::value + N> operator+( const Left& lhs, const StringConstant<N>& rhs )
217{
218 return ConcatStrings( lhs, rhs );
219}
220
221template <std::size_t X, std::size_t Y>
222constexpr StringConstant<X + Y> operator+( const StringConstant<X>& lhs, const StringConstant<Y>& rhs )
223{
224 return ConcatStrings( lhs, rhs );
225}
226
227// Equality operator
228template <std::size_t N, typename Right>
229constexpr auto operator==( const StringConstant<N>& lhs, const Right& rhs ) -> typename std::enable_if<N == length_of<Right>::value, bool>::type
230{
231return CompareCharacters<N, 0>( lhs, rhs );
232}
233
234template <typename Left, std::size_t N>
235constexpr auto operator==( const Left& lhs, const StringConstant<N>& rhs ) -> typename std::enable_if<length_of<Left>::value == N, bool>::type
236{
237return CompareCharacters<N, 0>( lhs, rhs );
238}
239
240template <std::size_t X, std::size_t Y>
241constexpr auto operator==( const StringConstant<X>& lhs, const StringConstant<Y>& rhs ) -> typename std::enable_if<X == Y, bool>::type
242{
243return CompareCharacters<X, 0>( lhs, rhs );
244}
245
246// Different length strings can never be equal
247template <std::size_t N, typename Right, typename std::enable_if<N != length_of<Right>::value, bool>::type = 0>
248constexpr bool operator==( const StringConstant<N>& lhs, const Right& rhs )
249{
250 return false;
251}
252
253// Different length strings can never be equal
254template <typename Left, std::size_t N, typename std::enable_if<length_of<Left>::value != N, bool>::type = 0>
255constexpr bool operator==( const Left& lhs, const StringConstant<N>& rhs )
256{
257 return false;
258}
259
260// Different length strings can never be equal
261template <std::size_t X, std::size_t Y, typename std::enable_if<X != Y, bool>::type = 0>
262constexpr bool operator==( const StringConstant<X>& lhs, const StringConstant<Y>& rhs )
263{
264 return false;
265}
266
267
268template <std::size_t N, std::size_t... Indexes>
269constexpr auto StringFactory( const char(&value)[N], std::index_sequence<Indexes...> dummy )
270{
271 return StringConstant<N - 1>( value[Indexes]... );
272}
273
274
275// A helper factory function for creating FixedStringConstant objects
276// which handles figuring out the length of the string for you
277template <std::size_t N>
278constexpr auto StringFactory( const char(&value)[N] )
279{
280 return StringFactory( value, typename std::make_index_sequence<N - 1>{} );
281}
282
283
284} // namespace test
285#endif
Definition compile_time_string_concatenation.hpp:86
Definition compile_time_string_concatenation.hpp:160
Definition compile_time_string_concatenation.hpp:52