summaryrefslogtreecommitdiff
path: root/protocols/Telegram/tdlib/td/tdutils/td/utils/StringBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/Telegram/tdlib/td/tdutils/td/utils/StringBuilder.cpp')
-rw-r--r--protocols/Telegram/tdlib/td/tdutils/td/utils/StringBuilder.cpp151
1 files changed, 131 insertions, 20 deletions
diff --git a/protocols/Telegram/tdlib/td/tdutils/td/utils/StringBuilder.cpp b/protocols/Telegram/tdlib/td/tdutils/td/utils/StringBuilder.cpp
index ce64bbc9a6..d82fdbea53 100644
--- a/protocols/Telegram/tdlib/td/tdutils/td/utils/StringBuilder.cpp
+++ b/protocols/Telegram/tdlib/td/tdutils/td/utils/StringBuilder.cpp
@@ -1,5 +1,5 @@
//
-// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -8,70 +8,181 @@
#include "td/utils/misc.h"
#include "td/utils/port/thread_local.h"
+#include "td/utils/Slice.h"
#include <cstdio>
+#include <cstring>
+#include <limits>
#include <locale>
+#include <memory>
#include <sstream>
+#include <utility>
namespace td {
-// TODO: optimize
+StringBuilder::StringBuilder(MutableSlice slice, bool use_buffer)
+ : begin_ptr_(slice.begin()), current_ptr_(begin_ptr_), use_buffer_(use_buffer) {
+ if (slice.size() <= RESERVED_SIZE) {
+ auto buffer_size = RESERVED_SIZE + 100;
+ buffer_ = std::make_unique<char[]>(buffer_size);
+ begin_ptr_ = buffer_.get();
+ current_ptr_ = begin_ptr_;
+ end_ptr_ = begin_ptr_ + buffer_size - RESERVED_SIZE;
+ } else {
+ end_ptr_ = slice.end() - RESERVED_SIZE;
+ }
+}
+
+StringBuilder &StringBuilder::operator<<(Slice slice) {
+ size_t size = slice.size();
+ if (unlikely(!reserve(size))) {
+ if (end_ptr_ < current_ptr_) {
+ return on_error();
+ }
+ auto available_size = static_cast<size_t>(end_ptr_ + RESERVED_SIZE - 1 - current_ptr_);
+ if (size > available_size) {
+ error_flag_ = true;
+ size = available_size;
+ }
+ }
+
+ std::memcpy(current_ptr_, slice.begin(), size);
+ current_ptr_ += size;
+ return *this;
+}
+
+template <class T>
+static char *print_uint(char *current_ptr, T x) {
+ if (x < 100) {
+ if (x < 10) {
+ *current_ptr++ = static_cast<char>('0' + x);
+ } else {
+ *current_ptr++ = static_cast<char>('0' + x / 10);
+ *current_ptr++ = static_cast<char>('0' + x % 10);
+ }
+ return current_ptr;
+ }
+
+ auto begin_ptr = current_ptr;
+ do {
+ *current_ptr++ = static_cast<char>('0' + x % 10);
+ x /= 10;
+ } while (x > 0);
+
+ auto end_ptr = current_ptr - 1;
+ while (begin_ptr < end_ptr) {
+ std::swap(*begin_ptr++, *end_ptr--);
+ }
+
+ return current_ptr;
+}
+
+template <class T>
+static char *print_int(char *current_ptr, T x) {
+ if (x < 0) {
+ if (x == std::numeric_limits<T>::min()) {
+ current_ptr = print_int(current_ptr, x + 1);
+ CHECK(current_ptr[-1] != '9');
+ current_ptr[-1]++;
+ return current_ptr;
+ }
+
+ *current_ptr++ = '-';
+ x = -x;
+ }
+
+ return print_uint(current_ptr, x);
+}
+
+bool StringBuilder::reserve_inner(size_t size) {
+ if (!use_buffer_) {
+ return false;
+ }
+
+ size_t old_data_size = current_ptr_ - begin_ptr_;
+ if (size >= std::numeric_limits<size_t>::max() - RESERVED_SIZE - old_data_size - 1) {
+ return false;
+ }
+ size_t need_data_size = old_data_size + size;
+ size_t old_buffer_size = end_ptr_ - begin_ptr_;
+ if (old_buffer_size >= (std::numeric_limits<size_t>::max() - RESERVED_SIZE) / 2 - 2) {
+ return false;
+ }
+ size_t new_buffer_size = (old_buffer_size + 1) * 2;
+ if (new_buffer_size < need_data_size) {
+ new_buffer_size = need_data_size;
+ }
+ if (new_buffer_size < 100) {
+ new_buffer_size = 100;
+ }
+ new_buffer_size += RESERVED_SIZE;
+ auto new_buffer = std::make_unique<char[]>(new_buffer_size);
+ std::memcpy(new_buffer.get(), begin_ptr_, old_data_size);
+ buffer_ = std::move(new_buffer);
+ begin_ptr_ = buffer_.get();
+ current_ptr_ = begin_ptr_ + old_data_size;
+ end_ptr_ = begin_ptr_ + new_buffer_size - RESERVED_SIZE;
+ CHECK(end_ptr_ > current_ptr_);
+ CHECK(static_cast<size_t>(end_ptr_ - current_ptr_) >= size);
+ return true;
+}
+
StringBuilder &StringBuilder::operator<<(int x) {
- if (unlikely(end_ptr_ < current_ptr_)) {
+ if (unlikely(!reserve())) {
return on_error();
}
- current_ptr_ += std::snprintf(current_ptr_, reserved_size, "%d", x);
+ current_ptr_ = print_int(current_ptr_, x);
return *this;
}
StringBuilder &StringBuilder::operator<<(unsigned int x) {
- if (unlikely(end_ptr_ < current_ptr_)) {
+ if (unlikely(!reserve())) {
return on_error();
}
- current_ptr_ += std::snprintf(current_ptr_, reserved_size, "%u", x);
+ current_ptr_ = print_uint(current_ptr_, x);
return *this;
}
StringBuilder &StringBuilder::operator<<(long int x) {
- if (unlikely(end_ptr_ < current_ptr_)) {
+ if (unlikely(!reserve())) {
return on_error();
}
- current_ptr_ += std::snprintf(current_ptr_, reserved_size, "%ld", x);
+ current_ptr_ = print_int(current_ptr_, x);
return *this;
}
StringBuilder &StringBuilder::operator<<(long unsigned int x) {
- if (unlikely(end_ptr_ < current_ptr_)) {
+ if (unlikely(!reserve())) {
return on_error();
}
- current_ptr_ += std::snprintf(current_ptr_, reserved_size, "%lu", x);
+ current_ptr_ = print_uint(current_ptr_, x);
return *this;
}
StringBuilder &StringBuilder::operator<<(long long int x) {
- if (unlikely(end_ptr_ < current_ptr_)) {
+ if (unlikely(!reserve())) {
return on_error();
}
- current_ptr_ += std::snprintf(current_ptr_, reserved_size, "%lld", x);
+ current_ptr_ = print_int(current_ptr_, x);
return *this;
}
StringBuilder &StringBuilder::operator<<(long long unsigned int x) {
- if (unlikely(end_ptr_ < current_ptr_)) {
+ if (unlikely(!reserve())) {
return on_error();
}
- current_ptr_ += std::snprintf(current_ptr_, reserved_size, "%llu", x);
+ current_ptr_ = print_uint(current_ptr_, x);
return *this;
}
StringBuilder &StringBuilder::operator<<(FixedDouble x) {
- if (unlikely(end_ptr_ < current_ptr_)) {
+ if (unlikely(!reserve(std::numeric_limits<double>::max_exponent10 + x.precision + 4))) {
return on_error();
}
static TD_THREAD_LOCAL std::stringstream *ss;
if (init_thread_local<std::stringstream>(ss)) {
- ss->imbue(std::locale::classic());
+ auto previous_locale = ss->imbue(std::locale::classic());
ss->setf(std::ios_base::fixed, std::ios_base::floatfield);
} else {
ss->str(std::string());
@@ -80,8 +191,8 @@ StringBuilder &StringBuilder::operator<<(FixedDouble x) {
ss->precision(x.precision);
*ss << x.d;
- int len = narrow_cast<int>(static_cast<std::streamoff>(ss->tellp()));
- auto left = end_ptr_ + reserved_size - current_ptr_;
+ auto len = narrow_cast<int>(static_cast<std::streamoff>(ss->tellp()));
+ auto left = end_ptr_ + RESERVED_SIZE - current_ptr_;
if (unlikely(len >= left)) {
error_flag_ = true;
len = left ? narrow_cast<int>(left - 1) : 0;
@@ -92,10 +203,10 @@ StringBuilder &StringBuilder::operator<<(FixedDouble x) {
}
StringBuilder &StringBuilder::operator<<(const void *ptr) {
- if (unlikely(end_ptr_ < current_ptr_)) {
+ if (unlikely(!reserve())) {
return on_error();
}
- current_ptr_ += std::snprintf(current_ptr_, reserved_size, "%p", ptr);
+ current_ptr_ += std::snprintf(current_ptr_, RESERVED_SIZE, "%p", ptr);
return *this;
}