Ring Daemon
Loading...
Searching...
No Matches
string_utils.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17#pragma once
18
19#include <cstdint>
20#include <string>
21#include <vector>
22#include <set>
23#include <algorithm>
24#include <regex>
25#include <iterator>
26#include <charconv>
27#include <string_view>
28
29#ifdef _WIN32
30#include <WTypes.h>
31#endif
32#if defined(__APPLE__)
33#include <TargetConditionals.h>
34#endif
35
36namespace jami {
37
38constexpr static const char TRUE_STR[] = "true";
39constexpr static const char FALSE_STR[] = "false";
40
41constexpr static const char*
42bool_to_str(bool b) noexcept
43{
44 return b ? TRUE_STR : FALSE_STR;
45}
46
47const std::string& userAgent();
48
49constexpr inline std::string_view
51{
52 using namespace std::literals;
53#ifdef __linux__
54#if defined(__ANDROID__)
55 return "Android"sv;
56#else
57 return "Linux"sv;
58#endif
59#elif defined(_WIN32)
60 return "Windows"sv;
61#elif defined(__APPLE__)
62#if TARGET_OS_IOS
63 return "iOS"sv;
64#else
65 return "macOS"sv;
66#endif
67#else
68 return "unknown"sv;
69#endif
70}
71
72constexpr inline std::string_view
74{
75 using namespace std::literals;
76#if defined(__x86_64__) || defined(_M_X64)
77 return "x86_64"sv;
78#elif defined(__i386__) || defined(_M_IX86)
79 return "x86"sv;
80#elif defined(__aarch64__) || defined(_M_ARM64)
81 return "arm64"sv;
82#elif defined(__arm__) || defined(_M_ARM)
83 return "arm"sv;
84#else
85 return "unknown"sv;
86#endif
87}
88
89std::string to_string(double value);
90
91#ifdef _WIN32
92std::wstring to_wstring(const std::string& str, int codePage = CP_UTF8);
93std::string to_string(const std::wstring& wstr, int codePage = CP_UTF8);
94#endif
95
96std::string to_hex_string(uint64_t id);
97uint64_t from_hex_string(const std::string& str);
98
99template<typename T>
100inline T
101to_int(std::string_view str, T defaultValue)
102{
103 T result;
104 auto [p, ec] = std::from_chars(str.data(), str.data() + str.size(), result);
105 if (ec == std::errc())
106 return result;
107 else
108 return defaultValue;
109}
110
111template<typename T>
112T
113to_int(std::string_view str)
114{
115 T result;
116 auto [p, ec] = std::from_chars(str.data(), str.data() + str.size(), result);
117 if (ec == std::errc())
118 return result;
119 if (ec == std::errc::invalid_argument)
120 throw std::invalid_argument("Unable to parse integer: invalid_argument");
121 else if (ec == std::errc::result_out_of_range)
122 throw std::out_of_range("Unable to parse integer: out of range");
123 throw std::system_error(std::make_error_code(ec));
124}
125
126template<typename T>
127T
128to_enum(std::string_view str, T defaultValue)
129{
130 return static_cast<T>(to_int<std::underlying_type_t<T>>(str, static_cast<std::underlying_type_t<T>>(defaultValue)));
131}
132
133template<typename T>
134T
135to_enum(std::string_view str)
136{
137 return static_cast<T>(to_int<std::underlying_type_t<T>>(str));
138}
139
140static inline bool
141starts_with(std::string_view str, std::string_view prefix)
142{
143 return str.size() >= prefix.size() && str.compare(0, prefix.size(), prefix) == 0;
144}
145
146template<typename... Args>
147std::string
149{
150 static_assert((std::is_constructible_v<std::string_view, Args&&> && ...));
151 std::string s;
152 s.reserve((std::string_view {args}.size() + ...));
153 (s.append(std::forward<Args>(args)), ...);
154 return s;
155}
156
157std::string_view trim(std::string_view s);
158
166inline bool
167getline_full(std::string_view& str, std::string_view& line, char delim = '\n')
168{
169 if (str.empty())
170 return false;
171 auto pos = str.find(delim);
172 line = str.substr(0, pos);
173 str.remove_prefix(pos < str.size() ? pos + 1 : str.size());
174 return true;
175}
176
180inline bool
181getline(std::string_view& str, std::string_view& line, char delim = '\n')
182{
183 do {
184 if (!getline_full(str, line, delim))
185 return false;
186 } while (line.empty());
187 return true;
188}
189
190inline std::vector<std::string_view>
191split_string(std::string_view str, char delim)
192{
193 std::vector<std::string_view> output;
194 for (auto first = str.data(), second = str.data(), last = first + str.size(); second != last && first != last;
195 first = second + 1) {
196 second = std::find(first, last, delim);
197 if (first != second)
198 output.emplace_back(first, second - first);
199 }
200 return output;
201}
202
203inline std::vector<std::string_view>
204split_string(std::string_view str, std::string_view delims = " ")
205{
206 std::vector<std::string_view> output;
207 for (auto first = str.data(), second = str.data(), last = first + str.size(); second != last && first != last;
208 first = second + 1) {
209 second = std::find_first_of(first, last, std::cbegin(delims), std::cend(delims));
210 if (first != second)
211 output.emplace_back(first, second - first);
212 }
213 return output;
214}
215
216std::vector<unsigned> split_string_to_unsigned(std::string_view s, char sep);
217
218void string_replace(std::string& str, const std::string& from, const std::string& to);
219
220std::string_view string_remove_suffix(std::string_view str, char separator);
221
222std::string string_join(const std::set<std::string>& set, std::string_view separator = "/");
223
224std::set<std::string> string_split_set(std::string& str, std::string_view separator = "/");
225
232std::string urlEncode(std::string_view input);
233
234} // namespace jami
235
236// Add string operators crucially missing from standard
237// see https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/1RcShRhrmRc
238namespace std {
239inline string
240operator+(const string& s, const string_view& sv)
241{
242 return jami::concat(s, sv);
243}
244inline string
245operator+(const string_view& sv, const string& s)
246{
247 return jami::concat(sv, s);
248}
249using svmatch = match_results<string_view::const_iterator>;
250using svsub_match = sub_match<string_view::const_iterator>;
251constexpr string_view
252svsub_match_view(const svsub_match& submatch) noexcept
253{
254 return string_view(&*submatch.first, submatch.second - submatch.first);
255}
256inline bool
257regex_match(string_view sv,
258 svmatch& m,
259 const regex& e,
260 regex_constants::match_flag_type flags = regex_constants::match_default)
261{
262 return regex_match(sv.begin(), sv.end(), m, e, flags);
263}
264inline bool
265regex_match(string_view sv, const regex& e, regex_constants::match_flag_type flags = regex_constants::match_default)
266{
267 return regex_match(sv.begin(), sv.end(), e, flags);
268}
269inline bool
270regex_search(string_view sv,
271 svmatch& m,
272 const regex& e,
273 regex_constants::match_flag_type flags = regex_constants::match_default)
274{
275 return regex_search(sv.begin(), sv.end(), m, e, flags);
276}
277} // namespace std
T to_int(std::string_view str, T defaultValue)
static constexpr const char TRUE_STR[]
constexpr std::string_view platform()
void emitSignal(Args... args)
Definition jami_signal.h:64
std::string string_join(const std::set< std::string > &set, std::string_view separator)
std::string to_hex_string(uint64_t id)
static constexpr const char * bool_to_str(bool b) noexcept
std::string concat(Args &&... args)
std::string to_string(double value)
bool getline(std::string_view &str, std::string_view &line, char delim='\n')
Similar to @getline_full but skips empty results.
const std::string & userAgent()
std::vector< unsigned > split_string_to_unsigned(std::string_view str, char delim)
uint64_t from_hex_string(const std::string &str)
std::string_view string_remove_suffix(std::string_view str, char separator)
static constexpr const char FALSE_STR[]
std::string_view trim(std::string_view s)
std::string urlEncode(std::string_view input)
Percent-encode a string according to RFC 3986 unreserved characters.
T to_enum(std::string_view str, T defaultValue)
static bool starts_with(std::string_view str, std::string_view prefix)
bool getline_full(std::string_view &str, std::string_view &line, char delim='\n')
Split a string_view with an API similar to std::getline.
std::vector< std::string_view > split_string(std::string_view str, char delim)
std::set< std::string > string_split_set(std::string &str, std::string_view separator)
void string_replace(std::string &str, const std::string &from, const std::string &to)
constexpr std::string_view arch()
bool regex_match(string_view sv, svmatch &m, const regex &e, regex_constants::match_flag_type flags=regex_constants::match_default)
match_results< string_view::const_iterator > svmatch
sub_match< string_view::const_iterator > svsub_match
constexpr string_view svsub_match_view(const svsub_match &submatch) noexcept
bool regex_search(string_view sv, svmatch &m, const regex &e, regex_constants::match_flag_type flags=regex_constants::match_default)
string operator+(const string &s, const string_view &sv)