template <typename char_type, typename Size, Size max_size, bool NulTerminate = true>
class basic_sstring;
+#ifdef SEASTAR_SSTRING
using sstring = basic_sstring<char, uint32_t, 15>;
-
-template <typename string_type = sstring, typename T>
-inline string_type to_sstring(T value);
+#else
+using sstring = std::string;
+#endif
+
+namespace internal {
+[[noreturn]] void throw_bad_alloc();
+[[noreturn]] void throw_sstring_overflow();
+[[noreturn]] void throw_sstring_out_of_range();
+}
template <typename char_type, typename Size, Size max_size, bool NulTerminate>
class basic_sstring {
bool is_external() const noexcept {
return !is_internal();
}
- const char_type* str() const {
+ const char_type* str() const noexcept {
return is_internal() ? u.internal.str : u.external.str;
}
- char_type* str() {
+ char_type* str() noexcept {
return is_internal() ? u.internal.str : u.external.str;
}
- template <typename string_type, typename T>
- static inline string_type to_sstring_sprintf(T value, const char* fmt) {
- char tmp[sizeof(value) * 3 + 2];
- auto len = std::sprintf(tmp, fmt, value);
- using ch_type = typename string_type::value_type;
- return string_type(reinterpret_cast<ch_type*>(tmp), len);
- }
-
- template <typename string_type>
- static inline string_type to_sstring(int value) {
- return to_sstring_sprintf<string_type>(value, "%d");
- }
-
- template <typename string_type>
- static inline string_type to_sstring(unsigned value) {
- return to_sstring_sprintf<string_type>(value, "%u");
- }
-
- template <typename string_type>
- static inline string_type to_sstring(long value) {
- return to_sstring_sprintf<string_type>(value, "%ld");
- }
-
- template <typename string_type>
- static inline string_type to_sstring(unsigned long value) {
- return to_sstring_sprintf<string_type>(value, "%lu");
- }
-
- template <typename string_type>
- static inline string_type to_sstring(long long value) {
- return to_sstring_sprintf<string_type>(value, "%lld");
- }
-
- template <typename string_type>
- static inline string_type to_sstring(unsigned long long value) {
- return to_sstring_sprintf<string_type>(value, "%llu");
- }
-
- template <typename string_type>
- static inline string_type to_sstring(float value) {
- return to_sstring_sprintf<string_type>(value, "%g");
- }
-
- template <typename string_type>
- static inline string_type to_sstring(double value) {
- return to_sstring_sprintf<string_type>(value, "%g");
- }
-
- template <typename string_type>
- static inline string_type to_sstring(long double value) {
- return to_sstring_sprintf<string_type>(value, "%Lg");
- }
-
- template <typename string_type>
- static inline string_type to_sstring(const char* value) {
- return string_type(value);
- }
-
- template <typename string_type>
- static inline string_type to_sstring(sstring value) {
- return value;
- }
-
- template <typename string_type>
- static inline string_type to_sstring(const temporary_buffer<char>& buf) {
- return string_type(buf.get(), buf.size());
- }
public:
using value_type = char_type;
using traits_type = std::char_traits<char_type>;
u.internal.size = -1;
u.external.str = reinterpret_cast<char_type*>(std::malloc(x.u.external.size + padding()));
if (!u.external.str) {
- throw std::bad_alloc();
+ internal::throw_bad_alloc();
}
std::copy(x.u.external.str, x.u.external.str + x.u.external.size + padding(), u.external.str);
u.external.size = x.u.external.size;
}
basic_sstring(initialized_later, size_t size) {
if (size_type(size) != size) {
- throw std::overflow_error("sstring overflow");
+ internal::throw_sstring_overflow();
}
if (size + padding() <= sizeof(u.internal.str)) {
if (NulTerminate) {
u.internal.size = -1;
u.external.str = reinterpret_cast<char_type*>(std::malloc(size + padding()));
if (!u.external.str) {
- throw std::bad_alloc();
+ internal::throw_bad_alloc();
}
u.external.size = size;
if (NulTerminate) {
}
basic_sstring(const char_type* x, size_t size) {
if (size_type(size) != size) {
- throw std::overflow_error("sstring overflow");
+ internal::throw_sstring_overflow();
}
if (size + padding() <= sizeof(u.internal.str)) {
std::copy(x, x + size, u.internal.str);
u.internal.size = -1;
u.external.str = reinterpret_cast<char_type*>(std::malloc(size + padding()));
if (!u.external.str) {
- throw std::bad_alloc();
+ internal::throw_bad_alloc();
}
u.external.size = size;
std::copy(x, x + size, u.external.str);
: basic_sstring(initialized_later(), std::distance(first, last)) {
std::copy(first, last, begin());
}
- explicit basic_sstring(compat::basic_string_view<char_type, traits_type> v)
+ explicit basic_sstring(std::basic_string_view<char_type, traits_type> v)
: basic_sstring(v.data(), v.size()) {
}
~basic_sstring() noexcept {
}
basic_sstring& operator=(basic_sstring&& x) noexcept {
if (this != &x) {
- swap(x);
- x.reset();
+ this->~basic_sstring();
+ new (this) basic_sstring(std::move(x));
}
return *this;
}
basic_sstring& replace(size_type pos, size_type n1, const char_type* s,
size_type n2) {
if (pos > size()) {
- throw std::out_of_range("sstring::replace out of range");
+ internal::throw_sstring_out_of_range();
}
if (n1 > size() - pos) {
basic_sstring& replace (const_iterator i1, const_iterator i2,
InputIterator first, InputIterator last) {
if (i1 < begin() || i1 > end() || i2 < begin()) {
- throw std::out_of_range("sstring::replace out of range");
+ internal::throw_sstring_out_of_range();
}
if (i2 > end()) {
i2 = end();
basic_sstring substr(size_t from, size_t len = npos) const {
if (from > size()) {
- throw std::out_of_range("sstring::substr out of range");
+ internal::throw_sstring_out_of_range();
}
if (len > size() - from) {
len = size() - from;
const char_type& at(size_t pos) const {
if (pos >= size()) {
- throw std::out_of_range("sstring::at out of range");
+ internal::throw_sstring_out_of_range();
}
return *(str() + pos);
}
char_type& at(size_t pos) {
if (pos >= size()) {
- throw std::out_of_range("sstring::at out of range");
+ internal::throw_sstring_out_of_range();
}
return *(str() + pos);
}
bool empty() const noexcept {
return u.internal.size == 0;
}
+
+ // Deprecated March 2020.
+ [[deprecated("Use = {}")]]
void reset() noexcept {
if (is_external()) {
std::free(u.external.str);
return buf;
}
}
- int compare(const basic_sstring& x) const noexcept {
+ int compare(std::basic_string_view<char_type, traits_type> x) const noexcept {
auto n = traits_type::compare(begin(), x.begin(), std::min(size(), x.size()));
if (n != 0) {
return n;
}
}
- int compare(size_t pos, size_t sz, const basic_sstring& x) const {
+ int compare(size_t pos, size_t sz, std::basic_string_view<char_type, traits_type> x) const {
if (pos > size()) {
- throw std::out_of_range("pos larger than string size");
+ internal::throw_sstring_out_of_range();
}
sz = std::min(size() - pos, sz);
x.u = u;
u = tmp;
}
- char_type* data() {
+ char_type* data() noexcept {
return str();
}
- const char_type* data() const {
+ const char_type* data() const noexcept {
return str();
}
- const char_type* c_str() const {
+ const char_type* c_str() const noexcept {
return str();
}
- const char_type* begin() const { return str(); }
- const char_type* end() const { return str() + size(); }
- const char_type* cbegin() const { return str(); }
- const char_type* cend() const { return str() + size(); }
- char_type* begin() { return str(); }
- char_type* end() { return str() + size(); }
- bool operator==(const basic_sstring& x) const {
+ const char_type* begin() const noexcept { return str(); }
+ const char_type* end() const noexcept { return str() + size(); }
+ const char_type* cbegin() const noexcept { return str(); }
+ const char_type* cend() const noexcept { return str() + size(); }
+ char_type* begin() noexcept { return str(); }
+ char_type* end() noexcept { return str() + size(); }
+ bool operator==(const basic_sstring& x) const noexcept {
return size() == x.size() && std::equal(begin(), end(), x.begin());
}
- bool operator!=(const basic_sstring& x) const {
+ bool operator!=(const basic_sstring& x) const noexcept {
return !operator==(x);
}
- bool operator<(const basic_sstring& x) const {
+ bool operator<(const basic_sstring& x) const noexcept {
return compare(x) < 0;
}
basic_sstring operator+(const basic_sstring& x) const {
basic_sstring& operator+=(const basic_sstring& x) {
return *this = *this + x;
}
- char_type& operator[](size_type pos) {
+ char_type& operator[](size_type pos) noexcept {
return str()[pos];
}
- const char_type& operator[](size_type pos) const {
+ const char_type& operator[](size_type pos) const noexcept {
return str()[pos];
}
- operator compat::basic_string_view<char_type>() const {
- return compat::basic_string_view<char_type>(str(), size());
+ operator std::basic_string_view<char_type>() const noexcept {
+ // we assume that std::basic_string_view<char_type>(str(), size())
+ // won't throw, although it is not specified as noexcept in
+ // https://en.cppreference.com/w/cpp/string/basic_string_view/basic_string_view
+ // at this time (C++20).
+ //
+ // This is similar to std::string operator std::basic_string_view:
+ // https://en.cppreference.com/w/cpp/string/basic_string/operator_basic_string_view
+ // that is specified as noexcept too.
+ static_assert(noexcept(std::basic_string_view<char_type>(str(), size())));
+ return std::basic_string_view<char_type>(str(), size());
}
-
- template <typename string_type, typename T>
- friend inline string_type to_sstring(T value);
};
template <typename char_type, typename Size, Size max_size, bool NulTerminate>
constexpr Size basic_sstring<char_type, Size, max_size, NulTerminate>::npos;
+template <typename string_type = sstring>
+string_type uninitialized_string(size_t size) {
+ string_type ret;
+ // FIXME: use __resize_default_init if available
+ ret.resize(size);
+ return ret;
+}
+
+template <typename char_type, typename Size, Size max_size, bool NulTerminate>
+basic_sstring<char_type, Size, max_size, NulTerminate> uninitialized_string(size_t size) {
+ using sstring_type = basic_sstring<char_type, Size, max_size, NulTerminate>;
+ return sstring_type(sstring_type::initialized_later(), size);
+}
+
template <typename char_type, typename size_type, size_type Max, size_type N, bool NulTerminate>
inline
basic_sstring<char_type, size_type, Max, NulTerminate>
return ret;
}
-template <size_t N>
-static inline
-size_t str_len(const char(&s)[N]) { return N - 1; }
-
-template <size_t N>
static inline
-const char* str_begin(const char(&s)[N]) { return s; }
-
-template <size_t N>
-static inline
-const char* str_end(const char(&s)[N]) { return str_begin(s) + str_len(s); }
-
-template <typename char_type, typename size_type, size_type max_size, bool NulTerminate>
-static inline
-const char_type* str_begin(const basic_sstring<char_type, size_type, max_size, NulTerminate>& s) { return s.begin(); }
-
-template <typename char_type, typename size_type, size_type max_size, bool NulTerminate>
-static inline
-const char_type* str_end(const basic_sstring<char_type, size_type, max_size, NulTerminate>& s) { return s.end(); }
-
-template <typename char_type, typename size_type, size_type max_size, bool NulTerminate>
-static inline
-size_type str_len(const basic_sstring<char_type, size_type, max_size, NulTerminate>& s) { return s.size(); }
+size_t str_len() {
+ return 0;
+}
-template <typename First, typename Second, typename... Tail>
+template <typename First, typename... Tail>
static inline
-size_t str_len(const First& first, const Second& second, const Tail&... tail) {
- return str_len(first) + str_len(second, tail...);
+size_t str_len(const First& first, const Tail&... tail) {
+ return std::string_view(first).size() + str_len(tail...);
}
template <typename char_type, typename size_type, size_type max_size>
template <typename char_type, typename size_type, size_type max_size, bool NulTerminate>
struct hash<seastar::basic_sstring<char_type, size_type, max_size, NulTerminate>> {
size_t operator()(const seastar::basic_sstring<char_type, size_type, max_size, NulTerminate>& s) const {
- return std::hash<seastar::compat::basic_string_view<char_type>>()(s);
+ return std::hash<std::basic_string_view<char_type>>()(s);
}
};
template <typename Head, typename... Tail>
static inline
char* copy_str_to(char* dst, const Head& head, const Tail&... tail) {
- return copy_str_to(std::copy(str_begin(head), str_end(head), dst), tail...);
+ std::string_view v(head);
+ return copy_str_to(std::copy(v.begin(), v.end(), dst), tail...);
}
template <typename String = sstring, typename... Args>
static String make_sstring(Args&&... args)
{
- String ret(sstring::initialized_later(), str_len(args...));
- copy_str_to(ret.begin(), args...);
+ String ret = uninitialized_string<String>(str_len(args...));
+ copy_str_to(ret.data(), args...);
return ret;
}
+namespace internal {
template <typename string_type, typename T>
-inline string_type to_sstring(T value) {
- return sstring::to_sstring<string_type>(value);
+string_type to_sstring_sprintf(T value, const char* fmt) {
+ char tmp[sizeof(value) * 3 + 2];
+ auto len = std::sprintf(tmp, fmt, value);
+ using ch_type = typename string_type::value_type;
+ return string_type(reinterpret_cast<ch_type*>(tmp), len);
+}
+
+template <typename string_type>
+string_type to_sstring(int value) {
+ return to_sstring_sprintf<string_type>(value, "%d");
+}
+
+template <typename string_type>
+string_type to_sstring(unsigned value) {
+ return to_sstring_sprintf<string_type>(value, "%u");
+}
+
+template <typename string_type>
+string_type to_sstring(long value) {
+ return to_sstring_sprintf<string_type>(value, "%ld");
+}
+
+template <typename string_type>
+string_type to_sstring(unsigned long value) {
+ return to_sstring_sprintf<string_type>(value, "%lu");
}
+template <typename string_type>
+string_type to_sstring(long long value) {
+ return to_sstring_sprintf<string_type>(value, "%lld");
+}
+
+template <typename string_type>
+string_type to_sstring(unsigned long long value) {
+ return to_sstring_sprintf<string_type>(value, "%llu");
+}
+
+template <typename string_type>
+string_type to_sstring(float value) {
+ return to_sstring_sprintf<string_type>(value, "%g");
+}
+
+template <typename string_type>
+string_type to_sstring(double value) {
+ return to_sstring_sprintf<string_type>(value, "%g");
+}
+
+template <typename string_type>
+string_type to_sstring(long double value) {
+ return to_sstring_sprintf<string_type>(value, "%Lg");
+}
+
+template <typename string_type>
+string_type to_sstring(const char* value) {
+ return string_type(value);
+}
+
+template <typename string_type>
+string_type to_sstring(sstring value) {
+ return value;
+}
+
+template <typename string_type>
+string_type to_sstring(const temporary_buffer<char>& buf) {
+ return string_type(buf.get(), buf.size());
+}
+}
+
+template <typename string_type = sstring, typename T>
+string_type to_sstring(T value) {
+ return internal::to_sstring<string_type>(value);
+}
}
namespace std {