Fix tdutils after merge.

GitOrigin-RevId: 5b9a863e405a9e3782157570156fda71bf2bb589
This commit is contained in:
levlam 2020-06-26 02:24:13 +03:00
parent a9e95b7f4b
commit 8872fbf6ac
80 changed files with 750 additions and 341 deletions

View File

@ -276,7 +276,7 @@ if (NOT CMAKE_CROSSCOMPILING)
endif() endif()
if (NOT OPENSSL_FOUND) if (NOT OPENSSL_FOUND)
message(WARNING "Not found OpenSSL: skip TDLib, tdactor, tdnet, tddb") message(WARNING "Can't find OpenSSL: stop TDLib building")
return() return()
endif() endif()
@ -284,7 +284,12 @@ if (NOT ZLIB_FOUND)
find_package(ZLIB) find_package(ZLIB)
endif() endif()
if (NOT ZLIB_FOUND) if (NOT ZLIB_FOUND)
message(WARNING "Not found zlib: skip TDLib, tdactor, tdnet, tddb") message(WARNING "Can't find zlib: stop TDLib building")
return()
endif()
if (NOT TDUTILS_MIME_TYPE)
message(WARNING "Option TDUTILS_MIME_TYPE must not be disabled: stop TDLib building")
return() return()
endif() endif()

View File

@ -340,7 +340,7 @@ void StorageManager::schedule_next_gc() {
if (next_gc_at > sys_time + GC_EACH) { if (next_gc_at > sys_time + GC_EACH) {
next_gc_at = sys_time + GC_EACH; next_gc_at = sys_time + GC_EACH;
} }
next_gc_at += Random::fast(static_cast<int>(GC_DELAY), static_cast<int>(GC_DELAY + GC_RAND_DELAY)); next_gc_at += Random::fast(GC_DELAY, GC_DELAY + GC_RAND_DELAY);
CHECK(next_gc_at >= sys_time); CHECK(next_gc_at >= sys_time);
auto next_gc_in = next_gc_at - sys_time; auto next_gc_in = next_gc_at - sys_time;

View File

@ -41,9 +41,9 @@ class StorageManager : public Actor {
void on_new_file(int64 size, int64 real_size, int32 cnt); void on_new_file(int64 size, int64 real_size, int32 cnt);
private: private:
static constexpr uint32 GC_EACH = 60 * 60 * 24; // 1 day static constexpr int GC_EACH = 60 * 60 * 24; // 1 day
static constexpr uint32 GC_DELAY = 60; static constexpr int GC_DELAY = 60;
static constexpr uint32 GC_RAND_DELAY = 60 * 15; static constexpr int GC_RAND_DELAY = 60 * 15;
ActorShared<> parent_; ActorShared<> parent_;

View File

@ -46,7 +46,6 @@
#include <clocale> #include <clocale>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring>
#include <ctime> #include <ctime>
#include <iostream> #include <iostream>
#include <limits> #include <limits>
@ -4330,7 +4329,7 @@ void main(int argc, char **argv) {
return std::string(); return std::string();
}(std::getenv("TD_API_HASH")); }(std::getenv("TD_API_HASH"));
td::OptionParser options; OptionParser options;
options.set_description("TDLib test client"); options.set_description("TDLib test client");
options.add_option('\0', "test", "Use test DC", [&] { use_test_dc = true; }); options.add_option('\0', "test", "Use test DC", [&] { use_test_dc = true; });
options.add_option('v', "verbosity", "Set verbosity level", [&](Slice level) { options.add_option('v', "verbosity", "Set verbosity level", [&](Slice level) {

View File

@ -12,6 +12,7 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/format.h" #include "td/utils/format.h"
#include "td/utils/misc.h"
#include <algorithm> #include <algorithm>
#include <unordered_set> #include <unordered_set>

View File

@ -31,7 +31,6 @@
#include <functional> #include <functional>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
namespace td { namespace td {
namespace { namespace {

View File

@ -257,7 +257,7 @@ std::shared_ptr<NetStatsCallback> NetStatsManager::get_media_stats_callback() co
std::vector<std::shared_ptr<NetStatsCallback>> NetStatsManager::get_file_stats_callbacks() const { std::vector<std::shared_ptr<NetStatsCallback>> NetStatsManager::get_file_stats_callbacks() const {
auto result = transform(files_stats_, [](auto &stat) { return stat.stats.get_callback(); }); auto result = transform(files_stats_, [](auto &stat) { return stat.stats.get_callback(); });
for (int32 i = 0; i < MAX_FILE_TYPE; i++) { for (int32 i = 0; i < MAX_FILE_TYPE; i++) {
int32 main_file_type = static_cast<size_t>(get_main_file_type(static_cast<FileType>(i))); int32 main_file_type = static_cast<int32>(get_main_file_type(static_cast<FileType>(i)));
if (main_file_type != i) { if (main_file_type != i) {
result[i] = result[main_file_type]; result[i] = result[main_file_type];
} }

View File

@ -11,7 +11,6 @@
#include "td/db/binlog/BinlogHelper.h" #include "td/db/binlog/BinlogHelper.h"
#include "td/db/binlog/BinlogInterface.h" #include "td/db/binlog/BinlogInterface.h"
#include "td/utils/format.h"
#include "td/utils/misc.h" #include "td/utils/misc.h"
#include "td/utils/port/Clocks.h" #include "td/utils/port/Clocks.h"
#include "td/utils/Random.h" #include "td/utils/Random.h"
@ -226,7 +225,7 @@ class TQueueImpl : public TQueue {
return 0; return 0;
} }
td::MutableSpan<td::TQueue::Event> span; MutableSpan<Event> span;
return do_get(queue_id, q, q.events.front().event_id, true, Time::now(), span); return do_get(queue_id, q, q.events.front().event_id, true, Time::now(), span);
} }

View File

@ -16,12 +16,13 @@
namespace td { namespace td {
inline uint64 binlog_add(BinlogInterface *binlog_ptr, int32 type, const Storer &storer, Promise<> promise = Promise<>()) { inline uint64 binlog_add(BinlogInterface *binlog_ptr, int32 type, const Storer &storer,
Promise<> promise = Promise<>()) {
return binlog_ptr->add(type, storer, std::move(promise)); return binlog_ptr->add(type, storer, std::move(promise));
} }
inline uint64 binlog_rewrite(BinlogInterface *binlog_ptr, uint64 logevent_id, int32 type, const Storer &storer, inline uint64 binlog_rewrite(BinlogInterface *binlog_ptr, uint64 logevent_id, int32 type, const Storer &storer,
Promise<> promise = Promise<>()) { Promise<> promise = Promise<>()) {
return binlog_ptr->rewrite(logevent_id, type, storer, std::move(promise)); return binlog_ptr->rewrite(logevent_id, type, storer, std::move(promise));
} }

View File

@ -24,8 +24,8 @@ MutableSlice HttpQuery::get_arg(Slice key) const {
return it == args_.end() ? MutableSlice() : it->second; return it == args_.end() ? MutableSlice() : it->second;
} }
td::vector<std::pair<string, string>> HttpQuery::get_args() const { vector<std::pair<string, string>> HttpQuery::get_args() const {
td::vector<std::pair<string, string>> res; vector<std::pair<string, string>> res;
res.reserve(args_.size()); res.reserve(args_.size());
for (auto &it : args_) { for (auto &it : args_) {
res.emplace_back(it.first.str(), it.second.str()); res.emplace_back(it.first.str(), it.second.str());

View File

@ -21,23 +21,23 @@ class HttpQuery {
public: public:
enum class Type : int8 { Empty, Get, Post, Response }; enum class Type : int8 { Empty, Get, Post, Response };
td::vector<BufferSlice> container_; vector<BufferSlice> container_;
Type type_ = Type::Empty; Type type_ = Type::Empty;
int32 code_ = 0; int32 code_ = 0;
MutableSlice url_path_; MutableSlice url_path_;
td::vector<std::pair<MutableSlice, MutableSlice>> args_; vector<std::pair<MutableSlice, MutableSlice>> args_;
MutableSlice reason_; MutableSlice reason_;
bool keep_alive_ = true; bool keep_alive_ = true;
td::vector<std::pair<MutableSlice, MutableSlice>> headers_; vector<std::pair<MutableSlice, MutableSlice>> headers_;
td::vector<HttpFile> files_; vector<HttpFile> files_;
MutableSlice content_; MutableSlice content_;
Slice get_header(Slice key) const; Slice get_header(Slice key) const;
MutableSlice get_arg(Slice key) const; MutableSlice get_arg(Slice key) const;
td::vector<std::pair<string, string>> get_args() const; vector<std::pair<string, string>> get_args() const;
int get_retry_after() const; int get_retry_after() const;
}; };

View File

@ -1,14 +1,6 @@
cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR) cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
option(TDUTILS_MIME_TYPE "Generate mime types conversion (gperf is required)" ON) option(TDUTILS_MIME_TYPE "Generate mime types conversion; requires gperf" ON)
if (WIN32)
if (WINGETOPT_FOUND)
set(TD_HAVE_GETOPT 1)
endif()
else()
set(TD_HAVE_GETOPT 1)
endif()
if (NOT DEFINED CMAKE_INSTALL_LIBDIR) if (NOT DEFINED CMAKE_INSTALL_LIBDIR)
set(CMAKE_INSTALL_LIBDIR "lib") set(CMAKE_INSTALL_LIBDIR "lib")
@ -69,7 +61,6 @@ set(TDUTILS_SOURCE
td/utils/port/Stat.cpp td/utils/port/Stat.cpp
td/utils/port/StdStreams.cpp td/utils/port/StdStreams.cpp
td/utils/port/thread_local.cpp td/utils/port/thread_local.cpp
td/utils/port/user.cpp
td/utils/port/UdpSocketFd.cpp td/utils/port/UdpSocketFd.cpp
td/utils/port/uname.cpp td/utils/port/uname.cpp
td/utils/port/user.cpp td/utils/port/user.cpp
@ -115,10 +106,10 @@ set(TDUTILS_SOURCE
td/utils/StackAllocator.cpp td/utils/StackAllocator.cpp
td/utils/Status.cpp td/utils/Status.cpp
td/utils/StringBuilder.cpp td/utils/StringBuilder.cpp
td/utils/tests.cpp
td/utils/Time.cpp td/utils/Time.cpp
td/utils/Timer.cpp td/utils/Timer.cpp
td/utils/TsFileLog.cpp td/utils/TsFileLog.cpp
td/utils/tests.cpp
td/utils/tl_parsers.cpp td/utils/tl_parsers.cpp
td/utils/translit.cpp td/utils/translit.cpp
td/utils/TsFileLog.cpp td/utils/TsFileLog.cpp
@ -150,7 +141,6 @@ set(TDUTILS_SOURCE
td/utils/port/StdStreams.h td/utils/port/StdStreams.h
td/utils/port/thread.h td/utils/port/thread.h
td/utils/port/thread_local.h td/utils/port/thread_local.h
td/utils/port/user.h
td/utils/port/UdpSocketFd.h td/utils/port/UdpSocketFd.h
td/utils/port/uname.h td/utils/port/uname.h
td/utils/port/user.h td/utils/port/user.h
@ -174,6 +164,7 @@ set(TDUTILS_SOURCE
td/utils/AesCtrByteFlow.h td/utils/AesCtrByteFlow.h
td/utils/as.h td/utils/as.h
td/utils/AtomicRead.h
td/utils/base64.h td/utils/base64.h
td/utils/benchmark.h td/utils/benchmark.h
td/utils/BigNum.h td/utils/BigNum.h
@ -283,6 +274,7 @@ set(TDUTILS_TEST_SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/test/ConcurrentHashMap.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/ConcurrentHashMap.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/crypto.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/crypto.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/Enumerator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/Enumerator.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/EpochBasedMemoryReclamation.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/filesystem.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/filesystem.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/gzip.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/gzip.cpp
${CMAKE_CURRENT_SOURCE_DIR}/test/HazardPointers.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test/HazardPointers.cpp
@ -337,11 +329,7 @@ if (CRC32C_FOUND)
target_link_libraries(tdutils PRIVATE crc32c) target_link_libraries(tdutils PRIVATE crc32c)
endif() endif()
if (ABSL_FOUND) if (ABSL_FOUND)
target_link_libraries_system(tdutils absl::flat_hash_map absl::flat_hash_set absl::hash) target_link_libraries(tdutils SYSTEM PUBLIC absl::flat_hash_map absl::flat_hash_set absl::hash)
endif()
if (WIN32 AND WINGETOPT_FOUND)
target_link_libraries(tdutils PRIVATE wingetopt)
endif() endif()
if (ANDROID) if (ANDROID)

View File

@ -0,0 +1,79 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
//
// 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)
//
#pragma once
#include "td/utils/common.h"
#include "td/utils/port/thread.h"
#include <atomic>
#include <cstring>
#include <type_traits>
namespace td {
template <class T>
class AtomicRead {
public:
void read(T &dest) const {
while (true) {
static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable");
auto version_before = version.load();
if (version_before % 2 == 0) {
std::memcpy(&dest, &value, sizeof(dest));
auto version_after = version.load();
if (version_before == version_after) {
break;
}
}
td::this_thread::yield();
}
}
struct Write {
explicit Write(AtomicRead *read) {
read->do_lock();
ptr.reset(read);
}
struct Destructor {
void operator()(AtomicRead *read) const {
read->do_unlock();
}
};
T &operator*() {
return value();
}
T *operator->() {
return &value();
}
T &value() {
CHECK(ptr);
return ptr->value;
}
private:
std::unique_ptr<AtomicRead, Destructor> ptr;
};
Write lock() {
return Write(this);
}
private:
std::atomic<uint64> version{0};
T value;
void do_lock() {
bool is_locked = ++version % 2 == 1;
CHECK(is_locked);
}
void do_unlock() {
bool is_unlocked = ++version % 2 == 0;
CHECK(is_unlocked);
}
};
} // namespace td

View File

@ -213,13 +213,13 @@ string BigNum::to_le_binary(int exact_size) const {
} else { } else {
CHECK(exact_size >= num_size); CHECK(exact_size >= num_size);
} }
string res(exact_size, '\0'); string result(exact_size, '\0');
#if defined(OPENSSL_IS_BORINGSSL) #if defined(OPENSSL_IS_BORINGSSL)
BN_bn2le_padded(MutableSlice(res).ubegin(), exact_size, impl_->big_num); BN_bn2le_padded(MutableSlice(result).ubegin(), exact_size, impl_->big_num);
#else #else
BN_bn2lebinpad(impl_->big_num, MutableSlice(res).ubegin(), exact_size); BN_bn2lebinpad(impl_->big_num, MutableSlice(result).ubegin(), exact_size);
#endif #endif
return res; return result;
#else #else
string result = to_binary(exact_size); string result = to_binary(exact_size);
std::reverse(result.begin(), result.end()); std::reverse(result.begin(), result.end());

View File

@ -72,10 +72,11 @@ class BufferedFd : public BufferedFdBase<FdT> {
~BufferedFd(); ~BufferedFd();
void close(); void close();
size_t left_unread() {
size_t left_unread() const {
return input_reader_.size(); return input_reader_.size();
} }
size_t left_unwritten() { size_t left_unwritten() const {
return output_reader_.size(); return output_reader_.size();
} }

View File

@ -20,7 +20,7 @@ struct RawCancellationToken {
class CancellationToken { class CancellationToken {
public: public:
explicit operator bool() const { explicit operator bool() const {
// Empty CancellationToken is never cancelled // empty CancellationToken is never cancelled
if (!token_) { if (!token_) {
return false; return false;
} }

View File

@ -317,6 +317,6 @@ class ConcurrentHashMap {
}; };
template <class KeyT, class ValueT> template <class KeyT, class ValueT>
td::HazardPointers<typename ConcurrentHashMap<KeyT, ValueT>::HashMap> ConcurrentHashMap<KeyT, ValueT>::hp_(64); HazardPointers<typename ConcurrentHashMap<KeyT, ValueT>::HashMap> ConcurrentHashMap<KeyT, ValueT>::hp_(64);
} // namespace td } // namespace td

View File

@ -13,8 +13,6 @@
#include "td/utils/port/StdStreams.h" #include "td/utils/port/StdStreams.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include <limits>
namespace td { namespace td {
Status FileLog::init(string path, int64 rotate_threshold, bool redirect_stderr) { Status FileLog::init(string path, int64 rotate_threshold, bool redirect_stderr) {
@ -104,7 +102,7 @@ void FileLog::lazy_rotate() {
void FileLog::do_rotate() { void FileLog::do_rotate() {
want_rotate_ = false; want_rotate_ = false;
td::ScopedDisableLog disable_log; // to ensure that nothing will be printed to the closed log ScopedDisableLog disable_log; // to ensure that nothing will be printed to the closed log
CHECK(!path_.empty()); CHECK(!path_.empty());
fd_.close(); fd_.close();
auto r_fd = FileFd::open(path_, FileFd::Create | FileFd::Truncate | FileFd::Write); auto r_fd = FileFd::open(path_, FileFd::Create | FileFd::Truncate | FileFd::Write);
@ -118,7 +116,7 @@ void FileLog::do_rotate() {
size_ = 0; size_ = 0;
} }
Result<td::unique_ptr<LogInterface>> FileLog::create(string path, int64 rotate_threshold, bool redirect_stderr) { Result<unique_ptr<LogInterface>> FileLog::create(string path, int64 rotate_threshold, bool redirect_stderr) {
auto l = make_unique<FileLog>(); auto l = make_unique<FileLog>();
TRY_STATUS(l->init(std::move(path), rotate_threshold, redirect_stderr)); TRY_STATUS(l->init(std::move(path), rotate_threshold, redirect_stderr));
return std::move(l); return std::move(l);

View File

@ -12,14 +12,16 @@
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
#include <atomic>
namespace td { namespace td {
class FileLog : public LogInterface { class FileLog : public LogInterface {
static constexpr int64 DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20); static constexpr int64 DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20);
public: public:
static Result<td::unique_ptr<LogInterface>> create(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD, static Result<unique_ptr<LogInterface>> create(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD,
bool redirect_stderr = true); bool redirect_stderr = true);
Status init(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD, bool redirect_stderr = true); Status init(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD, bool redirect_stderr = true);
Slice get_path() const; Slice get_path() const;
@ -42,7 +44,7 @@ class FileLog : public LogInterface {
int64 size_ = 0; int64 size_ = 0;
int64 rotate_threshold_ = 0; int64 rotate_threshold_ = 0;
bool redirect_stderr_ = false; bool redirect_stderr_ = false;
std::atomic<bool> want_rotate_{}; std::atomic<bool> want_rotate_{false};
void do_rotate(); void do_rotate();
}; };

View File

@ -37,7 +37,7 @@ class KHeap {
return array_[0].key_; return array_[0].key_;
} }
HeapNode *top() const { const HeapNode *top() const {
return array_[0].node_; return array_[0].node_;
} }

View File

@ -350,10 +350,7 @@ class JsonArrayScope : public JsonScope {
} }
void leave() { void leave() {
jb_->dec_offset(); jb_->dec_offset();
if (jb_->is_pretty()) { jb_->print_offset();
*sb_ << "\n";
jb_->print_offset();
}
*sb_ << "]"; *sb_ << "]";
} }
template <class T> template <class T>
@ -372,10 +369,7 @@ class JsonArrayScope : public JsonScope {
} else { } else {
is_first_ = true; is_first_ = true;
} }
if (jb_->is_pretty()) { jb_->print_offset();
*sb_ << "\n";
jb_->print_offset();
}
return jb_->enter_value(); return jb_->enter_value();
} }
@ -397,10 +391,7 @@ class JsonObjectScope : public JsonScope {
} }
void leave() { void leave() {
jb_->dec_offset(); jb_->dec_offset();
if (jb_->is_pretty()) { jb_->print_offset();
*sb_ << "\n";
jb_->print_offset();
}
*sb_ << "}"; *sb_ << "}";
} }
template <class T> template <class T>
@ -411,10 +402,7 @@ class JsonObjectScope : public JsonScope {
} else { } else {
is_first_ = true; is_first_ = true;
} }
if (jb_->is_pretty()) { jb_->print_offset();
*sb_ << "\n";
jb_->print_offset();
}
jb_->enter_value() << key; jb_->enter_value() << key;
if (jb_->is_pretty()) { if (jb_->is_pretty()) {
*sb_ << " : "; *sb_ << " : ";

View File

@ -10,8 +10,8 @@
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/port/thread.h" #include "td/utils/port/thread.h"
#include <atomic>
#include <algorithm> #include <algorithm>
#include <atomic>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
@ -149,7 +149,7 @@ class MpmcSleepyWaiter {
} }
void unpark() { void unpark() {
//TODO: try unlock guard before notify_all //TODO: try to unlock guard before notify_all
std::unique_lock<std::mutex> guard(mutex_); std::unique_lock<std::mutex> guard(mutex_);
unpark_flag_ = true; unpark_flag_ = true;
condition_variable_.notify_all(); condition_variable_.notify_all();
@ -182,10 +182,10 @@ class MpmcSleepyWaiter {
// //
// When worker found nothing it may try to call wait. // When worker found nothing it may try to call wait.
// This may put it in a Sleep for some time. // This may put it in a Sleep for some time.
// After wait return worker will be in Search state again. // After wait returns worker will be in Search state again.
// //
// Suppose worker found a work and ready to process it. // Suppose worker found a work and ready to process it.
// Than it may call stop_wait. This will cause transition from // Then it may call stop_wait. This will cause transition from
// Search to Work state. // Search to Work state.
// //
// Main invariant: // Main invariant:
@ -200,7 +200,7 @@ class MpmcSleepyWaiter {
VLOG(waiter) << "Init slot " << worker_id; VLOG(waiter) << "Init slot " << worker_id;
} }
int VERBOSITY_NAME(waiter) = VERBOSITY_NAME(DEBUG) + 10; static constexpr int VERBOSITY_NAME(waiter) = VERBOSITY_NAME(DEBUG) + 10;
void wait(Slot &slot) { void wait(Slot &slot) {
if (slot.state_ == Slot::State::Work) { if (slot.state_ == Slot::State::Work) {
VLOG(waiter) << "Work -> Search"; VLOG(waiter) << "Work -> Search";
@ -225,10 +225,10 @@ class MpmcSleepyWaiter {
} }
sleepers_.push_back(&slot); sleepers_.push_back(&slot);
LOG_CHECK(slot.unpark_flag_ == false) << slot.worker_id; LOG_CHECK(slot.unpark_flag_ == false) << slot.worker_id;
VLOG(waiter) << "add to sleepers " << slot.worker_id; VLOG(waiter) << "Add to sleepers " << slot.worker_id;
//guard.unlock(); //guard.unlock();
if (should_search) { if (should_search) {
VLOG(waiter) << "Search -> Search once then Sleep "; VLOG(waiter) << "Search -> Search once, then Sleep ";
return; return;
} }
VLOG(waiter) << "Search -> Sleep " << state_view.searching_count << " " << state_view.parked_count; VLOG(waiter) << "Search -> Sleep " << state_view.searching_count << " " << state_view.parked_count;
@ -247,22 +247,22 @@ class MpmcSleepyWaiter {
return; return;
} }
if (slot.state_ == Slot::State::Sleep) { if (slot.state_ == Slot::State::Sleep) {
VLOG(waiter) << "Search once then Sleep -> Work/Search " << slot.worker_id; VLOG(waiter) << "Search once, then Sleep -> Work/Search " << slot.worker_id;
slot.state_ = Slot::State::Work; slot.state_ = Slot::State::Work;
std::unique_lock<std::mutex> guard(sleepers_mutex_); std::unique_lock<std::mutex> guard(sleepers_mutex_);
auto it = std::find(sleepers_.begin(), sleepers_.end(), &slot); auto it = std::find(sleepers_.begin(), sleepers_.end(), &slot);
if (it != sleepers_.end()) { if (it != sleepers_.end()) {
sleepers_.erase(it); sleepers_.erase(it);
VLOG(waiter) << "remove from sleepers " << slot.worker_id; VLOG(waiter) << "Remove from sleepers " << slot.worker_id;
state_.fetch_sub((1 << PARKING_SHIFT) - 1); state_.fetch_sub((1 << PARKING_SHIFT) - 1);
guard.unlock(); guard.unlock();
} else { } else {
guard.unlock(); guard.unlock();
VLOG(waiter) << "not in sleepers" << slot.worker_id; VLOG(waiter) << "Not in sleepers" << slot.worker_id;
CHECK(slot.cancel_park()); CHECK(slot.cancel_park());
} }
} }
VLOG(waiter) << "Search once then Sleep -> Work " << slot.worker_id; VLOG(waiter) << "Search once, then Sleep -> Work " << slot.worker_id;
slot.state_ = Slot::State::Search; slot.state_ = Slot::State::Search;
auto state_view = StateView(state_.fetch_sub(1)); auto state_view = StateView(state_.fetch_sub(1));
CHECK(state_view.searching_count != 0); CHECK(state_view.searching_count != 0);
@ -313,19 +313,19 @@ class MpmcSleepyWaiter {
} }
private: private:
static constexpr td::int32 PARKING_SHIFT = 16; static constexpr int32 PARKING_SHIFT = 16;
struct StateView { struct StateView {
td::int32 parked_count; int32 parked_count;
td::int32 searching_count; int32 searching_count;
explicit StateView(int32 x) { explicit StateView(int32 x) {
parked_count = x >> PARKING_SHIFT; parked_count = x >> PARKING_SHIFT;
searching_count = x & ((1 << PARKING_SHIFT) - 1); searching_count = x & ((1 << PARKING_SHIFT) - 1);
} }
}; };
std::atomic<td::int32> state_{0}; std::atomic<int32> state_{0};
std::mutex sleepers_mutex_; std::mutex sleepers_mutex_;
std::vector<Slot *> sleepers_; vector<Slot *> sleepers_;
bool closed_ = false; bool closed_ = false;
}; };

View File

@ -4,10 +4,9 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "td/utils/OptionParser.h" #include "td/utils/OptionParser.h"
#include "td/utils/misc.h" #include "td/utils/logging.h"
#include <cstring> #include <cstring>
#include <unordered_map> #include <unordered_map>
@ -21,8 +20,8 @@ void OptionParser::set_description(string description) {
void OptionParser::add_option(Option::Type type, char short_key, Slice long_key, Slice description, void OptionParser::add_option(Option::Type type, char short_key, Slice long_key, Slice description,
std::function<Status(Slice)> callback) { std::function<Status(Slice)> callback) {
for (auto &option : options_) { for (auto &option : options_) {
if (option.short_key == short_key || (!long_key.empty() && long_key == option.long_key)) { if ((short_key != '\0' && option.short_key == short_key) || (!long_key.empty() && long_key == option.long_key)) {
LOG(ERROR) << "Ignore duplicated option '" << short_key << "' '" << long_key << "'"; LOG(ERROR) << "Ignore duplicated option '" << (short_key == '\0' ? '-' : short_key) << "' '" << long_key << "'";
} }
} }
options_.push_back(Option{type, short_key, long_key.str(), description.str(), std::move(callback)}); options_.push_back(Option{type, short_key, long_key.str(), description.str(), std::move(callback)});

View File

@ -4,9 +4,9 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "td/utils/PathView.h" #include "td/utils/PathView.h"
#include "td/utils/common.h"
#include "td/utils/misc.h" #include "td/utils/misc.h"
namespace td { namespace td {
@ -26,6 +26,18 @@ PathView::PathView(Slice path) : path_(path) {
} }
} }
Slice PathView::parent_dir_noslash() const {
if (last_slash_ < 0) {
return Slice(".");
}
if (last_slash_ == 0) {
static char buf[1];
buf[0] = TD_DIR_SLASH;
return Slice(buf, 1);
}
return path_.substr(0, last_slash_);
}
Slice PathView::relative(Slice path, Slice dir, bool force) { Slice PathView::relative(Slice path, Slice dir, bool force) {
if (begins_with(path, dir)) { if (begins_with(path, dir)) {
path.remove_prefix(dir.size()); path.remove_prefix(dir.size());

View File

@ -28,9 +28,7 @@ class PathView {
Slice parent_dir() const { Slice parent_dir() const {
return path_.substr(0, last_slash_ + 1); return path_.substr(0, last_slash_ + 1);
} }
Slice parent_dir_noslash() const { Slice parent_dir_noslash() const;
return last_slash_ <= 0 ? td::Slice(".") : path_.substr(0, last_slash_);
}
Slice extension() const { Slice extension() const {
if (last_dot_ == static_cast<int32>(path_.size())) { if (last_dot_ == static_cast<int32>(path_.size())) {

View File

@ -40,7 +40,7 @@ void Random::secure_bytes(unsigned char *ptr, size_t size) {
generation = 0; generation = 0;
} }
if (ptr == nullptr) { if (ptr == nullptr) {
td::MutableSlice(buf, BUF_SIZE).fill_zero_secure(); MutableSlice(buf, BUF_SIZE).fill_zero_secure();
buf_pos = BUF_SIZE; buf_pos = BUF_SIZE;
return; return;
} }
@ -145,10 +145,7 @@ int Random::fast(int min, int max) {
double Random::fast(double min, double max) { double Random::fast(double min, double max) {
DCHECK(min <= max); DCHECK(min <= max);
return min + return min + fast_uint32() * 1.0 / std::numeric_limits<uint32>::max() * (max - min);
fast_uint32() * 1.0 /
(static_cast<double>(std::numeric_limits<td::uint32>::max()) - std::numeric_limits<td::uint32>::min()) *
(max - min);
} }
Random::Xorshift128plus::Xorshift128plus(uint64 seed) { Random::Xorshift128plus::Xorshift128plus(uint64 seed) {

View File

@ -10,6 +10,8 @@
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/Span.h" #include "td/utils/Span.h"
#include <utility>
namespace td { namespace td {
class Random { class Random {
@ -55,10 +57,11 @@ class Random {
}; };
template <class T, class R> template <class T, class R>
void random_shuffle(td::MutableSpan<T> v, R &rnd) { void random_shuffle(MutableSpan<T> v, R &rnd) {
for (std::size_t i = 1; i < v.size(); i++) { for (size_t i = 1; i < v.size(); i++) {
auto pos = static_cast<std::size_t>(rnd() % (i + 1)); auto pos = static_cast<size_t>(rnd()) % (i + 1);
std::swap(v[i], v[pos]); using std::swap;
swap(v[i], v[pos]);
} }
} }

View File

@ -37,7 +37,9 @@ class AtomicRefCnt {
}; };
template <class DataT, class DeleterT> template <class DataT, class DeleterT>
class SharedPtrRaw : public DeleterT, private MpscLinkQueueImpl::Node { class SharedPtrRaw
: public DeleterT
, private MpscLinkQueueImpl::Node {
public: public:
explicit SharedPtrRaw(DeleterT deleter) : DeleterT(std::move(deleter)), ref_cnt_{0}, option_magic_(Magic) { explicit SharedPtrRaw(DeleterT deleter) : DeleterT(std::move(deleter)), ref_cnt_{0}, option_magic_(Magic) {
} }

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "td/utils/SharedSlice.h" #include "td/utils/SharedSlice.h"
#include "td/utils/buffer.h" #include "td/utils/buffer.h"

View File

@ -4,9 +4,9 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#pragma once #pragma once
#include "td/utils/common.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include <atomic> #include <atomic>

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#if TD_HAVE_OPENSSL #if TD_HAVE_OPENSSL

View File

@ -105,6 +105,7 @@ class SpanImpl {
InnerT *end() const { InnerT *end() const {
return data_ + size_; return data_ + size_;
} }
std::reverse_iterator<InnerT *> rbegin() const { std::reverse_iterator<InnerT *> rbegin() const {
return std::reverse_iterator<InnerT *>(end()); return std::reverse_iterator<InnerT *>(end());
} }
@ -149,7 +150,7 @@ Span<T> span(const T *ptr, size_t size) {
return Span<T>(ptr, size); return Span<T>(ptr, size);
} }
template <class T> template <class T>
Span<T> span(const std::vector<T> &vec) { Span<T> span(const vector<T> &vec) {
return Span<T>(vec); return Span<T>(vec);
} }
@ -158,17 +159,17 @@ MutableSpan<T> mutable_span(T *ptr, size_t size) {
return MutableSpan<T>(ptr, size); return MutableSpan<T>(ptr, size);
} }
template <class T> template <class T>
MutableSpan<T> mutable_span(std::vector<T> &vec) { MutableSpan<T> mutable_span(vector<T> &vec) {
return MutableSpan<T>(vec); return MutableSpan<T>(vec);
} }
template <class T> template <class T>
Span<T> span_one(const T &value) { Span<T> span_one(const T &value) {
return td::Span<T>(&value, 1); return Span<T>(&value, 1);
} }
template <class T> template <class T>
MutableSpan<T> mutable_span_one(T &value) { MutableSpan<T> mutable_span_one(T &value) {
return td::MutableSpan<T>(&value, 1); return MutableSpan<T>(&value, 1);
} }
template <class T> template <class T>

View File

@ -318,10 +318,7 @@ class Status {
return std::move(*this); return std::move(*this);
} }
Auto move_as_ok() { Status move_as_ok() = delete;
UNREACHABLE();
return {};
}
Status move_as_error_prefix(const Status &status) const TD_WARN_UNUSED_RESULT { Status move_as_error_prefix(const Status &status) const TD_WARN_UNUSED_RESULT {
return status.move_as_error_suffix(message()); return status.move_as_error_suffix(message());
@ -533,13 +530,13 @@ class Result {
} }
Status move_as_error_prefix(const Status &prefix) TD_WARN_UNUSED_RESULT { Status move_as_error_prefix(const Status &prefix) TD_WARN_UNUSED_RESULT {
SCOPE_EXIT { SCOPE_EXIT {
status_ = Status::Error<-5>(); status_ = Status::Error<-6>();
}; };
return status_.move_as_error_prefix(prefix); return status_.move_as_error_prefix(prefix);
} }
Status move_as_error_suffix(Slice suffix) TD_WARN_UNUSED_RESULT { Status move_as_error_suffix(Slice suffix) TD_WARN_UNUSED_RESULT {
SCOPE_EXIT { SCOPE_EXIT {
status_ = Status::Error<-5>(); status_ = Status::Error<-7>();
}; };
return status_.move_as_error_suffix(suffix); return status_.move_as_error_suffix(suffix);
} }
@ -571,7 +568,7 @@ class Result {
} }
template <class F> template <class F>
td::Result<decltype(std::declval<F>()(std::declval<T>()))> move_map(F &&f) { Result<decltype(std::declval<F>()(std::declval<T>()))> move_map(F &&f) {
if (is_error()) { if (is_error()) {
return move_as_error(); return move_as_error();
} }

View File

@ -0,0 +1,125 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
//
// 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)
//
#pragma once
#include "td/utils/common.h"
#include "td/utils/misc.h"
#include <array>
#include <atomic>
namespace td {
template <class T, size_t N = 256>
class StealingQueue {
public:
static_assert(N > 0 && (N & (N - 1)) == 0, "");
// tries to put a value
// returns if succeeded
// only owner is allowed to to do this
template <class F>
void local_push(T value, F &&overflow_f) {
while (true) {
auto tail = tail_.load(std::memory_order_relaxed);
auto head = head_.load(); // TODO: memory order
if (static_cast<size_t>(tail - head) < N) {
buf_[tail & MASK].store(value, std::memory_order_relaxed);
tail_.store(tail + 1, std::memory_order_release);
return;
}
// queue is full
// TODO: batch insert into global queue?
auto n = N / 2 + 1;
auto new_head = head + n;
if (!head_.compare_exchange_strong(head, new_head)) {
continue;
}
for (size_t i = 0; i < n; i++) {
overflow_f(buf_[(i + head) & MASK].load(std::memory_order_relaxed));
}
overflow_f(value);
return;
}
}
// tries to pop a value
// returns if succeeded
// only owner is allowed to do this
bool local_pop(T &value) {
auto tail = tail_.load(std::memory_order_relaxed);
auto head = head_.load();
if (head == tail) {
return false;
}
value = buf_[head & MASK].load(std::memory_order_relaxed);
return head_.compare_exchange_strong(head, head + 1);
}
bool steal(T &value, StealingQueue<T, N> &other) {
while (true) {
auto tail = tail_.load(std::memory_order_relaxed);
auto head = head_.load(); // TODO: memory order
auto other_head = other.head_.load();
auto other_tail = other.tail_.load(std::memory_order_acquire);
if (other_tail < other_head) {
continue;
}
size_t n = narrow_cast<size_t>(other_tail - other_head);
if (n > N) {
continue;
}
n -= n / 2;
n = td::min(n, static_cast<size_t>(head + N - tail));
if (n == 0) {
return false;
}
for (size_t i = 0; i < n; i++) {
buf_[(i + tail) & MASK].store(other.buf_[(i + other_head) & MASK].load(std::memory_order_relaxed),
std::memory_order_relaxed);
}
if (!other.head_.compare_exchange_strong(other_head, other_head + n)) {
continue;
}
n--;
value = buf_[(tail + n) & MASK].load(std::memory_order_relaxed);
tail_.store(tail + n, std::memory_order_release);
return true;
}
}
StealingQueue() {
for (auto &x : buf_) {
// workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64658
#if TD_GCC && GCC_VERSION <= 40902
x = T();
#else
std::atomic_init(&x, T());
#endif
}
std::atomic_thread_fence(std::memory_order_seq_cst);
}
private:
std::atomic<int64> head_{0};
std::atomic<int64> tail_{0};
static constexpr size_t MASK{N - 1};
std::array<std::atomic<T>, N> buf_;
};
} // namespace td

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#pragma once #pragma once
#include "td/utils/common.h" #include "td/utils/common.h"
@ -14,6 +13,7 @@
#include <atomic> #include <atomic>
namespace td { namespace td {
template <class T> template <class T>
class ThreadLocalStorage { class ThreadLocalStorage {
public: public:
@ -51,4 +51,5 @@ class ThreadLocalStorage {
return nodes_[thread_id]; return nodes_[thread_id];
} }
}; };
} // namespace td } // namespace td

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#pragma once #pragma once
#include "td/utils/common.h" #include "td/utils/common.h"
@ -17,6 +16,7 @@
#include <mutex> #include <mutex>
namespace td { namespace td {
template <size_t N> template <size_t N>
class ThreadSafeMultiCounter { class ThreadSafeMultiCounter {
public: public:
@ -28,11 +28,11 @@ class ThreadSafeMultiCounter {
int64 sum(size_t index) const { int64 sum(size_t index) const {
CHECK(index < N); CHECK(index < N);
int64 res = 0; int64 res = 0;
tls_.for_each([&](auto &value) { res += value[index].load(std::memory_order_relaxed); }); tls_.for_each([&res](auto &value) { res += value[index].load(std::memory_order_relaxed); });
return res; return res;
} }
void clear() { void clear() {
tls_.for_each([&](auto &value) { tls_.for_each([](auto &value) {
for (auto &x : value) { for (auto &x : value) {
x = 0; x = 0;
} }

View File

@ -6,17 +6,17 @@
// //
#include "td/utils/Time.h" #include "td/utils/Time.h"
#include <cmath>
#include <atomic> #include <atomic>
#include <cmath>
namespace td { namespace td {
bool operator==(Timestamp a, Timestamp b) { bool operator==(Timestamp a, Timestamp b) {
return std::abs(a.at() - b.at()) < 1e-6; return std::abs(a.at() - b.at()) < 1e-6;
} }
namespace {
std::atomic<double> time_diff; static std::atomic<double> time_diff;
}
double Time::now() { double Time::now() {
return now_unadjusted() + time_diff.load(std::memory_order_relaxed); return now_unadjusted() + time_diff.load(std::memory_order_relaxed);
} }
@ -26,9 +26,8 @@ double Time::now_unadjusted() {
} }
void Time::jump_in_future(double at) { void Time::jump_in_future(double at) {
auto old_time_diff = time_diff.load();
while (true) { while (true) {
auto old_time_diff = time_diff.load();
auto diff = at - now(); auto diff = at - now();
if (diff < 0) { if (diff < 0) {
return; return;

View File

@ -62,11 +62,11 @@ class Timestamp {
return Timestamp{timeout - Clocks::system() + Time::now()}; return Timestamp{timeout - Clocks::system() + Time::now()};
} }
static Timestamp in(double timeout, td::Timestamp now = td::Timestamp::now_cached()) { static Timestamp in(double timeout, Timestamp now = now_cached()) {
return Timestamp{now.at() + timeout}; return Timestamp{now.at() + timeout};
} }
bool is_in_past(td::Timestamp now) const { bool is_in_past(Timestamp now) const {
return at_ <= now.at(); return at_ <= now.at();
} }
bool is_in_past() const { bool is_in_past() const {

View File

@ -9,6 +9,7 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/optional.h" #include "td/utils/optional.h"
#include <functional>
#include <utility> #include <utility>
namespace td { namespace td {
@ -69,27 +70,28 @@ class TimedStat {
} }
}; };
namespace detail {
template <class T, class Cmp> template <class T, class Cmp>
struct MinMaxStat { struct MinMaxStat {
public:
using Event = T; using Event = T;
void on_event(Event event) { void on_event(Event event) {
if (!best_ || Cmp()(event, best_.value())) { if (!best_ || Cmp()(event, best_.value())) {
best_ = event; best_ = event;
} }
} }
td::optional<T> get_stat() const { optional<T> get_stat() const {
return best_.copy(); return best_.copy();
} }
private: private:
td::optional<T> best_; optional<T> best_;
}; };
} // namespace detail
template <class T> template <class T>
using MinStat = MinMaxStat<T, std::less<>>; using MinStat = detail::MinMaxStat<T, std::less<>>;
template <class T> template <class T>
using MaxStat = MinMaxStat<T, std::greater<>>; using MaxStat = detail::MinMaxStat<T, std::greater<>>;
} // namespace td } // namespace td

View File

@ -12,11 +12,9 @@
namespace td { namespace td {
Timer::Timer(bool is_paused) : is_paused_(is_paused) { Timer::Timer(bool is_paused) {
if (is_paused_) { if (!is_paused) {
start_time_ = 0; resume();
} else {
start_time_ = Time::now();
} }
} }
@ -45,7 +43,7 @@ double Timer::elapsed() const {
} }
StringBuilder &operator<<(StringBuilder &string_builder, const Timer &timer) { StringBuilder &operator<<(StringBuilder &string_builder, const Timer &timer) {
return string_builder << format::as_time(timer.elapsed()); return string_builder << " in " << format::as_time(timer.elapsed());
} }
PerfWarningTimer::PerfWarningTimer(string name, double max_duration) PerfWarningTimer::PerfWarningTimer(string name, double max_duration)

View File

@ -15,19 +15,19 @@ class Timer {
Timer() : Timer(false) { Timer() : Timer(false) {
} }
explicit Timer(bool is_paused); explicit Timer(bool is_paused);
Timer(const Timer &other) = default;
Timer &operator=(const Timer &other) = default;
double elapsed() const; double elapsed() const;
void pause(); void pause();
void resume(); void resume();
private: private:
friend StringBuilder &operator<<(StringBuilder &string_builder, const Timer &timer); friend StringBuilder &operator<<(StringBuilder &string_builder, const Timer &timer);
double elapsed_{0}; double elapsed_{0};
double start_time_; double start_time_{0};
bool is_paused_{false}; bool is_paused_{true};
}; };
class PerfWarningTimer { class PerfWarningTimer {

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "td/utils/TsFileLog.h" #include "td/utils/TsFileLog.h"
#include "td/utils/common.h" #include "td/utils/common.h"
@ -14,17 +13,20 @@
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include <array> #include <array>
#include <atomic>
#include <limits> #include <limits>
#include <mutex>
namespace td { namespace td {
namespace detail { namespace detail {
class TsFileLog : public LogInterface { class TsFileLog : public LogInterface {
public: public:
Status init(string path, td::int64 rotate_threshold, bool redirect_stderr) { Status init(string path, int64 rotate_threshold, bool redirect_stderr) {
path_ = std::move(path); path_ = std::move(path);
rotate_threshold_ = rotate_threshold; rotate_threshold_ = rotate_threshold;
redirect_stderr_ = redirect_stderr; redirect_stderr_ = redirect_stderr;
for (int i = 0; i < (int)logs_.size(); i++) { for (size_t i = 0; i < logs_.size(); i++) {
logs_[i].id = i; logs_[i].id = i;
} }
return init_info(&logs_[0]); return init_info(&logs_[0]);
@ -49,18 +51,23 @@ class TsFileLog : public LogInterface {
struct Info { struct Info {
FileLog log; FileLog log;
std::atomic<bool> is_inited{false}; std::atomic<bool> is_inited{false};
int id; size_t id;
}; };
static constexpr int MAX_THREAD_ID = 128;
td::int64 rotate_threshold_; static constexpr size_t MAX_THREAD_ID = 128;
int64 rotate_threshold_;
bool redirect_stderr_; bool redirect_stderr_;
std::string path_; std::string path_;
std::array<Info, MAX_THREAD_ID> logs_; std::array<Info, MAX_THREAD_ID> logs_;
std::mutex init_mutex_;
LogInterface *get_current_logger() { LogInterface *get_current_logger() {
auto *info = get_current_info(); auto *info = get_current_info();
if (!info->is_inited.load(std::memory_order_relaxed)) { if (!info->is_inited.load(std::memory_order_relaxed)) {
CHECK(init_info(info).is_ok()); std::unique_lock<std::mutex> lock(init_mutex_);
if (!info->is_inited.load(std::memory_order_relaxed)) {
init_info(info).ensure();
}
} }
return &info->log; return &info->log;
} }
@ -75,7 +82,7 @@ class TsFileLog : public LogInterface {
return Status::OK(); return Status::OK();
} }
string get_path(Info *info) { string get_path(const Info *info) const {
if (info->id == 0) { if (info->id == 0) {
return path_; return path_;
} }
@ -84,7 +91,7 @@ class TsFileLog : public LogInterface {
void rotate() override { void rotate() override {
for (auto &info : logs_) { for (auto &info : logs_) {
if (info.is_inited.load(std::memory_order_consume)) { if (info.is_inited.load(std::memory_order_acquire)) {
info.log.lazy_rotate(); info.log.lazy_rotate();
} }
} }
@ -92,9 +99,10 @@ class TsFileLog : public LogInterface {
}; };
} // namespace detail } // namespace detail
Result<td::unique_ptr<LogInterface>> TsFileLog::create(string path, td::int64 rotate_threshold, bool redirect_stderr) { Result<unique_ptr<LogInterface>> TsFileLog::create(string path, int64 rotate_threshold, bool redirect_stderr) {
auto res = td::make_unique<detail::TsFileLog>(); auto res = make_unique<detail::TsFileLog>();
TRY_STATUS(res->init(path, rotate_threshold, redirect_stderr)); TRY_STATUS(res->init(path, rotate_threshold, redirect_stderr));
return std::move(res); return std::move(res);
} }
} // namespace td } // namespace td

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#pragma once #pragma once
#include "td/utils/common.h" #include "td/utils/common.h"
@ -12,11 +11,13 @@
#include "td/utils/Status.h" #include "td/utils/Status.h"
namespace td { namespace td {
class TsFileLog { class TsFileLog {
static constexpr int64 DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20); static constexpr int64 DEFAULT_ROTATE_THRESHOLD = 10 * (1 << 20);
public: public:
static Result<td::unique_ptr<LogInterface>> create(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD, static Result<unique_ptr<LogInterface>> create(string path, int64 rotate_threshold = DEFAULT_ROTATE_THRESHOLD,
bool redirect_stderr = true); bool redirect_stderr = true);
}; };
} // namespace td } // namespace td

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#pragma once #pragma once
#include "td/utils/common.h" #include "td/utils/common.h"

View File

@ -20,42 +20,51 @@ class VectorQueue {
void push(S &&s) { void push(S &&s) {
vector_.emplace_back(std::forward<S>(s)); vector_.emplace_back(std::forward<S>(s));
} }
template <class... Args> template <class... Args>
void emplace(Args &&... args) { void emplace(Args &&... args) {
vector_.emplace_back(std::forward<Args>(args)...); vector_.emplace_back(std::forward<Args>(args)...);
} }
T pop() { T pop() {
try_shrink(); try_shrink();
return std::move(vector_[read_pos_++]); return std::move(vector_[read_pos_++]);
} }
void pop_n(size_t n) { void pop_n(size_t n) {
read_pos_ += n; read_pos_ += n;
try_shrink(); try_shrink();
} }
const T &front() const {
return vector_[read_pos_];
}
T &front() { T &front() {
return vector_[read_pos_]; return vector_[read_pos_];
} }
const T &back() const {
return vector_.back();
}
T &back() { T &back() {
return vector_.back(); return vector_.back();
} }
const T &front() const {
return vector_[read_pos_];
}
const T &back() const {
return vector_.back();
}
bool empty() const { bool empty() const {
return size() == 0; return size() == 0;
} }
size_t size() const { size_t size() const {
return vector_.size() - read_pos_; return vector_.size() - read_pos_;
} }
const T *data() const { const T *data() const {
return vector_.data() + read_pos_; return vector_.data() + read_pos_;
} }
T *data() { T *data() {
return vector_.data() + read_pos_; return vector_.data() + read_pos_;
} }
Span<T> as_span() const { Span<T> as_span() const {
return {data(), size()}; return {data(), size()};
} }

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "td/utils/base64.h" #include "td/utils/base64.h"
#include "td/utils/common.h" #include "td/utils/common.h"
@ -237,11 +236,28 @@ string base64_filter(Slice input) {
return res; return res;
} }
static const char *const symbols32_lc = "abcdefghijklmnopqrstuvwxyz234567"; static const char *get_base32_characters(bool upper_case) {
static const char *const symbols32_uc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; return upper_case ? "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" : "abcdefghijklmnopqrstuvwxyz234567";
}
static const unsigned char *get_base32_character_table() {
static unsigned char char_to_value[256];
static bool is_inited = [] {
std::fill(std::begin(char_to_value), std::end(char_to_value), static_cast<unsigned char>(32));
auto characters_lc = get_base32_characters(false);
auto characters_uc = get_base32_characters(true);
for (unsigned char i = 0; i < 32; i++) {
char_to_value[static_cast<size_t>(characters_lc[i])] = i;
char_to_value[static_cast<size_t>(characters_uc[i])] = i;
}
return true;
}();
CHECK(is_inited);
return char_to_value;
}
string base32_encode(Slice input, bool upper_case) { string base32_encode(Slice input, bool upper_case) {
auto *symbols32 = (upper_case ? symbols32_uc : symbols32_lc); auto *characters = get_base32_characters(upper_case);
string base32; string base32;
base32.reserve((input.size() * 8 + 4) / 5); base32.reserve((input.size() * 8 + 4) / 5);
uint32 c = 0; uint32 c = 0;
@ -251,45 +267,32 @@ string base32_encode(Slice input, bool upper_case) {
length += 8; length += 8;
while (length >= 5) { while (length >= 5) {
length -= 5; length -= 5;
base32.push_back(symbols32[(c >> length) & 31]); base32.push_back(characters[(c >> length) & 31]);
} }
} }
if (length != 0) { if (length != 0) {
base32.push_back(symbols32[(c << (5 - length)) & 31]); base32.push_back(characters[(c << (5 - length)) & 31]);
} }
//TODO: optional padding //TODO: optional padding
return base32; return base32;
} }
static unsigned char b32_char_to_value[256];
static void init_base32_table() {
static bool is_inited = [] {
std::fill(std::begin(b32_char_to_value), std::end(b32_char_to_value), static_cast<unsigned char>(32));
for (unsigned char i = 0; i < 32; i++) {
b32_char_to_value[static_cast<size_t>(symbols32_lc[i])] = i;
b32_char_to_value[static_cast<size_t>(symbols32_uc[i])] = i;
}
return true;
}();
CHECK(is_inited);
}
Result<string> base32_decode(Slice base32) { Result<string> base32_decode(Slice base32) {
init_base32_table();
string res; string res;
res.reserve(base32.size() * 5 / 8); res.reserve(base32.size() * 5 / 8);
uint32 c = 0; uint32 c = 0;
uint32 length = 0; uint32 length = 0;
auto *table = get_base32_character_table();
for (size_t i = 0; i < base32.size(); i++) { for (size_t i = 0; i < base32.size(); i++) {
auto value = b32_char_to_value[base32.ubegin()[i]]; auto value = table[base32.ubegin()[i]];
if (value == 32) { if (value == 32) {
return Status::Error("Wrong character in the string"); return Status::Error("Wrong character in the string");
} }
c = (c << 5) | value; c = (c << 5) | value;
length += 5; length += 5;
while (length >= 8) { if (length >= 8) {
length -= 8; length -= 8;
res.push_back(td::uint8((c >> length) & 255)); res.push_back(static_cast<char>((c >> length) & 255));
} }
} }
if ((c & ((1 << length) - 1)) != 0) { if ((c & ((1 << length) - 1)) != 0) {
@ -298,4 +301,5 @@ Result<string> base32_decode(Slice base32) {
//TODO: check padding //TODO: check padding
return res; return res;
} }
} // namespace td } // namespace td

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#pragma once #pragma once
#include "td/utils/common.h" #include "td/utils/common.h"
@ -28,6 +27,8 @@ bool is_base64_characters(Slice input);
bool is_base64url_characters(Slice input); bool is_base64url_characters(Slice input);
string base64_filter(Slice input); string base64_filter(Slice input);
string base32_encode(Slice input, bool upper_case = false); string base32_encode(Slice input, bool upper_case = false);
Result<string> base32_decode(Slice base32); Result<string> base32_decode(Slice base32);
} // namespace td } // namespace td

View File

@ -271,10 +271,7 @@ inline int32 count_bits64(uint64 x) {
#endif #endif
struct BitsRange { struct BitsRange {
td::uint64 bits{0}; explicit BitsRange(uint64 bits = 0) : bits{bits}, pos{-1} {
mutable td::int32 pos{-1};
explicit BitsRange(td::uint64 bits = 0) : bits{bits}, pos{-1} {
} }
BitsRange begin() const { BitsRange begin() const {
@ -285,9 +282,9 @@ struct BitsRange {
return BitsRange{}; return BitsRange{};
} }
td::int32 operator*() const { int32 operator*() const {
if (pos == -1) { if (pos == -1) {
pos = td::count_trailing_zeroes64(bits); pos = count_trailing_zeroes64(bits);
} }
return pos; return pos;
} }
@ -304,6 +301,10 @@ struct BitsRange {
pos = -1; pos = -1;
return *this; return *this;
} }
private:
uint64 bits{0};
mutable int32 pos{-1};
}; };
} // namespace td } // namespace td

View File

@ -606,7 +606,7 @@ void aes_cbc_decrypt(Slice aes_key, MutableSlice aes_iv, Slice from, MutableSlic
aes_cbc_xcrypt(aes_key, aes_iv, from, to, false); aes_cbc_xcrypt(aes_key, aes_iv, from, to, false);
} }
AesCbcState::AesCbcState(Slice key256, Slice iv128) : raw_{td::SecureString(key256), td::SecureString(iv128)} { AesCbcState::AesCbcState(Slice key256, Slice iv128) : raw_{SecureString(key256), SecureString(iv128)} {
CHECK(raw_.key.size() == 32); CHECK(raw_.key.size() == 32);
CHECK(raw_.iv.size() == 16); CHECK(raw_.iv.size() == 16);
} }

View File

@ -10,7 +10,6 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/SharedSlice.h" #include "td/utils/SharedSlice.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/SharedSlice.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
namespace td { namespace td {
@ -95,11 +94,11 @@ class AesCbcState {
void encrypt(Slice from, MutableSlice to); void encrypt(Slice from, MutableSlice to);
void decrypt(Slice from, MutableSlice to); void decrypt(Slice from, MutableSlice to);
struct Raw { struct Raw {
SecureString key; SecureString key;
SecureString iv; SecureString iv;
}; };
const Raw &raw() const { const Raw &raw() const {
return raw_; return raw_;
} }

View File

@ -33,6 +33,7 @@ template <>
BufferSlice create_empty<BufferSlice>(size_t size) { BufferSlice create_empty<BufferSlice>(size_t size) {
return BufferSlice{size}; return BufferSlice{size};
} }
template <> template <>
SecureString create_empty<SecureString>(size_t size) { SecureString create_empty<SecureString>(size_t size) {
return SecureString{size}; return SecureString{size};
@ -45,15 +46,8 @@ Result<T> read_file_impl(CSlice path, int64 size, int64 offset) {
if (offset < 0 || offset > file_size) { if (offset < 0 || offset > file_size) {
return Status::Error("Failed to read file: invalid offset"); return Status::Error("Failed to read file: invalid offset");
} }
if (size == -1) { if (size < 0 || size > file_size - offset) {
size = file_size - offset; size = file_size - offset;
} else if (size >= 0) {
if (size + offset > file_size) {
size = file_size - offset;
}
}
if (size < 0) {
return Status::Error("Failed to read file: invalid size");
} }
auto content = create_empty<T>(narrow_cast<size_t>(size)); auto content = create_empty<T>(narrow_cast<size_t>(size));
TRY_RESULT(got_size, from_file.pread(as_mutable_slice(content), offset)); TRY_RESULT(got_size, from_file.pread(as_mutable_slice(content), offset));
@ -193,4 +187,5 @@ Status atomic_write_file(CSlice path, Slice data, CSlice path_tmp) {
TRY_STATUS(write_file(path_tmp, data, options)); TRY_STATUS(write_file(path_tmp, data, options));
return rename(path_tmp, path); return rename(path_tmp, path);
} }
} // namespace td } // namespace td

View File

@ -9,7 +9,6 @@
#include "td/utils/buffer.h" #include "td/utils/buffer.h"
#include "td/utils/SharedSlice.h" #include "td/utils/SharedSlice.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/SharedSlice.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
namespace td { namespace td {
@ -21,15 +20,15 @@ Result<SecureString> read_file_secure(CSlice path, int64 size = -1, int64 offset
Status copy_file(CSlice from, CSlice to, int64 size = -1) TD_WARN_UNUSED_RESULT; Status copy_file(CSlice from, CSlice to, int64 size = -1) TD_WARN_UNUSED_RESULT;
struct WriteFileOptions { struct WriteFileOptions {
bool need_sync = true; bool need_sync = false;
bool need_lock = true; bool need_lock = true;
}; };
Status write_file(CSlice to, Slice data, WriteFileOptions options = {}) TD_WARN_UNUSED_RESULT; Status write_file(CSlice to, Slice data, WriteFileOptions options = {}) TD_WARN_UNUSED_RESULT;
string clean_filename(CSlice name); string clean_filename(CSlice name);
// write file and ensure that it either fully overriden with new data, or left intact. // writes data to file and ensures that the file is either fully overriden, or is left intact
// Uses path_tmp to temporary storat data, than calls rename // uses path_tmp to temporary store data, then calls rename
Status atomic_write_file(CSlice path, Slice data, CSlice path_tmp = {}); Status atomic_write_file(CSlice path, Slice data, CSlice path_tmp = {});
} // namespace td } // namespace td

View File

@ -11,9 +11,9 @@
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/StringBuilder.h" #include "td/utils/StringBuilder.h"
#include <set>
#include <tuple> #include <tuple>
#include <utility> #include <utility>
#include <set>
namespace td { namespace td {
namespace format { namespace format {

View File

@ -14,6 +14,7 @@
#include <atomic> #include <atomic>
#include <cstdlib> #include <cstdlib>
#include <limits>
#include <mutex> #include <mutex>
#if TD_ANDROID #if TD_ANDROID
@ -268,8 +269,8 @@ namespace {
std::mutex sdl_mutex; std::mutex sdl_mutex;
int sdl_cnt = 0; int sdl_cnt = 0;
int sdl_verbosity = 0; int sdl_verbosity = 0;
} // namespace } // namespace
ScopedDisableLog::ScopedDisableLog() { ScopedDisableLog::ScopedDisableLog() {
std::unique_lock<std::mutex> guard(sdl_mutex); std::unique_lock<std::mutex> guard(sdl_mutex);
if (sdl_cnt == 0) { if (sdl_cnt == 0) {

View File

@ -150,6 +150,9 @@ struct LogOptions {
add_info = other.add_info; add_info = other.add_info;
return *this; return *this;
} }
LogOptions(LogOptions &&) = default; // i.e. deleted
LogOptions &operator=(LogOptions &&) = default; // i.e. deleted
~LogOptions() = default;
}; };
extern LogOptions log_options; extern LogOptions log_options;
@ -163,6 +166,10 @@ inline int get_verbosity_level() {
class ScopedDisableLog { class ScopedDisableLog {
public: public:
ScopedDisableLog(); ScopedDisableLog();
ScopedDisableLog(const ScopedDisableLog &) = delete;
ScopedDisableLog &operator=(const ScopedDisableLog &) = delete;
ScopedDisableLog(ScopedDisableLog &&) = delete;
ScopedDisableLog &operator=(ScopedDisableLog &&) = delete;
~ScopedDisableLog(); ~ScopedDisableLog();
}; };

View File

@ -40,12 +40,11 @@ vector<T> full_split(T s, char delimiter = ' ', size_t max_parts = std::numeric_
while (result.size() + 1 < max_parts) { while (result.size() + 1 < max_parts) {
auto delimiter_pos = s.find(delimiter); auto delimiter_pos = s.find(delimiter);
if (delimiter_pos == string::npos) { if (delimiter_pos == string::npos) {
result.push_back(std::move(s)); break;
return result;
} else {
result.push_back(s.substr(0, delimiter_pos));
s = s.substr(delimiter_pos + 1);
} }
result.push_back(s.substr(0, delimiter_pos));
s = s.substr(delimiter_pos + 1);
} }
result.push_back(std::move(s)); result.push_back(std::move(s));
return result; return result;
@ -349,10 +348,14 @@ Result<typename std::enable_if<std::is_unsigned<T>::value, T>::type> hex_to_inte
auto begin = str.begin(); auto begin = str.begin();
auto end = str.end(); auto end = str.end();
while (begin != end) { while (begin != end) {
if (!is_hex_digit(*begin)) { T digit = hex_to_int(*begin++);
return Status::Error("not a hex digit"); if (digit == 16) {
return Status::Error("Not a hex digit");
} }
integer_value = static_cast<T>(integer_value * 16 + hex_to_int(*begin++)); if (integer_value > std::numeric_limits<T>::max() / 16) {
return Status::Error("Hex number overflow");
}
integer_value = integer_value * 16 + digit;
} }
return integer_value; return integer_value;
} }
@ -380,8 +383,8 @@ string url_encode(Slice data);
namespace detail { namespace detail {
template <class T, class U> template <class T, class U>
struct is_same_signedness : public std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value> { struct is_same_signedness
}; : public std::integral_constant<bool, std::is_signed<T>::value == std::is_signed<U>::value> {};
template <class T, class Enable = void> template <class T, class Enable = void>
struct safe_undeflying_type { struct safe_undeflying_type {

View File

@ -64,7 +64,7 @@ class optional {
return res; return res;
} }
td::optional<T> copy() const { optional<T> copy() const {
if (*this) { if (*this) {
return value(); return value();
} }

View File

@ -15,7 +15,6 @@
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include <atomic> #include <atomic>
#include <cassert>
namespace td { namespace td {
@ -23,7 +22,9 @@ namespace td {
template <int id> template <int id>
static FileFd &get_file_fd() { static FileFd &get_file_fd() {
static FileFd result = FileFd::from_native_fd(NativeFd(id, true)); static FileFd result = FileFd::from_native_fd(NativeFd(id, true));
static auto guard = ScopeExit() + [&] { result.move_as_native_fd().release(); }; static auto guard = ScopeExit() + [&] {
result.move_as_native_fd().release();
};
return result; return result;
} }
@ -43,7 +44,9 @@ static FileFd &get_file_fd() {
static auto handle = GetStdHandle(id); static auto handle = GetStdHandle(id);
LOG_IF(FATAL, handle == INVALID_HANDLE_VALUE) << "Failed to GetStdHandle " << id; LOG_IF(FATAL, handle == INVALID_HANDLE_VALUE) << "Failed to GetStdHandle " << id;
static FileFd result = FileFd::from_native_fd(NativeFd(handle, true)); static FileFd result = FileFd::from_native_fd(NativeFd(handle, true));
static auto guard = ScopeExit() + [&] { result.move_as_native_fd().release(); }; static auto guard = ScopeExit() + [&] {
result.move_as_native_fd().release();
};
#else #else
static FileFd result; static FileFd result;
#endif #endif

View File

@ -101,8 +101,6 @@ void Epoll::run(int timeout_ms) {
if (event->events & EPOLLRDHUP) { if (event->events & EPOLLRDHUP) {
event->events &= ~EPOLLRDHUP; event->events &= ~EPOLLRDHUP;
flags = flags | PollFlags::Close(); flags = flags | PollFlags::Close();
// flags |= Fd::Close;
// TODO
} }
#endif #endif
if (event->events & EPOLLHUP) { if (event->events & EPOLLHUP) {

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "td/utils/port/detail/ThreadPthread.h" #include "td/utils/port/detail/ThreadPthread.h"
char disable_linker_warning_about_empty_file_thread_pthread_cpp TD_UNUSED; char disable_linker_warning_about_empty_file_thread_pthread_cpp TD_UNUSED;

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#pragma once #pragma once
#include <cerrno> #include <cerrno>

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "td/utils/port/rlimit.h" #include "td/utils/port/rlimit.h"
#include "td/utils/port/config.h" #include "td/utils/port/config.h"
@ -20,76 +19,79 @@
namespace td { namespace td {
#if TD_PORT_POSIX #if TD_PORT_POSIX
static int get_resource(ResourceLimitType type) {
namespace { switch (type) {
int get_rlimit_type(ResourceLimitType rlim_type) {
switch (rlim_type) {
case ResourceLimitType::NoFile: case ResourceLimitType::NoFile:
return RLIMIT_NOFILE; return RLIMIT_NOFILE;
case ResourceLimitType::Rss:
return RLIMIT_RSS;
default: default:
UNREACHABLE(); UNREACHABLE();
return -1;
} }
} }
} // namespace
td::Status set_resource_limit(ResourceLimitType rlim_type, td::uint64 value, td::uint64 cap) {
if (cap && value > cap) {
return td::Status::Error("setrlimit(): bad argument");
}
int resource = get_rlimit_type(rlim_type);
struct rlimit r;
if (getrlimit(resource, &r) < 0) {
return td::Status::PosixError(errno, "failed getrlimit()");
}
if (cap) {
r.rlim_max = cap;
} else if (r.rlim_max < value) {
r.rlim_max = value;
}
r.rlim_cur = value;
if (setrlimit(resource, &r) < 0) {
return td::Status::PosixError(errno, "failed setrlimit()");
}
return td::Status::OK();
}
td::Status set_maximize_resource_limit(ResourceLimitType rlim_type, td::uint64 value) {
int resource = get_rlimit_type(rlim_type);
struct rlimit r;
if (getrlimit(resource, &r) < 0) {
return td::Status::PosixError(errno, "failed getrlimit()");
}
if (r.rlim_max < value) {
auto t = r;
t.rlim_cur = value;
t.rlim_max = value;
if (setrlimit(resource, &t) >= 0) {
return td::Status::OK();
}
}
r.rlim_cur = value < r.rlim_max ? value : r.rlim_max;
if (setrlimit(resource, &r) < 0) {
return td::Status::PosixError(errno, "failed setrlimit()");
}
return td::Status::OK();
}
#else
td::Status set_resource_limit(ResourceLimitType rlim, td::uint64 value) {
return td::Status::Error("setrlimit not implemented on WINDOWS");
}
td::Status set_maximize_resource_limit(ResourceLimitType rlim, td::uint64 value) {
return td::Status::OK();
}
#endif #endif
} // namespace td Status set_resource_limit(ResourceLimitType type, uint64 value, uint64 max_value) {
#if TD_PORT_POSIX
if (max_value != 0 && value > max_value) {
return Status::Error("New resource limit value must not be bigger than max_value");
}
int resource = get_resource(type);
rlimit rlim;
if (getrlimit(resource, &rlim) == -1) {
return OS_ERROR("Failed to get current resource limit");
}
TRY_RESULT(new_value, narrow_cast_safe<rlim_t>(value));
TRY_RESULT(new_max_value, narrow_cast_safe<rlim_t>(max_value));
if (new_max_value) {
rlim.rlim_max = new_max_value;
} else if (rlim.rlim_max < new_value) {
rlim.rlim_max = new_value;
}
rlim.rlim_cur = new_value;
if (setrlimit(resource, &rlim) < 0) {
return OS_ERROR("Failed to set resource limit");
}
return Status::OK();
#elif TD_PORT_WINDOWS
return Status::OK(); // Windows has no limits
#endif
}
Status set_maximize_resource_limit(ResourceLimitType type, uint64 value) {
#if TD_PORT_POSIX
int resource = get_resource(type);
rlimit rlim;
if (getrlimit(resource, &rlim) == -1) {
return OS_ERROR("Failed to get current resource limit");
}
TRY_RESULT(new_value, narrow_cast_safe<rlim_t>(value));
if (rlim.rlim_max < new_value) {
// trying to increase rlim_max
rlimit new_rlim;
new_rlim.rlim_cur = new_value;
new_rlim.rlim_max = new_value;
if (setrlimit(resource, &new_rlim) >= 0) {
return Status::OK();
}
// do not increase rlim_max if have no rights
new_value = rlim.rlim_max;
}
rlim.rlim_cur = new_value;
if (setrlimit(resource, &rlim) < 0) {
return OS_ERROR("Failed to set resource limit");
}
return Status::OK();
#elif TD_PORT_WINDOWS
return Status::OK(); // Windows has no limits
#endif
}
} // namespace td

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#pragma once #pragma once
#include "td/utils/common.h" #include "td/utils/common.h"
@ -12,8 +11,10 @@
namespace td { namespace td {
enum class ResourceLimitType { NoFile, Rss }; enum class ResourceLimitType { NoFile };
Status set_resource_limit(ResourceLimitType type, uint64 value, uint64 max_value = 0);
Status set_maximize_resource_limit(ResourceLimitType type, uint64 value);
td::Status set_resource_limit(ResourceLimitType rlim_type, td::uint64 value, td::uint64 cap = 0);
td::Status set_maximize_resource_limit(ResourceLimitType rlim, td::uint64 value);
} // namespace td } // namespace td

View File

@ -320,8 +320,8 @@ static void default_failure_signal_handler(int sig) {
Status set_default_failure_signal_handler() { Status set_default_failure_signal_handler() {
#if TD_PORT_POSIX #if TD_PORT_POSIX
Stdin(); // init static variables before atexit Stdin(); // init static variables before atexit
#endif
std::atexit(block_stdin); std::atexit(block_stdin);
#endif
TRY_STATUS(setup_signals_alt_stack()); TRY_STATUS(setup_signals_alt_stack());
TRY_STATUS(set_signal_handler(SignalType::Abort, default_failure_signal_handler)); TRY_STATUS(set_signal_handler(SignalType::Abort, default_failure_signal_handler));
TRY_STATUS(set_signal_handler(SignalType::Error, default_failure_signal_handler)); TRY_STATUS(set_signal_handler(SignalType::Error, default_failure_signal_handler));

View File

@ -12,4 +12,4 @@ namespace td {
Slice get_operating_system_version(); Slice get_operating_system_version();
} } // namespace td

View File

@ -4,12 +4,13 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "td/utils/port/user.h" #include "td/utils/port/user.h"
#include "td/utils/port/config.h" #include "td/utils/port/config.h"
#if TD_PORT_POSIX #if TD_PORT_POSIX
#include "td/utils/logging.h"
#include <grp.h> #include <grp.h>
#include <pwd.h> #include <pwd.h>
#if TD_DARWIN || TD_FREEBSD || TD_NETBSD #if TD_DARWIN || TD_FREEBSD || TD_NETBSD

View File

@ -4,12 +4,13 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#pragma once #pragma once
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
namespace td { namespace td {
Status change_user(CSlice username, CSlice groupname = CSlice()); Status change_user(CSlice username, CSlice groupname = CSlice());
}
} // namespace td

View File

@ -202,7 +202,7 @@ bool TestsRunner::run_all_step() {
auto passed = Time::now() - state_.start; auto passed = Time::now() - state_.start;
auto real_passed = Time::now_unadjusted() - state_.start_unadjusted; auto real_passed = Time::now_unadjusted() - state_.start_unadjusted;
if (real_passed + 1e-9 > passed) { if (real_passed + 1e-6 > passed) {
LOG(ERROR) << format::as_time(passed); LOG(ERROR) << format::as_time(passed);
} else { } else {
LOG(ERROR) << format::as_time(passed) << " real[" << format::as_time(real_passed) << "]"; LOG(ERROR) << format::as_time(passed) << " real[" << format::as_time(real_passed) << "]";

View File

@ -13,7 +13,6 @@
#include "td/utils/port/thread.h" #include "td/utils/port/thread.h"
#include "td/utils/Random.h" #include "td/utils/Random.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/Span.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
#include <atomic> #include <atomic>
@ -32,17 +31,19 @@ class RandomSteps {
public: public:
struct Step { struct Step {
std::function<void()> func; std::function<void()> func;
td::uint32 weight; uint32 weight;
}; };
RandomSteps(std::vector<Step> steps) : steps_(std::move(steps)) {
for (auto &step : steps_) { explicit RandomSteps(vector<Step> steps) : steps_(std::move(steps)) {
for (const auto &step : steps_) {
steps_sum_ += step.weight; steps_sum_ += step.weight;
} }
} }
template <class Random> template <class Random>
void step(Random &rnd) { void step(Random &rnd) const {
auto w = rnd() % steps_sum_; auto w = rnd() % steps_sum_;
for (auto &step : steps_) { for (const auto &step : steps_) {
if (w < step.weight) { if (w < step.weight) {
step.func(); step.func();
break; break;
@ -52,8 +53,8 @@ class RandomSteps {
} }
private: private:
std::vector<Step> steps_; vector<Step> steps_;
td::int32 steps_sum_ = 0; int32 steps_sum_ = 0;
}; };
class RegressionTester { class RegressionTester {

View File

@ -11,7 +11,6 @@
#include "td/utils/misc.h" #include "td/utils/misc.h"
#include "td/utils/SharedSlice.h" #include "td/utils/SharedSlice.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/SharedSlice.h"
#include "td/utils/StackAllocator.h" #include "td/utils/StackAllocator.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
#include "td/utils/tl_parsers.h" #include "td/utils/tl_parsers.h"

View File

@ -8,12 +8,11 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/SharedSlice.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/StorerBase.h" #include "td/utils/StorerBase.h"
#include "td/utils/UInt.h" #include "td/utils/UInt.h"
#include "td/utils/SharedSlice.h"
#include <cstring> #include <cstring>
namespace td { namespace td {

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/List.h" #include "td/utils/List.h"
#include "td/utils/MovableValue.h" #include "td/utils/MovableValue.h"

View File

@ -14,7 +14,7 @@
#if !TD_THREAD_UNSUPPORTED #if !TD_THREAD_UNSUPPORTED
template <class W> template <class W>
void test_waiter_stress_one_one() { static void test_waiter_stress_one_one() {
td::Stage run; td::Stage run;
td::Stage check; td::Stage check;
@ -60,15 +60,17 @@ void test_waiter_stress_one_one() {
thread.join(); thread.join();
} }
} }
TEST(MpmcEagerWaiter, stress_one_one) { TEST(MpmcEagerWaiter, stress_one_one) {
test_waiter_stress_one_one<td::MpmcEagerWaiter>(); test_waiter_stress_one_one<td::MpmcEagerWaiter>();
} }
TEST(MpmcSleepyWaiter, stress_one_one) { TEST(MpmcSleepyWaiter, stress_one_one) {
test_waiter_stress_one_one<td::MpmcSleepyWaiter>(); test_waiter_stress_one_one<td::MpmcSleepyWaiter>();
} }
template <class W> template <class W>
void test_waiter_stress() { static void test_waiter_stress() {
td::Stage run; td::Stage run;
td::Stage check; td::Stage check;
@ -130,9 +132,11 @@ void test_waiter_stress() {
thread.join(); thread.join();
} }
} }
TEST(MpmcEagerWaiter, stress_multi) { TEST(MpmcEagerWaiter, stress_multi) {
test_waiter_stress<td::MpmcEagerWaiter>(); test_waiter_stress<td::MpmcEagerWaiter>();
} }
TEST(MpmcSleepyWaiter, stress_multi) { TEST(MpmcSleepyWaiter, stress_multi) {
test_waiter_stress<td::MpmcSleepyWaiter>(); test_waiter_stress<td::MpmcSleepyWaiter>();
} }

View File

@ -4,12 +4,10 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/misc.h" #include "td/utils/misc.h"
#include "td/utils/OptionParser.h" #include "td/utils/OptionParser.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include "td/utils/tests.h" #include "td/utils/tests.h"
TEST(OptionParser, run) { TEST(OptionParser, run) {

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/port/thread.h" #include "td/utils/port/thread.h"
#include "td/utils/SharedSlice.h" #include "td/utils/SharedSlice.h"

View File

@ -0,0 +1,173 @@
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
//
// 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/AtomicRead.h"
#include "td/utils/benchmark.h"
#include "td/utils/MpmcQueue.h"
#include "td/utils/port/thread.h"
#include "td/utils/StealingQueue.h"
#include "td/utils/tests.h"
#include <atomic>
TEST(StealingQueue, very_simple) {
td::StealingQueue<int, 8> q;
q.local_push(1, [](auto x) { UNREACHABLE(); });
int x;
CHECK(q.local_pop(x));
ASSERT_EQ(1, x);
}
TEST(AtomicRead, simple) {
td::Stage run;
td::Stage check;
std::size_t threads_n = 10;
td::vector<td::thread> threads;
int x{0};
std::atomic<int> version{0};
td::int64 res = 0;
for (std::size_t i = 0; i < threads_n; i++) {
threads.emplace_back([&, id = static_cast<td::uint32>(i)] {
for (td::uint64 round = 1; round < 10000; round++) {
run.wait(round * threads_n);
if (id == 0) {
version++;
x++;
version++;
} else {
int y = 0;
auto v1 = version.load();
y = x;
auto v2 = version.load();
if (v1 == v2 && v1 % 2 == 0) {
res += y;
}
}
check.wait(round * threads_n);
}
});
}
td::do_not_optimize_away(res);
for (auto &thread : threads) {
thread.join();
}
}
TEST(AtomicRead, simple2) {
td::Stage run;
td::Stage check;
std::size_t threads_n = 10;
td::vector<td::thread> threads;
struct Value {
td::uint64 value = 0;
char str[50] = "0 0 0 0";
};
td::AtomicRead<Value> value;
auto to_str = [](td::uint64 i) {
return PSTRING() << i << " " << i << " " << i << " " << i;
};
for (std::size_t i = 0; i < threads_n; i++) {
threads.emplace_back([&, id = static_cast<td::uint32>(i)] {
for (td::uint64 round = 1; round < 10000; round++) {
run.wait(round * threads_n);
if (id == 0) {
auto x = value.lock();
x->value = round;
auto str = to_str(round);
memcpy(x->str, str.c_str(), str.size() + 1);
} else {
Value x;
value.read(x);
LOG_CHECK(x.value == round || x.value == round - 1) << x.value << " " << round;
CHECK(x.str == to_str(x.value));
}
check.wait(round * threads_n);
}
});
}
for (auto &thread : threads) {
thread.join();
}
}
TEST(StealingQueue, simple) {
td::uint64 sum;
std::atomic<td::uint64> got_sum;
td::Stage run;
td::Stage check;
std::size_t threads_n = 10;
td::vector<td::thread> threads;
td::vector<td::StealingQueue<int, 8>> lq(threads_n);
td::MpmcQueue<int> gq(threads_n);
constexpr td::uint64 XN = 20;
td::uint64 x_sum[XN];
x_sum[0] = 0;
x_sum[1] = 1;
for (td::uint64 i = 2; i < XN; i++) {
x_sum[i] = i + x_sum[i - 1] + x_sum[i - 2];
}
td::Random::Xorshift128plus rnd(123);
for (std::size_t i = 0; i < threads_n; i++) {
threads.emplace_back([&, id = static_cast<td::uint32>(i)] {
for (td::uint64 round = 1; round < 10000; round++) {
if (id == 0) {
sum = 0;
int n = rnd() % 5;
for (int j = 0; j < n; j++) {
int x = rand() % XN;
sum += x_sum[x];
gq.push(x, id);
}
got_sum = 0;
}
run.wait(round * threads_n);
while (got_sum.load() != sum) {
auto x = [&] {
int res;
if (lq[id].local_pop(res)) {
return res;
}
if (gq.try_pop(res, id)) {
return res;
}
if (lq[id].steal(res, lq[rand() % threads_n])) {
//LOG(ERROR) << "STEAL";
return res;
}
return 0;
}();
if (x == 0) {
continue;
}
//LOG(ERROR) << x << " " << got_sum.load() << " " << sum;
got_sum.fetch_add(x, std::memory_order_relaxed);
lq[id].local_push(x - 1, [&](auto y) {
//LOG(ERROR) << "OVERFLOW";
gq.push(y, id);
});
if (x > 1) {
lq[id].local_push(x - 2, [&](auto y) { gq.push(y, id); });
}
}
check.wait(round * threads_n);
}
});
}
for (auto &thread : threads) {
thread.join();
}
}

View File

@ -9,6 +9,7 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/Heap.h" #include "td/utils/Heap.h"
#include "td/utils/Random.h" #include "td/utils/Random.h"
#include "td/utils/Span.h"
#include <cstdio> #include <cstdio>
#include <set> #include <set>
@ -25,7 +26,7 @@ TEST(Heap, sort_random_perm) {
} }
td::Random::Xorshift128plus rnd(123); td::Random::Xorshift128plus rnd(123);
td::random_shuffle(td::as_mutable_span(v), rnd); td::random_shuffle(td::as_mutable_span(v), rnd);
std::vector<td::HeapNode> nodes(n); td::vector<td::HeapNode> nodes(n);
td::KHeap<int> kheap; td::KHeap<int> kheap;
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
kheap.insert(v[i], &nodes[i]); kheap.insert(v[i], &nodes[i]);

View File

@ -4,7 +4,6 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying // 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) // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// //
#include "td/utils/benchmark.h" #include "td/utils/benchmark.h"
#include "td/utils/FileLog.h" #include "td/utils/FileLog.h"
#include "td/utils/format.h" #include "td/utils/format.h"

View File

@ -127,14 +127,14 @@ TEST(Misc, errno_tls_bug) {
event.release(); event.release();
} }
for (auto &event : events) { for (auto &event : events) {
threads.push_back(td::thread([&] { threads.emplace_back([&] {
{ {
EventFd tmp; EventFd tmp;
tmp.init(); tmp.init();
tmp.acquire(); tmp.acquire();
} }
event.acquire(); event.acquire();
})); });
} }
for (auto &thread : threads) { for (auto &thread : threads) {
thread.join(); thread.join();
@ -154,7 +154,8 @@ TEST(Misc, get_last_argument) {
} }
TEST(Misc, call_n_arguments) { TEST(Misc, call_n_arguments) {
auto f = [](int, int) {}; auto f = [](int, int) {
};
call_n_arguments<2>(f, 1, 3, 4); call_n_arguments<2>(f, 1, 3, 4);
} }
@ -253,10 +254,18 @@ static void test_remove_if(vector<int> v, const T &func, vector<int> expected) {
} }
TEST(Misc, remove_if) { TEST(Misc, remove_if) {
auto odd = [](int x) { return x % 2 == 1; }; auto odd = [](int x) {
auto even = [](int x) { return x % 2 == 0; }; return x % 2 == 1;
auto all = [](int x) { return true; }; };
auto none = [](int x) { return false; }; auto even = [](int x) {
return x % 2 == 0;
};
auto all = [](int x) {
return true;
};
auto none = [](int x) {
return false;
};
vector<int> v{1, 2, 3, 4, 5, 6}; vector<int> v{1, 2, 3, 4, 5, 6};
test_remove_if(v, odd, {2, 4, 6}); test_remove_if(v, odd, {2, 4, 6});
@ -862,7 +871,7 @@ TEST(Misc, Bits) {
TEST(Misc, BitsRange) { TEST(Misc, BitsRange) {
auto to_vec_a = [](td::uint64 x) { auto to_vec_a = [](td::uint64 x) {
std::vector<td::int32> bits; td::vector<td::int32> bits;
for (auto i : td::BitsRange(x)) { for (auto i : td::BitsRange(x)) {
bits.push_back(i); bits.push_back(i);
} }
@ -870,7 +879,7 @@ TEST(Misc, BitsRange) {
}; };
auto to_vec_b = [](td::uint64 x) { auto to_vec_b = [](td::uint64 x) {
std::vector<td::int32> bits; td::vector<td::int32> bits;
td::int32 pos = 0; td::int32 pos = 0;
while (x != 0) { while (x != 0) {
if ((x & 1) != 0) { if ((x & 1) != 0) {
@ -882,8 +891,12 @@ TEST(Misc, BitsRange) {
return bits; return bits;
}; };
auto do_check = [](std::vector<td::int32> a, std::vector<td::int32> b) { ASSERT_EQ(b, a); }; auto do_check = [](const td::vector<td::int32> &a, const td::vector<td::int32> &b) {
auto check = [&](td::uint64 x) { do_check(to_vec_a(x), to_vec_b(x)); }; ASSERT_EQ(b, a);
};
auto check = [&](td::uint64 x) {
do_check(to_vec_a(x), to_vec_b(x));
};
do_check(to_vec_a(21), {0, 2, 4}); do_check(to_vec_a(21), {0, 2, 4});
for (int x = 0; x < 100; x++) { for (int x = 0; x < 100; x++) {
@ -954,8 +967,12 @@ TEST(Misc, uint128) {
static_cast<int64>(std::numeric_limits<int32>::min()) - 1}; static_cast<int64>(std::numeric_limits<int32>::min()) - 1};
#if TD_HAVE_INT128 #if TD_HAVE_INT128
auto to_intrinsic = [](uint128_emulated num) { return uint128_intrinsic(num.hi(), num.lo()); }; auto to_intrinsic = [](uint128_emulated num) {
auto eq = [](uint128_emulated a, uint128_intrinsic b) { return a.hi() == b.hi() && a.lo() == b.lo(); }; return uint128_intrinsic(num.hi(), num.lo());
};
auto eq = [](uint128_emulated a, uint128_intrinsic b) {
return a.hi() == b.hi() && a.lo() == b.lo();
};
auto ensure_eq = [&](uint128_emulated a, uint128_intrinsic b) { auto ensure_eq = [&](uint128_emulated a, uint128_intrinsic b) {
if (!eq(a, b)) { if (!eq(a, b)) {
LOG(FATAL) << "[" << a.hi() << ";" << a.lo() << "] vs [" << b.hi() << ";" << b.lo() << "]"; LOG(FATAL) << "[" << a.hi() << ";" << a.lo() << "] vs [" << b.hi() << ";" << b.lo() << "]";

View File

@ -11,9 +11,6 @@
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/OptionParser.h" #include "td/utils/OptionParser.h"
#include "td/utils/Slice.h" #include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include <cstring>
#if TD_EMSCRIPTEN #if TD_EMSCRIPTEN
#include <emscripten.h> #include <emscripten.h>