diff --git a/include/sled/log/log.h b/include/sled/log/log.h index d83f4ed..f31641c 100644 --- a/include/sled/log/log.h +++ b/include/sled/log/log.h @@ -56,8 +56,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) @@ -87,6 +87,6 @@ void Log(LogLevel level, #define LOGF(tag, fmt, ...) \ SLOG(sled::LogLevel::kFatal, tag, fmt, ##__VA_ARGS__) -#define ASSERT(cond, fmt, ...) SLOG_ASSERT(cond, "ASSERT", fmt, ##__VA_ARGS__); +#define ASSERT(cond, fmt, ...) SLOG_ASSERT(cond, "ASSERT", fmt, ##__VA_ARGS__) #endif// LOG_H diff --git a/include/sled/numerics/fixed_point_number.h b/include/sled/numerics/fixed_point_number.h new file mode 100644 index 0000000..fdc3238 --- /dev/null +++ b/include/sled/numerics/fixed_point_number.h @@ -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 +#include +#include +#include +#include + +//========================================================================== +//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 +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 + q(q a); + + operator int() const; + operator float() const; + operator double() const; + operator long double() const; + template + q operator+(q b) const; + template + q operator-(q b) const; + template + q operator*(q b) const; + template + q operator/(q b) const; + template + q operator%(q b) const; + + template + q operator+(T b) const; + template + q operator-(T b) const; + template + q operator*(T b) const; + template + q operator/(T b) const; + template + q operator%(T b) const; + + template + q &operator+=(T b); + template + q &operator-=(T b); + template + q &operator*=(T b); + template + q &operator/=(T b); + template + q &operator%=(T b); + + q operator-() const; + + template + q &operator=(q b); + q &operator=(int b); + q &operator=(double b); + q &operator=(long double b); + + template + bool operator>=(q b) const; + template + bool operator>(q b) const; + template + bool operator<=(q b) const; + template + bool operator<(q b) const; + template + bool operator==(q b) const; + template + bool operator!=(q b) const; + + friend std::ostream &operator<<(std::ostream &os, const q &fp) + { + os << (float) fp; + return os; + } + + friend std::istream &operator>>(std::istream &is, q &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 +q abs(q x); +}// namespace fp + +//========================================================================== +//Internal helper functions and classes +//========================================================================== +namespace fp_internal { +/*Count leading zeroes*/ +template +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 +struct shifter { + static T op(T x); +}; + +template +struct shifter { + static T op(T x) { return x >> shift; }; +}; + +template +struct shifter { + static T op(T x) { return x << -shift; }; +}; + +template +struct shifter { + static T op(T x) { return 0; }; +}; + +template +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 +constexpr T +signed_rsh(T x) +{ + return shifter= 0), (abs_helper(shift) >= sizeof(T) * 8), + T>::op(x); +} + +/*Signed right shift, run time version.*/ +template +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 +T +signed_lsh(T x) +{ + return signed_rsh<-shift, T>(x); +} + +/*Signed left shift, run time version*/ +template +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 +T +mul_rsh(T a, T b) +{ + typedef typename std::make_unsigned::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); + low += signed_lsh(high); + return low; +} + +/*Run time version*/ +template +T +mul_rsh(T a, T b, int shift) +{ + typedef typename std::make_unsigned::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 +fp::q::q(int u) +{ + i = fp_internal::signed_lsh((I) u); +} + +template +fp::q::q(unsigned u) +{ + i = fp_internal::signed_lsh((I) u); +} + +template +fp::q::q(uintmax_t s) +{ + i = fp_internal::signed_lsh((I) s); +} + +template +fp::q::q(double d) +{ + int exp = 0; + double tmp = frexp(d, &exp); + i = lroundl(ldexp(tmp, exp + f)); +} + +template +fp::q::q(long double d) +{ + int exp = 0; + long double tmp = frexp(d, &exp); + i = llroundl(ldexp(tmp, exp + f)); +} + +template +template +fp::q::q(q a) +{ + i = fp_internal::signed_rsh(a.i); +} + +template +fp::q::operator int() const +{ + return fp_internal::signed_rsh(i); +} + +template +fp::q::operator float() const +{ + return ldexpf((float) i, -(int) f); +} + +template +fp::q::operator double() const +{ + return ldexp((double) i, -(int) f); +} + +template +fp::q::operator long double() const +{ + return ldexp((long double) i, -(int) f); +} + +template +template +fp::q +fp::q::operator+(q b) const +{ + q t; + t.i = i + fp_internal::signed_rsh(b.i); + return t; +} + +template +template +fp::q +fp::q::operator-(q b) const +{ + q t; + t.i = i - fp_internal::signed_rsh(b.i); + return t; +} + +template +template +fp::q +fp::q::operator*(q b) const +{ + q t; + t.i = fp_internal::mul_rsh(i, b.i); + return t; +} + +template +template +fp::q +fp::q::operator/(q 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::type> e; + e.i = (~d + 1) << 1;//[0, 0.5[ + //r is the reciprocal of d + q::type> r(1); + for (unsigned i = 0; i < sizeof(I) - 1; ++i) { + r = r + r * e; + e = e * e; + } + q t; + t.i = (I) fp_internal::mul_rsh(//adjust the radix point of (this*r) + r.i, + (typename std::make_unsigned::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 +template +fp::q +fp::q::operator%(q b) const +{ + q t; + t.i = i % fp_internal::signed_rsh(b.i); + return t; +} + +template +template +fp::q +fp::q::operator+(T b) const +{ + return *this + q(b); +} + +template +template +fp::q +fp::q::operator-(T b) const +{ + return *this - q(b); +} + +template +template +fp::q +fp::q::operator*(T b) const +{ + return *this * q(b); +} + +template +template +fp::q +fp::q::operator/(T b) const +{ + return *this / q(b); +} + +template +template +fp::q +fp::q::operator%(T b) const +{ + return *this % q(b); +} + +template +template +fp::q & +fp::q::operator+=(T b) +{ + return *this = *this + b; +} + +template +template +fp::q & +fp::q::operator-=(T b) +{ + return *this = *this - b; +} + +template +template +fp::q & +fp::q::operator*=(T b) +{ + return *this = *this * b; +} + +template +template +fp::q & +fp::q::operator/=(T b) +{ + return *this = *this / b; +} + +template +template +fp::q & +fp::q::operator%=(T b) +{ + return *this = *this % b; +} + +template +fp::q +fp::q::operator-() const +{ + q t; + t.i = -i; + return t; +} + +template +template +fp::q & +fp::q::operator=(q b) +{ + i = fp_internal::signed_rsh(b.i); + return *this; +} + +template +fp::q & +fp::q::operator=(int b) +{ + i = fp_internal::signed_lsh((I) b); + return *this; +} + +template +fp::q & +fp::q::operator=(double b) +{ + int exp = 0; + double tmp = frexp(b, &exp); + i = llroundl(ldexp(tmp, exp + f)); + return *this; +} + +template +fp::q & +fp::q::operator=(long double b) +{ + int exp = 0; + long double tmp = frexp(b, &exp); + i = llroundl(ldexp(tmp, exp + f)); + return *this; +} + +template +template +bool +fp::q::operator>=(q b) const +{ + static const unsigned bits = sizeof(I) * 8; + I ma = fp_internal::signed_rsh(i); + I mb = fp_internal::signed_rsh(b.i); + return (ma > mb) + || ((ma == mb) + && ((typename std::make_unsigned::type) + fp_internal::signed_lsh(i) + >= (typename std::make_unsigned::type) + fp_internal::signed_lsh(b.i))); +} + +template +template +bool +fp::q::operator>(q b) const +{ + static const unsigned bits = sizeof(I) * 8; + I ma = fp_internal::signed_rsh(i); + I mb = fp_internal::signed_rsh(b.i); + return (ma > mb) + || ((ma == mb) + && ((typename std::make_unsigned::type) + fp_internal::signed_lsh(i) + > (typename std::make_unsigned::type) + fp_internal::signed_lsh(b.i))); +} + +template +template +bool +fp::q::operator<=(q b) const +{ + static const unsigned bits = sizeof(I) * 8; + I ma = fp_internal::signed_rsh(i); + I mb = fp_internal::signed_rsh(b.i); + return (ma < mb) + || ((ma == mb) + && ((typename std::make_unsigned::type) + fp_internal::signed_lsh(i) + <= (typename std::make_unsigned::type) + fp_internal::signed_lsh(b.i))); +} + +template +template +bool +fp::q::operator<(q b) const +{ + static const unsigned bits = sizeof(I) * 8; + I ma = fp_internal::signed_rsh(i); + I mb = fp_internal::signed_rsh(b.i); + return (ma < mb) + || ((ma == mb) + && ((typename std::make_unsigned::type) + fp_internal::signed_lsh(i) + < (typename std::make_unsigned::type) + fp_internal::signed_lsh(b.i))); +} + +template +template +bool +fp::q::operator==(q b) const +{ + return fp_internal::signed_rsh(i) == b.i + && fp_internal::signed_rsh(b.i) == i; +} + +template +template +bool +fp::q::operator!=(q b) const +{ + return fp_internal::signed_rsh(i) != b.i + || fp_internal::signed_rsh(b.i) != i; +} + +template +fp::q +fp::abs(q x) +{ + return (x.i >= 0 ? x : -x); +} + +namespace sled { +template +using FixedPoint = fp::q; + +using FixedFloat = fp::Q32_32; + +template +inline const FixedPoint +conj(const FixedPoint &val) +{ + return val; +} + +template +inline const FixedPoint +real(const FixedPoint &val) +{ + return val; +} + +template +inline const FixedPoint +imag(const FixedPoint &val) +{ + return 0.; +} + +template +inline const FixedPoint +abs(const FixedPoint &val) +{ + return fp::abs(val); +} + +template +inline const FixedPoint +abs2(const FixedPoint &val) +{ + return val * val; +} + +}// namespace sled + +template +struct fmt::formatter> : ostream_formatter {}; + +namespace Eigen { +template +struct NumTraits> : NumTraits { + typedef sled::FixedPoint Real; + typedef sled::FixedPoint NonInteger; + typedef sled::FixedPoint Nested; + + enum { + IsComplex = 0, + IsInteger = 0, + IsSigned = std::is_signed::value, + RequireInitialization = 1, + ReadCost = 1, + AddCost = 3, + MulCost = 3 + }; +}; + +template +struct ScalarBinaryOpTraits, float, BinaryOp> { + typedef sled::FixedPoint ReturnType; +}; + +template +struct ScalarBinaryOpTraits, BinaryOp> { + typedef sled::FixedPoint ReturnType; +}; + +}// namespace Eigen + +#endif diff --git a/include/sled/queue/circle_queue.h b/include/sled/queue/circle_queue.h index 06d7f67..11eafd8 100644 --- a/include/sled/queue/circle_queue.h +++ b/include/sled/queue/circle_queue.h @@ -14,38 +14,38 @@ namespace sled { template class CircleQueue { - static_assert(LEN > 0, "LEN should be greater than 0"); + static_assert(LEN > 0, "LEN should be greater than 0."); public: void Push(T &&val) { - ASSERT(size() < LEN, "queue is full"); + ASSERT(size() < LEN, "queue is full."); queue_.get(tail_) = std::move(val); ++tail_; } void Push(const T &val) { - ASSERT(size() < LEN, "queue is full"); + ASSERT(size() < LEN, "queue is full."); queue_.get(tail_) = val; ++tail_; } T &Front() { - ASSERT(!empty()); + ASSERT(!empty(), "queue is empty."); return queue_.get(head_); } T &Back() { - ASSERT(!empty()); + ASSERT(!empty(), "queue is empty."); return queue_.get((tail_ + LEN) % (LEN + 1)); } void Pop() { - ASSERT(!empty()); + ASSERT(!empty(), "queue is empty."); head_ = (head_ + 1) % (LEN + 1); } diff --git a/include/sled/scoped_refptr.h b/include/sled/scoped_refptr.h index c55abb4..7d2f731 100644 --- a/include/sled/scoped_refptr.h +++ b/include/sled/scoped_refptr.h @@ -84,6 +84,7 @@ public: scoped_refptr &operator=(const scoped_refptr &&r) noexcept { scoped_refptr(std::move(r)).swap(*this); + return *this; } template diff --git a/src/log/log.cc b/src/log/log.cc index 7499256..f050167 100644 --- a/src/log/log.cc +++ b/src/log/log.cc @@ -3,6 +3,21 @@ #include 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_; +}; + void Log(LogLevel level, const char *tag, @@ -12,6 +27,8 @@ 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--; } diff --git a/src/synchronization/event.cc b/src/synchronization/event.cc index 28e09a6..5b160cc 100644 --- a/src/synchronization/event.cc +++ b/src/synchronization/event.cc @@ -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(lock, 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; }