diff options
author | Alexander Smirnov <alex@ydb.tech> | 2024-11-08 08:53:31 +0000 |
---|---|---|
committer | Alexander Smirnov <alex@ydb.tech> | 2024-11-08 08:53:31 +0000 |
commit | 826596ba5418687a87696a06770b2350dec7793d (patch) | |
tree | a9111b318a9dd68d20785dc39e45d8b1404c27b4 /library/cpp | |
parent | 37b6f076aac14aa8c23251c80178aa3c6bb663b3 (diff) | |
parent | 726d467e9898a4afca4523f30dd420cd2a85b43c (diff) | |
download | ydb-826596ba5418687a87696a06770b2350dec7793d.tar.gz |
Merge branch 'rightlib' into mergelibs-241108-0852
Diffstat (limited to 'library/cpp')
32 files changed, 554 insertions, 72 deletions
diff --git a/library/cpp/monlib/service/pages/mon_page.h b/library/cpp/monlib/service/pages/mon_page.h index a10d0cdc7e5..dcc021c0584 100644 --- a/library/cpp/monlib/service/pages/mon_page.h +++ b/library/cpp/monlib/service/pages/mon_page.h @@ -11,6 +11,7 @@ namespace NMonitoring { static const char HTTPOKBIN[] = "HTTP/1.1 200 Ok\r\nContent-Type: application/octet-stream\r\nConnection: Close\r\n\r\n"; static const char HTTPOKHTML[] = "HTTP/1.1 200 Ok\r\nContent-Type: text/html\r\nConnection: Close\r\n\r\n"; static const char HTTPOKJSON[] = "HTTP/1.1 200 Ok\r\nContent-Type: application/json\r\nConnection: Close\r\n\r\n"; + static const char HTTPOKYAML[] = "HTTP/1.1 200 Ok\r\nContent-Type: application/yaml\r\nConnection: Close\r\n\r\n"; static const char HTTPOKSPACK[] = "HTTP/1.1 200 Ok\r\nContent-Type: application/x-solomon-spack\r\nConnection: Close\r\n\r\n"; static const char HTTPOKPROMETHEUS[] = "HTTP/1.1 200 Ok\r\nContent-Type: text/plain\r\nConnection: Close\r\n\r\n"; static const char HTTPOKUNISTAT[] = "HTTP/1.1 200 Ok\r\nContent-Type: text/json\r\nConnection: Close\r\n\r\n"; diff --git a/library/cpp/threading/thread_local/thread_local.h b/library/cpp/threading/thread_local/thread_local.h index bb0d11347db..15cb43d37f3 100644 --- a/library/cpp/threading/thread_local/thread_local.h +++ b/library/cpp/threading/thread_local/thread_local.h @@ -220,8 +220,8 @@ public: , Pool_{0} {} - template <typename ...ConsturctArgs> - T* Get(TThread::TId tid, ConsturctArgs&& ...args) { + template <typename ...ConstructArgs> + T* Get(TThread::TId tid, ConstructArgs&& ...args) { TNode* head = Head_.load(std::memory_order_acquire); for (TNode* node = head; node; node = node->Next) { if (node->Key == tid) { @@ -229,7 +229,7 @@ public: } } - TNode* newNode = AllocateNode(tid, head, std::forward<ConsturctArgs>(args)...); + TNode* newNode = AllocateNode(tid, head, std::forward<ConstructArgs>(args)...); while (!Head_.compare_exchange_weak(head, newNode, std::memory_order_release, std::memory_order_relaxed)) { newNode->Next = head; } diff --git a/library/cpp/tld/tlds-alpha-by-domain.txt b/library/cpp/tld/tlds-alpha-by-domain.txt index cd5a49783fd..2a7c080416b 100644 --- a/library/cpp/tld/tlds-alpha-by-domain.txt +++ b/library/cpp/tld/tlds-alpha-by-domain.txt @@ -1,4 +1,4 @@ -# Version 2024110100, Last Updated Fri Nov 1 07:07:01 2024 UTC +# Version 2024110700, Last Updated Thu Nov 7 07:07:01 2024 UTC AAA AARP ABB diff --git a/library/cpp/yt/memory/atomic_intrusive_ptr-inl.h b/library/cpp/yt/memory/atomic_intrusive_ptr-inl.h index e337a78bcfc..ffb2aaff5f3 100644 --- a/library/cpp/yt/memory/atomic_intrusive_ptr-inl.h +++ b/library/cpp/yt/memory/atomic_intrusive_ptr-inl.h @@ -237,6 +237,12 @@ typename TAtomicIntrusivePtr<T>::TRawPtr TAtomicIntrusivePtr<T>::Get() const } template <class T> +typename TAtomicIntrusivePtr<T>::TRawPtr TAtomicIntrusivePtr<T>::get() const +{ + return Get(); +} + +template <class T> TPackedPtr TAtomicIntrusivePtr<T>::AcquireObject(T* obj, bool consumeRef) { if (obj) { diff --git a/library/cpp/yt/memory/atomic_intrusive_ptr.h b/library/cpp/yt/memory/atomic_intrusive_ptr.h index 4bab78ef580..243920bdabd 100644 --- a/library/cpp/yt/memory/atomic_intrusive_ptr.h +++ b/library/cpp/yt/memory/atomic_intrusive_ptr.h @@ -20,6 +20,9 @@ template <class T> class TAtomicIntrusivePtr { public: + using TUnderlying = T; + using element_type = T; + TAtomicIntrusivePtr() = default; TAtomicIntrusivePtr(std::nullptr_t); @@ -45,6 +48,9 @@ public: //! Result is only suitable for comparison, not dereference. TRawPtr Get() const; + //! Result is only suitable for comparison, not dereference. + TRawPtr get() const; + explicit operator bool() const; private: diff --git a/library/cpp/yt/memory/chunked_memory_pool-inl.h b/library/cpp/yt/memory/chunked_memory_pool-inl.h index 25022041607..00733235f49 100644 --- a/library/cpp/yt/memory/chunked_memory_pool-inl.h +++ b/library/cpp/yt/memory/chunked_memory_pool-inl.h @@ -31,9 +31,10 @@ TDerived* TAllocationHolder::Allocate(size_t size, TRefCountedTypeCookie cookie) { auto requestedSize = sizeof(TDerived) + size; auto* ptr = ::malloc(requestedSize); - - if (!ptr) { - AbortProcess(ToUnderlying(EProcessExitCode::OutOfMemory)); + if (Y_UNLIKELY(!ptr)) { + AbortProcessDramatically( + EProcessExitCode::OutOfMemory, + "Out-of-memory during chunked memory pool allocation"); } #ifndef _win_ diff --git a/library/cpp/yt/memory/intrusive_ptr.h b/library/cpp/yt/memory/intrusive_ptr.h index 91b15279aec..1a168cec0ec 100644 --- a/library/cpp/yt/memory/intrusive_ptr.h +++ b/library/cpp/yt/memory/intrusive_ptr.h @@ -18,6 +18,9 @@ class TIntrusivePtr public: using TUnderlying = T; + //! For compatibility with std:: smart pointers. + using element_type = T; + constexpr TIntrusivePtr() noexcept { } @@ -148,6 +151,12 @@ public: return T_; } + //! Returns the pointer, for compatibility with std:: smart pointers. + T* get() const noexcept + { + return T_; + } + //! Returns the pointer and releases the ownership. T* Release() noexcept { diff --git a/library/cpp/yt/memory/new-inl.h b/library/cpp/yt/memory/new-inl.h index f0646582ec8..53308fb254e 100644 --- a/library/cpp/yt/memory/new-inl.h +++ b/library/cpp/yt/memory/new-inl.h @@ -10,8 +10,6 @@ #include <library/cpp/yt/malloc//malloc.h> -#include <library/cpp/yt/system/exit.h> - namespace NYT { //////////////////////////////////////////////////////////////////////////////// @@ -178,6 +176,8 @@ Y_FORCE_INLINE TIntrusivePtr<T> SafeConstruct(void* ptr, As&&... args) } } +void AbortOnOom(); + template <size_t Size, size_t Alignment> Y_FORCE_INLINE void* AllocateConstSizeAlignedOrCrash() { @@ -192,7 +192,7 @@ Y_FORCE_INLINE void* AllocateConstSizeAlignedOrCrash() } #endif if (Y_UNLIKELY(!ptr)) { - AbortProcess(ToUnderlying(EProcessExitCode::OutOfMemory)); + AbortOnOom(); } return ptr; } @@ -211,7 +211,7 @@ Y_FORCE_INLINE void* AllocateOrCrash(size_t size) } #endif if (Y_UNLIKELY(!ptr)) { - AbortProcess(ToUnderlying(EProcessExitCode::OutOfMemory)); + AbortOnOom(); } return ptr; } @@ -249,7 +249,7 @@ Y_FORCE_INLINE TIntrusivePtr<T> New( { auto obj = TryNew<T>(allocator, std::forward<As>(args)...); if (Y_UNLIKELY(!obj)) { - AbortProcess(ToUnderlying(EProcessExitCode::OutOfMemory)); + NYT::NDetail::AbortOnOom(); } return obj; } @@ -288,7 +288,7 @@ Y_FORCE_INLINE TIntrusivePtr<T> NewWithExtraSpace( { auto obj = TryNewWithExtraSpace<T>(allocator, extraSpaceSize, std::forward<As>(args)...); if (Y_UNLIKELY(!obj)) { - AbortProcess(ToUnderlying(EProcessExitCode::OutOfMemory)); + NYT::NDetail::AbortOnOom(); } return obj; } diff --git a/library/cpp/yt/memory/new.cpp b/library/cpp/yt/memory/new.cpp new file mode 100644 index 00000000000..0b4a4b3b8b8 --- /dev/null +++ b/library/cpp/yt/memory/new.cpp @@ -0,0 +1,18 @@ +#include "new.h" + +#include <library/cpp/yt/system/exit.h> + +namespace NYT::NDetail { + +//////////////////////////////////////////////////////////////////////////////// + +void AbortOnOom() +{ + AbortProcessDramatically( + EProcessExitCode::OutOfMemory, + "Out-of-memory during object allocation"); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NDetail diff --git a/library/cpp/yt/memory/weak_ptr.h b/library/cpp/yt/memory/weak_ptr.h index c647198aaf5..e7b847653d4 100644 --- a/library/cpp/yt/memory/weak_ptr.h +++ b/library/cpp/yt/memory/weak_ptr.h @@ -13,6 +13,7 @@ class TWeakPtr { public: using TUnderlying = T; + using element_type = T; //! Empty constructor. TWeakPtr() = default; diff --git a/library/cpp/yt/memory/ya.make b/library/cpp/yt/memory/ya.make index bd817454a93..5397dccf32f 100644 --- a/library/cpp/yt/memory/ya.make +++ b/library/cpp/yt/memory/ya.make @@ -15,6 +15,7 @@ SRCS( chunked_memory_pool_output.cpp chunked_output_stream.cpp memory_tag.cpp + new.cpp ref.cpp ref_tracked.cpp safe_memory_reader.cpp diff --git a/library/cpp/yt/misc/arcadia_enum-inl.h b/library/cpp/yt/misc/arcadia_enum-inl.h index 17a10bb3b22..1df8b2c4647 100644 --- a/library/cpp/yt/misc/arcadia_enum-inl.h +++ b/library/cpp/yt/misc/arcadia_enum-inl.h @@ -42,6 +42,18 @@ struct TArcadiaEnumTraitsImpl auto it = LiteralToValue.find(literal); return it == LiteralToValue.end() ? std::nullopt : std::make_optional(it->second); } + + static bool IsKnownValue(T value) + { + static const auto Values = [] { + THashSet<T> result; + for (const auto& [value, _] : GetEnumNames<T>()) { + result.insert(value); + } + return result; + }(); + return Values.contains(value); + } }; //////////////////////////////////////////////////////////////////////////////// diff --git a/library/cpp/yt/misc/cast-inl.h b/library/cpp/yt/misc/cast-inl.h index 00e6e240b82..50920f01934 100644 --- a/library/cpp/yt/misc/cast-inl.h +++ b/library/cpp/yt/misc/cast-inl.h @@ -94,20 +94,19 @@ constexpr bool IsInIntegralRange(S value) } template <class T, class S> -constexpr bool TryIntegralCast(S value, T* result) +constexpr std::optional<T> TryCheckedIntegralCast(S value) { - if (!NDetail::IsInIntegralRange<T>(value)) { - return false; + [[unlikely]] if (!NDetail::IsInIntegralRange<T>(value)) { + return std::nullopt; } - *result = static_cast<T>(value); - return true; + return static_cast<T>(value); } template <class T, class S> T CheckedIntegralCast(S value) { - T result; - if (!TryIntegralCast<T>(value, &result)) { + auto result = TryCheckedIntegralCast<T>(value); + if (!result) { throw TSimpleException(Sprintf("Error casting %s value \"%s\" to %s: value is out of expected range [%s; %s]", TypeName<S>().c_str(), NYT::NDetail::FormatInvalidCastValue(value).c_str(), @@ -115,35 +114,43 @@ T CheckedIntegralCast(S value) ::ToString(std::numeric_limits<T>::lowest()).c_str(), ::ToString(std::numeric_limits<T>::max()).c_str())); } - return result; + return *result; } template <class T, class S> -constexpr bool TryEnumCast(S value, T* result) + requires TEnumTraits<T>::IsEnum +constexpr std::optional<T> TryCheckedEnumCast(S value) { - std::underlying_type_t<T> underlying; - if (!TryIntegralCast<std::underlying_type_t<T>>(value, &underlying)) { - return false; + auto underlying = TryCheckedIntegralCast<std::underlying_type_t<T>>(value); + [[unlikely]] if (!underlying) { + return std::nullopt; } - auto candidate = static_cast<T>(underlying); - if (!TEnumTraits<T>::FindLiteralByValue(candidate)) { - return false; + auto candidate = static_cast<T>(*underlying); + [[unlikely]] if (!TEnumTraits<T>::IsValidValue(candidate)) { + return std::nullopt; } - *result = candidate; - return true; + return candidate; } template <class T, class S> + requires TEnumTraits<T>::IsEnum T CheckedEnumCast(S value) { - T result; - if (!TryEnumCast<T>(value, &result)) { - throw TSimpleException(Sprintf("Error casting %s value \"%d\" to enum %s", - TypeName<S>().c_str(), - static_cast<int>(value), - TEnumTraits<T>::GetTypeName().data())); + auto result = TryCheckedEnumCast<T>(value); + [[unlikely]] if (!result) { + if constexpr (std::is_signed_v<S>) { + throw TSimpleException(Sprintf("Error casting %s value \"%" PRIi64 "\" to enum %s", + TypeName<S>().c_str(), + static_cast<i64>(value), + TEnumTraits<T>::GetTypeName().data())); + } else { + throw TSimpleException(Sprintf("Error casting %s value \"%" PRIu64 "\" to enum %s", + TypeName<S>().c_str(), + static_cast<ui64>(value), + TEnumTraits<T>::GetTypeName().data())); + } } - return result; + return *result; } //////////////////////////////////////////////////////////////////////////////// diff --git a/library/cpp/yt/misc/cast.h b/library/cpp/yt/misc/cast.h index e8654cc1222..a4e32e0287d 100644 --- a/library/cpp/yt/misc/cast.h +++ b/library/cpp/yt/misc/cast.h @@ -1,7 +1,11 @@ #pragma once +#include "enum.h" + #include <library/cpp/yt/exception/exception.h> +#include <optional> + namespace NYT { //////////////////////////////////////////////////////////////////////////////// @@ -13,7 +17,7 @@ template <class T, class S> constexpr bool IsInIntegralRange(S value); template <class T, class S> -constexpr bool TryIntegralCast(S value, T* result); +constexpr std::optional<T> TryCheckedIntegralCast(S value); template <class T, class S> T CheckedIntegralCast(S value); @@ -21,9 +25,11 @@ T CheckedIntegralCast(S value); //////////////////////////////////////////////////////////////////////////////// template <class T, class S> -constexpr bool TryEnumCast(S value, T* result); + requires TEnumTraits<T>::IsEnum +constexpr std::optional<T> TryCheckedEnumCast(S value); template <class T, class S> + requires TEnumTraits<T>::IsEnum T CheckedEnumCast(S value); //////////////////////////////////////////////////////////////////////////////// diff --git a/library/cpp/yt/misc/compare-inl.h b/library/cpp/yt/misc/compare-inl.h new file mode 100644 index 00000000000..b9dfb5319f5 --- /dev/null +++ b/library/cpp/yt/misc/compare-inl.h @@ -0,0 +1,71 @@ +#ifndef COMPARE_INL_H_ +#error "Direct inclusion of this file is not allowed, include compare.h" +// For the sake of sane code completion. +#include "compare.h" +#endif + +#include "numeric_helpers.h" + +#include <util/generic/string.h> + +#include <string> +#include <string_view> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +Y_FORCE_INLINE int TernaryCompare(const T& lhs, const T& rhs) +{ + if (lhs == rhs) { + return 0; + } else if (lhs < rhs) { + return -1; + } else { + return +1; + } +} + +//! An optimized version for string types. +template <class T> + requires + std::is_same_v<T, TString> || + std::is_same_v<T, TStringBuf> || + std::is_same_v<T, std::string> || + std::is_same_v<T, std::string_view> +Y_FORCE_INLINE int TernaryCompare(const T& lhs, const T& rhs) +{ + return GetSign(std::string_view(lhs).compare(std::string_view(rhs))); +} + +template <class T> +Y_FORCE_INLINE int NaNSafeTernaryCompare(const T& lhs, const T& rhs) +{ + return TernaryCompare(lhs, rhs); +} + +template <class T> + requires std::is_floating_point_v<T> +Y_FORCE_INLINE int NaNSafeTernaryCompare(const T& lhs, const T& rhs) +{ + if (lhs < rhs) { + return -1; + } else if (lhs > rhs) { + return +1; + } else if (std::isnan(lhs)) { + if (std::isnan(rhs)) { + return 0; + } else { + return +1; + } + } else if (std::isnan(rhs)) { + return -1; + } else { + return 0; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/misc/compare.h b/library/cpp/yt/misc/compare.h new file mode 100644 index 00000000000..22e452b355c --- /dev/null +++ b/library/cpp/yt/misc/compare.h @@ -0,0 +1,28 @@ +#pragma once + +#include <util/generic/string.h> + +#include <string_view> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +//! Compares #lhs with #rhs; +//! returns -1 (if |lhs < rhs|), 0 (if |lhs == rhs|), or 1 (|lhs > rhs|). +template <class T> +int TernaryCompare(const T& lhs, const T& rhs); + +//! Same as #TernaryCompare but handles NaN values gracefully +//! (assuming NaNs are larger than any regular number and all NaNs are equal). +//! If |T| is not a floating-point type, #NaNSafeTernaryCompare is equivalent to #TernaryCompare. +template <class T> +int NaNSafeTernaryCompare(const T& lhs, const T& rhs); + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT + +#define COMPARE_INL_H_ +#include "compare-inl.h" +#undef COMPARE_INL_H_ diff --git a/library/cpp/yt/misc/enum-inl.h b/library/cpp/yt/misc/enum-inl.h index f1fb9f63e10..d8037bbf749 100644 --- a/library/cpp/yt/misc/enum-inl.h +++ b/library/cpp/yt/misc/enum-inl.h @@ -324,6 +324,16 @@ constexpr bool TEnumTraits<T, true>::IsKnownValue(T value) } template <class T> +constexpr bool TEnumTraits<T, true>::IsValidValue(T value) +{ + if constexpr (IsBitEnum) { + return (value & TEnumTraits<T>::GetAllSetValue()) == value; + } else { + return IsKnownValue(value); + } +} + +template <class T> TString TEnumTraits<T, true>::ToString(T value) { using ::ToString; diff --git a/library/cpp/yt/misc/enum.h b/library/cpp/yt/misc/enum.h index d9611b2823b..331eb59f1a4 100644 --- a/library/cpp/yt/misc/enum.h +++ b/library/cpp/yt/misc/enum.h @@ -89,8 +89,10 @@ struct TEnumTraits<T, true> static constexpr std::optional<T> TryGetUnknownValue(); static std::optional<TStringBuf> FindLiteralByValue(T value); static std::optional<T> FindValueByLiteral(TStringBuf literal); + static constexpr bool IsKnownValue(T value) requires (!TEnumTraitsImpl<T>::IsBitEnum); + static constexpr bool IsValidValue(T value); static TString ToString(T value); static T FromString(TStringBuf literal); diff --git a/library/cpp/yt/misc/hash-inl.h b/library/cpp/yt/misc/hash-inl.h index 46eeefe6204..159748a09bc 100644 --- a/library/cpp/yt/misc/hash-inl.h +++ b/library/cpp/yt/misc/hash-inl.h @@ -4,6 +4,8 @@ #include "hash.h" #endif +#include <cmath> + namespace NYT { //////////////////////////////////////////////////////////////////////////////// @@ -29,6 +31,19 @@ void HashCombine(size_t& h, const T& k) HashCombine(h, THash<T>()(k)); } +template <class T> +Y_FORCE_INLINE size_t NaNSafeHash(const T& value) +{ + return ::THash<T>()(value); +} + +template <class T> + requires std::is_floating_point_v<T> +Y_FORCE_INLINE size_t NaNSafeHash(const T& value) +{ + return std::isnan(value) ? 0 : ::THash<T>()(value); +} + //////////////////////////////////////////////////////////////////////////////// template <class TElement, class TUnderlying> diff --git a/library/cpp/yt/misc/hash.h b/library/cpp/yt/misc/hash.h index 2fecf895061..fe4087c3315 100644 --- a/library/cpp/yt/misc/hash.h +++ b/library/cpp/yt/misc/hash.h @@ -17,6 +17,12 @@ void HashCombine(size_t& h, size_t k); template <class T> void HashCombine(size_t& h, const T& k); +//! Computes the hash of #value handling NaN values gracefully +//! (returning the same constant for all NaNs). +//! If |T| is not a floating-point type, #NaNSafeHash is equivalent to #THash. +template <class T> +size_t NaNSafeHash(const T& value); + //////////////////////////////////////////////////////////////////////////////// //! Provides a hasher that randomizes the results of another one. @@ -25,12 +31,11 @@ class TRandomizedHash { public: TRandomizedHash(); - size_t operator () (const TElement& element) const; + size_t operator()(const TElement& element) const; private: size_t Seed_; TUnderlying Underlying_; - }; //////////////////////////////////////////////////////////////////////////////// diff --git a/library/cpp/yt/misc/numeric_helpers-inl.h b/library/cpp/yt/misc/numeric_helpers-inl.h new file mode 100644 index 00000000000..c0dbc07490d --- /dev/null +++ b/library/cpp/yt/misc/numeric_helpers-inl.h @@ -0,0 +1,59 @@ +#ifndef NUMERIC_HELPERS_INL_H_ +#error "Direct inclusion of this file is not allowed, include numeric_helpers.h" +// For the sake of sane code completion. +#include "numeric_helpers.h" +#endif + +#include <cstdlib> +#include <cinttypes> +#include <cmath> +#include <algorithm> + +#include <util/system/compiler.h> + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +T DivCeil(const T& numerator, const T& denominator) +{ + YT_VERIFY(denominator != 0); + auto res = std::div(numerator, denominator); + return res.quot + (res.rem > static_cast<T>(0) ? static_cast<T>(1) : static_cast<T>(0)); +} + +template <typename T> +T DivRound(const T& numerator, const T& denominator) +{ + auto res = std::div(numerator, denominator); + return res.quot + (res.rem >= (denominator + 1) / 2 ? static_cast<T>(1) : static_cast<T>(0)); +} + +template <class T> +T RoundUp(const T& numerator, const T& denominator) +{ + return DivCeil(numerator, denominator) * denominator; +} + +template <class T> +T RoundDown(const T& numerator, const T& denominator) +{ + return (numerator / denominator) * denominator; +} + +template <class T> +Y_FORCE_INLINE int GetSign(const T& value) +{ + if (value < 0) { + return -1; + } else if (value > 0) { + return +1; + } else { + return 0; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/misc/numeric_helpers.h b/library/cpp/yt/misc/numeric_helpers.h new file mode 100644 index 00000000000..20844029c27 --- /dev/null +++ b/library/cpp/yt/misc/numeric_helpers.h @@ -0,0 +1,31 @@ +#pragma once + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +T DivCeil(const T& numerator, const T& denominator); + +//! A version of division that is a bit less noisy around the situation +//! when numerator is almost divisible by denominator. Round up if the remainder +//! is at least half of denominator, otherwise round down. +template<class T> +T DivRound(const T& numerator, const T& denominator); + +template <class T> +T RoundUp(const T& numerator, const T& denominator); + +template <class T> +T RoundDown(const T& numerator, const T& denominator); + +template <class T> +int GetSign(const T& value); + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT + +#define NUMERIC_HELPERS_INL_H_ +#include "numeric_helpers-inl.h" +#undef NUMERIC_HELPERS_INL_H_ diff --git a/library/cpp/yt/misc/unittests/cast_ut.cpp b/library/cpp/yt/misc/unittests/cast_ut.cpp new file mode 100644 index 00000000000..8662575d6c0 --- /dev/null +++ b/library/cpp/yt/misc/unittests/cast_ut.cpp @@ -0,0 +1,45 @@ +#include <library/cpp/testing/gtest/gtest.h> + +#include <library/cpp/yt/misc/cast.h> +#include <library/cpp/yt/misc/enum.h> + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +DEFINE_ENUM_WITH_UNDERLYING_TYPE(ECardinal, char, + ((West) (0)) + ((North) (1)) + ((East) (2)) + ((South) (3)) +); + +DEFINE_BIT_ENUM_WITH_UNDERLYING_TYPE(EFeatures, ui8, + ((None) (0x0000)) + ((First) (0x0001)) + ((Second)(0x0002)) +); + +TEST(TCastTest, TryCheckedEnumCast) +{ + EXPECT_EQ((TryCheckedEnumCast<ECardinal, char>(2)), ECardinal::East); + EXPECT_EQ((TryCheckedEnumCast<ECardinal, int>(3)), ECardinal::South); + + EXPECT_FALSE((TryCheckedEnumCast<ECardinal, char>(100))); + EXPECT_FALSE((TryCheckedEnumCast<ECardinal, int>(300))); + + EXPECT_EQ((TryCheckedEnumCast<EFeatures, ui8>(0)), EFeatures::None); + EXPECT_EQ((TryCheckedEnumCast<EFeatures, ui8>(ToUnderlying(EFeatures::First))), EFeatures::First); + EXPECT_EQ((TryCheckedEnumCast<EFeatures, ui8>(ToUnderlying(EFeatures::Second))), EFeatures::Second); + EXPECT_EQ((TryCheckedEnumCast<EFeatures, int>(ToUnderlying(EFeatures::First))), EFeatures::First); + EXPECT_EQ((TryCheckedEnumCast<EFeatures, ui8>(ToUnderlying(EFeatures::First | EFeatures::Second))), EFeatures::First | EFeatures::Second); + + EXPECT_FALSE((TryCheckedEnumCast<EFeatures, ui8>(0x10))); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT + diff --git a/library/cpp/yt/misc/unittests/compare_ut.cpp b/library/cpp/yt/misc/unittests/compare_ut.cpp new file mode 100644 index 00000000000..da149a0690e --- /dev/null +++ b/library/cpp/yt/misc/unittests/compare_ut.cpp @@ -0,0 +1,62 @@ +#include <library/cpp/testing/gtest/gtest.h> + +#include <library/cpp/yt/misc/compare.h> + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +TEST(TCompareTest, TernaryCompare) +{ + EXPECT_EQ(TernaryCompare(123, 123), 0); + EXPECT_EQ(TernaryCompare(10, 20), -1); + EXPECT_EQ(TernaryCompare(20, 10), +1); + EXPECT_EQ(TernaryCompare(std::nan("1"), std::nan("1")), +1); + EXPECT_EQ(TernaryCompare(std::nan("1"), std::nan("2")), +1); + EXPECT_EQ(TernaryCompare(std::nan("1"), 123.0), +1); + EXPECT_EQ(TernaryCompare(123.0, std::nan("1")), +1); +} + +TEST(TCompareTest, NaNSafeTernaryCompare) +{ + EXPECT_EQ(NaNSafeTernaryCompare(std::nan("1"), std::nan("1")), 0); + EXPECT_EQ(NaNSafeTernaryCompare(std::nan("1"), std::nan("2")), 0); + EXPECT_EQ(NaNSafeTernaryCompare(123.0, std::nan("1")), -1); + EXPECT_EQ(NaNSafeTernaryCompare(std::nan("1"), 123.0), +1); +} + +//////////////////////////////////////////////////////////////////////////////// + +template <class T> +class TTernaryCompareStringTest + : public ::testing::Test +{ }; + +TYPED_TEST_SUITE_P(TTernaryCompareStringTest); + +TYPED_TEST_P(TTernaryCompareStringTest, Compare) +{ + EXPECT_EQ(TernaryCompare(TypeParam("abc"), TypeParam("abc")), 0); + EXPECT_EQ(TernaryCompare(TypeParam("x"), TypeParam("y")), -1); + EXPECT_EQ(TernaryCompare(TypeParam("y"), TypeParam("x")), +1); +} + +REGISTER_TYPED_TEST_SUITE_P(TTernaryCompareStringTest, Compare); + +using TTernaryCompareStringTestTypes = ::testing::Types< + TString, + TStringBuf, + std::string, + std::string_view +>; + +INSTANTIATE_TYPED_TEST_SUITE_P( + TypeParametrized, + TTernaryCompareStringTest, + TTernaryCompareStringTestTypes); + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT diff --git a/library/cpp/yt/misc/unittests/enum_ut.cpp b/library/cpp/yt/misc/unittests/enum_ut.cpp index fc7feed2279..22bfe1fdc91 100644 --- a/library/cpp/yt/misc/unittests/enum_ut.cpp +++ b/library/cpp/yt/misc/unittests/enum_ut.cpp @@ -215,10 +215,21 @@ TEST(TEnumTest, IsKnownValue) EXPECT_TRUE(TEnumTraits<ESimple>::IsKnownValue(ESimple::X)); EXPECT_TRUE(TEnumTraits<ESimple>::IsKnownValue(ESimple::Y)); EXPECT_TRUE(TEnumTraits<ESimple>::IsKnownValue(ESimple::Z)); - EXPECT_FALSE(TEnumTraits<ESimple>::IsKnownValue(static_cast<ESimple>(100))); +} - EXPECT_TRUE(TEnumTraits<EColor>::IsKnownValue(EColor::Red)); +TEST(TEnumTest, IsValidValue) +{ + EXPECT_TRUE(TEnumTraits<ESimple>::IsValidValue(ESimple::X)); + EXPECT_TRUE(TEnumTraits<ESimple>::IsValidValue(ESimple::Y)); + EXPECT_TRUE(TEnumTraits<ESimple>::IsValidValue(ESimple::Z)); + EXPECT_FALSE(TEnumTraits<ESimple>::IsValidValue(static_cast<ESimple>(100))); + + EXPECT_TRUE(TEnumTraits<EFlag>::IsValidValue(EFlag())); + EXPECT_TRUE(TEnumTraits<EFlag>::IsValidValue(EFlag::_1)); + EXPECT_TRUE(TEnumTraits<EFlag>::IsValidValue(EFlag::_1 | EFlag::_2)); + EXPECT_TRUE(TEnumTraits<EFlag>::IsValidValue(EFlag::_1 | EFlag::_2 | EFlag::_3 | EFlag::_4)); + EXPECT_FALSE(TEnumTraits<EFlag>::IsValidValue(static_cast<EFlag>(0x10))); } TEST(TEnumTest, AllSetValue) @@ -280,29 +291,6 @@ TEST(TEnumTest, CustomString) EXPECT_EQ("1_b", ToString(ECustomString::B)); } -TEST(TEnumTest, Cast) -{ - ECardinal cardinal; - { - char validValue = 2; - EXPECT_TRUE(TryEnumCast(validValue, &cardinal)); - EXPECT_EQ(cardinal, ECardinal::East); - } - { - char invalidValue = 100; - EXPECT_FALSE(TryEnumCast(invalidValue, &cardinal)); - } - { - int widerTypeValidValue = 3; - EXPECT_TRUE(TryEnumCast(widerTypeValidValue, &cardinal)); - EXPECT_EQ(cardinal, ECardinal::South); - } - { - int widerTypeInvalueValue = (1 << 8) + 100; - EXPECT_FALSE(TryEnumCast(widerTypeInvalueValue, &cardinal)); - } -} - TEST(TEnumTest, UnknownValue) { EXPECT_EQ(TEnumTraits<EColor>::TryGetUnknownValue(), std::nullopt); diff --git a/library/cpp/yt/misc/unittests/hash_ut.cpp b/library/cpp/yt/misc/unittests/hash_ut.cpp new file mode 100644 index 00000000000..0c336be5dc3 --- /dev/null +++ b/library/cpp/yt/misc/unittests/hash_ut.cpp @@ -0,0 +1,19 @@ +#include <library/cpp/testing/gtest/gtest.h> + +#include <library/cpp/yt/misc/hash.h> + +namespace NYT { +namespace { + +//////////////////////////////////////////////////////////////////////////////// + +TEST(THashTest, NaNSafeHash) +{ + EXPECT_EQ(NaNSafeHash(123), THash<int>()(123)); + EXPECT_EQ(NaNSafeHash(std::nan("1")), NaNSafeHash(std::nan("2"))); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace +} // namespace NYT diff --git a/library/cpp/yt/misc/unittests/ya.make b/library/cpp/yt/misc/unittests/ya.make index 5a071c887c4..63df71fb832 100644 --- a/library/cpp/yt/misc/unittests/ya.make +++ b/library/cpp/yt/misc/unittests/ya.make @@ -3,8 +3,11 @@ GTEST(unittester-library-misc) INCLUDE(${ARCADIA_ROOT}/library/cpp/yt/ya_cpp.make.inc) SRCS( + cast_ut.cpp + compare_ut.cpp enum_ut.cpp guid_ut.cpp + hash_ut.cpp non_null_ptr_ut.cpp preprocessor_ut.cpp strong_typedef_ut.cpp diff --git a/library/cpp/yt/stockpile/stockpile_linux.cpp b/library/cpp/yt/stockpile/stockpile_linux.cpp index dafb4e9e8c8..ef0ad590327 100644 --- a/library/cpp/yt/stockpile/stockpile_linux.cpp +++ b/library/cpp/yt/stockpile/stockpile_linux.cpp @@ -25,7 +25,7 @@ namespace { void RunWithFixedBreaks(i64 bufferSize, TDuration period) { auto returnCode = -::madvise(nullptr, bufferSize, MADV_STOCKPILE); - YT_LOG_DEBUG_IF(returnCode, "System call \"madvise\" returned %v", strerror(returnCode)); + YT_LOG_DEBUG_IF(returnCode, "System call \"madvise\" failed: %v", strerror(returnCode)); Sleep(period); } @@ -33,7 +33,7 @@ void RunWithCappedLoad(i64 bufferSize, TDuration period) { auto started = GetApproximateCpuInstant(); auto returnCode = -::madvise(nullptr, bufferSize, MADV_STOCKPILE); - YT_LOG_DEBUG_IF(returnCode, "System call \"madvise\" returned %v", strerror(returnCode)); + YT_LOG_DEBUG_IF(returnCode, "System call \"madvise\" failed: %v", strerror(returnCode)); auto duration = CpuDurationToDuration(GetApproximateCpuInstant() - started); if (duration < period) { @@ -48,7 +48,7 @@ std::pair<i64, TDuration> RunWithBackoffs( i64 pageSize) { int returnCode = -::madvise(nullptr, adjustedBufferSize, MADV_STOCKPILE); - YT_LOG_DEBUG_IF(returnCode, "System call \"madvise\" returned %v", strerror(returnCode)); + YT_LOG_DEBUG_IF(returnCode, "System call \"madvise\" failed: %v", strerror(returnCode)); switch(returnCode) { case 0: diff --git a/library/cpp/yt/system/exit-inl.h b/library/cpp/yt/system/exit-inl.h new file mode 100644 index 00000000000..e4fe8ea5940 --- /dev/null +++ b/library/cpp/yt/system/exit-inl.h @@ -0,0 +1,32 @@ +#ifndef EXIT_INL_H_ +#error "Direct inclusion of this file is not allowed, include exit.h" +// For the sake of sane code completion. +#include "exit.h" +#endif + +namespace NYT { + +//////////////////////////////////////////////////////////////////////////////// + +template <class E> + requires std::is_enum_v<E> +[[noreturn]] void AbortProcessSilently(E exitCode) +{ + AbortProcessSilently(ToUnderlying(exitCode)); +} + +template <class E> + requires std::is_enum_v<E> +[[noreturn]] void AbortProcessDramatically( + E exitCode, + TStringBuf message) +{ + AbortProcessDramatically( + ToUnderlying(exitCode), + TEnumTraits<E>::FindLiteralByValue(exitCode).value_or("<unknown>"), + message); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT diff --git a/library/cpp/yt/system/exit.cpp b/library/cpp/yt/system/exit.cpp index b17f6c5ad73..e4088fe4da2 100644 --- a/library/cpp/yt/system/exit.cpp +++ b/library/cpp/yt/system/exit.cpp @@ -4,11 +4,25 @@ namespace NYT { //////////////////////////////////////////////////////////////////////////////// -void AbortProcess(int exitCode) +void AbortProcessSilently(int exitCode) { _exit(exitCode); } +void AbortProcessDramatically(int exitCode, TStringBuf exitCodeStr, TStringBuf message) +{ + fprintf(stderr, "\n"); + if (message) { + fprintf(stderr, "*** %s\n", message.data()); + } + fprintf(stderr, "*** Aborting process with exit code %d", exitCode); + if (exitCodeStr) { + fprintf(stderr, " (%s)", exitCodeStr.data()); + } + fprintf(stderr, "\n"); + _exit(exitCode); +} + //////////////////////////////////////////////////////////////////////////////// } // namespace NYT diff --git a/library/cpp/yt/system/exit.h b/library/cpp/yt/system/exit.h index 6c009fff901..e06c0bd3ddd 100644 --- a/library/cpp/yt/system/exit.h +++ b/library/cpp/yt/system/exit.h @@ -2,6 +2,8 @@ #include <library/cpp/yt/misc/enum.h> +#include <type_traits> + namespace NYT { //////////////////////////////////////////////////////////////////////////////// @@ -14,9 +16,33 @@ DEFINE_ENUM(EProcessExitCode, ((OutOfMemory) (9)) ); -//! Invokes _exit to abort the process immediately without calling any cleanup code. -[[noreturn]] void AbortProcess(int exitCode); +//! Invokes _exit to abort the process immediately without calling any cleanup code +//! and without printing any details to stderr. +[[noreturn]] void AbortProcessSilently(int exitCode); + +//! A typed version of #AbortProcessSilently. +template <class E> + requires std::is_enum_v<E> +[[noreturn]] void AbortProcessSilently(E exitCode); + +//! Invokes _exit to abort the process immediately +//! without calling any cleanup code but printing error message to stderr. +[[noreturn]] void AbortProcessDramatically( + int exitCode, + TStringBuf exitCodeStr, + TStringBuf message); + +//! A typed version of #AbortProcessDramatically. +template <class E> + requires std::is_enum_v<E> +[[noreturn]] void AbortProcessDramatically( + E exitCode, + TStringBuf message); //////////////////////////////////////////////////////////////////////////////// } // namespace NYT + +#define EXIT_INL_H_ +#include "exit-inl.h" +#undef EXIT_INL_H_ diff --git a/library/cpp/yt/system/ya.make b/library/cpp/yt/system/ya.make index de4516d928e..c60a940dbf2 100644 --- a/library/cpp/yt/system/ya.make +++ b/library/cpp/yt/system/ya.make @@ -7,4 +7,8 @@ SRCS( thread_id.cpp ) +PEERDIR( + library/cpp/yt/misc +) + END() |