KIDS  ver-0.0.1
KIDS : Kernel Integrated Dynamics Simulator
Loading...
Searching...
No Matches
concat.h
Go to the documentation of this file.
1/*
2 * CONCAT
3 * Version: 2014-07-29
4 * ----------------------------------------------------------
5 * Copyright (c) 2014 José Manuel Barroso Galindo. All rights reserved.
6 *
7 * Distributed under the Boost Software License, Version 1.0. (See accompanying
8 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 */
10#ifndef THEYPSILON_CONCAT
11#define THEYPSILON_CONCAT
12
13#include <iomanip>
14#include <sstream>
15#include <tuple>
16#include <utility>
17
18namespace utils {
19
20template <typename CharT>
21struct separator_t { // this class shouldn't be explicitly invoked in client code, use "separator" instead
22 const CharT* sep;
23 constexpr explicit separator_t(const CharT* s) noexcept : sep{s} {}
24};
25
26template <typename CharT>
27constexpr separator_t<CharT> separator(const CharT* s) {
28 return separator_t<CharT>(s);
29}
30
31namespace sep { // this can be used as an additional way of defining a separator, check 3. entry point
32constexpr char none[] = "";
33constexpr char space[] = " ";
34constexpr char endl[] = "\n";
35constexpr char comma[] = ", ";
36constexpr char plus[] = " + ";
37}; // namespace sep
38
39namespace { // type helpers and traits
40template <typename T, typename CharT>
41struct is_writable_stream : std::integral_constant<bool, std::is_same<T, std::basic_ostringstream<CharT>>::value ||
42 std::is_same<T, std::basic_stringstream<CharT>>::value ||
43 std::is_same<T, std::basic_ostream<CharT>>::value> {};
44
45template <typename T, typename CharT = char>
46struct is_stringstream : std::integral_constant<bool, std::is_same<T, std::basic_istringstream<CharT>>::value ||
47 std::is_same<T, std::basic_ostringstream<CharT>>::value ||
48 std::is_same<T, std::basic_stringstream<CharT>>::value> {};
49
50template <typename T, typename CharT = char>
51struct is_c_str : std::integral_constant<bool, std::is_same<typename std::decay<T>::type, CharT const*>::value ||
52 std::is_same<typename std::decay<T>::type, CharT*>::value> {};
53
54template <typename T>
55struct is_char_sequence
56 : std::integral_constant<bool, is_c_str<T, char>::value || is_c_str<T, wchar_t>::value ||
57 is_c_str<T, char16_t>::value || is_c_str<T, char32_t>::value> {};
58
59template <typename T>
60struct is_string
61 : std::integral_constant<bool, std::is_same<T, std::string>::value || std::is_same<T, std::wstring>::value ||
62 std::is_same<T, std::u16string>::value ||
63 std::is_same<T, std::u32string>::value> {};
64
65struct can_const_begin_end_impl {
66 template <typename T, typename B = decltype(std::begin(std::declval<const T&>())),
67 typename E = decltype(std::end(std::declval<const T&>()))>
68 static std::true_type test(int);
69 template <typename...>
70 static std::false_type test(...);
71};
72
73template <typename T>
74struct can_const_begin_end : public decltype(can_const_begin_end_impl::test<T>(0)) {};
75
76template <typename T>
77struct is_iterable : std::integral_constant<bool, can_const_begin_end<T>::value && !is_string<T>::value &&
78 !is_stringstream<T>::value && !is_char_sequence<T*>::value> {};
79
80template <typename CharT>
81struct does_overload_ostream_impl {
82 template <typename T, typename B = decltype(std::declval<std::basic_ostream<CharT>&>() << std::declval<const T&>())>
83
84 static std::true_type test(int);
85 template <typename...>
86 static std::false_type test(...);
87};
88
89template <typename CharT, typename T>
90struct does_overload_ostream : public decltype(does_overload_ostream_impl<CharT>::template test<T>(0)) {};
91
92template <typename CharT, typename T>
93struct is_parametrized_manipulator
94 : std::integral_constant<
95 bool, std::is_same<T, decltype(std::setbase(std::declval<int>()))>::value ||
96 std::is_same<T, decltype(std::setprecision(std::declval<int>()))>::value ||
97 std::is_same<T, decltype(std::setw(std::declval<int>()))>::value ||
98 std::is_same<T, decltype(std::setfill(std::declval<CharT>()))>::value ||
99 std::is_same<T, decltype(std::setiosflags(std::declval<std::ios::fmtflags>()))>::value ||
100 std::is_same<T, decltype(std::resetiosflags(std::declval<std::ios::fmtflags>()))>::value> {};
101
102template <typename CharT, typename T>
103struct is_manipulator
104 : std::integral_constant<bool, (std::is_function<T>::value || is_parametrized_manipulator<CharT, T>::value) &&
105 does_overload_ostream<CharT, T>::value> {};
106
107template <typename T, template <typename...> class Template>
108struct is_specialization_of : std::false_type {};
109
110template <template <typename...> class Template, typename... Args>
111struct is_specialization_of<Template<Args...>, Template> : std::true_type {};
112
113template <bool B, class T = void>
114using enable_if_t = typename std::enable_if<B, T>::type;
115} // namespace
116
117namespace { // concat_impl : stringstream to string helper, separator handlers, and parameter writer functions
118
119template <typename CharT, typename W>
120std::basic_string<CharT> concat_to_string(const W& writer) {
121 return writer.good() ? writer.str() : std::basic_string<CharT>();
122}
123
124template <typename CharT, char head, char... tail>
125std::basic_string<CharT> get_separator() {
126 return {head, tail...};
127}
128
129template <typename W, typename S>
130void separate(W& writer, const S* separator) {
131 if (separator) writer << separator;
132}
133
134template <typename W, typename S>
135void separate(W& writer, const S& separator) {
136 writer << separator;
137}
138
139template <typename CharT, typename T, typename W, typename S>
140void concat_impl_write_separator(W& writer, const S& separator) {
141 if (!is_manipulator<CharT, T>::value) separate(writer, separator);
142}
143
144template <typename CharT, typename W, typename S, typename... Args>
145void concat_impl_write_element(W&, const S&, const std::tuple<Args...>&);
146
147template <typename CharT, typename W, typename S, typename P1, typename P2>
148void concat_impl_write_element(W&, const S&, const std::pair<P1, P2>&);
149
150// we have 6 base cases, depending of the parameter type:
151// 1. base case any type compatible with << that doesn't require a special handling
152template <typename CharT, typename W, typename S, typename T>
153enable_if_t<!is_iterable<T>::value && !is_stringstream<T>::value, void> concat_impl_write_element(W& writer, const S&,
154 const T& element) {
155 writer << element;
156}
157
158// 2. base case for fundamental built-in string types (const CharT* family, a.k.a. cstrings)
159template <typename CharT, typename W, typename S, typename T>
160enable_if_t<is_char_sequence<T*>::value, void> concat_impl_write_element(W& writer, const S&, const T* element) {
161 if (element) writer << element;
162}
163
164// 3. base case for std::stringstream types
165template <typename CharT, typename W, typename S, typename T>
166enable_if_t<is_stringstream<T>::value, void> concat_impl_write_element(W& writer, const S&, const T& element) {
167 if (element.good())
168 writer << concat_to_string<CharT>(element);
169 else
170 writer.setstate(element.rdstate());
171}
172
173// 4. base case for containers, arrays, and any iterable type EXCEPT the standard string types
174template <typename CharT, typename W, typename S, typename T>
175enable_if_t<is_iterable<T>::value, void> concat_impl_write_element(W& writer, const S& separator, const T& container) {
176 auto it = std::begin(container), et = std::end(container);
177 while (it != et) {
178 concat_impl_write_element<CharT>(writer, separator, *it);
179 if (++it != et) concat_impl_write_separator<CharT, T>(writer, separator);
180 }
181}
182
183// 5. base case for std::tuples
184template <unsigned N, unsigned Last>
185struct tuple_printer {
186 template <typename CharT, typename W, typename S, typename T>
187 static void print(W& writer, const S& separator, const T& tuple) {
188 concat_impl_write_element<CharT>(writer, separator, std::get<N>(tuple));
189 concat_impl_write_separator<CharT, T>(writer, separator);
190 tuple_printer<N + 1, Last>::template print<CharT>(writer, separator, tuple);
191 }
192};
193
194template <unsigned N>
195struct tuple_printer<N, N> {
196 template <typename CharT, typename W, typename S, typename T>
197 static void print(W& writer, const S& separator, const T& tuple) {
198 concat_impl_write_element<CharT>(writer, separator, std::get<N>(tuple));
199 }
200};
201
202template <typename CharT, typename W, typename S, typename... Args>
203inline void concat_impl_write_element(W& writer, const S& separator, const std::tuple<Args...>& tuple) {
204 tuple_printer<0, sizeof...(Args) - 1>::template print<CharT>(writer, separator, tuple);
205}
206
207// 6. base case for std::pairs
208template <typename CharT, typename W, typename S, typename P1, typename P2>
209inline void concat_impl_write_element(W& writer, const S& separator, const std::pair<P1, P2>& pair) {
210 concat_impl_write_element<CharT>(writer, separator, pair.first);
211 concat_impl_write_separator<CharT, std::pair<P1, P2>>(writer, separator);
212 concat_impl_write_element<CharT>(writer, separator, pair.second);
213}
214
215// the following function is the recursive step that unpacks all the variadic parameters
216template <typename CharT, typename W, typename S, typename T, typename... Args>
217void concat_impl_write_element(W& writer, const S& separator, const T& head, const Args&... tail) {
218 concat_impl_write_element<CharT>(writer, separator, head);
219 concat_impl_write_separator<CharT, T>(writer, separator);
220 concat_impl_write_element<CharT>(writer, separator, tail...);
221}
222
223// rearranges the parameters in order to prepare the recursive calls
224template <typename CharT, typename S, typename T, typename... Args,
225 typename = enable_if_t<is_writable_stream<T, CharT>::value, T>>
226std::basic_string<CharT> concat_impl(const S& separator, T& writer, const Args&... seq) {
227 concat_impl_write_element<CharT>(writer, separator, seq...);
228 return concat_to_string<CharT>(writer);
229}
230
231// when the first parameter is not a stringstream non-const reference, this defines the writer stream
232template <typename CharT, typename S, typename... Args>
233std::basic_string<CharT> concat_impl(const S& separator, const Args&... seq) {
234 std::basic_ostringstream<CharT> writer;
235 return concat_impl<CharT>(separator, writer, seq...);
236}
237} // namespace
238
239// the 5 entry points:
240// 1. entry point, when received a separator as first element
241template <typename CharT = char, typename... Args>
242std::basic_string<CharT> concat(const separator_t<CharT>& sep, Args&&... seq) {
243 return concat_impl<CharT>(sep.sep, std::forward<Args>(seq)...);
244}
245
246// 2. entry point, when the separator es specified via templated char-pack arguments
247template <char head, char... tail, typename F, typename... Args,
248 typename = enable_if_t<!std::is_same<F, separator_t<char>>::value, F>>
249std::basic_string<char> concat(F&& first, Args&&... rest) {
250 return concat_impl<char>(get_separator<char, head, tail...>(), std::forward<F>(first), std::forward<Args>(rest)...);
251}
252
253// 3. entry point, when the separator is a template argument of compile-time defined const char*
254template <const char* sep, typename F, typename... Args,
255 typename = enable_if_t<!std::is_same<F, separator_t<char>>::value, F>>
256std::basic_string<char> concat(F&& first, Args&&... rest) {
257 return concat_impl<char>(sep, std::forward<F>(first), std::forward<Args>(rest)...);
258}
259
260// 4. entry point, when there is no separator.
261template <typename CharT = char, typename F, typename... Args,
262 typename = enable_if_t<!std::is_same<F, separator_t<CharT>>::value, F>>
263std::basic_string<CharT> concat(F&& first, Args&&... rest) {
264 return concat_impl<CharT>((const CharT*) nullptr, std::forward<F>(first), std::forward<Args>(rest)...);
265}
266
267// 5. entry point, when the separator is std::endl passed as template argument
268template <std::ostream& sep(std::ostream&), typename CharT = char, typename F, typename... Args,
269 typename = enable_if_t<!std::is_same<F, separator_t<CharT>>::value, F>>
270std::basic_string<CharT> concat(F&& first, Args&&... rest) {
271 return concat_impl<CharT>(sep, std::forward<F>(first), std::forward<Args>(rest)...);
272}
273} // namespace utils
274
275#endif
Param::LoadOption::fromString value("fromFile", Param::LoadOption::fromFile) .export_values()
VARIABLE< kids_complex > S
VARIABLE< kids_real > E
VARIABLE< kids_real > T
constexpr char space[]
Definition concat.h:33
constexpr char endl[]
Definition concat.h:34
constexpr char plus[]
Definition concat.h:36
constexpr char comma[]
Definition concat.h:35
constexpr char none[]
Definition concat.h:32
Definition concat.h:18
constexpr separator_t< CharT > separator(const CharT *s)
Definition concat.h:27
std::basic_string< CharT > concat(const separator_t< CharT > &sep, Args &&... seq)
Definition concat.h:242
constexpr separator_t(const CharT *s) noexcept
Definition concat.h:23
const CharT * sep
Definition concat.h:22