This commit is contained in:
tqcq 2024-02-28 15:40:19 +08:00
commit 8c3ab60c73
23 changed files with 1130 additions and 124 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
.cache/
out/
build/
compile_commands.json

View File

@ -29,6 +29,7 @@ target_sources(
src/synchronization/mutex.cc
src/synchronization/sequence_checker_internal.cc
src/synchronization/thread_local.cc
src/system/location.cc
src/system/thread.cc
src/task_queue/pending_task_safety_flag.cc
src/task_queue/task_queue_base.cc
@ -50,3 +51,10 @@ target_include_directories(
PRIVATE src)
target_link_libraries(sled PUBLIC rpc_core fmt)
find_package(benchmark REQUIRED)
add_executable(sled_benchmark
benchmark/strings/base64_benchmark.cc
)
target_link_libraries(sled_benchmark PRIVATE sled benchmark::benchmark benchmark::benchmark_main)

View File

@ -0,0 +1,59 @@
#include <benchmark/benchmark.h>
#include <sled/random.h>
#include <sled/strings/base64.h>
#include <sstream>
struct strings {};
static std::string
AllocRandomString(sled::Random &random, int len)
{
std::stringstream ss;
for (int i = len; i > 0; i--) { ss << random.Rand<char>(); }
return ss.str();
}
void
BenchmarkBase64Encode(benchmark::State &state)
{
state.PauseTiming();
sled::Random random(2393);
std::vector<std::string> test_data;
for (int i = 0; i < state.range(0); i++) {
test_data.emplace_back(AllocRandomString(random, state.range(1)));
}
state.ResumeTiming();
for (int i = 0; i < state.range(2); i++) {
for (const auto &str : test_data) {
auto base64 = sled::Base64::Encode(str);
}
}
}
std::string
uint2str(unsigned int num)
{
std::ostringstream oss;
oss << num;
return oss.str();
}
void
test(benchmark::State &state)
{
for (int i = 0; i < 1000000; i++) (void) uint2str(i);
state.end();
}
BENCHMARK(test);
/*
BENCHMARK(BenchmarkBase64Encode)
->ArgsProduct({
// generate the num of strings
benchmark::CreateRange(10, 1000, 10),
// generate the length of each string
benchmark::CreateRange(10, 1000, 10),
benchmark::CreateRange(10, 1000, 10),
});
*/

View File

@ -1,5 +1,30 @@
#include <arpa/inet.h>
#if defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define htobe16(x) OSSwapHostToBigInt16(x)
#define htole16(x) OSSwapHostToLittleInt16(x)
#define be16toh(x) OSSwapBigToHostInt16(x)
#define le16toh(x) OSSwapLittleToHostInt16(x)
#define htobe32(x) OSSwapHostToBigInt32(x)
#define htole32(x) OSSwapHostToLittleInt32(x)
#define be32toh(x) OSSwapBigToHostInt32(x)
#define le32toh(x) OSSwapLittleToHostInt32(x)
#define htobe64(x) OSSwapHostToBigInt64(x)
#define htole64(x) OSSwapHostToLittleInt64(x)
#define be64toh(x) OSSwapBigToHostInt64(x)
#define le64toh(x) OSSwapLittleToHostInt64(x)
#define __BYTE_ORDER BYTE_ORDER
#define __BIG_ENDIAN BIG_ENDIAN
#define __LITTLE_ENDIAN LITTLE_ENDIAN
#define __PDP_ENDIAN PDP_ENDIAN
#endif
inline uint16_t
HostToNetwork16(uint16_t n)
{

View File

@ -6,6 +6,7 @@
#ifndef LOG_H
#define LOG_H
#include "sled/system/location.h"
#include <fmt/format.h>
namespace sled {
@ -32,10 +33,18 @@ void Log(LogLevel level,
// sled::Log(level, tag, fmt, __FILE__, __FUNCTION__, __VA_ARGS__)
#define _SLOG(level, tag, fmt_str, ...) \
sled::Log(level, tag, fmt::format(fmt_str, #__VA_ARGS__).c_str(), \
__FILE__, __LINE__, __FUNCTION__)
do { \
std::string __fmt_str; \
try { \
__fmt_str = fmt::format(fmt_str, ##__VA_ARGS__); \
} catch (const std::exception &e) { \
__fmt_str = " fmt error: " + std::string(e.what()); \
} \
sled::Log(level, tag, __fmt_str.c_str(), __FILE__, __LINE__, \
__FUNCTION__); \
} while (0)
#define SLOG(level, tag, fmt, ...) _SLOG(level, tag, fmt, #__VA_ARGS__)
#define SLOG(level, tag, fmt, ...) _SLOG(level, tag, fmt, ##__VA_ARGS__)
#define SLOG_TRACE(tag, fmt, ...) \
SLOG(sled::LogLevel::kTrace, tag, fmt, __VA_ARGS__)
#define SLOG_INFO(tag, fmt, ...) \
@ -56,8 +65,8 @@ void Log(LogLevel level,
#define SLOG_ASSERT(cond, tag, fmt, ...) \
do { \
if (!(cond)) { \
SLOG(sled::LogLevel::kFatal, __VA_ARGS__); \
if (!!(cond)) { \
SLOG(sled::LogLevel::kFatal, tag, fmt, ##__VA_ARGS__); \
assert(cond); \
} \
} while (0)
@ -75,12 +84,18 @@ void Log(LogLevel level,
#define LOGF_IF(cond, tag, fmt, ...) \
SLOG_IF(cond, sled::LogLevel::kFatal, tag, fmt, __VA_ARGS__)
#define LOGV(tag, fmt, ...) SLOG(sled::LogLevel::kTrace, tag, fmt, #__VA_ARGS__)
#define LOGD(tag, fmt, ...) SLOG(sled::LogLevel::kDebug, tag, fmt, #__VA_ARGS__)
#define LOGI(tag, fmt, ...) SLOG(sled::LogLevel::kInfo, tag, fmt, #__VA_ARGS__)
#define LOGV(tag, fmt, ...) \
SLOG(sled::LogLevel::kTrace, tag, fmt, ##__VA_ARGS__)
#define LOGD(tag, fmt, ...) \
SLOG(sled::LogLevel::kDebug, tag, fmt, ##__VA_ARGS__)
#define LOGI(tag, fmt, ...) SLOG(sled::LogLevel::kInfo, tag, fmt, ##__VA_ARGS__)
#define LOGW(tag, fmt, ...) \
SLOG(sled::LogLevel::kWarning, tag, fmt, #__VA_ARGS__)
#define LOGE(tag, fmt, ...) SLOG(sled::LogLevel::kError, tag, fmt, #__VA_ARGS__)
#define LOGF(tag, fmt, ...) SLOG(sled::LogLevel::kFatal, tag, fmt, #__VA_ARGS__)
SLOG(sled::LogLevel::kWarning, tag, fmt, ##__VA_ARGS__)
#define LOGE(tag, fmt, ...) \
SLOG(sled::LogLevel::kError, tag, fmt, ##__VA_ARGS__)
#define LOGF(tag, fmt, ...) \
SLOG(sled::LogLevel::kFatal, tag, fmt, ##__VA_ARGS__)
#define ASSERT(cond, fmt, ...) SLOG_ASSERT(cond, "ASSERT", fmt, ##__VA_ARGS__)
#endif// LOG_H

View File

@ -53,9 +53,9 @@ public:
private:
static const int kForeverMs = -1;
static int ToCmsWait(TimeDelta max_wait_duration);
static int ToCusWait(TimeDelta max_wait_duration);
bool WaitSelect(int cmsWait, bool process_io);
bool WaitSelect(int64_t cusWait, bool process_io);
uint64_t next_dispatcher_key_ = 0;
std::unordered_map<uint64_t, Dispatcher *> dispatcher_by_key_;

View File

@ -0,0 +1,708 @@
/*
The MIT License (MIT)
Copyright (c) 2015 Julius Ikkala
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef FIXED_POINT_H_
#define FIXED_POINT_H_
#include <Eigen/Eigen>
#include <cmath>
#include <cstdint>
#include <fmt/ostream.h>
#include <type_traits>
//==========================================================================
//Fixed-point numbers
//==========================================================================
namespace fp {
/*The fixed-point number class. f is the amount of fractional bits, I is
the internal type. If I is signed, q will be signed.*/
template<unsigned f, typename I>
struct q {
I i;
q(int i = 0); /*Integer literals are int*/
q(unsigned u);
q(uintmax_t s);
q(double d);
q(long double d);
template<unsigned fb>
q(q<fb, I> a);
operator int() const;
operator float() const;
operator double() const;
operator long double() const;
template<unsigned fb>
q<f, I> operator+(q<fb, I> b) const;
template<unsigned fb>
q<f, I> operator-(q<fb, I> b) const;
template<unsigned fb>
q<f, I> operator*(q<fb, I> b) const;
template<unsigned fb>
q<f, I> operator/(q<fb, I> b) const;
template<unsigned fb>
q<f, I> operator%(q<fb, I> b) const;
template<typename T>
q<f, I> operator+(T b) const;
template<typename T>
q<f, I> operator-(T b) const;
template<typename T>
q<f, I> operator*(T b) const;
template<typename T>
q<f, I> operator/(T b) const;
template<typename T>
q<f, I> operator%(T b) const;
template<typename T>
q<f, I> &operator+=(T b);
template<typename T>
q<f, I> &operator-=(T b);
template<typename T>
q<f, I> &operator*=(T b);
template<typename T>
q<f, I> &operator/=(T b);
template<typename T>
q<f, I> &operator%=(T b);
q<f, I> operator-() const;
template<unsigned fb>
q<f, I> &operator=(q<fb, I> b);
q<f, I> &operator=(int b);
q<f, I> &operator=(double b);
q<f, I> &operator=(long double b);
template<unsigned fb>
bool operator>=(q<fb, I> b) const;
template<unsigned fb>
bool operator>(q<fb, I> b) const;
template<unsigned fb>
bool operator<=(q<fb, I> b) const;
template<unsigned fb>
bool operator<(q<fb, I> b) const;
template<unsigned fb>
bool operator==(q<fb, I> b) const;
template<unsigned fb>
bool operator!=(q<fb, I> b) const;
friend std::ostream &operator<<(std::ostream &os, const q<f, I> &fp)
{
os << (float) fp;
return os;
}
friend std::istream &operator>>(std::istream &is, q<f, I> &fp)
{
float val;
is >> val;
fp = val;
return is;
}
};
typedef q<16, uint32_t> UQ16_16;
typedef q<32, uint64_t> UQ32_32;
typedef q<16, uint64_t> UQ48_16;
typedef q<16, int32_t> Q16_16;
typedef q<32, int64_t> Q32_32;
typedef q<16, int64_t> Q48_16;
/*Returns the absolute value of x*/
template<unsigned f, typename I>
q<f, I> abs(q<f, I> x);
}// namespace fp
//==========================================================================
//Internal helper functions and classes
//==========================================================================
namespace fp_internal {
/*Count leading zeroes*/
template<typename T>
unsigned
clz(T x)
{
unsigned i = 0;
while (!(x & (((T) 1) << (sizeof(T) * 8 - 1))) && (x <<= 1)) ++i;
return i;
}
/*Used to select the correct shift operator in compile-time*/
template<int shift, bool rsh, bool zero, typename T>
struct shifter {
static T op(T x);
};
template<int shift, typename T>
struct shifter<shift, true, false, T> {
static T op(T x) { return x >> shift; };
};
template<int shift, typename T>
struct shifter<shift, false, false, T> {
static T op(T x) { return x << -shift; };
};
template<int shift, bool rsh, typename T>
struct shifter<shift, rsh, true, T> {
static T op(T x) { return 0; };
};
template<typename T>
constexpr T
abs_helper(const T x) noexcept
{
return (// deal with signed-zeros
x == T(0) ? T(0) :
// else
x < T(0) ? -x
: x);
}
/*Signed right shift. Accepts negative values of shift and never
complains about too big shifts. Compile-time version.*/
template<int shift, typename T>
constexpr T
signed_rsh(T x)
{
return shifter<shift, (shift >= 0), (abs_helper(shift) >= sizeof(T) * 8),
T>::op(x);
}
/*Signed right shift, run time version.*/
template<typename T>
T
signed_rsh(T x, int shift)
{
return std::abs(shift) < sizeof(T) * 8
? (shift < 0 ? x << -shift : x >> shift)
: 0;
}
/*Signed left shift, compile-time version*/
template<int shift, typename T>
T
signed_lsh(T x)
{
return signed_rsh<-shift, T>(x);
}
/*Signed left shift, run time version*/
template<typename T>
T
signed_lsh(T x, int shift)
{
return std::abs(shift) < sizeof(T) * 8
? (shift < 0 ? x >> -shift : x << shift)
: 0;
}
/*Multiplies and simultaneously right-shifts the argument values,
without losing the high bits. Compile-time version*/
template<int shift, typename T>
T
mul_rsh(T a, T b)
{
typedef typename std::make_unsigned<T>::type U;
static const int bits = sizeof(T) * 8;
static const int halfbits = sizeof(T) * 4;
static const U lowmask = (((T) 1) << (halfbits)) - 1;
static const U highmask = lowmask << (halfbits);
T a1 = a >> (halfbits);
T a2 = a - (a & highmask);
T b1 = b >> (halfbits);
T b2 = b - (b & highmask);
T a1b1 = a1 * b1;
T a1b2 = a1 * b2;
T a2b1 = a2 * b1;
T a2b2 = a2 * b2;
U high = a1b1 + (a2b1 >> (halfbits)) + (a1b2 >> (halfbits));
U low = a2b2;
high += (low += (a2b1 << halfbits)) < a2b2;
U tmp = low;
high += (low += (a1b2 << halfbits)) < tmp;
low = signed_rsh<shift>(low);
low += signed_lsh<bits - shift>(high);
return low;
}
/*Run time version*/
template<typename T>
T
mul_rsh(T a, T b, int shift)
{
typedef typename std::make_unsigned<T>::type U;
static const int bits = sizeof(T) * 8;
static const int halfbits = sizeof(T) * 4;
static const U lowmask = (((T) 1) << (halfbits)) - 1;
static const U highmask = lowmask << (halfbits);
T a1 = a >> (halfbits);
T a2 = a - (a & highmask);
T b1 = b >> (halfbits);
T b2 = b - (b & highmask);
T a1b1 = a1 * b1;
T a1b2 = a1 * b2;
T a2b1 = a2 * b1;
T a2b2 = a2 * b2;
U high = a1b1 + (a2b1 >> (halfbits)) + (a1b2 >> (halfbits));
U low = a2b2;
high += (low += (a2b1 << halfbits)) < a2b2;
U tmp = low;
high += (low += (a1b2 << halfbits)) < tmp;
low = signed_rsh(low, shift);
low += signed_lsh(high, bits - shift);
return low;
}
}// namespace fp_internal
//==========================================================================
//Implementation
//==========================================================================
template<unsigned f, typename I>
fp::q<f, I>::q(int u)
{
i = fp_internal::signed_lsh<f>((I) u);
}
template<unsigned f, typename I>
fp::q<f, I>::q(unsigned u)
{
i = fp_internal::signed_lsh<f>((I) u);
}
template<unsigned f, typename I>
fp::q<f, I>::q(uintmax_t s)
{
i = fp_internal::signed_lsh<f>((I) s);
}
template<unsigned f, typename I>
fp::q<f, I>::q(double d)
{
int exp = 0;
double tmp = frexp(d, &exp);
i = lroundl(ldexp(tmp, exp + f));
}
template<unsigned f, typename I>
fp::q<f, I>::q(long double d)
{
int exp = 0;
long double tmp = frexp(d, &exp);
i = llroundl(ldexp(tmp, exp + f));
}
template<unsigned f, typename I>
template<unsigned fb>
fp::q<f, I>::q(q<fb, I> a)
{
i = fp_internal::signed_rsh<fb - f>(a.i);
}
template<unsigned f, typename I>
fp::q<f, I>::operator int() const
{
return fp_internal::signed_rsh<f>(i);
}
template<unsigned f, typename I>
fp::q<f, I>::operator float() const
{
return ldexpf((float) i, -(int) f);
}
template<unsigned f, typename I>
fp::q<f, I>::operator double() const
{
return ldexp((double) i, -(int) f);
}
template<unsigned f, typename I>
fp::q<f, I>::operator long double() const
{
return ldexp((long double) i, -(int) f);
}
template<unsigned f, typename I>
template<unsigned fb>
fp::q<f, I>
fp::q<f, I>::operator+(q<fb, I> b) const
{
q<f, I> t;
t.i = i + fp_internal::signed_rsh<fb - f>(b.i);
return t;
}
template<unsigned f, typename I>
template<unsigned fb>
fp::q<f, I>
fp::q<f, I>::operator-(q<fb, I> b) const
{
q<f, I> t;
t.i = i - fp_internal::signed_rsh<fb - f>(b.i);
return t;
}
template<unsigned f, typename I>
template<unsigned fb>
fp::q<f, I>
fp::q<f, I>::operator*(q<fb, I> b) const
{
q<f, I> t;
t.i = fp_internal::mul_rsh<fb>(i, b.i);
return t;
}
template<unsigned f, typename I>
template<unsigned fb>
fp::q<f, I>
fp::q<f, I>::operator/(q<fb, I> b) const
{
static const I msb = (I) 1
<< (sizeof(I) * 8 - 1);//Most significant bit for the type
//Make b positive so that leading zeroes can be properly computed
I abs_b = b.i < 0 ? -b.i : b.i;
unsigned lz = fp_internal::clz(abs_b);//Amount of leading zeroes
//normalize b to [0.5, 1.0[, where all digits are after radix
I d = (abs_b << lz);
q<sizeof(I) * 8 + 1, typename std::make_unsigned<I>::type> e;
e.i = (~d + 1) << 1;//[0, 0.5[
//r is the reciprocal of d
q<sizeof(I) * 8 - 1, typename std::make_unsigned<I>::type> r(1);
for (unsigned i = 0; i < sizeof(I) - 1; ++i) {
r = r + r * e;
e = e * e;
}
q<f, I> t;
t.i = (I) fp_internal::mul_rsh(//adjust the radix point of (this*r)
r.i,
(typename std::make_unsigned<I>::type)(this->i < 0 ? -this->i
: this->i),
sizeof(i) * 16 - fb - lz - (d == msb) - 1);
t.i = (b.i < 0) ^ (this->i < 0) ? -t.i : t.i;//set correct sign
return t;
}
template<unsigned f, typename I>
template<unsigned fb>
fp::q<f, I>
fp::q<f, I>::operator%(q<fb, I> b) const
{
q<f, I> t;
t.i = i % fp_internal::signed_rsh<fb - f>(b.i);
return t;
}
template<unsigned f, typename I>
template<typename T>
fp::q<f, I>
fp::q<f, I>::operator+(T b) const
{
return *this + q<f, I>(b);
}
template<unsigned f, typename I>
template<typename T>
fp::q<f, I>
fp::q<f, I>::operator-(T b) const
{
return *this - q<f, I>(b);
}
template<unsigned f, typename I>
template<typename T>
fp::q<f, I>
fp::q<f, I>::operator*(T b) const
{
return *this * q<f, I>(b);
}
template<unsigned f, typename I>
template<typename T>
fp::q<f, I>
fp::q<f, I>::operator/(T b) const
{
return *this / q<f, I>(b);
}
template<unsigned f, typename I>
template<typename T>
fp::q<f, I>
fp::q<f, I>::operator%(T b) const
{
return *this % q<f, I>(b);
}
template<unsigned f, typename I>
template<typename T>
fp::q<f, I> &
fp::q<f, I>::operator+=(T b)
{
return *this = *this + b;
}
template<unsigned f, typename I>
template<typename T>
fp::q<f, I> &
fp::q<f, I>::operator-=(T b)
{
return *this = *this - b;
}
template<unsigned f, typename I>
template<typename T>
fp::q<f, I> &
fp::q<f, I>::operator*=(T b)
{
return *this = *this * b;
}
template<unsigned f, typename I>
template<typename T>
fp::q<f, I> &
fp::q<f, I>::operator/=(T b)
{
return *this = *this / b;
}
template<unsigned f, typename I>
template<typename T>
fp::q<f, I> &
fp::q<f, I>::operator%=(T b)
{
return *this = *this % b;
}
template<unsigned f, typename I>
fp::q<f, I>
fp::q<f, I>::operator-() const
{
q<f, I> t;
t.i = -i;
return t;
}
template<unsigned f, typename I>
template<unsigned fb>
fp::q<f, I> &
fp::q<f, I>::operator=(q<fb, I> b)
{
i = fp_internal::signed_rsh<fb - f>(b.i);
return *this;
}
template<unsigned f, typename I>
fp::q<f, I> &
fp::q<f, I>::operator=(int b)
{
i = fp_internal::signed_lsh<f>((I) b);
return *this;
}
template<unsigned f, typename I>
fp::q<f, I> &
fp::q<f, I>::operator=(double b)
{
int exp = 0;
double tmp = frexp(b, &exp);
i = llroundl(ldexp(tmp, exp + f));
return *this;
}
template<unsigned f, typename I>
fp::q<f, I> &
fp::q<f, I>::operator=(long double b)
{
int exp = 0;
long double tmp = frexp(b, &exp);
i = llroundl(ldexp(tmp, exp + f));
return *this;
}
template<unsigned f, typename I>
template<unsigned fb>
bool
fp::q<f, I>::operator>=(q<fb, I> b) const
{
static const unsigned bits = sizeof(I) * 8;
I ma = fp_internal::signed_rsh<f>(i);
I mb = fp_internal::signed_rsh<fb>(b.i);
return (ma > mb)
|| ((ma == mb)
&& ((typename std::make_unsigned<I>::type)
fp_internal::signed_lsh<bits - f>(i)
>= (typename std::make_unsigned<I>::type)
fp_internal::signed_lsh<bits - fb>(b.i)));
}
template<unsigned f, typename I>
template<unsigned fb>
bool
fp::q<f, I>::operator>(q<fb, I> b) const
{
static const unsigned bits = sizeof(I) * 8;
I ma = fp_internal::signed_rsh<f>(i);
I mb = fp_internal::signed_rsh<fb>(b.i);
return (ma > mb)
|| ((ma == mb)
&& ((typename std::make_unsigned<I>::type)
fp_internal::signed_lsh<bits - f>(i)
> (typename std::make_unsigned<I>::type)
fp_internal::signed_lsh<bits - fb>(b.i)));
}
template<unsigned f, typename I>
template<unsigned fb>
bool
fp::q<f, I>::operator<=(q<fb, I> b) const
{
static const unsigned bits = sizeof(I) * 8;
I ma = fp_internal::signed_rsh<f>(i);
I mb = fp_internal::signed_rsh<fb>(b.i);
return (ma < mb)
|| ((ma == mb)
&& ((typename std::make_unsigned<I>::type)
fp_internal::signed_lsh<bits - f>(i)
<= (typename std::make_unsigned<I>::type)
fp_internal::signed_lsh<bits - fb>(b.i)));
}
template<unsigned f, typename I>
template<unsigned fb>
bool
fp::q<f, I>::operator<(q<fb, I> b) const
{
static const unsigned bits = sizeof(I) * 8;
I ma = fp_internal::signed_rsh<f>(i);
I mb = fp_internal::signed_rsh<fb>(b.i);
return (ma < mb)
|| ((ma == mb)
&& ((typename std::make_unsigned<I>::type)
fp_internal::signed_lsh<bits - f>(i)
< (typename std::make_unsigned<I>::type)
fp_internal::signed_lsh<bits - fb>(b.i)));
}
template<unsigned f, typename I>
template<unsigned fb>
bool
fp::q<f, I>::operator==(q<fb, I> b) const
{
return fp_internal::signed_rsh<f - fb>(i) == b.i
&& fp_internal::signed_rsh<fb - f>(b.i) == i;
}
template<unsigned f, typename I>
template<unsigned fb>
bool
fp::q<f, I>::operator!=(q<fb, I> b) const
{
return fp_internal::signed_rsh<f - fb>(i) != b.i
|| fp_internal::signed_rsh<fb - f>(b.i) != i;
}
template<unsigned f, typename I>
fp::q<f, I>
fp::abs(q<f, I> x)
{
return (x.i >= 0 ? x : -x);
}
namespace sled {
template<unsigned bits, typename T>
using FixedPoint = fp::q<bits, T>;
using FixedFloat = fp::Q32_32;
template<unsigned bits, typename T>
inline const FixedPoint<bits, T>
conj(const FixedPoint<bits, T> &val)
{
return val;
}
template<unsigned bits, typename T>
inline const FixedPoint<bits, T>
real(const FixedPoint<bits, T> &val)
{
return val;
}
template<unsigned bits, typename T>
inline const FixedPoint<bits, T>
imag(const FixedPoint<bits, T> &val)
{
return 0.;
}
template<unsigned bits, typename T>
inline const FixedPoint<bits, T>
abs(const FixedPoint<bits, T> &val)
{
return fp::abs(val);
}
template<unsigned bits, typename T>
inline const FixedPoint<bits, T>
abs2(const FixedPoint<bits, T> &val)
{
return val * val;
}
}// namespace sled
template<unsigned bits, typename T>
struct fmt::formatter<sled::FixedPoint<bits, T>> : ostream_formatter {};
namespace Eigen {
template<unsigned bits, typename T>
struct NumTraits<sled::FixedPoint<bits, T>> : NumTraits<float> {
typedef sled::FixedPoint<bits, T> Real;
typedef sled::FixedPoint<bits, T> NonInteger;
typedef sled::FixedPoint<bits, T> Nested;
enum {
IsComplex = 0,
IsInteger = 0,
IsSigned = std::is_signed<T>::value,
RequireInitialization = 1,
ReadCost = 1,
AddCost = 3,
MulCost = 3
};
};
template<typename BinaryOp, unsigned bits, typename T>
struct ScalarBinaryOpTraits<sled::FixedPoint<bits, T>, float, BinaryOp> {
typedef sled::FixedPoint<bits, T> ReturnType;
};
template<typename BinaryOp, unsigned bits, typename T>
struct ScalarBinaryOpTraits<float, sled::FixedPoint<bits, T>, BinaryOp> {
typedef sled::FixedPoint<bits, T> ReturnType;
};
}// namespace Eigen
#endif

View File

@ -0,0 +1,69 @@
/**
* @file : circle_queue
* @created : 2 24, 2024 16:06:23 CST
* @license : MIT
**/
#ifndef CIRCLE_QUEUE_H
#define CIRCLE_QUEUE_H
#include "sled/log/log.h"
#include <array>
namespace sled {
template<typename T, size_t LEN>
class CircleQueue {
static_assert(LEN > 0, "LEN should be greater than 0.");
public:
void Push(T &&val)
{
ASSERT(size() < LEN, "queue is full.");
queue_.get(tail_) = std::move(val);
++tail_;
}
void Push(const T &val)
{
ASSERT(size() < LEN, "queue is full.");
queue_.get(tail_) = val;
++tail_;
}
T &Front()
{
ASSERT(!empty(), "queue is empty.");
return queue_.get(head_);
}
T &Back()
{
ASSERT(!empty(), "queue is empty.");
return queue_.get((tail_ + LEN) % (LEN + 1));
}
void Pop()
{
ASSERT(!empty(), "queue is empty.");
head_ = (head_ + 1) % (LEN + 1);
}
size_t size() const
{
return tail_ >= head_ ? tail_ - head_ : (LEN + 1) - (head_ - tail_);
}
bool empty() const { return (tail_ + 1) % (LEN + 1) == head_; }
bool capacity() const { return LEN; }
private:
std::array<T, LEN + 1> queue_;
size_t head_ = 0;
size_t tail_ = 0;
};
}// namespace sled
#endif// CIRCLE_QUEUE_H

View File

@ -0,0 +1,24 @@
/**
* @file : reflect
* @created : 2 26, 2024 09:55:19 CST
* @license : MIT
**/
#ifndef SLED_REFLECT_REFLECT_H
#define SLED_REFLECT_REFLECT_H
#if !defined(__NO_META_PARSER__) && !defined(__META_PARSER__)
#define __META_PARSER__
#endif
#if defined(__META_PARSER__)
#define REFLECT_CLASS __attribute__((annotate("reflect-class")))
#define PROPERTY() __attribute__((annotate("reflect-property")))
#define METHOD() __attribute__((annotate("reflect-method")))
#else
#define REFLECT_CLASS
#define PROPERTY()
#define METHOD()
#endif
#endif// SLED_REFLECT_REFLECT_H

View File

@ -84,6 +84,7 @@ public:
scoped_refptr<T> &operator=(const scoped_refptr<T> &&r) noexcept
{
scoped_refptr<T>(std::move(r)).swap(*this);
return *this;
}
template<typename U>

View File

@ -17,10 +17,12 @@ namespace sled {
namespace internal {
template<typename T>
struct HasLockAndUnlock {
template<typename TClass,
decltype(std::declval<TClass>().Lock()) * = nullptr,
decltype(std::declval<TClass>().Unlock()) * = nullptr>
static int Test(T);
template<typename U,
decltype(std::declval<U>().Lock()) * = nullptr,
decltype(std::declval<U>().Unlock()) * = nullptr>
static int Test(int);
template<typename>
static char Test(...);
static constexpr bool value =
@ -69,45 +71,50 @@ template<typename TLock,
typename std::enable_if<internal::HasLockAndUnlock<TLock>::value,
TLock>::type * = nullptr>
class LockGuard final {
public:
LockGuard(const LockGuard &) = delete;
LockGuard &operator=(const LockGuard &) = delete;
explicit LockGuard(TLock *lock) : lock_(lock) { lock_->Lock(); };
explicit LockGuard(TLock *lock) : mutex_(lock) { mutex_->Lock(); };
~LockGuard() { lock_->Unlock(); };
~LockGuard() { mutex_->Unlock(); };
private:
TLock *lock_;
TLock *mutex_;
friend class ConditionVariable;
};
class MutexLock final {
public:
MutexLock(const MutexLock &) = delete;
MutexLock &operator=(const MutexLock &) = delete;
using MutexLock = LockGuard<Mutex>;
using RecursiveMutexLock = LockGuard<RecursiveMutex>;
explicit MutexLock(Mutex *mutex) : mutex_(mutex) { mutex->Lock(); }
~MutexLock() { mutex_->Unlock(); }
private:
Mutex *mutex_;
};
class RecursiveMutexLock final {
public:
RecursiveMutexLock(const RecursiveMutexLock &) = delete;
RecursiveMutexLock &operator=(const RecursiveMutexLock &) = delete;
explicit RecursiveMutexLock(RecursiveMutex *mutex) : mutex_(mutex)
{
mutex->Lock();
}
~RecursiveMutexLock() { mutex_->Unlock(); }
private:
RecursiveMutex *mutex_;
};
// class MutexLock final {
// public:
// MutexLock(const MutexLock &) = delete;
// MutexLock &operator=(const MutexLock &) = delete;
//
// explicit MutexLock(Mutex *mutex) : mutex_(mutex) { mutex->Lock(); }
//
// ~MutexLock() { mutex_->Unlock(); }
//
// private:
// Mutex *mutex_;
// };
//
// class RecursiveMutexLock final {
// public:
// RecursiveMutexLock(const RecursiveMutexLock &) = delete;
// RecursiveMutexLock &operator=(const RecursiveMutexLock &) = delete;
//
// explicit RecursiveMutexLock(RecursiveMutex *mutex) : mutex_(mutex)
// {
// mutex->Lock();
// }
//
// ~RecursiveMutexLock() { mutex_->Unlock(); }
//
// private:
// RecursiveMutex *mutex_;
// };
class ConditionVariable final {
public:
@ -117,17 +124,18 @@ public:
ConditionVariable &operator=(const ConditionVariable &) = delete;
template<typename Predicate>
inline bool Wait(Mutex *mutex, Predicate pred)
inline bool Wait(LockGuard<Mutex> &guard, Predicate pred)
{
std::unique_lock<std::mutex> lock(mutex->impl_, std::adopt_lock);
std::unique_lock<std::mutex> lock(guard.mutex_->impl_, std::adopt_lock);
cv_.wait(lock, pred);
return true;
}
template<typename Predicate>
inline bool WaitFor(Mutex *mutex, TimeDelta timeout, Predicate pred)
inline bool
WaitFor(LockGuard<Mutex> &guard, TimeDelta timeout, Predicate pred)
{
std::unique_lock<std::mutex> lock(mutex->impl_, std::adopt_lock);
std::unique_lock<std::mutex> lock(guard.mutex_->impl_, std::adopt_lock);
if (timeout == kForever) {
cv_.wait(lock, pred);
return true;

View File

@ -7,13 +7,30 @@
#ifndef LOCATION_H
#define LOCATION_H
#include <string>
namespace sled {
class Location {
class Location final {
public:
static Location Current() { return Location(); }
Location() = delete;
static Location Current(const char *file_name = __builtin_FILE(),
int file_line = __builtin_LINE(),
const char *function = __builtin_FUNCTION());
std::string ToString() const;
private:
Location(const char *file_name, int file_line, const char *function);
const char *file_name;
int file_line;
const char *function;
};
}// namespace sled
#define SLED_FROM_HERE sled::Location::Current();
#endif// LOCATION_H

View File

@ -13,9 +13,12 @@ namespace sled {
static const int64_t kNumMillisecsPerSec = 1000;
static const int64_t kNumMicrosecsPerSec = 1000000;
static const int64_t kNumNanosecsPerSec = 1000000000;
static const int64_t kNumMicrosecsPerMillisec = kNumMicrosecsPerSec / kNumMillisecsPerSec;
static const int64_t kNumNanosecsPerMillisec = kNumNanosecsPerSec / kNumMillisecsPerSec;
static const int64_t kNumNanosecsPerMicrosec = kNumNanosecsPerSec / kNumMicrosecsPerSec;
static const int64_t kNumMicrosecsPerMillisec =
kNumMicrosecsPerSec / kNumMillisecsPerSec;
static const int64_t kNumNanosecsPerMillisec =
kNumNanosecsPerSec / kNumMillisecsPerSec;
static const int64_t kNumNanosecsPerMicrosec =
kNumNanosecsPerSec / kNumMicrosecsPerSec;
constexpr int64_t kNtpJan1970Millisecs = 2208988800 * kNumMillisecsPerSec;
class ClockInterface {

View File

@ -77,7 +77,10 @@ public:
return ToFractionOr<1000>(fallback_value);
}
constexpr int64_t us_or(int64_t fallback_value) const { return ToValueOr(fallback_value); }
constexpr int64_t us_or(int64_t fallback_value) const
{
return ToValueOr(fallback_value);
}
Timestamp operator+(const TimeDelta delta) const
{

29
src/include/sled/ubench.h Normal file
View File

@ -0,0 +1,29 @@
/**
* @file : {{FILE}}
* @created : {{TIMESTAMP}}
* @license : {{LICENSE}}
**/
#ifndef{{MACRO_GUARD } }
#define{{MACRO_GUARD } }
namespace {
{
CURSOR
}
}// namespace
{
class {
{
CAMEL_CLASS
}
} {
public:
};
}// namespace
#endif// {{MACRO_GUARD}}

View File

@ -1,8 +1,53 @@
#include "sled/log/log.h"
#include "sled/time_utils.h"
#include <ctime>
#include <fmt/format.h>
#include <iostream>
namespace sled {
class ScopedAtomicWaiter {
public:
ScopedAtomicWaiter(std::atomic_bool &flag) : flag_(flag)
{
bool old = flag_.load();
while (!flag_.compare_exchange_weak(old, false)) { continue; }
}
~ScopedAtomicWaiter() { flag_.store(true); }
private:
std::atomic_bool &flag_;
};
static std::string
GetCurrentUTCTime()
{
#if true
// struct timespec tp;
// clock_gettime(CLOCK_REALTIME, &tp);
// int64_t now = tp.tv_sec * kNumNanosecsPerSec + tp.tv_nsec;
// std::time_t t = tp.tv_sec;
const int64_t now = TimeUTCNanos();
std::time_t t = now / kNumNanosecsPerSec;
#else
std::time_t t = std::time(nullptr);
#endif
std::tm tm = *std::gmtime(&t);
char buf[64];
std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &tm);
std::string result(buf);
#if true
return result
+ fmt::format(".{:03d}Z",
static_cast<int>(now % kNumNanosecsPerSec)
/ kNumNanosecsPerMillisec);
#else
return result + "Z";
#endif
return result;
}
void
Log(LogLevel level,
const char *tag,
@ -12,11 +57,13 @@ Log(LogLevel level,
const char *func_name,
...)
{
static std::atomic_bool allow(true);
ScopedAtomicWaiter waiter(allow);
int len = file_name ? strlen(file_name) : 0;
while (len > 0 && file_name[len - 1] != '/') { len--; }
auto msg = fmt::format("{}:{}@{} {} {}", file_name + len, line, func_name,
tag, fmt);
auto msg = fmt::format("{} {}:{}@{} {} {}", GetCurrentUTCTime(),
file_name + len, line, func_name, tag, fmt);
std::cout << msg << std::endl;
}

View File

@ -1,4 +1,5 @@
#include "sled/network/physical_socket_server.h"
#include "sled/log/log.h"
#include "sled/network/async_resolver.h"
#include "sled/network/socket.h"
#include "sled/synchronization/event.h"
@ -155,11 +156,11 @@ PhysicalSocketServer::Update(Dispatcher *pdispatcher)
}
int
PhysicalSocketServer::ToCmsWait(TimeDelta max_wait_duration)
PhysicalSocketServer::ToCusWait(TimeDelta max_wait_duration)
{
return max_wait_duration == Event::kForever
? kForeverMs
: max_wait_duration.RoundUpTo(TimeDelta::Millis(1)).ms();
: max_wait_duration.RoundUpTo(TimeDelta::Micros(1)).us();
}
bool
@ -167,9 +168,9 @@ PhysicalSocketServer::Wait(TimeDelta max_wait_duration, bool process_io)
{
ScopedSetTrue s(&waiting_);
const int cmsWait = ToCmsWait(max_wait_duration);
const int64_t cusWait = ToCusWait(max_wait_duration);
return WaitSelect(cmsWait, process_io);
return WaitSelect(cusWait, process_io);
}
static void
@ -216,16 +217,16 @@ ProcessEvents(Dispatcher *pdispatcher,
}
bool
PhysicalSocketServer::WaitSelect(int cmsWait, bool process_io)
PhysicalSocketServer::WaitSelect(int64_t cusWait, bool process_io)
{
struct timeval *ptvWait = nullptr;
struct timeval tvWait;
int64_t stop_us;
if (cmsWait != kForeverMs) {
tvWait.tv_sec = cmsWait / 1000;
tvWait.tv_usec = (cmsWait % 1000) * 1000;
if (cusWait != kForeverMs) {
tvWait.tv_sec = cusWait / sled::kNumMicrosecsPerSec;
tvWait.tv_usec = (cusWait % sled::kNumMicrosecsPerSec);
ptvWait = &tvWait;
stop_us = TimeMicros() + cmsWait * 1000;
stop_us = TimeMicros() + cusWait;
}
fd_set fdsRead;

View File

@ -8,6 +8,8 @@
#include "sled/network/physical_socket_server.h"
namespace sled {
constexpr TimeDelta SocketServer::kForever;
std::unique_ptr<sled::SocketServer>
CreateDefaultSocketServer()
{

View File

@ -30,9 +30,9 @@ Event::Reset()
bool
Event::Wait(TimeDelta give_up_after, TimeDelta warn_after)
{
MutexLock lock(&mutex_);
MutexLock guard(&mutex_);
bool wait_success =
cv_.WaitFor(&mutex_, give_up_after, [&] { return event_status_; });
cv_.WaitFor(guard, give_up_after, [&] { return event_status_; });
if (!wait_success) { return false; }
if (!is_manual_reset_) { event_status_ = false; }

23
src/system/location.cc Normal file
View File

@ -0,0 +1,23 @@
#include "sled/system/location.h"
namespace sled {
Location
Location::Current(const char *file_name, int file_line, const char *function)
{
return Location(file_name, file_line, function);
}
Location::Location(const char *file_name, int file_line, const char *function)
: file_name(file_name),
file_line(file_line),
function(function)
{}
std::string
Location::ToString() const
{
return std::string(file_name) + ":" + std::to_string(file_line) + " "
+ function;
}
}// namespace sled

View File

@ -8,7 +8,8 @@ SystemTimeNanos()
int64_t ticks;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) + static_cast<int64_t>(ts.tv_nsec);
ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec)
+ static_cast<int64_t>(ts.tv_nsec);
return ticks;
}
}// namespace sled

View File

@ -22,13 +22,13 @@ TimeMillis()
int64_t
TimeMicros()
{
if (g_clock) { return g_clock->TimeNanos(); }
return TimeNanos() / kNumNanosecsPerMicrosec;
}
int64_t
TimeNanos()
{
if (g_clock) { return g_clock->TimeNanos(); }
return SystemTimeNanos();
}
@ -51,49 +51,10 @@ TimeDiff(int32_t later, int32_t earlier)
}
int64_t
TmToSeconds(const tm &tm)
TmToSeconds(const tm &tm_val)
{
static short int mdays[12] = {31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31};
static short int cumul_mdays[12] = {0, 31, 59, 90, 120, 151,
181, 212, 243, 273, 304, 334};
int year = tm.tm_year + 1900;
int month = tm.tm_mon;
int day = tm.tm_mday - 1;// Make 0-based like the rest.
int hour = tm.tm_hour;
int min = tm.tm_min;
int sec = tm.tm_sec;
bool expiry_in_leap_year =
(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
if (year < 1970) return -1;
if (month < 0 || month > 11) return -1;
if (day < 0
|| day >= mdays[month] + (expiry_in_leap_year && month == 2 - 1))
return -1;
if (hour < 0 || hour > 23) return -1;
if (min < 0 || min > 59) return -1;
if (sec < 0 || sec > 59) return -1;
day += cumul_mdays[month];
// Add number of leap days between 1970 and the expiration year, inclusive.
day += ((year / 4 - 1970 / 4) - (year / 100 - 1970 / 100)
+ (year / 400 - 1970 / 400));
// We will have added one day too much above if expiration is during a leap
// year, and expiration is in January or February.
if (expiry_in_leap_year && month <= 2 - 1)// `month` is zero based.
day -= 1;
// Combine all variables into seconds from 1970-01-01 00:00 (except `month`
// which was accumulated into `day` above).
return (((static_cast<int64_t>(year - 1970) * 365 + day) * 24 + hour) * 60
+ min)
* 60
+ sec;
return -1;
struct tm *ptm = const_cast<struct tm *>(&tm_val);
return ::timegm(ptm);
}
int64_t
@ -118,11 +79,9 @@ int64_t
TimeUTCNanos()
{
if (g_clock) { return g_clock->TimeNanos() / kNumNanosecsPerMicrosec; }
struct timeval time;
gettimeofday(&time, nullptr);
int64_t nanosecs =
static_cast<int64_t>(time.tv_sec) * kNumNanosecsPerSec + time.tv_usec;
return nanosecs;
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return ts.tv_nsec + ts.tv_sec * kNumNanosecsPerSec;
}
}// namespace sled