diff options
| author | Stefan Boberg <[email protected]> | 2021-09-15 19:49:20 +0200 |
|---|---|---|
| committer | Stefan Boberg <[email protected]> | 2021-09-15 19:49:20 +0200 |
| commit | 83ccd52321a23c8f1c8a3228cbbf34b8f199a22b (patch) | |
| tree | 9cf1fb68651f616aef2fa28000e4f328ef9204d8 /zencore | |
| parent | Added GetSize/GetData functions to reduce cognitive load and bridge the gap b... (diff) | |
| parent | Tweaked logging to streamline access, and simplified setup code for new loggers (diff) | |
| download | zen-83ccd52321a23c8f1c8a3228cbbf34b8f199a22b.tar.xz zen-83ccd52321a23c8f1c8a3228cbbf34b8f199a22b.zip | |
Merge branch 'main' into cbpackage-update
Diffstat (limited to 'zencore')
32 files changed, 502 insertions, 85 deletions
diff --git a/zencore/compress.cpp b/zencore/compress.cpp index 2b2c4dd0b..12a7b9ef8 100644 --- a/zencore/compress.cpp +++ b/zencore/compress.cpp @@ -8,11 +8,14 @@ #include <zencore/endian.h> #include "../3rdparty/Oodle/include/oodle2.h" -#pragma comment(lib, "oo2core_win64.lib") +#if ZEN_PLATFORM_WINDOWS +# pragma comment(lib, "oo2core_win64.lib") +#endif #include <doctest/doctest.h> #include <lz4.h> #include <functional> +#include <limits> namespace zen::detail { @@ -100,7 +103,7 @@ struct BufferHeader constexpr uint64_t MethodOffset = offsetof(BufferHeader, Method); for (MemoryView View = HeaderView + MethodOffset; const uint64_t ViewSize = View.GetSize();) { - const int32_t Size = static_cast<int32_t>(zen::Min<uint64_t>(ViewSize, INT_MAX)); + const int32_t Size = static_cast<int32_t>(zen::Min<uint64_t>(ViewSize, /* INT_MAX */ 2147483647u)); Crc32 = zen::MemCrc32(View.GetData(), Size, Crc32); View += Size; } @@ -208,7 +211,7 @@ private: CompositeBuffer BlockEncoder::Compress(const CompositeBuffer& RawData, const uint64_t BlockSize) const { - ZEN_ASSERT(IsPow2(BlockSize) && BlockSize <= (1 << 31)); + ZEN_ASSERT(IsPow2(BlockSize) && (BlockSize <= (1u << 31))); const uint64_t RawSize = RawData.GetSize(); BLAKE3Stream RawHash; @@ -589,7 +592,7 @@ protected: const int Size = LZ4_decompress_safe(static_cast<const char*>(CompressedData.GetData()), static_cast<char*>(RawData.GetData()), static_cast<int>(CompressedData.GetSize()), - static_cast<int>(zen::Min<uint64_t>(RawData.GetSize(), LZ4_MAX_INPUT_SIZE))); + static_cast<int>(zen::Min<uint64_t>(RawData.GetSize(), uint64_t(LZ4_MAX_INPUT_SIZE)))); return static_cast<uint64_t>(Size) == RawData.GetSize(); } return false; diff --git a/zencore/except.cpp b/zencore/except.cpp index 9bd447308..834585522 100644 --- a/zencore/except.cpp +++ b/zencore/except.cpp @@ -2,10 +2,11 @@ #include <fmt/format.h> #include <zencore/except.h> -#include <system_error> namespace zen { +#if ZEN_PLATFORM_WINDOWS + void ThrowSystemException([[maybe_unused]] HRESULT hRes, [[maybe_unused]] std::string_view Message) { @@ -19,16 +20,18 @@ ThrowSystemException([[maybe_unused]] HRESULT hRes, [[maybe_unused]] std::string } } +#endif // ZEN_PLATFORM_WINDOWS + void ThrowLastError(std::string_view Message) { - throw std::system_error(std::error_code(::GetLastError(), std::system_category()), std::string(Message)); + throw std::system_error(std::error_code(zen::GetLastError(), std::system_category()), std::string(Message)); } std::string GetLastErrorAsString() { - return GetWindowsErrorAsString(::GetLastError()); + return GetWindowsErrorAsString(zen::GetLastError()); } std::string @@ -37,12 +40,14 @@ GetWindowsErrorAsString(uint32_t Win32ErrorCode) return std::error_code(Win32ErrorCode, std::system_category()).message(); } +#if __cpp_lib_source_location void ThrowLastError(std::string_view Message, const std::source_location& Location) { using namespace fmt::literals; - throw std::system_error(std::error_code(::GetLastError(), std::system_category()), + throw std::system_error(std::error_code(zen::GetLastError(), std::system_category()), "{}({}): {}"_format(Location.file_name(), Location.line(), Message)); } +#endif } // namespace zen diff --git a/zencore/filesystem.cpp b/zencore/filesystem.cpp index 09c2e7386..59300b7ad 100644 --- a/zencore/filesystem.cpp +++ b/zencore/filesystem.cpp @@ -5,6 +5,7 @@ #include <zencore/except.h> #include <zencore/fmtutils.h> #include <zencore/iobuffer.h> +#include <zencore/logging.h> #include <zencore/string.h> #include <zencore/windows.h> @@ -14,8 +15,6 @@ #include <winnt.h> #include <filesystem> -#include <spdlog/spdlog.h> - #include <gsl/gsl-lite.hpp> namespace zen { @@ -582,7 +581,7 @@ FileSystemTraversal::TraverseFileSystem(const std::filesystem::path& RootDir, Tr } else if (DirInfo->FileAttributes & FILE_ATTRIBUTE_DEVICE) { - spdlog::warn("encountered device node during file system traversal: {} found in {}", WideToUtf8(FileName), RootDir); + ZEN_WARN("encountered device node during file system traversal: {} found in {}", WideToUtf8(FileName), RootDir); } else { @@ -618,6 +617,8 @@ PathFromHandle(void* NativeHandle) const DWORD FinalLength = GetFinalPathNameByHandleW(NativeHandle, FullPath.data(), RequiredLengthIncludingNul, FILE_NAME_OPENED); + ZEN_UNUSED(FinalLength); + return FullPath; } diff --git a/zencore/include/zencore/atomic.h b/zencore/include/zencore/atomic.h index 457128bd4..7e261771b 100644 --- a/zencore/include/zencore/atomic.h +++ b/zencore/include/zencore/atomic.h @@ -2,7 +2,14 @@ #pragma once +#include <zencore/zencore.h> + +#if ZEN_COMPILER_MSC #include <intrin.h> +#else +#include <atomic> +#endif + #include <cinttypes> namespace zen { @@ -10,34 +17,58 @@ namespace zen { inline uint32_t AtomicIncrement(volatile uint32_t& value) { +#if ZEN_COMPILER_MSC return _InterlockedIncrement((long volatile*)&value); +#else + return ((std::atomic<uint32_t>*)(&value))->fetch_add(1, std::memory_order_seq_cst) + 1; +#endif } inline uint32_t AtomicDecrement(volatile uint32_t& value) { +#if ZEN_COMPILER_MSC return _InterlockedDecrement((long volatile*)&value); +#else + return ((std::atomic<uint32_t>*)(&value))->fetch_sub(1, std::memory_order_seq_cst) - 1; +#endif } inline uint64_t AtomicIncrement(volatile uint64_t& value) { +#if ZEN_COMPILER_MSC return _InterlockedIncrement64((__int64 volatile*)&value); +#else + return ((std::atomic<uint64_t>*)(&value))->fetch_add(1, std::memory_order_seq_cst) + 1; +#endif } inline uint64_t AtomicDecrement(volatile uint64_t& value) { +#if ZEN_COMPILER_MSC return _InterlockedDecrement64((__int64 volatile*)&value); +#else + return ((std::atomic<uint64_t>*)(&value))->fetch_sub(1, std::memory_order_seq_cst) - 1; +#endif } inline uint32_t AtomicAdd(volatile uint32_t& value, uint32_t amount) { +#if ZEN_COMPILER_MSC return _InterlockedExchangeAdd((long volatile*)&value, amount); +#else + return ((std::atomic<uint32_t>*)(&value))->fetch_add(amount, std::memory_order_seq_cst); +#endif } inline uint64_t AtomicAdd(volatile uint64_t& value, uint64_t amount) { +#if ZEN_COMPILER_MSC return _InterlockedExchangeAdd64((__int64 volatile*)&value, amount); +#else + return ((std::atomic<uint64_t>*)(&value))->fetch_add(amount, std::memory_order_seq_cst); +#endif } } // namespace zen diff --git a/zencore/include/zencore/compactbinary.h b/zencore/include/zencore/compactbinary.h index 09619be8b..4fce129ea 100644 --- a/zencore/include/zencore/compactbinary.h +++ b/zencore/include/zencore/compactbinary.h @@ -748,6 +748,8 @@ private: friend class CbFieldViewIterator; + friend class CbFieldIterator; + /** Pointer to the first byte past the end of the last field. Set to null at the end. */ const void* FieldsEnd = nullptr; }; diff --git a/zencore/include/zencore/compactbinarybuilder.h b/zencore/include/zencore/compactbinarybuilder.h index f7f2bbfd3..5f6d9fd0c 100644 --- a/zencore/include/zencore/compactbinarybuilder.h +++ b/zencore/include/zencore/compactbinarybuilder.h @@ -533,7 +533,7 @@ operator<<(CbWriter& Writer, const CbArray& Value) } inline CbWriter& -operator<<(CbWriter& Writer, nullptr_t) +operator<<(CbWriter& Writer, std::nullptr_t) { Writer.AddNull(); return Writer; diff --git a/zencore/include/zencore/endian.h b/zencore/include/zencore/endian.h index 1f79a59e8..d44a27b01 100644 --- a/zencore/include/zencore/endian.h +++ b/zencore/include/zencore/endian.h @@ -7,19 +7,31 @@ namespace zen { inline uint16_t ByteSwap(uint16_t x) { +#if ZEN_COMPILER_MSC return _byteswap_ushort(x); +#else + return __builtin_bswap16(x); +#endif } inline uint32_t ByteSwap(uint32_t x) { +#if ZEN_COMPILER_MSC return _byteswap_ulong(x); +#else + return __builtin_bswap32(x); +#endif } inline uint64_t ByteSwap(uint64_t x) { +#if ZEN_COMPILER_MSC return _byteswap_uint64(x); +#else + return __builtin_bswap64(x); +#endif } inline uint16_t diff --git a/zencore/include/zencore/except.h b/zencore/include/zencore/except.h index 8625f01d0..36cca895f 100644 --- a/zencore/include/zencore/except.h +++ b/zencore/include/zencore/except.h @@ -3,12 +3,18 @@ #pragma once #include <zencore/string.h> -#include <zencore/windows.h> +#if ZEN_PLATFORM_WINDOWS +# include <zencore/windows.h> +#else +# include <errno.h> +#endif #include <source_location> #include <string> +#include <system_error> namespace zen { +#if ZEN_PLATFORM_WINDOWS class WindowsException : public std::exception { public: @@ -45,17 +51,36 @@ private: }; ZENCORE_API void ThrowSystemException(HRESULT hRes, std::string_view Message); +#endif // ZEN_PLATFORM_WINDOWS + +ZENCORE_API void ThrowLastError(std::string_view Message); + +#if __cpp_lib_source_location +ZENCORE_API void ThrowLastError(std::string_view Message, const std::source_location& Location); +#endif + +ZENCORE_API std::string GetLastErrorAsString(); +ZENCORE_API std::string GetWindowsErrorAsString(uint32_t Win32ErrorCode); inline void ThrowSystemException(const char* Message) { +#if ZEN_PLATFORM_WINDOWS throw WindowsException(Message); +#else + ThrowLastError(Message); +#endif } -ZENCORE_API void ThrowLastError(std::string_view Message); -ZENCORE_API void ThrowLastError(std::string_view Message, const std::source_location& Location); -ZENCORE_API std::string GetLastErrorAsString(); -ZENCORE_API std::string GetWindowsErrorAsString(uint32_t Win32ErrorCode); +inline int32_t +GetLastError() +{ +#if ZEN_PLATFORM_WINDOWS + return ::GetLastError(); +#else + return errno; +#endif +} inline std::error_code MakeWin32ErrorCode(uint32_t Win32ErrorCode) noexcept @@ -66,7 +91,7 @@ MakeWin32ErrorCode(uint32_t Win32ErrorCode) noexcept inline std::error_code MakeErrorCodeFromLastError() noexcept { - return std::error_code(::GetLastError(), std::system_category()); + return std::error_code(zen::GetLastError(), std::system_category()); } } // namespace zen diff --git a/zencore/include/zencore/fmtutils.h b/zencore/include/zencore/fmtutils.h index fb5a08d56..29e2ae78a 100644 --- a/zencore/include/zencore/fmtutils.h +++ b/zencore/include/zencore/fmtutils.h @@ -43,7 +43,7 @@ struct fmt::formatter<std::filesystem::path> : formatter<string_view> auto format(const std::filesystem::path& Path, FormatContext& ctx) { zen::ExtendableStringBuilder<128> String; - WideToUtf8(Path.c_str(), String); + String << Path.u8string(); return formatter<string_view>::format(String.ToView(), ctx); } }; diff --git a/zencore/include/zencore/intmath.h b/zencore/include/zencore/intmath.h index 792b8b2b4..814a03df4 100644 --- a/zencore/include/zencore/intmath.h +++ b/zencore/include/zencore/intmath.h @@ -9,8 +9,46 @@ ////////////////////////////////////////////////////////////////////////// -#pragma intrinsic(_BitScanReverse) -#pragma intrinsic(_BitScanReverse64) +#if ZEN_COMPILER_MSC || ZEN_PLATFORM_WINDOWS +# pragma intrinsic(_BitScanReverse) +# pragma intrinsic(_BitScanReverse64) +#else +inline uint8_t +_BitScanReverse(unsigned long* Index, uint32_t Mask) +{ + if (Mask == 0) + { + return 0; + } + + *Index = __builtin_clz(Mask); + return 1; +} + +inline uint8_t +_BitScanReverse64(unsigned long* Index, uint64_t Mask) +{ + if (Mask == 0) + { + return 0; + } + + *Index = __builtin_clzll(Mask); + return 0; +} + +inline uint8_t +_BitScanForward64(unsigned long* Index, uint64_t Mask) +{ + if (Mask == 0) + { + return 0; + } + + *Index = __builtin_ctzll(Mask); + return 0; +} +#endif namespace zen { @@ -121,8 +159,10 @@ IsPointerAligned(const void* Ptr, uint64_t Alignment) ////////////////////////////////////////////////////////////////////////// -#ifdef min -# error "Looks like you did #include <windows.h> -- use <zencore/windows.h> instead" +#if ZEN_PLATFORM_WINDOWS +# ifdef min +# error "Looks like you did #include <windows.h> -- use <zencore/windows.h> instead" +# endif #endif constexpr auto @@ -137,4 +177,8 @@ Max(auto x, auto y) return x > y ? x : y; } +////////////////////////////////////////////////////////////////////////// + +void intmath_forcelink(); // internal + } // namespace zen diff --git a/zencore/include/zencore/iohash.h b/zencore/include/zencore/iohash.h index aaa638684..fd0f4b2a7 100644 --- a/zencore/include/zencore/iohash.h +++ b/zencore/include/zencore/iohash.h @@ -8,6 +8,7 @@ #include <zencore/blake3.h> #include <zencore/memory.h> +#include <compare> #include <string_view> namespace zen { diff --git a/zencore/include/zencore/logging.h b/zencore/include/zencore/logging.h index a2404a5e9..4eee20414 100644 --- a/zencore/include/zencore/logging.h +++ b/zencore/include/zencore/logging.h @@ -13,6 +13,7 @@ namespace zen::logging { spdlog::logger& Default(); +void SetDefault(std::shared_ptr<spdlog::logger> NewDefaultLogger); spdlog::logger& ConsoleLog(); spdlog::logger& Get(std::string_view Name); @@ -20,3 +21,29 @@ void InitializeLogging(); void ShutdownLogging(); } // namespace zen::logging + +namespace zen { +extern spdlog::logger* TheDefaultLogger; + +inline spdlog::logger& +Log() +{ + return *TheDefaultLogger; +} + +using logging::ConsoleLog; +} // namespace zen + +using zen::ConsoleLog; +using zen::Log; + +// Helper macros for logging + +using namespace std::literals; + +#define ZEN_TRACE(fmtstr, ...) Log().trace(fmtstr##sv, __VA_ARGS__) +#define ZEN_DEBUG(fmtstr, ...) Log().debug(fmtstr##sv, __VA_ARGS__) +#define ZEN_INFO(fmtstr, ...) Log().info(fmtstr##sv, __VA_ARGS__) +#define ZEN_WARN(fmtstr, ...) Log().warn(fmtstr##sv, __VA_ARGS__) +#define ZEN_ERROR(fmtstr, ...) Log().error(fmtstr##sv, __VA_ARGS__) +#define ZEN_CRITICAL(fmtstr, ...) Log().critical(fmtstr##sv, __VA_ARGS__) diff --git a/zencore/include/zencore/memory.h b/zencore/include/zencore/memory.h index 5a324955d..9d6339595 100644 --- a/zencore/include/zencore/memory.h +++ b/zencore/include/zencore/memory.h @@ -8,6 +8,8 @@ #include <zencore/thread.h> #include <algorithm> +#include <cstddef> +#include <cstring> #include <span> #include <vector> @@ -81,7 +83,7 @@ struct MutableMemoryView { } - inline bool IsEmpty() const { return m_Data == m_DataEnd; } + inline bool IsEmpty() const { return m_Data == m_DataEnd; } void* GetData() const { return m_Data; } void* GetDataEnd() const { return m_DataEnd; } size_t GetSize() const { return reinterpret_cast<uint8_t*>(m_DataEnd) - reinterpret_cast<uint8_t*>(m_Data); } @@ -111,7 +113,7 @@ struct MutableMemoryView } /** Modifies the view by chopping the given number of bytes from the left. */ - inline constexpr void RightChopInline(uint64_t InSize) + inline void RightChopInline(uint64_t InSize) { const uint64_t Offset = zen::Min(GetSize(), InSize); m_Data = GetDataAtOffsetNoCheck(Offset); @@ -151,7 +153,7 @@ struct MutableMemoryView return View; } - inline constexpr MutableMemoryView& operator+=(size_t InSize) + inline MutableMemoryView& operator+=(size_t InSize) { RightChopInline(InSize); return *this; @@ -192,10 +194,10 @@ struct MemoryView { } - inline bool Contains(const MemoryView& Other) const { return (m_Data <= Other.m_Data) && (m_DataEnd >= Other.m_DataEnd); } - inline bool IsEmpty() const { return m_Data == m_DataEnd; } - const void* GetData() const { return m_Data; } - const void* GetDataEnd() const { return m_DataEnd; } + inline bool Contains(const MemoryView& Other) const { return (m_Data <= Other.m_Data) && (m_DataEnd >= Other.m_DataEnd); } + inline bool IsEmpty() const { return m_Data == m_DataEnd; } + const void* GetData() const { return m_Data; } + const void* GetDataEnd() const { return m_DataEnd; } size_t GetSize() const { return reinterpret_cast<const uint8_t*>(m_DataEnd) - reinterpret_cast<const uint8_t*>(m_Data); } inline bool operator==(const MemoryView& Rhs) const { return m_Data == Rhs.m_Data && m_DataEnd == Rhs.m_DataEnd; } @@ -206,14 +208,14 @@ struct MemoryView return Size == InView.GetSize() && (memcmp(m_Data, InView.GetData(), Size) == 0); } - inline constexpr MemoryView& operator+=(size_t InSize) + inline MemoryView& operator+=(size_t InSize) { RightChopInline(InSize); return *this; } /** Modifies the view by chopping the given number of bytes from the left. */ - inline constexpr void RightChopInline(uint64_t InSize) + inline void RightChopInline(uint64_t InSize) { const uint64_t Offset = std::min(GetSize(), InSize); m_Data = GetDataAtOffsetNoCheck(Offset); @@ -244,7 +246,7 @@ struct MemoryView } /** Returns the left-most part of the view by taking the given number of bytes from the left. */ - constexpr inline MemoryView Left(uint64_t InSize) const + inline MemoryView Left(uint64_t InSize) const { MemoryView View(*this); View.LeftInline(InSize); @@ -252,7 +254,7 @@ struct MemoryView } /** Modifies the view to be the given number of bytes from the left. */ - constexpr inline void LeftInline(uint64_t InSize) + inline void LeftInline(uint64_t InSize) { InSize = zen::Min(GetSize(), InSize); m_DataEnd = std::min(m_DataEnd, m_Data + InSize); @@ -296,28 +298,28 @@ MutableMemoryView::CopyFrom(MemoryView InView) const } /** Advances the start of the view by an offset, which is clamped to stay within the view. */ -constexpr inline MemoryView +inline MemoryView operator+(const MemoryView& View, uint64_t Offset) { return MemoryView(View) += Offset; } /** Advances the start of the view by an offset, which is clamped to stay within the view. */ -constexpr inline MemoryView +inline MemoryView operator+(uint64_t Offset, const MemoryView& View) { return MemoryView(View) += Offset; } /** Advances the start of the view by an offset, which is clamped to stay within the view. */ -constexpr inline MutableMemoryView +inline MutableMemoryView operator+(const MutableMemoryView& View, uint64_t Offset) { return MutableMemoryView(View) += Offset; } /** Advances the start of the view by an offset, which is clamped to stay within the view. */ -constexpr inline MutableMemoryView +inline MutableMemoryView operator+(uint64_t Offset, const MutableMemoryView& View) { return MutableMemoryView(View) += Offset; diff --git a/zencore/include/zencore/sharedbuffer.h b/zencore/include/zencore/sharedbuffer.h index b230c05b1..640c3fe74 100644 --- a/zencore/include/zencore/sharedbuffer.h +++ b/zencore/include/zencore/sharedbuffer.h @@ -12,6 +12,8 @@ namespace zen { +class SharedBuffer; + /** * Reference to a memory buffer with a single owner * diff --git a/zencore/include/zencore/string.h b/zencore/include/zencore/string.h index de2ca71d9..2b5f20f86 100644 --- a/zencore/include/zencore/string.h +++ b/zencore/include/zencore/string.h @@ -560,15 +560,17 @@ NiceRate(uint64_t Num, uint32_t DurationMilliseconds, const char* Unit = "B") if (DurationMilliseconds) { - NiceNumToBuffer(Num * 1000 / DurationMilliseconds, Buffer); + // Leave a little of 'Buffer' for the "Unit/s" suffix + std::span<char> BufferSpan(Buffer, sizeof(Buffer) - 8); + NiceNumToBuffer(Num * 1000 / DurationMilliseconds, BufferSpan); } else { - strcpy_s(Buffer, "0"); + strcpy(Buffer, "0"); } - strcat_s(Buffer, Unit); - strcat_s(Buffer, "/s"); + strncat(Buffer, Unit, 4); + strcat(Buffer, "/s"); return Buffer; } diff --git a/zencore/include/zencore/thread.h b/zencore/include/zencore/thread.h index 30d0c0897..b18da6031 100644 --- a/zencore/include/zencore/thread.h +++ b/zencore/include/zencore/thread.h @@ -4,6 +4,10 @@ #include "zencore.h" +#if !ZEN_PLATFORM_WINDOWS +# include <shared_mutex> +#endif + namespace zen { /** @@ -60,7 +64,11 @@ public: }; private: +#if ZEN_PLATFORM_WINDOWS void* m_Srw = nullptr; +#else + std::shared_mutex m_Mutex; +#endif }; /** Basic abstraction of a simple event synchronization mechanism (aka 'binary semaphore') diff --git a/zencore/include/zencore/timer.h b/zencore/include/zencore/timer.h index c9122eb44..eb284eaee 100644 --- a/zencore/include/zencore/timer.h +++ b/zencore/include/zencore/timer.h @@ -2,10 +2,16 @@ #pragma once -#include <intrin.h> -#include <stdint.h> #include "zencore.h" +#if ZEN_COMPILER_MSC +# include <intrin.h> +#elif ZEN_ARCH_X64 +# include <x86intrin.h> +#endif + +#include <stdint.h> + namespace zen { // High frequency timers diff --git a/zencore/include/zencore/zencore.h b/zencore/include/zencore/zencore.h index 206046f0b..73446b447 100644 --- a/zencore/include/zencore/zencore.h +++ b/zencore/include/zencore/zencore.h @@ -10,24 +10,65 @@ // Platform // -#define ZEN_PLATFORM_WINDOWS 1 -#define ZEN_PLATFORM_LINUX 0 -#define ZEN_PLATFORM_MACOS 0 +#define ZEN_PLATFORM_WINDOWS 0 +#define ZEN_PLATFORM_LINUX 0 +#define ZEN_PLATFORM_MACOS 0 + +#ifdef _WIN32 +# undef ZEN_PLATFORM_WINDOWS +# define ZEN_PLATFORM_WINDOWS 1 +#elif defined(__linux__) +# undef ZEN_PLATFORM_LINUX +# define ZEN_PLATFORM_LINUX 1 +#elif defined(__APPLE__) +# undef ZEN_PLATFORM_MACOS +# define ZEN_PLATFORM_MACOS 1 +#endif ////////////////////////////////////////////////////////////////////////// // Compiler // -#ifdef _MSC_VER -# define ZEN_COMPILER_MSC 1 +#define ZEN_COMPILER_CLANG 0 +#define ZEN_COMPILER_MSC 0 +#define ZEN_COMPILER_GCC 0 + +// Clang can define __GNUC__ and/or _MSC_VER so we check for Clang first +#ifdef __clang__ +# undef ZEN_COMPILER_CLANG +# define ZEN_COMPILER_CLANG 1 +#elif defined(_MSC_VER) +# undef ZEN_COMPILER_MSC +# define ZEN_COMPILER_MSC 1 +#elif defined(__GNUC__) +# undef ZEN_COMPILER_GCC +# define ZEN_COMPILER_GCC 1 +#else +# error Unknown compiler #endif -#ifndef ZEN_COMPILER_MSC -# define ZEN_COMPILER_MSC 0 +// Check for C++20 support +#if !ZEN_PLATFORM_WINDOWS +# if ZEN_COMPILER_CLANG && __clang_major__ < 14 +# error LLVM-14 onwards required for complete C++20 support +# elif ZEN_COMPILER_GCC && __GNUC__ < 11 +# error GCC-11 onwards required for complete C++20 support +# endif #endif -#ifndef ZEN_COMPILER_CLANG -# define ZEN_COMPILER_CLANG 0 + +////////////////////////////////////////////////////////////////////////// +// Architecture +// + +#if defined(__amd64__) || defined(_M_X64) +# define ZEN_ARCH_X64 1 +# define ZEN_ARCH_ARM64 0 +#elif defined(__arm64__) || defined(_M_ARM64) +# define ZEN_ARCH_X64 0 +# define ZEN_ARCH_ARM64 1 +#else +# error Unknown architecture #endif ////////////////////////////////////////////////////////////////////////// @@ -58,7 +99,7 @@ public: AssertException(const char* Msg); ~AssertException(); - [[nodiscard]] virtual char const* what() const override { return m_Msg.c_str(); } + [[nodiscard]] virtual char const* what() const noexcept override { return m_Msg.c_str(); } private: std::string m_Msg; @@ -100,7 +141,12 @@ char (&ZenArrayCountHelper(const T (&)[N]))[N + 1]; ////////////////////////////////////////////////////////////////////////// -#define ZEN_NOINLINE __declspec(noinline) +#if ZEN_COMPILER_MSC +# define ZEN_NOINLINE __declspec(noinline) +#else +# define ZEN_NOINLINE __attribute__((noinline)) +#endif + #define ZEN_UNUSED(...) ((void)__VA_ARGS__) #define ZEN_NOT_IMPLEMENTED(...) ZEN_ASSERT(false) #define ZENCORE_API // Placeholder to allow DLL configs in the future diff --git a/zencore/intmath.cpp b/zencore/intmath.cpp new file mode 100644 index 000000000..4039a3b39 --- /dev/null +++ b/zencore/intmath.cpp @@ -0,0 +1,56 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include <zencore/intmath.h> + +#include <doctest/doctest.h> + +namespace zen { + +////////////////////////////////////////////////////////////////////////// +// +// Testing related code follows... +// + +void +intmath_forcelink() +{ +} + +TEST_CASE("intmath") +{ + CHECK(FloorLog2(0x00) == 0); + CHECK(FloorLog2(0x01) == 0); + CHECK(FloorLog2(0x0f) == 3); + CHECK(FloorLog2(0x10) == 4); + CHECK(FloorLog2(0x11) == 4); + CHECK(FloorLog2(0x12) == 4); + CHECK(FloorLog2(0x22) == 5); + CHECK(FloorLog2(0x0001'0000) == 16); + CHECK(FloorLog2(0x0001'000f) == 16); + CHECK(FloorLog2(0x8000'0000) == 31); + + CHECK(FloorLog2_64(0x00ull) == 0); + CHECK(FloorLog2_64(0x01ull) == 0); + CHECK(FloorLog2_64(0x0full) == 3); + CHECK(FloorLog2_64(0x10ull) == 4); + CHECK(FloorLog2_64(0x11ull) == 4); + CHECK(FloorLog2_64(0x0001'0000ull) == 16); + CHECK(FloorLog2_64(0x0001'000full) == 16); + CHECK(FloorLog2_64(0x8000'0000ull) == 31); + CHECK(FloorLog2_64(0x0000'0001'0000'0000ull) == 32); + CHECK(FloorLog2_64(0x8000'0000'0000'0000ull) == 63); + + CHECK(CountLeadingZeros64(0x8000'0000'0000'0000ull) == 0); + CHECK(CountLeadingZeros64(0x0000'0000'0000'0000ull) == 64); + CHECK(CountLeadingZeros64(0x0000'0000'0000'0001ull) == 63); + CHECK(CountLeadingZeros64(0x0000'0000'8000'0000ull) == 32); + CHECK(CountLeadingZeros64(0x0000'0001'0000'0000ull) == 31); + + CHECK(CountTrailingZeros64(0x8000'0000'0000'0000ull) == 63); + CHECK(CountTrailingZeros64(0x0000'0000'0000'0000ull) == 64); + CHECK(CountTrailingZeros64(0x0000'0000'0000'0001ull) == 0); + CHECK(CountTrailingZeros64(0x0000'0000'8000'0000ull) == 31); + CHECK(CountTrailingZeros64(0x0000'0001'0000'0000ull) == 32); +} + +} // namespace zen diff --git a/zencore/iobuffer.cpp b/zencore/iobuffer.cpp index 9c7781663..758cf539c 100644 --- a/zencore/iobuffer.cpp +++ b/zencore/iobuffer.cpp @@ -6,12 +6,12 @@ #include <memory.h> #include <zencore/filesystem.h> #include <zencore/fmtutils.h> +#include <zencore/logging.h> #include <zencore/memory.h> #include <zencore/thread.h> #include <system_error> #include <atlfile.h> -#include <spdlog/spdlog.h> #include <gsl/gsl-lite.hpp> namespace zen { @@ -165,7 +165,7 @@ IoBufferExtendedCore::~IoBufferExtendedCore() if (!Success) { - spdlog::warn("Error reported on file handle close!"); + ZEN_WARN("Error reported on file handle close!"); } } @@ -220,7 +220,7 @@ IoBufferExtendedCore::Materialize() const { throw std::system_error( std::error_code(::GetLastError(), std::system_category()), - "MapViewOfFile failed (offset {#x}, size {#x}) file: '{}'"_format(MapOffset, MapSize, zen::PathFromHandle(m_FileHandle))); + "MapViewOfFile failed (offset {:#x}, size {:#x}) file: '{}'"_format(MapOffset, MapSize, zen::PathFromHandle(m_FileHandle))); } m_MappedPointer = MappedBase; diff --git a/zencore/logging.cpp b/zencore/logging.cpp index 6441fc3bc..c5c0b6446 100644 --- a/zencore/logging.cpp +++ b/zencore/logging.cpp @@ -4,25 +4,36 @@ #include <spdlog/sinks/stdout_color_sinks.h> +namespace zen { + +// We shadow the underlying spdlog default logger, in order to avoid a bunch of overhead +spdlog::logger* TheDefaultLogger; + +} // namespace zen + namespace zen::logging { spdlog::logger& Default() { - return *spdlog::default_logger(); + return *TheDefaultLogger; +} + +void +SetDefault(std::shared_ptr<spdlog::logger> NewDefaultLogger) +{ + spdlog::set_default_logger(NewDefaultLogger); + TheDefaultLogger = spdlog::default_logger_raw(); } spdlog::logger& Get(std::string_view Name) { std::shared_ptr<spdlog::logger> Logger = spdlog::get(std::string(Name)); + if (!Logger) { - Logger = std::make_shared<spdlog::logger>(std::string(Name), - begin(spdlog::default_logger()->sinks()), - end(spdlog::default_logger()->sinks())); - - Logger->set_level(spdlog::default_logger()->level()); + Logger = Default().clone(std::string(Name)); spdlog::register_logger(Logger); } @@ -47,6 +58,7 @@ ConsoleLog() void InitializeLogging() { + TheDefaultLogger = spdlog::default_logger_raw(); } void diff --git a/zencore/memory.cpp b/zencore/memory.cpp index 63d61f5e1..9c7fb8333 100644 --- a/zencore/memory.cpp +++ b/zencore/memory.cpp @@ -1,15 +1,47 @@ // Copyright Epic Games, Inc. All Rights Reserved. -#include <malloc.h> #include <zencore/intmath.h> #include <zencore/memory.h> +#ifdef ZEN_PLATFORM_WINDOWS +# include <malloc.h> +#else +# include <cstdlib> +#endif + #include <doctest/doctest.h> namespace zen { ////////////////////////////////////////////////////////////////////////// +static void* AlignedAllocImpl(size_t size, size_t alignment) +{ +#if ZEN_PLATFORM_WINDOWS + // return _aligned_malloc(size, alignment); // MSVC alternative + return _mm_malloc(size, alignment); +#else + // posix_memalign(&Ret, Alignment, Size); // Apple, AndroidApi<28 + return std::aligned_alloc(alignment, size); +#endif +} + +void AlignedFreeImpl(void* ptr) +{ + if (ptr == nullptr) + return; + +#if ZEN_PLATFORM_WINDOWS + // _aligned_free(ptr); MSVC alternative + _mm_free(ptr); +#else + // free(ptr) // Apple :) + std::free(ptr); +#endif +} + +////////////////////////////////////////////////////////////////////////// + MemoryArena::MemoryArena() { } @@ -21,14 +53,13 @@ MemoryArena::~MemoryArena() void* MemoryArena::Alloc(size_t size, size_t alignment) { - return _mm_malloc(size, alignment); + return AlignedAllocImpl(size, alignment); } void MemoryArena::Free(void* ptr) { - if (ptr) - _mm_free(ptr); + AlignedFreeImpl(ptr); } ////////////////////////////////////////////////////////////////////////// @@ -36,14 +67,13 @@ MemoryArena::Free(void* ptr) void* Memory::Alloc(size_t size, size_t alignment) { - return _mm_malloc(size, alignment); + return AlignedAllocImpl(size, alignment); } void Memory::Free(void* ptr) { - if (ptr) - _mm_free(ptr); + AlignedFreeImpl(ptr); } ////////////////////////////////////////////////////////////////////////// diff --git a/zencore/sharedbuffer.cpp b/zencore/sharedbuffer.cpp index a14da1bf7..2761d0b4d 100644 --- a/zencore/sharedbuffer.cpp +++ b/zencore/sharedbuffer.cpp @@ -5,7 +5,6 @@ #include <doctest/doctest.h> #include <memory.h> -#include <atlfile.h> #include <gsl/gsl-lite.hpp> namespace zen { diff --git a/zencore/snapshot_manifest.cpp b/zencore/snapshot_manifest.cpp index 7d0769d13..87625fb7f 100644 --- a/zencore/snapshot_manifest.cpp +++ b/zencore/snapshot_manifest.cpp @@ -13,7 +13,9 @@ // Used for getting My Documents for default snapshot dir #include <ShlObj.h> -#pragma comment(lib, "shell32.lib") +#if ZEN_PLATFORM_WINDOWS +# pragma comment(lib, "shell32.lib") +#endif namespace zen { diff --git a/zencore/stream.cpp b/zencore/stream.cpp index bd925ebc4..8687d5501 100644 --- a/zencore/stream.cpp +++ b/zencore/stream.cpp @@ -5,7 +5,7 @@ #include <zencore/memory.h> #include <zencore/stream.h> #include <algorithm> -#include <exception> +#include <stdexcept> namespace zen { @@ -22,7 +22,7 @@ MemoryInStream::Read(void* buffer, size_t byteCount, uint64_t offset) const size_t needEnd = offset + byteCount; if (needEnd > m_Buffer.size()) - throw std::exception("read past end of file!"); // TODO: better exception + throw std::runtime_error("read past end of file!"); // TODO: better exception memcpy(buffer, m_Buffer.data() + offset, byteCount); } @@ -95,7 +95,11 @@ TextWriter& operator<<(TextWriter& writer, int8_t value) { char buffer[16]; +#if ZEN_PLATFORM_WINDOWS _itoa_s(value, buffer, 10); +#else + sprintf(buffer, "%d", value); +#endif writer << buffer; return writer; } @@ -104,7 +108,11 @@ TextWriter& operator<<(TextWriter& writer, int16_t value) { char buffer[16]; +#if ZEN_PLATFORM_WINDOWS _itoa_s(value, buffer, 10); +#else + sprintf(buffer, "%d", value); +#endif writer << buffer; return writer; } @@ -113,7 +121,11 @@ TextWriter& operator<<(TextWriter& writer, int32_t value) { char buffer[16]; +#if ZEN_PLATFORM_WINDOWS _itoa_s(value, buffer, 10); +#else + sprintf(buffer, "%d", value); +#endif writer << buffer; return writer; } @@ -122,7 +134,11 @@ TextWriter& operator<<(TextWriter& writer, int64_t value) { char buffer[32]; +#if ZEN_PLATFORM_WINDOWS _i64toa_s(value, buffer, sizeof buffer, 10); +#else + sprintf(buffer, "%" PRId64, value); +#endif writer << buffer; return writer; } @@ -131,7 +147,11 @@ TextWriter& operator<<(TextWriter& writer, uint8_t value) { char buffer[16]; +#if ZEN_PLATFORM_WINDOWS _ultoa_s(value, buffer, 10); +#else + sprintf(buffer, "%u", value); +#endif writer << buffer; return writer; } @@ -140,7 +160,11 @@ TextWriter& operator<<(TextWriter& writer, uint16_t value) { char buffer[16]; +#if ZEN_PLATFORM_WINDOWS _ultoa_s(value, buffer, 10); +#else + sprintf(buffer, "%u", value); +#endif writer << buffer; return writer; } @@ -149,7 +173,11 @@ TextWriter& operator<<(TextWriter& writer, uint32_t value) { char buffer[16]; +#if ZEN_PLATFORM_WINDOWS _ultoa_s(value, buffer, 10); +#else + sprintf(buffer, "%u", value); +#endif writer << buffer; return writer; } @@ -158,7 +186,11 @@ TextWriter& operator<<(TextWriter& writer, uint64_t value) { char buffer[32]; +#if ZEN_PLATFORM_WINDOWS _ui64toa_s(value, buffer, sizeof buffer, 10); +#else + sprintf(buffer, "%" PRIu64, value); +#endif writer << buffer; return writer; } diff --git a/zencore/string.cpp b/zencore/string.cpp index 21ba5b204..8ea10d2a3 100644 --- a/zencore/string.cpp +++ b/zencore/string.cpp @@ -2,11 +2,13 @@ #include <doctest/doctest.h> #include <inttypes.h> +#include <math.h> #include <stdio.h> #include <zencore/memory.h> #include <zencore/string.h> #include <exception> #include <ostream> +#include <stdexcept> #include <utf8.h> @@ -34,14 +36,14 @@ namespace zen { bool ToString(std::span<char> Buffer, uint64_t Num) { - snprintf(Buffer.data(), Buffer.size(), "%I64u", Num); + snprintf(Buffer.data(), Buffer.size(), "%" PRIu64, Num); return true; } bool ToString(std::span<char> Buffer, int64_t Num) { - snprintf(Buffer.data(), Buffer.size(), "%I64d", Num); + snprintf(Buffer.data(), Buffer.size(), "%" PRId64, Num); return true; } @@ -231,12 +233,12 @@ NiceNumGeneral(uint64_t Num, std::span<char> Buffer, NicenumFormat Format) switch (Format) { case kNicenumRaw: - return snprintf(Buffer.data(), Buffer.size(), "%llu", (uint64_t)Num); + return snprintf(Buffer.data(), Buffer.size(), "%" PRIu64, (uint64_t)Num); case kNicenumRawTime: if (Num > 0) { - return snprintf(Buffer.data(), Buffer.size(), "%llu", (uint64_t)Num); + return snprintf(Buffer.data(), Buffer.size(), "%" PRIu64, (uint64_t)Num); } else { @@ -275,7 +277,7 @@ NiceNumGeneral(uint64_t Num, std::span<char> Buffer, NicenumFormat Format) * If this is an even multiple of the base, always display * without any decimal precision. */ - return snprintf(Buffer.data(), Buffer.size(), "%llu%s", (uint64_t)n, u); + return snprintf(Buffer.data(), Buffer.size(), "%" PRIu64 "%s", (uint64_t)n, u); } else { @@ -437,7 +439,7 @@ template<typename C> [[noreturn]] void StringBuilderImpl<C>::Fail(const char* reason) { - throw std::exception(reason); + throw std::runtime_error(reason); } // Instantiate templates once diff --git a/zencore/thread.cpp b/zencore/thread.cpp index fa9da0258..598466bb4 100644 --- a/zencore/thread.cpp +++ b/zencore/thread.cpp @@ -5,33 +5,53 @@ #include <fmt/format.h> #include <zencore/except.h> #include <zencore/string.h> -#include <zencore/windows.h> -#include <thread> + +#if ZEN_PLATFORM_WINDOWS +# include <zencore/windows.h> +#elif ZEN_PLATFORM_LINUX +# include <unistd.h> +#endif namespace zen { void RwLock::AcquireShared() { +#if ZEN_PLATFORM_WINDOWS AcquireSRWLockShared((PSRWLOCK)&m_Srw); +#else + m_Mutex.lock_shared(); +#endif } void RwLock::ReleaseShared() { +#if ZEN_PLATFORM_WINDOWS ReleaseSRWLockShared((PSRWLOCK)&m_Srw); +#else + m_Mutex.unlock_shared(); +#endif } void RwLock::AcquireExclusive() { +#if ZEN_PLATFORM_WINDOWS AcquireSRWLockExclusive((PSRWLOCK)&m_Srw); +#else + m_Mutex.lock(); +#endif } void RwLock::ReleaseExclusive() { +#if ZEN_PLATFORM_WINDOWS ReleaseSRWLockExclusive((PSRWLOCK)&m_Srw); +#else + m_Mutex.unlock(); +#endif } Event::Event() @@ -253,13 +273,21 @@ IsProcessRunning(int pid) int GetCurrentProcessId() { +#if ZEN_PLATFORM_WINDOWS return ::GetCurrentProcessId(); +#else + return getpid(); +#endif } void Sleep(int ms) { +#if ZEN_PLATFORM_WINDOWS ::Sleep(ms); +#else + usleep(ms * 1000U); +#endif } ////////////////////////////////////////////////////////////////////////// diff --git a/zencore/timer.cpp b/zencore/timer.cpp index ee8e1cf9c..08b5e06d2 100644 --- a/zencore/timer.cpp +++ b/zencore/timer.cpp @@ -3,26 +3,41 @@ #include <doctest/doctest.h> #include <zencore/thread.h> #include <zencore/timer.h> -#include <zencore/windows.h> +#if ZEN_PLATFORM_WINDOWS +# include <zencore/windows.h> +#elif ZEN_PLATFORM_LINUX +# include <time.h> +# include <unistd.h> +#endif namespace zen { uint64_t GetHifreqTimerValue() { +#if ZEN_PLATFORM_WINDOWS LARGE_INTEGER li; QueryPerformanceCounter(&li); return li.QuadPart; +#else + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t(ts.tv_sec) * 1000000ull) + (uint64_t(ts.tv_nsec) / 1000ull); +#endif } uint64_t internalGetHifreqTimerFrequency() { +#if ZEN_PLATFORM_WINDOWS LARGE_INTEGER li; QueryPerformanceFrequency(&li); return li.QuadPart; +#else + return 1000000ull; +#endif } static uint64_t qpcFreq = internalGetHifreqTimerFrequency(); @@ -56,7 +71,7 @@ TEST_CASE("Timer") { uint64_t s0 = GetHifreqTimerValue(); uint64_t t0 = GetCpuTimerValue(); - Sleep(1000); + zen::Sleep(1000); uint64_t s1 = GetHifreqTimerValue(); uint64_t t1 = GetCpuTimerValue(); // double r = double(t1 - t0) / (s1 - s0); diff --git a/zencore/uid.cpp b/zencore/uid.cpp index 644d0aa77..acf9f9790 100644 --- a/zencore/uid.cpp +++ b/zencore/uid.cpp @@ -100,6 +100,7 @@ TEST_CASE("Oid") SUBCASE("Basic") { Oid id1 = Oid::NewOid(); + ZEN_UNUSED(id1); std::vector<Oid> ids; std::set<Oid> idset; diff --git a/zencore/zencore.cpp b/zencore/zencore.cpp index c2a57b653..c53fd218f 100644 --- a/zencore/zencore.cpp +++ b/zencore/zencore.cpp @@ -2,7 +2,13 @@ #include <zencore/zencore.h> +#if ZEN_PLATFORM_WINDOWS #include <zencore/windows.h> +#endif + +#if ZEN_PLATFORM_LINUX +#include <pthread.h> +#endif #include <zencore/blake3.h> #include <zencore/compactbinary.h> @@ -25,12 +31,26 @@ bool IsPointerToStack(const void* ptr) { +#if ZEN_PLATFORM_WINDOWS ULONG_PTR low, high; GetCurrentThreadStackLimits(&low, &high); const uintptr_t intPtr = reinterpret_cast<uintptr_t>(ptr); return (intPtr - low) < (high - low); +#elif ZEN_PLATFORM_LINUX + pthread_t self = pthread_self(); + + pthread_attr_t attr; + pthread_getattr_np(self, &attr); + + void* low; + size_t size; + pthread_attr_getstack(&attr, &low, &size); + + return (uintptr_t(ptr) - uintptr_t(low)) < uintptr_t(size); +#elif 0 +#endif } zen::AssertException::AssertException(const char* Msg) : m_Msg(Msg) @@ -65,6 +85,7 @@ zencore_forcelinktests() zen::blake3_forcelink(); zen::compositebuffer_forcelink(); zen::compress_forcelink(); + zen::intmath_forcelink(); zen::iobuffer_forcelink(); zen::memory_forcelink(); zen::refcount_forcelink(); diff --git a/zencore/zencore.vcxproj b/zencore/zencore.vcxproj index 4b5bba185..4f1e63670 100644 --- a/zencore/zencore.vcxproj +++ b/zencore/zencore.vcxproj @@ -160,6 +160,7 @@ <ClCompile Include="crc32.cpp" /> <ClCompile Include="except.cpp" /> <ClCompile Include="filesystem.cpp" /> + <ClCompile Include="intmath.cpp" /> <ClCompile Include="iohash.cpp" /> <ClCompile Include="logging.cpp" /> <ClCompile Include="md5.cpp" /> diff --git a/zencore/zencore.vcxproj.filters b/zencore/zencore.vcxproj.filters index 70c1cfb01..de3d915b8 100644 --- a/zencore/zencore.vcxproj.filters +++ b/zencore/zencore.vcxproj.filters @@ -71,6 +71,7 @@ <ClCompile Include="compositebuffer.cpp" /> <ClCompile Include="crc32.cpp" /> <ClCompile Include="logging.cpp" /> + <ClCompile Include="intmath.cpp" /> </ItemGroup> <ItemGroup> <Filter Include="CAS"> |