]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/strtol.h
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / common / strtol.h
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15#ifndef CEPH_COMMON_STRTOL_H
16#define CEPH_COMMON_STRTOL_H
17
f91f0fd5
TL
18#if __has_include(<charconv>)
19#include <charconv>
20#endif // __has_include(<charconv>)
21#include <cinttypes>
22#include <cstdlib>
23#include <optional>
7c673cae 24#include <string>
f91f0fd5
TL
25#include <string_view>
26#include <system_error>
27#include <type_traits>
28
29
30namespace ceph {
31#if __has_include(<charconv>)
32// Wrappers around std::from_chars.
33//
34// Why do we want this instead of strtol and friends? Because the
35// string doesn't have to be NUL-terminated! (Also, for a lot of
36// purposes, just putting a string_view in and getting an optional out
37// is friendly.)
38//
39// Returns the found number on success. Returns an empty optional on
40// failure OR on trailing characters.
41template<typename T>
42auto parse(std::string_view s, int base = 10)
43 -> std::enable_if_t<std::is_integral_v<T>, std::optional<T>>
44{
45 T t;
46 auto r = std::from_chars(s.data(), s.data() + s.size(), t, base);
47 if ((r.ec != std::errc{}) || (r.ptr != s.data() + s.size())) {
48 return std::nullopt;
49 }
50 return t;
51}
52
53// As above, but succeed on trailing characters and trim the supplied
54// string_view to remove the parsed number. Set the supplied
55// string_view to empty if it ends with the number.
56template<typename T>
57auto consume(std::string_view& s, int base = 10)
58 -> std::enable_if_t<std::is_integral_v<T>, std::optional<T>>
59{
60 T t;
61 auto r = std::from_chars(s.data(), s.data() + s.size(), t, base);
62 if (r.ec != std::errc{})
63 return std::nullopt;
64
65 if (r.ptr == s.data() + s.size()) {
66 s = std::string_view{};
67 } else {
68 s.remove_prefix(r.ptr - s.data());
69 }
70 return t;
71}
72// Sadly GCC is missing the floating point versions.
73#else // __has_include(<charconv>)
74template<typename T>
75auto parse(std::string_view sv, int base = 10)
76 -> std::enable_if_t<std::is_integral_v<T>, std::optional<T>>
77{
78 std::string s(sv);
79 char* end = nullptr;
80 std::conditional_t<std::is_signed_v<T>, std::intmax_t, std::uintmax_t> v;
81 errno = 0;
82
83 if (s.size() > 0 && std::isspace(s[0]))
84 return std::nullopt;
85
86 if constexpr (std::is_signed_v<T>) {
87 v = std::strtoimax(s.data(), &end, base);
88 } else {
89 if (s.size() > 0 && s[0] == '-')
90 return std::nullopt;
91 v = std::strtoumax(s.data(), &end, base);
92 }
93 if (errno != 0 ||
94 end != s.data() + s.size() ||
95 v > std::numeric_limits<T>::max() ||
96 v < std::numeric_limits<T>::min())
97 return std::nullopt;
98 return static_cast<T>(v);
99}
100
101template<typename T>
102auto consume(std::string_view& sv, int base = 10)
103 -> std::enable_if_t<std::is_integral_v<T>, std::optional<T>>
104{
105 std::string s(sv);
106 char* end = nullptr;
107 std::conditional_t<std::is_signed_v<T>, std::intmax_t, std::uintmax_t> v;
108 errno = 0;
109
110 if (s.size() > 0 && std::isspace(s[0]))
111 return std::nullopt;
112
113 if constexpr (std::is_signed_v<T>) {
114 v = std::strtoimax(s.data(), &end, base);
115 } else {
116 if (s.size() > 0 && s[0] == '-')
117 return std::nullopt;
118 v = std::strtoumax(s.data(), &end, base);
119 }
120 if (errno != 0 ||
121 end == s.data() ||
122 v > std::numeric_limits<T>::max() ||
123 v < std::numeric_limits<T>::min())
124 return std::nullopt;
125 if (end == s.data() + s.size()) {
126 sv = std::string_view{};
127 } else {
128 sv.remove_prefix(end - s.data());
129 }
130 return static_cast<T>(v);
7c673cae 131}
f91f0fd5
TL
132#endif // __has_include(<charconv>)
133} // namespace ceph
7c673cae 134
f67539c2
TL
135bool strict_strtob(const char* str, std::string *err);
136
137long long strict_strtoll(std::string_view str, int base, std::string *err);
7c673cae
FG
138long long strict_strtoll(const char *str, int base, std::string *err);
139
f67539c2 140int strict_strtol(std::string_view str, int base, std::string *err);
7c673cae
FG
141int strict_strtol(const char *str, int base, std::string *err);
142
143double strict_strtod(const char *str, std::string *err);
144
145float strict_strtof(const char *str, std::string *err);
146
1adf2230
AA
147uint64_t strict_iecstrtoll(const char *str, std::string *err);
148
149template<typename T>
150T strict_iec_cast(const char *str, std::string *err);
151
7c673cae
FG
152uint64_t strict_sistrtoll(const char *str, std::string *err);
153
154template<typename T>
155T strict_si_cast(const char *str, std::string *err);
156
157/* On enter buf points to the end of the buffer, e.g. where the least
158 * significant digit of the input number will be printed. Returns pointer to
159 * where the most significant digit were printed, including zero padding.
160 * Does NOT add zero at the end of buffer, this is responsibility of the caller.
161 */
162template<typename T, const unsigned base = 10, const unsigned width = 1>
163static inline
164char* ritoa(T u, char *buf)
165{
f67539c2 166 static_assert(std::is_unsigned_v<T>, "signed types are not supported");
7c673cae
FG
167 static_assert(base <= 16, "extend character map below to support higher bases");
168 unsigned digits = 0;
169 while (u) {
170 *--buf = "0123456789abcdef"[u % base];
171 u /= base;
172 digits++;
173 }
174 while (digits++ < width)
175 *--buf = '0';
176 return buf;
177}
178
179#endif