// Copyright (C) 2021-2023 Joel Rosdahl and other contributors // // See doc/AUTHORS.adoc for a complete list of contributors. // // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3 of the License, or (at your option) // any later version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for // more details. // // You should have received a copy of the GNU General Public License along with // this program; if not, write to the Free Software Foundation, Inc., 51 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #pragma once #include #include #include #include // for mode_t #include #include #include #include #include #include namespace util { // --- Interface --- enum class SizeUnitPrefixType { binary, decimal }; // Return true if `suffix` is a suffix of `string`. bool ends_with(std::string_view string, std::string_view suffix); // Format `diff` as a human-readable string. std::string format_human_readable_diff(int64_t diff, SizeUnitPrefixType prefix_type); // Format `size` as a human-readable string. std::string format_human_readable_size(uint64_t size, SizeUnitPrefixType prefix_type); // Join stringified elements of `container` delimited by `delimiter` into a // string. There must exist an `std::string to_string(T::value_type)` function. template std::string join(const T& container, const std::string_view delimiter); // Join stringified elements between input iterators `begin` and `end` delimited // by `delimiter` into a string. There must exist an `std::string // to_string(T::value_type)` function. template std::string join(const T& begin, const T& end, const std::string_view delimiter); // Parse a string into a double. // // Returns an error string if `value` cannot be parsed as a double. nonstd::expected parse_double(const std::string& value); // Parse a string into a signed integer. // // Returns an error string if `value` cannot be parsed as an int64_t or if the // value falls out of the range [`min_value`, `max_value`]. `min_value` and // `max_value` default to min and max values of int64_t. `description` is // included in the error message for range violations. nonstd::expected parse_signed(std::string_view value, std::optional min_value = std::nullopt, std::optional max_value = std::nullopt, std::string_view description = "integer"); // Parse a "size value", i.e. a string that can end in k, M, G, T (10-based // suffixes) or Ki, Mi, Gi, Ti (2-based suffixes). For backward compatibility, K // is also recognized as a synonym of k. nonstd::expected, std::string> parse_size(const std::string& value); // Parse `value` (an octal integer). nonstd::expected parse_umask(std::string_view value); // Parse a string into an unsigned integer. // // Returns an error string if `value` cannot be parsed as an uint64_t with base // `base`, or if the value falls out of the range [`min_value`, `max_value`]. // `min_value` and `max_value` default to min and max values of uint64_t. // `description` is included in the error message for range violations. nonstd::expected parse_unsigned(std::string_view value, std::optional min_value = std::nullopt, std::optional max_value = std::nullopt, std::string_view description = "integer", int base = 10); // Percent-decode[1] `string`. // // [1]: https://en.wikipedia.org/wiki/Percent-encoding nonstd::expected percent_decode(std::string_view string); // Replace the all occurrences of `from` to `to` in `string`. std::string replace_all(std::string_view string, std::string_view from, std::string_view to); // Replace the first occurrence of `from` to `to` in `string`. std::string replace_first(std::string_view string, std::string_view from, std::string_view to); // Split `string` into two parts using `split_char` as the delimiter. The second // part will be `nullopt` if there is no `split_char` in `string.` std::pair> split_once(const char* string, char split_char); std::pair> split_once(std::string&& string, char split_char); std::pair> split_once(std::string_view string, char split_char); // Return true if `prefix` is a prefix of `string`. bool starts_with(const char* string, std::string_view prefix); // Return true if `prefix` is a prefix of `string`. bool starts_with(std::string_view string, std::string_view prefix); // Strip whitespace from left and right side of a string. [[nodiscard]] std::string strip_whitespace(std::string_view string); // Convert `value` to a `nonstd::span`. nonstd::span to_span(std::string_view value); // Convert `value` to a string. This function is used when joining // `std::string`s with `util::join`. template std::string to_string(const T& value); // Convert `data` to a `std::string_view`. std::string_view to_string_view(nonstd::span data); // --- Inline implementations --- inline bool ends_with(const std::string_view string, const std::string_view suffix) { return string.length() >= suffix.length() && string.substr(string.length() - suffix.length()) == suffix; } template inline std::string join(const T& container, const std::string_view delimiter) { return join(container.begin(), container.end(), delimiter); } template inline std::string join(const T& begin, const T& end, const std::string_view delimiter) { std::string result; for (auto it = begin; it != end; ++it) { if (it != begin) { result.append(delimiter.data(), delimiter.length()); } result += to_string(*it); } return result; } inline bool starts_with(const char* const string, const std::string_view prefix) { // Optimized version of starts_with(string_view, string_view): avoid computing // the length of the string argument. return std::strncmp(string, prefix.data(), prefix.length()) == 0; } inline bool starts_with(const std::string_view string, const std::string_view prefix) { return string.substr(0, prefix.size()) == prefix; } inline nonstd::span to_span(std::string_view data) { return nonstd::span( reinterpret_cast(data.data()), data.size()); } template inline std::string to_string(const T& t) { using std::to_string; return to_string(std::forward(t)); } template<> inline std::string to_string(const std::string& string) { return std::string(string); } template<> inline std::string to_string(const std::string_view& sv) { return std::string(sv); } template<> inline std::string to_string(const nonstd::span& bytes) { return std::string(to_string_view(bytes)); } template<> inline std::string to_string(const util::Bytes& bytes) { return std::string(to_string_view(bytes)); } inline std::string_view to_string_view(nonstd::span data) { return std::string_view(reinterpret_cast(data.data()), data.size()); } } // namespace util