2018-02-03 17:49:39 +01:00
|
|
|
//
|
|
|
|
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
|
|
|
|
//
|
|
|
|
// 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)
|
|
|
|
//
|
|
|
|
#include "td/utils/StringBuilder.h"
|
|
|
|
|
2018-02-03 20:40:06 +01:00
|
|
|
#include "td/utils/misc.h"
|
2018-02-11 16:58:18 +01:00
|
|
|
#include "td/utils/port/thread_local.h"
|
2018-02-03 20:40:06 +01:00
|
|
|
|
2018-02-03 17:49:39 +01:00
|
|
|
#include <cstdio>
|
2018-06-05 01:34:51 +02:00
|
|
|
#include <limits>
|
2018-02-03 20:40:06 +01:00
|
|
|
#include <locale>
|
|
|
|
#include <sstream>
|
2018-06-05 01:34:51 +02:00
|
|
|
#include <utility>
|
2018-02-03 17:49:39 +01:00
|
|
|
|
|
|
|
namespace td {
|
|
|
|
|
2018-06-05 01:34:51 +02:00
|
|
|
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()) {
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << x;
|
|
|
|
auto len = narrow_cast<int>(static_cast<std::streamoff>(ss.tellp()));
|
|
|
|
ss.read(current_ptr, len);
|
|
|
|
return current_ptr + len;
|
|
|
|
}
|
|
|
|
|
|
|
|
*current_ptr++ = '-';
|
|
|
|
x = -x;
|
|
|
|
}
|
|
|
|
|
|
|
|
return print_uint(current_ptr, x);
|
|
|
|
}
|
|
|
|
|
2018-02-03 17:49:39 +01:00
|
|
|
StringBuilder &StringBuilder::operator<<(int x) {
|
|
|
|
if (unlikely(end_ptr_ < current_ptr_)) {
|
|
|
|
return on_error();
|
|
|
|
}
|
2018-06-05 01:34:51 +02:00
|
|
|
current_ptr_ = print_int(current_ptr_, x);
|
2018-02-03 17:49:39 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringBuilder &StringBuilder::operator<<(unsigned int x) {
|
|
|
|
if (unlikely(end_ptr_ < current_ptr_)) {
|
|
|
|
return on_error();
|
|
|
|
}
|
2018-06-05 01:34:51 +02:00
|
|
|
current_ptr_ = print_uint(current_ptr_, x);
|
2018-02-03 17:49:39 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringBuilder &StringBuilder::operator<<(long int x) {
|
|
|
|
if (unlikely(end_ptr_ < current_ptr_)) {
|
|
|
|
return on_error();
|
|
|
|
}
|
2018-06-05 01:34:51 +02:00
|
|
|
current_ptr_ = print_int(current_ptr_, x);
|
2018-02-03 17:49:39 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringBuilder &StringBuilder::operator<<(long unsigned int x) {
|
|
|
|
if (unlikely(end_ptr_ < current_ptr_)) {
|
|
|
|
return on_error();
|
|
|
|
}
|
2018-06-05 01:34:51 +02:00
|
|
|
current_ptr_ = print_uint(current_ptr_, x);
|
2018-02-03 17:49:39 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringBuilder &StringBuilder::operator<<(long long int x) {
|
|
|
|
if (unlikely(end_ptr_ < current_ptr_)) {
|
|
|
|
return on_error();
|
|
|
|
}
|
2018-06-05 01:34:51 +02:00
|
|
|
current_ptr_ = print_int(current_ptr_, x);
|
2018-02-03 17:49:39 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringBuilder &StringBuilder::operator<<(long long unsigned int x) {
|
|
|
|
if (unlikely(end_ptr_ < current_ptr_)) {
|
|
|
|
return on_error();
|
|
|
|
}
|
2018-06-05 01:34:51 +02:00
|
|
|
current_ptr_ = print_uint(current_ptr_, x);
|
2018-02-03 17:49:39 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2018-02-11 12:38:08 +01:00
|
|
|
StringBuilder &StringBuilder::operator<<(FixedDouble x) {
|
2018-02-03 17:49:39 +01:00
|
|
|
if (unlikely(end_ptr_ < current_ptr_)) {
|
|
|
|
return on_error();
|
|
|
|
}
|
2018-02-03 20:40:06 +01:00
|
|
|
|
|
|
|
static TD_THREAD_LOCAL std::stringstream *ss;
|
|
|
|
if (init_thread_local<std::stringstream>(ss)) {
|
2018-10-26 16:11:20 +02:00
|
|
|
auto previous_locale = ss->imbue(std::locale::classic());
|
2018-02-11 10:47:11 +01:00
|
|
|
ss->setf(std::ios_base::fixed, std::ios_base::floatfield);
|
2018-02-03 20:40:06 +01:00
|
|
|
} else {
|
|
|
|
ss->str(std::string());
|
|
|
|
ss->clear();
|
|
|
|
}
|
2018-02-11 12:38:08 +01:00
|
|
|
ss->precision(x.precision);
|
|
|
|
*ss << x.d;
|
2018-02-03 20:40:06 +01:00
|
|
|
|
|
|
|
int len = narrow_cast<int>(static_cast<std::streamoff>(ss->tellp()));
|
2018-02-03 17:49:39 +01:00
|
|
|
auto left = end_ptr_ + reserved_size - current_ptr_;
|
|
|
|
if (unlikely(len >= left)) {
|
|
|
|
error_flag_ = true;
|
2018-02-03 21:13:05 +01:00
|
|
|
len = left ? narrow_cast<int>(left - 1) : 0;
|
2018-02-03 17:49:39 +01:00
|
|
|
}
|
2018-02-03 20:40:06 +01:00
|
|
|
ss->read(current_ptr_, len);
|
|
|
|
current_ptr_ += len;
|
2018-02-03 17:49:39 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringBuilder &StringBuilder::operator<<(const void *ptr) {
|
|
|
|
if (unlikely(end_ptr_ < current_ptr_)) {
|
|
|
|
return on_error();
|
|
|
|
}
|
|
|
|
current_ptr_ += std::snprintf(current_ptr_, reserved_size, "%p", ptr);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace td
|