25#include <rocprofiler-sdk/cxx/details/mpl.hpp>
29#include <initializer_list>
43template <
typename... ArgsT>
45consume_args(ArgsT&&...)
57 static constexpr auto index() {
return Idx; }
58 std::string_view delimiter = {};
59 std::string_view prefix = {};
60 std::string_view suffix = {};
63using generic_config = triplet_config<0>;
64using array_config = triplet_config<1>;
65using pair_config = triplet_config<2>;
67struct config : generic_config
69 using format_flags_t = std::ios_base::fmtflags;
70 using base_type = generic_config;
74 config(
const config&) =
default;
75 config(config&&) noexcept = default;
77 config& operator=(const config&) = default;
78 config& operator=(config&&) noexcept = default;
81 config(
std::string_view _delim)
86 config(
const char*
const _delim)
90 config(generic_config _cfg)
94 config(array_config _cfg)
98 config(pair_config _cfg)
102 config(generic_config _generic, array_config _array)
103 : base_type{_generic}
107 config(generic_config _generic, pair_config _pair)
108 : base_type{_generic}
112 config(array_config _array, pair_config _pair)
117 format_flags_t flags = std::ios_base::boolalpha;
118 array_config array = {
", ",
"[",
"]"};
119 pair_config pair = {
", ",
"{",
"}"};
124template <
int TraitT,
typename ArgT>
126join_arg(config _cfg, ArgT&& _v)
128 using arg_type = mpl::basic_identity_t<ArgT>;
130 constexpr bool _is_string_type = mpl::is_string_type<arg_type>::value;
131 constexpr bool _is_iterable = mpl::is_iterable<arg_type>(0);
132 constexpr bool _has_traits_type = mpl::has_traits<arg_type>(0);
133 constexpr bool _has_key_type = mpl::has_key_type<arg_type>(0);
134 constexpr bool _has_value_type = mpl::has_value_type<arg_type>(0);
135 constexpr bool _has_mapped_type = mpl::has_mapped_type<arg_type>(0);
137 if constexpr(_is_string_type)
139 if constexpr(TraitT == QuoteStrings)
141 return std::string{
"\""} + std::string{std::forward<ArgT>(_v)} + std::string{
"\""};
145 return std::forward<ArgT>(_v);
148 else if constexpr(_is_iterable && !_has_traits_type &&
149 (_has_value_type || (_has_key_type && _has_mapped_type)))
151 if constexpr(_has_key_type && _has_mapped_type)
153 std::stringstream _ss{};
154 _ss.setf(_cfg.flags);
155 for(
auto&& itr :
std::forward<ArgT>(_v))
156 _ss << _cfg.array.delimiter << _cfg.pair.prefix << join_arg<TraitT>(_cfg, itr.first)
157 << _cfg.pair.delimiter << join_arg<TraitT>(_cfg, itr.second)
159 auto _ret = _ss.str();
160 auto&& _len = _cfg.array.delimiter.length();
161 return (_ret.length() > _len) ? (std::string{_cfg.array.prefix} + _ret.substr(_len) +
162 std::string{_cfg.array.suffix})
165 else if constexpr(_has_value_type)
167 std::stringstream _ss{};
168 _ss.setf(_cfg.flags);
169 for(
auto&& itr :
std::forward<ArgT>(_v))
170 _ss << _cfg.array.delimiter << join_arg<TraitT>(_cfg, itr);
171 auto _ret = _ss.str();
172 auto&& _len = _cfg.array.delimiter.length();
173 return (_ret.length() > _len) ? (std::string{_cfg.array.prefix} + _ret.substr(_len) +
174 std::string{_cfg.array.suffix})
178 else if constexpr(mpl::supports_ostream<ArgT>(0))
180 return std::forward<ArgT>(_v);
184 static_assert(_is_iterable,
"Type is not iterable");
185 static_assert(!_has_traits_type,
"Type has a traits type");
186 if constexpr(!_has_value_type)
188 static_assert(_has_key_type && _has_mapped_type,
189 "Type must have a key_type and mapped_type if there is no value_type");
193 static_assert(_has_value_type,
194 "Type must have a value_type if there is no key_type and mapped_type");
196 static_assert(std::is_empty<ArgT>::value,
197 "Error! argument type cannot be written to output stream");
200 consume_args(_is_string_type,
209template <
int TraitT = NoQuoteStrings,
typename... Args>
211join(config _cfg, Args&&... _args)
213 static_assert(std::is_trivially_copyable<config>::value,
214 "Error! config is not trivially copyable");
216 std::stringstream _ss{};
217 _ss.setf(_cfg.flags);
218 ((_ss << ((mpl::is_empty(_args)) ? std::string_view{} : std::string_view{_cfg.delimiter})
219 << impl::join_arg<TraitT>(_cfg, _args)),
221 auto _ret = _ss.str();
222 auto&& _len = _cfg.delimiter.length();
224 strncmp(std::string_view{_ret}.data(), std::string_view{_cfg.delimiter}.data(), _len) == 0;
225 return (_ret.length() > _len) ? (std::string{_cfg.prefix} +
226 ((_cmp) ? _ret.substr(_len) : _ret) + std::string{_cfg.suffix})
230template <
int TraitT = NoQuoteStrings,
typename... Args>
232join(std::array<std::string_view, 3>&& _delims, Args&&... _args)
234 auto _cfg = config{};
235 _cfg.delimiter = _delims.at(0);
236 _cfg.prefix = _delims.at(1);
237 _cfg.suffix = _delims.at(2);
238 return join(_cfg, std::forward<Args>(_args)...);
241template <
int TraitT = NoQuoteStrings,
244 std::enable_if_t<!mpl::is_basic_same<config, DelimT>::value,
int> = 0>
246join(DelimT&& _delim, Args&&... _args)
248 using delim_type = mpl::basic_identity_t<DelimT>;
250 if constexpr(std::is_constructible<config, delim_type>::value)
252 auto _cfg = config{std::forward<DelimT>(_delim)};
253 return join<TraitT>(_cfg, std::forward<Args>(_args)...);
255 else if constexpr(std::is_same<delim_type, char>::value)
257 auto _cfg = config{};
258 const char _delim_c[2] = {_delim,
'\0'};
259 _cfg.delimiter = _delim_c;
260 return join<TraitT>(_cfg, std::forward<Args>(_args)...);
264 auto _cfg = config{};
265 _cfg.delimiter = std::string_view{_delim};
266 return join<TraitT>(_cfg, std::forward<Args>(_args)...);
270template <
typename ArgT>
274 auto _cfg = config{};
277 return join(_cfg, std::forward<ArgT>(_arg));