feature add sigslot
This commit is contained in:
parent
3998561a53
commit
8cd9dfba1d
3
.gitignore
vendored
3
.gitignore
vendored
@ -45,3 +45,6 @@ compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
|
||||
# Clion
|
||||
.idea/
|
||||
cmake-*
|
||||
|
51
CMakeLists.txt
Normal file
51
CMakeLists.txt
Normal 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
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
27
src/base/checks.cpp
Normal 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
58
src/base/checks.h
Normal 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
8
src/base/inline.h
Normal 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
80
src/base/location.cpp
Normal 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
49
src/base/location.h
Normal 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_
|
21
src/base/location_unittest.cpp
Normal file
21
src/base/location_unittest.cpp
Normal 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());
|
||||
}
|
||||
|
||||
}
|
8
src/base/scoped_clear_last_error.cpp
Normal file
8
src/base/scoped_clear_last_error.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// Created by tqcq on 2023/11/16.
|
||||
//
|
||||
|
||||
#include "scoped_clear_last_error.h"
|
||||
|
||||
namespace tqcq {
|
||||
} // namespace tqcq
|
22
src/base/scoped_clear_last_error.h
Normal file
22
src/base/scoped_clear_last_error.h
Normal 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_
|
22
src/base/task_queue_base.cpp
Normal file
22
src/base/task_queue_base.cpp
Normal 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
|
91
src/base/task_queue_base.h
Normal file
91
src/base/task_queue_base.h
Normal 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
8
src/network/socket.cpp
Normal 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
57
src/network/socket.h
Normal 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_
|
8
src/network/socket_address.cpp
Normal file
8
src/network/socket_address.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// Created by tqcq on 2023/11/16.
|
||||
//
|
||||
|
||||
#include "socket_address.h"
|
||||
|
||||
namespace tqcq {
|
||||
} // namespace tqcq
|
15
src/network/socket_address.h
Normal file
15
src/network/socket_address.h
Normal 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_
|
8
src/network/socket_factory.cpp
Normal file
8
src/network/socket_factory.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// Created by tqcq on 2023/11/16.
|
||||
//
|
||||
|
||||
#include "socket_factory.h"
|
||||
|
||||
namespace tqcq {
|
||||
} // namespace tqcq
|
20
src/network/socket_factory.h
Normal file
20
src/network/socket_factory.h
Normal 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_
|
8
src/network/socket_server.cpp
Normal file
8
src/network/socket_server.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// Created by tqcq on 2023/11/16.
|
||||
//
|
||||
|
||||
#include "socket_server.h"
|
||||
|
||||
namespace tqcq {
|
||||
} // namespace tqcq
|
31
src/network/socket_server.h
Normal file
31
src/network/socket_server.h
Normal 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_
|
80
src/strings/string_printf.cpp
Normal file
80
src/strings/string_printf.cpp
Normal 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
|
18
src/strings/string_printf.h
Normal file
18
src/strings/string_printf.h
Normal 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_
|
80
src/synchronization/event.cpp
Normal file
80
src/synchronization/event.cpp
Normal 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
|
41
src/synchronization/event.h
Normal file
41
src/synchronization/event.h
Normal 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_
|
8
src/synchronization/mutex.cpp
Normal file
8
src/synchronization/mutex.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// Created by tqcq on 2023/11/16.
|
||||
//
|
||||
|
||||
#include "mutex.h"
|
||||
|
||||
namespace tqcq {
|
||||
} // namespace tqcq
|
39
src/synchronization/mutex.h
Normal file
39
src/synchronization/mutex.h
Normal 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
23
src/system/export_api.h
Normal 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_
|
16
src/system/system_time.cpp
Normal file
16
src/system/system_time.cpp
Normal 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
14
src/system/system_time.h
Normal 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
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
8
src/units/time_delta.cpp
Normal 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
81
src/units/time_delta.h
Normal 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
109
src/units/unit_base.h
Normal 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_
|
Loading…
Reference in New Issue
Block a user