diff options
| author | Stefan Boberg <[email protected]> | 2021-10-05 22:25:53 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2021-10-05 22:25:53 +0200 |
| commit | 20ac7384f8ca558f1fb933eda846604792240ea0 (patch) | |
| tree | e5c95b422b847af50b77807af916e389fcaf83aa /zencore | |
| parent | stats: Mean returns zero when the count is zero (diff) | |
| download | zen-20ac7384f8ca558f1fb933eda846604792240ea0.tar.xz zen-20ac7384f8ca558f1fb933eda846604792240ea0.zip | |
Merged from upstream
Diffstat (limited to 'zencore')
| -rw-r--r-- | zencore/compactbinary.cpp | 51 | ||||
| -rw-r--r-- | zencore/filesystem.cpp | 9 | ||||
| -rw-r--r-- | zencore/include/zencore/blockingqueue.h | 73 | ||||
| -rw-r--r-- | zencore/include/zencore/refcount.h | 9 | ||||
| -rw-r--r-- | zencore/include/zencore/timer.h | 15 | ||||
| -rw-r--r-- | zencore/timer.cpp | 16 |
6 files changed, 169 insertions, 4 deletions
diff --git a/zencore/compactbinary.cpp b/zencore/compactbinary.cpp index 4072ab5cf..c4694733c 100644 --- a/zencore/compactbinary.cpp +++ b/zencore/compactbinary.cpp @@ -1474,10 +1474,30 @@ public: Builder << Accessor.AsIntegerNegative(); break; case CbFieldType::Float32: - Builder.Append("{:.9g}"_format(Accessor.AsFloat32())); + { + const float Value = Accessor.AsFloat32(); + if (std::isfinite(Value)) + { + Builder.Append("{:.9g}"_format(Value)); + } + else + { + Builder << "null"sv; + } + } break; case CbFieldType::Float64: - Builder.Append("{:.17g}"_format(Accessor.AsFloat64())); + { + const double Value = Accessor.AsFloat64(); + if (std::isfinite(Value)) + { + Builder.Append("{:.17g}"_format(Value)); + } + else + { + Builder << "null"sv; + } + } break; case CbFieldType::BoolFalse: Builder << "false"sv; @@ -1834,7 +1854,7 @@ TEST_CASE("uson.json") SUBCASE("number") { - const double ExpectedFloatValue = 21.21f; + const float ExpectedFloatValue = 21.21f; const double ExpectedDoubleValue = 42.42; CbObjectWriter Writer; @@ -1856,6 +1876,31 @@ TEST_CASE("uson.json") CHECK(FloatValue == doctest::Approx(ExpectedFloatValue)); CHECK(DoubleValue == doctest::Approx(ExpectedDoubleValue)); } + + SUBCASE("number.nan") + { + const float FloatNan = std::numeric_limits<float>::quiet_NaN(); + const double DoubleNan = std::numeric_limits<double>::quiet_NaN(); + + CbObjectWriter Writer; + Writer << "FloatNan" << FloatNan; + Writer << "DoubleNan" << DoubleNan; + + CbObject Obj = Writer.Save(); + + StringBuilder<128> Sb; + const std::string_view JsonText = Obj.ToJson(Sb).ToView(); + + std::string JsonError; + json11::Json Json = json11::Json::parse(JsonText.data(), JsonError); + + const double FloatValue = Json["FloatNan"].number_value(); + const double DoubleValue = Json["DoubleNan"].number_value(); + + CHECK(JsonError.empty()); + CHECK(FloatValue == 0); + CHECK(DoubleValue == 0); + } } #endif diff --git a/zencore/filesystem.cpp b/zencore/filesystem.cpp index f6ba92f98..745fe0779 100644 --- a/zencore/filesystem.cpp +++ b/zencore/filesystem.cpp @@ -63,6 +63,13 @@ DeleteReparsePoint(const wchar_t* Path, DWORD dwReparseTag) bool CreateDirectories(const wchar_t* Dir) { + // This may be suboptimal, in that it appears to try and create directories + // from the root on up instead of from some directory which is known to + // be present + // + // We should implement a smarter version at some point since this can be + // pretty expensive in aggregate + return std::filesystem::create_directories(Dir); } @@ -522,7 +529,7 @@ WriteFile(std::filesystem::path Path, IoBuffer Data) WriteFile(Path, &DataPtr, 1); } -IoBuffer +IoBuffer FileContents::Flatten() { if (Data.size() == 1) diff --git a/zencore/include/zencore/blockingqueue.h b/zencore/include/zencore/blockingqueue.h new file mode 100644 index 000000000..fbb4480a1 --- /dev/null +++ b/zencore/include/zencore/blockingqueue.h @@ -0,0 +1,73 @@ +#pragma once + +#include <atomic> +#include <deque> +#include <mutex> + +namespace zen { + +template<typename T> +class BlockingQueue +{ +public: + BlockingQueue() = default; + + ~BlockingQueue() { CompleteAdding(); } + + void Enqueue(T&& Item) + { + { + std::lock_guard Lock(m_Lock); + m_Queue.emplace_back(std::move(Item)); + m_Size++; + } + + m_NewItemSignal.notify_one(); + } + + bool WaitAndDequeue(T& Item) + { + if (m_CompleteAdding.load()) + { + return false; + } + + std::unique_lock Lock(m_Lock); + m_NewItemSignal.wait(Lock, [this]() { return !m_Queue.empty() || m_CompleteAdding.load(); }); + + if (!m_Queue.empty()) + { + Item = std::move(m_Queue.front()); + m_Queue.pop_front(); + m_Size--; + + return true; + } + + return false; + } + + void CompleteAdding() + { + if (!m_CompleteAdding.load()) + { + m_CompleteAdding.store(true); + m_NewItemSignal.notify_all(); + } + } + + std::size_t Size() const + { + std::unique_lock Lock(m_Lock); + return m_Queue.size(); + } + +private: + mutable std::mutex m_Lock; + std::condition_variable m_NewItemSignal; + std::deque<T> m_Queue; + std::atomic_bool m_CompleteAdding{false}; + std::atomic_uint32_t m_Size; +}; + +} // namespace zen diff --git a/zencore/include/zencore/refcount.h b/zencore/include/zencore/refcount.h index 320718f5b..7167ab3b5 100644 --- a/zencore/include/zencore/refcount.h +++ b/zencore/include/zencore/refcount.h @@ -4,6 +4,8 @@ #include "atomic.h" #include "zencore.h" +#include <concepts> + namespace zen { /** @@ -114,6 +116,10 @@ public: inline Ref(T* Ptr) : m_Ref(Ptr) { m_Ref && m_Ref->AddRef(); } inline ~Ref() { m_Ref && m_Ref->Release(); } + template<typename DerivedType> + requires std::derived_from<DerivedType, T> + inline Ref(const Ref<DerivedType>& Rhs) : Ref(Rhs.m_Ref) {} + [[nodiscard]] inline bool IsNull() const { return m_Ref == nullptr; } inline explicit operator bool() const { return m_Ref != nullptr; } inline T* operator->() const { return m_Ref; } @@ -152,6 +158,9 @@ public: private: T* m_Ref = nullptr; + + template<class T> + friend class Ref; }; void refcount_forcelink(); diff --git a/zencore/include/zencore/timer.h b/zencore/include/zencore/timer.h index 693b6daaa..e4ddc3505 100644 --- a/zencore/include/zencore/timer.h +++ b/zencore/include/zencore/timer.h @@ -38,6 +38,21 @@ private: uint64_t m_StartValue; }; +// Low frequency timers + +namespace detail { + extern ZENCORE_API uint64_t g_LofreqTimerValue; +} // namespace detail + +inline uint64_t +GetLofreqTimerValue() +{ + return detail::g_LofreqTimerValue; +} + +ZENCORE_API void UpdateLofreqTimerValue(); +ZENCORE_API uint64_t GetLofreqTimerFrequency(); + void timer_forcelink(); // internal } // namespace zen diff --git a/zencore/timer.cpp b/zencore/timer.cpp index 5d30d9b29..9180519bd 100644 --- a/zencore/timer.cpp +++ b/zencore/timer.cpp @@ -69,6 +69,22 @@ GetHifreqTimerFrequencySafe() } ////////////////////////////////////////////////////////////////////////// + +uint64_t detail::g_LofreqTimerValue = GetHifreqTimerValue(); + +void +UpdateLofreqTimerValue() +{ + detail::g_LofreqTimerValue = GetHifreqTimerValue(); +} + +uint64_t +GetLofreqTimerFrequency() +{ + return GetHifreqTimerFrequencySafe(); +} + +////////////////////////////////////////////////////////////////////////// // // Testing related code follows... // |