blob: 75661a298448d5eac8f8e6b631a72cc125b5d0a9 [file] [log] [blame]
Adrien Béraud612b55b2023-05-29 10:42:04 -04001/*
2 * Copyright (C) 2004-2023 Savoir-faire Linux Inc.
3 *
4 * Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
5 * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22#pragma once
23
24#include <cstdint>
25#include <string>
26#include <vector>
27#include <set>
28#include <algorithm>
29#include <regex>
30#include <iterator>
31#include <charconv>
32
33#ifdef _WIN32
34#include <WTypes.h>
35#endif
36
37namespace jami {
38
39constexpr static const char TRUE_STR[] = "true";
40constexpr static const char FALSE_STR[] = "false";
41
42constexpr static const char*
43bool_to_str(bool b) noexcept
44{
45 return b ? TRUE_STR : FALSE_STR;
46}
47
48std::string to_string(double value);
49
50#ifdef _WIN32
51std::wstring to_wstring(const std::string& str, int codePage = CP_UTF8);
52std::string to_string(const std::wstring& wstr, int codePage = CP_UTF8);
53#endif
54
55std::string to_hex_string(uint64_t id);
56uint64_t from_hex_string(const std::string& str);
57
58template<typename T>
59T
60to_int(std::string_view str, T defaultValue)
61{
62 T result;
63 auto [p, ec] = std::from_chars(str.data(), str.data()+str.size(), result);
64 if (ec == std::errc())
65 return result;
66 else
67 return defaultValue;
68}
69
70template<typename T>
71T
72to_int(std::string_view str)
73{
74 T result;
75 auto [p, ec] = std::from_chars(str.data(), str.data()+str.size(), result);
76 if (ec == std::errc())
77 return result;
78 if (ec == std::errc::invalid_argument)
79 throw std::invalid_argument("Can't parse integer: invalid_argument");
80 else if (ec == std::errc::result_out_of_range)
81 throw std::out_of_range("Can't parse integer: out of range");
82 throw std::system_error(std::make_error_code(ec));
83}
84
85static inline int
86stoi(const std::string& str)
87{
88 return std::stoi(str);
89}
90
91static inline double
92stod(const std::string& str)
93{
94 return std::stod(str);
95}
96
97template<typename... Args>
98std::string concat(Args &&... args){
99 static_assert((std::is_constructible_v<std::string_view, Args&&> && ...));
100 std::string s;
101 s.reserve((std::string_view{ args }.size() + ...));
102 (s.append(std::forward<Args>(args)), ...);
103 return s;
104}
105
106std::string_view trim(std::string_view s);
107
108/**
109 * Split a string_view with an API similar to std::getline.
110 * @param str The input string stream to iterate on, trimed of line during iteration.
111 * @param line The output substring.
112 * @param delim The delimiter.
113 * @return True if line was set, false if the end of the input was reached.
114 */
115inline bool
116getline_full(std::string_view& str, std::string_view& line, char delim = '\n')
117{
118 if (str.empty())
119 return false;
120 auto pos = str.find(delim);
121 line = str.substr(0, pos);
122 str.remove_prefix(pos < str.size() ? pos + 1 : str.size());
123 return true;
124}
125
126/**
127 * Similar to @getline_full but skips empty results.
128 */
129inline bool
130getline(std::string_view& str, std::string_view& line, char delim = '\n')
131{
132 do {
133 if (!getline_full(str, line, delim))
134 return false;
135 } while (line.empty());
136 return true;
137}
138
139inline std::vector<std::string_view>
140split_string(std::string_view str, char delim)
141{
142 std::vector<std::string_view> output;
143 for (auto first = str.data(), second = str.data(), last = first + str.size();
144 second != last && first != last;
145 first = second + 1) {
146 second = std::find(first, last, delim);
147 if (first != second)
148 output.emplace_back(first, second - first);
149 }
150 return output;
151}
152
153inline std::vector<std::string_view>
154split_string(std::string_view str, std::string_view delims = " ")
155{
156 std::vector<std::string_view> output;
157 for (auto first = str.data(), second = str.data(), last = first + str.size();
158 second != last && first != last;
159 first = second + 1) {
160 second = std::find_first_of(first, last, std::cbegin(delims), std::cend(delims));
161 if (first != second)
162 output.emplace_back(first, second - first);
163 }
164 return output;
165}
166
167std::vector<unsigned> split_string_to_unsigned(std::string_view s, char sep);
168
169void string_replace(std::string& str, const std::string& from, const std::string& to);
170
171std::string_view string_remove_suffix(std::string_view str, char separator);
172
173std::string string_join(const std::set<std::string>& set, std::string_view separator = "/");
174
175std::set<std::string> string_split_set(std::string& str, std::string_view separator = "/");
176
177} // namespace jami
178
179/*
180// Add string operators missing from standard
181// see https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/1RcShRhrmRc
182namespace std {
183inline string
184operator+(const string& s, const string_view& sv)
185{
186 return jami::concat(s, sv);
187}
188inline string
189operator+(const string_view& sv, const string& s)
190{
191 return jami::concat(sv, s);
192}
193using svmatch = match_results<string_view::const_iterator>;
194using svsub_match = sub_match<string_view::const_iterator>;
195constexpr string_view svsub_match_view(const svsub_match& submatch) noexcept {
196 return string_view(&*submatch.first, submatch.second - submatch.first);
197}
198inline bool
199regex_match(string_view sv,
200 svmatch& m,
201 const regex& e,
202 regex_constants::match_flag_type flags = regex_constants::match_default)
203{
204 return regex_match(sv.begin(), sv.end(), m, e, flags);
205}
206inline bool
207regex_match(string_view sv,
208 const regex& e,
209 regex_constants::match_flag_type flags = regex_constants::match_default)
210{
211 return regex_match(sv.begin(), sv.end(), e, flags);
212}
213inline bool
214regex_search(string_view sv,
215 svmatch& m,
216 const regex& e,
217 regex_constants::match_flag_type flags = regex_constants::match_default)
218{
219 return regex_search(sv.begin(), sv.end(), m, e, flags);
220}
221} // namespace std
222*/