feature add sigslot

This commit is contained in:
tqcq 2023-11-16 14:28:55 +08:00
parent 3998561a53
commit 8cd9dfba1d
34 changed files with 4885 additions and 0 deletions

3
.gitignore vendored
View File

@ -45,3 +45,6 @@ compile_commands.json
CTestTestfile.cmake
_deps
# Clion
.idea/
cmake-*

51
CMakeLists.txt Normal file
View File

@ -0,0 +1,51 @@
cmake_minimum_required(VERSION 3.10)
option(ULIB_BUILD_TESTS "Build tests" OFF)
project(ulib LANGUAGES CXX VERSION 0.1.0)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS ON)
add_library(${PROJECT_NAME} STATIC ""
src/base/location.cpp
src/strings/string_printf.cpp
src/system/system_time.cpp
src/base/task_queue_base.cpp
src/units/time_delta.cpp
src/synchronization/mutex.cpp
src/network/socket_factory.cpp
src/network/socket_address.cpp
src/network/socket_server.cpp
src/synchronization/event.cpp)
target_compile_definitions(${PROJECT_NAME} PRIVATE ULIB_LIBRARY_IMPL)
target_include_directories(${PROJECT_NAME} PUBLIC src)
target_sources(${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src//base/checks.h
${CMAKE_CURRENT_SOURCE_DIR}/src//base/checks.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/types/optional.h
${CMAKE_CURRENT_SOURCE_DIR}/src/system/export_api.h
)
if (ULIB_BUILD_TESTS)
find_package(GTest CONFIG REQUIRED)
add_executable(ulib_test ""
src/base/location_unittest.cpp)
target_link_libraries(ulib_test PRIVATE
ulib
GTest::gtest
GTest::gtest_main
GTest::gmock
GTest::gmock_main
)
target_sources(ulib_test PRIVATE
src/base/location_unittest.cpp
)
add_test(AllTestsInUlib ulib_test)
endif ()

1682
src/3party/sigslot/sigslot.h Normal file

File diff suppressed because it is too large Load Diff

27
src/base/checks.cpp Normal file
View File

@ -0,0 +1,27 @@
//
// Created by tqcq on 2023/11/16.
//
#include "checks.h"
#include <cstdlib>
#include <cstdarg>
namespace tqcq {
namespace detail {
void CheckLog(const char *expr, const char *file, int line, const char *msg, ...) {
std::fprintf(stderr, "Check failed: %s:%d \"%s\" ", file, line, expr);
if (msg) {
va_list ap;
va_start(ap, msg);
std::vfprintf(stderr, msg, ap);
va_end(ap);
}
std::fprintf(stderr, "\n");
std::abort();
}
}
}

58
src/base/checks.h Normal file
View File

@ -0,0 +1,58 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_BASE_CHECKS_H_
#define ULIB_SRC_BASE_CHECKS_H_
#include <ostream>
namespace tqcq {
namespace detail {
void CheckLog(const char* expr, const char* file, int line, const char* msg, ...);
} // namespace detail
#define ULIB_CHECK_IMPL(condition, file, line) ::tqcq::detail::CheckLog(condition, file, line, "")
#if !defined(NDEBUG) || defined(ULIB_DCHECK_ALWAYS_ON)
#define ULIB_DCHECK_IS_ON 1
#else
#define ULIB_DCHECK_IS_ON 0
#endif
#define ULIB_CHECK(condition) \
(condition) ? static_cast<void>(0) : ULIB_CHECK_IMPL(#condition, __FILE__, __LINE__)
#define ULIB_CHECK_OP(val1, val2, op) \
((val1) op (val2)) ? static_cast<void>(0) : ULIB_CHECK_OP_IMPL(#val1 " " #op " " #val2, __FILE__, __LINE__)
#define ULIB_CHECK_EQ(val1, val2) ULIB_CHECK_OP(val1, val2, ==)
#define ULIB_CHECK_NE(val1, val2) ULIB_CHECK_OP(val1, val2, !=)
#define ULIB_CHECK_LE(val1, val2) ULIB_CHECK_OP(val1, val2, <=)
#define ULIB_CHECK_LT(val1, val2) ULIB_CHECK_OP(val1, val2, <)
#define ULIB_CHECK_GE(val1, val2) ULIB_CHECK_OP(val1, val2, >=)
#define ULIB_CHECK_GT(val1, val2) ULIB_CHECK_OP(val1, val2, >)
#if ULIB_DCHECK_IS_ON
#define ULIB_DCHECK(condition) ULIB_CHECK(condition)
#define ULIB_DCHECK_EQ(val1, val2) ULIB_CHECK_EQ(val1, val2)
#define ULIB_DCHECK_NE(val1, val2) ULIB_CHECK_NE(val1, val2)
#define ULIB_DCHECK_LE(val1, val2) ULIB_CHECK_LE(val1, val2)
#define ULIB_DCHECK_LT(val1, val2) ULIB_CHECK_LT(val1, val2)
#define ULIB_DCHECK_GE(val1, val2) ULIB_CHECK_GE(val1, val2)
#define ULIB_DCHECK_GT(val1, val2) ULIB_CHECK_GT(val1, val2)
#else // ULIB_DCHECK_IS_ON
#define ULIB_DCHECK(condition) static_cast<void>(0)
#define ULIB_DCHECK_EQ(val1, val2) static_cast<void>(0)
#define ULIB_DCHECK_NE(val1, val2) static_cast<void>(0)
#define ULIB_DCHECK_LE(val1, val2) static_cast<void>(0)
#define ULIB_DCHECK_LT(val1, val2) static_cast<void>(0)
#define ULIB_DCHECK_GE(val1, val2) static_cast<void>(0)
#define ULIB_DCHECK_GT(val1, val2) static_cast<void>(0)
#endif // ULIB_DCHECK_IS_ON
#define ULIB_RATAL() ULIB_CHECK(false)
} // namespacce tqcq
#endif //ULIB_SRC_BASE_CHECKS_H_

8
src/base/inline.h Normal file
View File

@ -0,0 +1,8 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_BASE_INLINE_H_
#define ULIB_SRC_BASE_INLINE_H_
#endif //ULIB_SRC_BASE_INLINE_H_

80
src/base/location.cpp Normal file
View File

@ -0,0 +1,80 @@
//
// Created by tqcq on 2023/11/16.
//
#include "location.h"
#include "strings/string_printf.h"
namespace tqcq {
#if defined(COMPILER_MSVC)
#define RETURN_ADDRESS() _ReturnAddress()
#elif defined(COMPILER_GCC)
#define RETURN_ADDRESS() \
__builtin_extract_return_addr(__builtin_return_address(0))
#else
#define RETURN_ADDRESS() nullptr
#endif
template<char ch, int len, const char *str>
struct StrLenImpl {
static constexpr int value = StrLenImpl<str[len], len + 1, str>::value;
};
template<int len, const char *str>
struct StrLenImpl<'\0', len, str> {
static constexpr int value = len;
};
template<const char* str>
struct StrLen {
static constexpr int value = StrLenImpl<str[0], 0, str>::value;
};
template<>
struct StrLen<nullptr> {
static constexpr int value = 0;
};
// calc stripped length
constexpr char full_path[] = __FILE__;
#if defined(__clang__) && defined(_MSC_VER)
constexpr char stripped[] = "base\\location.cpp";
#else
constexpr char stripped[] = "base/location.cpp";
#endif
static_assert(StrLen<full_path>::value >= StrLen<stripped>::value,
"The file name does not match the expected prefix format.");
constexpr size_t kStrippedFilePathPrefixLength= StrLen<full_path>::value - StrLen<stripped>::value;
Location::Location() = default;
Location::Location(const Location &other) = default;
Location::Location(Location &&other) = default;
Location &Location::operator=(const Location &other) = default;
Location Location::Current(const char *function_name, const char *file_name, int line_number) {
return Location(function_name, file_name + kStrippedFilePathPrefixLength, line_number, RETURN_ADDRESS());
}
std::string Location::ToString() const {
if (has_source_info()) {
return std::string(function_name_) + "@" + file_name_ + ":" + std::to_string(line_number_);
}
return StringPrintf("pc:%p", program_counter_);
}
Location::Location(const char *function_name, const char *file_name, int line_number, const void *program_counter)
: function_name_(function_name),
file_name_(file_name),
line_number_(line_number),
program_counter_(program_counter) {
}
const void *GetProgramCounter() {
return RETURN_ADDRESS();
}
} // namespace tqcq

49
src/base/location.h Normal file
View File

@ -0,0 +1,49 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_BASE_LOCATION_H_
#define ULIB_SRC_BASE_LOCATION_H_
#include <string>
namespace tqcq {
class Location {
public:
Location();
Location(const Location &other);
Location(Location &&other);
Location &operator=(const Location &other);
static Location Current(const char *function_name = __builtin_FUNCTION(), const char *file_name = __builtin_FILE(), int line_number = __builtin_LINE());
bool operator < (const Location& other) const {
return program_counter_ < other.program_counter_;
}
bool operator == (const Location& other) const {
return program_counter_ == other.program_counter_;
}
bool has_source_info() const { return function_name_ && file_name_; }
const char *function_name() const { return function_name_; }
const char *file_name() const { return file_name_; }
int line_number() const { return line_number_; }
const void *program_counter() const { return program_counter_; }
std::string ToString() const;
private:
Location(const char *function_name, const char *file_name, int line_number, const void *program_counter);
const char *function_name_ = nullptr;
const char *file_name_ = nullptr;
int line_number_ = -1;
const void *program_counter_ = nullptr;
};
const void *GetProgramCounter();
#define FROM_HERE ::tqcq::Location::Current(__FUNCTION__, __FILE__, __LINE__)
} // namespace tqcq
#endif //ULIB_SRC_BASE_LOCATION_H_

View File

@ -0,0 +1,21 @@
//
// Created by tqcq on 2023/11/16.
//
#include "location.h"
#include <gtest/gtest.h>
#include <gmock/gmock.h>
namespace tqcq {
#define WhereAmI() (FROM_HERE)
TEST(LocationTest, CurrentYieldsCorrectValue) {
int previous_line = __LINE__;
Location here = WhereAmI();
EXPECT_NE(here.program_counter(), WhereAmI().program_counter());
EXPECT_THAT(here.file_name(), ::testing::EndsWith("location_unittest.cpp"));
EXPECT_EQ(here.line_number(), previous_line + 1);
EXPECT_STREQ("TestBody", here.function_name());
}
}

View File

@ -0,0 +1,8 @@
//
// Created by tqcq on 2023/11/16.
//
#include "scoped_clear_last_error.h"
namespace tqcq {
} // namespace tqcq

View File

@ -0,0 +1,22 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_BASE_SCOPED_CLEAR_LAST_ERROR_H_
#define ULIB_SRC_BASE_SCOPED_CLEAR_LAST_ERROR_H_
#include <errno.h>
namespace tqcq {
class ScopedClearLastError {
public:
ScopedClearLastError() : last_errno_(errno) { errno = 0; }
ScopedClearLastError(const ScopedClearLastError &) = delete;
ScopedClearLastError &operator=(const ScopedClearLastError &) = delete;
~ScopedClearLastError() { errno = last_errno_; }
private:
const int last_errno_;
};
} // namespace tqcq
#endif //ULIB_SRC_BASE_SCOPED_CLEAR_LAST_ERROR_H_

View File

@ -0,0 +1,22 @@
//
// Created by tqcq on 2023/11/16.
//
#include "task_queue_base.h"
namespace tqcq {
namespace {
thread_local TaskQueueBase *current_task_queue = nullptr;
}
TaskQueueBase::CurrentTaskQueueSetter::CurrentTaskQueueSetter(TaskQueueBase *task_queue)
: previous_(current_task_queue) {
current_task_queue = task_queue;
}
TaskQueueBase::CurrentTaskQueueSetter::~CurrentTaskQueueSetter() {
current_task_queue = previous_;
}
} // namespace tqcq

View File

@ -0,0 +1,91 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_BASE_TASK_QUEUE_BASE_H_
#define ULIB_SRC_BASE_TASK_QUEUE_BASE_H_
#include <functional>
#include "location.h"
#include "units/time_delta.h"
namespace tqcq {
class TaskQueueBase {
public:
enum class DelayPrecision {
kLow,
kHigh,
};
// 销毁队列
virtual void Delete() = 0;
void PostTask(std::function<void()> task,
const Location &location = Location::Current()) {
PostTaskImpl(std::move(task), {}, location);
};
void PostDelayedTask(std::function<void()> task,
TimeDelta delay,
const Location &location = Location::Current()) {
PostDelayedTaskImpl(std::move(task), delay, {}, location);
};
void PostDelayedHighPrecisionTask(
std::function<void()> task,
TimeDelta delay,
const Location &location = Location::Current()) {
PostDelayedTaskTraits traits;
traits.high_precision = true;
PostDelayedTaskImpl(std::move(task), delay, traits, location);
}
void PostDelayedTaskWithPrecision(
DelayPrecision precision,
std::function<void()> task,
TimeDelta delay,
const Location &location = Location::Current()) {
switch (precision) {
case DelayPrecision::kLow:PostDelayedTask(std::move(task), delay, location);
break;
case DelayPrecision::kHigh:PostDelayedHighPrecisionTask(std::move(task), delay, location);
break;
}
};
static TaskQueueBase *Current();
bool IsCurrent() const { return Current() == this; }
protected:
struct PostTaskTraits {};
struct PostDelayedTaskTraits {
bool high_precision = false;
};
virtual void PostTaskImpl(std::function<void()> task,
const PostTaskTraits &traits,
const Location &location) = 0;
virtual void PostDelayedTaskImpl(std::function<void()> task,
TimeDelta delay,
const PostDelayedTaskTraits &traits,
const Location &location) = 0;
class CurrentTaskQueueSetter {
public:
explicit CurrentTaskQueueSetter(TaskQueueBase *task_queue);
CurrentTaskQueueSetter(const CurrentTaskQueueSetter &) = delete;
CurrentTaskQueueSetter &operator=(const CurrentTaskQueueSetter &) = delete;
~CurrentTaskQueueSetter();
private:
TaskQueueBase *const previous_;
};
};
struct TaskQueueDeleter {
void operator()(TaskQueueBase *task_queue) const {
task_queue->Delete();
}
};
} // namespace tqcq
#endif //ULIB_SRC_BASE_TASK_QUEUE_BASE_H_

8
src/network/socket.cpp Normal file
View File

@ -0,0 +1,8 @@
//
// Created by tqcq on 2023/11/16.
//
#include "socket.h"
namespace tqcq {
} // namespace tqcq

57
src/network/socket.h Normal file
View File

@ -0,0 +1,57 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_NETWORK_SOCKET_H_
#define ULIB_SRC_NETWORK_SOCKET_H_
#include <errno.h>
#include <cstdint>
#include <sys/types.h>
#include "network/socket_address.h"
#include "3party/sigslot/sigslot.h"
namespace tqcq {
inline bool IsBlockingError(int e) {
return (e == EWOULDBLOCK) || (e == EAGAIN) || (e == EINPROGRESS);
}
class Socket {
public:
virtual ~Socket() = default;
Socket(const Socket &) = delete;
Socket &operator=(const Socket &) = delete;
virtual SocketAddress GetLocalAddress() const = 0;
virtual SocketAddress GetRemoteAddress() const = 0;
virtual int Bind(const SocketAddress &addr) = 0;
virtual int Connect(const SocketAddress &addr) = 0;
virtual int Send(const void *pv, size_t cb) = 0;
virtual int SendTo(const void *pv, size_t cb, const SocketAddress &addr) = 0;
virtual int Recv(void *pv, size_t cb, int64_t *timestamp) = 0;
virtual int RecvFrom(void *pv,
size_t cb,
SocketAddress *paddr,
int64_t *timestamp) = 0;
virtual int Listen(int backlog) = 0;
virtual Socket *Accept(SocketAddress *paddr) = 0;
virtual int Close() = 0;
virtual int GetError() const = 0;
virtual void SetError(int error) = 0;
inline bool IsBlocking() const { return IsBlockingError(GetError()); }
enum ConnState { CS_CLOSED, CS_CONNECTING, CS_CONNECTED };
virtual ConnState GetState() const = 0;
sigslot::signal1<Socket *, sigslot::multi_threaded_local> SignalReadEvent;
sigslot::signal1<Socket *, sigslot::multi_threaded_local> SignalWriteEvent;
sigslot::signal1<Socket *> SignalConnectEvent;
sigslot::signal2<Socket *, int> SignalCloseEvent;
};
} // namespace tqcq
#endif //ULIB_SRC_NETWORK_SOCKET_H_

View File

@ -0,0 +1,8 @@
//
// Created by tqcq on 2023/11/16.
//
#include "socket_address.h"
namespace tqcq {
} // namespace tqcq

View File

@ -0,0 +1,15 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_NETWORK_SOCKET_ADDRESS_H_
#define ULIB_SRC_NETWORK_SOCKET_ADDRESS_H_
namespace tqcq {
class SocketAddress {
};
} // namespace tqcq
#endif //ULIB_SRC_NETWORK_SOCKET_ADDRESS_H_

View File

@ -0,0 +1,8 @@
//
// Created by tqcq on 2023/11/16.
//
#include "socket_factory.h"
namespace tqcq {
} // namespace tqcq

View File

@ -0,0 +1,20 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_NETWORK_SOCKET_FACTORY_H_
#define ULIB_SRC_NETWORK_SOCKET_FACTORY_H_
#include "socket.h"
namespace tqcq {
class SocketFactory {
public:
virtual ~SocketFactory() = default;
virtual Socket* CreateSocket(int family, int type) = 0;
};
} // namespace tqcq
#endif //ULIB_SRC_NETWORK_SOCKET_FACTORY_H_

View File

@ -0,0 +1,8 @@
//
// Created by tqcq on 2023/11/16.
//
#include "socket_server.h"
namespace tqcq {
} // namespace tqcq

View File

@ -0,0 +1,31 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_NETWORK_SOCKET_SERVER_H_
#define ULIB_SRC_NETWORK_SOCKET_SERVER_H_
#include "network/socket_factory.h"
#include "units/time_delta.h"
#include "synchronization/event.h"
namespace tqcq {
class Thread;
class SocketServer : public SocketFactory {
public:
static const TimeDelta kForever; // = Event::kForever;
static std::unique_ptr<SocketServer> CreateDefault();
virtual void SetMessageQueue(Thread* queue) {}
virtual bool Wait(TimeDelta max_wait_duration, bool process_io) = 0;
virtual void WakeUp() = 0;
};
} // namespace tqcq
#endif //ULIB_SRC_NETWORK_SOCKET_SERVER_H_

View File

@ -0,0 +1,80 @@
//
// Created by tqcq on 2023/11/16.
//
#include "string_printf.h"
#include <stdarg.h>
#include <vector>
#include "base/scoped_clear_last_error.h"
namespace tqcq {
std::string StringPrintf(const char *format, ...) {
va_list ap;
va_start(ap, format);
std::string result;
StringAppendV(&result, format, ap);
va_end(ap);
return result;
}
void StringAppendF(std::string *dst, const char *format, ...) {
va_list ap;
va_start(ap, format);
StringAppendV(dst, format, ap);
va_end(ap);
}
template<typename CharT>
void StringAppendV(std::basic_string<CharT> *dst, const char *format, va_list ap) {
// 32MB stack buffer, if the string is larger than this, failed
const size_t kMaxBufferSize = 32 * 1024 * 1024;
CharT stack_buf[1024];
va_list ap_copy;
va_copy(ap_copy, ap);
ScopedClearLastError last_error;
int result = vsnprintf(stack_buf, sizeof(stack_buf), format, ap_copy);
va_end(ap_copy);
if (result >= 0 && static_cast<size_t>(result) < sizeof(stack_buf)) {
dst->append(stack_buf, static_cast<size_t>(result));
return;
}
size_t mem_length = sizeof(stack_buf);
while (true) {
if (result < 0) {
if (errno != 0 && errno != EOVERFLOW) {
return;
}
mem_length *= 2;
} else {
// increase 1 characters
mem_length = static_cast<size_t>(result) + 1;
}
if (mem_length > kMaxBufferSize) {
// log
return;
}
std::vector<CharT> mem_buf(mem_length);
va_copy(ap_copy, ap);
result = vsnprintf(mem_buf.data(), mem_length, format, ap_copy);
va_end(ap_copy);
if (result >= 0 && static_cast<size_t>(result) < mem_length) {
dst->append(mem_buf.data(), static_cast<size_t>(result));
return;
}
}
}
void StringAppendV(std::string *dst, const char *format, va_list ap) {
StringAppendV<char>(dst, format, ap);
}
} // namespace tqcq

View File

@ -0,0 +1,18 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_STRINGS_STRING_PRINTF_H_
#define ULIB_SRC_STRINGS_STRING_PRINTF_H_
#include <string>
#include <stdarg.h>
namespace tqcq {
std::string StringPrintf(const char* format, ...);
void StringAppendF(std::string* dst, const char* format, ...);
void StringAppendV(std::string* dst, const char* format, va_list ap);
} // namespace tqcq
#endif //ULIB_SRC_STRINGS_STRING_PRINTF_H_

View File

@ -0,0 +1,80 @@
//
// Created by tqcq on 2023/11/16.
//
#include "event.h"
#include <pthread.h>
#include <sys/time.h>
namespace tqcq {
const TimeDelta Event::kForever = TimeDelta::PlusInfinity();
Event::Event() : Event(false, false) {}
Event::Event(bool manua_reset, bool initially_signaled)
: is_manual_reset_(manua_reset), event_status_(initially_signaled) {
pthread_mutex_init(&mutex_, nullptr);
pthread_cond_init(&cond_, nullptr);
}
Event::~Event() {
pthread_mutex_destroy(&mutex_);
pthread_cond_destroy(&cond_);
}
void Event::Set() {
pthread_mutex_lock(&mutex_);
event_status_ = true;
pthread_cond_broadcast(&cond_);
pthread_mutex_unlock(&mutex_);
}
void Event::Reset() {
pthread_mutex_lock(&mutex_);
event_status_ = false;
pthread_mutex_unlock(&mutex_);
}
namespace {
timespec GetTimespec(TimeDelta duration_from_now) {
timespec ts;
// use clock ?
if (false) {
// clock_gettime(CLOCK_MONOTONIC, &ts);
} else {
timeval tv;
gettimeofday(&tv, nullptr);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000;
}
int64_t microsecs_from_now = duration_from_now.us();
ts.tv_sec += microsecs_from_now / 1000000;
ts.tv_nsec += (microsecs_from_now % 1000000) * 1000;
if (ts.tv_nsec >= 1000000000) {
ts.tv_sec++;
ts.tv_nsec -= 1000000000;
}
return ts;
}
}
bool Event::Wait(TimeDelta give_up_after, TimeDelta warn_after) {
timespec ts;
int error = 0;
pthread_mutex_lock(&mutex_);
if (give_up_after.IsPlusInfinity()) {
error = pthread_cond_wait(&cond_, &mutex_);
} else {
ts = GetTimespec(give_up_after);
error = pthread_cond_timedwait(&cond_, &mutex_, &ts);
}
return error;
}
} // namespace tqcq

View File

@ -0,0 +1,41 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_SYNCHRONIZATION_EVENT_H_
#define ULIB_SRC_SYNCHRONIZATION_EVENT_H_
#include "units/time_delta.h"
#include <pthread.h>
namespace tqcq {
class Event {
public:
static const TimeDelta kForever; // = TimeDelta::PlusInfinity();
Event();
Event(bool manua__reset, bool initially_signaled);
Event(const Event &) = delete;
~Event();
void Set();
void Reset();
bool Wait(TimeDelta give_up_after, TimeDelta warn_after);
bool Wait(TimeDelta give_up_after) {
// 如果是无限等待那么超过3秒就可能是死锁了
// 如果使用者有明确的等待时间,那么不用警告
return Wait(give_up_after, give_up_after.IsPlusInfinity()
? TimeDelta::Seconds(3)
: kForever);
}
private:
const bool is_manual_reset_;
bool event_status_;
pthread_mutex_t mutex_;
pthread_cond_t cond_;
};
} // namespace tqcq
#endif //ULIB_SRC_SYNCHRONIZATION_EVENT_H_

View File

@ -0,0 +1,8 @@
//
// Created by tqcq on 2023/11/16.
//
#include "mutex.h"
namespace tqcq {
} // namespace tqcq

View File

@ -0,0 +1,39 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_SYNCHRONIZATION_MUTEX_H_
#define ULIB_SRC_SYNCHRONIZATION_MUTEX_H_
#include <mutex>
namespace tqcq {
class Mutex final {
public:
Mutex() = default;
Mutex(const Mutex &) = delete;
Mutex &operator=(const Mutex &) = delete;
void Lock() { mutex_.lock(); }
bool TryLock() { return mutex_.try_lock(); }
void Unlock() { mutex_.unlock(); }
void AssertHeld() const {};
private:
std::mutex mutex_;
};
class MutexLock final {
public:
MutexLock(const MutexLock &) = delete;
MutexLock &operator=(const MutexLock &) = delete;
explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
~MutexLock() { mu_->Unlock(); }
private:
Mutex *const mu_;
};
} // namespace tqcq
#endif //ULIB_SRC_SYNCHRONIZATION_MUTEX_H_

23
src/system/export_api.h Normal file
View File

@ -0,0 +1,23 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_SYSTEM_EXPORTAPI_H_
#define ULIB_SRC_SYSTEM_EXPORTAPI_H_
#ifdef _WIN32
#ifdef ULIB_LIBRARY_IMPL
#define ULIB_EXPORT __declspec(dllexport)
#else
#define ULIB_EXPORT __declspec(dllimport)
#endif
#else // _WIN32
#if __has_attribute(visibility) && defined(ULIB_LIBRARY_IMPL)
#define ULIB_EXPORT __attribute__((visibility("default")))
#endif
#endif // _WIN32
#endif //ULIB_SRC_SYSTEM_EXPORTAPI_H_

View File

@ -0,0 +1,16 @@
//
// Created by tqcq on 2023/11/16.
//
#include "system_time.h"
#include <sys/time.h>
namespace tqcq {
//TODO 后续使用系统相关API获取时间
int64_t SystemTimeNanos() {
struct timeval tv;
gettimeofday(&tv, nullptr);
return tv.tv_sec * 1000000000LL + tv.tv_usec * 1000LL;
}
} // namespace tqcq

14
src/system/system_time.h Normal file
View File

@ -0,0 +1,14 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_SYSTEM_SYSTEM_TIME_H_
#define ULIB_SRC_SYSTEM_SYSTEM_TIME_H_
#include <cstdint>
namespace tqcq {
int64_t SystemTimeNanos();
} // namespace tqcq
#endif //ULIB_SRC_SYSTEM_SYSTEM_TIME_H_

2091
src/types/optional.h Normal file

File diff suppressed because it is too large Load Diff

8
src/units/time_delta.cpp Normal file
View File

@ -0,0 +1,8 @@
//
// Created by tqcq on 2023/11/16.
//
#include "time_delta.h"
namespace tqcq {
} // namespace tqcq

81
src/units/time_delta.h Normal file
View File

@ -0,0 +1,81 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_UNITS_TIME_DELTA_H_
#define ULIB_SRC_UNITS_TIME_DELTA_H_
#include <cstdint>
#include <type_traits>
#include <string>
#include "units/unit_base.h"
namespace tqcq {
class TimeDelta final : public RelativeUnit<TimeDelta>{
public:
TimeDelta() = delete;
template<typename T>
static constexpr TimeDelta Minutes(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return Seconds(value * 60);
}
template<typename T>
static constexpr TimeDelta Seconds(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return TimeDelta(value * 1000000);
}
template<typename T>
static constexpr TimeDelta Millis(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return TimeDelta(value * 1000);
}
template<typename T>
static constexpr TimeDelta Micros(T value) {
static_assert(std::is_arithmetic<T>::value, "");
return FromValue(value);
}
static constexpr TimeDelta Max() {
return TimeDelta::Micros(std::numeric_limits<int64_t>::max());
}
template<typename T = int64_t>
constexpr T seconds() const { return value_ / 1000000; }
template<typename T = int64_t>
constexpr T ms() const { return value_ / 1000; }
template<typename T = int64_t>
constexpr T us() const { return value_; }
template<typename T = int64_t>
constexpr T ns() const { return value_ * 1000; }
constexpr TimeDelta Abs() const {
return us() < 0 ? TimeDelta::Micros(-us()) : *this;
}
private:
friend class UnitBase<TimeDelta>;
int64_t value_;
using RelativeUnit::RelativeUnit;
static constexpr bool one_sided = false;
};
std::string ToString(const TimeDelta &value);
inline std::string ToString(const TimeDelta &value) {
return std::to_string(value.us());
}
inline std::ostream& operator<<(std::ostream& stream, const TimeDelta& value) {
return stream << ToString(value);
}
} // namespace tqcq
#endif //ULIB_SRC_UNITS_TIME_DELTA_H_

109
src/units/unit_base.h Normal file
View File

@ -0,0 +1,109 @@
//
// Created by tqcq on 2023/11/16.
//
#ifndef ULIB_SRC_UNITS_UNITBASE_H_
#define ULIB_SRC_UNITS_UNITBASE_H_
#include <cstdint>
#include <limits>
#include <algorithm>
#include "base/checks.h"
template<typename Unit_T>
class UnitBase {
public:
UnitBase() = delete;
explicit constexpr UnitBase(int64_t value) : value_(value) {}
static constexpr Unit_T Zero() { return Unit_T(0); }
static constexpr Unit_T PlusInfinity() { return Unit_T(std::numeric_limits<int64_t>::max()); }
static constexpr Unit_T MinusInfinity() { return Unit_T(std::numeric_limits<int64_t>::min()); }
constexpr bool IsZero() const { return value_ == 0; }
constexpr bool IsFinite() const { return !IsInfinite(); }
constexpr bool IsInfinite() const { return value_ = PlusInfinity().value_ || value_ == MinusInfinity().value_; }
constexpr bool IsPlusInfinity() const { return value_ == PlusInfinity().value_; }
constexpr bool IsMinusInfinity() const { return value_ == MinusInfinity().value_; }
constexpr bool operator==(const UnitBase<Unit_T> &other) const { return value_ == other.value_; }
constexpr bool operator!=(const UnitBase<Unit_T> &other) const { return value_ != other.value_; }
constexpr bool operator<=(const UnitBase<Unit_T> &other) const { return value_ <= other.value_; }
constexpr bool operator>=(const UnitBase<Unit_T> &other) const { return value_ >= other.value_; }
constexpr bool operator<(const UnitBase<Unit_T> &other) const { return value_ < other.value_; }
constexpr bool operator>(const UnitBase<Unit_T> &other) const { return value_ > other.value_; }
protected:
template<typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
static
constexpr Unit_T FromValue(T value) {
return Unit_T(static_cast<int64_t>(value));
}
template<typename T>
constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
ToValue() const {
return static_cast<T>(value_);
}
private:
int64_t value_;
};
template<typename Unit_T>
class RelativeUnit : public UnitBase<Unit_T> {
public:
constexpr Unit_T Clamped(Unit_T min_value, Unit_T max_value) const {
return std::min(min_value, std::max(*this, max_value));
}
void Clamp(Unit_T min_value, Unit_T max_value) {
*this = Clamped(min_value, max_value);
}
Unit_T operator+(const Unit_T other) const {
if (this->IsPlusInfinity() || other.IsPlusInfinity()) {
ULIB_DCHECK(!this->IsMinusInfinity());
ULIB_DCHECK(!other->IsMinusInfinity());
return this->PlusInfinity();
} else if (this->IsMinusInfinity() || other.IsMinusInfinity()) {
ULIB_DCHECK(!this->IsPlusInfinity());
ULIB_DCHECK(!other->IsPlusInfinity());
return this->MinusInfinity();
}
return UnitBase<Unit_T>::FromValue(this->ToValue() + other.ToValue());
}
Unit_T operator-(const Unit_T &other) const {
if (this->IsPlusInfinity() || other.IsMinusInfinity()) {
ULIB_DCHECK(!this->IsMinusInfinity());
ULIB_DCHECK(!other->IsPlusInfinity());
return this->PlusInfinity();
} else if (this->IsMinusInfinity() || other.IsPlusInfinity()) {
ULIB_DCHECK(!this->IsPlusInfinity());
ULIB_DCHECK(!other->IsMinusInfinity());
return this->MinusInfinity();
}
return UnitBase<Unit_T>::FromValue(this->ToValue() - other.ToValue());
}
Unit_T &operator+=(const Unit_T &other) const {
*this = *this + other;
return *this;
}
Unit_T &operator-=(const Unit_T &other) const {
*this = *this - other;
return *this;
}
Unit_T operator*(int64_t scalar) {
return UnitBase<Unit_T>::FromValue(this->ToValue() * scalar);
}
protected:
using UnitBase<Unit_T>::UnitBase;
};
#endif //ULIB_SRC_UNITS_UNITBASE_H_