diff options
author | mikhnenko <[email protected]> | 2025-01-20 01:34:08 +0300 |
---|---|---|
committer | mikhnenko <[email protected]> | 2025-01-20 01:51:09 +0300 |
commit | 2ab2ef14e493133a483a7210a0133c1d8918eee2 (patch) | |
tree | b25a613d75999386160a0ffe41a4f69282a592b3 /contrib/libs/cxxsupp/libcxx/src | |
parent | 11def371ff569cef09101fa40c00e6180c3885bc (diff) |
Update libcxx to 5 Mar 2024 80f9458cf30d13eef21b09042ea590945c5e64db
commit_hash:c45aa2ed98c2a01fa86b69bac97f40a32bd68ae2
Diffstat (limited to 'contrib/libs/cxxsupp/libcxx/src')
35 files changed, 1408 insertions, 350 deletions
diff --git a/contrib/libs/cxxsupp/libcxx/src/atomic.cpp b/contrib/libs/cxxsupp/libcxx/src/atomic.cpp index 2f0389ae697..2b67685c8a0 100644 --- a/contrib/libs/cxxsupp/libcxx/src/atomic.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/atomic.cpp @@ -178,6 +178,7 @@ _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_one(__cxx_atomic_contention_t _LIBCPP_EXPORTED_FROM_ABI void __cxx_atomic_notify_all(__cxx_atomic_contention_t const volatile* __location) { __libcpp_contention_notify(&__libcpp_contention_state(__location)->__contention_state, __location, false); } +// This function is never used, but still exported for ABI compatibility. _LIBCPP_EXPORTED_FROM_ABI __cxx_contention_t __libcpp_atomic_monitor(__cxx_atomic_contention_t const volatile* __location) { return __libcpp_contention_monitor_for_wait(&__libcpp_contention_state(__location)->__contention_state, __location); diff --git a/contrib/libs/cxxsupp/libcxx/src/call_once.cpp b/contrib/libs/cxxsupp/libcxx/src/call_once.cpp index 7f5aef1db5c..2b981b69ab8 100644 --- a/contrib/libs/cxxsupp/libcxx/src/call_once.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/call_once.cpp @@ -10,7 +10,7 @@ #include <__utility/exception_guard.h> #ifndef _LIBCPP_HAS_NO_THREADS -# include <__threading_support> +# include <__thread/support.h> #endif #include "include/atomic_support.h" diff --git a/contrib/libs/cxxsupp/libcxx/src/condition_variable_destructor.cpp b/contrib/libs/cxxsupp/libcxx/src/condition_variable_destructor.cpp index 8b62d418401..59811ed7ff3 100644 --- a/contrib/libs/cxxsupp/libcxx/src/condition_variable_destructor.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/condition_variable_destructor.cpp @@ -12,7 +12,7 @@ // definition is only provided for ABI compatibility. #include <__config> -#include <__threading_support> +#include <__thread/support.h> #if _LIBCPP_ABI_VERSION == 1 || !defined(_LIBCPP_HAS_TRIVIAL_CONDVAR_DESTRUCTION) # define NEEDS_CONDVAR_DESTRUCTOR diff --git a/contrib/libs/cxxsupp/libcxx/src/filesystem/error.h b/contrib/libs/cxxsupp/libcxx/src/filesystem/error.h index b86f4ed4107..572cc73292a 100644 --- a/contrib/libs/cxxsupp/libcxx/src/filesystem/error.h +++ b/contrib/libs/cxxsupp/libcxx/src/filesystem/error.h @@ -99,7 +99,7 @@ inline errc __win_err_to_errc(int err) { #endif // _LIBCPP_WIN32API inline error_code capture_errno() { - _LIBCPP_ASSERT_UNCATEGORIZED(errno != 0, "Expected errno to be non-zero"); + _LIBCPP_ASSERT_INTERNAL(errno != 0, "Expected errno to be non-zero"); return error_code(errno, generic_category()); } diff --git a/contrib/libs/cxxsupp/libcxx/src/filesystem/format_string.h b/contrib/libs/cxxsupp/libcxx/src/filesystem/format_string.h index 215d42421b2..a44def86f53 100644 --- a/contrib/libs/cxxsupp/libcxx/src/filesystem/format_string.h +++ b/contrib/libs/cxxsupp/libcxx/src/filesystem/format_string.h @@ -47,7 +47,7 @@ inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 0) string vformat_string(const ch size_t size_with_null = static_cast<size_t>(ret) + 1; result.__resize_default_init(size_with_null - 1); ret = ::vsnprintf(&result[0], size_with_null, msg, ap); - _LIBCPP_ASSERT_UNCATEGORIZED(static_cast<size_t>(ret) == (size_with_null - 1), "TODO"); + _LIBCPP_ASSERT_INTERNAL(static_cast<size_t>(ret) == (size_with_null - 1), "TODO"); } return result; } diff --git a/contrib/libs/cxxsupp/libcxx/src/filesystem/operations.cpp b/contrib/libs/cxxsupp/libcxx/src/filesystem/operations.cpp index 1b9f2605805..fa31f05b2d2 100644 --- a/contrib/libs/cxxsupp/libcxx/src/filesystem/operations.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/filesystem/operations.cpp @@ -460,8 +460,21 @@ path __current_path(error_code* ec) { typedef decltype(&::free) Deleter; Deleter deleter = &::free; #else + errno = 0; // Note: POSIX mandates that modifying `errno` is thread-safe. auto size = ::pathconf(".", _PC_PATH_MAX); - _LIBCPP_ASSERT_UNCATEGORIZED(size >= 0, "pathconf returned a 0 as max size"); + if (size == -1) { + if (errno != 0) { + return err.report(capture_errno(), "call to pathconf failed"); + + // `pathconf` returns `-1` without an error to indicate no limit. + } else { +# if defined(__MVS__) && !defined(PATH_MAX) + size = _XOPEN_PATH_MAX + 1; +# else + size = PATH_MAX + 1; +# endif + } + } auto buff = unique_ptr<path::value_type[]>(new path::value_type[size + 1]); path::value_type* ptr = buff.get(); @@ -608,10 +621,9 @@ void __permissions(const path& p, perms prms, perm_options opts, error_code* ec) const bool resolve_symlinks = !has_opt(perm_options::nofollow); const bool add_perms = has_opt(perm_options::add); const bool remove_perms = has_opt(perm_options::remove); - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN( (add_perms + remove_perms + has_opt(perm_options::replace)) == 1, - "One and only one of the perm_options constants replace, add, or remove " - "is present in opts"); + "One and only one of the perm_options constants 'replace', 'add', or 'remove' must be present in opts"); bool set_sym_perms = false; prms &= perms::mask; @@ -621,7 +633,9 @@ void __permissions(const path& p, perms prms, perm_options opts, error_code* ec) set_sym_perms = is_symlink(st); if (m_ec) return err.report(m_ec); - _LIBCPP_ASSERT_UNCATEGORIZED(st.permissions() != perms::unknown, "Permissions unexpectedly unknown"); + // TODO(hardening): double-check this assertion -- it might be a valid (if rare) case when the permissions are + // unknown. + _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(st.permissions() != perms::unknown, "Permissions unexpectedly unknown"); if (add_perms) prms |= st.permissions(); else if (remove_perms) @@ -668,7 +682,7 @@ path __read_symlink(const path& p, error_code* ec) { detail::SSizeT ret; if ((ret = detail::readlink(p.c_str(), buff.get(), size)) == -1) return err.report(capture_errno()); - _LIBCPP_ASSERT_UNCATEGORIZED(ret > 0, "TODO"); + // Note that `ret` returning `0` would work, resulting in a valid empty string being returned. if (static_cast<size_t>(ret) >= size) return err.report(errc::value_too_large); buff[ret] = 0; @@ -801,8 +815,9 @@ uintmax_t remove_all_impl(int parent_directory, const path& p, error_code& ec) { // If opening `p` failed because it wasn't a directory, remove it as // a normal file instead. Note that `openat()` can return either ENOTDIR - // or ELOOP depending on the exact reason of the failure. - if (ec == errc::not_a_directory || ec == errc::too_many_symbolic_link_levels) { + // or ELOOP depending on the exact reason of the failure. On FreeBSD it + // may return EMLINK instead of ELOOP, contradicting POSIX. + if (ec == errc::not_a_directory || ec == errc::too_many_symbolic_link_levels || ec == errc::too_many_links) { ec.clear(); if (::unlinkat(parent_directory, p.c_str(), /* flags = */ 0) == -1) { ec = detail::capture_errno(); diff --git a/contrib/libs/cxxsupp/libcxx/src/filesystem/posix_compat.h b/contrib/libs/cxxsupp/libcxx/src/filesystem/posix_compat.h index ec2de49960b..760cdb65dae 100644 --- a/contrib/libs/cxxsupp/libcxx/src/filesystem/posix_compat.h +++ b/contrib/libs/cxxsupp/libcxx/src/filesystem/posix_compat.h @@ -318,8 +318,8 @@ inline int statvfs(const wchar_t* p, StatVFS* buf) { inline wchar_t* getcwd([[maybe_unused]] wchar_t* in_buf, [[maybe_unused]] size_t in_size) { // Only expected to be used with us allocating the buffer. - _LIBCPP_ASSERT_UNCATEGORIZED(in_buf == nullptr, "Windows getcwd() assumes in_buf==nullptr"); - _LIBCPP_ASSERT_UNCATEGORIZED(in_size == 0, "Windows getcwd() assumes in_size==0"); + _LIBCPP_ASSERT_INTERNAL(in_buf == nullptr, "Windows getcwd() assumes in_buf==nullptr"); + _LIBCPP_ASSERT_INTERNAL(in_size == 0, "Windows getcwd() assumes in_size==0"); size_t buff_size = MAX_PATH + 10; std::unique_ptr<wchar_t, decltype(&::free)> buff(static_cast<wchar_t*>(malloc(buff_size * sizeof(wchar_t))), &::free); @@ -338,7 +338,7 @@ inline wchar_t* getcwd([[maybe_unused]] wchar_t* in_buf, [[maybe_unused]] size_t inline wchar_t* realpath(const wchar_t* path, [[maybe_unused]] wchar_t* resolved_name) { // Only expected to be used with us allocating the buffer. - _LIBCPP_ASSERT_UNCATEGORIZED(resolved_name == nullptr, "Windows realpath() assumes a null resolved_name"); + _LIBCPP_ASSERT_INTERNAL(resolved_name == nullptr, "Windows realpath() assumes a null resolved_name"); WinHandle h(path, FILE_READ_ATTRIBUTES, 0); if (!h) { diff --git a/contrib/libs/cxxsupp/libcxx/src/fstream.cpp b/contrib/libs/cxxsupp/libcxx/src/fstream.cpp new file mode 100644 index 00000000000..55a4442b9c7 --- /dev/null +++ b/contrib/libs/cxxsupp/libcxx/src/fstream.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include <__config> +#include <cstdio> +#include <fstream> + +#if defined(_LIBCPP_WIN32API) +# define WIN32_LEAN_AND_MEAN +# define NOMINMAX +# include <io.h> +# include <windows.h> +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if defined(_LIBCPP_WIN32API) + +// Confirm that `HANDLE` is `void*` as implemented in `basic_filebuf` +static_assert(std::same_as<HANDLE, void*>); + +_LIBCPP_EXPORTED_FROM_ABI void* __filebuf_windows_native_handle(FILE* __file) noexcept { + // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/get-osfhandle?view=msvc-170 + intptr_t __handle = _get_osfhandle(fileno(__file)); + if (__handle == -1) + return nullptr; + return reinterpret_cast<void*>(__handle); +} + +#endif + +_LIBCPP_END_NAMESPACE_STD diff --git a/contrib/libs/cxxsupp/libcxx/src/include/overridable_function.h b/contrib/libs/cxxsupp/libcxx/src/include/overridable_function.h new file mode 100644 index 00000000000..7b0fba10f47 --- /dev/null +++ b/contrib/libs/cxxsupp/libcxx/src/include/overridable_function.h @@ -0,0 +1,119 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_SRC_INCLUDE_OVERRIDABLE_FUNCTION_H +#define _LIBCPP_SRC_INCLUDE_OVERRIDABLE_FUNCTION_H + +#include <__config> +#include <cstdint> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +// +// This file provides the std::__is_function_overridden utility, which allows checking +// whether an overridable function (typically a weak symbol) like `operator new` +// has been overridden by a user or not. +// +// This is a low-level utility which does not work on all platforms, since it needs +// to make assumptions about the object file format in use. Furthermore, it requires +// the "base definition" of the function (the one we want to check whether it has been +// overridden) to be annotated with the _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE macro. +// +// This currently works with Mach-O files (used on Darwin) and with ELF files (used on Linux +// and others). On platforms where we know how to implement this detection, the macro +// _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION is defined to 1, and it is defined to 0 on +// other platforms. The _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE macro is defined to +// nothing on unsupported platforms so that it can be used to decorate functions regardless +// of whether detection is actually supported. +// +// How does this work? +// ------------------- +// +// Let's say we want to check whether a weak function `f` has been overridden by the user. +// The general mechanism works by placing `f`'s definition (in the libc++ built library) +// inside a special section, which we do using the `__section__` attribute via the +// _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE macro. +// +// Then, when comes the time to check whether the function has been overridden, we take +// the address of the function and we check whether it falls inside the special function +// we created. This can be done by finding pointers to the start and the end of the section +// (which is done differently for ELF and Mach-O), and then checking whether `f` falls +// within those bounds. If it falls within those bounds, then `f` is still inside the +// special section and so it is the version we defined in the libc++ built library, i.e. +// it was not overridden. Otherwise, it was overridden by the user because it falls +// outside of the section. +// +// Important note +// -------------- +// +// This mechanism should never be used outside of the libc++ built library. In particular, +// attempting to use this within the libc++ headers will not work at all because we don't +// want to be defining special sections inside user's executables which use our headers. +// This is provided inside libc++'s include tree solely to make it easier to share with +// libc++abi, which needs the same mechanism. +// + +#if defined(_LIBCPP_OBJECT_FORMAT_MACHO) + +# define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 1 +# define _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE \ + __attribute__((__section__("__TEXT,__lcxx_override,regular,pure_instructions"))) + +_LIBCPP_BEGIN_NAMESPACE_STD +template <class _Ret, class... _Args> +_LIBCPP_HIDE_FROM_ABI bool __is_function_overridden(_Ret (*__fptr)(_Args...)) noexcept { + // Declare two dummy bytes and give them these special `__asm` values. These values are + // defined by the linker, which means that referring to `&__lcxx_override_start` will + // effectively refer to the address where the section starts (and same for the end). + extern char __lcxx_override_start __asm("section$start$__TEXT$__lcxx_override"); + extern char __lcxx_override_end __asm("section$end$__TEXT$__lcxx_override"); + + // Now get a uintptr_t out of these locations, and out of the function pointer. + uintptr_t __start = reinterpret_cast<uintptr_t>(&__lcxx_override_start); + uintptr_t __end = reinterpret_cast<uintptr_t>(&__lcxx_override_end); + uintptr_t __ptr = reinterpret_cast<uintptr_t>(__fptr); + + // Finally, the function was overridden if it falls outside of the section's bounds. + return __ptr < __start || __ptr > __end; +} +_LIBCPP_END_NAMESPACE_STD + +#elif defined(_LIBCPP_OBJECT_FORMAT_ELF) + +# define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 1 +# define _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE __attribute__((__section__("__lcxx_override"))) + +// This is very similar to what we do for Mach-O above. The ELF linker will implicitly define +// variables with those names corresponding to the start and the end of the section. +// +// See https://stackoverflow.com/questions/16552710/how-do-you-get-the-start-and-end-addresses-of-a-custom-elf-section +extern char __start___lcxx_override; +extern char __stop___lcxx_override; + +_LIBCPP_BEGIN_NAMESPACE_STD +template <class _Ret, class... _Args> +_LIBCPP_HIDE_FROM_ABI bool __is_function_overridden(_Ret (*__fptr)(_Args...)) noexcept { + uintptr_t __start = reinterpret_cast<uintptr_t>(&__start___lcxx_override); + uintptr_t __end = reinterpret_cast<uintptr_t>(&__stop___lcxx_override); + uintptr_t __ptr = reinterpret_cast<uintptr_t>(__fptr); + + return __ptr < __start || __ptr > __end; +} +_LIBCPP_END_NAMESPACE_STD + +#else + +# define _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION 0 +# define _LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE /* nothing */ + +#endif + +#endif // _LIBCPP_SRC_INCLUDE_OVERRIDABLE_FUNCTION_H diff --git a/contrib/libs/cxxsupp/libcxx/src/include/to_chars_floating_point.h b/contrib/libs/cxxsupp/libcxx/src/include/to_chars_floating_point.h index 3110bc20e16..01c26181697 100644 --- a/contrib/libs/cxxsupp/libcxx/src/include/to_chars_floating_point.h +++ b/contrib/libs/cxxsupp/libcxx/src/include/to_chars_floating_point.h @@ -269,7 +269,7 @@ to_chars_result _Floating_to_chars_hex_precision( // * Print the leading hexit, then mask it away. { const uint32_t _Nibble = static_cast<uint32_t>(_Adjusted_mantissa >> _Adjusted_explicit_bits); - _LIBCPP_ASSERT_UNCATEGORIZED(_Nibble < 3, ""); + _LIBCPP_ASSERT_INTERNAL(_Nibble < 3, ""); const char _Leading_hexit = static_cast<char>('0' + _Nibble); *_First++ = _Leading_hexit; @@ -288,12 +288,12 @@ to_chars_result _Floating_to_chars_hex_precision( int32_t _Number_of_bits_remaining = _Adjusted_explicit_bits; // 24 for float, 52 for double for (;;) { - _LIBCPP_ASSERT_UNCATEGORIZED(_Number_of_bits_remaining >= 4, ""); - _LIBCPP_ASSERT_UNCATEGORIZED(_Number_of_bits_remaining % 4 == 0, ""); + _LIBCPP_ASSERT_INTERNAL(_Number_of_bits_remaining >= 4, ""); + _LIBCPP_ASSERT_INTERNAL(_Number_of_bits_remaining % 4 == 0, ""); _Number_of_bits_remaining -= 4; const uint32_t _Nibble = static_cast<uint32_t>(_Adjusted_mantissa >> _Number_of_bits_remaining); - _LIBCPP_ASSERT_UNCATEGORIZED(_Nibble < 16, ""); + _LIBCPP_ASSERT_INTERNAL(_Nibble < 16, ""); const char _Hexit = __itoa::_Charconv_digits[_Nibble]; *_First++ = _Hexit; @@ -415,12 +415,12 @@ to_chars_result _Floating_to_chars_hex_shortest( // '0' hexits, the same condition works (as we print the final hexit and mask it away); we don't need to test // _Number_of_bits_remaining. do { - _LIBCPP_ASSERT_UNCATEGORIZED(_Number_of_bits_remaining >= 4, ""); - _LIBCPP_ASSERT_UNCATEGORIZED(_Number_of_bits_remaining % 4 == 0, ""); + _LIBCPP_ASSERT_INTERNAL(_Number_of_bits_remaining >= 4, ""); + _LIBCPP_ASSERT_INTERNAL(_Number_of_bits_remaining % 4 == 0, ""); _Number_of_bits_remaining -= 4; const uint32_t _Nibble = static_cast<uint32_t>(_Adjusted_mantissa >> _Number_of_bits_remaining); - _LIBCPP_ASSERT_UNCATEGORIZED(_Nibble < 16, ""); + _LIBCPP_ASSERT_INTERNAL(_Nibble < 16, ""); const char _Hexit = __itoa::_Charconv_digits[_Nibble]; if (_First == _Last) { @@ -940,13 +940,13 @@ to_chars_result _Floating_to_chars_general_precision( _Effective_precision = std::min(_Precision - (_Scientific_exponent_X + 1), _Max_fixed_precision); const to_chars_result _Buf_result = _Floating_to_chars_fixed_precision(_Buffer, std::end(_Buffer), _Value, _Effective_precision); - _LIBCPP_ASSERT_UNCATEGORIZED(_Buf_result.ec == errc{}, ""); + _LIBCPP_ASSERT_INTERNAL(_Buf_result.ec == errc{}, ""); _Significand_last = _Buf_result.ptr; } else { _Effective_precision = std::min(_Precision - 1, _Max_scientific_precision); const to_chars_result _Buf_result = _Floating_to_chars_scientific_precision(_Buffer, std::end(_Buffer), _Value, _Effective_precision); - _LIBCPP_ASSERT_UNCATEGORIZED(_Buf_result.ec == errc{}, ""); + _LIBCPP_ASSERT_INTERNAL(_Buf_result.ec == errc{}, ""); _Significand_last = std::find(_Buffer, _Buf_result.ptr, 'e'); _Exponent_first = _Significand_last; _Exponent_last = _Buf_result.ptr; @@ -992,9 +992,9 @@ to_chars_result _Floating_to_chars( char* _First, char* const _Last, _Floating _Value, const chars_format _Fmt, const int _Precision) noexcept { if constexpr (_Overload == _Floating_to_chars_overload::_Plain) { - _LIBCPP_ASSERT_UNCATEGORIZED(_Fmt == chars_format{}, ""); // plain overload must pass chars_format{} internally + _LIBCPP_ASSERT_INTERNAL(_Fmt == chars_format{}, ""); // plain overload must pass chars_format{} internally } else { - _LIBCPP_ASSERT_UNCATEGORIZED(_Fmt == chars_format::general || _Fmt == chars_format::scientific + _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(_Fmt == chars_format::general || _Fmt == chars_format::scientific || _Fmt == chars_format::fixed || _Fmt == chars_format::hex, "invalid format in to_chars()"); } diff --git a/contrib/libs/cxxsupp/libcxx/src/include/tzdb/time_zone_link_private.h b/contrib/libs/cxxsupp/libcxx/src/include/tzdb/time_zone_link_private.h new file mode 100644 index 00000000000..13923762527 --- /dev/null +++ b/contrib/libs/cxxsupp/libcxx/src/include/tzdb/time_zone_link_private.h @@ -0,0 +1,27 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#ifndef _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_LINK_PRIVATE_H +#define _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_LINK_PRIVATE_H + +#include <chrono> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +struct time_zone_link::__constructor_tag {}; + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_LINK_PRIVATE_H diff --git a/contrib/libs/cxxsupp/libcxx/src/include/tzdb/time_zone_private.h b/contrib/libs/cxxsupp/libcxx/src/include/tzdb/time_zone_private.h new file mode 100644 index 00000000000..039a3b0ffeb --- /dev/null +++ b/contrib/libs/cxxsupp/libcxx/src/include/tzdb/time_zone_private.h @@ -0,0 +1,48 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#ifndef _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_PRIVATE_H +#define _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_PRIVATE_H + +#include <chrono> +#include <string> +#include <vector> + +#include "types_private.h" + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +class time_zone::__impl { +public: + explicit _LIBCPP_HIDE_FROM_ABI __impl(string&& __name) : __name_(std::move(__name)) {} + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_view __name() const noexcept { return __name_; } + + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI vector<__tz::__continuation>& __continuations() { return __continuations_; } + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const vector<__tz::__continuation>& __continuations() const { + return __continuations_; + } + +private: + string __name_; + // Note the first line has a name + __continuation, the other lines + // are just __continuations. So there is always at least one item in + // the vector. + vector<__tz::__continuation> __continuations_; +}; + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_PRIVATE_H diff --git a/contrib/libs/cxxsupp/libcxx/src/include/tzdb/types_private.h b/contrib/libs/cxxsupp/libcxx/src/include/tzdb/types_private.h new file mode 100644 index 00000000000..4604b9fc881 --- /dev/null +++ b/contrib/libs/cxxsupp/libcxx/src/include/tzdb/types_private.h @@ -0,0 +1,106 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#ifndef __LIBCPP_SRC_INCLUDE_TZDB_TYPES_PRIVATE_H +#define __LIBCPP_SRC_INCLUDE_TZDB_TYPES_PRIVATE_H + +#include <chrono> +#include <string> +#include <utility> +#include <variant> +#include <vector> + +_LIBCPP_BEGIN_NAMESPACE_STD + +// TODO TZDB +// The helper classes in this header have no constructor but are loaded with +// dedicated parse functions. In the original design this header was public and +// the parsing was done in the dylib. In that design having constructors would +// expand the ABI interface. Since this header is now in the dylib that design +// should be reconsidered. (For now the design is kept as is, in case this +// header needs to be public for unforseen reasons.) + +namespace chrono::__tz { + +// Sun>=8 first Sunday on or after the eighth +// Sun<=25 last Sunday on or before the 25th +struct __constrained_weekday { + /* year_month_day operator()(year __year, month __month);*/ // needed but not implemented + + weekday __weekday; + enum __comparison_t { __le, __ge } __comparison; + day __day; +}; + +// The on field has a few alternative presentations +// 5 the fifth of the month +// lastSun the last Sunday in the month +// lastMon the last Monday in the month +// Sun>=8 first Sunday on or after the eighth +// Sun<=25 last Sunday on or before the 25th +using __on = variant<day, weekday_last, __constrained_weekday>; + +enum class __clock { __local, __standard, __universal }; + +struct __at { + seconds __time{0}; + __tz::__clock __clock{__tz::__clock::__local}; +}; + +struct __save { + seconds __time; + bool __is_dst; +}; + +// The names of the fields match the fields of a Rule. +struct __rule { + year __from; + year __to; + month __in; + __tz::__on __on; + __tz::__at __at; + __tz::__save __save; + string __letters; +}; + +using __rules_storage_type = std::vector<std::pair<string, vector<__tz::__rule>>>; // TODO TZDB use flat_map; + +struct __continuation { + // Non-owning link to the RULE entries. + __tz::__rules_storage_type* __rule_database_; + + seconds __stdoff; + + // The RULES is either a SAVE or a NAME. + // The size_t is used as cache. After loading the rules they are + // sorted and remain stable, then an index in the vector can be + // used. + // If this field contains - then standard time always + // applies. This is indicated by the monostate. + using __rules_t = variant<monostate, __tz::__save, string, size_t>; + + __rules_t __rules; + + string __format; + // TODO TZDB the until field can contain more than just a year. + // Parts of the UNTIL, the optional parts are default initialized + // optional<year> __until_; + year __year = chrono::year::min(); + month __in{January}; + __tz::__on __on{chrono::day{1}}; + __tz::__at __at{chrono::seconds{0}, __tz::__clock::__local}; +}; + +} // namespace chrono::__tz + +_LIBCPP_END_NAMESPACE_STD + +#endif // __LIBCPP_SRC_INCLUDE_TZDB_TYPES_PRIVATE_H diff --git a/contrib/libs/cxxsupp/libcxx/src/include/tzdb/tzdb_list_private.h b/contrib/libs/cxxsupp/libcxx/src/include/tzdb/tzdb_list_private.h new file mode 100644 index 00000000000..f43d7d8ea77 --- /dev/null +++ b/contrib/libs/cxxsupp/libcxx/src/include/tzdb/tzdb_list_private.h @@ -0,0 +1,104 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#ifndef _LIBCPP_SRC_INCLUDE_TZDB_TZDB_LIST_PRIVATE_H +#define _LIBCPP_SRC_INCLUDE_TZDB_TZDB_LIST_PRIVATE_H + +#include <__mutex/unique_lock.h> +#include <forward_list> + +// When threads are not available the locking is not required. +#ifndef _LIBCPP_HAS_NO_THREADS +# include <shared_mutex> +#endif + +#include "types_private.h" +#include "tzdb_private.h" + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +//===----------------------------------------------------------------------===// +// Private API +//===----------------------------------------------------------------------===// + +// The tzdb_list stores a list of "tzdb" entries. +// +// The public tzdb database does not store the RULE entries of the IANA +// database. These entries are considered an implementation detail. Since most +// of the tzdb_list interface is exposed as "a list of tzdb entries" it's not +// possible to use a helper struct that stores a tzdb and the RULE database. +// Instead this class stores these in parallel forward lists. +// +// Since the nodes of a forward_list are stable it's possible to store pointers +// and references to these nodes. +class tzdb_list::__impl { +public: + __impl() { __load_no_lock(); } + + [[nodiscard]] const tzdb& __load() { +#ifndef _LIBCPP_HAS_NO_THREADS + unique_lock __lock{__mutex_}; +#endif + __load_no_lock(); + return __tzdb_.front(); + } + + using const_iterator = tzdb_list::const_iterator; + + const tzdb& front() const noexcept { +#ifndef _LIBCPP_HAS_NO_THREADS + shared_lock __lock{__mutex_}; +#endif + return __tzdb_.front(); + } + + const_iterator erase_after(const_iterator __p) { +#ifndef _LIBCPP_HAS_NO_THREADS + unique_lock __lock{__mutex_}; +#endif + + __rules_.erase_after(std::next(__rules_.cbegin(), std::distance(__tzdb_.cbegin(), __p))); + return __tzdb_.erase_after(__p); + } + + const_iterator begin() const noexcept { +#ifndef _LIBCPP_HAS_NO_THREADS + shared_lock __lock{__mutex_}; +#endif + return __tzdb_.begin(); + } + const_iterator end() const noexcept { + // forward_list<T>::end does not access the list, so no need to take a lock. + return __tzdb_.end(); + } + + const_iterator cbegin() const noexcept { return begin(); } + const_iterator cend() const noexcept { return end(); } + +private: + // Loads the tzdbs + // pre: The caller ensures the locking, if needed, is done. + void __load_no_lock() { chrono::__init_tzdb(__tzdb_.emplace_front(), __rules_.emplace_front()); } + +#ifndef _LIBCPP_HAS_NO_THREADS + mutable shared_mutex __mutex_; +#endif + forward_list<tzdb> __tzdb_; + + forward_list<__tz::__rules_storage_type> __rules_; +}; + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_SRC_INCLUDE_TZDB_TZDB_LIST_PRIVATE_H diff --git a/contrib/libs/cxxsupp/libcxx/src/include/tzdb/tzdb_private.h b/contrib/libs/cxxsupp/libcxx/src/include/tzdb/tzdb_private.h new file mode 100644 index 00000000000..8ec3f890ef6 --- /dev/null +++ b/contrib/libs/cxxsupp/libcxx/src/include/tzdb/tzdb_private.h @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#ifndef _LIBCPP_SRC_INCLUDE_TZDB_TZ_PRIVATE_H +#define _LIBCPP_SRC_INCLUDE_TZDB_TZ_PRIVATE_H + +#include <chrono> + +#include "types_private.h" + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules); + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_SRC_INCLUDE_TZDB_TZ_PRIVATE_H diff --git a/contrib/libs/cxxsupp/libcxx/src/iostream.cpp b/contrib/libs/cxxsupp/libcxx/src/iostream.cpp index 93edf3a0d57..029de4a6806 100644 --- a/contrib/libs/cxxsupp/libcxx/src/iostream.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/iostream.cpp @@ -22,127 +22,119 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if defined(_LIBCPP_ABI_MICROSOFT) && !defined(__clang__) -_ALIGNAS_TYPE(istream) char _cin[sizeof(istream)]; +alignas(istream) char _cin[sizeof(istream)]; _LIBCPP_EXPORTED_FROM_ABI istream& cin = *reinterpret_cast<istream*>(_cin); #else -_ALIGNAS_TYPE(istream) -_LIBCPP_EXPORTED_FROM_ABI char cin[sizeof(istream)] -# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) +alignas(istream) _LIBCPP_EXPORTED_FROM_ABI char cin[sizeof(istream)] +#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) __asm__("?cin@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_istream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A") -# endif +#endif ; #endif -_ALIGNAS_TYPE(__stdinbuf<char>) static char __cin[sizeof(__stdinbuf<char>)]; +alignas(__stdinbuf<char>) static char __cin[sizeof(__stdinbuf<char>)]; static mbstate_t mb_cin; #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS # if defined(_LIBCPP_ABI_MICROSOFT) && !defined(__clang__) -_ALIGNAS_TYPE(wistream) char _wcin[sizeof(wistream)]; +alignas(wistream) char _wcin[sizeof(wistream)]; _LIBCPP_EXPORTED_FROM_ABI wistream& wcin = *reinterpret_cast<wistream*>(_wcin); # else -_ALIGNAS_TYPE(wistream) -_LIBCPP_EXPORTED_FROM_ABI char wcin[sizeof(wistream)] -# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) +alignas(wistream) _LIBCPP_EXPORTED_FROM_ABI char wcin[sizeof(wistream)] +# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) __asm__("?wcin@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_istream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A") -# endif - ; # endif -_ALIGNAS_TYPE(__stdinbuf<wchar_t>) static char __wcin[sizeof(__stdinbuf<wchar_t>)]; + ; +#endif +alignas(__stdinbuf<wchar_t>) static char __wcin[sizeof(__stdinbuf<wchar_t>)]; static mbstate_t mb_wcin; #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS #if defined(_LIBCPP_ABI_MICROSOFT) && !defined(__clang__) -_ALIGNAS_TYPE(ostream) char _cout[sizeof(ostream)]; +alignas(ostream) char _cout[sizeof(ostream)]; _LIBCPP_EXPORTED_FROM_ABI ostream& cout = *reinterpret_cast<ostream*>(_cout); #else -_ALIGNAS_TYPE(ostream) -_LIBCPP_EXPORTED_FROM_ABI char cout[sizeof(ostream)] -# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) +alignas(ostream) _LIBCPP_EXPORTED_FROM_ABI char cout[sizeof(ostream)] +#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) __asm__("?cout@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A") -# endif +#endif ; #endif -_ALIGNAS_TYPE(__stdoutbuf<char>) static char __cout[sizeof(__stdoutbuf<char>)]; +alignas(__stdoutbuf<char>) static char __cout[sizeof(__stdoutbuf<char>)]; static mbstate_t mb_cout; #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS # if defined(_LIBCPP_ABI_MICROSOFT) && !defined(__clang__) -_ALIGNAS_TYPE(wostream) char _wcout[sizeof(wostream)]; +alignas(wostream) char _wcout[sizeof(wostream)]; _LIBCPP_EXPORTED_FROM_ABI wostream& wcout = *reinterpret_cast<wostream*>(_wcout); # else -_ALIGNAS_TYPE(wostream) -_LIBCPP_EXPORTED_FROM_ABI char wcout[sizeof(wostream)] -# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) +alignas(wostream) _LIBCPP_EXPORTED_FROM_ABI char wcout[sizeof(wostream)] +# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) __asm__("?wcout@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A") -# endif - ; # endif -_ALIGNAS_TYPE(__stdoutbuf<wchar_t>) static char __wcout[sizeof(__stdoutbuf<wchar_t>)]; + ; +#endif +alignas(__stdoutbuf<wchar_t>) static char __wcout[sizeof(__stdoutbuf<wchar_t>)]; static mbstate_t mb_wcout; #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS #if defined(_LIBCPP_ABI_MICROSOFT) && !defined(__clang__) -_ALIGNAS_TYPE(ostream) char _cerr[sizeof(ostream)]; +alignas(ostream) char _cerr[sizeof(ostream)]; _LIBCPP_EXPORTED_FROM_ABI ostream& cerr = *reinterpret_cast<ostream*>(_cerr); #else -_ALIGNAS_TYPE(ostream) -_LIBCPP_EXPORTED_FROM_ABI char cerr[sizeof(ostream)] -# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) +alignas(ostream) _LIBCPP_EXPORTED_FROM_ABI char cerr[sizeof(ostream)] +#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) __asm__("?cerr@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A") -# endif +#endif ; #endif -_ALIGNAS_TYPE(__stdoutbuf<char>) static char __cerr[sizeof(__stdoutbuf<char>)]; +alignas(__stdoutbuf<char>) static char __cerr[sizeof(__stdoutbuf<char>)]; static mbstate_t mb_cerr; #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS # if defined(_LIBCPP_ABI_MICROSOFT) && !defined(__clang__) -_ALIGNAS_TYPE(wostream) char _wcerr[sizeof(wostream)]; +alignas(wostream) char _wcerr[sizeof(wostream)]; _LIBCPP_EXPORTED_FROM_ABI wostream& wcerr = *reinterpret_cast<wostream*>(_wcerr); # else -_ALIGNAS_TYPE(wostream) -_LIBCPP_EXPORTED_FROM_ABI char wcerr[sizeof(wostream)] -# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) +alignas(wostream) _LIBCPP_EXPORTED_FROM_ABI char wcerr[sizeof(wostream)] +# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) __asm__("?wcerr@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A") -# endif +# endif ; # endif -_ALIGNAS_TYPE(__stdoutbuf<wchar_t>) static char __wcerr[sizeof(__stdoutbuf<wchar_t>)]; +alignas(__stdoutbuf<wchar_t>) static char __wcerr[sizeof(__stdoutbuf<wchar_t>)]; static mbstate_t mb_wcerr; #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS #if defined(_LIBCPP_ABI_MICROSOFT) && !defined(__clang__) -_ALIGNAS_TYPE(ostream) char _clog[sizeof(ostream)]; +alignas(ostream) char _clog[sizeof(ostream)]; _LIBCPP_EXPORTED_FROM_ABI ostream& clog = *reinterpret_cast<ostream*>(_clog); #else -_ALIGNAS_TYPE(ostream) -_LIBCPP_EXPORTED_FROM_ABI char clog[sizeof(ostream)] -# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) +alignas(ostream) _LIBCPP_EXPORTED_FROM_ABI char clog[sizeof(ostream)] +#if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) __asm__("?clog@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@DU?$char_traits@D@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A") -# endif +#endif ; #endif #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS # if defined(_LIBCPP_ABI_MICROSOFT) && !defined(__clang__) -_ALIGNAS_TYPE(wostream) char _wclog[sizeof(wostream)]; +alignas(wostream) char _wclog[sizeof(wostream)]; _LIBCPP_EXPORTED_FROM_ABI wostream& wclog = *reinterpret_cast<wostream*>(_wclog); # else -_ALIGNAS_TYPE(wostream) -_LIBCPP_EXPORTED_FROM_ABI char wclog[sizeof(wostream)] -# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) +alignas(wostream) _LIBCPP_EXPORTED_FROM_ABI char wclog[sizeof(wostream)] +# if defined(_LIBCPP_ABI_MICROSOFT) && defined(__clang__) __asm__("?wclog@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream@_WU?$char_traits@_W@" _LIBCPP_ABI_NAMESPACE_STR "@std@@@12@A") -# endif - ; # endif + ; +#endif #endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS // Pretend we're inside a system header so the compiler doesn't flag the use of the init_priority diff --git a/contrib/libs/cxxsupp/libcxx/src/locale.cpp b/contrib/libs/cxxsupp/libcxx/src/locale.cpp index 433394d58f6..1b937dcf970 100644 --- a/contrib/libs/cxxsupp/libcxx/src/locale.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/locale.cpp @@ -34,9 +34,7 @@ # define _CTYPE_DISABLE_MACROS #endif -#if defined(_LIBCPP_MSVCRT) || defined(__MINGW32__) -# include "__support/win32/locale_win32.h" -#elif !defined(__BIONIC__) && !defined(__NuttX__) +#if !defined(_LIBCPP_MSVCRT) && !defined(__MINGW32__) && !defined(__BIONIC__) && !defined(__NuttX__) # include <langinfo.h> #endif diff --git a/contrib/libs/cxxsupp/libcxx/src/memory_resource.cpp b/contrib/libs/cxxsupp/libcxx/src/memory_resource.cpp index afd1b892086..2117238e634 100644 --- a/contrib/libs/cxxsupp/libcxx/src/memory_resource.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/memory_resource.cpp @@ -189,7 +189,8 @@ void unsynchronized_pool_resource::__adhoc_pool::__do_deallocate( return; } } - _LIBCPP_ASSERT_UNCATEGORIZED(false, "deallocating a block that was not allocated with this allocator"); + // The request to deallocate memory ends up being a no-op, likely resulting in a memory leak. + _LIBCPP_ASSERT_VALID_DEALLOCATION(false, "deallocating a block that was not allocated with this allocator"); } } @@ -230,7 +231,7 @@ public: } void* __allocate_in_new_chunk(memory_resource* upstream, size_t block_size, size_t chunk_size) { - _LIBCPP_ASSERT_UNCATEGORIZED(chunk_size % block_size == 0, ""); + _LIBCPP_ASSERT_INTERNAL(chunk_size % block_size == 0, ""); static_assert(__default_alignment >= alignof(std::max_align_t), ""); static_assert(__default_alignment >= alignof(__chunk_footer), ""); static_assert(__default_alignment >= alignof(__vacancy_header), ""); diff --git a/contrib/libs/cxxsupp/libcxx/src/mutex.cpp b/contrib/libs/cxxsupp/libcxx/src/mutex.cpp index 13c63247f1a..26b26b691a2 100644 --- a/contrib/libs/cxxsupp/libcxx/src/mutex.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/mutex.cpp @@ -38,7 +38,8 @@ bool mutex::try_lock() noexcept { return __libcpp_mutex_trylock(&__m_); } void mutex::unlock() noexcept { int ec = __libcpp_mutex_unlock(&__m_); (void)ec; - _LIBCPP_ASSERT_UNCATEGORIZED(ec == 0, "call to mutex::unlock failed"); + _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL( + ec == 0, "call to mutex::unlock failed. A possible reason is that the mutex wasn't locked"); } // recursive_mutex @@ -52,7 +53,7 @@ recursive_mutex::recursive_mutex() { recursive_mutex::~recursive_mutex() { int e = __libcpp_recursive_mutex_destroy(&__m_); (void)e; - _LIBCPP_ASSERT_UNCATEGORIZED(e == 0, "call to ~recursive_mutex() failed"); + _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(e == 0, "call to ~recursive_mutex() failed"); } void recursive_mutex::lock() { @@ -64,7 +65,8 @@ void recursive_mutex::lock() { void recursive_mutex::unlock() noexcept { int e = __libcpp_recursive_mutex_unlock(&__m_); (void)e; - _LIBCPP_ASSERT_UNCATEGORIZED(e == 0, "call to recursive_mutex::unlock() failed"); + _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL( + e == 0, "call to recursive_mutex::unlock() failed. A possible reason is that the mutex wasn't locked"); } bool recursive_mutex::try_lock() noexcept { return __libcpp_recursive_mutex_trylock(&__m_); } diff --git a/contrib/libs/cxxsupp/libcxx/src/mutex_destructor.cpp b/contrib/libs/cxxsupp/libcxx/src/mutex_destructor.cpp index d5ac257f94d..a6ceaaaf23f 100644 --- a/contrib/libs/cxxsupp/libcxx/src/mutex_destructor.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/mutex_destructor.cpp @@ -17,7 +17,7 @@ // _LIBCPP_BUILDING_LIBRARY to change the definition in the headers. #include <__config> -#include <__threading_support> +#include <__thread/support.h> #if _LIBCPP_ABI_VERSION == 1 || !defined(_LIBCPP_HAS_TRIVIAL_MUTEX_DESTRUCTION) # define NEEDS_MUTEX_DESTRUCTOR diff --git a/contrib/libs/cxxsupp/libcxx/src/new.cpp b/contrib/libs/cxxsupp/libcxx/src/new.cpp index e9a4adcfdf4..7f1cc671f15 100644 --- a/contrib/libs/cxxsupp/libcxx/src/new.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/new.cpp @@ -6,7 +6,10 @@ // //===----------------------------------------------------------------------===// +#include "include/overridable_function.h" +#include <__assert> #include <__memory/aligned_alloc.h> +#include <cstddef> #include <cstdlib> #include <new> @@ -15,12 +18,22 @@ // The code below is copied as-is into libc++abi's libcxxabi/src/stdlib_new_delete.cpp // file. The version in this file is the canonical one. +inline void __throw_bad_alloc_shim() { +# ifdef __EMSCRIPTEN__ + abort(); +#else + std::__throw_bad_alloc(); +#endif +} + +# define _LIBCPP_ASSERT_SHIM(expr, str) _LIBCPP_ASSERT(expr, str) + // ------------------ BEGIN COPY ------------------ // Implement all new and delete operators as weak definitions // in this shared library, so that they can be overridden by programs // that define non-weak copies of the functions. -static void* operator_new_impl(std::size_t size) noexcept { +static void* operator_new_impl(std::size_t size) { if (size == 0) size = 1; void* p; @@ -36,51 +49,63 @@ static void* operator_new_impl(std::size_t size) noexcept { return p; } -_LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC { +_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new(std::size_t size) _THROW_BAD_ALLOC { void* p = operator_new_impl(size); -# ifndef _LIBCPP_HAS_NO_EXCEPTIONS - if (p == nullptr) - throw std::bad_alloc(); -# else -# ifdef __EMSCRIPTEN__ if (p == nullptr) - // Abort here so that when exceptions are disabled, we do not just - // return 0 when malloc returns 0. - // We could also do this with set_new_handler, but that adds a - // global constructor and a table entry, overhead that we can avoid - // by doing it this way. - abort(); -# endif -# endif + __throw_bad_alloc_shim(); return p; } _LIBCPP_WEAK void* operator new(size_t size, const std::nothrow_t&) noexcept { +# ifdef _LIBCPP_HAS_NO_EXCEPTIONS +# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION + _LIBCPP_ASSERT_SHIM( + !std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new)), + "libc++ was configured with exceptions disabled and `operator new(size_t)` has been overridden, " + "but `operator new(size_t, nothrow_t)` has not been overridden. This is problematic because " + "`operator new(size_t, nothrow_t)` must call `operator new(size_t)`, which will terminate in case " + "it fails to allocate, making it impossible for `operator new(size_t, nothrow_t)` to fulfill its " + "contract (since it should return nullptr upon failure). Please make sure you override " + "`operator new(size_t, nothrow_t)` as well."); +# endif + + return operator_new_impl(size); +# else void* p = nullptr; -# ifndef _LIBCPP_HAS_NO_EXCEPTIONS try { -# endif // _LIBCPP_HAS_NO_EXCEPTIONS p = ::operator new(size); -# ifndef _LIBCPP_HAS_NO_EXCEPTIONS } catch (...) { } -# endif // _LIBCPP_HAS_NO_EXCEPTIONS return p; +# endif } -_LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC { return ::operator new(size); } +_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* operator new[](size_t size) _THROW_BAD_ALLOC { + return ::operator new(size); +} _LIBCPP_WEAK void* operator new[](size_t size, const std::nothrow_t&) noexcept { +# ifdef _LIBCPP_HAS_NO_EXCEPTIONS +# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION + _LIBCPP_ASSERT_SHIM( + !std::__is_function_overridden(static_cast<void* (*)(std::size_t)>(&operator new[])), + "libc++ was configured with exceptions disabled and `operator new[](size_t)` has been overridden, " + "but `operator new[](size_t, nothrow_t)` has not been overridden. This is problematic because " + "`operator new[](size_t, nothrow_t)` must call `operator new[](size_t)`, which will terminate in case " + "it fails to allocate, making it impossible for `operator new[](size_t, nothrow_t)` to fulfill its " + "contract (since it should return nullptr upon failure). Please make sure you override " + "`operator new[](size_t, nothrow_t)` as well."); +# endif + + return operator_new_impl(size); +# else void* p = nullptr; -# ifndef _LIBCPP_HAS_NO_EXCEPTIONS try { -# endif // _LIBCPP_HAS_NO_EXCEPTIONS p = ::operator new[](size); -# ifndef _LIBCPP_HAS_NO_EXCEPTIONS } catch (...) { } -# endif // _LIBCPP_HAS_NO_EXCEPTIONS return p; +# endif } _LIBCPP_WEAK void operator delete(void* ptr) noexcept { std::free(ptr); } @@ -97,7 +122,7 @@ _LIBCPP_WEAK void operator delete[](void* ptr, size_t) noexcept { ::operator del # if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) -static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) noexcept { +static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignment) { if (size == 0) size = 1; if (static_cast<size_t>(alignment) < sizeof(void*)) @@ -117,43 +142,66 @@ static void* operator_new_aligned_impl(std::size_t size, std::align_val_t alignm return p; } -_LIBCPP_WEAK void* operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { +_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* +operator new(std::size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { void* p = operator_new_aligned_impl(size, alignment); -# ifndef _LIBCPP_HAS_NO_EXCEPTIONS if (p == nullptr) - throw std::bad_alloc(); -# endif + __throw_bad_alloc_shim(); return p; } _LIBCPP_WEAK void* operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { +# ifdef _LIBCPP_HAS_NO_EXCEPTIONS +# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION + _LIBCPP_ASSERT_SHIM( + !std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new)), + "libc++ was configured with exceptions disabled and `operator new(size_t, align_val_t)` has been overridden, " + "but `operator new(size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because " + "`operator new(size_t, align_val_t, nothrow_t)` must call `operator new(size_t, align_val_t)`, which will " + "terminate in case it fails to allocate, making it impossible for `operator new(size_t, align_val_t, nothrow_t)` " + "to fulfill its contract (since it should return nullptr upon failure). Please make sure you override " + "`operator new(size_t, align_val_t, nothrow_t)` as well."); +# endif + + return operator_new_aligned_impl(size, alignment); +# else void* p = nullptr; -# ifndef _LIBCPP_HAS_NO_EXCEPTIONS try { -# endif // _LIBCPP_HAS_NO_EXCEPTIONS p = ::operator new(size, alignment); -# ifndef _LIBCPP_HAS_NO_EXCEPTIONS } catch (...) { } -# endif // _LIBCPP_HAS_NO_EXCEPTIONS return p; +# endif } -_LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { +_LIBCPP_MAKE_OVERRIDABLE_FUNCTION_DETECTABLE _LIBCPP_WEAK void* +operator new[](size_t size, std::align_val_t alignment) _THROW_BAD_ALLOC { return ::operator new(size, alignment); } _LIBCPP_WEAK void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept { +# ifdef _LIBCPP_HAS_NO_EXCEPTIONS +# if _LIBCPP_CAN_DETECT_OVERRIDDEN_FUNCTION + _LIBCPP_ASSERT_SHIM( + !std::__is_function_overridden(static_cast<void* (*)(std::size_t, std::align_val_t)>(&operator new[])), + "libc++ was configured with exceptions disabled and `operator new[](size_t, align_val_t)` has been overridden, " + "but `operator new[](size_t, align_val_t, nothrow_t)` has not been overridden. This is problematic because " + "`operator new[](size_t, align_val_t, nothrow_t)` must call `operator new[](size_t, align_val_t)`, which will " + "terminate in case it fails to allocate, making it impossible for `operator new[](size_t, align_val_t, " + "nothrow_t)` to fulfill its contract (since it should return nullptr upon failure). Please make sure you " + "override " + "`operator new[](size_t, align_val_t, nothrow_t)` as well."); +# endif + + return operator_new_aligned_impl(size, alignment); +# else void* p = nullptr; -# ifndef _LIBCPP_HAS_NO_EXCEPTIONS try { -# endif // _LIBCPP_HAS_NO_EXCEPTIONS p = ::operator new[](size, alignment); -# ifndef _LIBCPP_HAS_NO_EXCEPTIONS } catch (...) { } -# endif // _LIBCPP_HAS_NO_EXCEPTIONS return p; +# endif } _LIBCPP_WEAK void operator delete(void* ptr, std::align_val_t) noexcept { std::__libcpp_aligned_free(ptr); } diff --git a/contrib/libs/cxxsupp/libcxx/src/ostream.cpp b/contrib/libs/cxxsupp/libcxx/src/ostream.cpp new file mode 100644 index 00000000000..443dce9a390 --- /dev/null +++ b/contrib/libs/cxxsupp/libcxx/src/ostream.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include <__availability> +#include <__config> +#ifndef _LIBCPP_HAS_NO_FILESYSTEM +# include <fstream> +#endif +#include <ostream> + +#include "std_stream.h" + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_EXPORTED_FROM_ABI FILE* __get_ostream_file(ostream& __os) { + // dynamic_cast requires RTTI, this only affects users whose vendor builds + // the dylib with RTTI disabled. It does not affect users who build with RTTI + // disabled but use a dylib where the RTTI is enabled. + // + // Returning a nullptr means the stream is not considered a terminal and the + // special terminal handling is not done. The terminal handling is mainly of + // importance on Windows. +#ifndef _LIBCPP_HAS_NO_RTTI + auto* __rdbuf = __os.rdbuf(); +# ifndef _LIBCPP_HAS_NO_FILESYSTEM + if (auto* __buffer = dynamic_cast<filebuf*>(__rdbuf)) + return __buffer->__file_; +# endif + + if (auto* __buffer = dynamic_cast<__stdoutbuf<char>*>(__rdbuf)) + return __buffer->__file_; +#endif // _LIBCPP_HAS_NO_RTTI + + return nullptr; +} + +_LIBCPP_END_NAMESPACE_STD diff --git a/contrib/libs/cxxsupp/libcxx/src/print.cpp b/contrib/libs/cxxsupp/libcxx/src/print.cpp index 3692187a595..8fa59fdd097 100644 --- a/contrib/libs/cxxsupp/libcxx/src/print.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/print.cpp @@ -8,22 +8,26 @@ #include <__config> -#if defined(_LIBCPP_WIN32API) +#include <cstdlib> +#include <print> + +#include <__system_error/system_error.h> -# include <cstdlib> -# include <print> +#include "filesystem/error.h" +#if defined(_LIBCPP_WIN32API) # define WIN32_LEAN_AND_MEAN # define NOMINMAX # include <io.h> # include <windows.h> - -# include <__system_error/system_error.h> - -# include "filesystem/error.h" +#elif __has_include(<unistd.h>) +# include <unistd.h> +#endif _LIBCPP_BEGIN_NAMESPACE_STD +#if defined(_LIBCPP_WIN32API) + _LIBCPP_EXPORTED_FROM_ABI bool __is_windows_terminal(FILE* __stream) { // Note the Standard does this in one call, but it's unclear whether // an invalid handle is allowed when calling GetConsoleMode. @@ -52,6 +56,9 @@ __write_to_windows_console([[maybe_unused]] FILE* __stream, [[maybe_unused]] wst } # endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS -_LIBCPP_END_NAMESPACE_STD +#elif __has_include(<unistd.h>) // !_LIBCPP_WIN32API -#endif // !_LIBCPP_WIN32API +_LIBCPP_EXPORTED_FROM_ABI bool __is_posix_terminal(FILE* __stream) { return isatty(fileno(__stream)); } +#endif + +_LIBCPP_END_NAMESPACE_STD diff --git a/contrib/libs/cxxsupp/libcxx/src/std_stream.h b/contrib/libs/cxxsupp/libcxx/src/std_stream.h index c4e9733601d..e55cd0b6b77 100644 --- a/contrib/libs/cxxsupp/libcxx/src/std_stream.h +++ b/contrib/libs/cxxsupp/libcxx/src/std_stream.h @@ -269,6 +269,8 @@ private: __stdoutbuf(const __stdoutbuf&); __stdoutbuf& operator=(const __stdoutbuf&); + + _LIBCPP_EXPORTED_FROM_ABI friend FILE* __get_ostream_file(ostream&); }; template <class _CharT> diff --git a/contrib/libs/cxxsupp/libcxx/src/strstream.cpp b/contrib/libs/cxxsupp/libcxx/src/strstream.cpp index a9b5989ec49..70374191c6a 100644 --- a/contrib/libs/cxxsupp/libcxx/src/strstream.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/strstream.cpp @@ -120,7 +120,7 @@ strstreambuf::int_type strstreambuf::overflow(int_type __c) { if (buf == nullptr) return int_type(EOF); if (old_size != 0) { - _LIBCPP_ASSERT_UNCATEGORIZED(eback(), "overflow copying from NULL"); + _LIBCPP_ASSERT_INTERNAL(eback(), "strstreambuf::overflow reallocating but the get area is a null pointer"); memcpy(buf, eback(), static_cast<size_t>(old_size)); } ptrdiff_t ninp = gptr() - eback(); diff --git a/contrib/libs/cxxsupp/libcxx/src/support/ibm/xlocale_zos.cpp b/contrib/libs/cxxsupp/libcxx/src/support/ibm/xlocale_zos.cpp index 4c20997b4eb..9a90e08e11c 100644 --- a/contrib/libs/cxxsupp/libcxx/src/support/ibm/xlocale_zos.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/support/ibm/xlocale_zos.cpp @@ -103,7 +103,7 @@ locale_t uselocale(locale_t newloc) { tokenized.push_back(s); } - _LIBCPP_ASSERT_UNCATEGORIZED(tokenized.size() >= _NCAT, "locale-name list is too short"); + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(tokenized.size() >= _NCAT, "locale-name list is too short"); previous_loc->lc_collate = tokenized[LC_COLLATE]; previous_loc->lc_ctype = tokenized[LC_CTYPE]; diff --git a/contrib/libs/cxxsupp/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp b/contrib/libs/cxxsupp/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp index c07de5838b1..bdb17b9996b 100644 --- a/contrib/libs/cxxsupp/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp +++ b/contrib/libs/cxxsupp/libcxx/src/support/runtime/exception_pointer_cxxabi.ipp @@ -28,6 +28,14 @@ exception_ptr& exception_ptr::operator=(const exception_ptr& other) noexcept { return *this; } +exception_ptr exception_ptr::__from_native_exception_pointer(void* __e) noexcept { + exception_ptr ptr; + ptr.__ptr_ = __e; + __cxa_increment_exception_refcount(ptr.__ptr_); + + return ptr; +} + nested_exception::nested_exception() noexcept : __ptr_(current_exception()) {} nested_exception::~nested_exception() noexcept {} diff --git a/contrib/libs/cxxsupp/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp b/contrib/libs/cxxsupp/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp index 8e0e63cd4d4..6dad248f9e1 100644 --- a/contrib/libs/cxxsupp/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp +++ b/contrib/libs/cxxsupp/libcxx/src/support/runtime/exception_pointer_glibcxx.ipp @@ -23,6 +23,7 @@ namespace __exception_ptr { struct exception_ptr { void* __ptr_; + explicit exception_ptr(void*) noexcept; exception_ptr(const exception_ptr&) noexcept; exception_ptr& operator=(const exception_ptr&) noexcept; ~exception_ptr() noexcept; @@ -45,6 +46,13 @@ exception_ptr& exception_ptr::operator=(const exception_ptr& other) noexcept { return *this; } +exception_ptr exception_ptr::__from_native_exception_pointer(void* __e) noexcept { + exception_ptr ptr{}; + new (reinterpret_cast<void*>(&ptr)) __exception_ptr::exception_ptr(__e); + + return ptr; +} + nested_exception::nested_exception() noexcept : __ptr_(current_exception()) {} _LIBCPP_NORETURN void nested_exception::rethrow_nested() const { diff --git a/contrib/libs/cxxsupp/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp b/contrib/libs/cxxsupp/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp index de0605d7774..e12b0caf419 100644 --- a/contrib/libs/cxxsupp/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp +++ b/contrib/libs/cxxsupp/libcxx/src/support/runtime/exception_pointer_unimplemented.ipp @@ -30,6 +30,12 @@ exception_ptr& exception_ptr::operator=(const exception_ptr& other) noexcept { ::abort(); } +exception_ptr exception_ptr::__from_native_exception_pointer(void *__e) noexcept { +#warning exception_ptr not yet implemented + fprintf(stderr, "exception_ptr not yet implemented\n"); + ::abort(); +} + nested_exception::nested_exception() noexcept : __ptr_(current_exception()) {} #if !defined(__GLIBCXX__) diff --git a/contrib/libs/cxxsupp/libcxx/src/support/win32/thread_win32.cpp b/contrib/libs/cxxsupp/libcxx/src/support/win32/thread_win32.cpp index 8736a532073..a2585c0b89f 100644 --- a/contrib/libs/cxxsupp/libcxx/src/support/win32/thread_win32.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/support/win32/thread_win32.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include <__threading_support> +#include <__thread/support/windows.h> #include <chrono> #define NOMINMAX diff --git a/contrib/libs/cxxsupp/libcxx/src/system_error.cpp b/contrib/libs/cxxsupp/libcxx/src/system_error.cpp index 034b73c5480..f518b480a27 100644 --- a/contrib/libs/cxxsupp/libcxx/src/system_error.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/system_error.cpp @@ -68,7 +68,7 @@ __attribute__((unused)) const char* handle_strerror_r_return(int strerror_return if (new_errno == EINVAL) return ""; - _LIBCPP_ASSERT_UNCATEGORIZED(new_errno == ERANGE, "unexpected error from ::strerror_r"); + _LIBCPP_ASSERT_INTERNAL(new_errno == ERANGE, "unexpected error from ::strerror_r"); // FIXME maybe? 'strerror_buff_size' is likely to exceed the // maximum error size so ERANGE shouldn't be returned. std::abort(); diff --git a/contrib/libs/cxxsupp/libcxx/src/time_zone.cpp b/contrib/libs/cxxsupp/libcxx/src/time_zone.cpp new file mode 100644 index 00000000000..b6bf06a116f --- /dev/null +++ b/contrib/libs/cxxsupp/libcxx/src/time_zone.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#include <chrono> + +#include "include/tzdb/time_zone_private.h" + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI time_zone time_zone::__create(unique_ptr<time_zone::__impl>&& __p) { + _LIBCPP_ASSERT_NON_NULL(__p != nullptr, "initialized time_zone without a valid pimpl object"); + time_zone result; + result.__impl_ = std::move(__p); + return result; +} + +_LIBCPP_EXPORTED_FROM_ABI time_zone::~time_zone() = default; + +[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI string_view time_zone::__name() const noexcept { return __impl_->__name(); } + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD diff --git a/contrib/libs/cxxsupp/libcxx/src/tz.cpp b/contrib/libs/cxxsupp/libcxx/src/tz.cpp deleted file mode 100644 index 4425f0e6b91..00000000000 --- a/contrib/libs/cxxsupp/libcxx/src/tz.cpp +++ /dev/null @@ -1,146 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html - -#include <chrono> -#include <filesystem> -#include <fstream> -#include <stdexcept> -#include <string> - -// Contains a parser for the IANA time zone data files. -// -// These files can be found at https://data.iana.org/time-zones/ and are in the -// public domain. Information regarding the input can be found at -// https://data.iana.org/time-zones/tz-how-to.html and -// https://man7.org/linux/man-pages/man8/zic.8.html. -// -// As indicated at https://howardhinnant.github.io/date/tz.html#Installation -// For Windows another file seems to be required -// https://raw.githubusercontent.com/unicode-org/cldr/master/common/supplemental/windowsZones.xml -// This file seems to contain the mapping of Windows time zone name to IANA -// time zone names. -// -// However this article mentions another way to do the mapping on Windows -// https://devblogs.microsoft.com/oldnewthing/20210527-00/?p=105255 -// This requires Windows 10 Version 1903, which was released in May of 2019 -// and considered end of life in December 2020 -// https://learn.microsoft.com/en-us/lifecycle/announcements/windows-10-1903-end-of-servicing -// -// TODO TZDB Implement the Windows mapping in tzdb::current_zone - -_LIBCPP_BEGIN_NAMESPACE_STD - -namespace chrono { - -// This function is weak so it can be overriden in the tests. The -// declaration is in the test header test/support/test_tzdb.h -_LIBCPP_WEAK string_view __libcpp_tzdb_directory() { -#if defined(__linux__) - return "/usr/share/zoneinfo/"; -#else -# error "unknown path to the IANA Time Zone Database" -#endif -} - -[[nodiscard]] static bool __is_whitespace(int __c) { return __c == ' ' || __c == '\t'; } - -static void __skip_optional_whitespace(istream& __input) { - while (chrono::__is_whitespace(__input.peek())) - __input.get(); -} - -static void __skip_mandatory_whitespace(istream& __input) { - if (!chrono::__is_whitespace(__input.get())) - std::__throw_runtime_error("corrupt tzdb: expected whitespace"); - - chrono::__skip_optional_whitespace(__input); -} - -static void __matches(istream& __input, char __expected) { - if (std::tolower(__input.get()) != __expected) - std::__throw_runtime_error((string("corrupt tzdb: expected character '") + __expected + '\'').c_str()); -} - -static void __matches(istream& __input, string_view __expected) { - for (auto __c : __expected) - if (std::tolower(__input.get()) != __c) - std::__throw_runtime_error((string("corrupt tzdb: expected string '") + string(__expected) + '\'').c_str()); -} - -[[nodiscard]] static string __parse_string(istream& __input) { - string __result; - while (true) { - int __c = __input.get(); - switch (__c) { - case ' ': - case '\t': - case '\n': - __input.unget(); - [[fallthrough]]; - case istream::traits_type::eof(): - if (__result.empty()) - std::__throw_runtime_error("corrupt tzdb: expected a string"); - - return __result; - - default: - __result.push_back(__c); - } - } -} - -static string __parse_version(istream& __input) { - // The first line in tzdata.zi contains - // # version YYYYw - // The parser expects this pattern - // #\s*version\s*\(.*) - // This part is not documented. - chrono::__matches(__input, '#'); - chrono::__skip_optional_whitespace(__input); - chrono::__matches(__input, "version"); - chrono::__skip_mandatory_whitespace(__input); - return chrono::__parse_string(__input); -} - -static tzdb __make_tzdb() { - tzdb __result; - - filesystem::path __root = chrono::__libcpp_tzdb_directory(); - ifstream __tzdata{__root / "tzdata.zi"}; - - __result.version = chrono::__parse_version(__tzdata); - return __result; -} - -//===----------------------------------------------------------------------===// -// Public API -//===----------------------------------------------------------------------===// - -_LIBCPP_NODISCARD_EXT _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI tzdb_list& get_tzdb_list() { - static tzdb_list __result{chrono::__make_tzdb()}; - return __result; -} - -_LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI const tzdb& reload_tzdb() { - if (chrono::remote_version() == chrono::get_tzdb().version) - return chrono::get_tzdb(); - - return chrono::get_tzdb_list().__emplace_front(chrono::__make_tzdb()); -} - -_LIBCPP_NODISCARD_EXT _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI string remote_version() { - filesystem::path __root = chrono::__libcpp_tzdb_directory(); - ifstream __tzdata{__root / "tzdata.zi"}; - return chrono::__parse_version(__tzdata); -} - -} // namespace chrono - -_LIBCPP_END_NAMESPACE_STD diff --git a/contrib/libs/cxxsupp/libcxx/src/tzdb.cpp b/contrib/libs/cxxsupp/libcxx/src/tzdb.cpp new file mode 100644 index 00000000000..2bb801e4869 --- /dev/null +++ b/contrib/libs/cxxsupp/libcxx/src/tzdb.cpp @@ -0,0 +1,641 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html + +#include <algorithm> +#include <chrono> +#include <filesystem> +#include <fstream> +#include <stdexcept> +#include <string> + +#include "include/tzdb/time_zone_link_private.h" +#include "include/tzdb/time_zone_private.h" +#include "include/tzdb/types_private.h" +#include "include/tzdb/tzdb_list_private.h" +#include "include/tzdb/tzdb_private.h" + +// Contains a parser for the IANA time zone data files. +// +// These files can be found at https://data.iana.org/time-zones/ and are in the +// public domain. Information regarding the input can be found at +// https://data.iana.org/time-zones/tz-how-to.html and +// https://man7.org/linux/man-pages/man8/zic.8.html. +// +// As indicated at https://howardhinnant.github.io/date/tz.html#Installation +// For Windows another file seems to be required +// https://raw.githubusercontent.com/unicode-org/cldr/master/common/supplemental/windowsZones.xml +// This file seems to contain the mapping of Windows time zone name to IANA +// time zone names. +// +// However this article mentions another way to do the mapping on Windows +// https://devblogs.microsoft.com/oldnewthing/20210527-00/?p=105255 +// This requires Windows 10 Version 1903, which was released in May of 2019 +// and considered end of life in December 2020 +// https://learn.microsoft.com/en-us/lifecycle/announcements/windows-10-1903-end-of-servicing +// +// TODO TZDB Implement the Windows mapping in tzdb::current_zone + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace chrono { + +// This function is weak so it can be overriden in the tests. The +// declaration is in the test header test/support/test_tzdb.h +_LIBCPP_WEAK string_view __libcpp_tzdb_directory() { +#if defined(__linux__) + return "/usr/share/zoneinfo/"; +#else +# error "unknown path to the IANA Time Zone Database" +#endif +} + +//===----------------------------------------------------------------------===// +// Details +//===----------------------------------------------------------------------===// + +[[nodiscard]] static bool __is_whitespace(int __c) { return __c == ' ' || __c == '\t'; } + +static void __skip_optional_whitespace(istream& __input) { + while (chrono::__is_whitespace(__input.peek())) + __input.get(); +} + +static void __skip_mandatory_whitespace(istream& __input) { + if (!chrono::__is_whitespace(__input.get())) + std::__throw_runtime_error("corrupt tzdb: expected whitespace"); + + chrono::__skip_optional_whitespace(__input); +} + +[[nodiscard]] static bool __is_eol(int __c) { return __c == '\n' || __c == std::char_traits<char>::eof(); } + +static void __skip_line(istream& __input) { + while (!chrono::__is_eol(__input.peek())) { + __input.get(); + } + __input.get(); +} + +static void __skip(istream& __input, char __suffix) { + if (std::tolower(__input.peek()) == __suffix) + __input.get(); +} + +static void __skip(istream& __input, string_view __suffix) { + for (auto __c : __suffix) + if (std::tolower(__input.peek()) == __c) + __input.get(); +} + +static void __matches(istream& __input, char __expected) { + if (std::tolower(__input.get()) != __expected) + std::__throw_runtime_error((string("corrupt tzdb: expected character '") + __expected + '\'').c_str()); +} + +static void __matches(istream& __input, string_view __expected) { + for (auto __c : __expected) + if (std::tolower(__input.get()) != __c) + std::__throw_runtime_error((string("corrupt tzdb: expected string '") + string(__expected) + '\'').c_str()); +} + +[[nodiscard]] static string __parse_string(istream& __input) { + string __result; + while (true) { + int __c = __input.get(); + switch (__c) { + case ' ': + case '\t': + case '\n': + __input.unget(); + [[fallthrough]]; + case istream::traits_type::eof(): + if (__result.empty()) + std::__throw_runtime_error("corrupt tzdb: expected a string"); + + return __result; + + default: + __result.push_back(__c); + } + } +} + +[[nodiscard]] static int64_t __parse_integral(istream& __input, bool __leading_zero_allowed) { + int64_t __result = __input.get(); + if (__leading_zero_allowed) { + if (__result < '0' || __result > '9') + std::__throw_runtime_error("corrupt tzdb: expected a digit"); + } else { + if (__result < '1' || __result > '9') + std::__throw_runtime_error("corrupt tzdb: expected a non-zero digit"); + } + __result -= '0'; + while (true) { + if (__input.peek() < '0' || __input.peek() > '9') + return __result; + + // In order to avoid possible overflows we limit the accepted range. + // Most values parsed are expected to be very small: + // - 8784 hours in a year + // - 31 days in a month + // - year no real maximum, these values are expected to be less than + // the range of the year type. + // + // However the leapseconds use a seconds after epoch value. Using an + // int would run into an overflow in 2038. By using a 64-bit value + // the range is large enough for the bilions of years. Limiting that + // range slightly to make the code easier is not an issue. + if (__result > (std::numeric_limits<int64_t>::max() / 16)) + std::__throw_runtime_error("corrupt tzdb: integral too large"); + + __result *= 10; + __result += __input.get() - '0'; + } +} + +//===----------------------------------------------------------------------===// +// Calendar +//===----------------------------------------------------------------------===// + +[[nodiscard]] static day __parse_day(istream& __input) { + unsigned __result = chrono::__parse_integral(__input, false); + if (__result > 31) + std::__throw_runtime_error("corrupt tzdb day: value too large"); + return day{__result}; +} + +[[nodiscard]] static weekday __parse_weekday(istream& __input) { + // TZDB allows the shortest unique name. + switch (std::tolower(__input.get())) { + case 'f': + chrono::__skip(__input, "riday"); + return Friday; + + case 'm': + chrono::__skip(__input, "onday"); + return Monday; + + case 's': + switch (std::tolower(__input.get())) { + case 'a': + chrono::__skip(__input, "turday"); + return Saturday; + + case 'u': + chrono::__skip(__input, "nday"); + return Sunday; + } + break; + + case 't': + switch (std::tolower(__input.get())) { + case 'h': + chrono::__skip(__input, "ursday"); + return Thursday; + + case 'u': + chrono::__skip(__input, "esday"); + return Tuesday; + } + break; + case 'w': + chrono::__skip(__input, "ednesday"); + return Wednesday; + } + + std::__throw_runtime_error("corrupt tzdb weekday: invalid name"); +} + +[[nodiscard]] static month __parse_month(istream& __input) { + // TZDB allows the shortest unique name. + switch (std::tolower(__input.get())) { + case 'a': + switch (std::tolower(__input.get())) { + case 'p': + chrono::__skip(__input, "ril"); + return April; + + case 'u': + chrono::__skip(__input, "gust"); + return August; + } + break; + + case 'd': + chrono::__skip(__input, "ecember"); + return December; + + case 'f': + chrono::__skip(__input, "ebruary"); + return February; + + case 'j': + switch (std::tolower(__input.get())) { + case 'a': + chrono::__skip(__input, "nuary"); + return January; + + case 'u': + switch (std::tolower(__input.get())) { + case 'n': + chrono::__skip(__input, 'e'); + return June; + + case 'l': + chrono::__skip(__input, 'y'); + return July; + } + } + break; + + case 'm': + if (std::tolower(__input.get()) == 'a') + switch (std::tolower(__input.get())) { + case 'y': + return May; + + case 'r': + chrono::__skip(__input, "ch"); + return March; + } + break; + + case 'n': + chrono::__skip(__input, "ovember"); + return November; + + case 'o': + chrono::__skip(__input, "ctober"); + return October; + + case 's': + chrono::__skip(__input, "eptember"); + return September; + } + std::__throw_runtime_error("corrupt tzdb month: invalid name"); +} + +[[nodiscard]] static year __parse_year_value(istream& __input) { + bool __negative = __input.peek() == '-'; + if (__negative) [[unlikely]] + __input.get(); + + int64_t __result = __parse_integral(__input, true); + if (__result > static_cast<int>(year::max())) { + if (__negative) + std::__throw_runtime_error("corrupt tzdb year: year is less than the minimum"); + + std::__throw_runtime_error("corrupt tzdb year: year is greater than the maximum"); + } + + return year{static_cast<int>(__negative ? -__result : __result)}; +} + +[[nodiscard]] static year __parse_year(istream& __input) { + if (std::tolower(__input.peek()) != 'm') [[likely]] + return chrono::__parse_year_value(__input); + + __input.get(); + switch (std::tolower(__input.peek())) { + case 'i': + __input.get(); + chrono::__skip(__input, 'n'); + [[fallthrough]]; + + case ' ': + // The m is minimum, even when that is ambiguous. + return year::min(); + + case 'a': + __input.get(); + chrono::__skip(__input, 'x'); + return year::max(); + } + + std::__throw_runtime_error("corrupt tzdb year: expected 'min' or 'max'"); +} + +//===----------------------------------------------------------------------===// +// TZDB fields +//===----------------------------------------------------------------------===// + +[[nodiscard]] static year __parse_to(istream& __input, year __only) { + if (std::tolower(__input.peek()) != 'o') + return chrono::__parse_year(__input); + + __input.get(); + chrono::__skip(__input, "nly"); + return __only; +} + +[[nodiscard]] static __tz::__constrained_weekday::__comparison_t __parse_comparison(istream& __input) { + switch (__input.get()) { + case '>': + chrono::__matches(__input, '='); + return __tz::__constrained_weekday::__ge; + + case '<': + chrono::__matches(__input, '='); + return __tz::__constrained_weekday::__le; + } + std::__throw_runtime_error("corrupt tzdb on: expected '>=' or '<='"); +} + +[[nodiscard]] static __tz::__on __parse_on(istream& __input) { + if (std::isdigit(__input.peek())) + return chrono::__parse_day(__input); + + if (std::tolower(__input.peek()) == 'l') { + chrono::__matches(__input, "last"); + return weekday_last(chrono::__parse_weekday(__input)); + } + + return __tz::__constrained_weekday{ + chrono::__parse_weekday(__input), chrono::__parse_comparison(__input), chrono::__parse_day(__input)}; +} + +[[nodiscard]] static seconds __parse_duration(istream& __input) { + seconds __result{0}; + int __c = __input.peek(); + bool __negative = __c == '-'; + if (__negative) { + __input.get(); + // Negative is either a negative value or a single -. + // The latter means 0 and the parsing is complete. + if (!std::isdigit(__input.peek())) + return __result; + } + + __result += hours(__parse_integral(__input, true)); + if (__input.peek() != ':') + return __negative ? -__result : __result; + + __input.get(); + __result += minutes(__parse_integral(__input, true)); + if (__input.peek() != ':') + return __negative ? -__result : __result; + + __input.get(); + __result += seconds(__parse_integral(__input, true)); + if (__input.peek() != '.') + return __negative ? -__result : __result; + + __input.get(); + (void)__parse_integral(__input, true); // Truncate the digits. + + return __negative ? -__result : __result; +} + +[[nodiscard]] static __tz::__clock __parse_clock(istream& __input) { + switch (__input.get()) { // case sensitive + case 'w': + return __tz::__clock::__local; + case 's': + return __tz::__clock::__standard; + + case 'u': + case 'g': + case 'z': + return __tz::__clock::__universal; + } + + __input.unget(); + return __tz::__clock::__local; +} + +[[nodiscard]] static bool __parse_dst(istream& __input, seconds __offset) { + switch (__input.get()) { // case sensitive + case 's': + return false; + + case 'd': + return true; + } + + __input.unget(); + return __offset != 0s; +} + +[[nodiscard]] static __tz::__at __parse_at(istream& __input) { + return {__parse_duration(__input), __parse_clock(__input)}; +} + +[[nodiscard]] static __tz::__save __parse_save(istream& __input) { + seconds __time = chrono::__parse_duration(__input); + return {__time, chrono::__parse_dst(__input, __time)}; +} + +[[nodiscard]] static string __parse_letters(istream& __input) { + string __result = __parse_string(__input); + // Canonicalize "-" to "" since they are equivalent in the specification. + return __result != "-" ? __result : ""; +} + +[[nodiscard]] static __tz::__continuation::__rules_t __parse_rules(istream& __input) { + int __c = __input.peek(); + // A single - is not a SAVE but a special case. + if (__c == '-') { + __input.get(); + if (chrono::__is_whitespace(__input.peek())) + return monostate{}; + __input.unget(); + return chrono::__parse_save(__input); + } + + if (std::isdigit(__c) || __c == '+') + return chrono::__parse_save(__input); + + return chrono::__parse_string(__input); +} + +[[nodiscard]] static __tz::__continuation __parse_continuation(__tz::__rules_storage_type& __rules, istream& __input) { + __tz::__continuation __result; + + __result.__rule_database_ = std::addressof(__rules); + + // Note STDOFF is specified as + // This field has the same format as the AT and SAVE fields of rule lines; + // These fields have different suffix letters, these letters seem + // not to be used so do not allow any of them. + + __result.__stdoff = chrono::__parse_duration(__input); + chrono::__skip_mandatory_whitespace(__input); + __result.__rules = chrono::__parse_rules(__input); + chrono::__skip_mandatory_whitespace(__input); + __result.__format = chrono::__parse_string(__input); + chrono::__skip_optional_whitespace(__input); + + if (chrono::__is_eol(__input.peek())) + return __result; + __result.__year = chrono::__parse_year(__input); + chrono::__skip_optional_whitespace(__input); + + if (chrono::__is_eol(__input.peek())) + return __result; + __result.__in = chrono::__parse_month(__input); + chrono::__skip_optional_whitespace(__input); + + if (chrono::__is_eol(__input.peek())) + return __result; + __result.__on = chrono::__parse_on(__input); + chrono::__skip_optional_whitespace(__input); + + if (chrono::__is_eol(__input.peek())) + return __result; + __result.__at = __parse_at(__input); + + return __result; +} + +//===----------------------------------------------------------------------===// +// Time Zone Database entries +//===----------------------------------------------------------------------===// + +static string __parse_version(istream& __input) { + // The first line in tzdata.zi contains + // # version YYYYw + // The parser expects this pattern + // #\s*version\s*\(.*) + // This part is not documented. + chrono::__matches(__input, '#'); + chrono::__skip_optional_whitespace(__input); + chrono::__matches(__input, "version"); + chrono::__skip_mandatory_whitespace(__input); + return chrono::__parse_string(__input); +} + +static void __parse_rule(tzdb& __tzdb, __tz::__rules_storage_type& __rules, istream& __input) { + chrono::__skip_mandatory_whitespace(__input); + string __name = chrono::__parse_string(__input); + + if (__rules.empty() || __rules.back().first != __name) + __rules.emplace_back(__name, vector<__tz::__rule>{}); + + __tz::__rule& __rule = __rules.back().second.emplace_back(); + + chrono::__skip_mandatory_whitespace(__input); + __rule.__from = chrono::__parse_year(__input); + chrono::__skip_mandatory_whitespace(__input); + __rule.__to = chrono::__parse_to(__input, __rule.__from); + chrono::__skip_mandatory_whitespace(__input); + chrono::__matches(__input, '-'); + chrono::__skip_mandatory_whitespace(__input); + __rule.__in = chrono::__parse_month(__input); + chrono::__skip_mandatory_whitespace(__input); + __rule.__on = chrono::__parse_on(__input); + chrono::__skip_mandatory_whitespace(__input); + __rule.__at = __parse_at(__input); + chrono::__skip_mandatory_whitespace(__input); + __rule.__save = __parse_save(__input); + chrono::__skip_mandatory_whitespace(__input); + __rule.__letters = chrono::__parse_letters(__input); + chrono::__skip_line(__input); +} + +static void __parse_zone(tzdb& __tzdb, __tz::__rules_storage_type& __rules, istream& __input) { + chrono::__skip_mandatory_whitespace(__input); + auto __p = std::make_unique<time_zone::__impl>(chrono::__parse_string(__input)); + vector<__tz::__continuation>& __continuations = __p->__continuations(); + chrono::__skip_mandatory_whitespace(__input); + + do { + // The first line must be valid, continuations are optional. + __continuations.emplace_back(__parse_continuation(__rules, __input)); + chrono::__skip_line(__input); + chrono::__skip_optional_whitespace(__input); + } while (std::isdigit(__input.peek()) || __input.peek() == '-'); + + __tzdb.zones.emplace_back(time_zone::__create(std::move(__p))); +} + +static void __parse_link(tzdb& __tzdb, istream& __input) { + chrono::__skip_mandatory_whitespace(__input); + string __target = chrono::__parse_string(__input); + chrono::__skip_mandatory_whitespace(__input); + string __name = chrono::__parse_string(__input); + chrono::__skip_line(__input); + + __tzdb.links.emplace_back(time_zone_link::__constructor_tag{}, std::move(__name), std::move(__target)); +} + +static void __parse_tzdata(tzdb& __db, __tz::__rules_storage_type& __rules, istream& __input) { + while (true) { + int __c = std::tolower(__input.get()); + + switch (__c) { + case istream::traits_type::eof(): + return; + + case ' ': + case '\t': + case '\n': + break; + + case '#': + chrono::__skip_line(__input); + break; + + case 'r': + chrono::__skip(__input, "ule"); + chrono::__parse_rule(__db, __rules, __input); + break; + + case 'z': + chrono::__skip(__input, "one"); + chrono::__parse_zone(__db, __rules, __input); + break; + + case 'l': + chrono::__skip(__input, "ink"); + chrono::__parse_link(__db, __input); + break; + + default: + std::__throw_runtime_error("corrupt tzdb: unexpected input"); + } + } +} + +void __init_tzdb(tzdb& __tzdb, __tz::__rules_storage_type& __rules) { + filesystem::path __root = chrono::__libcpp_tzdb_directory(); + ifstream __tzdata{__root / "tzdata.zi"}; + + __tzdb.version = chrono::__parse_version(__tzdata); + chrono::__parse_tzdata(__tzdb, __rules, __tzdata); + std::ranges::sort(__tzdb.zones); + std::ranges::sort(__tzdb.links); + std::ranges::sort(__rules, {}, [](const auto& p) { return p.first; }); +} + +//===----------------------------------------------------------------------===// +// Public API +//===----------------------------------------------------------------------===// + +_LIBCPP_NODISCARD_EXT _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI tzdb_list& get_tzdb_list() { + static tzdb_list __result{new tzdb_list::__impl()}; + return __result; +} + +_LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI const tzdb& reload_tzdb() { + if (chrono::remote_version() == chrono::get_tzdb().version) + return chrono::get_tzdb(); + + return chrono::get_tzdb_list().__implementation().__load(); +} + +_LIBCPP_NODISCARD_EXT _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI string remote_version() { + filesystem::path __root = chrono::__libcpp_tzdb_directory(); + ifstream __tzdata{__root / "tzdata.zi"}; + return chrono::__parse_version(__tzdata); +} + +} // namespace chrono + +_LIBCPP_END_NAMESPACE_STD diff --git a/contrib/libs/cxxsupp/libcxx/src/tzdb_list.cpp b/contrib/libs/cxxsupp/libcxx/src/tzdb_list.cpp index 7eaaedc6eda..d3ee8b58f98 100644 --- a/contrib/libs/cxxsupp/libcxx/src/tzdb_list.cpp +++ b/contrib/libs/cxxsupp/libcxx/src/tzdb_list.cpp @@ -10,76 +10,12 @@ #include <chrono> -#include <__mutex/unique_lock.h> -#include <forward_list> - -// When threads are not available the locking is not required. -#ifndef _LIBCPP_HAS_NO_THREADS -# include <shared_mutex> -#endif +#include "include/tzdb/tzdb_list_private.h" _LIBCPP_BEGIN_NAMESPACE_STD namespace chrono { -//===----------------------------------------------------------------------===// -// Private API -//===----------------------------------------------------------------------===// - -class tzdb_list::__impl { -public: - explicit __impl(tzdb&& __tzdb) { __tzdb_.push_front(std::move(__tzdb)); } - - using const_iterator = tzdb_list::const_iterator; - - const tzdb& front() const noexcept { -#ifndef _LIBCPP_HAS_NO_THREADS - shared_lock __lock{__mutex_}; -#endif - return __tzdb_.front(); - } - - const_iterator erase_after(const_iterator __p) { -#ifndef _LIBCPP_HAS_NO_THREADS - unique_lock __lock{__mutex_}; -#endif - return __tzdb_.erase_after(__p); - } - - tzdb& __emplace_front(tzdb&& __tzdb) { -#ifndef _LIBCPP_HAS_NO_THREADS - unique_lock __lock{__mutex_}; -#endif - return __tzdb_.emplace_front(std::move(__tzdb)); - } - - const_iterator begin() const noexcept { -#ifndef _LIBCPP_HAS_NO_THREADS - shared_lock __lock{__mutex_}; -#endif - return __tzdb_.begin(); - } - const_iterator end() const noexcept { - // forward_list<T>::end does not access the list, so no need to take a lock. - return __tzdb_.end(); - } - - const_iterator cbegin() const noexcept { return begin(); } - const_iterator cend() const noexcept { return end(); } - -private: -#ifndef _LIBCPP_HAS_NO_THREADS - mutable shared_mutex __mutex_; -#endif - forward_list<tzdb> __tzdb_; -}; - -//===----------------------------------------------------------------------===// -// Public API -//===----------------------------------------------------------------------===// - -_LIBCPP_EXPORTED_FROM_ABI tzdb_list::tzdb_list(tzdb&& __tzdb) : __impl_{new __impl(std::move(__tzdb))} {} - _LIBCPP_EXPORTED_FROM_ABI tzdb_list::~tzdb_list() { delete __impl_; } _LIBCPP_NODISCARD_EXT _LIBCPP_EXPORTED_FROM_ABI const tzdb& tzdb_list::front() const noexcept { @@ -90,10 +26,6 @@ _LIBCPP_EXPORTED_FROM_ABI tzdb_list::const_iterator tzdb_list::erase_after(const return __impl_->erase_after(__p); } -_LIBCPP_EXPORTED_FROM_ABI tzdb& tzdb_list::__emplace_front(tzdb&& __tzdb) { - return __impl_->__emplace_front(std::move(__tzdb)); -} - _LIBCPP_NODISCARD_EXT _LIBCPP_EXPORTED_FROM_ABI tzdb_list::const_iterator tzdb_list::begin() const noexcept { return __impl_->begin(); } |