Ring Daemon 16.0.0
Loading...
Searching...
No Matches
string_utils.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2025 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 using namespace std::literals;
52#ifdef __linux__
53 #if defined(__ANDROID__)
54 return "Android"sv;
55 #else
56 return "Linux"sv;
57 #endif
58#elif defined(_WIN32)
59 return "Windows"sv;
60#elif defined(__APPLE__)
61 #if TARGET_OS_IOS
62 return "iOS"sv;
63 #else
64 return "macOS"sv;
65 #endif
66#else
67 return "unknown"sv;
68#endif
69}
70
71constexpr inline std::string_view
73 using namespace std::literals;
74#if defined(__x86_64__) || defined(_M_X64)
75 return "x86_64"sv;
76#elif defined(__i386__) || defined(_M_IX86)
77 return "x86"sv;
78#elif defined(__aarch64__) || defined(_M_ARM64)
79 return "arm64"sv;
80#elif defined(__arm__) || defined(_M_ARM)
81 return "arm"sv;
82#else
83 return "unknown"sv;
84#endif
85}
86
87std::string to_string(double value);
88
89#ifdef _WIN32
90std::wstring to_wstring(const std::string& str, int codePage = CP_UTF8);
91std::string to_string(const std::wstring& wstr, int codePage = CP_UTF8);
92#endif
93
94std::string to_hex_string(uint64_t id);
95uint64_t from_hex_string(const std::string& str);
96
97template<typename T>
98inline T
99to_int(std::string_view str, T defaultValue)
100{
101 T result;
102 auto [p, ec] = std::from_chars(str.data(), str.data()+str.size(), result);
103 if (ec == std::errc())
104 return result;
105 else
106 return defaultValue;
107}
108
109template<typename T>
110T
111to_int(std::string_view str)
112{
113 T result;
114 auto [p, ec] = std::from_chars(str.data(), str.data()+str.size(), result);
115 if (ec == std::errc())
116 return result;
117 if (ec == std::errc::invalid_argument)
118 throw std::invalid_argument("Unable to parse integer: invalid_argument");
119 else if (ec == std::errc::result_out_of_range)
120 throw std::out_of_range("Unable to parse integer: out of range");
121 throw std::system_error(std::make_error_code(ec));
122}
123
124static inline bool
125starts_with(std::string_view str, std::string_view prefix)
126{
127 return str.size() >= prefix.size() && str.compare(0, prefix.size(), prefix) == 0;
128}
129
130template<typename... Args>
131std::string concat(Args &&... args){
132 static_assert((std::is_constructible_v<std::string_view, Args&&> && ...));
133 std::string s;
134 s.reserve((std::string_view{ args }.size() + ...));
135 (s.append(std::forward<Args>(args)), ...);
136 return s;
137}
138
139std::string_view trim(std::string_view s);
140
148inline bool
149getline_full(std::string_view& str, std::string_view& line, char delim = '\n')
150{
151 if (str.empty())
152 return false;
153 auto pos = str.find(delim);
154 line = str.substr(0, pos);
155 str.remove_prefix(pos < str.size() ? pos + 1 : str.size());
156 return true;
157}
158
162inline bool
163getline(std::string_view& str, std::string_view& line, char delim = '\n')
164{
165 do {
166 if (!getline_full(str, line, delim))
167 return false;
168 } while (line.empty());
169 return true;
170}
171
172inline std::vector<std::string_view>
173split_string(std::string_view str, char delim)
174{
175 std::vector<std::string_view> output;
176 for (auto first = str.data(), second = str.data(), last = first + str.size();
177 second != last && first != last;
178 first = second + 1) {
179 second = std::find(first, last, delim);
180 if (first != second)
181 output.emplace_back(first, second - first);
182 }
183 return output;
184}
185
186inline std::vector<std::string_view>
187split_string(std::string_view str, std::string_view delims = " ")
188{
189 std::vector<std::string_view> output;
190 for (auto first = str.data(), second = str.data(), last = first + str.size();
191 second != last && first != last;
192 first = second + 1) {
193 second = std::find_first_of(first, last, std::cbegin(delims), std::cend(delims));
194 if (first != second)
195 output.emplace_back(first, second - first);
196 }
197 return output;
198}
199
200std::vector<unsigned> split_string_to_unsigned(std::string_view s, char sep);
201
202void string_replace(std::string& str, const std::string& from, const std::string& to);
203
204std::string_view string_remove_suffix(std::string_view str, char separator);
205
206std::string string_join(const std::set<std::string>& set, std::string_view separator = "/");
207
208std::set<std::string> string_split_set(std::string& str, std::string_view separator = "/");
209
216std::string urlEncode(std::string_view input);
217
218} // namespace jami
219
220// Add string operators crucially missing from standard
221// see https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/1RcShRhrmRc
222namespace std {
223inline string
224operator+(const string& s, const string_view& sv)
225{
226 return jami::concat(s, sv);
227}
228inline string
229operator+(const string_view& sv, const string& s)
230{
231 return jami::concat(sv, s);
232}
233using svmatch = match_results<string_view::const_iterator>;
234using svsub_match = sub_match<string_view::const_iterator>;
235constexpr string_view svsub_match_view(const svsub_match& submatch) noexcept {
236 return string_view(&*submatch.first, submatch.second - submatch.first);
237}
238inline bool
239regex_match(string_view sv,
240 svmatch& m,
241 const regex& e,
242 regex_constants::match_flag_type flags = regex_constants::match_default)
243{
244 return regex_match(sv.begin(), sv.end(), m, e, flags);
245}
246inline bool
247regex_match(string_view sv,
248 const regex& e,
249 regex_constants::match_flag_type flags = regex_constants::match_default)
250{
251 return regex_match(sv.begin(), sv.end(), e, flags);
252}
253inline bool
254regex_search(string_view sv,
255 svmatch& m,
256 const regex& e,
257 regex_constants::match_flag_type flags = regex_constants::match_default)
258{
259 return regex_search(sv.begin(), sv.end(), m, e, flags);
260}
261} // 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 ring_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.
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)