aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted
diff options
context:
space:
mode:
authorAlexander Smirnov <alex@ydb.tech>2024-10-16 12:11:24 +0000
committerAlexander Smirnov <alex@ydb.tech>2024-10-16 12:11:24 +0000
commit40811e93f3fdf9342a9295369994012420fac548 (patch)
treea8d85e094a9c21e10aa250f537c101fc2016a049 /contrib/restricted
parent30ebe5357bb143648c6be4d151ecd4944af81ada (diff)
parent28a0c4a9f297064538a018c512cd9bbd00a1a35d (diff)
downloadydb-40811e93f3fdf9342a9295369994012420fac548.tar.gz
Merge branch 'rightlib' into mergelibs-241016-1210
Diffstat (limited to 'contrib/restricted')
-rw-r--r--contrib/restricted/boost/filesystem/.yandex_meta/devtools.copyrights.report503
-rw-r--r--contrib/restricted/boost/filesystem/.yandex_meta/devtools.licenses.report179
-rw-r--r--contrib/restricted/boost/filesystem/.yandex_meta/licenses.list.txt175
-rw-r--r--contrib/restricted/boost/filesystem/README.md28
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem.hpp22
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/config.hpp153
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/cstdio.hpp87
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/detail/footer.hpp23
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/detail/header.hpp54
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/detail/path_traits.hpp734
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/detail/type_traits/conjunction.hpp49
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/detail/type_traits/disjunction.hpp49
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/detail/type_traits/negation.hpp49
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/detail/utf8_codecvt_facet.hpp33
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/directory.hpp1039
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/exception.hpp92
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/file_status.hpp252
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/fstream.hpp257
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/operations.hpp724
-rw-r--r--contrib/restricted/boost/filesystem/include/boost/filesystem/path.hpp1710
-rw-r--r--contrib/restricted/boost/filesystem/src/atomic_ref.hpp32
-rw-r--r--contrib/restricted/boost/filesystem/src/atomic_tools.hpp69
-rw-r--r--contrib/restricted/boost/filesystem/src/codecvt_error_category.cpp120
-rw-r--r--contrib/restricted/boost/filesystem/src/directory.cpp1772
-rw-r--r--contrib/restricted/boost/filesystem/src/error_handling.hpp237
-rw-r--r--contrib/restricted/boost/filesystem/src/exception.cpp188
-rw-r--r--contrib/restricted/boost/filesystem/src/operations.cpp5202
-rw-r--r--contrib/restricted/boost/filesystem/src/path.cpp1719
-rw-r--r--contrib/restricted/boost/filesystem/src/path_traits.cpp187
-rw-r--r--contrib/restricted/boost/filesystem/src/platform_config.hpp83
-rw-r--r--contrib/restricted/boost/filesystem/src/portability.cpp83
-rw-r--r--contrib/restricted/boost/filesystem/src/posix_tools.hpp78
-rw-r--r--contrib/restricted/boost/filesystem/src/private_config.hpp74
-rw-r--r--contrib/restricted/boost/filesystem/src/unique_path.cpp351
-rw-r--r--contrib/restricted/boost/filesystem/src/utf8_codecvt_facet.cpp29
-rw-r--r--contrib/restricted/boost/filesystem/src/windows_file_codecvt.cpp72
-rw-r--r--contrib/restricted/boost/filesystem/src/windows_file_codecvt.hpp72
-rw-r--r--contrib/restricted/boost/filesystem/src/windows_tools.hpp310
-rw-r--r--contrib/restricted/boost/filesystem/ya.make68
-rw-r--r--contrib/restricted/boost/scope/.yandex_meta/devtools.copyrights.report91
-rw-r--r--contrib/restricted/boost/scope/.yandex_meta/devtools.licenses.report108
-rw-r--r--contrib/restricted/boost/scope/.yandex_meta/licenses.list.txt48
-rw-r--r--contrib/restricted/boost/scope/LICENSE23
-rw-r--r--contrib/restricted/boost/scope/README.md28
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/defer.hpp180
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/compact_storage.hpp102
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/config.hpp50
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/footer.hpp22
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/header.hpp49
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/is_nonnull_default_constructible.hpp66
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/is_not_like.hpp49
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/move_or_copy_assign_ref.hpp52
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/move_or_copy_construct_ref.hpp52
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/conjunction.hpp53
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/disjunction.hpp53
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_final.hpp53
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_invocable.hpp63
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_nothrow_invocable.hpp69
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_nothrow_swappable.hpp53
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_swappable.hpp53
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/negation.hpp53
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/error_code_checker.hpp103
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/exception_checker.hpp106
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/fd_deleter.hpp82
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/fd_resource_traits.hpp49
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/scope_exit.hpp560
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/scope_fail.hpp265
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/scope_success.hpp309
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/unique_fd.hpp38
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/unique_resource.hpp1642
-rw-r--r--contrib/restricted/boost/scope/include/boost/scope/unique_resource_fwd.hpp46
-rw-r--r--contrib/restricted/boost/scope/ya.make27
-rw-r--r--contrib/restricted/expected-lite/.yandex_meta/devtools.copyrights.report41
-rw-r--r--contrib/restricted/expected-lite/.yandex_meta/devtools.licenses.report79
-rw-r--r--contrib/restricted/expected-lite/.yandex_meta/licenses.list.txt62
-rw-r--r--contrib/restricted/expected-lite/CHANGES.txt5
-rw-r--r--contrib/restricted/expected-lite/LICENSE.txt23
-rw-r--r--contrib/restricted/expected-lite/README.md506
-rw-r--r--contrib/restricted/expected-lite/include/nonstd/expected.hpp3555
-rw-r--r--contrib/restricted/expected-lite/ya.make13
80 files changed, 25839 insertions, 0 deletions
diff --git a/contrib/restricted/boost/filesystem/.yandex_meta/devtools.copyrights.report b/contrib/restricted/boost/filesystem/.yandex_meta/devtools.copyrights.report
new file mode 100644
index 0000000000..9491a2d6aa
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/.yandex_meta/devtools.copyrights.report
@@ -0,0 +1,503 @@
+# File format ($ symbol means the beginning of a line):
+#
+# $ # this message
+# $ # =======================
+# $ # comments (all commentaries should starts with some number of spaces and # symbol)
+# $ IGNORE_FILES {file1.ext1} {file2.ext2} - (optional) ignore listed files when generating license macro and credits
+# $ RENAME {original license id} TO {new license id} # user comments - (optional) use {new license id} instead {original license id} in ya.make files
+# $ # user comments
+# $
+# ${action} {license id} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/1/ya.make ./ya/make/2/ya.make
+# ${all_file_action} filename
+# $ # user commentaries (many lines)
+# $ generated description - files with this license, license text... (some number of lines that starts with some number of spaces, do not modify)
+# ${action} {license spdx} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/3/ya.make
+# ${all_file_action} filename
+# $ # user commentaries
+# $ generated description
+# $ ...
+#
+# You can modify action, all_file_action and add commentaries
+# Available actions:
+# keep - keep license in contrib and use in credits
+# skip - skip license
+# remove - remove all files with this license
+# rename - save license text/links into licenses texts file, but not store SPDX into LINCENSE macro. You should store correct license id into devtools.license.spdx.txt file
+#
+# {all file action} records will be generated when license text contains filename that exists on filesystem (in contrib directory)
+# We suppose that that files can contain some license info
+# Available all file actions:
+# FILE_IGNORE - ignore file (do nothing)
+# FILE_INCLUDE - include all file data into licenses text file
+# =======================
+
+KEEP COPYRIGHT_SERVICE_LABEL 0106e29d815b6be7c9d2d76fe96e71bd
+BELONGS ya.make
+ License text:
+ // Copyright 2002-2009, 2014 Beman Dawes
+ // Copyright 2019 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/error_handling.hpp [3:4]
+
+KEEP COPYRIGHT_SERVICE_LABEL 0577358848238a2ccf175d4150580c55
+BELONGS ya.make
+ License text:
+ // Copyright 2002-2009, 2014 Beman Dawes
+ // Copyright 2001 Dietmar Kuehl
+ // Copyright 2018-2024 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/operations.cpp [3:5]
+
+KEEP COPYRIGHT_SERVICE_LABEL 29b575183bf7715bbbd1ac18a2d411d8
+BELONGS ya.make
+ License text:
+ // Copyright Vladimir Prus 2002
+ // Copyright Beman Dawes 2002-2005, 2009
+ // Copyright Andrey Semashev 2021-2024
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/path.hpp [3:5]
+ src/path.cpp [3:4]
+
+KEEP COPYRIGHT_SERVICE_LABEL 31dab43fa080cbb98017ca60b8536ab0
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2003
+ // Copyright Andrey Semashev 2021-2023
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/config.hpp [3:4]
+ include/boost/filesystem/exception.hpp [3:4]
+ src/exception.cpp [3:4]
+
+KEEP COPYRIGHT_SERVICE_LABEL 40943c7a65585558b5a8a647077af90b
+BELONGS ya.make
+ License text:
+ // Copyright 2009 Beman Dawes
+ // Copyright 2022 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/codecvt_error_category.cpp [3:4]
+
+KEEP COPYRIGHT_SERVICE_LABEL 4654eb52be7c4d34a5204f2702ae51df
+BELONGS ya.make
+ License text:
+ // Copyright 2021-2024 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/posix_tools.hpp [3:3]
+
+KEEP COPYRIGHT_SERVICE_LABEL 4b76d293e7e0b07c0269a1e8929c4f9a
+BELONGS ya.make
+ License text:
+ // Copyright 2002-2005 Beman Dawes
+ // Use, modification, and distribution is subject to the Boost Software
+ // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/portability.cpp [3:5]
+
+KEEP COPYRIGHT_SERVICE_LABEL 4d26b906dcfafbac2938fc9f553e8765
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2008, 2009
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/path_traits.cpp [3:3]
+
+KEEP COPYRIGHT_SERVICE_LABEL 5ca418207a9a9e57884eb84192e8056e
+BELONGS ya.make
+ License text:
+ // Copyright Vladimir Prus 2004.
+ // Distributed under the Boost Software License, Version 1.0.
+ // (See accompanying file LICENSE_1_0.txt
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/utf8_codecvt_facet.cpp [1:3]
+
+KEEP COPYRIGHT_SERVICE_LABEL 5e2789af15a3f0dceb1a6835b257fde9
+BELONGS ya.make
+ License text:
+ // Copyright 2002-2009, 2014 Beman Dawes
+ // Copyright 2001 Dietmar Kuehl
+ // Copyright 2019, 2022-2024 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/directory.cpp [3:5]
+ src/error_handling.hpp [3:4]
+ src/operations.cpp [3:5]
+ src/windows_tools.hpp [3:5]
+
+KEEP COPYRIGHT_SERVICE_LABEL 5ee46bb8f4cfeb03304f0c40f09d31f4
+BELONGS ya.make
+ License text:
+ * Copyright Andrey Semashev 2021.
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/detail/footer.hpp [2:4]
+ include/boost/filesystem/detail/header.hpp [2:4]
+
+KEEP COPYRIGHT_SERVICE_LABEL 5f5f9caa49264cbb4cb51ab4b0070946
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2010
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem.hpp [3:3]
+ src/unique_path.cpp [3:4]
+
+KEEP COPYRIGHT_SERVICE_LABEL 6543e5a77421b1baaaf79a9a214494d8
+BELONGS ya.make
+ License text:
+ // Copyright 2002-2009, 2014 Beman Dawes
+ // Copyright 2001 Dietmar Kuehl
+ // Copyright 2019, 2022-2024 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/directory.cpp [3:5]
+ src/operations.cpp [3:5]
+ src/windows_tools.hpp [3:5]
+
+KEEP COPYRIGHT_SERVICE_LABEL 68dc02374f20324ede6b933ec6332a17
+BELONGS ya.make
+ License text:
+ // Copyright 2001 Dietmar Kuehl
+ // Copyright 2002-2009, 2014 Beman Dawes
+ // Copyright 2021-2022 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/windows_tools.hpp [3:5]
+
+KEEP COPYRIGHT_SERVICE_LABEL 6d59e81fdd72b00433694c8efadc38af
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2002-2009
+ // Copyright Jan Langer 2002
+ // Copyright Dietmar Kuehl 2001
+ // Copyright Vladimir Prus 2002
+ // Copyright Andrey Semashev 2019, 2022
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/directory.hpp [3:7]
+
+KEEP COPYRIGHT_SERVICE_LABEL 7594bc6afcdef4c27932b42df772d631
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2010
+ // Copyright Andrey Semashev 2020, 2024
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/unique_path.cpp [3:4]
+
+KEEP COPYRIGHT_SERVICE_LABEL 75ef7529f27f9a710eea2869f97333f1
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2008
+ // Copyright Andrey Semashev 2021-2024
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/path.cpp [3:4]
+
+KEEP COPYRIGHT_SERVICE_LABEL 791de63e8a85039486e8b095c3912ad1
+BELONGS ya.make
+ License text:
+ // Copyright (c) 2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu)
+ // Andrew Lumsdaine, Indiana University (lums@osl.iu.edu).
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/detail/utf8_codecvt_facet.hpp [1:2]
+
+KEEP COPYRIGHT_SERVICE_LABEL 79847d622a0625e4d77b3b1d999b7ed6
+BELONGS ya.make
+ License text:
+ // Copyright 2021 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/atomic_ref.hpp [3:3]
+ src/atomic_tools.hpp [3:3]
+ src/private_config.hpp [3:3]
+
+KEEP COPYRIGHT_SERVICE_LABEL 7d2ce92b5651d63b72a42d5c7eaed67f
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2003
+ // Copyright Andrey Semashev 2019
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/exception.hpp [3:4]
+ include/boost/filesystem/file_status.hpp [3:7]
+ src/exception.cpp [3:4]
+
+KEEP COPYRIGHT_SERVICE_LABEL 9a830292eb7d7692c5b622def685d36a
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2009
+ // Copyright Andrey Semashev 2022-2024
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/detail/path_traits.hpp [3:4]
+ src/windows_file_codecvt.cpp [3:3]
+ src/windows_file_codecvt.hpp [3:3]
+
+KEEP COPYRIGHT_SERVICE_LABEL 9cc1cbe1db928fd72af9865f2977880e
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2002-2009
+ // Copyright Jan Langer 2002
+ // Copyright Dietmar Kuehl 2001
+ // Copyright Vladimir Prus 2002
+ // Copyright Andrey Semashev 2020-2024
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/operations.hpp [3:7]
+
+KEEP COPYRIGHT_SERVICE_LABEL 9e7998261b95e69bd3775056e00500da
+BELONGS ya.make
+ License text:
+ // Copyright 2009 Beman Dawes
+ // Copyright 2022 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/codecvt_error_category.cpp [3:4]
+
+KEEP COPYRIGHT_SERVICE_LABEL a00ef2913f053c40e19dbb04a67f672d
+BELONGS ya.make
+ License text:
+ // Copyright Vladimir Prus 2002
+ // Copyright Beman Dawes 2002-2005, 2009
+ // Copyright Andrey Semashev 2021-2024
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/path.hpp [3:5]
+
+KEEP COPYRIGHT_SERVICE_LABEL aab0f7927eb905b8b8d0be7082f1129f
+BELONGS ya.make
+ License text:
+ // Copyright Andrey Semashev 2023
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/cstdio.hpp [3:3]
+
+KEEP COPYRIGHT_SERVICE_LABEL bbdecc0b9528cc3e811715c5267e8923
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2003
+ // Copyright Andrey Semashev 2021-2023
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/config.hpp [3:4]
+ include/boost/filesystem/fstream.hpp [3:4]
+
+KEEP COPYRIGHT_SERVICE_LABEL bd5e197c40c289f178ae8b137d43f0a4
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2009
+ // Copyright Andrey Semashev 2022-2024
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/detail/path_traits.hpp [3:4]
+
+KEEP COPYRIGHT_SERVICE_LABEL bdde4763d6a57dbe14d89f4fed53a008
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2002
+ // Copyright Andrey Semashev 2021-2023
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/fstream.hpp [3:4]
+
+KEEP COPYRIGHT_SERVICE_LABEL bdf099522fdb545139e4e9b02eab27e1
+BELONGS ya.make
+ License text:
+ // Copyright 2002-2009, 2014 Beman Dawes
+ // Copyright 2001 Dietmar Kuehl
+ // Copyright 2019, 2022-2024 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/directory.cpp [3:5]
+
+KEEP COPYRIGHT_SERVICE_LABEL cbcc84d7a80f4d8aeabd2a87eca7072c
+BELONGS ya.make
+ License text:
+ // Copyright 2020 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/platform_config.hpp [3:3]
+
+KEEP COPYRIGHT_SERVICE_LABEL cf5e56ae189ec8cdbf6a61c940073563
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2002-2009
+ // Copyright Jan Langer 2002
+ // Copyright Dietmar Kuehl 2001
+ // Copyright Vladimir Prus 2002
+ // Copyright Andrey Semashev 2019, 2022
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/directory.hpp [3:7]
+ include/boost/filesystem/file_status.hpp [3:7]
+ include/boost/filesystem/operations.hpp [3:7]
+ include/boost/filesystem/path.hpp [3:5]
+
+KEEP COPYRIGHT_SERVICE_LABEL de436355f6cfaff01d7ce0d889764ae9
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2002-2009
+ // Copyright Jan Langer 2002
+ // Copyright Dietmar Kuehl 2001
+ // Copyright Vladimir Prus 2002
+ // Copyright Andrey Semashev 2019, 2022
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/directory.hpp [3:7]
+ include/boost/filesystem/file_status.hpp [3:7]
+ include/boost/filesystem/operations.hpp [3:7]
+
+KEEP COPYRIGHT_SERVICE_LABEL e38d04805dcf88e6564ae734a4cd8a49
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2002-2009
+ // Copyright Jan Langer 2002
+ // Copyright Dietmar Kuehl 2001
+ // Copyright Vladimir Prus 2002
+ // Copyright Andrey Semashev 2019, 2022
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/directory.hpp [3:7]
+ include/boost/filesystem/file_status.hpp [3:7]
+ include/boost/filesystem/operations.hpp [3:7]
+
+KEEP COPYRIGHT_SERVICE_LABEL eb3a0ca480ae49d67ca93db4d779aa0f
+BELONGS ya.make
+ License text:
+ * Copyright (c) 2024 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/detail/type_traits/conjunction.hpp [6:6]
+ include/boost/filesystem/detail/type_traits/disjunction.hpp [6:6]
+ include/boost/filesystem/detail/type_traits/negation.hpp [6:6]
+
+KEEP COPYRIGHT_SERVICE_LABEL f47d692aff1724cf5d6cfdcc998f6b84
+BELONGS ya.make
+ License text:
+ // Copyright Beman Dawes 2002-2009
+ // Copyright Jan Langer 2002
+ // Copyright Dietmar Kuehl 2001
+ // Copyright Vladimir Prus 2002
+ // Copyright Andrey Semashev 2019, 2022
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/filesystem/directory.hpp [3:7]
+ include/boost/filesystem/file_status.hpp [3:7]
+ include/boost/filesystem/operations.hpp [3:7]
diff --git a/contrib/restricted/boost/filesystem/.yandex_meta/devtools.licenses.report b/contrib/restricted/boost/filesystem/.yandex_meta/devtools.licenses.report
new file mode 100644
index 0000000000..d0ef27a0ba
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/.yandex_meta/devtools.licenses.report
@@ -0,0 +1,179 @@
+# File format ($ symbol means the beginning of a line):
+#
+# $ # this message
+# $ # =======================
+# $ # comments (all commentaries should starts with some number of spaces and # symbol)
+# $ IGNORE_FILES {file1.ext1} {file2.ext2} - (optional) ignore listed files when generating license macro and credits
+# $ RENAME {original license id} TO {new license id} # user comments - (optional) use {new license id} instead {original license id} in ya.make files
+# $ # user comments
+# $
+# ${action} {license id} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/1/ya.make ./ya/make/2/ya.make
+# ${all_file_action} filename
+# $ # user commentaries (many lines)
+# $ generated description - files with this license, license text... (some number of lines that starts with some number of spaces, do not modify)
+# ${action} {license spdx} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/3/ya.make
+# ${all_file_action} filename
+# $ # user commentaries
+# $ generated description
+# $ ...
+#
+# You can modify action, all_file_action and add commentaries
+# Available actions:
+# keep - keep license in contrib and use in credits
+# skip - skip license
+# remove - remove all files with this license
+# rename - save license text/links into licenses texts file, but not store SPDX into LINCENSE macro. You should store correct license id into devtools.license.spdx.txt file
+#
+# {all file action} records will be generated when license text contains filename that exists on filesystem (in contrib directory)
+# We suppose that that files can contain some license info
+# Available all file actions:
+# FILE_IGNORE - ignore file (do nothing)
+# FILE_INCLUDE - include all file data into licenses text file
+# =======================
+
+KEEP BSL-1.0 1e1b35c3ae13c65f63b2c7467cce8a87
+BELONGS ya.make
+ License text:
+ // Distributed under the Boost Software License, Version 1.0.
+ // (See accompanying file LICENSE_1_0.txt
+ // or copy at http://www.boost.org/LICENSE_1_0.txt)
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 100.00
+ Match type : NOTICE
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ src/utf8_codecvt_facet.cpp [2:4]
+
+KEEP BSL-1.0 2077ca9d01c7e6d6029ec1763233c5b0
+BELONGS ya.make
+ License text:
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 100.00
+ Match type : NOTICE
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ include/boost/filesystem/detail/type_traits/conjunction.hpp [2:4]
+ include/boost/filesystem/detail/type_traits/disjunction.hpp [2:4]
+ include/boost/filesystem/detail/type_traits/negation.hpp [2:4]
+
+KEEP BSL-1.0 49af97cadb10453f2b05003f793e4adc
+BELONGS ya.make
+ License text:
+ Distributed under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt).
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 88.89
+ Match type : NOTICE
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ README.md [28:28]
+
+KEEP BSL-1.0 67c315f84c9f7fe64ea5034b22a3514e
+BELONGS ya.make
+ License text:
+ // Distributed under the Boost Software License, Version 1.0.
+ // See http://www.boost.org/LICENSE_1_0.txt)
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 100.00
+ Match type : NOTICE
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ src/codecvt_error_category.cpp [6:7]
+
+KEEP BSL-1.0 a5006bb276a0e8fcc0c080cd5a14814e
+BELONGS ya.make
+ Note: matched license text is too long. Read it in the source files.
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 55.00
+ Match type : NOTICE
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ README.md [17:17]
+
+KEEP BSL-1.0 a779859d4b2e8896d4ed9ba8f600ca99
+BELONGS ya.make
+ License text:
+ // Distributed under the Boost Software License, Version 1.0.
+ // (See http://www.boost.org/LICENSE_1_0.txt)
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 100.00
+ Match type : NOTICE
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ include/boost/filesystem/detail/utf8_codecvt_facet.hpp [4:5]
+
+KEEP BSL-1.0 bb6c4a594a57e74611676fda9449a7e3
+BELONGS ya.make
+ License text:
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 100.00
+ Match type : NOTICE
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ include/boost/filesystem/detail/footer.hpp [3:5]
+ include/boost/filesystem/detail/header.hpp [3:5]
+
+KEEP BSL-1.0 da2a87ccf5ae416e33c8d6bfe78baa14
+BELONGS ya.make
+ License text:
+ // Distributed under the Boost Software License, Version 1.0.
+ // See http://www.boost.org/LICENSE_1_0.txt
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 100.00
+ Match type : NOTICE
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ include/boost/filesystem.hpp [5:6]
+ include/boost/filesystem/config.hpp [6:7]
+ include/boost/filesystem/cstdio.hpp [5:6]
+ include/boost/filesystem/detail/path_traits.hpp [6:7]
+ include/boost/filesystem/directory.hpp [9:10]
+ include/boost/filesystem/exception.hpp [6:7]
+ include/boost/filesystem/file_status.hpp [9:10]
+ include/boost/filesystem/fstream.hpp [6:7]
+ include/boost/filesystem/operations.hpp [9:10]
+ include/boost/filesystem/path.hpp [7:8]
+ src/atomic_ref.hpp [5:6]
+ src/atomic_tools.hpp [5:6]
+ src/directory.cpp [7:8]
+ src/error_handling.hpp [6:7]
+ src/exception.cpp [6:7]
+ src/operations.cpp [7:8]
+ src/path.cpp [6:7]
+ src/path_traits.cpp [5:6]
+ src/platform_config.hpp [5:6]
+ src/posix_tools.hpp [5:6]
+ src/private_config.hpp [5:6]
+ src/unique_path.cpp [6:7]
+ src/windows_file_codecvt.cpp [5:6]
+ src/windows_file_codecvt.hpp [5:6]
+ src/windows_tools.hpp [7:8]
+
+KEEP BSL-1.0 f0421be5a87b237d5f722433355f7a9e
+BELONGS ya.make
+ License text:
+ // Use, modification, and distribution is subject to the Boost Software
+ // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
+ // at http://www.boost.org/LICENSE_1_0.txt)
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 96.88
+ Match type : NOTICE
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ src/portability.cpp [4:6]
diff --git a/contrib/restricted/boost/filesystem/.yandex_meta/licenses.list.txt b/contrib/restricted/boost/filesystem/.yandex_meta/licenses.list.txt
new file mode 100644
index 0000000000..7437319473
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/.yandex_meta/licenses.list.txt
@@ -0,0 +1,175 @@
+====================BSL-1.0====================
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+
+
+====================BSL-1.0====================
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+
+
+====================BSL-1.0====================
+* Submit your patches as [pull requests](https://github.com/boostorg/filesystem/compare) against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt).
+
+
+====================BSL-1.0====================
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+
+====================BSL-1.0====================
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt)
+
+
+====================BSL-1.0====================
+// Use, modification, and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
+// at http://www.boost.org/LICENSE_1_0.txt)
+
+
+====================BSL-1.0====================
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt
+// or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+
+====================BSL-1.0====================
+// Distributed under the Boost Software License, Version 1.0.
+// (See http://www.boost.org/LICENSE_1_0.txt)
+
+
+====================BSL-1.0====================
+Distributed under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt).
+
+====================COPYRIGHT====================
+ * Copyright Andrey Semashev 2021.
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+
+
+====================COPYRIGHT====================
+ * Copyright (c) 2024 Andrey Semashev
+
+
+====================COPYRIGHT====================
+// Copyright 2001 Dietmar Kuehl
+// Copyright 2002-2009, 2014 Beman Dawes
+// Copyright 2021-2022 Andrey Semashev
+
+
+====================COPYRIGHT====================
+// Copyright 2002-2005 Beman Dawes
+// Use, modification, and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
+
+
+====================COPYRIGHT====================
+// Copyright 2002-2009, 2014 Beman Dawes
+// Copyright 2001 Dietmar Kuehl
+// Copyright 2018-2024 Andrey Semashev
+
+
+====================COPYRIGHT====================
+// Copyright 2002-2009, 2014 Beman Dawes
+// Copyright 2001 Dietmar Kuehl
+// Copyright 2019, 2022-2024 Andrey Semashev
+
+
+====================COPYRIGHT====================
+// Copyright 2002-2009, 2014 Beman Dawes
+// Copyright 2019 Andrey Semashev
+
+
+====================COPYRIGHT====================
+// Copyright 2009 Beman Dawes
+// Copyright 2022 Andrey Semashev
+
+
+====================COPYRIGHT====================
+// Copyright 2020 Andrey Semashev
+
+
+====================COPYRIGHT====================
+// Copyright 2021 Andrey Semashev
+
+
+====================COPYRIGHT====================
+// Copyright 2021-2024 Andrey Semashev
+
+
+====================COPYRIGHT====================
+// Copyright Andrey Semashev 2023
+
+
+====================COPYRIGHT====================
+// Copyright Beman Dawes 2002
+// Copyright Andrey Semashev 2021-2023
+
+
+====================COPYRIGHT====================
+// Copyright Beman Dawes 2002-2009
+// Copyright Jan Langer 2002
+// Copyright Dietmar Kuehl 2001
+// Copyright Vladimir Prus 2002
+// Copyright Andrey Semashev 2019, 2022
+
+
+====================COPYRIGHT====================
+// Copyright Beman Dawes 2002-2009
+// Copyright Jan Langer 2002
+// Copyright Dietmar Kuehl 2001
+// Copyright Vladimir Prus 2002
+// Copyright Andrey Semashev 2020-2024
+
+
+====================COPYRIGHT====================
+// Copyright Beman Dawes 2003
+// Copyright Andrey Semashev 2019
+
+
+====================COPYRIGHT====================
+// Copyright Beman Dawes 2003
+// Copyright Andrey Semashev 2021-2023
+
+
+====================COPYRIGHT====================
+// Copyright Beman Dawes 2008
+// Copyright Andrey Semashev 2021-2024
+
+
+====================COPYRIGHT====================
+// Copyright Beman Dawes 2008, 2009
+
+
+====================COPYRIGHT====================
+// Copyright Beman Dawes 2009
+// Copyright Andrey Semashev 2022-2024
+
+
+====================COPYRIGHT====================
+// Copyright Beman Dawes 2010
+
+
+====================COPYRIGHT====================
+// Copyright Beman Dawes 2010
+// Copyright Andrey Semashev 2020, 2024
+
+
+====================COPYRIGHT====================
+// Copyright Vladimir Prus 2002
+// Copyright Beman Dawes 2002-2005, 2009
+// Copyright Andrey Semashev 2021-2024
+
+
+====================COPYRIGHT====================
+// Copyright (c) 2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu)
+// Andrew Lumsdaine, Indiana University (lums@osl.iu.edu).
+
+
+====================COPYRIGHT====================
+// Copyright Vladimir Prus 2004.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt
diff --git a/contrib/restricted/boost/filesystem/README.md b/contrib/restricted/boost/filesystem/README.md
new file mode 100644
index 0000000000..9af3f0140d
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/README.md
@@ -0,0 +1,28 @@
+# Boost.Filesystem
+
+Boost.Filesystem, part of collection of the [Boost C++ Libraries](https://github.com/boostorg), provides facilities to manipulate files and directories, and the paths that identify them.
+
+### Directories
+
+* **doc** - Documentation sources
+* **include** - Interface headers of Boost.Filesystem
+* **src** - Compilable source files of Boost.Filesystem
+* **test** - Boost.Filesystem unit tests
+* **example** - Boost.Filesystem usage examples
+
+### More information
+
+* [Documentation](https://boost.org/libs/filesystem)
+* [Report bugs](https://github.com/boostorg/filesystem/issues/new). Be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well.
+* Submit your patches as [pull requests](https://github.com/boostorg/filesystem/compare) against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt).
+
+### Build status
+
+Branch | GitHub Actions | AppVeyor | Test Matrix | Dependencies |
+:-------------: | -------------- | -------- | ----------- | ------------ |
+[`master`](https://github.com/boostorg/filesystem/tree/master) | [![GitHub Actions](https://github.com/boostorg/filesystem/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/filesystem/actions?query=branch%3Amaster) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/nx3e7bcavvn3q953/branch/master?svg=true)](https://ci.appveyor.com/project/Lastique/filesystem/branch/master) | [![Tests](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/filesystem.html) | [![Dependencies](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/filesystem.html)
+[`develop`](https://github.com/boostorg/filesystem/tree/develop) | [![GitHub Actions](https://github.com/boostorg/filesystem/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/filesystem/actions?query=branch%3Adevelop) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/nx3e7bcavvn3q953/branch/develop?svg=true)](https://ci.appveyor.com/project/Lastique/filesystem/branch/develop) | [![Tests](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/filesystem.html) | [![Dependencies](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/filesystem.html)
+
+### License
+
+Distributed under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt).
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem.hpp
new file mode 100644
index 0000000000..ee22fbcac2
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem.hpp
@@ -0,0 +1,22 @@
+// boost/filesystem.hpp --------------------------------------------------------------//
+
+// Copyright Beman Dawes 2010
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#ifndef BOOST_FILESYSTEM_FILESYSTEM_HPP
+#define BOOST_FILESYSTEM_FILESYSTEM_HPP
+
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/exception.hpp>
+#include <boost/filesystem/directory.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/file_status.hpp>
+
+#endif // BOOST_FILESYSTEM_FILESYSTEM_HPP
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/config.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/config.hpp
new file mode 100644
index 0000000000..795a0fe2c2
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/config.hpp
@@ -0,0 +1,153 @@
+// boost/filesystem/v3/config.hpp ----------------------------------------------------//
+
+// Copyright Beman Dawes 2003
+// Copyright Andrey Semashev 2021-2023
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#ifndef BOOST_FILESYSTEM_CONFIG_HPP
+#define BOOST_FILESYSTEM_CONFIG_HPP
+
+// This header implements separate compilation features as described in
+// http://www.boost.org/more/separate_compilation.html
+
+#include <boost/config.hpp>
+#include <boost/system/api_config.hpp> // for BOOST_POSIX_API or BOOST_WINDOWS_API
+#include <boost/detail/workaround.hpp>
+
+#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION != 3 && BOOST_FILESYSTEM_VERSION != 4
+#error Compiling Boost.Filesystem file with BOOST_FILESYSTEM_VERSION defined != 3 or 4
+#endif
+
+#if defined(BOOST_FILESYSTEM_SOURCE)
+#undef BOOST_FILESYSTEM_VERSION
+#define BOOST_FILESYSTEM_VERSION 4
+#elif !defined(BOOST_FILESYSTEM_VERSION)
+#define BOOST_FILESYSTEM_VERSION 3
+#endif
+
+#define BOOST_FILESYSTEM_VERSIONED_SYM(sym) BOOST_JOIN(sym, BOOST_JOIN(_v, BOOST_FILESYSTEM_VERSION))
+#define BOOST_FILESYSTEM_VERSION_NAMESPACE BOOST_JOIN(v, BOOST_FILESYSTEM_VERSION)
+
+#if BOOST_FILESYSTEM_VERSION == 4
+#undef BOOST_FILESYSTEM_DEPRECATED
+#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED)
+#define BOOST_FILESYSTEM_NO_DEPRECATED
+#endif
+#endif
+
+#define BOOST_FILESYSTEM_I18N // aid users wishing to compile several versions
+
+// BOOST_FILESYSTEM_DEPRECATED needed for source compiles -----------------------------//
+
+#ifdef BOOST_FILESYSTEM_SOURCE
+#define BOOST_FILESYSTEM_DEPRECATED
+#undef BOOST_FILESYSTEM_NO_DEPRECATED // fixes #9454, src bld fails if NO_DEP defined
+#endif
+
+#if defined(BOOST_FILESYSTEM_DEPRECATED) && defined(BOOST_FILESYSTEM_NO_DEPRECATED)
+#error Both BOOST_FILESYSTEM_DEPRECATED and BOOST_FILESYSTEM_NO_DEPRECATED are defined
+#endif
+
+// throw an exception ----------------------------------------------------------------//
+//
+// Exceptions were originally thrown via boost::throw_exception().
+// As throw_exception() became more complex, it caused user error reporting
+// to be harder to interpret, since the exception reported became much more complex.
+// The immediate fix was to throw directly, wrapped in a macro to make any later change
+// easier.
+
+#define BOOST_FILESYSTEM_THROW(EX) throw EX
+
+#if defined(BOOST_NO_STD_WSTRING)
+#error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support
+#endif
+
+// Deprecated symbols markup -----------------------------------------------------------//
+
+#if !defined(BOOST_FILESYSTEM_ALLOW_DEPRECATED)
+#define BOOST_FILESYSTEM_DETAIL_DEPRECATED(msg) BOOST_DEPRECATED(msg)
+#else
+#define BOOST_FILESYSTEM_DETAIL_DEPRECATED(msg)
+#endif
+
+
+// This header implements separate compilation features as described in
+// http://www.boost.org/more/separate_compilation.html
+
+// normalize macros ------------------------------------------------------------------//
+
+#if !defined(BOOST_FILESYSTEM_DYN_LINK) && !defined(BOOST_FILESYSTEM_STATIC_LINK) && !defined(BOOST_ALL_DYN_LINK) && !defined(BOOST_ALL_STATIC_LINK)
+#define BOOST_FILESYSTEM_STATIC_LINK
+#endif
+
+#if defined(BOOST_ALL_DYN_LINK) && !defined(BOOST_FILESYSTEM_DYN_LINK)
+#define BOOST_FILESYSTEM_DYN_LINK
+#elif defined(BOOST_ALL_STATIC_LINK) && !defined(BOOST_FILESYSTEM_STATIC_LINK)
+#define BOOST_FILESYSTEM_STATIC_LINK
+#endif
+
+#if defined(BOOST_FILESYSTEM_DYN_LINK) && defined(BOOST_FILESYSTEM_STATIC_LINK)
+#error Must not define both BOOST_FILESYSTEM_DYN_LINK and BOOST_FILESYSTEM_STATIC_LINK
+#endif
+
+#if defined(BOOST_ALL_NO_LIB) && !defined(BOOST_FILESYSTEM_NO_LIB)
+#define BOOST_FILESYSTEM_NO_LIB
+#endif
+
+// enable dynamic linking ------------------------------------------------------------//
+
+#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_FILESYSTEM_DYN_LINK)
+#if defined(BOOST_FILESYSTEM_SOURCE)
+#define BOOST_FILESYSTEM_DECL BOOST_SYMBOL_EXPORT
+#else
+#define BOOST_FILESYSTEM_DECL BOOST_SYMBOL_IMPORT
+#endif
+#else
+#define BOOST_FILESYSTEM_DECL
+#endif
+
+// enable automatic library variant selection ----------------------------------------//
+
+#if !defined(BOOST_FILESYSTEM_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_FILESYSTEM_NO_LIB)
+//
+// Set the name of our library, this will get undef'ed by auto_link.hpp
+// once it's done with it:
+//
+#define BOOST_LIB_NAME boost_filesystem
+//
+// If we're importing code from a dll, then tell auto_link.hpp about it:
+//
+#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_FILESYSTEM_DYN_LINK)
+#define BOOST_DYN_LINK
+#endif
+//
+// And include the header that does the work:
+//
+#include <boost/config/auto_link.hpp>
+#endif // auto-linking disabled
+
+#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) ||\
+ (defined(BOOST_LIBSTDCXX_VERSION) && (BOOST_LIBSTDCXX_VERSION < 50000)) ||\
+ (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION < 100))
+// Indicates that the standard library fstream types do not support move constructor/assignment.
+#define BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS
+#endif
+
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) && \
+ (\
+ (defined(BOOST_DINKUMWARE_STDLIB) && defined(_HAS_CXX23) && (_HAS_CXX23 != 0) && defined(_MSVC_STL_UPDATE) && (_MSVC_STL_UPDATE < 202208L)) || \
+ (defined(BOOST_LIBSTDCXX_VERSION) && (BOOST_LIBSTDCXX_VERSION < 110400 || (BOOST_LIBSTDCXX_VERSION >= 120000 && BOOST_LIBSTDCXX_VERSION < 120200)) && (BOOST_CXX_VERSION > 202002L))\
+ )
+// Indicates that std::string_view has implicit constructor from ranges that was present in an early C++23 draft (N4892).
+// This was later rectified by marking the constructor explicit (https://wg21.link/p2499). Unfortunately, some compilers
+// were released with the constructor being implicit.
+#define BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR
+#endif
+
+#endif // BOOST_FILESYSTEM_CONFIG_HPP
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/cstdio.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/cstdio.hpp
new file mode 100644
index 0000000000..b09e89f002
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/cstdio.hpp
@@ -0,0 +1,87 @@
+// boost/filesystem/cstdio.hpp ------------------------------------------------------//
+
+// Copyright Andrey Semashev 2023
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#ifndef BOOST_FILESYSTEM_CSTDIO_HPP
+#define BOOST_FILESYSTEM_CSTDIO_HPP
+
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/path.hpp>
+#include <cstdio>
+#if defined(BOOST_WINDOWS_API)
+#include <wchar.h>
+#include <cstddef>
+#include <cstring>
+#include <cstdlib>
+#endif
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace boost {
+namespace filesystem {
+
+#if defined(BOOST_WINDOWS_API)
+
+inline std::FILE* fopen(filesystem::path const& p, const char* mode)
+{
+#if defined(__CYGWIN__) || (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) && defined(__STRICT_ANSI__))
+ // Cygwin and MinGW32 in strict ANSI mode do not declare _wfopen
+ return std::fopen(p.string().c_str(), mode);
+#else
+ // mode should only contain ASCII characters and is likely short
+ struct small_array
+ {
+ wchar_t buf[128u];
+ wchar_t* p;
+
+ small_array() noexcept : p(buf) {}
+ ~small_array() noexcept
+ {
+ if (BOOST_UNLIKELY(p != buf))
+ std::free(p);
+ }
+ }
+ wmode;
+ std::size_t wmode_len = std::mbstowcs(wmode.p, mode, sizeof(wmode.buf) / sizeof(wchar_t));
+ if (BOOST_UNLIKELY(wmode_len >= (sizeof(wmode.buf) / sizeof(wchar_t))))
+ {
+ wmode_len = std::mbstowcs(nullptr, mode, 0u);
+ // Check for size overflow, including (size_t)-1, which indicates mbstowcs error
+ if (BOOST_UNLIKELY(wmode_len >= (static_cast< std::size_t >(-1) / sizeof(wchar_t))))
+ return nullptr;
+
+ wmode.p = static_cast< wchar_t* >(std::malloc((wmode_len + 1u) * sizeof(wchar_t)));
+ if (BOOST_UNLIKELY(!wmode.p))
+ return nullptr;
+
+ std::size_t wmode_len2 = std::mbstowcs(wmode.p, mode, wmode_len + 1u);
+ if (BOOST_UNLIKELY(wmode_len2 > wmode_len))
+ return nullptr;
+ }
+
+ return ::_wfopen(p.c_str(), wmode.p);
+#endif
+}
+
+#else // defined(BOOST_WINDOWS_API)
+
+inline std::FILE* fopen(filesystem::path const& p, const char* mode)
+{
+ return std::fopen(p.c_str(), mode);
+}
+
+#endif // defined(BOOST_WINDOWS_API)
+
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
+
+#endif // BOOST_FILESYSTEM_CSTDIO_HPP
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/footer.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/footer.hpp
new file mode 100644
index 0000000000..ce4bc1feed
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/footer.hpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright Andrey Semashev 2021.
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+#if !defined(BOOST_FILESYSTEM_ENABLE_WARNINGS)
+
+#if defined(_MSC_VER) && !defined(__clang__)
+
+#pragma warning(pop)
+
+#elif (defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \
+ && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406) || defined(__clang__)
+
+#pragma GCC diagnostic pop
+
+#endif
+
+#endif // !defined(BOOST_FILESYSTEM_ENABLE_WARNINGS)
+
+#include <boost/config/abi_suffix.hpp>
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/header.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/header.hpp
new file mode 100644
index 0000000000..f98b0aba95
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/header.hpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright Andrey Semashev 2021.
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+#include <boost/config/abi_prefix.hpp>
+
+#if !defined(BOOST_FILESYSTEM_ENABLE_WARNINGS)
+
+#if defined(_MSC_VER) && !defined(__clang__)
+
+#pragma warning(push, 3)
+// 'm_A' : class 'A' needs to have dll-interface to be used by clients of class 'B'
+#pragma warning(disable: 4251)
+// non dll-interface class 'A' used as base for dll-interface class 'B'
+#pragma warning(disable: 4275)
+// 'int' : forcing value to bool 'true' or 'false' (performance warning)
+#pragma warning(disable: 4800)
+// unreferenced formal parameter
+#pragma warning(disable: 4100)
+// conditional expression is constant
+#pragma warning(disable: 4127)
+// function marked as __forceinline not inlined
+#pragma warning(disable: 4714)
+// decorated name length exceeded, name was truncated
+#pragma warning(disable: 4503)
+// 'X': This function or variable may be unsafe. Consider using Y instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
+#pragma warning(disable: 4996)
+// qualifier applied to function type has no meaning; ignored
+#pragma warning(disable: 4180)
+// qualifier applied to reference type; ignored
+#pragma warning(disable: 4181)
+
+#elif (defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \
+ && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406) || defined(__clang__)
+
+// Note: clang-cl goes here as well, as it seems to support gcc-style warning control pragmas.
+
+#pragma GCC diagnostic push
+// unused parameter 'arg'
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+// unused function 'foo'
+#pragma GCC diagnostic ignored "-Wunused-function"
+
+#if defined(__clang__)
+// template argument uses unnamed type
+#pragma clang diagnostic ignored "-Wunnamed-type-template-args"
+#endif // defined(__clang__)
+
+#endif
+
+#endif // !defined(BOOST_FILESYSTEM_ENABLE_WARNINGS)
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/path_traits.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/path_traits.hpp
new file mode 100644
index 0000000000..416c073788
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/path_traits.hpp
@@ -0,0 +1,734 @@
+// filesystem path_traits.hpp --------------------------------------------------------//
+
+// Copyright Beman Dawes 2009
+// Copyright Andrey Semashev 2022-2024
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+#ifndef BOOST_FILESYSTEM_DETAIL_PATH_TRAITS_HPP
+#define BOOST_FILESYSTEM_DETAIL_PATH_TRAITS_HPP
+
+#include <boost/filesystem/config.hpp>
+#include <cstddef>
+#include <cstring> // for strlen
+#include <cwchar> // for mbstate_t, wcslen
+#include <locale>
+#include <string>
+#include <iterator>
+#include <type_traits>
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+#include <string_view>
+#endif
+#include <boost/assert.hpp>
+#include <boost/system/error_category.hpp>
+#include <boost/iterator/is_iterator.hpp>
+#include <boost/filesystem/detail/type_traits/conjunction.hpp>
+#if defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR)
+#include <boost/filesystem/detail/type_traits/disjunction.hpp>
+#endif
+#if defined(BOOST_FILESYSTEM_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4
+#include <vector>
+#include <list>
+#endif
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace boost {
+
+template< typename, typename > class basic_string_view;
+
+namespace container {
+template< typename, typename, typename > class basic_string;
+} // namespace container
+
+namespace filesystem {
+
+BOOST_FILESYSTEM_DECL system::error_category const& codecvt_error_category() noexcept;
+
+class directory_entry;
+
+namespace detail {
+namespace path_traits {
+
+#if defined(BOOST_WINDOWS_API)
+typedef wchar_t path_native_char_type;
+#define BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE false
+#define BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE true
+#else
+typedef char path_native_char_type;
+#define BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE true
+#define BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE false
+#endif
+
+typedef std::codecvt< wchar_t, char, std::mbstate_t > codecvt_type;
+
+struct unknown_type_tag {};
+struct ntcts_type_tag {};
+struct char_ptr_tag : ntcts_type_tag {};
+struct char_array_tag : ntcts_type_tag {};
+struct string_class_tag {};
+struct std_string_tag : string_class_tag {};
+struct boost_container_string_tag : string_class_tag {};
+struct std_string_view_tag : string_class_tag {};
+struct boost_string_view_tag : string_class_tag {};
+struct range_type_tag {};
+struct directory_entry_tag {};
+
+//! The traits define a number of properties of a path source
+template< typename T >
+struct path_source_traits
+{
+ //! The kind of the path source. Useful for dispatching.
+ typedef unknown_type_tag tag_type;
+ //! Character type that the source contains
+ typedef void char_type;
+ //! Indicates whether the source is natively supported by \c path::string_type as arguments for constructors/assignment/appending
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = false;
+};
+
+template< >
+struct path_source_traits< char* >
+{
+ typedef char_ptr_tag tag_type;
+ typedef char char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE;
+};
+
+template< >
+struct path_source_traits< const char* >
+{
+ typedef char_ptr_tag tag_type;
+ typedef char char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE;
+};
+
+template< >
+struct path_source_traits< wchar_t* >
+{
+ typedef char_ptr_tag tag_type;
+ typedef wchar_t char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE;
+};
+
+template< >
+struct path_source_traits< const wchar_t* >
+{
+ typedef char_ptr_tag tag_type;
+ typedef wchar_t char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE;
+};
+
+template< >
+struct path_source_traits< char[] >
+{
+ typedef char_array_tag tag_type;
+ typedef char char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE;
+};
+
+template< >
+struct path_source_traits< const char[] >
+{
+ typedef char_array_tag tag_type;
+ typedef char char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE;
+};
+
+template< >
+struct path_source_traits< wchar_t[] >
+{
+ typedef char_array_tag tag_type;
+ typedef wchar_t char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE;
+};
+
+template< >
+struct path_source_traits< const wchar_t[] >
+{
+ typedef char_array_tag tag_type;
+ typedef wchar_t char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE;
+};
+
+template< std::size_t N >
+struct path_source_traits< char[N] >
+{
+ typedef char_array_tag tag_type;
+ typedef char char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE;
+};
+
+template< std::size_t N >
+struct path_source_traits< const char[N] >
+{
+ typedef char_array_tag tag_type;
+ typedef char char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE;
+};
+
+template< std::size_t N >
+struct path_source_traits< wchar_t[N] >
+{
+ typedef char_array_tag tag_type;
+ typedef wchar_t char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE;
+};
+
+template< std::size_t N >
+struct path_source_traits< const wchar_t[N] >
+{
+ typedef char_array_tag tag_type;
+ typedef wchar_t char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE;
+};
+
+template< >
+struct path_source_traits< std::string >
+{
+ typedef std_string_tag tag_type;
+ typedef char char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE;
+};
+
+template< >
+struct path_source_traits< std::wstring >
+{
+ typedef std_string_tag tag_type;
+ typedef wchar_t char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE;
+};
+
+template< >
+struct path_source_traits< boost::container::basic_string< char, std::char_traits< char >, void > >
+{
+ typedef boost_container_string_tag tag_type;
+ typedef char char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = false;
+};
+
+template< >
+struct path_source_traits< boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void > >
+{
+ typedef boost_container_string_tag tag_type;
+ typedef wchar_t char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = false;
+};
+
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+
+template< >
+struct path_source_traits< std::string_view >
+{
+ typedef std_string_view_tag tag_type;
+ typedef char char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE;
+};
+
+template< >
+struct path_source_traits< std::wstring_view >
+{
+ typedef std_string_view_tag tag_type;
+ typedef wchar_t char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE;
+};
+
+#endif // !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+
+template< >
+struct path_source_traits< boost::basic_string_view< char, std::char_traits< char > > >
+{
+ typedef boost_string_view_tag tag_type;
+ typedef char char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = false;
+};
+
+template< >
+struct path_source_traits< boost::basic_string_view< wchar_t, std::char_traits< wchar_t > > >
+{
+ typedef boost_string_view_tag tag_type;
+ typedef wchar_t char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = false;
+};
+
+#if defined(BOOST_FILESYSTEM_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4
+template< >
+struct
+BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignment/appending from containers is deprecated, use strings or iterators instead.")
+path_source_traits< std::vector< char > >
+{
+ // Since C++11 this could be string_class_tag as std::vector gained data() member
+ typedef range_type_tag tag_type;
+ typedef char char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = false;
+};
+
+template< >
+struct
+BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignment/appending from containers is deprecated, use strings or iterators instead.")
+path_source_traits< std::vector< wchar_t > >
+{
+ // Since C++11 this could be string_class_tag as std::vector gained data() member
+ typedef range_type_tag tag_type;
+ typedef wchar_t char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = false;
+};
+
+template< >
+struct
+BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignment/appending from containers is deprecated, use strings or iterators instead.")
+path_source_traits< std::list< char > >
+{
+ typedef range_type_tag tag_type;
+ typedef char char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = false;
+};
+
+template< >
+struct
+BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignment/appending from containers is deprecated, use strings or iterators instead.")
+path_source_traits< std::list< wchar_t > >
+{
+ typedef range_type_tag tag_type;
+ typedef wchar_t char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = false;
+};
+#endif // defined(BOOST_FILESYSTEM_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4
+
+template< >
+struct path_source_traits< directory_entry >
+{
+ typedef directory_entry_tag tag_type;
+ typedef path_native_char_type char_type;
+ static BOOST_CONSTEXPR_OR_CONST bool is_native = false;
+};
+
+#undef BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE
+#undef BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE
+
+
+//! The trait tests if the type is a known path Source tag
+template< typename Tag >
+struct is_known_path_source_tag :
+ public std::true_type
+{
+};
+
+template< >
+struct is_known_path_source_tag< unknown_type_tag > :
+ public std::false_type
+{
+};
+
+//! The trait tests if the type is compatible with path Source requirements
+template< typename T >
+struct is_path_source :
+ public is_known_path_source_tag< typename path_source_traits< T >::tag_type >::type
+{
+};
+
+
+//! The trait indicates whether the type is a path Source that is natively supported by path::string_type as the source for construction/assignment/appending
+template< typename T >
+struct is_native_path_source :
+ public std::integral_constant< bool, path_source_traits< T >::is_native >
+{
+};
+
+
+//! The trait indicates whether the type is one of the supported path character types
+template< typename T >
+struct is_path_char_type :
+ public std::false_type
+{
+};
+
+template< >
+struct is_path_char_type< char > :
+ public std::true_type
+{
+};
+
+template< >
+struct is_path_char_type< wchar_t > :
+ public std::true_type
+{
+};
+
+
+template< typename Iterator >
+struct is_iterator_to_path_chars :
+ public is_path_char_type< typename std::iterator_traits< Iterator >::value_type >::type
+{
+};
+
+//! The trait indicates whether the type is an iterator over a sequence of path characters
+template< typename Iterator >
+struct is_path_source_iterator :
+ public std::integral_constant<
+ bool,
+ detail::conjunction<
+ boost::iterators::is_iterator< Iterator >,
+ is_iterator_to_path_chars< Iterator >
+ >::value
+ >
+{
+};
+
+
+//! The trait indicates whether the type is a pointer to a sequence of native path characters
+template< typename T >
+struct is_native_char_ptr :
+ public std::false_type
+{
+};
+
+template< >
+struct is_native_char_ptr< path_native_char_type* > :
+ public std::true_type
+{
+};
+
+template< >
+struct is_native_char_ptr< const path_native_char_type* > :
+ public std::true_type
+{
+};
+
+
+//! Converts character encoding using the supplied codecvt facet. If \a cvt is \c nullptr then \c path::codecvt() will be used.
+BOOST_FILESYSTEM_DECL
+void convert(const char* from, const char* from_end, std::wstring& to, const codecvt_type* cvt = nullptr);
+
+//! \overload convert
+BOOST_FILESYSTEM_DECL
+void convert(const wchar_t* from, const wchar_t* from_end, std::string& to, const codecvt_type* cvt = nullptr);
+
+
+// Source dispatch -----------------------------------------------------------------//
+
+template< typename Source, typename Callback >
+typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt = nullptr);
+
+template< typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch(const char* source, Callback cb, const codecvt_type* cvt, ntcts_type_tag)
+{
+ return cb(source, source + std::strlen(source), cvt);
+}
+
+template< typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch(const wchar_t* source, Callback cb, const codecvt_type* cvt, ntcts_type_tag)
+{
+ return cb(source, source + std::wcslen(source), cvt);
+}
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt, string_class_tag)
+{
+ return cb(source.data(), source.data() + source.size(), cvt);
+}
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt, range_type_tag)
+{
+ std::basic_string< typename Source::value_type > src(source.begin(), source.end());
+ return cb(src.data(), src.data() + src.size(), cvt);
+}
+
+#if defined(BOOST_FILESYSTEM_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4
+
+template< typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch(std::vector< char > const& source, Callback cb, const codecvt_type* cvt, range_type_tag)
+{
+ const char* data = nullptr, *data_end = nullptr;
+ if (!source.empty())
+ {
+ data = &source[0];
+ data_end = data + source.size();
+ }
+ return cb(data, data_end, cvt);
+}
+
+template< typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch(std::vector< wchar_t > const& source, Callback cb, const codecvt_type* cvt, range_type_tag)
+{
+ const wchar_t* data = nullptr, *data_end = nullptr;
+ if (!source.empty())
+ {
+ data = &source[0];
+ data_end = data + source.size();
+ }
+ return cb(data, data_end, cvt);
+}
+
+#endif // defined(BOOST_FILESYSTEM_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4
+
+// Defined in directory.hpp to avoid circular header dependencies
+template< typename Callback >
+typename Callback::result_type dispatch(directory_entry const& de, Callback cb, const codecvt_type* cvt, directory_entry_tag);
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch(Source const& source, Callback cb, const codecvt_type* cvt)
+{
+ return path_traits::dispatch(source, cb, cvt,
+ typename path_traits::path_source_traits< typename std::remove_cv< Source >::type >::tag_type());
+}
+
+
+typedef char yes_type;
+struct no_type { char buf[2]; };
+
+#if !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR)
+
+namespace is_convertible_to_path_source_impl {
+
+yes_type check_convertible(const char*);
+yes_type check_convertible(const wchar_t*);
+yes_type check_convertible(std::string const&);
+yes_type check_convertible(std::wstring const&);
+yes_type check_convertible(boost::container::basic_string< char, std::char_traits< char >, void > const&);
+yes_type check_convertible(boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void > const&);
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+yes_type check_convertible(std::string_view const&);
+yes_type check_convertible(std::wstring_view const&);
+#endif
+yes_type check_convertible(boost::basic_string_view< char, std::char_traits< char > > const&);
+yes_type check_convertible(boost::basic_string_view< wchar_t, std::char_traits< wchar_t > > const&);
+no_type check_convertible(std::nullptr_t);
+no_type check_convertible(...);
+
+} // namespace is_convertible_to_path_source_impl
+
+//! The type trait indicates whether the type has a conversion path to one of the path source types
+template< typename T >
+struct is_convertible_to_path_source :
+ public std::integral_constant<
+ bool,
+ sizeof(is_convertible_to_path_source_impl::check_convertible(std::declval< T const& >())) == sizeof(yes_type)
+ >
+{
+};
+
+#else // !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR)
+
+// Note: We use separate checks for convertibility to std::string_view and other types to avoid ambiguity with an implicit range constructor
+// of std::string_view in the early C++23 draft (N4892). If a user's type is convertible to e.g. std::string and also satisfies
+// ranges::contiguous_range and ranges::sized_range concepts then the conversion is ambiguous: the type is convertible to std::string
+// through the conversion operator in the user's class and is also convertible to std::string_view through the implicit conversion
+// constructor in std::string_view. The solution is to check convertibility to std::string_view separately first.
+
+namespace is_convertible_to_std_string_view_impl {
+
+yes_type check_convertible(std::string_view const&);
+yes_type check_convertible(std::wstring_view const&);
+no_type check_convertible(std::nullptr_t);
+no_type check_convertible(...);
+
+} // namespace is_convertible_to_std_string_view_impl
+
+template< typename T >
+struct is_convertible_to_std_string_view :
+ public std::integral_constant<
+ bool,
+ sizeof(is_convertible_to_std_string_view_impl::check_convertible(std::declval< T const& >())) == sizeof(yes_type)
+ >
+{
+};
+
+namespace is_convertible_to_path_source_non_std_string_view_impl {
+
+yes_type check_convertible(const char*);
+yes_type check_convertible(const wchar_t*);
+yes_type check_convertible(std::string const&);
+yes_type check_convertible(std::wstring const&);
+yes_type check_convertible(boost::container::basic_string< char, std::char_traits< char >, void > const&);
+yes_type check_convertible(boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void > const&);
+yes_type check_convertible(boost::basic_string_view< char, std::char_traits< char > > const&);
+yes_type check_convertible(boost::basic_string_view< wchar_t, std::char_traits< wchar_t > > const&);
+no_type check_convertible(std::nullptr_t);
+no_type check_convertible(...);
+
+} // namespace is_convertible_to_path_source_non_std_string_view_impl
+
+template< typename T >
+struct is_convertible_to_path_source_non_std_string_view :
+ public std::integral_constant<
+ bool,
+ sizeof(is_convertible_to_path_source_non_std_string_view_impl::check_convertible(std::declval< T const& >())) == sizeof(yes_type)
+ >
+{
+};
+
+//! The type trait indicates whether the type has a conversion path to one of the path source types
+template< typename T >
+struct is_convertible_to_path_source :
+ public std::integral_constant<
+ bool,
+ detail::disjunction<
+ is_convertible_to_std_string_view< T >,
+ is_convertible_to_path_source_non_std_string_view< T >
+ >::value
+ >
+{
+};
+
+#endif // !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR)
+
+//! The type trait makes \a T dependent on the second template argument. Used to delay type resolution and name binding.
+template< typename T, typename >
+struct make_dependent
+{
+ typedef T type;
+};
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(const char* source, Callback cb, const codecvt_type* cvt)
+{
+ typedef typename path_traits::make_dependent< const char*, Source >::type source_t;
+ return path_traits::dispatch(static_cast< source_t >(source), cb, cvt);
+}
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(const wchar_t* source, Callback cb, const codecvt_type* cvt)
+{
+ typedef typename path_traits::make_dependent< const wchar_t*, Source >::type source_t;
+ return path_traits::dispatch(static_cast< source_t >(source), cb, cvt);
+}
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::string const& source, Callback cb, const codecvt_type* cvt)
+{
+ typedef typename path_traits::make_dependent< std::string, Source >::type source_t;
+ return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
+}
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::wstring const& source, Callback cb, const codecvt_type* cvt)
+{
+ typedef typename path_traits::make_dependent< std::wstring, Source >::type source_t;
+ return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
+}
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl
+(
+ boost::container::basic_string< char, std::char_traits< char >, void > const& source,
+ Callback cb,
+ const codecvt_type* cvt
+)
+{
+ typedef typename path_traits::make_dependent< boost::container::basic_string< char, std::char_traits< char >, void >, Source >::type source_t;
+ return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
+}
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl
+(
+ boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void > const& source,
+ Callback cb,
+ const codecvt_type* cvt
+)
+{
+ typedef typename path_traits::make_dependent< boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void >, Source >::type source_t;
+ return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
+}
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl
+(
+ boost::basic_string_view< char, std::char_traits< char > > const& source,
+ Callback cb,
+ const codecvt_type* cvt
+)
+{
+ typedef typename path_traits::make_dependent< boost::basic_string_view< char, std::char_traits< char > >, Source >::type source_t;
+ return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
+}
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl
+(
+ boost::basic_string_view< wchar_t, std::char_traits< wchar_t > > const& source,
+ Callback cb,
+ const codecvt_type* cvt
+)
+{
+ typedef typename path_traits::make_dependent< boost::basic_string_view< wchar_t, std::char_traits< wchar_t > >, Source >::type source_t;
+ return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
+}
+
+#if !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR)
+
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::string_view const& source, Callback cb, const codecvt_type* cvt)
+{
+ typedef typename path_traits::make_dependent< std::string_view, Source >::type source_t;
+ return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
+}
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::wstring_view const& source, Callback cb, const codecvt_type* cvt)
+{
+ typedef typename path_traits::make_dependent< std::wstring_view, Source >::type source_t;
+ return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
+}
+
+#endif // !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = nullptr)
+{
+ typedef typename std::remove_cv< Source >::type source_t;
+ return path_traits::dispatch_convertible_impl< source_t >(source, cb, cvt);
+}
+
+#else // !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR)
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_sv_impl(std::string_view const& source, Callback cb, const codecvt_type* cvt)
+{
+ typedef typename path_traits::make_dependent< std::string_view, Source >::type source_t;
+ return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
+}
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_sv_impl(std::wstring_view const& source, Callback cb, const codecvt_type* cvt)
+{
+ typedef typename path_traits::make_dependent< std::wstring_view, Source >::type source_t;
+ return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt);
+}
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename std::enable_if<
+ !is_convertible_to_std_string_view< typename std::remove_cv< Source >::type >::value,
+ typename Callback::result_type
+>::type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = nullptr)
+{
+ typedef typename std::remove_cv< Source >::type source_t;
+ return path_traits::dispatch_convertible_impl< source_t >(source, cb, cvt);
+}
+
+template< typename Source, typename Callback >
+BOOST_FORCEINLINE typename std::enable_if<
+ is_convertible_to_std_string_view< typename std::remove_cv< Source >::type >::value,
+ typename Callback::result_type
+>::type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = nullptr)
+{
+ typedef typename std::remove_cv< Source >::type source_t;
+ return path_traits::dispatch_convertible_sv_impl< source_t >(source, cb, cvt);
+}
+
+#endif // !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR)
+
+} // namespace path_traits
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
+
+#endif // BOOST_FILESYSTEM_DETAIL_PATH_TRAITS_HPP
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/type_traits/conjunction.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/type_traits/conjunction.hpp
new file mode 100644
index 0000000000..9d7cd830cc
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/type_traits/conjunction.hpp
@@ -0,0 +1,49 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2024 Andrey Semashev
+ */
+/*!
+ * \file filesystem/detail/type_traits/conjunction.hpp
+ *
+ * This header contains definition of \c conjunction type trait.
+ */
+
+#ifndef BOOST_FILESYSTEM_DETAIL_TYPE_TRAITS_CONJUNCTION_HPP_INCLUDED_
+#define BOOST_FILESYSTEM_DETAIL_TYPE_TRAITS_CONJUNCTION_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/filesystem/config.hpp>
+
+#if (defined(__cpp_lib_logical_traits) && (__cpp_lib_logical_traits >= 201510l)) || \
+ (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (_MSC_FULL_VER >= 190023918) && (BOOST_CXX_VERSION >= 201703l))
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+using std::conjunction;
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#else
+
+#include <boost/type_traits/conjunction.hpp>
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+using boost::conjunction;
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#endif
+
+#endif // BOOST_FILESYSTEM_DETAIL_TYPE_TRAITS_CONJUNCTION_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/type_traits/disjunction.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/type_traits/disjunction.hpp
new file mode 100644
index 0000000000..e9adc9d3e6
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/type_traits/disjunction.hpp
@@ -0,0 +1,49 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2024 Andrey Semashev
+ */
+/*!
+ * \file filesystem/detail/type_traits/disjunction.hpp
+ *
+ * This header contains definition of \c disjunction type trait.
+ */
+
+#ifndef BOOST_FILESYSTEM_DETAIL_TYPE_TRAITS_DISJUNCTION_HPP_INCLUDED_
+#define BOOST_FILESYSTEM_DETAIL_TYPE_TRAITS_DISJUNCTION_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/filesystem/config.hpp>
+
+#if (defined(__cpp_lib_logical_traits) && (__cpp_lib_logical_traits >= 201510l)) || \
+ (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (_MSC_FULL_VER >= 190023918) && (BOOST_CXX_VERSION >= 201703l))
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+using std::disjunction;
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#else
+
+#include <boost/type_traits/disjunction.hpp>
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+using boost::disjunction;
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#endif
+
+#endif // BOOST_FILESYSTEM_DETAIL_TYPE_TRAITS_DISJUNCTION_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/type_traits/negation.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/type_traits/negation.hpp
new file mode 100644
index 0000000000..a0c86b4011
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/type_traits/negation.hpp
@@ -0,0 +1,49 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2024 Andrey Semashev
+ */
+/*!
+ * \file filesystem/detail/type_traits/negation.hpp
+ *
+ * This header contains definition of \c negation type trait.
+ */
+
+#ifndef BOOST_FILESYSTEM_DETAIL_TYPE_TRAITS_NEGATION_HPP_INCLUDED_
+#define BOOST_FILESYSTEM_DETAIL_TYPE_TRAITS_NEGATION_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/filesystem/config.hpp>
+
+#if (defined(__cpp_lib_logical_traits) && (__cpp_lib_logical_traits >= 201510l)) || \
+ (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (_MSC_FULL_VER >= 190023918) && (BOOST_CXX_VERSION >= 201703l))
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+using std::negation;
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#else
+
+#include <boost/type_traits/negation.hpp>
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+using boost::negation;
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#endif
+
+#endif // BOOST_FILESYSTEM_DETAIL_TYPE_TRAITS_NEGATION_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/utf8_codecvt_facet.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/utf8_codecvt_facet.hpp
new file mode 100644
index 0000000000..4df9a7c620
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/detail/utf8_codecvt_facet.hpp
@@ -0,0 +1,33 @@
+// Copyright (c) 2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu)
+// Andrew Lumsdaine, Indiana University (lums@osl.iu.edu).
+
+// Distributed under the Boost Software License, Version 1.0.
+// (See http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_FILESYSTEM_UTF8_CODECVT_FACET_HPP
+#define BOOST_FILESYSTEM_UTF8_CODECVT_FACET_HPP
+
+#include <boost/filesystem/config.hpp>
+
+#include <boost/filesystem/detail/header.hpp>
+
+#define BOOST_UTF8_BEGIN_NAMESPACE \
+ namespace boost { \
+ namespace filesystem { \
+ namespace detail {
+
+#define BOOST_UTF8_END_NAMESPACE \
+ } \
+ } \
+ }
+#define BOOST_UTF8_DECL BOOST_FILESYSTEM_DECL
+
+#include <boost/detail/utf8_codecvt_facet.hpp>
+
+#undef BOOST_UTF8_BEGIN_NAMESPACE
+#undef BOOST_UTF8_END_NAMESPACE
+#undef BOOST_UTF8_DECL
+
+#include <boost/filesystem/detail/footer.hpp>
+
+#endif // BOOST_FILESYSTEM_UTF8_CODECVT_FACET_HPP
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/directory.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/directory.hpp
new file mode 100644
index 0000000000..821b1a97bb
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/directory.hpp
@@ -0,0 +1,1039 @@
+// boost/filesystem/directory.hpp ---------------------------------------------------//
+
+// Copyright Beman Dawes 2002-2009
+// Copyright Jan Langer 2002
+// Copyright Dietmar Kuehl 2001
+// Copyright Vladimir Prus 2002
+// Copyright Andrey Semashev 2019, 2022
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#ifndef BOOST_FILESYSTEM_DIRECTORY_HPP
+#define BOOST_FILESYSTEM_DIRECTORY_HPP
+
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/file_status.hpp>
+#include <boost/filesystem/detail/path_traits.hpp>
+
+#include <cstddef>
+#include <string>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/detail/bitmask.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/smart_ptr/intrusive_ptr.hpp>
+#include <boost/smart_ptr/intrusive_ref_counter.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/iterator/iterator_categories.hpp>
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+//--------------------------------------------------------------------------------------//
+
+namespace boost {
+namespace filesystem {
+
+enum class directory_options : unsigned int
+{
+ none = 0u,
+ skip_permission_denied = 1u, // if a directory cannot be opened because of insufficient permissions, pretend that the directory is empty
+ follow_directory_symlink = 1u << 1u, // recursive_directory_iterator: follow directory symlinks
+ skip_dangling_symlinks = 1u << 2u, // non-standard extension for recursive_directory_iterator: don't follow dangling directory symlinks,
+ pop_on_error = 1u << 3u, // non-standard extension for recursive_directory_iterator: instead of producing an end iterator on errors,
+ // repeatedly invoke pop() until it succeeds or the iterator becomes equal to end iterator
+ _detail_no_follow = 1u << 4u, // internal use only
+ _detail_no_push = 1u << 5u // internal use only
+};
+
+BOOST_BITMASK(directory_options)
+
+class directory_iterator;
+class recursive_directory_iterator;
+
+namespace detail {
+
+struct directory_iterator_params;
+
+BOOST_FILESYSTEM_DECL void directory_iterator_construct(directory_iterator& it, path const& p, directory_options opts, directory_iterator_params* params, system::error_code* ec);
+BOOST_FILESYSTEM_DECL void directory_iterator_increment(directory_iterator& it, system::error_code* ec);
+
+struct recur_dir_itr_imp;
+
+BOOST_FILESYSTEM_DECL void recursive_directory_iterator_construct(recursive_directory_iterator& it, path const& dir_path, directory_options opts, system::error_code* ec);
+BOOST_FILESYSTEM_DECL void recursive_directory_iterator_increment(recursive_directory_iterator& it, system::error_code* ec);
+BOOST_FILESYSTEM_DECL void recursive_directory_iterator_pop(recursive_directory_iterator& it, system::error_code* ec);
+
+} // namespace detail
+
+//--------------------------------------------------------------------------------------//
+// //
+// directory_entry //
+// //
+//--------------------------------------------------------------------------------------//
+
+// GCC has a problem with a member function named path within a namespace or
+// sub-namespace that also has a class named path. The workaround is to always
+// fully qualify the name path when it refers to the class name.
+
+class directory_entry
+{
+ friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_construct(directory_iterator& it, path const& p, directory_options opts, detail::directory_iterator_params* params, system::error_code* ec);
+ friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_increment(directory_iterator& it, system::error_code* ec);
+
+ friend BOOST_FILESYSTEM_DECL void detail::recursive_directory_iterator_increment(recursive_directory_iterator& it, system::error_code* ec);
+
+public:
+ typedef boost::filesystem::path::value_type value_type; // enables class path ctor taking directory_entry
+
+ directory_entry() noexcept {}
+
+ explicit directory_entry(boost::filesystem::path const& p);
+
+#if BOOST_FILESYSTEM_VERSION >= 4
+ directory_entry(boost::filesystem::path const& p, system::error_code& ec) :
+ m_path(p)
+ {
+ refresh_impl(&ec);
+ if (ec)
+ m_path.clear();
+ }
+#else
+ directory_entry(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status()) :
+ m_path(p), m_status(st), m_symlink_status(symlink_st)
+ {
+ }
+#endif
+
+ directory_entry(directory_entry const& rhs) :
+ m_path(rhs.m_path), m_status(rhs.m_status), m_symlink_status(rhs.m_symlink_status)
+ {
+ }
+
+ directory_entry& operator=(directory_entry const& rhs)
+ {
+ m_path = rhs.m_path;
+ m_status = rhs.m_status;
+ m_symlink_status = rhs.m_symlink_status;
+ return *this;
+ }
+
+ directory_entry(directory_entry&& rhs) noexcept :
+ m_path(static_cast< boost::filesystem::path&& >(rhs.m_path)),
+ m_status(static_cast< file_status&& >(rhs.m_status)),
+ m_symlink_status(static_cast< file_status&& >(rhs.m_symlink_status))
+ {
+ }
+
+ directory_entry& operator=(directory_entry&& rhs) noexcept
+ {
+ m_path = static_cast< boost::filesystem::path&& >(rhs.m_path);
+ m_status = static_cast< file_status&& >(rhs.m_status);
+ m_symlink_status = static_cast< file_status&& >(rhs.m_symlink_status);
+ return *this;
+ }
+
+ void assign(boost::filesystem::path&& p);
+
+#if BOOST_FILESYSTEM_VERSION >= 4
+ void assign(boost::filesystem::path&& p, system::error_code& ec)
+ {
+ m_path = static_cast< boost::filesystem::path&& >(p);
+ refresh_impl(&ec);
+ }
+#else
+ void assign(boost::filesystem::path&& p, file_status st, file_status symlink_st = file_status())
+ {
+ assign_with_status(static_cast< boost::filesystem::path&& >(p), st, symlink_st);
+ }
+#endif
+
+ void assign(boost::filesystem::path const& p);
+
+#if BOOST_FILESYSTEM_VERSION >= 4
+ void assign(boost::filesystem::path const& p, system::error_code& ec)
+ {
+ m_path = p;
+ refresh_impl(&ec);
+ }
+#else
+ void assign(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status())
+ {
+ assign_with_status(p, st, symlink_st);
+ }
+#endif
+
+ void replace_filename(boost::filesystem::path const& p);
+
+#if BOOST_FILESYSTEM_VERSION >= 4
+ void replace_filename(boost::filesystem::path const& p, system::error_code& ec)
+ {
+ m_path.replace_filename(p);
+ refresh_impl(&ec);
+ }
+#else
+ void replace_filename(boost::filesystem::path const& p, file_status st, file_status symlink_st = file_status())
+ {
+ replace_filename_with_status(p, st, symlink_st);
+ }
+
+ BOOST_FILESYSTEM_DETAIL_DEPRECATED("Use directory_entry::replace_filename() instead")
+ void replace_leaf(boost::filesystem::path const& p, file_status st, file_status symlink_st)
+ {
+ replace_filename_with_status(p, st, symlink_st);
+ }
+#endif
+
+ boost::filesystem::path const& path() const noexcept { return m_path; }
+ operator boost::filesystem::path const&() const noexcept { return m_path; }
+
+ void refresh() { refresh_impl(); }
+ void refresh(system::error_code& ec) noexcept { refresh_impl(&ec); }
+
+ file_status status() const
+ {
+ if (!filesystem::status_known(m_status))
+ refresh_impl();
+ return m_status;
+ }
+
+ file_status status(system::error_code& ec) const noexcept
+ {
+ ec.clear();
+
+ if (!filesystem::status_known(m_status))
+ refresh_impl(&ec);
+ return m_status;
+ }
+
+ file_status symlink_status() const
+ {
+ if (!filesystem::status_known(m_symlink_status))
+ refresh_impl();
+ return m_symlink_status;
+ }
+
+ file_status symlink_status(system::error_code& ec) const noexcept
+ {
+ ec.clear();
+
+ if (!filesystem::status_known(m_symlink_status))
+ refresh_impl(&ec);
+ return m_symlink_status;
+ }
+
+ filesystem::file_type file_type() const
+ {
+ if (!filesystem::type_present(m_status))
+ refresh_impl();
+ return m_status.type();
+ }
+
+ filesystem::file_type file_type(system::error_code& ec) const noexcept
+ {
+ ec.clear();
+
+ if (!filesystem::type_present(m_status))
+ refresh_impl(&ec);
+ return m_status.type();
+ }
+
+ filesystem::file_type symlink_file_type() const
+ {
+ if (!filesystem::type_present(m_symlink_status))
+ refresh_impl();
+ return m_symlink_status.type();
+ }
+
+ filesystem::file_type symlink_file_type(system::error_code& ec) const noexcept
+ {
+ ec.clear();
+
+ if (!filesystem::type_present(m_symlink_status))
+ refresh_impl(&ec);
+ return m_symlink_status.type();
+ }
+
+ bool exists() const
+ {
+ filesystem::file_type ft = this->file_type();
+ return ft != filesystem::status_error && ft != filesystem::file_not_found;
+ }
+
+ bool exists(system::error_code& ec) const noexcept
+ {
+ filesystem::file_type ft = this->file_type(ec);
+ return ft != filesystem::status_error && ft != filesystem::file_not_found;
+ }
+
+ bool is_regular_file() const
+ {
+ return this->file_type() == filesystem::regular_file;
+ }
+
+ bool is_regular_file(system::error_code& ec) const noexcept
+ {
+ return this->file_type(ec) == filesystem::regular_file;
+ }
+
+ bool is_directory() const
+ {
+ return this->file_type() == filesystem::directory_file;
+ }
+
+ bool is_directory(system::error_code& ec) const noexcept
+ {
+ return this->file_type(ec) == filesystem::directory_file;
+ }
+
+ bool is_symlink() const
+ {
+ return this->symlink_file_type() == filesystem::symlink_file;
+ }
+
+ bool is_symlink(system::error_code& ec) const noexcept
+ {
+ return this->symlink_file_type(ec) == filesystem::symlink_file;
+ }
+
+ bool is_block_file() const
+ {
+ return this->file_type() == filesystem::block_file;
+ }
+
+ bool is_block_file(system::error_code& ec) const noexcept
+ {
+ return this->file_type(ec) == filesystem::block_file;
+ }
+
+ bool is_character_file() const
+ {
+ return this->file_type() == filesystem::character_file;
+ }
+
+ bool is_character_file(system::error_code& ec) const noexcept
+ {
+ return this->file_type(ec) == filesystem::character_file;
+ }
+
+ bool is_fifo() const
+ {
+ return this->file_type() == filesystem::fifo_file;
+ }
+
+ bool is_fifo(system::error_code& ec) const noexcept
+ {
+ return this->file_type(ec) == filesystem::fifo_file;
+ }
+
+ bool is_socket() const
+ {
+ return this->file_type() == filesystem::socket_file;
+ }
+
+ bool is_socket(system::error_code& ec) const noexcept
+ {
+ return this->file_type(ec) == filesystem::socket_file;
+ }
+
+ bool is_reparse_file() const
+ {
+ return this->symlink_file_type() == filesystem::reparse_file;
+ }
+
+ bool is_reparse_file(system::error_code& ec) const noexcept
+ {
+ return this->symlink_file_type(ec) == filesystem::reparse_file;
+ }
+
+ bool is_other() const
+ {
+ filesystem::file_type ft = this->file_type();
+ return ft != filesystem::status_error && ft != filesystem::file_not_found &&
+ ft != filesystem::regular_file && ft != filesystem::directory_file;
+ }
+
+ bool is_other(system::error_code& ec) const noexcept
+ {
+ filesystem::file_type ft = this->file_type(ec);
+ return ft != filesystem::status_error && ft != filesystem::file_not_found &&
+ ft != filesystem::regular_file && ft != filesystem::directory_file;
+ }
+
+ bool operator==(directory_entry const& rhs) const { return m_path == rhs.m_path; }
+ bool operator!=(directory_entry const& rhs) const { return m_path != rhs.m_path; }
+ bool operator<(directory_entry const& rhs) const { return m_path < rhs.m_path; }
+ bool operator<=(directory_entry const& rhs) const { return m_path <= rhs.m_path; }
+ bool operator>(directory_entry const& rhs) const { return m_path > rhs.m_path; }
+ bool operator>=(directory_entry const& rhs) const { return m_path >= rhs.m_path; }
+
+private:
+ BOOST_FILESYSTEM_DECL void refresh_impl(system::error_code* ec = nullptr) const;
+
+ void assign_with_status(boost::filesystem::path&& p, file_status st, file_status symlink_st)
+ {
+ m_path = static_cast< boost::filesystem::path&& >(p);
+ m_status = static_cast< file_status&& >(st);
+ m_symlink_status = static_cast< file_status&& >(symlink_st);
+ }
+
+ void assign_with_status(boost::filesystem::path const& p, file_status st, file_status symlink_st)
+ {
+ m_path = p;
+ m_status = static_cast< file_status&& >(st);
+ m_symlink_status = static_cast< file_status&& >(symlink_st);
+ }
+
+ void replace_filename_with_status(boost::filesystem::path const& p, file_status st, file_status symlink_st)
+ {
+ m_path.replace_filename(p);
+ m_status = static_cast< file_status&& >(st);
+ m_symlink_status = static_cast< file_status&& >(symlink_st);
+ }
+
+private:
+ boost::filesystem::path m_path;
+ mutable file_status m_status; // stat()-like
+ mutable file_status m_symlink_status; // lstat()-like
+};
+
+#if !defined(BOOST_FILESYSTEM_SOURCE)
+
+inline directory_entry::directory_entry(boost::filesystem::path const& p) :
+ m_path(p)
+{
+#if BOOST_FILESYSTEM_VERSION >= 4
+ refresh_impl();
+#endif
+}
+
+inline void directory_entry::assign(boost::filesystem::path&& p)
+{
+ m_path = static_cast< boost::filesystem::path&& >(p);
+#if BOOST_FILESYSTEM_VERSION >= 4
+ refresh_impl();
+#else
+ m_status = file_status();
+ m_symlink_status = file_status();
+#endif
+}
+
+inline void directory_entry::assign(boost::filesystem::path const& p)
+{
+ m_path = p;
+#if BOOST_FILESYSTEM_VERSION >= 4
+ refresh_impl();
+#else
+ m_status = file_status();
+ m_symlink_status = file_status();
+#endif
+}
+
+inline void directory_entry::replace_filename(boost::filesystem::path const& p)
+{
+ m_path.replace_filename(p);
+#if BOOST_FILESYSTEM_VERSION >= 4
+ refresh_impl();
+#else
+ m_status = file_status();
+ m_symlink_status = file_status();
+#endif
+}
+
+#endif // !defined(BOOST_FILESYSTEM_SOURCE)
+
+namespace detail {
+namespace path_traits {
+
+// Dispatch function for integration with path class
+template< typename Callback >
+BOOST_FORCEINLINE typename Callback::result_type dispatch(directory_entry const& de, Callback cb, const codecvt_type* cvt, directory_entry_tag)
+{
+ boost::filesystem::path::string_type const& source = de.path().native();
+ return cb(source.data(), source.data() + source.size(), cvt);
+}
+
+} // namespace path_traits
+} // namespace detail
+
+//--------------------------------------------------------------------------------------//
+// //
+// directory_entry overloads //
+// //
+//--------------------------------------------------------------------------------------//
+
+// Without these functions, calling (for example) 'is_directory' with a 'directory_entry' results in:
+// - a conversion to 'path' using 'operator boost::filesystem::path const&()',
+// - then a call to 'is_directory(path const& p)' which recomputes the status with 'detail::status(p)'.
+//
+// These functions avoid a costly recomputation of the status if one calls 'is_directory(e)' instead of 'is_directory(e.status())'
+
+inline file_status status(directory_entry const& e)
+{
+ return e.status();
+}
+
+inline file_status status(directory_entry const& e, system::error_code& ec) noexcept
+{
+ return e.status(ec);
+}
+
+inline file_status symlink_status(directory_entry const& e)
+{
+ return e.symlink_status();
+}
+
+inline file_status symlink_status(directory_entry const& e, system::error_code& ec) noexcept
+{
+ return e.symlink_status(ec);
+}
+
+inline bool type_present(directory_entry const& e)
+{
+ return e.file_type() != filesystem::status_error;
+}
+
+inline bool type_present(directory_entry const& e, system::error_code& ec) noexcept
+{
+ return e.file_type(ec) != filesystem::status_error;
+}
+
+inline bool status_known(directory_entry const& e)
+{
+ return filesystem::status_known(e.status());
+}
+
+inline bool status_known(directory_entry const& e, system::error_code& ec) noexcept
+{
+ return filesystem::status_known(e.status(ec));
+}
+
+inline bool exists(directory_entry const& e)
+{
+ return e.exists();
+}
+
+inline bool exists(directory_entry const& e, system::error_code& ec) noexcept
+{
+ return e.exists(ec);
+}
+
+inline bool is_regular_file(directory_entry const& e)
+{
+ return e.is_regular_file();
+}
+
+inline bool is_regular_file(directory_entry const& e, system::error_code& ec) noexcept
+{
+ return e.is_regular_file(ec);
+}
+
+inline bool is_directory(directory_entry const& e)
+{
+ return e.is_directory();
+}
+
+inline bool is_directory(directory_entry const& e, system::error_code& ec) noexcept
+{
+ return e.is_directory(ec);
+}
+
+inline bool is_symlink(directory_entry const& e)
+{
+ return e.is_symlink();
+}
+
+inline bool is_symlink(directory_entry const& e, system::error_code& ec) noexcept
+{
+ return e.is_symlink(ec);
+}
+
+inline bool is_block_file(directory_entry const& e)
+{
+ return e.is_block_file();
+}
+
+inline bool is_block_file(directory_entry const& e, system::error_code& ec) noexcept
+{
+ return e.is_block_file(ec);
+}
+
+inline bool is_character_file(directory_entry const& e)
+{
+ return e.is_character_file();
+}
+
+inline bool is_character_file(directory_entry const& e, system::error_code& ec) noexcept
+{
+ return e.is_character_file(ec);
+}
+
+inline bool is_fifo(directory_entry const& e)
+{
+ return e.is_fifo();
+}
+
+inline bool is_fifo(directory_entry const& e, system::error_code& ec) noexcept
+{
+ return e.is_fifo(ec);
+}
+
+inline bool is_socket(directory_entry const& e)
+{
+ return e.is_socket();
+}
+
+inline bool is_socket(directory_entry const& e, system::error_code& ec) noexcept
+{
+ return e.is_socket(ec);
+}
+
+inline bool is_reparse_file(directory_entry const& e)
+{
+ return e.is_reparse_file();
+}
+
+inline bool is_reparse_file(directory_entry const& e, system::error_code& ec) noexcept
+{
+ return e.is_reparse_file(ec);
+}
+
+inline bool is_other(directory_entry const& e)
+{
+ return e.is_other();
+}
+
+inline bool is_other(directory_entry const& e, system::error_code& ec) noexcept
+{
+ return e.is_other(ec);
+}
+
+//--------------------------------------------------------------------------------------//
+// //
+// directory_iterator helpers //
+// //
+//--------------------------------------------------------------------------------------//
+
+namespace detail {
+
+struct dir_itr_imp :
+ public boost::intrusive_ref_counter< dir_itr_imp >
+{
+#ifdef BOOST_WINDOWS_API
+ bool close_handle;
+ unsigned char extra_data_format;
+ std::size_t current_offset;
+#endif
+ directory_entry dir_entry;
+ void* handle;
+
+ dir_itr_imp() noexcept :
+#ifdef BOOST_WINDOWS_API
+ close_handle(false),
+ extra_data_format(0u),
+ current_offset(0u),
+#endif
+ handle(nullptr)
+ {
+ }
+ BOOST_FILESYSTEM_DECL ~dir_itr_imp() noexcept;
+
+ BOOST_FILESYSTEM_DECL static void* operator new(std::size_t class_size, std::size_t extra_size) noexcept;
+ BOOST_FILESYSTEM_DECL static void operator delete(void* p, std::size_t extra_size) noexcept;
+ BOOST_FILESYSTEM_DECL static void operator delete(void* p) noexcept;
+};
+
+} // namespace detail
+
+//--------------------------------------------------------------------------------------//
+// //
+// directory_iterator //
+// //
+//--------------------------------------------------------------------------------------//
+
+class directory_iterator :
+ public boost::iterator_facade<
+ directory_iterator,
+ directory_entry,
+ boost::single_pass_traversal_tag
+ >
+{
+ friend class boost::iterator_core_access;
+
+ friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_construct(directory_iterator& it, path const& p, directory_options opts, detail::directory_iterator_params* params, system::error_code* ec);
+ friend BOOST_FILESYSTEM_DECL void detail::directory_iterator_increment(directory_iterator& it, system::error_code* ec);
+
+ friend BOOST_FILESYSTEM_DECL void detail::recursive_directory_iterator_increment(recursive_directory_iterator& it, system::error_code* ec);
+
+public:
+ directory_iterator() noexcept {} // creates the "end" iterator
+
+ // iterator_facade derived classes don't seem to like implementations in
+ // separate translation unit dll's, so forward to detail functions
+ explicit directory_iterator(path const& p, directory_options opts = directory_options::none)
+ {
+ detail::directory_iterator_construct(*this, p, opts, nullptr, nullptr);
+ }
+
+ directory_iterator(path const& p, system::error_code& ec) noexcept
+ {
+ detail::directory_iterator_construct(*this, p, directory_options::none, nullptr, &ec);
+ }
+
+ directory_iterator(path const& p, directory_options opts, system::error_code& ec) noexcept
+ {
+ detail::directory_iterator_construct(*this, p, opts, nullptr, &ec);
+ }
+
+ directory_iterator(directory_iterator const&) = default;
+ directory_iterator& operator=(directory_iterator const&) = default;
+
+ directory_iterator(directory_iterator&& that) noexcept :
+ m_imp(static_cast< boost::intrusive_ptr< detail::dir_itr_imp >&& >(that.m_imp))
+ {
+ }
+
+ directory_iterator& operator=(directory_iterator&& that) noexcept
+ {
+ m_imp = static_cast< boost::intrusive_ptr< detail::dir_itr_imp >&& >(that.m_imp);
+ return *this;
+ }
+
+ directory_iterator& increment(system::error_code& ec) noexcept
+ {
+ detail::directory_iterator_increment(*this, &ec);
+ return *this;
+ }
+
+private:
+ boost::iterator_facade<
+ directory_iterator,
+ directory_entry,
+ boost::single_pass_traversal_tag
+ >::reference dereference() const
+ {
+ BOOST_ASSERT_MSG(!is_end(), "attempt to dereference end directory iterator");
+ return m_imp->dir_entry;
+ }
+
+ void increment() { detail::directory_iterator_increment(*this, nullptr); }
+
+ bool equal(directory_iterator const& rhs) const noexcept
+ {
+ return m_imp == rhs.m_imp || (is_end() && rhs.is_end());
+ }
+
+ bool is_end() const noexcept
+ {
+ // Note: The check for handle is needed because the iterator can be copied and the copy
+ // can be incremented to end while the original iterator still refers to the same dir_itr_imp.
+ return !m_imp || !m_imp->handle;
+ }
+
+private:
+ // intrusive_ptr provides the shallow-copy semantics required for single pass iterators
+ // (i.e. InputIterators). The end iterator is indicated by is_end().
+ boost::intrusive_ptr< detail::dir_itr_imp > m_imp;
+};
+
+// enable directory_iterator C++11 range-based for statement use --------------------//
+
+// begin() and end() are only used by a range-based for statement in the context of
+// auto - thus the top-level const is stripped - so returning const is harmless and
+// emphasizes begin() is just a pass through.
+inline directory_iterator const& begin(directory_iterator const& iter) noexcept
+{
+ return iter;
+}
+
+inline directory_iterator end(directory_iterator const&) noexcept
+{
+ return directory_iterator();
+}
+
+// enable C++14 generic accessors for range const iterators
+inline directory_iterator const& cbegin(directory_iterator const& iter) noexcept
+{
+ return iter;
+}
+
+inline directory_iterator cend(directory_iterator const&) noexcept
+{
+ return directory_iterator();
+}
+
+// enable directory_iterator BOOST_FOREACH -----------------------------------------//
+
+inline directory_iterator& range_begin(directory_iterator& iter) noexcept
+{
+ return iter;
+}
+
+inline directory_iterator range_begin(directory_iterator const& iter) noexcept
+{
+ return iter;
+}
+
+inline directory_iterator range_end(directory_iterator&) noexcept
+{
+ return directory_iterator();
+}
+
+inline directory_iterator range_end(directory_iterator const&) noexcept
+{
+ return directory_iterator();
+}
+
+} // namespace filesystem
+
+// namespace boost template specializations
+template< typename C, typename Enabler >
+struct range_mutable_iterator;
+
+template<>
+struct range_mutable_iterator< boost::filesystem::directory_iterator, void >
+{
+ typedef boost::filesystem::directory_iterator type;
+};
+
+template< typename C, typename Enabler >
+struct range_const_iterator;
+
+template<>
+struct range_const_iterator< boost::filesystem::directory_iterator, void >
+{
+ typedef boost::filesystem::directory_iterator type;
+};
+
+namespace filesystem {
+
+//--------------------------------------------------------------------------------------//
+// //
+// recursive_directory_iterator helpers //
+// //
+//--------------------------------------------------------------------------------------//
+
+namespace detail {
+
+struct recur_dir_itr_imp :
+ public boost::intrusive_ref_counter< recur_dir_itr_imp >
+{
+ typedef directory_iterator element_type;
+ std::vector< element_type > m_stack;
+ directory_options m_options;
+
+ explicit recur_dir_itr_imp(directory_options opts) noexcept : m_options(opts) {}
+};
+
+} // namespace detail
+
+//--------------------------------------------------------------------------------------//
+// //
+// recursive_directory_iterator //
+// //
+//--------------------------------------------------------------------------------------//
+
+class recursive_directory_iterator :
+ public boost::iterator_facade<
+ recursive_directory_iterator,
+ directory_entry,
+ boost::single_pass_traversal_tag
+ >
+{
+ friend class boost::iterator_core_access;
+
+ friend BOOST_FILESYSTEM_DECL void detail::recursive_directory_iterator_construct(recursive_directory_iterator& it, path const& dir_path, directory_options opts, system::error_code* ec);
+ friend BOOST_FILESYSTEM_DECL void detail::recursive_directory_iterator_increment(recursive_directory_iterator& it, system::error_code* ec);
+ friend BOOST_FILESYSTEM_DECL void detail::recursive_directory_iterator_pop(recursive_directory_iterator& it, system::error_code* ec);
+
+public:
+ recursive_directory_iterator() noexcept {} // creates the "end" iterator
+
+ explicit recursive_directory_iterator(path const& dir_path)
+ {
+ detail::recursive_directory_iterator_construct(*this, dir_path, directory_options::none, nullptr);
+ }
+
+ recursive_directory_iterator(path const& dir_path, system::error_code& ec)
+ {
+ detail::recursive_directory_iterator_construct(*this, dir_path, directory_options::none, &ec);
+ }
+
+ recursive_directory_iterator(path const& dir_path, directory_options opts)
+ {
+ detail::recursive_directory_iterator_construct(*this, dir_path, opts, nullptr);
+ }
+
+ recursive_directory_iterator(path const& dir_path, directory_options opts, system::error_code& ec)
+ {
+ detail::recursive_directory_iterator_construct(*this, dir_path, opts, &ec);
+ }
+
+ recursive_directory_iterator(recursive_directory_iterator const&) = default;
+ recursive_directory_iterator& operator=(recursive_directory_iterator const&) = default;
+
+ recursive_directory_iterator(recursive_directory_iterator&& that) noexcept :
+ m_imp(static_cast< boost::intrusive_ptr< detail::recur_dir_itr_imp >&& >(that.m_imp))
+ {
+ }
+
+ recursive_directory_iterator& operator=(recursive_directory_iterator&& that) noexcept
+ {
+ m_imp = static_cast< boost::intrusive_ptr< detail::recur_dir_itr_imp >&& >(that.m_imp);
+ return *this;
+ }
+
+ recursive_directory_iterator& increment(system::error_code& ec) noexcept
+ {
+ detail::recursive_directory_iterator_increment(*this, &ec);
+ return *this;
+ }
+
+ int depth() const noexcept
+ {
+ BOOST_ASSERT_MSG(!is_end(), "depth() on end recursive_directory_iterator");
+ return static_cast< int >(m_imp->m_stack.size() - 1u);
+ }
+
+ bool recursion_pending() const noexcept
+ {
+ BOOST_ASSERT_MSG(!is_end(), "recursion_pending() on end recursive_directory_iterator");
+ return (m_imp->m_options & directory_options::_detail_no_push) == directory_options::none;
+ }
+
+ void pop()
+ {
+ detail::recursive_directory_iterator_pop(*this, nullptr);
+ }
+
+ void pop(system::error_code& ec) noexcept
+ {
+ detail::recursive_directory_iterator_pop(*this, &ec);
+ }
+
+ void disable_recursion_pending(bool value = true) noexcept
+ {
+ BOOST_ASSERT_MSG(!is_end(), "disable_recursion_pending() on end recursive_directory_iterator");
+ if (value)
+ m_imp->m_options |= directory_options::_detail_no_push;
+ else
+ m_imp->m_options &= ~directory_options::_detail_no_push;
+ }
+
+ file_status status() const
+ {
+ BOOST_ASSERT_MSG(!is_end(), "status() on end recursive_directory_iterator");
+ return m_imp->m_stack.back()->status();
+ }
+
+ file_status symlink_status() const
+ {
+ BOOST_ASSERT_MSG(!is_end(), "symlink_status() on end recursive_directory_iterator");
+ return m_imp->m_stack.back()->symlink_status();
+ }
+
+private:
+ boost::iterator_facade<
+ recursive_directory_iterator,
+ directory_entry,
+ boost::single_pass_traversal_tag
+ >::reference dereference() const
+ {
+ BOOST_ASSERT_MSG(!is_end(), "dereference of end recursive_directory_iterator");
+ return *m_imp->m_stack.back();
+ }
+
+ void increment() { detail::recursive_directory_iterator_increment(*this, nullptr); }
+
+ bool equal(recursive_directory_iterator const& rhs) const noexcept
+ {
+ return m_imp == rhs.m_imp || (is_end() && rhs.is_end());
+ }
+
+ bool is_end() const noexcept
+ {
+ // Note: The check for m_stack.empty() is needed because the iterator can be copied and the copy
+ // can be incremented to end while the original iterator still refers to the same recur_dir_itr_imp.
+ return !m_imp || m_imp->m_stack.empty();
+ }
+
+private:
+ // intrusive_ptr provides the shallow-copy semantics required for single pass iterators
+ // (i.e. InputIterators). The end iterator is indicated by is_end().
+ boost::intrusive_ptr< detail::recur_dir_itr_imp > m_imp;
+};
+
+// enable recursive directory iterator C++11 range-base for statement use ----------//
+
+// begin() and end() are only used by a range-based for statement in the context of
+// auto - thus the top-level const is stripped - so returning const is harmless and
+// emphasizes begin() is just a pass through.
+inline recursive_directory_iterator const& begin(recursive_directory_iterator const& iter) noexcept
+{
+ return iter;
+}
+
+inline recursive_directory_iterator end(recursive_directory_iterator const&) noexcept
+{
+ return recursive_directory_iterator();
+}
+
+// enable C++14 generic accessors for range const iterators
+inline recursive_directory_iterator const& cbegin(recursive_directory_iterator const& iter) noexcept
+{
+ return iter;
+}
+
+inline recursive_directory_iterator cend(recursive_directory_iterator const&) noexcept
+{
+ return recursive_directory_iterator();
+}
+
+// enable recursive directory iterator BOOST_FOREACH -------------------------------//
+
+inline recursive_directory_iterator& range_begin(recursive_directory_iterator& iter) noexcept
+{
+ return iter;
+}
+
+inline recursive_directory_iterator range_begin(recursive_directory_iterator const& iter) noexcept
+{
+ return iter;
+}
+
+inline recursive_directory_iterator range_end(recursive_directory_iterator&) noexcept
+{
+ return recursive_directory_iterator();
+}
+
+inline recursive_directory_iterator range_end(recursive_directory_iterator const&) noexcept
+{
+ return recursive_directory_iterator();
+}
+
+} // namespace filesystem
+
+// namespace boost template specializations
+template<>
+struct range_mutable_iterator< boost::filesystem::recursive_directory_iterator, void >
+{
+ typedef boost::filesystem::recursive_directory_iterator type;
+};
+
+template<>
+struct range_const_iterator< boost::filesystem::recursive_directory_iterator, void >
+{
+ typedef boost::filesystem::recursive_directory_iterator type;
+};
+
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
+
+#endif // BOOST_FILESYSTEM_DIRECTORY_HPP
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/exception.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/exception.hpp
new file mode 100644
index 0000000000..033f520201
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/exception.hpp
@@ -0,0 +1,92 @@
+// boost/filesystem/exception.hpp -----------------------------------------------------//
+
+// Copyright Beman Dawes 2003
+// Copyright Andrey Semashev 2019
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+#ifndef BOOST_FILESYSTEM_EXCEPTION_HPP
+#define BOOST_FILESYSTEM_EXCEPTION_HPP
+
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/path.hpp>
+
+#include <string>
+#include <boost/system/error_code.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/smart_ptr/intrusive_ptr.hpp>
+#include <boost/smart_ptr/intrusive_ref_counter.hpp>
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace boost {
+namespace filesystem {
+
+//--------------------------------------------------------------------------------------//
+// //
+// class filesystem_error //
+// //
+//--------------------------------------------------------------------------------------//
+
+class BOOST_SYMBOL_VISIBLE filesystem_error :
+ public system::system_error
+{
+ // see http://www.boost.org/more/error_handling.html for design rationale
+
+public:
+ BOOST_FILESYSTEM_DECL filesystem_error(const char* what_arg, system::error_code ec);
+ BOOST_FILESYSTEM_DECL filesystem_error(std::string const& what_arg, system::error_code ec);
+ BOOST_FILESYSTEM_DECL filesystem_error(const char* what_arg, path const& path1_arg, system::error_code ec);
+ BOOST_FILESYSTEM_DECL filesystem_error(std::string const& what_arg, path const& path1_arg, system::error_code ec);
+ BOOST_FILESYSTEM_DECL filesystem_error(const char* what_arg, path const& path1_arg, path const& path2_arg, system::error_code ec);
+ BOOST_FILESYSTEM_DECL filesystem_error(std::string const& what_arg, path const& path1_arg, path const& path2_arg, system::error_code ec);
+
+ BOOST_FILESYSTEM_DECL filesystem_error(filesystem_error const& that);
+ BOOST_FILESYSTEM_DECL filesystem_error& operator=(filesystem_error const& that);
+
+ BOOST_FILESYSTEM_DECL ~filesystem_error() noexcept;
+
+ path const& path1() const noexcept
+ {
+ return m_imp_ptr.get() ? m_imp_ptr->m_path1 : get_empty_path();
+ }
+ path const& path2() const noexcept
+ {
+ return m_imp_ptr.get() ? m_imp_ptr->m_path2 : get_empty_path();
+ }
+
+ BOOST_FILESYSTEM_DECL const char* what() const noexcept override;
+
+private:
+ BOOST_FILESYSTEM_DECL static path const& get_empty_path() noexcept;
+
+private:
+ struct impl :
+ public boost::intrusive_ref_counter< impl >
+ {
+ path m_path1; // may be empty()
+ path m_path2; // may be empty()
+ std::string m_what; // not built until needed
+
+ impl() = default;
+ explicit impl(path const& path1) :
+ m_path1(path1)
+ {
+ }
+ impl(path const& path1, path const& path2) :
+ m_path1(path1), m_path2(path2)
+ {
+ }
+ };
+ boost::intrusive_ptr< impl > m_imp_ptr;
+};
+
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
+
+#endif // BOOST_FILESYSTEM_EXCEPTION_HPP
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/file_status.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/file_status.hpp
new file mode 100644
index 0000000000..c435c7775e
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/file_status.hpp
@@ -0,0 +1,252 @@
+// boost/filesystem/file_status.hpp --------------------------------------------------//
+
+// Copyright Beman Dawes 2002-2009
+// Copyright Jan Langer 2002
+// Copyright Dietmar Kuehl 2001
+// Copyright Vladimir Prus 2002
+// Copyright Andrey Semashev 2019
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#ifndef BOOST_FILESYSTEM_FILE_STATUS_HPP
+#define BOOST_FILESYSTEM_FILE_STATUS_HPP
+
+#include <boost/filesystem/config.hpp>
+#include <boost/detail/bitmask.hpp>
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+//--------------------------------------------------------------------------------------//
+
+namespace boost {
+namespace filesystem {
+
+//--------------------------------------------------------------------------------------//
+// file_type //
+//--------------------------------------------------------------------------------------//
+
+enum file_type
+{
+ status_error,
+ file_not_found,
+ regular_file,
+ directory_file,
+ // the following may not apply to some operating systems or file systems
+ symlink_file,
+ block_file,
+ character_file,
+ fifo_file,
+ socket_file,
+ reparse_file, // Windows: FILE_ATTRIBUTE_REPARSE_POINT that is not a symlink
+ type_unknown // file does exist, but isn't one of the above types or
+ // we don't have strong enough permission to find its type
+};
+
+//--------------------------------------------------------------------------------------//
+// perms //
+//--------------------------------------------------------------------------------------//
+
+enum perms
+{
+ no_perms = 0, // file_not_found is no_perms rather than perms_not_known
+
+ // POSIX equivalent macros given in comments.
+ // Values are from POSIX and are given in octal per the POSIX standard.
+
+ // permission bits
+
+ owner_read = 0400, // S_IRUSR, Read permission, owner
+ owner_write = 0200, // S_IWUSR, Write permission, owner
+ owner_exe = 0100, // S_IXUSR, Execute/search permission, owner
+ owner_all = 0700, // S_IRWXU, Read, write, execute/search by owner
+
+ group_read = 040, // S_IRGRP, Read permission, group
+ group_write = 020, // S_IWGRP, Write permission, group
+ group_exe = 010, // S_IXGRP, Execute/search permission, group
+ group_all = 070, // S_IRWXG, Read, write, execute/search by group
+
+ others_read = 04, // S_IROTH, Read permission, others
+ others_write = 02, // S_IWOTH, Write permission, others
+ others_exe = 01, // S_IXOTH, Execute/search permission, others
+ others_all = 07, // S_IRWXO, Read, write, execute/search by others
+
+ all_all = 0777, // owner_all|group_all|others_all
+
+ // other POSIX bits
+
+ set_uid_on_exe = 04000, // S_ISUID, Set-user-ID on execution
+ set_gid_on_exe = 02000, // S_ISGID, Set-group-ID on execution
+ sticky_bit = 01000, // S_ISVTX,
+ // (POSIX XSI) On directories, restricted deletion flag
+ // (V7) 'sticky bit': save swapped text even after use
+ // (SunOS) On non-directories: don't cache this file
+ // (SVID-v4.2) On directories: restricted deletion flag
+ // Also see http://en.wikipedia.org/wiki/Sticky_bit
+
+ perms_mask = 07777, // all_all|set_uid_on_exe|set_gid_on_exe|sticky_bit
+
+ perms_not_known = 0xFFFF, // present when directory_entry cache not loaded
+
+ // options for permissions() function
+
+ add_perms = 0x1000, // adds the given permission bits to the current bits
+ remove_perms = 0x2000, // removes the given permission bits from the current bits;
+ // choose add_perms or remove_perms, not both; if neither add_perms
+ // nor remove_perms is given, replace the current bits with
+ // the given bits.
+
+ symlink_perms = 0x4000, // on POSIX, don't resolve symlinks; implied on Windows
+
+ // BOOST_BITMASK op~ casts to int32_least_t, producing invalid enum values
+ _detail_extend_perms_32_1 = 0x7fffffff,
+ _detail_extend_perms_32_2 = -0x7fffffff - 1
+};
+
+BOOST_BITMASK(perms)
+
+//--------------------------------------------------------------------------------------//
+// file_status //
+//--------------------------------------------------------------------------------------//
+
+class file_status
+{
+public:
+ BOOST_CONSTEXPR file_status() noexcept :
+ m_value(status_error),
+ m_perms(perms_not_known)
+ {
+ }
+ explicit BOOST_CONSTEXPR file_status(file_type v) noexcept :
+ m_value(v),
+ m_perms(perms_not_known)
+ {
+ }
+ BOOST_CONSTEXPR file_status(file_type v, perms prms) noexcept :
+ m_value(v),
+ m_perms(prms)
+ {
+ }
+
+ BOOST_CONSTEXPR file_status(file_status const& rhs) noexcept :
+ m_value(rhs.m_value),
+ m_perms(rhs.m_perms)
+ {
+ }
+ BOOST_CXX14_CONSTEXPR file_status& operator=(file_status const& rhs) noexcept
+ {
+ m_value = rhs.m_value;
+ m_perms = rhs.m_perms;
+ return *this;
+ }
+
+ // Note: std::move is not constexpr in C++11, that's why we're not using it here
+ BOOST_CONSTEXPR file_status(file_status&& rhs) noexcept :
+ m_value(static_cast< file_type&& >(rhs.m_value)),
+ m_perms(static_cast< perms&& >(rhs.m_perms))
+ {
+ }
+ BOOST_CXX14_CONSTEXPR file_status& operator=(file_status&& rhs) noexcept
+ {
+ m_value = static_cast< file_type&& >(rhs.m_value);
+ m_perms = static_cast< perms&& >(rhs.m_perms);
+ return *this;
+ }
+
+ // observers
+ BOOST_CONSTEXPR file_type type() const noexcept { return m_value; }
+ BOOST_CONSTEXPR perms permissions() const noexcept { return m_perms; }
+
+ // modifiers
+ BOOST_CXX14_CONSTEXPR void type(file_type v) noexcept { m_value = v; }
+ BOOST_CXX14_CONSTEXPR void permissions(perms prms) noexcept { m_perms = prms; }
+
+ BOOST_CONSTEXPR bool operator==(file_status const& rhs) const noexcept
+ {
+ return type() == rhs.type() && permissions() == rhs.permissions();
+ }
+ BOOST_CONSTEXPR bool operator!=(file_status const& rhs) const noexcept
+ {
+ return !(*this == rhs);
+ }
+
+private:
+ file_type m_value;
+ perms m_perms;
+};
+
+inline BOOST_CONSTEXPR bool type_present(file_status f) noexcept
+{
+ return f.type() != filesystem::status_error;
+}
+
+inline BOOST_CONSTEXPR bool permissions_present(file_status f) noexcept
+{
+ return f.permissions() != filesystem::perms_not_known;
+}
+
+inline BOOST_CONSTEXPR bool status_known(file_status f) noexcept
+{
+ return filesystem::type_present(f) && filesystem::permissions_present(f);
+}
+
+inline BOOST_CONSTEXPR bool exists(file_status f) noexcept
+{
+ return f.type() != filesystem::status_error && f.type() != filesystem::file_not_found;
+}
+
+inline BOOST_CONSTEXPR bool is_regular_file(file_status f) noexcept
+{
+ return f.type() == filesystem::regular_file;
+}
+
+inline BOOST_CONSTEXPR bool is_directory(file_status f) noexcept
+{
+ return f.type() == filesystem::directory_file;
+}
+
+inline BOOST_CONSTEXPR bool is_symlink(file_status f) noexcept
+{
+ return f.type() == filesystem::symlink_file;
+}
+
+inline BOOST_CONSTEXPR bool is_block_file(file_status f) noexcept
+{
+ return f.type() == filesystem::block_file;
+}
+
+inline BOOST_CONSTEXPR bool is_character_file(file_status f) noexcept
+{
+ return f.type() == filesystem::character_file;
+}
+
+inline BOOST_CONSTEXPR bool is_fifo(file_status f) noexcept
+{
+ return f.type() == filesystem::fifo_file;
+}
+
+inline BOOST_CONSTEXPR bool is_socket(file_status f) noexcept
+{
+ return f.type() == filesystem::socket_file;
+}
+
+inline BOOST_CONSTEXPR bool is_reparse_file(file_status f) noexcept
+{
+ return f.type() == filesystem::reparse_file;
+}
+
+inline BOOST_CONSTEXPR bool is_other(file_status f) noexcept
+{
+ return filesystem::exists(f) && !filesystem::is_regular_file(f) && !filesystem::is_directory(f) && !filesystem::is_symlink(f);
+}
+
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp> // pops abi_prefix.hpp pragmas
+
+#endif // BOOST_FILESYSTEM_FILE_STATUS_HPP
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/fstream.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/fstream.hpp
new file mode 100644
index 0000000000..452f76426c
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/fstream.hpp
@@ -0,0 +1,257 @@
+// boost/filesystem/fstream.hpp ------------------------------------------------------//
+
+// Copyright Beman Dawes 2002
+// Copyright Andrey Semashev 2021-2023
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#ifndef BOOST_FILESYSTEM_FSTREAM_HPP
+#define BOOST_FILESYSTEM_FSTREAM_HPP
+
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/path.hpp>
+#include <iosfwd>
+#include <fstream>
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+#if defined(BOOST_WINDOWS_API)
+// On Windows, except for standard libaries known to have wchar_t overloads for
+// file stream I/O, use path::string() to get a narrow character c_str()
+#if (defined(_CPPLIB_VER) && _CPPLIB_VER >= 405 && !defined(_STLPORT_VERSION)) || \
+ (defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 7000 && defined(_LIBCPP_HAS_OPEN_WITH_WCHAR))
+// Use wide characters directly
+// Note: We don't use C++17 std::filesystem::path as a means to pass wide paths
+// to file streams because of various problems:
+// - std::filesystem is available in gcc 8 but it is broken there (fails to compile path definition
+// on Windows). Compilation errors seem to be fixed since gcc 9.
+// - In gcc 10.2 and clang 8.0.1 on Cygwin64, the path attempts to convert the wide string to narrow
+// and fails in runtime. This may be system locale dependent, and performing character code conversion
+// is against the purpose of using std::filesystem::path anyway.
+// - Other std::filesystem implementations were not tested, so it is not known if they actually work
+// with wide paths.
+#define BOOST_FILESYSTEM_C_STR(p) p.c_str()
+#else
+// Use narrow characters, since wide not available
+#define BOOST_FILESYSTEM_C_STR(p) p.string().c_str()
+#endif
+#endif // defined(BOOST_WINDOWS_API)
+
+#if !defined(BOOST_FILESYSTEM_C_STR)
+#define BOOST_FILESYSTEM_C_STR(p) p.c_str()
+#endif
+
+#if defined(BOOST_MSVC)
+#pragma warning(push)
+// 'boost::filesystem::basic_fstream<Char>' : inherits 'std::basic_istream<_Elem,_Traits>::std::basic_istream<_Elem,_Traits>::_Add_vtordisp1' via dominance
+#pragma warning(disable : 4250)
+#endif
+
+namespace boost {
+namespace filesystem {
+
+//--------------------------------------------------------------------------------------//
+// basic_filebuf //
+//--------------------------------------------------------------------------------------//
+
+template< class Char, class Traits = std::char_traits< Char > >
+class basic_filebuf :
+ public std::basic_filebuf< Char, Traits >
+{
+private:
+ typedef std::basic_filebuf< Char, Traits > base_type;
+
+public:
+ basic_filebuf() = default;
+
+#if !defined(BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS)
+ basic_filebuf(basic_filebuf&&) = default;
+ basic_filebuf& operator= (basic_filebuf&&) = default;
+#endif // !defined(BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS)
+
+ basic_filebuf(basic_filebuf const&) = delete;
+ basic_filebuf const& operator= (basic_filebuf const&) = delete;
+
+public:
+ basic_filebuf* open(path const& p, std::ios_base::openmode mode)
+ {
+ return base_type::open(BOOST_FILESYSTEM_C_STR(p), mode) ? this : nullptr;
+ }
+};
+
+//--------------------------------------------------------------------------------------//
+// basic_ifstream //
+//--------------------------------------------------------------------------------------//
+
+template< class Char, class Traits = std::char_traits< Char > >
+class basic_ifstream :
+ public std::basic_ifstream< Char, Traits >
+{
+private:
+ typedef std::basic_ifstream< Char, Traits > base_type;
+
+public:
+ basic_ifstream() = default;
+
+ // use two signatures, rather than one signature with default second
+ // argument, to workaround VC++ 7.1 bug (ID VSWhidbey 38416)
+
+ explicit basic_ifstream(path const& p) :
+ base_type(BOOST_FILESYSTEM_C_STR(p), std::ios_base::in) {}
+
+ basic_ifstream(path const& p, std::ios_base::openmode mode) :
+ base_type(BOOST_FILESYSTEM_C_STR(p), mode) {}
+
+#if !defined(BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS)
+ basic_ifstream(basic_ifstream&& that) :
+ base_type(static_cast< base_type&& >(that)) {}
+
+ basic_ifstream& operator= (basic_ifstream&& that)
+ {
+ *static_cast< base_type* >(this) = static_cast< base_type&& >(that);
+ return *this;
+ }
+#endif
+
+ basic_ifstream(basic_ifstream const&) = delete;
+ basic_ifstream const& operator= (basic_ifstream const&) = delete;
+
+public:
+ void open(path const& p)
+ {
+ base_type::open(BOOST_FILESYSTEM_C_STR(p), std::ios_base::in);
+ }
+
+ void open(path const& p, std::ios_base::openmode mode)
+ {
+ base_type::open(BOOST_FILESYSTEM_C_STR(p), mode);
+ }
+};
+
+//--------------------------------------------------------------------------------------//
+// basic_ofstream //
+//--------------------------------------------------------------------------------------//
+
+template< class Char, class Traits = std::char_traits< Char > >
+class basic_ofstream :
+ public std::basic_ofstream< Char, Traits >
+{
+private:
+ typedef std::basic_ofstream< Char, Traits > base_type;
+
+public:
+ basic_ofstream() = default;
+
+ // use two signatures, rather than one signature with default second
+ // argument, to workaround VC++ 7.1 bug (ID VSWhidbey 38416)
+
+ explicit basic_ofstream(path const& p) :
+ base_type(BOOST_FILESYSTEM_C_STR(p), std::ios_base::out) {}
+
+ basic_ofstream(path const& p, std::ios_base::openmode mode) :
+ base_type(BOOST_FILESYSTEM_C_STR(p), mode) {}
+
+#if !defined(BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS)
+ basic_ofstream(basic_ofstream&& that) :
+ base_type(static_cast< base_type&& >(that)) {}
+
+ basic_ofstream& operator= (basic_ofstream&& that)
+ {
+ *static_cast< base_type* >(this) = static_cast< base_type&& >(that);
+ return *this;
+ }
+#endif
+
+ basic_ofstream(basic_ofstream const&) = delete;
+ basic_ofstream const& operator= (basic_ofstream const&) = delete;
+
+public:
+ void open(path const& p)
+ {
+ base_type::open(BOOST_FILESYSTEM_C_STR(p), std::ios_base::out);
+ }
+
+ void open(path const& p, std::ios_base::openmode mode)
+ {
+ base_type::open(BOOST_FILESYSTEM_C_STR(p), mode);
+ }
+};
+
+//--------------------------------------------------------------------------------------//
+// basic_fstream //
+//--------------------------------------------------------------------------------------//
+
+template< class Char, class Traits = std::char_traits< Char > >
+class basic_fstream :
+ public std::basic_fstream< Char, Traits >
+{
+private:
+ typedef std::basic_fstream< Char, Traits > base_type;
+
+public:
+ basic_fstream() = default;
+
+ // use two signatures, rather than one signature with default second
+ // argument, to workaround VC++ 7.1 bug (ID VSWhidbey 38416)
+
+ explicit basic_fstream(path const& p) :
+ base_type(BOOST_FILESYSTEM_C_STR(p), std::ios_base::in | std::ios_base::out) {}
+
+ basic_fstream(path const& p, std::ios_base::openmode mode) :
+ base_type(BOOST_FILESYSTEM_C_STR(p), mode) {}
+
+#if !defined(BOOST_FILESYSTEM_DETAIL_NO_CXX11_MOVABLE_FSTREAMS)
+ basic_fstream(basic_fstream&& that) :
+ base_type(static_cast< base_type&& >(that)) {}
+
+ basic_fstream& operator= (basic_fstream&& that)
+ {
+ *static_cast< base_type* >(this) = static_cast< base_type&& >(that);
+ return *this;
+ }
+#endif
+
+ basic_fstream(basic_fstream const&) = delete;
+ basic_fstream const& operator= (basic_fstream const&) = delete;
+
+public:
+ void open(path const& p)
+ {
+ base_type::open(BOOST_FILESYSTEM_C_STR(p), std::ios_base::in | std::ios_base::out);
+ }
+
+ void open(path const& p, std::ios_base::openmode mode)
+ {
+ base_type::open(BOOST_FILESYSTEM_C_STR(p), mode);
+ }
+};
+
+//--------------------------------------------------------------------------------------//
+// typedefs //
+//--------------------------------------------------------------------------------------//
+
+typedef basic_filebuf< char > filebuf;
+typedef basic_ifstream< char > ifstream;
+typedef basic_ofstream< char > ofstream;
+typedef basic_fstream< char > fstream;
+
+typedef basic_filebuf< wchar_t > wfilebuf;
+typedef basic_ifstream< wchar_t > wifstream;
+typedef basic_ofstream< wchar_t > wofstream;
+typedef basic_fstream< wchar_t > wfstream;
+
+} // namespace filesystem
+} // namespace boost
+
+#if defined(BOOST_MSVC)
+#pragma warning(pop)
+#endif
+
+#include <boost/filesystem/detail/footer.hpp>
+
+#endif // BOOST_FILESYSTEM_FSTREAM_HPP
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/operations.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/operations.hpp
new file mode 100644
index 0000000000..5cd40a30fe
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/operations.hpp
@@ -0,0 +1,724 @@
+// boost/filesystem/operations.hpp ---------------------------------------------------//
+
+// Copyright Beman Dawes 2002-2009
+// Copyright Jan Langer 2002
+// Copyright Dietmar Kuehl 2001
+// Copyright Vladimir Prus 2002
+// Copyright Andrey Semashev 2020-2024
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#ifndef BOOST_FILESYSTEM_OPERATIONS_HPP
+#define BOOST_FILESYSTEM_OPERATIONS_HPP
+
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/file_status.hpp>
+
+#include <boost/detail/bitmask.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/cstdint.hpp>
+#include <ctime>
+#include <string>
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+//--------------------------------------------------------------------------------------//
+
+namespace boost {
+namespace filesystem {
+
+struct space_info
+{
+ // all values are byte counts
+ boost::uintmax_t capacity;
+ boost::uintmax_t free; // <= capacity
+ boost::uintmax_t available; // <= free
+};
+
+enum class copy_options : unsigned int
+{
+ none = 0u, // Default. For copy_file: error if the target file exists. For copy: do not recurse, follow symlinks, copy file contents.
+
+ // copy_file options:
+ skip_existing = 1u, // Don't overwrite the existing target file, don't report an error
+ overwrite_existing = 1u << 1u, // Overwrite existing file
+ update_existing = 1u << 2u, // Overwrite existing file if its last write time is older than the replacement file
+ synchronize_data = 1u << 3u, // Flush all buffered data written to the target file to permanent storage
+ synchronize = 1u << 4u, // Flush all buffered data and attributes written to the target file to permanent storage
+ ignore_attribute_errors = 1u << 5u, // Ignore errors of copying file attributes
+
+ // copy options:
+ recursive = 1u << 8u, // Recurse into sub-directories
+ copy_symlinks = 1u << 9u, // Copy symlinks as symlinks instead of copying the referenced file
+ skip_symlinks = 1u << 10u, // Don't copy symlinks
+ directories_only = 1u << 11u, // Only copy directory structure, do not copy non-directory files
+ create_symlinks = 1u << 12u, // Create symlinks instead of copying files
+ create_hard_links = 1u << 13u, // Create hard links instead of copying files
+ _detail_recursing = 1u << 14u // Internal use only, do not use
+};
+
+BOOST_BITMASK(copy_options)
+
+//--------------------------------------------------------------------------------------//
+// implementation details //
+//--------------------------------------------------------------------------------------//
+
+namespace detail {
+
+BOOST_FILESYSTEM_DECL
+path absolute_v3(path const& p, path const& base, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+path absolute_v4(path const& p, path const& base, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+file_status status(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+file_status symlink_status(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+bool is_empty(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+path initial_path(system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+path canonical_v3(path const& p, path const& base, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+path canonical_v4(path const& p, path const& base, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+void copy(path const& from, path const& to, copy_options options, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+bool copy_file(path const& from, path const& to, copy_options options, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+void copy_symlink(path const& existing_symlink, path const& new_symlink, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+bool create_directories(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+bool create_directory(path const& p, const path* existing, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+void create_directory_symlink(path const& to, path const& from, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+void create_hard_link(path const& to, path const& from, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+void create_symlink(path const& to, path const& from, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+path current_path(system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+void current_path(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+bool equivalent_v3(path const& p1, path const& p2, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+bool equivalent_v4(path const& p1, path const& p2, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+boost::uintmax_t file_size(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+boost::uintmax_t hard_link_count(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+std::time_t creation_time(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+std::time_t last_write_time(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+void last_write_time(path const& p, const std::time_t new_time, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+void permissions(path const& p, perms prms, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+path read_symlink(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+path relative(path const& p, path const& base, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+bool remove(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+boost::uintmax_t remove_all(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+void rename(path const& old_p, path const& new_p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+void resize_file(path const& p, uintmax_t size, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+space_info space(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+path system_complete(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+path temp_directory_path(system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+path unique_path(path const& p, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+path weakly_canonical_v3(path const& p, path const& base, system::error_code* ec = nullptr);
+BOOST_FILESYSTEM_DECL
+path weakly_canonical_v4(path const& p, path const& base, system::error_code* ec = nullptr);
+
+} // namespace detail
+
+//--------------------------------------------------------------------------------------//
+// //
+// status query functions //
+// //
+//--------------------------------------------------------------------------------------//
+
+inline file_status status(path const& p)
+{
+ return detail::status(p);
+}
+
+inline file_status status(path const& p, system::error_code& ec) noexcept
+{
+ return detail::status(p, &ec);
+}
+
+inline file_status symlink_status(path const& p)
+{
+ return detail::symlink_status(p);
+}
+
+inline file_status symlink_status(path const& p, system::error_code& ec) noexcept
+{
+ return detail::symlink_status(p, &ec);
+}
+
+inline bool exists(path const& p)
+{
+ return filesystem::exists(detail::status(p));
+}
+
+inline bool exists(path const& p, system::error_code& ec) noexcept
+{
+ return filesystem::exists(detail::status(p, &ec));
+}
+
+inline bool is_regular_file(path const& p)
+{
+ return filesystem::is_regular_file(detail::status(p));
+}
+
+inline bool is_regular_file(path const& p, system::error_code& ec) noexcept
+{
+ return filesystem::is_regular_file(detail::status(p, &ec));
+}
+
+inline bool is_directory(path const& p)
+{
+ return filesystem::is_directory(detail::status(p));
+}
+
+inline bool is_directory(path const& p, system::error_code& ec) noexcept
+{
+ return filesystem::is_directory(detail::status(p, &ec));
+}
+
+inline bool is_symlink(path const& p)
+{
+ return filesystem::is_symlink(detail::symlink_status(p));
+}
+
+inline bool is_symlink(path const& p, system::error_code& ec) noexcept
+{
+ return filesystem::is_symlink(detail::symlink_status(p, &ec));
+}
+
+inline bool is_block_file(path const& p)
+{
+ return filesystem::is_block_file(detail::status(p));
+}
+
+inline bool is_block_file(path const& p, system::error_code& ec) noexcept
+{
+ return filesystem::is_block_file(detail::status(p, &ec));
+}
+
+inline bool is_character_file(path const& p)
+{
+ return filesystem::is_character_file(detail::status(p));
+}
+
+inline bool is_character_file(path const& p, system::error_code& ec) noexcept
+{
+ return filesystem::is_character_file(detail::status(p, &ec));
+}
+
+inline bool is_fifo(path const& p)
+{
+ return filesystem::is_fifo(detail::status(p));
+}
+
+inline bool is_fifo(path const& p, system::error_code& ec) noexcept
+{
+ return filesystem::is_fifo(detail::status(p, &ec));
+}
+
+inline bool is_socket(path const& p)
+{
+ return filesystem::is_socket(detail::status(p));
+}
+
+inline bool is_socket(path const& p, system::error_code& ec) noexcept
+{
+ return filesystem::is_socket(detail::status(p, &ec));
+}
+
+inline bool is_reparse_file(path const& p)
+{
+ return filesystem::is_reparse_file(detail::symlink_status(p));
+}
+
+inline bool is_reparse_file(path const& p, system::error_code& ec) noexcept
+{
+ return filesystem::is_reparse_file(detail::symlink_status(p, &ec));
+}
+
+inline bool is_other(path const& p)
+{
+ return filesystem::is_other(detail::status(p));
+}
+
+inline bool is_other(path const& p, system::error_code& ec) noexcept
+{
+ return filesystem::is_other(detail::status(p, &ec));
+}
+
+inline bool is_empty(path const& p)
+{
+ return detail::is_empty(p);
+}
+
+inline bool is_empty(path const& p, system::error_code& ec)
+{
+ return detail::is_empty(p, &ec);
+}
+
+//--------------------------------------------------------------------------------------//
+// //
+// operational functions //
+// //
+//--------------------------------------------------------------------------------------//
+
+inline path initial_path()
+{
+ return detail::initial_path();
+}
+
+inline path initial_path(system::error_code& ec)
+{
+ return detail::initial_path(&ec);
+}
+
+template< class Path >
+path initial_path()
+{
+ return initial_path();
+}
+template< class Path >
+path initial_path(system::error_code& ec)
+{
+ return detail::initial_path(&ec);
+}
+
+inline path current_path()
+{
+ return detail::current_path();
+}
+
+inline path current_path(system::error_code& ec)
+{
+ return detail::current_path(&ec);
+}
+
+inline void current_path(path const& p)
+{
+ detail::current_path(p);
+}
+
+inline void current_path(path const& p, system::error_code& ec) noexcept
+{
+ detail::current_path(p, &ec);
+}
+
+inline void copy(path const& from, path const& to)
+{
+ detail::copy(from, to, copy_options::none);
+}
+
+inline void copy(path const& from, path const& to, system::error_code& ec) noexcept
+{
+ detail::copy(from, to, copy_options::none, &ec);
+}
+
+inline void copy(path const& from, path const& to, copy_options options)
+{
+ detail::copy(from, to, options);
+}
+
+inline void copy(path const& from, path const& to, copy_options options, system::error_code& ec) noexcept
+{
+ detail::copy(from, to, options, &ec);
+}
+
+inline bool copy_file(path const& from, path const& to)
+{
+ return detail::copy_file(from, to, copy_options::none);
+}
+
+inline bool copy_file(path const& from, path const& to, system::error_code& ec) noexcept
+{
+ return detail::copy_file(from, to, copy_options::none, &ec);
+}
+
+inline bool copy_file(path const& from, path const& to, copy_options options)
+{
+ return detail::copy_file(from, to, options);
+}
+
+inline bool copy_file(path const& from, path const& to, copy_options options, system::error_code& ec) noexcept
+{
+ return detail::copy_file(from, to, options, &ec);
+}
+
+inline void copy_symlink(path const& existing_symlink, path const& new_symlink)
+{
+ detail::copy_symlink(existing_symlink, new_symlink);
+}
+
+inline void copy_symlink(path const& existing_symlink, path const& new_symlink, system::error_code& ec) noexcept
+{
+ detail::copy_symlink(existing_symlink, new_symlink, &ec);
+}
+
+inline bool create_directories(path const& p)
+{
+ return detail::create_directories(p);
+}
+
+inline bool create_directories(path const& p, system::error_code& ec) noexcept
+{
+ return detail::create_directories(p, &ec);
+}
+
+inline bool create_directory(path const& p)
+{
+ return detail::create_directory(p, nullptr);
+}
+
+inline bool create_directory(path const& p, system::error_code& ec) noexcept
+{
+ return detail::create_directory(p, nullptr, &ec);
+}
+
+inline bool create_directory(path const& p, path const& existing)
+{
+ return detail::create_directory(p, &existing);
+}
+
+inline bool create_directory(path const& p, path const& existing, system::error_code& ec) noexcept
+{
+ return detail::create_directory(p, &existing, &ec);
+}
+
+inline void create_directory_symlink(path const& to, path const& from)
+{
+ detail::create_directory_symlink(to, from);
+}
+
+inline void create_directory_symlink(path const& to, path const& from, system::error_code& ec) noexcept
+{
+ detail::create_directory_symlink(to, from, &ec);
+}
+
+inline void create_hard_link(path const& to, path const& new_hard_link)
+{
+ detail::create_hard_link(to, new_hard_link);
+}
+
+inline void create_hard_link(path const& to, path const& new_hard_link, system::error_code& ec) noexcept
+{
+ detail::create_hard_link(to, new_hard_link, &ec);
+}
+
+inline void create_symlink(path const& to, path const& new_symlink)
+{
+ detail::create_symlink(to, new_symlink);
+}
+
+inline void create_symlink(path const& to, path const& new_symlink, system::error_code& ec) noexcept
+{
+ detail::create_symlink(to, new_symlink, &ec);
+}
+
+inline boost::uintmax_t file_size(path const& p)
+{
+ return detail::file_size(p);
+}
+
+inline boost::uintmax_t file_size(path const& p, system::error_code& ec) noexcept
+{
+ return detail::file_size(p, &ec);
+}
+
+inline boost::uintmax_t hard_link_count(path const& p)
+{
+ return detail::hard_link_count(p);
+}
+
+inline boost::uintmax_t hard_link_count(path const& p, system::error_code& ec) noexcept
+{
+ return detail::hard_link_count(p, &ec);
+}
+
+inline std::time_t creation_time(path const& p)
+{
+ return detail::creation_time(p);
+}
+
+inline std::time_t creation_time(path const& p, system::error_code& ec) noexcept
+{
+ return detail::creation_time(p, &ec);
+}
+
+inline std::time_t last_write_time(path const& p)
+{
+ return detail::last_write_time(p);
+}
+
+inline std::time_t last_write_time(path const& p, system::error_code& ec) noexcept
+{
+ return detail::last_write_time(p, &ec);
+}
+
+inline void last_write_time(path const& p, const std::time_t new_time)
+{
+ detail::last_write_time(p, new_time);
+}
+
+inline void last_write_time(path const& p, const std::time_t new_time, system::error_code& ec) noexcept
+{
+ detail::last_write_time(p, new_time, &ec);
+}
+
+inline void permissions(path const& p, perms prms)
+{
+ detail::permissions(p, prms);
+}
+
+inline void permissions(path const& p, perms prms, system::error_code& ec) noexcept
+{
+ detail::permissions(p, prms, &ec);
+}
+
+inline path read_symlink(path const& p)
+{
+ return detail::read_symlink(p);
+}
+
+inline path read_symlink(path const& p, system::error_code& ec)
+{
+ return detail::read_symlink(p, &ec);
+}
+
+inline bool remove(path const& p)
+{
+ return detail::remove(p);
+}
+
+inline bool remove(path const& p, system::error_code& ec) noexcept
+{
+ return detail::remove(p, &ec);
+}
+
+inline boost::uintmax_t remove_all(path const& p)
+{
+ return detail::remove_all(p);
+}
+
+inline boost::uintmax_t remove_all(path const& p, system::error_code& ec) noexcept
+{
+ return detail::remove_all(p, &ec);
+}
+
+inline void rename(path const& old_p, path const& new_p)
+{
+ detail::rename(old_p, new_p);
+}
+
+inline void rename(path const& old_p, path const& new_p, system::error_code& ec) noexcept
+{
+ detail::rename(old_p, new_p, &ec);
+}
+
+// name suggested by Scott McMurray
+inline void resize_file(path const& p, uintmax_t size)
+{
+ detail::resize_file(p, size);
+}
+
+inline void resize_file(path const& p, uintmax_t size, system::error_code& ec) noexcept
+{
+ detail::resize_file(p, size, &ec);
+}
+
+inline path relative(path const& p, path const& base = current_path())
+{
+ return detail::relative(p, base);
+}
+
+inline path relative(path const& p, system::error_code& ec)
+{
+ path base = current_path(ec);
+ if (ec)
+ return path();
+ return detail::relative(p, base, &ec);
+}
+
+inline path relative(path const& p, path const& base, system::error_code& ec)
+{
+ return detail::relative(p, base, &ec);
+}
+
+inline space_info space(path const& p)
+{
+ return detail::space(p);
+}
+
+inline space_info space(path const& p, system::error_code& ec) noexcept
+{
+ return detail::space(p, &ec);
+}
+
+inline path system_complete(path const& p)
+{
+ return detail::system_complete(p);
+}
+
+inline path system_complete(path const& p, system::error_code& ec)
+{
+ return detail::system_complete(p, &ec);
+}
+
+inline path temp_directory_path()
+{
+ return detail::temp_directory_path();
+}
+
+inline path temp_directory_path(system::error_code& ec)
+{
+ return detail::temp_directory_path(&ec);
+}
+
+inline path unique_path(path const& p =
+#if defined(BOOST_WINDOWS_API)
+ L"%%%%-%%%%-%%%%-%%%%"
+#else
+ "%%%%-%%%%-%%%%-%%%%"
+#endif
+)
+{
+ return detail::unique_path(p);
+}
+
+inline path unique_path(system::error_code& ec)
+{
+ return detail::unique_path
+ (
+#if defined(BOOST_WINDOWS_API)
+ L"%%%%-%%%%-%%%%-%%%%",
+#else
+ "%%%%-%%%%-%%%%-%%%%",
+#endif
+ &ec
+ );
+}
+
+inline path unique_path(path const& p, system::error_code& ec)
+{
+ return detail::unique_path(p, &ec);
+}
+
+namespace BOOST_FILESYSTEM_VERSION_NAMESPACE {
+
+inline path absolute(path const& p, path const& base = current_path())
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::absolute)(p, base);
+}
+
+inline path absolute(path const& p, system::error_code& ec)
+{
+ path base = current_path(ec);
+ if (ec)
+ return path();
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::absolute)(p, base, &ec);
+}
+
+inline path absolute(path const& p, path const& base, system::error_code& ec)
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::absolute)(p, base, &ec);
+}
+
+inline path canonical(path const& p, path const& base = current_path())
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::canonical)(p, base);
+}
+
+inline path canonical(path const& p, system::error_code& ec)
+{
+ path base = current_path(ec);
+ if (ec)
+ return path();
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::canonical)(p, base, &ec);
+}
+
+inline path canonical(path const& p, path const& base, system::error_code& ec)
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::canonical)(p, base, &ec);
+}
+
+inline bool equivalent(path const& p1, path const& p2)
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::equivalent)(p1, p2);
+}
+
+inline bool equivalent(path const& p1, path const& p2, system::error_code& ec) noexcept
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::equivalent)(p1, p2, &ec);
+}
+
+inline path weakly_canonical(path const& p, path const& base = current_path())
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::weakly_canonical)(p, base);
+}
+
+inline path weakly_canonical(path const& p, system::error_code& ec)
+{
+ path base = current_path(ec);
+ if (ec)
+ return path();
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::weakly_canonical)(p, base, &ec);
+}
+
+inline path weakly_canonical(path const& p, path const& base, system::error_code& ec)
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::weakly_canonical)(p, base, &ec);
+}
+
+} // namespace BOOST_FILESYSTEM_VERSION_NAMESPACE
+
+using BOOST_FILESYSTEM_VERSION_NAMESPACE::absolute;
+using BOOST_FILESYSTEM_VERSION_NAMESPACE::canonical;
+using BOOST_FILESYSTEM_VERSION_NAMESPACE::equivalent;
+using BOOST_FILESYSTEM_VERSION_NAMESPACE::weakly_canonical;
+
+// test helper -----------------------------------------------------------------------//
+
+// Not part of the documented interface since false positives are possible;
+// there is no law that says that an OS that has large stat.st_size
+// actually supports large file sizes.
+
+namespace detail {
+
+BOOST_FILESYSTEM_DECL bool possible_large_file_size_support();
+
+} // namespace detail
+
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
+
+#endif // BOOST_FILESYSTEM_OPERATIONS_HPP
diff --git a/contrib/restricted/boost/filesystem/include/boost/filesystem/path.hpp b/contrib/restricted/boost/filesystem/include/boost/filesystem/path.hpp
new file mode 100644
index 0000000000..f6e38f4b22
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/include/boost/filesystem/path.hpp
@@ -0,0 +1,1710 @@
+// filesystem path.hpp ---------------------------------------------------------------//
+
+// Copyright Vladimir Prus 2002
+// Copyright Beman Dawes 2002-2005, 2009
+// Copyright Andrey Semashev 2021-2024
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+// path::stem(), extension(), and replace_extension() are based on
+// basename(), extension(), and change_extension() from the original
+// filesystem/convenience.hpp header by Vladimir Prus.
+
+#ifndef BOOST_FILESYSTEM_PATH_HPP
+#define BOOST_FILESYSTEM_PATH_HPP
+
+#include <boost/filesystem/config.hpp>
+#include <cstddef>
+#include <iosfwd>
+#include <locale>
+#include <string>
+#include <iterator>
+#include <type_traits>
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+#include <string_view>
+#endif
+#include <boost/assert.hpp>
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/iterator/iterator_categories.hpp>
+#include <boost/io/quoted.hpp>
+#include <boost/functional/hash_fwd.hpp>
+#include <boost/filesystem/detail/path_traits.hpp>
+#include <boost/filesystem/detail/type_traits/negation.hpp>
+#include <boost/filesystem/detail/type_traits/conjunction.hpp>
+#include <boost/filesystem/detail/type_traits/disjunction.hpp>
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace boost {
+namespace filesystem {
+
+class path;
+
+namespace path_detail { // intentionally don't use filesystem::detail to not bring internal Boost.Filesystem functions into ADL via path_constants
+
+template< typename Char, Char Separator, Char PreferredSeparator, Char Dot >
+struct path_constants
+{
+ typedef path_constants< Char, Separator, PreferredSeparator, Dot > path_constants_base;
+ typedef Char value_type;
+ static BOOST_CONSTEXPR_OR_CONST value_type separator = Separator;
+ static BOOST_CONSTEXPR_OR_CONST value_type preferred_separator = PreferredSeparator;
+ static BOOST_CONSTEXPR_OR_CONST value_type dot = Dot;
+};
+
+#if defined(BOOST_NO_CXX17_INLINE_VARIABLES)
+template< typename Char, Char Separator, Char PreferredSeparator, Char Dot >
+BOOST_CONSTEXPR_OR_CONST typename path_constants< Char, Separator, PreferredSeparator, Dot >::value_type
+path_constants< Char, Separator, PreferredSeparator, Dot >::separator;
+template< typename Char, Char Separator, Char PreferredSeparator, Char Dot >
+BOOST_CONSTEXPR_OR_CONST typename path_constants< Char, Separator, PreferredSeparator, Dot >::value_type
+path_constants< Char, Separator, PreferredSeparator, Dot >::preferred_separator;
+template< typename Char, Char Separator, Char PreferredSeparator, Char Dot >
+BOOST_CONSTEXPR_OR_CONST typename path_constants< Char, Separator, PreferredSeparator, Dot >::value_type
+path_constants< Char, Separator, PreferredSeparator, Dot >::dot;
+#endif
+
+class path_iterator;
+class path_reverse_iterator;
+
+} // namespace path_detail
+
+namespace detail {
+
+struct path_algorithms
+{
+ // A struct that denotes a contiguous range of characters in a string. A lightweight alternative to string_view.
+ struct substring
+ {
+ std::size_t pos;
+ std::size_t size;
+ };
+
+ typedef path_traits::path_native_char_type value_type;
+ typedef std::basic_string< value_type > string_type;
+
+ static bool has_filename_v3(path const& p);
+ static bool has_filename_v4(path const& p);
+ BOOST_FILESYSTEM_DECL static path filename_v3(path const& p);
+ static path filename_v4(path const& p);
+
+ BOOST_FILESYSTEM_DECL static path stem_v3(path const& p);
+ BOOST_FILESYSTEM_DECL static path stem_v4(path const& p);
+ BOOST_FILESYSTEM_DECL static path extension_v3(path const& p);
+ static path extension_v4(path const& p);
+
+ BOOST_FILESYSTEM_DECL static void remove_filename_v3(path& p);
+ BOOST_FILESYSTEM_DECL static void remove_filename_v4(path& p);
+
+ BOOST_FILESYSTEM_DECL static void replace_extension_v3(path& p, path const& new_extension);
+ BOOST_FILESYSTEM_DECL static void replace_extension_v4(path& p, path const& new_extension);
+
+ BOOST_FILESYSTEM_DECL static path lexically_normal_v3(path const& p);
+ BOOST_FILESYSTEM_DECL static path lexically_normal_v4(path const& p);
+
+ BOOST_FILESYSTEM_DECL static path generic_path_v3(path const& p);
+ BOOST_FILESYSTEM_DECL static path generic_path_v4(path const& p);
+
+#if defined(BOOST_WINDOWS_API)
+ BOOST_FILESYSTEM_DECL static void make_preferred_v3(path& p);
+ BOOST_FILESYSTEM_DECL static void make_preferred_v4(path& p);
+#endif
+
+ BOOST_FILESYSTEM_DECL static int compare_v3(path const& left, path const& right);
+ BOOST_FILESYSTEM_DECL static int compare_v4(path const& left, path const& right);
+
+ BOOST_FILESYSTEM_DECL static void append_v3(path& p, const value_type* b, const value_type* e);
+ BOOST_FILESYSTEM_DECL static void append_v4(path& p, const value_type* b, const value_type* e);
+ static void append_v4(path& left, path const& right);
+
+ // Returns: If separator is to be appended, m_pathname.size() before append. Otherwise 0.
+ // Note: An append is never performed if size()==0, so a returned 0 is unambiguous.
+ BOOST_FILESYSTEM_DECL static string_type::size_type append_separator_if_needed(path& p);
+ BOOST_FILESYSTEM_DECL static void erase_redundant_separator(path& p, string_type::size_type sep_pos);
+
+ BOOST_FILESYSTEM_DECL static string_type::size_type find_root_name_size(path const& p);
+ BOOST_FILESYSTEM_DECL static string_type::size_type find_root_path_size(path const& p);
+ BOOST_FILESYSTEM_DECL static substring find_root_directory(path const& p);
+ BOOST_FILESYSTEM_DECL static substring find_relative_path(path const& p);
+ BOOST_FILESYSTEM_DECL static string_type::size_type find_parent_path_size(path const& p);
+ BOOST_FILESYSTEM_DECL static string_type::size_type find_filename_v4_size(path const& p);
+ BOOST_FILESYSTEM_DECL static string_type::size_type find_extension_v4_size(path const& p);
+
+ BOOST_FILESYSTEM_DECL static int lex_compare_v3
+ (
+ path_detail::path_iterator first1, path_detail::path_iterator const& last1,
+ path_detail::path_iterator first2, path_detail::path_iterator const& last2
+ );
+ BOOST_FILESYSTEM_DECL static int lex_compare_v4
+ (
+ path_detail::path_iterator first1, path_detail::path_iterator const& last1,
+ path_detail::path_iterator first2, path_detail::path_iterator const& last2
+ );
+
+ BOOST_FILESYSTEM_DECL static void increment_v3(path_detail::path_iterator& it);
+ BOOST_FILESYSTEM_DECL static void increment_v4(path_detail::path_iterator& it);
+ BOOST_FILESYSTEM_DECL static void decrement_v3(path_detail::path_iterator& it);
+ BOOST_FILESYSTEM_DECL static void decrement_v4(path_detail::path_iterator& it);
+};
+
+} // namespace detail
+
+//------------------------------------------------------------------------------------//
+// //
+// class path //
+// //
+//------------------------------------------------------------------------------------//
+
+class path :
+ public filesystem::path_detail::path_constants<
+#ifdef BOOST_WINDOWS_API
+ detail::path_traits::path_native_char_type, L'/', L'\\', L'.'
+#else
+ detail::path_traits::path_native_char_type, '/', '/', '.'
+#endif
+ >
+{
+ friend class path_detail::path_iterator;
+ friend class path_detail::path_reverse_iterator;
+ friend struct detail::path_algorithms;
+
+public:
+ // value_type is the character type used by the operating system API to
+ // represent paths.
+
+ typedef detail::path_algorithms::value_type value_type;
+ typedef detail::path_algorithms::string_type string_type;
+ typedef detail::path_traits::codecvt_type codecvt_type;
+
+ // ----- character encoding conversions -----
+
+ // Following the principle of least astonishment, path input arguments
+ // passed to or obtained from the operating system via objects of
+ // class path behave as if they were directly passed to or
+ // obtained from the O/S API, unless conversion is explicitly requested.
+ //
+ // POSIX specfies that path strings are passed unchanged to and from the
+ // API. Note that this is different from the POSIX command line utilities,
+ // which convert according to a locale.
+ //
+ // Thus for POSIX, char strings do not undergo conversion. wchar_t strings
+ // are converted to/from char using the path locale or, if a conversion
+ // argument is given, using a conversion object modeled on
+ // std::wstring_convert.
+ //
+ // The path locale, which is global to the thread, can be changed by the
+ // imbue() function. It is initialized to an implementation defined locale.
+ //
+ // For Windows, wchar_t strings do not undergo conversion. char strings
+ // are converted using the "ANSI" or "OEM" code pages, as determined by
+ // the AreFileApisANSI() function, or, if a conversion argument is given,
+ // using a conversion object modeled on std::wstring_convert.
+ //
+ // See m_pathname comments for further important rationale.
+
+ // TODO: rules needed for operating systems that use / or .
+ // differently, or format directory paths differently from file paths.
+ //
+ // **********************************************************************************
+ //
+ // More work needed: How to handle an operating system that may have
+ // slash characters or dot characters in valid filenames, either because
+ // it doesn't follow the POSIX standard, or because it allows MBCS
+ // filename encodings that may contain slash or dot characters. For
+ // example, ISO/IEC 2022 (JIS) encoding which allows switching to
+ // JIS x0208-1983 encoding. A valid filename in this set of encodings is
+ // 0x1B 0x24 0x42 [switch to X0208-1983] 0x24 0x2F [U+304F Kiragana letter KU]
+ // ^^^^
+ // Note that 0x2F is the ASCII slash character
+ //
+ // **********************************************************************************
+
+ // Supported source arguments: half-open iterator range, container, c-array,
+ // and single pointer to null terminated string.
+
+ // All source arguments except pointers to null terminated byte strings support
+ // multi-byte character strings which may have embedded nulls. Embedded null
+ // support is required for some Asian languages on Windows.
+
+ // "const codecvt_type& cvt=codecvt()" default arguments are not used because this
+ // limits the impact of locale("") initialization failures on POSIX systems to programs
+ // that actually depend on locale(""). It further ensures that exceptions thrown
+ // as a result of such failues occur after main() has started, so can be caught.
+
+private:
+ //! Assignment operation
+ class assign_op
+ {
+ private:
+ path& m_self;
+
+ public:
+ typedef void result_type;
+
+ explicit assign_op(path& self) noexcept : m_self(self) {}
+
+ result_type operator() (const value_type* source, const value_type* source_end, const codecvt_type* = nullptr) const
+ {
+ m_self.m_pathname.assign(source, source_end);
+ }
+
+ template< typename OtherChar >
+ result_type operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt = nullptr) const
+ {
+ m_self.m_pathname.clear();
+ detail::path_traits::convert(source, source_end, m_self.m_pathname, cvt);
+ }
+ };
+
+ //! Concatenation operation
+ class concat_op
+ {
+ private:
+ path& m_self;
+
+ public:
+ typedef void result_type;
+
+ explicit concat_op(path& self) noexcept : m_self(self) {}
+
+ result_type operator() (const value_type* source, const value_type* source_end, const codecvt_type* = nullptr) const
+ {
+ m_self.m_pathname.append(source, source_end);
+ }
+
+ template< typename OtherChar >
+ result_type operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt = nullptr) const
+ {
+ detail::path_traits::convert(source, source_end, m_self.m_pathname, cvt);
+ }
+ };
+
+ //! Path appending operation
+ class append_op
+ {
+ private:
+ path& m_self;
+
+ public:
+ typedef void result_type;
+
+ explicit append_op(path& self) noexcept : m_self(self) {}
+
+ BOOST_FORCEINLINE result_type operator() (const value_type* source, const value_type* source_end, const codecvt_type* = nullptr) const
+ {
+ m_self.append(source, source_end);
+ }
+
+ template< typename OtherChar >
+ BOOST_FORCEINLINE result_type operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt = nullptr) const
+ {
+ string_type src;
+ detail::path_traits::convert(source, source_end, src, cvt);
+ m_self.append(src.data(), src.data() + src.size());
+ }
+ };
+
+ //! Path comparison operation
+ class compare_op
+ {
+ private:
+ path const& m_self;
+
+ public:
+ typedef int result_type;
+
+ explicit compare_op(path const& self) noexcept : m_self(self) {}
+
+ result_type operator() (const value_type* source, const value_type* source_end, const codecvt_type* = nullptr) const;
+
+ template< typename OtherChar >
+ result_type operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt = nullptr) const;
+ };
+
+public:
+ typedef path_detail::path_iterator iterator;
+ typedef iterator const_iterator;
+ typedef path_detail::path_reverse_iterator reverse_iterator;
+ typedef reverse_iterator const_reverse_iterator;
+
+public:
+ // ----- constructors -----
+
+ path() noexcept {}
+ path(path const& p) : m_pathname(p.m_pathname) {}
+ path(path const& p, codecvt_type const&) : m_pathname(p.m_pathname) {}
+
+ path(const value_type* s) : m_pathname(s) {}
+ path(const value_type* s, codecvt_type const&) : m_pathname(s) {}
+ path(string_type const& s) : m_pathname(s) {}
+ path(string_type const& s, codecvt_type const&) : m_pathname(s) {}
+#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
+ path(std::basic_string_view< value_type > const& s) : m_pathname(s) {}
+ path(std::basic_string_view< value_type > const& s, codecvt_type const&) : m_pathname(s) {}
+#endif
+
+ template<
+ typename Source,
+ typename = typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >,
+ detail::negation< detail::path_traits::is_native_path_source< typename std::remove_cv< Source >::type > >
+ >::value
+ >::type
+ >
+ path(Source const& source)
+ {
+ assign(source);
+ }
+
+ template<
+ typename Source,
+ typename = typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >,
+ detail::negation< detail::path_traits::is_native_path_source< typename std::remove_cv< Source >::type > >
+ >::value
+ >::type
+ >
+ explicit path(Source const& source, codecvt_type const& cvt)
+ {
+ assign(source, cvt);
+ }
+
+ path(path&& p) noexcept : m_pathname(static_cast< string_type&& >(p.m_pathname))
+ {
+ }
+ path(path&& p, codecvt_type const&) noexcept : m_pathname(static_cast< string_type&& >(p.m_pathname))
+ {
+ }
+ path& operator=(path&& p) noexcept
+ {
+ m_pathname = static_cast< string_type&& >(p.m_pathname);
+ return *this;
+ }
+ path& assign(path&& p) noexcept
+ {
+ m_pathname = static_cast< string_type&& >(p.m_pathname);
+ return *this;
+ }
+ path& assign(path&& p, codecvt_type const&) noexcept
+ {
+ m_pathname = static_cast< string_type&& >(p.m_pathname);
+ return *this;
+ }
+
+ path(string_type&& s) noexcept : m_pathname(static_cast< string_type&& >(s))
+ {
+ }
+ path(string_type&& s, codecvt_type const&) noexcept : m_pathname(static_cast< string_type&& >(s))
+ {
+ }
+ path& operator=(string_type&& p) noexcept
+ {
+ m_pathname = static_cast< string_type&& >(p);
+ return *this;
+ }
+ path& assign(string_type&& p) noexcept
+ {
+ m_pathname = static_cast< string_type&& >(p);
+ return *this;
+ }
+ path& assign(string_type&& p, codecvt_type const&) noexcept
+ {
+ m_pathname = static_cast< string_type&& >(p);
+ return *this;
+ }
+
+ path(const value_type* begin, const value_type* end) : m_pathname(begin, end) {}
+ path(const value_type* begin, const value_type* end, codecvt_type const&) : m_pathname(begin, end) {}
+
+ template<
+ typename InputIterator,
+ typename = typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_path_source_iterator< InputIterator >,
+ detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > >
+ >::value
+ >::type
+ >
+ path(InputIterator begin, InputIterator end)
+ {
+ if (begin != end)
+ {
+ typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t;
+ source_t source(begin, end);
+ assign(static_cast< source_t&& >(source));
+ }
+ }
+
+ template<
+ typename InputIterator,
+ typename = typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_path_source_iterator< InputIterator >,
+ detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > >
+ >::value
+ >::type
+ >
+ path(InputIterator begin, InputIterator end, codecvt_type const& cvt)
+ {
+ if (begin != end)
+ {
+ typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t;
+ source_t source(begin, end);
+ assign(static_cast< source_t&& >(source), cvt);
+ }
+ }
+
+ path(std::nullptr_t) = delete;
+ path& operator= (std::nullptr_t) = delete;
+
+public:
+ // ----- assignments -----
+
+ // We need to explicitly define copy assignment as otherwise it will be implicitly defined as deleted because there is move assignment
+ path& operator=(path const& p);
+
+ template< typename Source >
+ typename std::enable_if<
+ detail::disjunction<
+ detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >,
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >
+ >::value,
+ path&
+ >::type operator=(Source const& source)
+ {
+ return assign(source);
+ }
+
+ path& assign(path const& p)
+ {
+ m_pathname = p.m_pathname;
+ return *this;
+ }
+
+ template< typename Source >
+ typename std::enable_if<
+ detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value,
+ path&
+ >::type assign(Source const& source)
+ {
+ detail::path_traits::dispatch(source, assign_op(*this));
+ return *this;
+ }
+
+ template< typename Source >
+ typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >,
+ detail::negation< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type > >
+ >::value,
+ path&
+ >::type assign(Source const& source)
+ {
+ detail::path_traits::dispatch_convertible(source, assign_op(*this));
+ return *this;
+ }
+
+ path& assign(path const& p, codecvt_type const&)
+ {
+ m_pathname = p.m_pathname;
+ return *this;
+ }
+
+ template< typename Source >
+ typename std::enable_if<
+ detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value,
+ path&
+ >::type assign(Source const& source, codecvt_type const& cvt)
+ {
+ detail::path_traits::dispatch(source, assign_op(*this), &cvt);
+ return *this;
+ }
+
+ template< typename Source >
+ typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >,
+ detail::negation< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type > >
+ >::value,
+ path&
+ >::type assign(Source const& source, codecvt_type const& cvt)
+ {
+ detail::path_traits::dispatch_convertible(source, assign_op(*this), &cvt);
+ return *this;
+ }
+
+ path& assign(const value_type* begin, const value_type* end)
+ {
+ m_pathname.assign(begin, end);
+ return *this;
+ }
+
+ template< typename InputIterator >
+ typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_path_source_iterator< InputIterator >,
+ detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > >
+ >::value,
+ path&
+ >::type assign(InputIterator begin, InputIterator end)
+ {
+ m_pathname.clear();
+ if (begin != end)
+ {
+ typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t;
+ source_t source(begin, end);
+ assign(static_cast< source_t&& >(source));
+ }
+ return *this;
+ }
+
+ path& assign(const value_type* begin, const value_type* end, codecvt_type const&)
+ {
+ m_pathname.assign(begin, end);
+ return *this;
+ }
+
+ template< typename InputIterator >
+ typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_path_source_iterator< InputIterator >,
+ detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > >
+ >::value,
+ path&
+ >::type assign(InputIterator begin, InputIterator end, codecvt_type const& cvt)
+ {
+ m_pathname.clear();
+ if (begin != end)
+ {
+ typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t;
+ source_t source(begin, end);
+ assign(static_cast< source_t&& >(source), cvt);
+ }
+ return *this;
+ }
+
+ // ----- concatenation -----
+
+ path& operator+=(path const& p);
+
+ template< typename Source >
+ typename std::enable_if<
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >::value,
+ path&
+ >::type operator+=(Source const& source)
+ {
+ return concat(source);
+ }
+
+ path& operator+=(value_type c)
+ {
+ m_pathname.push_back(c);
+ return *this;
+ }
+
+ template< typename CharT >
+ typename std::enable_if<
+ detail::path_traits::is_path_char_type< CharT >::value,
+ path&
+ >::type operator+=(CharT c)
+ {
+ CharT tmp[2];
+ tmp[0] = c;
+ tmp[1] = static_cast< CharT >(0);
+ concat_op(*this)(tmp, tmp + 1);
+ return *this;
+ }
+
+ path& concat(path const& p)
+ {
+ m_pathname.append(p.m_pathname);
+ return *this;
+ }
+
+ template< typename Source >
+ typename std::enable_if<
+ detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value,
+ path&
+ >::type concat(Source const& source)
+ {
+ detail::path_traits::dispatch(source, concat_op(*this));
+ return *this;
+ }
+
+ template< typename Source >
+ typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >,
+ detail::negation< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type > >
+ >::value,
+ path&
+ >::type concat(Source const& source)
+ {
+ detail::path_traits::dispatch_convertible(source, concat_op(*this));
+ return *this;
+ }
+
+ path& concat(path const& p, codecvt_type const&)
+ {
+ m_pathname.append(p.m_pathname);
+ return *this;
+ }
+
+ template< typename Source >
+ typename std::enable_if<
+ detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value,
+ path&
+ >::type concat(Source const& source, codecvt_type const& cvt)
+ {
+ detail::path_traits::dispatch(source, concat_op(*this), &cvt);
+ return *this;
+ }
+
+ template< typename Source >
+ typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >,
+ detail::negation< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type > >
+ >::value,
+ path&
+ >::type concat(Source const& source, codecvt_type const& cvt)
+ {
+ detail::path_traits::dispatch_convertible(source, concat_op(*this), &cvt);
+ return *this;
+ }
+
+ path& concat(const value_type* begin, const value_type* end)
+ {
+ m_pathname.append(begin, end);
+ return *this;
+ }
+
+ template< typename InputIterator >
+ typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_path_source_iterator< InputIterator >,
+ detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > >
+ >::value,
+ path&
+ >::type concat(InputIterator begin, InputIterator end)
+ {
+ if (begin != end)
+ {
+ std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source(begin, end);
+ detail::path_traits::dispatch(source, concat_op(*this));
+ }
+ return *this;
+ }
+
+ path& concat(const value_type* begin, const value_type* end, codecvt_type const&)
+ {
+ m_pathname.append(begin, end);
+ return *this;
+ }
+
+ template< typename InputIterator >
+ typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_path_source_iterator< InputIterator >,
+ detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > >
+ >::value,
+ path&
+ >::type concat(InputIterator begin, InputIterator end, codecvt_type const& cvt)
+ {
+ if (begin != end)
+ {
+ std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source(begin, end);
+ detail::path_traits::dispatch(source, concat_op(*this), &cvt);
+ }
+ return *this;
+ }
+
+ // ----- appends -----
+
+ // if a separator is added, it is the preferred separator for the platform;
+ // slash for POSIX, backslash for Windows
+
+ path& operator/=(path const& p);
+
+ template< typename Source >
+ BOOST_FORCEINLINE typename std::enable_if<
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >::value,
+ path&
+ >::type operator/=(Source const& source)
+ {
+ return append(source);
+ }
+
+ path& append(path const& p);
+
+ template< typename Source >
+ BOOST_FORCEINLINE typename std::enable_if<
+ detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value,
+ path&
+ >::type append(Source const& source)
+ {
+ detail::path_traits::dispatch(source, append_op(*this));
+ return *this;
+ }
+
+ template< typename Source >
+ BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >,
+ detail::negation< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type > >
+ >::value,
+ path&
+ >::type append(Source const& source)
+ {
+ detail::path_traits::dispatch_convertible(source, append_op(*this));
+ return *this;
+ }
+
+ path& append(path const& p, codecvt_type const&);
+
+ template< typename Source >
+ BOOST_FORCEINLINE typename std::enable_if<
+ detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value,
+ path&
+ >::type append(Source const& source, codecvt_type const& cvt)
+ {
+ detail::path_traits::dispatch(source, append_op(*this), &cvt);
+ return *this;
+ }
+
+ template< typename Source >
+ BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >,
+ detail::negation< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type > >
+ >::value,
+ path&
+ >::type append(Source const& source, codecvt_type const& cvt)
+ {
+ detail::path_traits::dispatch_convertible(source, append_op(*this), &cvt);
+ return *this;
+ }
+
+ path& append(const value_type* begin, const value_type* end);
+
+ template< typename InputIterator >
+ BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_path_source_iterator< InputIterator >,
+ detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > >
+ >::value,
+ path&
+ >::type append(InputIterator begin, InputIterator end)
+ {
+ std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source(begin, end);
+ detail::path_traits::dispatch(source, append_op(*this));
+ return *this;
+ }
+
+ path& append(const value_type* begin, const value_type* end, codecvt_type const&);
+
+ template< typename InputIterator >
+ BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_path_source_iterator< InputIterator >,
+ detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > >
+ >::value,
+ path&
+ >::type append(InputIterator begin, InputIterator end, const codecvt_type& cvt)
+ {
+ std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source(begin, end);
+ detail::path_traits::dispatch(source, append_op(*this), &cvt);
+ return *this;
+ }
+
+ // ----- modifiers -----
+
+ void clear() noexcept { m_pathname.clear(); }
+ path& make_preferred();
+ path& remove_filename();
+ BOOST_FILESYSTEM_DECL path& remove_filename_and_trailing_separators();
+ BOOST_FILESYSTEM_DECL path& remove_trailing_separator();
+ BOOST_FILESYSTEM_DECL path& replace_filename(path const& replacement);
+ path& replace_extension(path const& new_extension = path());
+
+ void swap(path& rhs) noexcept { m_pathname.swap(rhs.m_pathname); }
+
+ // ----- observers -----
+
+ // For operating systems that format file paths differently than directory
+ // paths, return values from observers are formatted as file names unless there
+ // is a trailing separator, in which case returns are formatted as directory
+ // paths. POSIX and Windows make no such distinction.
+
+ // Implementations are permitted to return const values or const references.
+
+ // The string or path returned by an observer are specified as being formatted
+ // as "native" or "generic".
+ //
+ // For POSIX, these are all the same format; slashes and backslashes are as input and
+ // are not modified.
+ //
+ // For Windows, native: as input; slashes and backslashes are not modified;
+ // this is the format of the internally stored string.
+ // generic: backslashes are converted to slashes
+
+ // ----- native format observers -----
+
+ string_type const& native() const noexcept { return m_pathname; }
+ const value_type* c_str() const noexcept { return m_pathname.c_str(); }
+ string_type::size_type size() const noexcept { return m_pathname.size(); }
+
+ template< typename String >
+ String string() const;
+
+ template< typename String >
+ String string(codecvt_type const& cvt) const;
+
+#ifdef BOOST_WINDOWS_API
+ std::string string() const
+ {
+ std::string tmp;
+ if (!m_pathname.empty())
+ detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp);
+ return tmp;
+ }
+ std::string string(codecvt_type const& cvt) const
+ {
+ std::string tmp;
+ if (!m_pathname.empty())
+ detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp, &cvt);
+ return tmp;
+ }
+
+ // string_type is std::wstring, so there is no conversion
+ std::wstring const& wstring() const { return m_pathname; }
+ std::wstring const& wstring(codecvt_type const&) const { return m_pathname; }
+#else // BOOST_POSIX_API
+ // string_type is std::string, so there is no conversion
+ std::string const& string() const { return m_pathname; }
+ std::string const& string(codecvt_type const&) const { return m_pathname; }
+
+ std::wstring wstring() const
+ {
+ std::wstring tmp;
+ if (!m_pathname.empty())
+ detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp);
+ return tmp;
+ }
+ std::wstring wstring(codecvt_type const& cvt) const
+ {
+ std::wstring tmp;
+ if (!m_pathname.empty())
+ detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp, &cvt);
+ return tmp;
+ }
+#endif
+
+ // ----- generic format observers -----
+
+ // Experimental generic function returning generic formatted path (i.e. separators
+ // are forward slashes). Motivation: simpler than a family of generic_*string
+ // functions.
+ path generic_path() const;
+
+ template< typename String >
+ String generic_string() const;
+
+ template< typename String >
+ String generic_string(codecvt_type const& cvt) const;
+
+ std::string generic_string() const { return generic_path().string(); }
+ std::string generic_string(codecvt_type const& cvt) const { return generic_path().string(cvt); }
+ std::wstring generic_wstring() const { return generic_path().wstring(); }
+ std::wstring generic_wstring(codecvt_type const& cvt) const { return generic_path().wstring(cvt); }
+
+ // ----- compare -----
+
+ int compare(path const& p) const; // generic, lexicographical
+
+ template< typename Source >
+ BOOST_FORCEINLINE typename std::enable_if<
+ detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value,
+ int
+ >::type compare(Source const& source) const
+ {
+ return detail::path_traits::dispatch(source, compare_op(*this));
+ }
+
+ template< typename Source >
+ BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >,
+ detail::negation< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type > >
+ >::value,
+ int
+ >::type compare(Source const& source) const
+ {
+ return detail::path_traits::dispatch_convertible(source, compare_op(*this));
+ }
+
+ template< typename Source >
+ BOOST_FORCEINLINE typename std::enable_if<
+ detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value,
+ int
+ >::type compare(Source const& source, codecvt_type const& cvt) const
+ {
+ return detail::path_traits::dispatch(source, compare_op(*this), &cvt);
+ }
+
+ template< typename Source >
+ BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >,
+ detail::negation< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type > >
+ >::value,
+ int
+ >::type compare(Source const& source, codecvt_type const& cvt) const
+ {
+ return detail::path_traits::dispatch_convertible(source, compare_op(*this), &cvt);
+ }
+
+ // ----- decomposition -----
+
+ path root_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_root_path_size(*this)); }
+ // returns 0 or 1 element path even on POSIX, root_name() is non-empty() for network paths
+ path root_name() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_root_name_size(*this)); }
+
+ // returns 0 or 1 element path
+ path root_directory() const
+ {
+ detail::path_algorithms::substring root_dir = detail::path_algorithms::find_root_directory(*this);
+ const value_type* p = m_pathname.c_str() + root_dir.pos;
+ return path(p, p + root_dir.size);
+ }
+
+ path relative_path() const
+ {
+ detail::path_algorithms::substring rel_path = detail::path_algorithms::find_relative_path(*this);
+ const value_type* p = m_pathname.c_str() + rel_path.pos;
+ return path(p, p + rel_path.size);
+ }
+
+ path parent_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_parent_path_size(*this)); }
+
+ path filename() const; // returns 0 or 1 element path
+ path stem() const; // returns 0 or 1 element path
+ path extension() const; // returns 0 or 1 element path
+
+ // ----- query -----
+
+ bool empty() const noexcept { return m_pathname.empty(); }
+ bool filename_is_dot() const;
+ bool filename_is_dot_dot() const;
+ bool has_root_path() const { return detail::path_algorithms::find_root_path_size(*this) > 0; }
+ bool has_root_name() const { return detail::path_algorithms::find_root_name_size(*this) > 0; }
+ bool has_root_directory() const { return detail::path_algorithms::find_root_directory(*this).size > 0; }
+ bool has_relative_path() const { return detail::path_algorithms::find_relative_path(*this).size > 0; }
+ bool has_parent_path() const { return detail::path_algorithms::find_parent_path_size(*this) > 0; }
+ bool has_filename() const;
+ bool has_stem() const { return !stem().empty(); }
+ bool has_extension() const { return !extension().empty(); }
+ bool is_relative() const { return !is_absolute(); }
+ bool is_absolute() const
+ {
+#if defined(BOOST_WINDOWS_API)
+ return has_root_name() && has_root_directory();
+#else
+ return has_root_directory();
+#endif
+ }
+
+ // ----- lexical operations -----
+
+ path lexically_normal() const;
+ BOOST_FILESYSTEM_DECL path lexically_relative(path const& base) const;
+ path lexically_proximate(path const& base) const;
+
+ // ----- iterators -----
+
+ BOOST_FILESYSTEM_DECL iterator begin() const;
+ BOOST_FILESYSTEM_DECL iterator end() const;
+ reverse_iterator rbegin() const;
+ reverse_iterator rend() const;
+
+ // ----- static member functions -----
+
+ static BOOST_FILESYSTEM_DECL std::locale imbue(std::locale const& loc);
+ static BOOST_FILESYSTEM_DECL codecvt_type const& codecvt();
+
+ //--------------------------------------------------------------------------------------//
+ // class path private members //
+ //--------------------------------------------------------------------------------------//
+private:
+ /*
+ * m_pathname has the type, encoding, and format required by the native
+ * operating system. Thus for POSIX and Windows there is no conversion for
+ * passing m_pathname.c_str() to the O/S API or when obtaining a path from the
+ * O/S API. POSIX encoding is unspecified other than for dot and slash
+ * characters; POSIX just treats paths as a sequence of bytes. Windows
+ * encoding is UCS-2 or UTF-16 depending on the version.
+ */
+ string_type m_pathname; // Windows: as input; backslashes NOT converted to slashes,
+ // slashes NOT converted to backslashes
+};
+
+namespace detail {
+BOOST_FILESYSTEM_DECL path const& dot_path();
+BOOST_FILESYSTEM_DECL path const& dot_dot_path();
+} // namespace detail
+
+namespace path_detail {
+
+//------------------------------------------------------------------------------------//
+// class path::iterator //
+//------------------------------------------------------------------------------------//
+
+class path_iterator :
+ public boost::iterator_facade<
+ path_iterator,
+ const path,
+ boost::bidirectional_traversal_tag
+ >
+{
+private:
+ friend class boost::iterator_core_access;
+ friend class boost::filesystem::path;
+ friend class path_reverse_iterator;
+ friend struct boost::filesystem::detail::path_algorithms;
+
+ path const& dereference() const { return m_element; }
+
+ bool equal(path_iterator const& rhs) const noexcept
+ {
+ return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos;
+ }
+
+ void increment();
+ void decrement();
+
+private:
+ // current element
+ path m_element;
+ // path being iterated over
+ const path* m_path_ptr;
+ // position of m_element in m_path_ptr->m_pathname.
+ // if m_element is implicit dot, m_pos is the
+ // position of the last separator in the path.
+ // end() iterator is indicated by
+ // m_pos == m_path_ptr->m_pathname.size()
+ path::string_type::size_type m_pos;
+};
+
+//------------------------------------------------------------------------------------//
+// class path::reverse_iterator //
+//------------------------------------------------------------------------------------//
+
+class path_reverse_iterator :
+ public boost::iterator_facade<
+ path_reverse_iterator,
+ const path,
+ boost::bidirectional_traversal_tag
+ >
+{
+public:
+ explicit path_reverse_iterator(path_iterator itr) :
+ m_itr(itr)
+ {
+ if (itr != itr.m_path_ptr->begin())
+ m_element = *--itr;
+ }
+
+private:
+ friend class boost::iterator_core_access;
+ friend class boost::filesystem::path;
+
+ path const& dereference() const { return m_element; }
+ bool equal(path_reverse_iterator const& rhs) const noexcept { return m_itr == rhs.m_itr; }
+
+ void increment()
+ {
+ --m_itr;
+ if (m_itr != m_itr.m_path_ptr->begin())
+ {
+ path_iterator tmp = m_itr;
+ m_element = *--tmp;
+ }
+ }
+
+ void decrement()
+ {
+ m_element = *m_itr;
+ ++m_itr;
+ }
+
+private:
+ path_iterator m_itr;
+ path m_element;
+};
+
+// std::lexicographical_compare would infinitely recurse because path iterators
+// yield paths, so provide a path aware version
+bool lexicographical_compare(path_iterator first1, path_iterator const& last1, path_iterator first2, path_iterator const& last2);
+
+} // namespace path_detail
+
+using path_detail::lexicographical_compare;
+
+//------------------------------------------------------------------------------------//
+// //
+// non-member functions //
+// //
+//------------------------------------------------------------------------------------//
+
+BOOST_FORCEINLINE bool operator==(path const& lhs, path const& rhs)
+{
+ return lhs.compare(rhs) == 0;
+}
+
+template< typename Path, typename Source >
+BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ std::is_same< Path, path >,
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >
+ >::value,
+ bool
+>::type operator==(Path const& lhs, Source const& rhs)
+{
+ return lhs.compare(rhs) == 0;
+}
+
+template< typename Source, typename Path >
+BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ std::is_same< Path, path >,
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >
+ >::value,
+ bool
+>::type operator==(Source const& lhs, Path const& rhs)
+{
+ return rhs.compare(lhs) == 0;
+}
+
+BOOST_FORCEINLINE bool operator!=(path const& lhs, path const& rhs)
+{
+ return lhs.compare(rhs) != 0;
+}
+
+template< typename Path, typename Source >
+BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ std::is_same< Path, path >,
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >
+ >::value,
+ bool
+>::type operator!=(Path const& lhs, Source const& rhs)
+{
+ return lhs.compare(rhs) != 0;
+}
+
+template< typename Source, typename Path >
+BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ std::is_same< Path, path >,
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >
+ >::value,
+ bool
+>::type operator!=(Source const& lhs, Path const& rhs)
+{
+ return rhs.compare(lhs) != 0;
+}
+
+BOOST_FORCEINLINE bool operator<(path const& lhs, path const& rhs)
+{
+ return lhs.compare(rhs) < 0;
+}
+
+template< typename Path, typename Source >
+BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ std::is_same< Path, path >,
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >
+ >::value,
+ bool
+>::type operator<(Path const& lhs, Source const& rhs)
+{
+ return lhs.compare(rhs) < 0;
+}
+
+template< typename Source, typename Path >
+BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ std::is_same< Path, path >,
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >
+ >::value,
+ bool
+>::type operator<(Source const& lhs, Path const& rhs)
+{
+ return rhs.compare(lhs) > 0;
+}
+
+BOOST_FORCEINLINE bool operator<=(path const& lhs, path const& rhs)
+{
+ return lhs.compare(rhs) <= 0;
+}
+
+template< typename Path, typename Source >
+BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ std::is_same< Path, path >,
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >
+ >::value,
+ bool
+>::type operator<=(Path const& lhs, Source const& rhs)
+{
+ return lhs.compare(rhs) <= 0;
+}
+
+template< typename Source, typename Path >
+BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ std::is_same< Path, path >,
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >
+ >::value,
+ bool
+>::type operator<=(Source const& lhs, Path const& rhs)
+{
+ return rhs.compare(lhs) >= 0;
+}
+
+BOOST_FORCEINLINE bool operator>(path const& lhs, path const& rhs)
+{
+ return lhs.compare(rhs) > 0;
+}
+
+template< typename Path, typename Source >
+BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ std::is_same< Path, path >,
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >
+ >::value,
+ bool
+>::type operator>(Path const& lhs, Source const& rhs)
+{
+ return lhs.compare(rhs) > 0;
+}
+
+template< typename Source, typename Path >
+BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ std::is_same< Path, path >,
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >
+ >::value,
+ bool
+>::type operator>(Source const& lhs, Path const& rhs)
+{
+ return rhs.compare(lhs) < 0;
+}
+
+BOOST_FORCEINLINE bool operator>=(path const& lhs, path const& rhs)
+{
+ return lhs.compare(rhs) >= 0;
+}
+
+template< typename Path, typename Source >
+BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ std::is_same< Path, path >,
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >
+ >::value,
+ bool
+>::type operator>=(Path const& lhs, Source const& rhs)
+{
+ return lhs.compare(rhs) >= 0;
+}
+
+template< typename Source, typename Path >
+BOOST_FORCEINLINE typename std::enable_if<
+ detail::conjunction<
+ std::is_same< Path, path >,
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >
+ >::value,
+ bool
+>::type operator>=(Source const& lhs, Path const& rhs)
+{
+ return rhs.compare(lhs) <= 0;
+}
+
+
+// Note: Declared as a template to delay binding to Boost.ContainerHash functions and make the dependency optional
+template< typename Path >
+inline typename std::enable_if<
+ std::is_same< Path, path >::value,
+ std::size_t
+>::type hash_value(Path const& p) noexcept
+{
+#ifdef BOOST_WINDOWS_API
+ std::size_t seed = 0u;
+ for (typename Path::value_type const* it = p.c_str(); *it; ++it)
+ hash_combine(seed, *it == L'/' ? L'\\' : *it);
+ return seed;
+#else // BOOST_POSIX_API
+ return hash_range(p.native().begin(), p.native().end());
+#endif
+}
+
+inline void swap(path& lhs, path& rhs) noexcept
+{
+ lhs.swap(rhs);
+}
+
+BOOST_FORCEINLINE path operator/(path lhs, path const& rhs)
+{
+ lhs.append(rhs);
+ return lhs;
+}
+
+template< typename Source >
+BOOST_FORCEINLINE typename std::enable_if<
+ detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >::value,
+ path
+>::type operator/(path lhs, Source const& rhs)
+{
+ lhs.append(rhs);
+ return lhs;
+}
+
+// inserters and extractors
+// use boost::io::quoted() to handle spaces in paths
+// use '&' as escape character to ease use for Windows paths
+
+template< typename Char, typename Traits >
+inline std::basic_ostream< Char, Traits >&
+operator<<(std::basic_ostream< Char, Traits >& os, path const& p)
+{
+ return os << boost::io::quoted(p.template string< std::basic_string< Char > >(), static_cast< Char >('&'));
+}
+
+template< typename Char, typename Traits >
+inline std::basic_istream< Char, Traits >&
+operator>>(std::basic_istream< Char, Traits >& is, path& p)
+{
+ std::basic_string< Char > str;
+ is >> boost::io::quoted(str, static_cast< Char >('&'));
+ p = str;
+ return is;
+}
+
+// name_checks
+
+// These functions are holdovers from version 1. It isn't clear they have much
+// usefulness, or how to generalize them for later versions.
+
+BOOST_FILESYSTEM_DECL bool portable_posix_name(std::string const& name);
+BOOST_FILESYSTEM_DECL bool windows_name(std::string const& name);
+BOOST_FILESYSTEM_DECL bool portable_name(std::string const& name);
+BOOST_FILESYSTEM_DECL bool portable_directory_name(std::string const& name);
+BOOST_FILESYSTEM_DECL bool portable_file_name(std::string const& name);
+BOOST_FILESYSTEM_DECL bool native(std::string const& name);
+
+namespace detail {
+
+// For POSIX, is_directory_separator() and is_element_separator() are identical since
+// a forward slash is the only valid directory separator and also the only valid
+// element separator. For Windows, forward slash and back slash are the possible
+// directory separators, but colon (example: "c:foo") is also an element separator.
+inline bool is_directory_separator(path::value_type c) noexcept
+{
+ return c == path::separator
+#ifdef BOOST_WINDOWS_API
+ || c == path::preferred_separator
+#endif
+ ;
+}
+
+inline bool is_element_separator(path::value_type c) noexcept
+{
+ return c == path::separator
+#ifdef BOOST_WINDOWS_API
+ || c == path::preferred_separator || c == L':'
+#endif
+ ;
+}
+
+} // namespace detail
+
+//------------------------------------------------------------------------------------//
+// class path miscellaneous function implementations //
+//------------------------------------------------------------------------------------//
+
+namespace detail {
+
+inline bool path_algorithms::has_filename_v3(path const& p)
+{
+ return !p.m_pathname.empty();
+}
+
+inline bool path_algorithms::has_filename_v4(path const& p)
+{
+ return path_algorithms::find_filename_v4_size(p) > 0;
+}
+
+inline path path_algorithms::filename_v4(path const& p)
+{
+ string_type::size_type filename_size = path_algorithms::find_filename_v4_size(p);
+ string_type::size_type pos = p.m_pathname.size() - filename_size;
+ const value_type* ptr = p.m_pathname.c_str() + pos;
+ return path(ptr, ptr + filename_size);
+}
+
+inline path path_algorithms::extension_v4(path const& p)
+{
+ string_type::size_type extension_size = path_algorithms::find_extension_v4_size(p);
+ string_type::size_type pos = p.m_pathname.size() - extension_size;
+ const value_type* ptr = p.m_pathname.c_str() + pos;
+ return path(ptr, ptr + extension_size);
+}
+
+inline void path_algorithms::append_v4(path& left, path const& right)
+{
+ path_algorithms::append_v4(left, right.m_pathname.c_str(), right.m_pathname.c_str() + right.m_pathname.size());
+}
+
+} // namespace detail
+
+// Note: Because of the range constructor in C++23 std::string_view that involves a check for contiguous_range concept,
+// any non-template function call that requires a check whether the source argument (which may be fs::path)
+// is convertible to std::string_view must be made after fs::path::iterator is defined. This includes overload
+// resolution and SFINAE checks. Otherwise, the concept check result formally changes between fs::path::iterator
+// is not defined and defined, which causes compilation errors with gcc 11 and later.
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106808
+
+BOOST_FORCEINLINE path::compare_op::result_type path::compare_op::operator() (const value_type* source, const value_type* source_end, const codecvt_type*) const
+{
+ path src;
+ src.m_pathname.assign(source, source_end);
+ return m_self.compare(src);
+}
+
+template< typename OtherChar >
+BOOST_FORCEINLINE path::compare_op::result_type path::compare_op::operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt) const
+{
+ path src;
+ detail::path_traits::convert(source, source_end, src.m_pathname, cvt);
+ return m_self.compare(src);
+}
+
+inline path& path::operator=(path const& p)
+{
+ return assign(p);
+}
+
+inline path& path::operator+=(path const& p)
+{
+ return concat(p);
+}
+
+BOOST_FORCEINLINE path& path::operator/=(path const& p)
+{
+ return append(p);
+}
+
+inline path path::lexically_proximate(path const& base) const
+{
+ path tmp(lexically_relative(base));
+ return tmp.empty() ? *this : tmp;
+}
+
+inline path::reverse_iterator path::rbegin() const
+{
+ return reverse_iterator(end());
+}
+
+inline path::reverse_iterator path::rend() const
+{
+ return reverse_iterator(begin());
+}
+
+inline bool path::filename_is_dot() const
+{
+ // implicit dot is tricky, so actually call filename(); see path::filename() example
+ // in reference.html
+ path p(filename());
+ return p.size() == 1 && *p.c_str() == dot;
+}
+
+inline bool path::filename_is_dot_dot() const
+{
+ return size() >= 2 && m_pathname[size() - 1] == dot && m_pathname[size() - 2] == dot && (m_pathname.size() == 2 || detail::is_element_separator(m_pathname[size() - 3]));
+ // use detail::is_element_separator() rather than detail::is_directory_separator
+ // to deal with "c:.." edge case on Windows when ':' acts as a separator
+}
+
+// The following functions are defined differently, depending on Boost.Filesystem version in use.
+// To avoid ODR violation, these functions are not defined when the library itself is built.
+// This makes sure they are not compiled when the library is built, and the only version there is
+// is the one in user's code. Users are supposed to consistently use the same Boost.Filesystem version
+// in all their translation units.
+#if !defined(BOOST_FILESYSTEM_SOURCE)
+
+BOOST_FORCEINLINE path& path::append(path const& p)
+{
+ BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, p.m_pathname.data(), p.m_pathname.data() + p.m_pathname.size());
+ return *this;
+}
+
+BOOST_FORCEINLINE path& path::append(path const& p, codecvt_type const&)
+{
+ BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, p.m_pathname.data(), p.m_pathname.data() + p.m_pathname.size());
+ return *this;
+}
+
+BOOST_FORCEINLINE path& path::append(const value_type* begin, const value_type* end)
+{
+ BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, begin, end);
+ return *this;
+}
+
+BOOST_FORCEINLINE path& path::append(const value_type* begin, const value_type* end, codecvt_type const&)
+{
+ BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::append)(*this, begin, end);
+ return *this;
+}
+
+BOOST_FORCEINLINE path& path::remove_filename()
+{
+ BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::remove_filename)(*this);
+ return *this;
+}
+
+BOOST_FORCEINLINE path& path::replace_extension(path const& new_extension)
+{
+ BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::replace_extension)(*this, new_extension);
+ return *this;
+}
+
+BOOST_FORCEINLINE int path::compare(path const& p) const
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::compare)(*this, p);
+}
+
+BOOST_FORCEINLINE path path::filename() const
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::filename)(*this);
+}
+
+BOOST_FORCEINLINE path path::stem() const
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::stem)(*this);
+}
+
+BOOST_FORCEINLINE path path::extension() const
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::extension)(*this);
+}
+
+BOOST_FORCEINLINE bool path::has_filename() const
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::has_filename)(*this);
+}
+
+BOOST_FORCEINLINE path path::lexically_normal() const
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::lexically_normal)(*this);
+}
+
+BOOST_FORCEINLINE path path::generic_path() const
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::generic_path)(*this);
+}
+
+BOOST_FORCEINLINE path& path::make_preferred()
+{
+ // No effect on POSIX
+#if defined(BOOST_WINDOWS_API)
+ BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::make_preferred)(*this);
+#endif
+ return *this;
+}
+
+namespace path_detail {
+
+BOOST_FORCEINLINE void path_iterator::increment()
+{
+ BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::increment)(*this);
+}
+
+BOOST_FORCEINLINE void path_iterator::decrement()
+{
+ BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::decrement)(*this);
+}
+
+BOOST_FORCEINLINE bool lexicographical_compare(path_iterator first1, path_iterator const& last1, path_iterator first2, path_iterator const& last2)
+{
+ return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::lex_compare)(first1, last1, first2, last2) < 0;
+}
+
+} // namespace path_detail
+
+#endif // !defined(BOOST_FILESYSTEM_SOURCE)
+
+//--------------------------------------------------------------------------------------//
+// class path member template specializations //
+//--------------------------------------------------------------------------------------//
+
+template< >
+inline std::string path::string< std::string >() const
+{
+ return string();
+}
+
+template< >
+inline std::wstring path::string< std::wstring >() const
+{
+ return wstring();
+}
+
+template< >
+inline std::string path::string< std::string >(codecvt_type const& cvt) const
+{
+ return string(cvt);
+}
+
+template< >
+inline std::wstring path::string< std::wstring >(codecvt_type const& cvt) const
+{
+ return wstring(cvt);
+}
+
+template< >
+inline std::string path::generic_string< std::string >() const
+{
+ return generic_string();
+}
+
+template< >
+inline std::wstring path::generic_string< std::wstring >() const
+{
+ return generic_wstring();
+}
+
+template< >
+inline std::string path::generic_string< std::string >(codecvt_type const& cvt) const
+{
+ return generic_string(cvt);
+}
+
+template< >
+inline std::wstring path::generic_string< std::wstring >(codecvt_type const& cvt) const
+{
+ return generic_wstring(cvt);
+}
+
+} // namespace filesystem
+} // namespace boost
+
+//----------------------------------------------------------------------------//
+
+#include <boost/filesystem/detail/footer.hpp>
+
+#endif // BOOST_FILESYSTEM_PATH_HPP
diff --git a/contrib/restricted/boost/filesystem/src/atomic_ref.hpp b/contrib/restricted/boost/filesystem/src/atomic_ref.hpp
new file mode 100644
index 0000000000..6e8208d39e
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/atomic_ref.hpp
@@ -0,0 +1,32 @@
+// atomic.hpp ------------------------------------------------------------------------//
+
+// Copyright 2021 Andrey Semashev
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// See library home page at http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#ifndef BOOST_FILESYSTEM_SRC_ATOMIC_REF_HPP_
+#define BOOST_FILESYSTEM_SRC_ATOMIC_REF_HPP_
+
+#include <boost/filesystem/config.hpp>
+
+#if !defined(BOOST_FILESYSTEM_NO_CXX20_ATOMIC_REF)
+
+#include <atomic>
+
+namespace atomic_ns = std;
+
+#else // !defined(BOOST_FILESYSTEM_NO_CXX20_ATOMIC_REF)
+
+#include <boost/memory_order.hpp>
+#include <boost/atomic/atomic_ref.hpp>
+
+namespace atomic_ns = boost;
+
+#endif // !defined(BOOST_FILESYSTEM_NO_CXX20_ATOMIC_REF)
+
+#endif // BOOST_FILESYSTEM_SRC_ATOMIC_REF_HPP_
diff --git a/contrib/restricted/boost/filesystem/src/atomic_tools.hpp b/contrib/restricted/boost/filesystem/src/atomic_tools.hpp
new file mode 100644
index 0000000000..a60e5d325a
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/atomic_tools.hpp
@@ -0,0 +1,69 @@
+// atomic_tools.hpp ------------------------------------------------------------------//
+
+// Copyright 2021 Andrey Semashev
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// See library home page at http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#ifndef BOOST_FILESYSTEM_SRC_ATOMIC_TOOLS_HPP_
+#define BOOST_FILESYSTEM_SRC_ATOMIC_TOOLS_HPP_
+
+#include <boost/filesystem/config.hpp>
+
+#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+
+#include "atomic_ref.hpp"
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+//! Atomically loads the value
+template< typename T >
+BOOST_FORCEINLINE T atomic_load_relaxed(T& a)
+{
+ return atomic_ns::atomic_ref< T >(a).load(atomic_ns::memory_order_relaxed);
+}
+
+//! Atomically stores the value
+template< typename T >
+BOOST_FORCEINLINE void atomic_store_relaxed(T& a, T val)
+{
+ atomic_ns::atomic_ref< T >(a).store(val, atomic_ns::memory_order_relaxed);
+}
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+//! Atomically loads the value
+template< typename T >
+BOOST_FORCEINLINE T atomic_load_relaxed(T const& a)
+{
+ return a;
+}
+
+//! Atomically stores the value
+template< typename T >
+BOOST_FORCEINLINE void atomic_store_relaxed(T& a, T val)
+{
+ a = val;
+}
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+
+#endif // BOOST_FILESYSTEM_SRC_ATOMIC_TOOLS_HPP_
diff --git a/contrib/restricted/boost/filesystem/src/codecvt_error_category.cpp b/contrib/restricted/boost/filesystem/src/codecvt_error_category.cpp
new file mode 100644
index 0000000000..dc3df54d36
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/codecvt_error_category.cpp
@@ -0,0 +1,120 @@
+// codecvt_error_category implementation file ----------------------------------------//
+
+// Copyright 2009 Beman Dawes
+// Copyright 2022 Andrey Semashev
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt)
+
+// Library home page at http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#include "platform_config.hpp"
+
+#include <boost/config/warning_disable.hpp>
+
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/detail/path_traits.hpp>
+#include <boost/system/error_category.hpp>
+#include <locale>
+#include <string>
+
+#include "private_config.hpp"
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+//--------------------------------------------------------------------------------------//
+
+namespace boost {
+namespace filesystem {
+
+namespace {
+
+#if (defined(BOOST_GCC) && BOOST_GCC >= 40600) || defined(BOOST_CLANG)
+#pragma GCC diagnostic push
+// '(anonymous namespace)::codecvt_error_cat' has virtual functions but non-virtual destructor
+// This is not a problem as instances of codecvt_error_cat are never destroyed through a pointer to base.
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
+class codecvt_error_cat final :
+ public boost::system::error_category
+{
+public:
+ // clang up to version 3.8 requires a user-defined default constructor in order to be able to declare a static constant of the error category.
+ BOOST_SYSTEM_CONSTEXPR codecvt_error_cat() noexcept {}
+ const char* name() const noexcept override;
+ std::string message(int ev) const override;
+};
+
+const char* codecvt_error_cat::name() const noexcept
+{
+ return "codecvt";
+}
+
+std::string codecvt_error_cat::message(int ev) const
+{
+ std::string str;
+ switch (ev)
+ {
+ case std::codecvt_base::ok:
+ str = "ok";
+ break;
+ case std::codecvt_base::partial:
+ str = "partial";
+ break;
+ case std::codecvt_base::error:
+ str = "error";
+ break;
+ case std::codecvt_base::noconv:
+ str = "noconv";
+ break;
+ default:
+ str = "unknown error";
+ break;
+ }
+ return str;
+}
+
+#if (defined(BOOST_GCC) && BOOST_GCC >= 40600) || defined(BOOST_CLANG)
+#pragma GCC diagnostic pop
+#endif
+
+} // unnamed namespace
+
+BOOST_FILESYSTEM_DECL boost::system::error_category const& codecvt_error_category() noexcept
+{
+ static
+#if defined(BOOST_SYSTEM_HAS_CONSTEXPR)
+ constexpr
+#else
+ const
+#endif
+ codecvt_error_cat codecvt_error_cat_const;
+ return codecvt_error_cat_const;
+}
+
+// Try to initialize the error category instance as early as possible to make sure it is
+// available during global deinitialization stage. For MSVC, codecvt_error_category() will
+// be called early by MSVC-specific initialization routine in path.cpp.
+#if !defined(BOOST_SYSTEM_HAS_CONSTEXPR) && !defined(_MSC_VER)
+
+namespace {
+
+struct codecvt_error_category_initializer
+{
+ codecvt_error_category_initializer() { boost::filesystem::codecvt_error_category(); }
+};
+
+BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN
+const codecvt_error_category_initializer g_codecvt_error_category_initializer;
+
+} // namespace
+
+#endif // !defined(BOOST_SYSTEM_HAS_CONSTEXPR) && !defined(_MSC_VER)
+
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
diff --git a/contrib/restricted/boost/filesystem/src/directory.cpp b/contrib/restricted/boost/filesystem/src/directory.cpp
new file mode 100644
index 0000000000..576a460dd3
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/directory.cpp
@@ -0,0 +1,1772 @@
+// directory.cpp --------------------------------------------------------------------//
+
+// Copyright 2002-2009, 2014 Beman Dawes
+// Copyright 2001 Dietmar Kuehl
+// Copyright 2019, 2022-2024 Andrey Semashev
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// See library home page at http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#include "platform_config.hpp"
+
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/directory.hpp>
+#include <boost/filesystem/exception.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/file_status.hpp>
+
+#include <cstddef>
+#include <cerrno>
+#include <cstring>
+#include <cstdlib> // std::malloc, std::free
+#include <new> // std::nothrow, std::bad_alloc
+#include <limits>
+#include <string>
+#include <utility> // std::move
+#include <boost/assert.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/smart_ptr/intrusive_ptr.hpp>
+
+#ifdef BOOST_POSIX_API
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <memory>
+#include <boost/scope/unique_fd.hpp>
+
+#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS >= 0) && defined(_SC_THREAD_SAFE_FUNCTIONS) && \
+ !defined(__CYGWIN__) && \
+ !(defined(linux) || defined(__linux) || defined(__linux__)) && \
+ !defined(__ANDROID__) && \
+ (!defined(__hpux) || defined(_REENTRANT)) && \
+ (!defined(_AIX) || defined(__THREAD_SAFE)) && \
+ !defined(__wasm)
+#define BOOST_FILESYSTEM_USE_READDIR_R
+#endif
+
+// At least Mac OS X 10.6 and older doesn't support O_CLOEXEC
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#define BOOST_FILESYSTEM_NO_O_CLOEXEC
+#endif
+
+#include "posix_tools.hpp"
+
+#else // BOOST_WINDOWS_API
+
+#include <cwchar>
+#include <windows.h>
+#include <boost/winapi/basic_types.hpp> // NTSTATUS_
+
+#include "windows_tools.hpp"
+
+#endif // BOOST_WINDOWS_API
+
+#include "atomic_tools.hpp"
+#include "error_handling.hpp"
+#include "private_config.hpp"
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace fs = boost::filesystem;
+using boost::system::error_code;
+using boost::system::system_category;
+
+namespace boost {
+namespace filesystem {
+
+//--------------------------------------------------------------------------------------//
+// //
+// directory_entry //
+// //
+//--------------------------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL void directory_entry::refresh_impl(system::error_code* ec) const
+{
+ m_status = filesystem::file_status();
+ m_symlink_status = filesystem::file_status();
+
+ m_symlink_status = detail::symlink_status(m_path, ec);
+
+ if (!filesystem::is_symlink(m_symlink_status))
+ {
+ // Also works if symlink_status fails - set m_status to status_error as well
+ m_status = m_symlink_status;
+ }
+ else
+ {
+ m_status = detail::status(m_path, ec);
+ }
+}
+
+//--------------------------------------------------------------------------------------//
+// //
+// directory_iterator //
+// //
+//--------------------------------------------------------------------------------------//
+
+namespace detail {
+
+#if defined(BOOST_POSIX_API)
+
+//! Opens a directory file and returns a file descriptor. Returns a negative value in case of error.
+boost::scope::unique_fd open_directory(path const& p, directory_options opts, system::error_code& ec)
+{
+ ec.clear();
+
+ int flags = O_DIRECTORY | O_RDONLY | O_NONBLOCK | O_CLOEXEC;
+
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+ if ((opts & directory_options::_detail_no_follow) != directory_options::none)
+ flags |= O_NOFOLLOW;
+#endif
+
+ int res;
+ while (true)
+ {
+ res = ::open(p.c_str(), flags);
+ if (BOOST_UNLIKELY(res < 0))
+ {
+ const int err = errno;
+ if (err == EINTR)
+ continue;
+ ec = system::error_code(err, system::system_category());
+ return boost::scope::unique_fd();
+ }
+
+ break;
+ }
+
+#if defined(BOOST_FILESYSTEM_NO_O_CLOEXEC) && defined(FD_CLOEXEC)
+ boost::scope::unique_fd fd(res);
+
+ res = ::fcntl(fd.get(), F_SETFD, FD_CLOEXEC);
+ if (BOOST_UNLIKELY(res < 0))
+ {
+ const int err = errno;
+ ec = system::error_code(err, system::system_category());
+ return boost::scope::unique_fd();
+ }
+
+ return fd;
+#else
+ return boost::scope::unique_fd(res);
+#endif
+}
+
+#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+
+//! Opens a directory file and returns a file descriptor. Returns a negative value in case of error.
+boost::scope::unique_fd openat_directory(int basedir_fd, path const& p, directory_options opts, system::error_code& ec)
+{
+ ec.clear();
+
+ int flags = O_DIRECTORY | O_RDONLY | O_NONBLOCK | O_CLOEXEC;
+
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+ if ((opts & directory_options::_detail_no_follow) != directory_options::none)
+ flags |= O_NOFOLLOW;
+#endif
+
+ int res;
+ while (true)
+ {
+ res = ::openat(basedir_fd, p.c_str(), flags);
+ if (BOOST_UNLIKELY(res < 0))
+ {
+ const int err = errno;
+ if (err == EINTR)
+ continue;
+ ec = system::error_code(err, system::system_category());
+ return boost::scope::unique_fd();
+ }
+
+ break;
+ }
+
+#if defined(BOOST_FILESYSTEM_NO_O_CLOEXEC) && defined(FD_CLOEXEC)
+ boost::scope::unique_fd fd(res);
+
+ res = ::fcntl(fd.get(), F_SETFD, FD_CLOEXEC);
+ if (BOOST_UNLIKELY(res < 0))
+ {
+ const int err = errno;
+ ec = system::error_code(err, system::system_category());
+ return boost::scope::unique_fd();
+ }
+
+ return fd;
+#else
+ return boost::scope::unique_fd(res);
+#endif
+}
+
+#endif // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+
+#endif // defined(BOOST_POSIX_API)
+
+BOOST_CONSTEXPR_OR_CONST std::size_t dir_itr_imp_extra_data_alignment = 16u;
+
+BOOST_FILESYSTEM_DECL void* dir_itr_imp::operator new(std::size_t class_size, std::size_t extra_size) noexcept
+{
+ if (extra_size > 0)
+ class_size = (class_size + dir_itr_imp_extra_data_alignment - 1u) & ~(dir_itr_imp_extra_data_alignment - 1u);
+ std::size_t total_size = class_size + extra_size;
+
+ // Return nullptr on OOM
+ void* p = std::malloc(total_size);
+ if (BOOST_LIKELY(p != nullptr))
+ std::memset(p, 0, total_size);
+ return p;
+}
+
+BOOST_FILESYSTEM_DECL void dir_itr_imp::operator delete(void* p, std::size_t extra_size) noexcept
+{
+ std::free(p);
+}
+
+BOOST_FILESYSTEM_DECL void dir_itr_imp::operator delete(void* p) noexcept
+{
+ std::free(p);
+}
+
+namespace {
+
+inline void* get_dir_itr_imp_extra_data(dir_itr_imp* imp) noexcept
+{
+ BOOST_CONSTEXPR_OR_CONST std::size_t extra_data_offset = (sizeof(dir_itr_imp) + dir_itr_imp_extra_data_alignment - 1u) & ~(dir_itr_imp_extra_data_alignment - 1u);
+ return reinterpret_cast< unsigned char* >(imp) + extra_data_offset;
+}
+
+#ifdef BOOST_POSIX_API
+
+inline system::error_code dir_itr_close(dir_itr_imp& imp) noexcept
+{
+ if (imp.handle != nullptr)
+ {
+ DIR* h = static_cast< DIR* >(imp.handle);
+ imp.handle = nullptr;
+ int err = 0;
+ if (BOOST_UNLIKELY(::closedir(h) != 0))
+ {
+ err = errno;
+ return system::error_code(err, system::system_category());
+ }
+ }
+
+ return error_code();
+}
+
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+
+// Obtains a file descriptor from the directory iterator
+inline int dir_itr_fd(dir_itr_imp const& imp, system::error_code& ec)
+{
+ int fd = ::dirfd(static_cast< DIR* >(imp.handle));
+ if (BOOST_UNLIKELY(fd < 0))
+ {
+ int err = errno;
+ ec = system::error_code(err, system::system_category());
+ }
+
+ return fd;
+}
+
+#endif // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+
+#if defined(BOOST_FILESYSTEM_USE_READDIR_R)
+
+// Obtains maximum length of a path, not including the terminating zero
+inline std::size_t get_path_max()
+{
+ // this code is based on Stevens and Rago, Advanced Programming in the
+ // UNIX envirnment, 2nd Ed., ISBN 0-201-43307-9, page 49
+ std::size_t max = 0;
+ errno = 0;
+ long res = ::pathconf("/", _PC_PATH_MAX);
+ if (res < 0)
+ {
+#if defined(PATH_MAX)
+ max = PATH_MAX;
+#else
+ max = 4096;
+#endif
+ }
+ else
+ {
+ max = static_cast< std::size_t >(res); // relative root
+#if defined(PATH_MAX)
+ if (max < PATH_MAX)
+ max = PATH_MAX;
+#endif
+ }
+
+ if ((max + 1) < sizeof(dirent().d_name))
+ max = sizeof(dirent().d_name) - 1;
+
+ return max;
+}
+
+// Returns maximum length of a path, not including the terminating zero
+inline std::size_t path_max()
+{
+ static const std::size_t max = get_path_max();
+ return max;
+}
+
+#endif // BOOST_FILESYSTEM_USE_READDIR_R
+
+// *result set to nullptr on end of directory
+#if !defined(BOOST_FILESYSTEM_USE_READDIR_R)
+inline
+#endif
+int readdir_impl(dir_itr_imp& imp, struct dirent** result)
+{
+ errno = 0;
+
+ struct dirent* p = ::readdir(static_cast< DIR* >(imp.handle));
+ *result = p;
+ if (!p)
+ return errno;
+ return 0;
+}
+
+#if !defined(BOOST_FILESYSTEM_USE_READDIR_R)
+
+inline int invoke_readdir(dir_itr_imp& imp, struct dirent** result)
+{
+ return readdir_impl(imp, result);
+}
+
+#else // !defined(BOOST_FILESYSTEM_USE_READDIR_R)
+
+int readdir_r_impl(dir_itr_imp& imp, struct dirent** result)
+{
+ return ::readdir_r
+ (
+ static_cast< DIR* >(imp.handle),
+ static_cast< struct dirent* >(get_dir_itr_imp_extra_data(&imp)),
+ result
+ );
+}
+
+int readdir_select_impl(dir_itr_imp& imp, struct dirent** result);
+
+typedef int readdir_impl_t(dir_itr_imp& imp, struct dirent** result);
+
+//! Pointer to the actual implementation of the copy_file_data implementation
+readdir_impl_t* readdir_impl_ptr = &readdir_select_impl;
+
+void init_readdir_impl()
+{
+ readdir_impl_t* impl = &readdir_impl;
+ if (::sysconf(_SC_THREAD_SAFE_FUNCTIONS) >= 0)
+ impl = &readdir_r_impl;
+
+ filesystem::detail::atomic_store_relaxed(readdir_impl_ptr, impl);
+}
+
+struct readdir_initializer
+{
+ readdir_initializer()
+ {
+ init_readdir_impl();
+ }
+};
+
+BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN
+const readdir_initializer readdir_init;
+
+int readdir_select_impl(dir_itr_imp& imp, struct dirent** result)
+{
+ init_readdir_impl();
+ return filesystem::detail::atomic_load_relaxed(readdir_impl_ptr)(imp, result);
+}
+
+inline int invoke_readdir(dir_itr_imp& imp, struct dirent** result)
+{
+ return filesystem::detail::atomic_load_relaxed(readdir_impl_ptr)(imp, result);
+}
+
+#endif // !defined(BOOST_FILESYSTEM_USE_READDIR_R)
+
+system::error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_status& sf, fs::file_status& symlink_sf)
+{
+ dirent* result = nullptr;
+ int err = invoke_readdir(imp, &result);
+ if (BOOST_UNLIKELY(err != 0))
+ return system::error_code(err, system::system_category());
+ if (result == nullptr)
+ return dir_itr_close(imp);
+
+ filename = result->d_name;
+
+#if defined(BOOST_FILESYSTEM_HAS_DIRENT_D_TYPE)
+ if (result->d_type == DT_UNKNOWN) // filesystem does not supply d_type value
+ {
+ sf = symlink_sf = fs::file_status(fs::status_error);
+ }
+ else // filesystem supplies d_type value
+ {
+ if (result->d_type == DT_REG)
+ sf = symlink_sf = fs::file_status(fs::regular_file);
+ else if (result->d_type == DT_DIR)
+ sf = symlink_sf = fs::file_status(fs::directory_file);
+ else if (result->d_type == DT_LNK)
+ {
+ sf = fs::file_status(fs::status_error);
+ symlink_sf = fs::file_status(fs::symlink_file);
+ }
+ else
+ {
+ switch (result->d_type)
+ {
+ case DT_SOCK:
+ sf = symlink_sf = fs::file_status(fs::socket_file);
+ break;
+ case DT_FIFO:
+ sf = symlink_sf = fs::file_status(fs::fifo_file);
+ break;
+ case DT_BLK:
+ sf = symlink_sf = fs::file_status(fs::block_file);
+ break;
+ case DT_CHR:
+ sf = symlink_sf = fs::file_status(fs::character_file);
+ break;
+ default:
+ sf = symlink_sf = fs::file_status(fs::status_error);
+ break;
+ }
+ }
+ }
+#else
+ sf = symlink_sf = fs::file_status(fs::status_error);
+#endif
+ return system::error_code();
+}
+
+system::error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::path const& dir, directory_options opts, directory_iterator_params* params, fs::path& first_filename, fs::file_status&, fs::file_status&)
+{
+ std::size_t extra_size = 0u;
+#if defined(BOOST_FILESYSTEM_USE_READDIR_R)
+ {
+ readdir_impl_t* rdimpl = filesystem::detail::atomic_load_relaxed(readdir_impl_ptr);
+ if (BOOST_UNLIKELY(rdimpl == &readdir_select_impl))
+ {
+ init_readdir_impl();
+ rdimpl = filesystem::detail::atomic_load_relaxed(readdir_impl_ptr);
+ }
+
+ if (rdimpl == &readdir_r_impl)
+ {
+ // According to readdir description, there's no reliable way to predict the length of the d_name string.
+ // It may exceed NAME_MAX and pathconf(_PC_NAME_MAX) limits. We are being conservative here and allocate
+ // buffer that is enough for PATH_MAX as the directory name. Still, this doesn't guarantee there won't be
+ // a buffer overrun. The readdir_r API is fundamentally flawed and we should avoid it as much as possible
+ // in favor of readdir.
+ extra_size = (sizeof(dirent) - sizeof(dirent().d_name)) + path_max() + 1u; // + 1 for "\0"
+ }
+ }
+#endif // defined(BOOST_FILESYSTEM_USE_READDIR_R)
+
+ boost::intrusive_ptr< detail::dir_itr_imp > pimpl(new (extra_size) detail::dir_itr_imp());
+ if (BOOST_UNLIKELY(!pimpl))
+ return make_error_code(system::errc::not_enough_memory);
+
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+ boost::scope::unique_fd fd;
+ if (params && params->dir_fd)
+ {
+ fd = std::move(params->dir_fd);
+ }
+ else
+ {
+ system::error_code ec;
+ fd = open_directory(dir, opts, ec);
+ if (BOOST_UNLIKELY(!!ec))
+ return ec;
+ }
+
+ pimpl->handle = ::fdopendir(fd.get());
+ if (BOOST_UNLIKELY(!pimpl->handle))
+ {
+ const int err = errno;
+ return system::error_code(err, system::system_category());
+ }
+
+ // At this point fd will be closed by closedir
+ fd.release();
+#else // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+ pimpl->handle = ::opendir(dir.c_str());
+ if (BOOST_UNLIKELY(!pimpl->handle))
+ {
+ const int err = errno;
+ return system::error_code(err, system::system_category());
+ }
+#endif // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+
+ // Force initial readdir call by the caller. This will initialize the actual first filename and statuses.
+ first_filename.assign(".");
+
+ imp.swap(pimpl);
+ return system::error_code();
+}
+
+BOOST_CONSTEXPR_OR_CONST err_t not_found_error_code = ENOENT;
+
+#else // BOOST_WINDOWS_API
+
+inline void set_file_statuses(DWORD attrs, const ULONG* reparse_point_tag, fs::path const& filename, fs::file_status& sf, fs::file_status& symlink_sf)
+{
+ if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u)
+ {
+ // Reparse points are complex, so don't try to resolve them here; instead just mark
+ // them as status_error which causes directory_entry caching to call status()
+ // and symlink_status() which do handle reparse points fully
+ if (reparse_point_tag)
+ {
+ // If we have a reparse point tag we can at least populate the symlink status,
+ // consistent with symlink_status() behavior
+ symlink_sf.type(is_reparse_point_tag_a_symlink(*reparse_point_tag) ? fs::symlink_file : fs::reparse_file);
+ symlink_sf.permissions(make_permissions(filename, attrs));
+ }
+ else
+ {
+ symlink_sf.type(fs::status_error);
+ }
+
+ sf.type(fs::status_error);
+ }
+ else
+ {
+ if ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0u)
+ {
+ sf.type(fs::directory_file);
+ symlink_sf.type(fs::directory_file);
+ }
+ else
+ {
+ sf.type(fs::regular_file);
+ symlink_sf.type(fs::regular_file);
+ }
+
+ sf.permissions(make_permissions(filename, attrs));
+ symlink_sf.permissions(sf.permissions());
+ }
+}
+
+//! FILE_ID_128 definition from Windows SDK
+struct file_id_128
+{
+ BYTE Identifier[16];
+};
+
+//! FILE_DIRECTORY_INFORMATION definition from Windows DDK. Used by NtQueryDirectoryFile, supported since Windows NT 4.0 (probably).
+struct file_directory_information
+{
+ ULONG NextEntryOffset;
+ ULONG FileIndex;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER EndOfFile;
+ LARGE_INTEGER AllocationSize;
+ ULONG FileAttributes;
+ ULONG FileNameLength;
+ WCHAR FileName[1];
+};
+
+//! FILE_ID_BOTH_DIR_INFO definition from Windows SDK. Basic support for directory iteration using GetFileInformationByHandleEx, supported since Windows Vista.
+struct file_id_both_dir_info
+{
+ DWORD NextEntryOffset;
+ DWORD FileIndex;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER EndOfFile;
+ LARGE_INTEGER AllocationSize;
+ DWORD FileAttributes;
+ DWORD FileNameLength;
+ DWORD EaSize;
+ CCHAR ShortNameLength;
+ WCHAR ShortName[12];
+ LARGE_INTEGER FileId;
+ WCHAR FileName[1];
+};
+
+//! FILE_FULL_DIR_INFO definition from Windows SDK. More lightweight than FILE_ID_BOTH_DIR_INFO, supported since Windows 8.
+struct file_full_dir_info
+{
+ ULONG NextEntryOffset;
+ ULONG FileIndex;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER EndOfFile;
+ LARGE_INTEGER AllocationSize;
+ ULONG FileAttributes;
+ ULONG FileNameLength;
+ ULONG EaSize;
+ WCHAR FileName[1];
+};
+
+//! FILE_ID_EXTD_DIR_INFO definition from Windows SDK. Provides reparse point tag, which saves us querying it with a few separate syscalls. Supported since Windows 8.
+struct file_id_extd_dir_info
+{
+ ULONG NextEntryOffset;
+ ULONG FileIndex;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER EndOfFile;
+ LARGE_INTEGER AllocationSize;
+ ULONG FileAttributes;
+ ULONG FileNameLength;
+ ULONG EaSize;
+ ULONG ReparsePointTag;
+ file_id_128 FileId;
+ WCHAR FileName[1];
+};
+
+//! Indicates format of the extra data in the directory iterator
+enum extra_data_format
+{
+ file_directory_information_format,
+ file_id_both_dir_info_format,
+ file_full_dir_info_format,
+ file_id_extd_dir_info_format
+};
+
+//! Indicates extra data format that should be used by directory iterator by default
+extra_data_format g_extra_data_format = file_directory_information_format;
+
+/*!
+ * \brief Extra buffer size for GetFileInformationByHandleEx-based or NtQueryDirectoryFile-based directory iterator.
+ *
+ * Must be large enough to accommodate at least one FILE_DIRECTORY_INFORMATION or *_DIR_INFO struct and one filename.
+ * NTFS, VFAT, exFAT and ReFS support filenames up to 255 UTF-16/UCS-2 characters. (For ReFS, there is no information
+ * on the on-disk format, and it is possible that it supports longer filenames, up to 32768 UTF-16/UCS-2 characters.)
+ * The buffer cannot be larger than 64k, otherwise up to Windows 8.1, NtQueryDirectoryFile and GetFileInformationByHandleEx
+ * fail with ERROR_INVALID_PARAMETER when trying to retrieve filenames from a network share.
+ */
+BOOST_CONSTEXPR_OR_CONST std::size_t dir_itr_extra_size = 65536u;
+
+inline system::error_code dir_itr_close(dir_itr_imp& imp) noexcept
+{
+ imp.extra_data_format = 0u;
+ imp.current_offset = 0u;
+
+ if (imp.handle != nullptr)
+ {
+ if (BOOST_LIKELY(imp.close_handle))
+ ::CloseHandle(imp.handle);
+ imp.handle = nullptr;
+ }
+
+ return error_code();
+}
+
+system::error_code dir_itr_increment(dir_itr_imp& imp, fs::path& filename, fs::file_status& sf, fs::file_status& symlink_sf)
+{
+ void* extra_data = get_dir_itr_imp_extra_data(&imp);
+ const void* current_data = static_cast< const unsigned char* >(extra_data) + imp.current_offset;
+ switch (imp.extra_data_format)
+ {
+ case file_id_extd_dir_info_format:
+ {
+ const file_id_extd_dir_info* data = static_cast< const file_id_extd_dir_info* >(current_data);
+ if (data->NextEntryOffset == 0u)
+ {
+ if (!filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api)(imp.handle, file_id_extd_directory_info_class, extra_data, dir_itr_extra_size))
+ {
+ DWORD error = ::GetLastError();
+
+ dir_itr_close(imp);
+ if (error == ERROR_NO_MORE_FILES)
+ goto done;
+
+ return system::error_code(error, system::system_category());
+ }
+
+ imp.current_offset = 0u;
+ data = static_cast< const file_id_extd_dir_info* >(extra_data);
+ }
+ else
+ {
+ imp.current_offset += data->NextEntryOffset;
+ data = reinterpret_cast< const file_id_extd_dir_info* >(static_cast< const unsigned char* >(current_data) + data->NextEntryOffset);
+ }
+
+ filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR));
+ set_file_statuses(data->FileAttributes, &data->ReparsePointTag, filename, sf, symlink_sf);
+ }
+ break;
+
+ case file_full_dir_info_format:
+ {
+ const file_full_dir_info* data = static_cast< const file_full_dir_info* >(current_data);
+ if (data->NextEntryOffset == 0u)
+ {
+ if (!filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api)(imp.handle, file_full_directory_info_class, extra_data, dir_itr_extra_size))
+ {
+ DWORD error = ::GetLastError();
+
+ dir_itr_close(imp);
+ if (error == ERROR_NO_MORE_FILES)
+ goto done;
+
+ return system::error_code(error, system::system_category());
+ }
+
+ imp.current_offset = 0u;
+ data = static_cast< const file_full_dir_info* >(extra_data);
+ }
+ else
+ {
+ imp.current_offset += data->NextEntryOffset;
+ data = reinterpret_cast< const file_full_dir_info* >(static_cast< const unsigned char* >(current_data) + data->NextEntryOffset);
+ }
+
+ filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR));
+ set_file_statuses(data->FileAttributes, nullptr, filename, sf, symlink_sf);
+ }
+ break;
+
+ case file_id_both_dir_info_format:
+ {
+ const file_id_both_dir_info* data = static_cast< const file_id_both_dir_info* >(current_data);
+ if (data->NextEntryOffset == 0u)
+ {
+ if (!filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api)(imp.handle, file_id_both_directory_info_class, extra_data, dir_itr_extra_size))
+ {
+ DWORD error = ::GetLastError();
+
+ dir_itr_close(imp);
+ if (error == ERROR_NO_MORE_FILES)
+ goto done;
+
+ return system::error_code(error, system::system_category());
+ }
+
+ imp.current_offset = 0u;
+ data = static_cast< const file_id_both_dir_info* >(extra_data);
+ }
+ else
+ {
+ imp.current_offset += data->NextEntryOffset;
+ data = reinterpret_cast< const file_id_both_dir_info* >(static_cast< const unsigned char* >(current_data) + data->NextEntryOffset);
+ }
+
+ filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR));
+ set_file_statuses(data->FileAttributes, nullptr, filename, sf, symlink_sf);
+ }
+ break;
+
+ default:
+ {
+ const file_directory_information* data = static_cast< const file_directory_information* >(current_data);
+ if (data->NextEntryOffset == 0u)
+ {
+ io_status_block iosb;
+ boost::winapi::NTSTATUS_ status = filesystem::detail::atomic_load_relaxed(nt_query_directory_file_api)
+ (
+ imp.handle,
+ nullptr, // Event
+ nullptr, // ApcRoutine
+ nullptr, // ApcContext
+ &iosb,
+ extra_data,
+ dir_itr_extra_size,
+ file_directory_information_class,
+ FALSE, // ReturnSingleEntry
+ nullptr, // FileName
+ FALSE // RestartScan
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ dir_itr_close(imp);
+ if (status == STATUS_NO_MORE_FILES)
+ goto done;
+
+ return system::error_code(translate_ntstatus(status), system::system_category());
+ }
+
+ imp.current_offset = 0u;
+ data = static_cast< const file_directory_information* >(extra_data);
+ }
+ else
+ {
+ imp.current_offset += data->NextEntryOffset;
+ data = reinterpret_cast< const file_directory_information* >(static_cast< const unsigned char* >(current_data) + data->NextEntryOffset);
+ }
+
+ filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR));
+ set_file_statuses(data->FileAttributes, nullptr, filename, sf, symlink_sf);
+ }
+ break;
+ }
+
+done:
+ return system::error_code();
+}
+
+//! Returns \c true if the error code indicates that the OS or the filesystem does not support a particular directory info class
+inline bool is_dir_info_class_not_supported(DWORD error)
+{
+ // Some mounted filesystems may not support FILE_ID_128 identifiers, which will cause
+ // GetFileInformationByHandleEx(FileIdExtdDirectoryRestartInfo) return ERROR_INVALID_PARAMETER,
+ // even though in general the operation is supported by the kernel. SMBv1 returns a special error
+ // code ERROR_INVALID_LEVEL in this case.
+ // Some other filesystems also don't implement other info classes and return ERROR_INVALID_PARAMETER
+ // (e.g. see https://github.com/boostorg/filesystem/issues/266), ERROR_GEN_FAILURE, ERROR_INVALID_FUNCTION
+ // or ERROR_INTERNAL_ERROR (https://github.com/boostorg/filesystem/issues/286). Treat these error codes
+ // as "non-permanent", even though ERROR_INVALID_PARAMETER is also returned if GetFileInformationByHandleEx
+ // in general does not support a certain info class. Worst case, we will make extra syscalls on directory
+ // iterator construction.
+ // Also note that Wine returns ERROR_CALL_NOT_IMPLEMENTED for unimplemented info classes, and
+ // up until 7.21 it didn't implement FileIdExtdDirectoryRestartInfo and FileFullDirectoryRestartInfo.
+ // (https://bugs.winehq.org/show_bug.cgi?id=53590)
+ return error == ERROR_NOT_SUPPORTED || error == ERROR_INVALID_PARAMETER ||
+ error == ERROR_INVALID_LEVEL || error == ERROR_CALL_NOT_IMPLEMENTED ||
+ error == ERROR_GEN_FAILURE || error == ERROR_INVALID_FUNCTION ||
+ error == ERROR_INTERNAL_ERROR;
+}
+
+system::error_code dir_itr_create(boost::intrusive_ptr< detail::dir_itr_imp >& imp, fs::path const& dir, directory_options opts, directory_iterator_params* params, fs::path& first_filename, fs::file_status& sf, fs::file_status& symlink_sf)
+{
+ boost::intrusive_ptr< detail::dir_itr_imp > pimpl(new (dir_itr_extra_size) detail::dir_itr_imp());
+ if (BOOST_UNLIKELY(!pimpl))
+ return make_error_code(system::errc::not_enough_memory);
+
+ GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api);
+
+ unique_handle h;
+ HANDLE iterator_handle;
+ bool close_handle = true;
+ if (params != nullptr && params->dir_handle != INVALID_HANDLE_VALUE)
+ {
+ // Operate on externally provided handle, which must be a directory handle
+ iterator_handle = params->dir_handle;
+ close_handle = params->close_handle;
+ }
+ else
+ {
+ DWORD flags = FILE_FLAG_BACKUP_SEMANTICS;
+ if ((opts & directory_options::_detail_no_follow) != directory_options::none)
+ flags |= FILE_FLAG_OPEN_REPARSE_POINT;
+
+ h = create_file_handle(dir, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, flags);
+ if (BOOST_UNLIKELY(!h))
+ {
+ return_last_error:
+ DWORD error = ::GetLastError();
+ return system::error_code(error, system::system_category());
+ }
+
+ iterator_handle = h.get();
+
+ if (BOOST_LIKELY(get_file_information_by_handle_ex != nullptr))
+ {
+ file_attribute_tag_info info;
+ BOOL res = get_file_information_by_handle_ex(iterator_handle, file_attribute_tag_info_class, &info, sizeof(info));
+ if (BOOST_UNLIKELY(!res))
+ {
+ // On FAT/exFAT filesystems requesting FILE_ATTRIBUTE_TAG_INFO returns ERROR_INVALID_PARAMETER. See the comment in symlink_status.
+ DWORD error = ::GetLastError();
+ if (error == ERROR_INVALID_PARAMETER || error == ERROR_NOT_SUPPORTED)
+ goto use_get_file_information_by_handle;
+
+ return system::error_code(error, system::system_category());
+ }
+
+ if (BOOST_UNLIKELY((info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0u))
+ return make_error_code(system::errc::not_a_directory);
+
+ if ((opts & directory_options::_detail_no_follow) != directory_options::none)
+ {
+ if ((info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u && is_reparse_point_tag_a_symlink(info.ReparseTag))
+ return make_error_code(system::errc::too_many_symbolic_link_levels);
+ }
+ }
+ else
+ {
+ use_get_file_information_by_handle:
+ BY_HANDLE_FILE_INFORMATION info;
+ BOOL res = ::GetFileInformationByHandle(iterator_handle, &info);
+ if (BOOST_UNLIKELY(!res))
+ goto return_last_error;
+
+ if (BOOST_UNLIKELY((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0u))
+ return make_error_code(system::errc::not_a_directory);
+
+ if ((opts & directory_options::_detail_no_follow) != directory_options::none && (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u)
+ {
+ error_code ec;
+ const ULONG reparse_point_tag = detail::get_reparse_point_tag_ioctl(iterator_handle, dir, &ec);
+ if (BOOST_UNLIKELY(!!ec))
+ return ec;
+
+ if (detail::is_reparse_point_tag_a_symlink(reparse_point_tag))
+ return make_error_code(system::errc::too_many_symbolic_link_levels);
+ }
+ }
+ }
+
+ void* extra_data = get_dir_itr_imp_extra_data(pimpl.get());
+ switch (filesystem::detail::atomic_load_relaxed(g_extra_data_format))
+ {
+ case file_id_extd_dir_info_format:
+ {
+ if (!get_file_information_by_handle_ex(iterator_handle, file_id_extd_directory_restart_info_class, extra_data, dir_itr_extra_size))
+ {
+ DWORD error = ::GetLastError();
+
+ if (is_dir_info_class_not_supported(error))
+ {
+ // Fall back to file_full_dir_info_format.
+ if (error == ERROR_NOT_SUPPORTED || error == ERROR_CALL_NOT_IMPLEMENTED)
+ filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_full_dir_info_format);
+ goto fallback_to_file_full_dir_info_format;
+ }
+
+ if (error == ERROR_NO_MORE_FILES || error == ERROR_FILE_NOT_FOUND)
+ goto done;
+
+ return system::error_code(error, system::system_category());
+ }
+
+ pimpl->extra_data_format = file_id_extd_dir_info_format;
+
+ const file_id_extd_dir_info* data = static_cast< const file_id_extd_dir_info* >(extra_data);
+ first_filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR));
+
+ set_file_statuses(data->FileAttributes, &data->ReparsePointTag, first_filename, sf, symlink_sf);
+ }
+ break;
+
+ case file_full_dir_info_format:
+ fallback_to_file_full_dir_info_format:
+ {
+ if (!get_file_information_by_handle_ex(iterator_handle, file_full_directory_restart_info_class, extra_data, dir_itr_extra_size))
+ {
+ DWORD error = ::GetLastError();
+
+ if (is_dir_info_class_not_supported(error))
+ {
+ // Fall back to file_id_both_dir_info
+ if (error == ERROR_NOT_SUPPORTED || error == ERROR_CALL_NOT_IMPLEMENTED)
+ filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_id_both_dir_info_format);
+ goto fallback_to_file_id_both_dir_info_format;
+ }
+
+ if (error == ERROR_NO_MORE_FILES || error == ERROR_FILE_NOT_FOUND)
+ goto done;
+
+ return system::error_code(error, system::system_category());
+ }
+
+ pimpl->extra_data_format = file_full_dir_info_format;
+
+ const file_full_dir_info* data = static_cast< const file_full_dir_info* >(extra_data);
+ first_filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR));
+
+ set_file_statuses(data->FileAttributes, nullptr, first_filename, sf, symlink_sf);
+ }
+ break;
+
+ case file_id_both_dir_info_format:
+ fallback_to_file_id_both_dir_info_format:
+ {
+ if (!get_file_information_by_handle_ex(iterator_handle, file_id_both_directory_restart_info_class, extra_data, dir_itr_extra_size))
+ {
+ DWORD error = ::GetLastError();
+
+ if (is_dir_info_class_not_supported(error))
+ {
+ // Fall back to file_directory_information
+ if (error == ERROR_NOT_SUPPORTED || error == ERROR_CALL_NOT_IMPLEMENTED)
+ filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_directory_information_format);
+ goto fallback_to_file_directory_information_format;
+ }
+
+ if (error == ERROR_NO_MORE_FILES || error == ERROR_FILE_NOT_FOUND)
+ goto done;
+
+ return system::error_code(error, system::system_category());
+ }
+
+ pimpl->extra_data_format = file_id_both_dir_info_format;
+
+ const file_id_both_dir_info* data = static_cast< const file_id_both_dir_info* >(extra_data);
+ first_filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR));
+
+ set_file_statuses(data->FileAttributes, nullptr, first_filename, sf, symlink_sf);
+ }
+ break;
+
+ default:
+ fallback_to_file_directory_information_format:
+ {
+ NtQueryDirectoryFile_t* nt_query_directory_file = filesystem::detail::atomic_load_relaxed(boost::filesystem::detail::nt_query_directory_file_api);
+ if (BOOST_UNLIKELY(!nt_query_directory_file))
+ return error_code(ERROR_NOT_SUPPORTED, system_category());
+
+ io_status_block iosb;
+ boost::winapi::NTSTATUS_ status = nt_query_directory_file
+ (
+ iterator_handle,
+ nullptr, // Event
+ nullptr, // ApcRoutine
+ nullptr, // ApcContext
+ &iosb,
+ extra_data,
+ dir_itr_extra_size,
+ file_directory_information_class,
+ FALSE, // ReturnSingleEntry
+ nullptr, // FileName
+ TRUE // RestartScan
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ // Note: an empty root directory has no "." or ".." entries, so this
+ // causes a ERROR_FILE_NOT_FOUND error returned from FindFirstFileW
+ // (which is presumably equivalent to STATUS_NO_SUCH_FILE) which we
+ // do not consider an error. It is treated as eof instead.
+ if (status == STATUS_NO_MORE_FILES || status == STATUS_NO_SUCH_FILE)
+ goto done;
+
+ return error_code(translate_ntstatus(status), system_category());
+ }
+
+ pimpl->extra_data_format = file_directory_information_format;
+
+ const file_directory_information* data = static_cast< const file_directory_information* >(extra_data);
+ first_filename.assign(data->FileName, data->FileName + data->FileNameLength / sizeof(WCHAR));
+
+ set_file_statuses(data->FileAttributes, nullptr, first_filename, sf, symlink_sf);
+ }
+ break;
+ }
+
+ pimpl->handle = iterator_handle;
+ h.release();
+ pimpl->close_handle = close_handle;
+
+done:
+ imp.swap(pimpl);
+ return system::error_code();
+}
+
+BOOST_CONSTEXPR_OR_CONST err_t not_found_error_code = ERROR_PATH_NOT_FOUND;
+
+#endif // BOOST_WINDOWS_API
+
+} // namespace
+
+#if defined(BOOST_POSIX_API)
+
+//! Tests if the directory is empty
+bool is_empty_directory(boost::scope::unique_fd&& fd, path const& p, error_code* ec)
+{
+#if !defined(BOOST_FILESYSTEM_USE_READDIR_R)
+ // Use a more optimal implementation without the overhead of constructing the iterator state
+
+ struct closedir_deleter
+ {
+ using result_type = void;
+ result_type operator() (DIR* dir) const noexcept
+ {
+ ::closedir(dir);
+ }
+ };
+
+ int err;
+
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+ std::unique_ptr< DIR, closedir_deleter > dir(::fdopendir(fd.get()));
+ if (BOOST_UNLIKELY(!dir))
+ {
+ err = errno;
+ fail:
+ emit_error(err, p, ec, "boost::filesystem::is_empty");
+ return false;
+ }
+
+ // At this point fd will be closed by closedir
+ fd.release();
+#else // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+ std::unique_ptr< DIR, closedir_deleter > dir(::opendir(p.c_str()));
+ if (BOOST_UNLIKELY(!dir))
+ {
+ err = errno;
+ fail:
+ emit_error(err, p, ec, "boost::filesystem::is_empty");
+ return false;
+ }
+#endif // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+
+ while (true)
+ {
+ errno = 0;
+ struct dirent* const ent = ::readdir(dir.get());
+ if (!ent)
+ {
+ err = errno;
+ if (err != 0)
+ goto fail;
+
+ return true;
+ }
+
+ // Skip dot and dot-dot entries
+ if (!(ent->d_name[0] == path::dot
+ && (ent->d_name[1] == static_cast< path::string_type::value_type >('\0') ||
+ (ent->d_name[1] == path::dot && ent->d_name[2] == static_cast< path::string_type::value_type >('\0')))))
+ {
+ return false;
+ }
+ }
+
+#else // !defined(BOOST_FILESYSTEM_USE_READDIR_R)
+
+ filesystem::directory_iterator itr;
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+ filesystem::detail::directory_iterator_params params{ std::move(fd) };
+ filesystem::detail::directory_iterator_construct(itr, p, directory_options::none, &params, ec);
+#else
+ filesystem::detail::directory_iterator_construct(itr, p, directory_options::none, nullptr, ec);
+#endif
+ return itr == filesystem::directory_iterator();
+
+#endif // !defined(BOOST_FILESYSTEM_USE_READDIR_R)
+}
+
+#else // BOOST_WINDOWS_API
+
+//! Tests if the directory is empty
+bool is_empty_directory(unique_handle&& h, path const& p, error_code* ec)
+{
+ filesystem::directory_iterator itr;
+ filesystem::detail::directory_iterator_params params{ h.get(), false };
+ filesystem::detail::directory_iterator_construct(itr, p, directory_options::none, &params, ec);
+ return itr == filesystem::directory_iterator();
+}
+
+//! Initializes directory iterator implementation
+void init_directory_iterator_impl() noexcept
+{
+ if (filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api) != nullptr)
+ {
+ // Enable the latest format we support. It will get downgraded, if needed, as we attempt
+ // to create the directory iterator the first time.
+ filesystem::detail::atomic_store_relaxed(g_extra_data_format, file_id_extd_dir_info_format);
+ }
+}
+
+#endif // defined(BOOST_WINDOWS_API)
+
+BOOST_FILESYSTEM_DECL
+dir_itr_imp::~dir_itr_imp() noexcept
+{
+ dir_itr_close(*this);
+}
+
+BOOST_FILESYSTEM_DECL
+void directory_iterator_construct(directory_iterator& it, path const& p, directory_options opts, directory_iterator_params* params, system::error_code* ec)
+{
+ // At most one of the two options may be specified, and follow_directory_symlink is ignored for directory_iterator.
+ BOOST_ASSERT((opts & (directory_options::follow_directory_symlink | directory_options::_detail_no_follow)) != (directory_options::follow_directory_symlink | directory_options::_detail_no_follow));
+
+ if (BOOST_UNLIKELY(p.empty()))
+ {
+ emit_error(not_found_error_code, p, ec, "boost::filesystem::directory_iterator::construct");
+ return;
+ }
+
+ if (ec)
+ ec->clear();
+
+ try
+ {
+ boost::intrusive_ptr< detail::dir_itr_imp > imp;
+ path filename;
+ file_status file_stat, symlink_file_stat;
+ system::error_code result = dir_itr_create(imp, p, opts, params, filename, file_stat, symlink_file_stat);
+
+ while (true)
+ {
+ if (result)
+ {
+ if (result != make_error_condition(system::errc::permission_denied) ||
+ (opts & directory_options::skip_permission_denied) == directory_options::none)
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::directory_iterator::construct", p, result));
+ *ec = result;
+ }
+
+ return;
+ }
+
+ if (imp->handle == nullptr) // eof, make end
+ return;
+
+ // Not eof
+ const path::string_type::value_type* filename_str = filename.c_str();
+ if (!(filename_str[0] == path::dot // dot or dot-dot
+ && (filename_str[1] == static_cast< path::string_type::value_type >('\0') ||
+ (filename_str[1] == path::dot && filename_str[2] == static_cast< path::string_type::value_type >('\0')))))
+ {
+ path full_path(p);
+ path_algorithms::append_v4(full_path, filename);
+ imp->dir_entry.assign_with_status
+ (
+ static_cast< path&& >(full_path),
+ file_stat,
+ symlink_file_stat
+ );
+ it.m_imp.swap(imp);
+ return;
+ }
+
+ // If dot or dot-dot name produced by the underlying API, skip it until the first actual file
+ result = dir_itr_increment(*imp, filename, file_stat, symlink_file_stat);
+ }
+ }
+ catch (std::bad_alloc&)
+ {
+ if (!ec)
+ throw;
+
+ *ec = make_error_code(system::errc::not_enough_memory);
+ it.m_imp.reset();
+ }
+}
+
+BOOST_FILESYSTEM_DECL
+void directory_iterator_increment(directory_iterator& it, system::error_code* ec)
+{
+ BOOST_ASSERT_MSG(!it.is_end(), "attempt to increment end iterator");
+
+ if (ec)
+ ec->clear();
+
+ try
+ {
+ path filename;
+ file_status file_stat, symlink_file_stat;
+ system::error_code increment_ec;
+
+ while (true)
+ {
+ increment_ec = dir_itr_increment(*it.m_imp, filename, file_stat, symlink_file_stat);
+
+ if (BOOST_UNLIKELY(!!increment_ec)) // happens if filesystem is corrupt, such as on a damaged optical disc
+ {
+ boost::intrusive_ptr< detail::dir_itr_imp > imp;
+ imp.swap(it.m_imp);
+ path error_path(imp->dir_entry.path().parent_path()); // fix ticket #5900
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::directory_iterator::operator++", error_path, increment_ec));
+
+ *ec = increment_ec;
+ return;
+ }
+
+ if (it.m_imp->handle == nullptr) // eof, make end
+ {
+ it.m_imp.reset();
+ return;
+ }
+
+ const path::string_type::value_type* filename_str = filename.c_str();
+ if (!(filename_str[0] == path::dot // !(dot or dot-dot)
+ && (filename_str[1] == static_cast< path::string_type::value_type >('\0') ||
+ (filename_str[1] == path::dot && filename_str[2] == static_cast< path::string_type::value_type >('\0')))))
+ {
+ it.m_imp->dir_entry.replace_filename_with_status(filename, file_stat, symlink_file_stat);
+ return;
+ }
+ }
+ }
+ catch (std::bad_alloc&)
+ {
+ if (!ec)
+ throw;
+
+ it.m_imp.reset();
+ *ec = make_error_code(system::errc::not_enough_memory);
+ }
+}
+
+//--------------------------------------------------------------------------------------//
+// //
+// recursive_directory_iterator //
+// //
+//--------------------------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL
+void recursive_directory_iterator_construct(recursive_directory_iterator& it, path const& dir_path, directory_options opts, system::error_code* ec)
+{
+ // At most one of the two options may be specified
+ BOOST_ASSERT((opts & (directory_options::follow_directory_symlink | directory_options::_detail_no_follow)) != (directory_options::follow_directory_symlink | directory_options::_detail_no_follow));
+
+ if (ec)
+ ec->clear();
+
+ directory_iterator dir_it;
+ detail::directory_iterator_construct(dir_it, dir_path, opts, nullptr, ec);
+ if ((ec && *ec) || dir_it == directory_iterator())
+ return;
+
+ boost::intrusive_ptr< detail::recur_dir_itr_imp > imp;
+ if (!ec)
+ {
+ imp = new detail::recur_dir_itr_imp(opts);
+ }
+ else
+ {
+ imp = new (std::nothrow) detail::recur_dir_itr_imp(opts);
+ if (BOOST_UNLIKELY(!imp))
+ {
+ *ec = make_error_code(system::errc::not_enough_memory);
+ return;
+ }
+ }
+
+ try
+ {
+ imp->m_stack.push_back(std::move(dir_it));
+ it.m_imp.swap(imp);
+ }
+ catch (std::bad_alloc&)
+ {
+ if (ec)
+ {
+ *ec = make_error_code(system::errc::not_enough_memory);
+ return;
+ }
+
+ throw;
+ }
+}
+
+namespace {
+
+void recursive_directory_iterator_pop_on_error(detail::recur_dir_itr_imp* imp)
+{
+ imp->m_stack.pop_back();
+
+ while (!imp->m_stack.empty())
+ {
+ directory_iterator& dir_it = imp->m_stack.back();
+ system::error_code increment_ec;
+ detail::directory_iterator_increment(dir_it, &increment_ec);
+ if (!increment_ec && dir_it != directory_iterator())
+ break;
+
+ imp->m_stack.pop_back();
+ }
+}
+
+} // namespace
+
+BOOST_FILESYSTEM_DECL
+void recursive_directory_iterator_pop(recursive_directory_iterator& it, system::error_code* ec)
+{
+ BOOST_ASSERT_MSG(!it.is_end(), "pop() on end recursive_directory_iterator");
+ detail::recur_dir_itr_imp* const imp = it.m_imp.get();
+
+ if (ec)
+ ec->clear();
+
+ imp->m_stack.pop_back();
+
+ while (true)
+ {
+ if (imp->m_stack.empty())
+ {
+ it.m_imp.reset(); // done, so make end iterator
+ break;
+ }
+
+ directory_iterator& dir_it = imp->m_stack.back();
+ system::error_code increment_ec;
+ detail::directory_iterator_increment(dir_it, &increment_ec);
+ if (BOOST_UNLIKELY(!!increment_ec))
+ {
+ if ((imp->m_options & directory_options::pop_on_error) == directory_options::none)
+ {
+ // Make an end iterator on errors
+ it.m_imp.reset();
+ }
+ else
+ {
+ recursive_directory_iterator_pop_on_error(imp);
+
+ if (imp->m_stack.empty())
+ it.m_imp.reset(); // done, so make end iterator
+ }
+
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::recursive_directory_iterator::pop", increment_ec));
+
+ *ec = increment_ec;
+ return;
+ }
+
+ if (dir_it != directory_iterator())
+ break;
+
+ imp->m_stack.pop_back();
+ }
+}
+
+BOOST_FILESYSTEM_DECL
+void recursive_directory_iterator_increment(recursive_directory_iterator& it, system::error_code* ec)
+{
+ enum push_directory_result : unsigned int
+ {
+ directory_not_pushed = 0u,
+ directory_pushed = 1u,
+ keep_depth = 1u << 1u
+ };
+
+ struct local
+ {
+ //! Attempts to descend into a directory
+ static push_directory_result push_directory(detail::recur_dir_itr_imp* imp, system::error_code& ec)
+ {
+ push_directory_result result = directory_not_pushed;
+ try
+ {
+ // Discover if the iterator is for a directory that needs to be recursed into,
+ // taking symlinks and options into account.
+
+ if ((imp->m_options & directory_options::_detail_no_push) != directory_options::none)
+ {
+ imp->m_options &= ~directory_options::_detail_no_push;
+ return result;
+ }
+
+ file_type symlink_ft = status_error;
+
+#if defined(BOOST_POSIX_API) && defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+ int parentdir_fd = -1;
+ path dir_it_filename;
+#elif defined(BOOST_WINDOWS_API)
+ unique_handle direntry_handle;
+#endif
+
+ // If we are not recursing into symlinks, we are going to have to know if the
+ // stack top is a symlink, so get symlink_status and verify no error occurred.
+ if ((imp->m_options & directory_options::follow_directory_symlink) == directory_options::none ||
+ (imp->m_options & directory_options::skip_dangling_symlinks) != directory_options::none)
+ {
+#if defined(BOOST_POSIX_API) && defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+ directory_iterator const& dir_it = imp->m_stack.back();
+ if (filesystem::type_present(dir_it->m_symlink_status))
+ {
+ symlink_ft = dir_it->m_symlink_status.type();
+ }
+ else
+ {
+ parentdir_fd = dir_itr_fd(*dir_it.m_imp, ec);
+ if (ec)
+ return result;
+
+ dir_it_filename = detail::path_algorithms::filename_v4(dir_it->path());
+
+ symlink_ft = detail::symlink_status_impl(dir_it_filename, &ec, parentdir_fd).type();
+ if (ec)
+ return result;
+ }
+#elif defined(BOOST_WINDOWS_API)
+ directory_iterator const& dir_it = imp->m_stack.back();
+ if (filesystem::type_present(dir_it->m_symlink_status))
+ {
+ symlink_ft = dir_it->m_symlink_status.type();
+ }
+ else
+ {
+ boost::winapi::NTSTATUS_ status = nt_create_file_handle_at
+ (
+ direntry_handle,
+ static_cast< HANDLE >(dir_it.m_imp->handle),
+ detail::path_algorithms::filename_v4(dir_it->path()),
+ 0u, // FileAttributes
+ FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ symlink_ft = detail::status_by_handle(direntry_handle.get(), dir_it->path(), &ec).type();
+ }
+ else if (status == STATUS_NOT_IMPLEMENTED)
+ {
+ symlink_ft = dir_it->symlink_file_type(ec);
+ }
+ else
+ {
+ if (!not_found_ntstatus(status))
+ ec.assign(translate_ntstatus(status), system::system_category());
+
+ return result;
+ }
+
+ if (ec)
+ return result;
+ }
+#else
+ symlink_ft = imp->m_stack.back()->symlink_file_type(ec);
+ if (ec)
+ return result;
+#endif
+ }
+
+ // Logic for following predicate was contributed by Daniel Aarno to handle cyclic
+ // symlinks correctly and efficiently, fixing ticket #5652.
+ // if (((m_options & directory_options::follow_directory_symlink) == directory_options::follow_directory_symlink
+ // || !is_symlink(m_stack.back()->symlink_status()))
+ // && is_directory(m_stack.back()->status())) ...
+ // The predicate code has since been rewritten to pass error_code arguments,
+ // per ticket #5653.
+
+ if ((imp->m_options & directory_options::follow_directory_symlink) != directory_options::none || symlink_ft != symlink_file)
+ {
+ directory_iterator const& dir_it = imp->m_stack.back();
+
+ // Don't query the file type from the filesystem yet, if not known. We will use dir_it for that below.
+ file_type ft = dir_it->m_status.type();
+ if (ft != status_error && ft != directory_file)
+ return result;
+
+#if defined(BOOST_POSIX_API) && defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+ if (parentdir_fd < 0)
+ {
+ parentdir_fd = dir_itr_fd(*dir_it.m_imp, ec);
+ if (ec)
+ return result;
+
+ dir_it_filename = detail::path_algorithms::filename_v4(dir_it->path());
+ }
+
+ // Try to open the file as a directory right away. This effectively tests whether the file is a directory, and, if it is, opens the directory in one system call.
+ detail::directory_iterator_params params{ detail::openat_directory(parentdir_fd, dir_it_filename, imp->m_options, ec) };
+ if (!!ec)
+ {
+ if
+ (
+ // Skip non-directory files
+ ec == system::error_code(ENOTDIR, system::system_category()) ||
+ (
+ // Skip dangling symlink, if requested by options
+ ec == system::error_code(ENOENT, system::system_category()) && symlink_ft == symlink_file &&
+ (imp->m_options & (directory_options::follow_directory_symlink | directory_options::skip_dangling_symlinks)) == (directory_options::follow_directory_symlink | directory_options::skip_dangling_symlinks)
+ )
+ )
+ {
+ ec.clear();
+ }
+
+ return result;
+ }
+#else // defined(BOOST_POSIX_API) && defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+#if defined(BOOST_WINDOWS_API)
+ if (!!direntry_handle && symlink_ft == symlink_file)
+ {
+ // Close the symlink to reopen the target file below
+ direntry_handle.reset();
+ }
+
+ if (!direntry_handle)
+ {
+ boost::winapi::NTSTATUS_ status = nt_create_file_handle_at
+ (
+ direntry_handle,
+ static_cast< HANDLE >(dir_it.m_imp->handle),
+ detail::path_algorithms::filename_v4(dir_it->path()),
+ 0u, // FileAttributes
+ FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ goto get_file_type_by_handle;
+ }
+ else if (status == STATUS_NOT_IMPLEMENTED)
+ {
+ ft = dir_it->file_type(ec);
+ }
+ else
+ {
+ ec.assign(translate_ntstatus(status), system::system_category());
+ }
+ }
+ else
+ {
+ get_file_type_by_handle:
+ ft = detail::status_by_handle(direntry_handle.get(), dir_it->path(), &ec).type();
+ }
+#else // defined(BOOST_WINDOWS_API)
+ if (ft == status_error)
+ ft = dir_it->file_type(ec);
+#endif // defined(BOOST_WINDOWS_API)
+
+ if (BOOST_UNLIKELY(!!ec))
+ {
+ if (ec == make_error_condition(system::errc::no_such_file_or_directory) && symlink_ft == symlink_file &&
+ (imp->m_options & (directory_options::follow_directory_symlink | directory_options::skip_dangling_symlinks)) == (directory_options::follow_directory_symlink | directory_options::skip_dangling_symlinks))
+ {
+ // Skip dangling symlink and continue iteration on the current depth level
+ ec.clear();
+ }
+
+ return result;
+ }
+
+ if (ft != directory_file)
+ return result;
+#endif // defined(BOOST_POSIX_API) && defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+
+ if (BOOST_UNLIKELY((imp->m_stack.size() - 1u) >= static_cast< std::size_t >((std::numeric_limits< int >::max)())))
+ {
+ // We cannot let depth to overflow
+ ec = make_error_code(system::errc::value_too_large);
+ // When depth overflow happens, avoid popping the current directory iterator
+ // and attempt to continue iteration on the current depth.
+ result = keep_depth;
+ return result;
+ }
+
+#if defined(BOOST_POSIX_API) && defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+ directory_iterator next;
+ detail::directory_iterator_construct(next, dir_it->path(), imp->m_options, &params, &ec);
+#elif defined(BOOST_WINDOWS_API)
+ detail::directory_iterator_params params;
+ params.dir_handle = direntry_handle.get();
+ params.close_handle = true;
+ directory_iterator next;
+ detail::directory_iterator_construct(next, dir_it->path(), imp->m_options, &params, &ec);
+#else
+ directory_iterator next(dir_it->path(), imp->m_options, ec);
+#endif
+ if (BOOST_LIKELY(!ec))
+ {
+#if defined(BOOST_WINDOWS_API)
+ direntry_handle.release();
+#endif
+ if (!next.is_end())
+ {
+ imp->m_stack.push_back(std::move(next)); // may throw
+ return directory_pushed;
+ }
+ }
+ }
+ }
+ catch (std::bad_alloc&)
+ {
+ ec = make_error_code(system::errc::not_enough_memory);
+ }
+
+ return result;
+ }
+ };
+
+ BOOST_ASSERT_MSG(!it.is_end(), "increment() on end recursive_directory_iterator");
+ detail::recur_dir_itr_imp* const imp = it.m_imp.get();
+
+ if (ec)
+ ec->clear();
+
+ system::error_code local_ec;
+
+ // if various conditions are met, push a directory_iterator into the iterator stack
+ push_directory_result push_result = local::push_directory(imp, local_ec);
+ if (push_result == directory_pushed)
+ return;
+
+ // report errors if any
+ if (BOOST_UNLIKELY(!!local_ec))
+ {
+ on_error:
+ if ((imp->m_options & directory_options::pop_on_error) == directory_options::none)
+ {
+ // Make an end iterator on errors
+ it.m_imp.reset();
+ }
+ else
+ {
+ if ((push_result & keep_depth) != 0u)
+ {
+ system::error_code increment_ec;
+ directory_iterator& dir_it = imp->m_stack.back();
+ detail::directory_iterator_increment(dir_it, &increment_ec);
+ if (!increment_ec && !dir_it.is_end())
+ goto on_error_return;
+ }
+
+ recursive_directory_iterator_pop_on_error(imp);
+
+ if (imp->m_stack.empty())
+ it.m_imp.reset(); // done, so make end iterator
+ }
+
+ on_error_return:
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("filesystem::recursive_directory_iterator increment error", local_ec));
+
+ *ec = local_ec;
+ return;
+ }
+
+ // Do the actual increment operation on the top iterator in the iterator
+ // stack, popping the stack if necessary, until either the stack is empty or a
+ // non-end iterator is reached.
+ while (true)
+ {
+ if (imp->m_stack.empty())
+ {
+ it.m_imp.reset(); // done, so make end iterator
+ break;
+ }
+
+ directory_iterator& dir_it = imp->m_stack.back();
+ detail::directory_iterator_increment(dir_it, &local_ec);
+ if (BOOST_UNLIKELY(!!local_ec))
+ goto on_error;
+
+ if (!dir_it.is_end())
+ break;
+
+ imp->m_stack.pop_back();
+ }
+}
+
+} // namespace detail
+
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
diff --git a/contrib/restricted/boost/filesystem/src/error_handling.hpp b/contrib/restricted/boost/filesystem/src/error_handling.hpp
new file mode 100644
index 0000000000..a83d92e976
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/error_handling.hpp
@@ -0,0 +1,237 @@
+// error_handling.hpp --------------------------------------------------------------------//
+
+// Copyright 2002-2009, 2014 Beman Dawes
+// Copyright 2019 Andrey Semashev
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// See library home page at http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#ifndef BOOST_FILESYSTEM_SRC_ERROR_HANDLING_HPP_
+#define BOOST_FILESYSTEM_SRC_ERROR_HANDLING_HPP_
+
+#include <cerrno>
+#include <boost/system/error_code.hpp>
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/exception.hpp>
+
+#if defined(BOOST_WINDOWS_API)
+#include <boost/winapi/basic_types.hpp>
+#include <boost/winapi/get_last_error.hpp>
+#include <boost/winapi/error_codes.hpp>
+#endif
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace boost {
+namespace filesystem {
+
+#if defined(BOOST_POSIX_API)
+
+typedef int err_t;
+
+// POSIX uses a 0 return to indicate success
+#define BOOST_ERRNO errno
+
+#define BOOST_ERROR_FILE_NOT_FOUND ENOENT
+#define BOOST_ERROR_ALREADY_EXISTS EEXIST
+#define BOOST_ERROR_NOT_SUPPORTED ENOSYS
+
+#else
+
+typedef boost::winapi::DWORD_ err_t;
+
+// Windows uses a non-0 return to indicate success
+#define BOOST_ERRNO boost::winapi::GetLastError()
+
+#define BOOST_ERROR_FILE_NOT_FOUND boost::winapi::ERROR_FILE_NOT_FOUND_
+#define BOOST_ERROR_ALREADY_EXISTS boost::winapi::ERROR_ALREADY_EXISTS_
+#define BOOST_ERROR_NOT_SUPPORTED boost::winapi::ERROR_NOT_SUPPORTED_
+
+// Note: Legacy MinGW doesn't have ntstatus.h and doesn't define NTSTATUS error codes other than STATUS_SUCCESS.
+#if !defined(NT_SUCCESS)
+#define NT_SUCCESS(Status) (((boost::winapi::NTSTATUS_)(Status)) >= 0)
+#endif
+#if !defined(STATUS_SUCCESS)
+#define STATUS_SUCCESS ((boost::winapi::NTSTATUS_)0x00000000l)
+#endif
+#if !defined(STATUS_NOT_IMPLEMENTED)
+#define STATUS_NOT_IMPLEMENTED ((boost::winapi::NTSTATUS_)0xC0000002l)
+#endif
+#if !defined(STATUS_INVALID_INFO_CLASS)
+#define STATUS_INVALID_INFO_CLASS ((boost::winapi::NTSTATUS_)0xC0000003l)
+#endif
+#if !defined(STATUS_INVALID_HANDLE)
+#define STATUS_INVALID_HANDLE ((boost::winapi::NTSTATUS_)0xC0000008l)
+#endif
+#if !defined(STATUS_INVALID_PARAMETER)
+#define STATUS_INVALID_PARAMETER ((boost::winapi::NTSTATUS_)0xC000000Dl)
+#endif
+#if !defined(STATUS_NO_SUCH_DEVICE)
+#define STATUS_NO_SUCH_DEVICE ((boost::winapi::NTSTATUS_)0xC000000El)
+#endif
+#if !defined(STATUS_NO_SUCH_FILE)
+#define STATUS_NO_SUCH_FILE ((boost::winapi::NTSTATUS_)0xC000000Fl)
+#endif
+#if !defined(STATUS_NO_MORE_FILES)
+#define STATUS_NO_MORE_FILES ((boost::winapi::NTSTATUS_)0x80000006l)
+#endif
+#if !defined(STATUS_BUFFER_OVERFLOW)
+#define STATUS_BUFFER_OVERFLOW ((boost::winapi::NTSTATUS_)0x80000005l)
+#endif
+#if !defined(STATUS_NO_MEMORY)
+#define STATUS_NO_MEMORY ((boost::winapi::NTSTATUS_)0xC0000017l)
+#endif
+#if !defined(STATUS_ACCESS_DENIED)
+#define STATUS_ACCESS_DENIED ((boost::winapi::NTSTATUS_)0xC0000022l)
+#endif
+#if !defined(STATUS_OBJECT_NAME_NOT_FOUND)
+#define STATUS_OBJECT_NAME_NOT_FOUND ((boost::winapi::NTSTATUS_)0xC0000034l)
+#endif
+#if !defined(STATUS_OBJECT_PATH_NOT_FOUND)
+#define STATUS_OBJECT_PATH_NOT_FOUND ((boost::winapi::NTSTATUS_)0xC000003Al)
+#endif
+#if !defined(STATUS_SHARING_VIOLATION)
+#define STATUS_SHARING_VIOLATION ((boost::winapi::NTSTATUS_)0xC0000043l)
+#endif
+#if !defined(STATUS_EAS_NOT_SUPPORTED)
+#define STATUS_EAS_NOT_SUPPORTED ((boost::winapi::NTSTATUS_)0xC000004Fl)
+#endif
+#if !defined(STATUS_NOT_SUPPORTED)
+#define STATUS_NOT_SUPPORTED ((boost::winapi::NTSTATUS_)0xC00000BBl)
+#endif
+#if !defined(STATUS_BAD_NETWORK_PATH)
+#define STATUS_BAD_NETWORK_PATH ((boost::winapi::NTSTATUS_)0xC00000BEl)
+#endif
+#if !defined(STATUS_DEVICE_DOES_NOT_EXIST)
+#define STATUS_DEVICE_DOES_NOT_EXIST ((boost::winapi::NTSTATUS_)0xC00000C0l)
+#endif
+#if !defined(STATUS_BAD_NETWORK_NAME)
+#define STATUS_BAD_NETWORK_NAME ((boost::winapi::NTSTATUS_)0xC00000CCl)
+#endif
+#if !defined(STATUS_DIRECTORY_NOT_EMPTY)
+#define STATUS_DIRECTORY_NOT_EMPTY ((boost::winapi::NTSTATUS_)0xC0000101l)
+#endif
+#if !defined(STATUS_NOT_A_DIRECTORY)
+#define STATUS_NOT_A_DIRECTORY ((boost::winapi::NTSTATUS_)0xC0000103l)
+#endif
+#if !defined(STATUS_NOT_FOUND)
+#define STATUS_NOT_FOUND ((boost::winapi::NTSTATUS_)0xC0000225l)
+#endif
+
+//! Converts NTSTATUS error codes to Win32 error codes for reporting
+inline boost::winapi::DWORD_ translate_ntstatus(boost::winapi::NTSTATUS_ status) noexcept
+{
+ // We have to cast to unsigned integral type to avoid signed overflow and narrowing conversion in the constants.
+ switch (static_cast< boost::winapi::ULONG_ >(status))
+ {
+ case static_cast< boost::winapi::ULONG_ >(STATUS_NO_MEMORY):
+ return boost::winapi::ERROR_OUTOFMEMORY_;
+ case static_cast< boost::winapi::ULONG_ >(STATUS_BUFFER_OVERFLOW):
+ return boost::winapi::ERROR_BUFFER_OVERFLOW_;
+ case static_cast< boost::winapi::ULONG_ >(STATUS_INVALID_HANDLE):
+ return boost::winapi::ERROR_INVALID_HANDLE_;
+ case static_cast< boost::winapi::ULONG_ >(STATUS_INVALID_PARAMETER):
+ return boost::winapi::ERROR_INVALID_PARAMETER_;
+ case static_cast< boost::winapi::ULONG_ >(STATUS_NO_MORE_FILES):
+ return boost::winapi::ERROR_NO_MORE_FILES_;
+ case static_cast< boost::winapi::ULONG_ >(STATUS_NO_SUCH_DEVICE):
+ case static_cast< boost::winapi::ULONG_ >(STATUS_DEVICE_DOES_NOT_EXIST):
+ return boost::winapi::ERROR_DEV_NOT_EXIST_;
+ case static_cast< boost::winapi::ULONG_ >(STATUS_NO_SUCH_FILE):
+ case static_cast< boost::winapi::ULONG_ >(STATUS_OBJECT_NAME_NOT_FOUND):
+ case static_cast< boost::winapi::ULONG_ >(STATUS_OBJECT_PATH_NOT_FOUND):
+ return boost::winapi::ERROR_FILE_NOT_FOUND_;
+ case static_cast< boost::winapi::ULONG_ >(STATUS_SHARING_VIOLATION):
+ return boost::winapi::ERROR_SHARING_VIOLATION_;
+ case static_cast< boost::winapi::ULONG_ >(STATUS_EAS_NOT_SUPPORTED):
+ return boost::winapi::ERROR_EAS_NOT_SUPPORTED_;
+ case static_cast< boost::winapi::ULONG_ >(STATUS_ACCESS_DENIED):
+ return boost::winapi::ERROR_ACCESS_DENIED_;
+ case static_cast< boost::winapi::ULONG_ >(STATUS_BAD_NETWORK_PATH):
+ return boost::winapi::ERROR_BAD_NETPATH_;
+ case static_cast< boost::winapi::ULONG_ >(STATUS_BAD_NETWORK_NAME):
+ return boost::winapi::ERROR_BAD_NET_NAME_;
+ case static_cast< boost::winapi::ULONG_ >(STATUS_DIRECTORY_NOT_EMPTY):
+ return boost::winapi::ERROR_DIR_NOT_EMPTY_;
+ case static_cast< boost::winapi::ULONG_ >(STATUS_NOT_A_DIRECTORY):
+ return boost::winapi::ERROR_DIRECTORY_; // The directory name is invalid
+ case static_cast< boost::winapi::ULONG_ >(STATUS_NOT_FOUND):
+ return boost::winapi::ERROR_NOT_FOUND_;
+ // map "invalid info class" to "not supported" as this error likely indicates that the kernel does not support what we request
+ case static_cast< boost::winapi::ULONG_ >(STATUS_INVALID_INFO_CLASS):
+ default:
+ return boost::winapi::ERROR_NOT_SUPPORTED_;
+ }
+}
+
+//! Tests if the NTSTATUS indicates that the file is not found
+inline bool not_found_ntstatus(boost::winapi::NTSTATUS_ status) noexcept
+{
+ return status == STATUS_NO_SUCH_FILE || status == STATUS_OBJECT_NAME_NOT_FOUND || status == STATUS_OBJECT_PATH_NOT_FOUND ||
+ status == STATUS_BAD_NETWORK_PATH || status == STATUS_BAD_NETWORK_NAME;
+}
+
+#endif
+
+// error handling helpers ----------------------------------------------------------//
+
+// Implemented in exception.cpp
+void emit_error(err_t error_num, system::error_code* ec, const char* message);
+void emit_error(err_t error_num, path const& p, system::error_code* ec, const char* message);
+void emit_error(err_t error_num, path const& p1, path const& p2, system::error_code* ec, const char* message);
+
+inline bool error(err_t error_num, system::error_code* ec, const char* message)
+{
+ if (BOOST_LIKELY(!error_num))
+ {
+ if (ec)
+ ec->clear();
+ return false;
+ }
+ else
+ { // error
+ filesystem::emit_error(error_num, ec, message);
+ return true;
+ }
+}
+
+inline bool error(err_t error_num, path const& p, system::error_code* ec, const char* message)
+{
+ if (BOOST_LIKELY(!error_num))
+ {
+ if (ec)
+ ec->clear();
+ return false;
+ }
+ else
+ { // error
+ filesystem::emit_error(error_num, p, ec, message);
+ return true;
+ }
+}
+
+inline bool error(err_t error_num, path const& p1, path const& p2, system::error_code* ec, const char* message)
+{
+ if (BOOST_LIKELY(!error_num))
+ {
+ if (ec)
+ ec->clear();
+ return false;
+ }
+ else
+ { // error
+ filesystem::emit_error(error_num, p1, p2, ec, message);
+ return true;
+ }
+}
+
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
+
+#endif // BOOST_FILESYSTEM_SRC_ERROR_HANDLING_HPP_
diff --git a/contrib/restricted/boost/filesystem/src/exception.cpp b/contrib/restricted/boost/filesystem/src/exception.cpp
new file mode 100644
index 0000000000..0b92c0d9c1
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/exception.cpp
@@ -0,0 +1,188 @@
+// boost/filesystem/exception.hpp -----------------------------------------------------//
+
+// Copyright Beman Dawes 2003
+// Copyright Andrey Semashev 2019
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+#include "platform_config.hpp"
+
+#include <string>
+#include <boost/system/error_code.hpp>
+#include <boost/system/system_category.hpp>
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/exception.hpp>
+
+#include "error_handling.hpp"
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace boost {
+namespace filesystem {
+
+BOOST_FILESYSTEM_DECL filesystem_error::filesystem_error(const char* what_arg, system::error_code ec) :
+ system::system_error(ec, what_arg)
+{
+ try
+ {
+ m_imp_ptr.reset(new impl());
+ }
+ catch (...)
+ {
+ m_imp_ptr.reset();
+ }
+}
+
+BOOST_FILESYSTEM_DECL filesystem_error::filesystem_error(std::string const& what_arg, system::error_code ec) :
+ system::system_error(ec, what_arg)
+{
+ try
+ {
+ m_imp_ptr.reset(new impl());
+ }
+ catch (...)
+ {
+ m_imp_ptr.reset();
+ }
+}
+
+BOOST_FILESYSTEM_DECL filesystem_error::filesystem_error(const char* what_arg, path const& path1_arg, system::error_code ec) :
+ system::system_error(ec, what_arg)
+{
+ try
+ {
+ m_imp_ptr.reset(new impl(path1_arg));
+ }
+ catch (...)
+ {
+ m_imp_ptr.reset();
+ }
+}
+
+BOOST_FILESYSTEM_DECL filesystem_error::filesystem_error(std::string const& what_arg, path const& path1_arg, system::error_code ec) :
+ system::system_error(ec, what_arg)
+{
+ try
+ {
+ m_imp_ptr.reset(new impl(path1_arg));
+ }
+ catch (...)
+ {
+ m_imp_ptr.reset();
+ }
+}
+
+BOOST_FILESYSTEM_DECL filesystem_error::filesystem_error(const char* what_arg, path const& path1_arg, path const& path2_arg, system::error_code ec) :
+ system::system_error(ec, what_arg)
+{
+ try
+ {
+ m_imp_ptr.reset(new impl(path1_arg, path2_arg));
+ }
+ catch (...)
+ {
+ m_imp_ptr.reset();
+ }
+}
+
+BOOST_FILESYSTEM_DECL filesystem_error::filesystem_error(std::string const& what_arg, path const& path1_arg, path const& path2_arg, system::error_code ec) :
+ system::system_error(ec, what_arg)
+{
+ try
+ {
+ m_imp_ptr.reset(new impl(path1_arg, path2_arg));
+ }
+ catch (...)
+ {
+ m_imp_ptr.reset();
+ }
+}
+
+BOOST_FILESYSTEM_DECL filesystem_error::filesystem_error(filesystem_error const& that) :
+ system::system_error(static_cast< system::system_error const& >(that)),
+ m_imp_ptr(that.m_imp_ptr)
+{
+}
+
+BOOST_FILESYSTEM_DECL filesystem_error& filesystem_error::operator=(filesystem_error const& that)
+{
+ static_cast< system::system_error& >(*this) = static_cast< system::system_error const& >(that);
+ m_imp_ptr = that.m_imp_ptr;
+ return *this;
+}
+
+BOOST_FILESYSTEM_DECL filesystem_error::~filesystem_error() noexcept
+{
+}
+
+BOOST_FILESYSTEM_DECL const char* filesystem_error::what() const noexcept
+{
+ if (m_imp_ptr.get()) try
+ {
+ if (m_imp_ptr->m_what.empty())
+ {
+ m_imp_ptr->m_what = system::system_error::what();
+ if (!m_imp_ptr->m_path1.empty())
+ {
+ m_imp_ptr->m_what += ": \"";
+ m_imp_ptr->m_what += m_imp_ptr->m_path1.string();
+ m_imp_ptr->m_what += "\"";
+ }
+ if (!m_imp_ptr->m_path2.empty())
+ {
+ m_imp_ptr->m_what += ", \"";
+ m_imp_ptr->m_what += m_imp_ptr->m_path2.string();
+ m_imp_ptr->m_what += "\"";
+ }
+ }
+
+ return m_imp_ptr->m_what.c_str();
+ }
+ catch (...)
+ {
+ m_imp_ptr->m_what.clear();
+ }
+
+ return system::system_error::what();
+}
+
+BOOST_FILESYSTEM_DECL path const& filesystem_error::get_empty_path() noexcept
+{
+ static const path empty_path;
+ return empty_path;
+}
+
+// error handling helpers declared in error_handling.hpp -----------------------------------------------------//
+
+void emit_error(err_t error_num, system::error_code* ec, const char* message)
+{
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error(message, system::error_code(error_num, system::system_category())));
+ else
+ ec->assign(error_num, system::system_category());
+}
+
+void emit_error(err_t error_num, path const& p, system::error_code* ec, const char* message)
+{
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error(message, p, system::error_code(error_num, system::system_category())));
+ else
+ ec->assign(error_num, system::system_category());
+}
+
+void emit_error(err_t error_num, path const& p1, path const& p2, system::error_code* ec, const char* message)
+{
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error(message, p1, p2, system::error_code(error_num, system::system_category())));
+ else
+ ec->assign(error_num, system::system_category());
+}
+
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
diff --git a/contrib/restricted/boost/filesystem/src/operations.cpp b/contrib/restricted/boost/filesystem/src/operations.cpp
new file mode 100644
index 0000000000..e2fa235451
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/operations.cpp
@@ -0,0 +1,5202 @@
+// operations.cpp --------------------------------------------------------------------//
+
+// Copyright 2002-2009, 2014 Beman Dawes
+// Copyright 2001 Dietmar Kuehl
+// Copyright 2018-2024 Andrey Semashev
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// See library home page at http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#include "platform_config.hpp"
+
+#include <boost/predef/os/bsd/open.h>
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/file_status.hpp>
+#include <boost/filesystem/exception.hpp>
+#include <boost/filesystem/directory.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/detail/workaround.hpp>
+#include <boost/core/bit.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/assert.hpp>
+#include <new> // std::bad_alloc, std::nothrow
+#include <limits>
+#include <memory>
+#include <string>
+#include <utility>
+#include <cstddef>
+#include <cstdlib> // for malloc, free
+#include <cstring>
+#include <cerrno>
+#include <stdio.h> // for rename
+
+// Default to POSIX under Emscripten
+// If BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI is set, use WASI instead
+#if defined(__wasm) && (!defined(__EMSCRIPTEN__) || defined(BOOST_FILESYSTEM_EMSCRIPTEN_USE_WASI))
+#define BOOST_FILESYSTEM_USE_WASI
+#endif
+
+#ifdef BOOST_POSIX_API
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(BOOST_FILESYSTEM_USE_WASI)
+// WASI does not have statfs or statvfs.
+#elif !defined(__APPLE__) && \
+ (!defined(__OpenBSD__) || BOOST_OS_BSD_OPEN >= BOOST_VERSION_NUMBER(4, 4, 0)) && \
+ !defined(__ANDROID__) && \
+ !defined(__VXWORKS__)
+#include <sys/statvfs.h>
+#define BOOST_STATVFS statvfs
+#define BOOST_STATVFS_F_FRSIZE vfs.f_frsize
+#else
+#ifdef __OpenBSD__
+#include <sys/param.h>
+#elif defined(__ANDROID__)
+#include <sys/vfs.h>
+#endif
+#if !defined(__VXWORKS__)
+#include <sys/mount.h>
+#endif
+#define BOOST_STATVFS statfs
+#define BOOST_STATVFS_F_FRSIZE static_cast< uintmax_t >(vfs.f_bsize)
+#endif // BOOST_STATVFS definition
+
+#include <unistd.h>
+#include <fcntl.h>
+#if !defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+#include <utime.h>
+#endif
+#include <limits.h>
+
+#if defined(linux) || defined(__linux) || defined(__linux__)
+
+#include <sys/vfs.h>
+#include <sys/utsname.h>
+#include <sys/syscall.h>
+#include <sys/sysmacros.h>
+#if !defined(BOOST_FILESYSTEM_DISABLE_SENDFILE)
+#include <sys/sendfile.h>
+#define BOOST_FILESYSTEM_USE_SENDFILE
+#endif // !defined(BOOST_FILESYSTEM_DISABLE_SENDFILE)
+#if !defined(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) && defined(__NR_copy_file_range)
+#define BOOST_FILESYSTEM_USE_COPY_FILE_RANGE
+#endif // !defined(BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE) && defined(__NR_copy_file_range)
+#if !defined(BOOST_FILESYSTEM_DISABLE_STATX) && (defined(BOOST_FILESYSTEM_HAS_STATX) || defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL))
+#if !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)
+#include <linux/stat.h>
+#endif
+#define BOOST_FILESYSTEM_USE_STATX
+#endif // !defined(BOOST_FILESYSTEM_DISABLE_STATX) && (defined(BOOST_FILESYSTEM_HAS_STATX) || defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL))
+
+#if defined(__has_include)
+#if __has_include(<linux/magic.h>)
+// This header was introduced in Linux kernel 2.6.19
+#include <linux/magic.h>
+#endif
+#endif
+
+// Some filesystem type magic constants are not defined in older kernel headers
+#ifndef PROC_SUPER_MAGIC
+#define PROC_SUPER_MAGIC 0x9fa0
+#endif
+#ifndef SYSFS_MAGIC
+#define SYSFS_MAGIC 0x62656572
+#endif
+#ifndef TRACEFS_MAGIC
+#define TRACEFS_MAGIC 0x74726163
+#endif
+#ifndef DEBUGFS_MAGIC
+#define DEBUGFS_MAGIC 0x64626720
+#endif
+
+#endif // defined(linux) || defined(__linux) || defined(__linux__)
+
+#include <boost/scope/unique_fd.hpp>
+
+#if defined(POSIX_FADV_SEQUENTIAL) && (!defined(__ANDROID__) || __ANDROID_API__ >= 21)
+#define BOOST_FILESYSTEM_HAS_POSIX_FADVISE
+#endif
+
+#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIM)
+#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtim.tv_nsec
+#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMESPEC)
+#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtimespec.tv_nsec
+#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_MTIMENSEC)
+#define BOOST_FILESYSTEM_STAT_ST_MTIMENSEC st_mtimensec
+#endif
+
+#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIM)
+#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtim.tv_sec
+#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtim.tv_nsec
+#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMESPEC)
+#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtimespec.tv_sec
+#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtimespec.tv_nsec
+#elif defined(BOOST_FILESYSTEM_HAS_STAT_ST_BIRTHTIMENSEC)
+#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIME st_birthtime
+#define BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC st_birthtimensec
+#endif
+
+#include "posix_tools.hpp"
+
+#else // BOOST_WINDOWS_API
+
+#include <boost/winapi/dll.hpp> // get_proc_address, GetModuleHandleW
+#include <cwchar>
+#include <io.h>
+#include <windows.h>
+#include <winnt.h>
+#if defined(__BORLANDC__) || defined(__MWERKS__)
+#if defined(BOOST_BORLANDC)
+using std::time_t;
+#endif
+#include <utime.h>
+#else
+#include <sys/utime.h>
+#endif
+
+#include "windows_tools.hpp"
+
+#endif // BOOST_WINDOWS_API
+
+#include "atomic_tools.hpp"
+#include "error_handling.hpp"
+#include "private_config.hpp"
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace fs = boost::filesystem;
+using boost::filesystem::path;
+using boost::filesystem::filesystem_error;
+using boost::filesystem::perms;
+using boost::system::error_code;
+using boost::system::system_category;
+
+#if defined(BOOST_POSIX_API)
+
+// At least Mac OS X 10.6 and older doesn't support O_CLOEXEC
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#define BOOST_FILESYSTEM_NO_O_CLOEXEC
+#endif
+
+#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
+#define BOOST_FILESYSTEM_HAS_FDATASYNC
+#endif
+
+#else // defined(BOOST_POSIX_API)
+
+#ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
+#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024)
+#endif
+
+#ifndef FSCTL_GET_REPARSE_POINT
+#define FSCTL_GET_REPARSE_POINT 0x900a8
+#endif
+
+#ifndef SYMLINK_FLAG_RELATIVE
+#define SYMLINK_FLAG_RELATIVE 1
+#endif
+
+// Fallback for MinGW/Cygwin
+#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
+#define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
+#endif
+
+#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
+#define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x2
+#endif
+
+#endif // defined(BOOST_POSIX_API)
+
+// POSIX/Windows macros ----------------------------------------------------//
+
+// Portions of the POSIX and Windows API's are very similar, except for name,
+// order of arguments, and meaning of zero/non-zero returns. The macros below
+// abstract away those differences. They follow Windows naming and order of
+// arguments, and return true to indicate no error occurred. [POSIX naming,
+// order of arguments, and meaning of return were followed initially, but
+// found to be less clear and cause more coding errors.]
+
+#if defined(BOOST_POSIX_API)
+
+#define BOOST_SET_CURRENT_DIRECTORY(P) (::chdir(P) == 0)
+#define BOOST_MOVE_FILE(OLD, NEW) (::rename(OLD, NEW) == 0)
+#define BOOST_RESIZE_FILE(P, SZ) (::truncate(P, SZ) == 0)
+
+#else // BOOST_WINDOWS_API
+
+#define BOOST_SET_CURRENT_DIRECTORY(P) (::SetCurrentDirectoryW(P) != 0)
+#define BOOST_MOVE_FILE(OLD, NEW) (::MoveFileExW(OLD, NEW, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) != 0)
+#define BOOST_RESIZE_FILE(P, SZ) (resize_file_impl(P, SZ) != 0)
+
+#endif
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+#if defined(linux) || defined(__linux) || defined(__linux__)
+//! Initializes fill_random implementation pointer. Implemented in unique_path.cpp.
+void init_fill_random_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver);
+#endif // defined(linux) || defined(__linux) || defined(__linux__)
+
+#if defined(BOOST_WINDOWS_API)
+//! Initializes directory iterator implementation. Implemented in directory.cpp.
+void init_directory_iterator_impl() noexcept;
+#endif // defined(BOOST_WINDOWS_API)
+
+//--------------------------------------------------------------------------------------//
+// //
+// helpers (all operating systems) //
+// //
+//--------------------------------------------------------------------------------------//
+
+namespace {
+
+// The number of retries remove_all should make if it detects that the directory it is about to enter has been replaced with a symlink or a regular file
+BOOST_CONSTEXPR_OR_CONST unsigned int remove_all_directory_replaced_retry_count = 5u;
+
+#if defined(BOOST_POSIX_API)
+
+// Size of a small buffer for a path that can be placed on stack, in character code units
+BOOST_CONSTEXPR_OR_CONST std::size_t small_path_size = 1024u;
+
+// Absolute maximum path length, in character code units, that we're willing to accept from various system calls.
+// This value is arbitrary, it is supposed to be a hard limit to avoid memory exhaustion
+// in some of the algorithms below in case of some corrupted or maliciously broken filesystem.
+// A few examples of path size limits:
+// - Windows: 32767 UTF-16 code units or 260 bytes for legacy multibyte APIs.
+// - Linux: 4096 bytes
+// - IRIX, HP-UX, Mac OS, QNX, FreeBSD, OpenBSD: 1024 bytes
+// - GNU/Hurd: no hard limit
+BOOST_CONSTEXPR_OR_CONST std::size_t absolute_path_max = 32u * 1024u;
+
+#endif // defined(BOOST_POSIX_API)
+
+// Maximum number of resolved symlinks before we register a loop
+BOOST_CONSTEXPR_OR_CONST unsigned int symloop_max =
+#if defined(SYMLOOP_MAX)
+ SYMLOOP_MAX < 40 ? 40 : SYMLOOP_MAX
+#else
+ 40
+#endif
+;
+
+// general helpers -----------------------------------------------------------------//
+
+#ifdef BOOST_POSIX_API
+
+//--------------------------------------------------------------------------------------//
+// //
+// POSIX-specific helpers //
+// //
+//--------------------------------------------------------------------------------------//
+
+inline bool not_found_error(int errval) noexcept
+{
+ return errval == ENOENT || errval == ENOTDIR;
+}
+
+/*!
+ * Closes a file descriptor and returns the result, similar to close(2). Unlike close(2), guarantees that the file descriptor is closed even if EINTR error happens.
+ *
+ * Some systems don't close the file descriptor in case if the thread is interrupted by a signal and close(2) returns EINTR.
+ * Other (most) systems do close the file descriptor even when when close(2) returns EINTR, and attempting to close it
+ * again could close a different file descriptor that was opened by a different thread. This function hides this difference in behavior.
+ *
+ * Future POSIX standards will likely fix this by introducing posix_close (see https://www.austingroupbugs.net/view.php?id=529)
+ * and prohibiting returning EINTR from close(2), but we still have to support older systems where this new behavior is not available and close(2)
+ * behaves differently between systems.
+ */
+inline int close_fd(int fd)
+{
+#if defined(hpux) || defined(_hpux) || defined(__hpux)
+ int res;
+ while (true)
+ {
+ res = ::close(fd);
+ if (BOOST_UNLIKELY(res < 0))
+ {
+ int err = errno;
+ if (err == EINTR)
+ continue;
+ }
+
+ break;
+ }
+
+ return res;
+#else
+ return ::close(fd);
+#endif
+}
+
+#if defined(BOOST_FILESYSTEM_HAS_STATX)
+
+//! A wrapper for statx libc function. Disable MSAN since at least on clang 10 it doesn't
+//! know which fields of struct statx are initialized by the syscall and misdetects errors.
+BOOST_FILESYSTEM_NO_SANITIZE_MEMORY
+BOOST_FORCEINLINE int invoke_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx)
+{
+ return ::statx(dirfd, path, flags, mask, stx);
+}
+
+#elif defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)
+
+//! statx emulation through fstatat
+int statx_fstatat(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx)
+{
+ struct ::stat st;
+ flags &= AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW;
+ int res = ::fstatat(dirfd, path, &st, flags);
+ if (BOOST_LIKELY(res == 0))
+ {
+ std::memset(stx, 0, sizeof(*stx));
+ stx->stx_mask = STATX_BASIC_STATS;
+ stx->stx_blksize = st.st_blksize;
+ stx->stx_nlink = st.st_nlink;
+ stx->stx_uid = st.st_uid;
+ stx->stx_gid = st.st_gid;
+ stx->stx_mode = st.st_mode;
+ stx->stx_ino = st.st_ino;
+ stx->stx_size = st.st_size;
+ stx->stx_blocks = st.st_blocks;
+ stx->stx_atime.tv_sec = st.st_atim.tv_sec;
+ stx->stx_atime.tv_nsec = st.st_atim.tv_nsec;
+ stx->stx_ctime.tv_sec = st.st_ctim.tv_sec;
+ stx->stx_ctime.tv_nsec = st.st_ctim.tv_nsec;
+ stx->stx_mtime.tv_sec = st.st_mtim.tv_sec;
+ stx->stx_mtime.tv_nsec = st.st_mtim.tv_nsec;
+ stx->stx_rdev_major = major(st.st_rdev);
+ stx->stx_rdev_minor = minor(st.st_rdev);
+ stx->stx_dev_major = major(st.st_dev);
+ stx->stx_dev_minor = minor(st.st_dev);
+ }
+
+ return res;
+}
+
+typedef int statx_t(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx);
+
+//! Pointer to the actual implementation of the statx implementation
+statx_t* statx_ptr = &statx_fstatat;
+
+inline int invoke_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx) noexcept
+{
+ return filesystem::detail::atomic_load_relaxed(statx_ptr)(dirfd, path, flags, mask, stx);
+}
+
+//! A wrapper for the statx syscall. Disable MSAN since at least on clang 10 it doesn't
+//! know which fields of struct statx are initialized by the syscall and misdetects errors.
+BOOST_FILESYSTEM_NO_SANITIZE_MEMORY
+int statx_syscall(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* stx)
+{
+ int res = ::syscall(__NR_statx, dirfd, path, flags, mask, stx);
+ if (res < 0)
+ {
+ const int err = errno;
+ if (BOOST_UNLIKELY(err == ENOSYS))
+ {
+ filesystem::detail::atomic_store_relaxed(statx_ptr, &statx_fstatat);
+ return statx_fstatat(dirfd, path, flags, mask, stx);
+ }
+ }
+
+ return res;
+}
+
+#endif // defined(BOOST_FILESYSTEM_HAS_STATX)
+
+#if defined(linux) || defined(__linux) || defined(__linux__)
+
+//! Initializes statx implementation pointer
+inline void init_statx_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver)
+{
+#if !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)
+ statx_t* stx = &statx_fstatat;
+ if (major_ver > 4u || (major_ver == 4u && minor_ver >= 11u))
+ stx = &statx_syscall;
+
+ filesystem::detail::atomic_store_relaxed(statx_ptr, stx);
+#endif // !defined(BOOST_FILESYSTEM_HAS_STATX) && defined(BOOST_FILESYSTEM_HAS_STATX_SYSCALL)
+}
+
+#endif // defined(linux) || defined(__linux) || defined(__linux__)
+
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+
+//! Returns \c true if the two \c statx structures refer to the same file
+inline bool equivalent_stat(struct ::statx const& s1, struct ::statx const& s2) noexcept
+{
+ return s1.stx_dev_major == s2.stx_dev_major && s1.stx_dev_minor == s2.stx_dev_minor && s1.stx_ino == s2.stx_ino;
+}
+
+//! Returns file type/access mode from \c statx structure
+inline mode_t get_mode(struct ::statx const& st) noexcept
+{
+ return st.stx_mode;
+}
+
+//! Returns file size from \c statx structure
+inline uintmax_t get_size(struct ::statx const& st) noexcept
+{
+ return st.stx_size;
+}
+
+//! Returns optimal block size from \c statx structure
+inline std::size_t get_blksize(struct ::statx const& st) noexcept
+{
+ return st.stx_blksize;
+}
+
+#else // defined(BOOST_FILESYSTEM_USE_STATX)
+
+//! Returns \c true if the two \c stat structures refer to the same file
+inline bool equivalent_stat(struct ::stat const& s1, struct ::stat const& s2) noexcept
+{
+ // According to the POSIX stat specs, "The st_ino and st_dev fields
+ // taken together uniquely identify the file within the system."
+ return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino;
+}
+
+//! Returns file type/access mode from \c stat structure
+inline mode_t get_mode(struct ::stat const& st) noexcept
+{
+ return st.st_mode;
+}
+
+//! Returns file size from \c stat structure
+inline uintmax_t get_size(struct ::stat const& st) noexcept
+{
+ return st.st_size;
+}
+
+//! Returns optimal block size from \c stat structure
+inline std::size_t get_blksize(struct ::stat const& st) noexcept
+{
+#if defined(BOOST_FILESYSTEM_HAS_STAT_ST_BLKSIZE)
+ return st.st_blksize;
+#else
+ return 4096u; // a suitable default used on most modern SSDs/HDDs
+#endif
+}
+
+#endif // defined(BOOST_FILESYSTEM_USE_STATX)
+
+} // namespace
+
+//! status() implementation
+file_status status_impl
+(
+ path const& p,
+ system::error_code* ec
+#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX)
+ , int basedir_fd
+#endif
+)
+{
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ struct ::statx path_stat;
+ int err = invoke_statx(basedir_fd, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &path_stat);
+#elif defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+ struct ::stat path_stat;
+ int err = ::fstatat(basedir_fd, p.c_str(), &path_stat, AT_NO_AUTOMOUNT);
+#else
+ struct ::stat path_stat;
+ int err = ::stat(p.c_str(), &path_stat);
+#endif
+
+ if (err != 0)
+ {
+ err = errno;
+ if (ec) // always report errno, even though some
+ ec->assign(err, system::system_category()); // errno values are not status_errors
+
+ if (not_found_error(err))
+ return fs::file_status(fs::file_not_found, fs::no_perms);
+
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", p, system::error_code(err, system::system_category())));
+
+ return fs::file_status(fs::status_error);
+ }
+
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE)))
+ {
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::status");
+ return fs::file_status(fs::status_error);
+ }
+#endif
+
+ const mode_t mode = get_mode(path_stat);
+ if (S_ISDIR(mode))
+ return fs::file_status(fs::directory_file, static_cast< perms >(mode) & fs::perms_mask);
+ if (S_ISREG(mode))
+ return fs::file_status(fs::regular_file, static_cast< perms >(mode) & fs::perms_mask);
+ if (S_ISBLK(mode))
+ return fs::file_status(fs::block_file, static_cast< perms >(mode) & fs::perms_mask);
+ if (S_ISCHR(mode))
+ return fs::file_status(fs::character_file, static_cast< perms >(mode) & fs::perms_mask);
+ if (S_ISFIFO(mode))
+ return fs::file_status(fs::fifo_file, static_cast< perms >(mode) & fs::perms_mask);
+ if (S_ISSOCK(mode))
+ return fs::file_status(fs::socket_file, static_cast< perms >(mode) & fs::perms_mask);
+
+ return fs::file_status(fs::type_unknown);
+}
+
+//! symlink_status() implementation
+file_status symlink_status_impl
+(
+ path const& p,
+ system::error_code* ec
+#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX)
+ , int basedir_fd
+#endif
+)
+{
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ struct ::statx path_stat;
+ int err = invoke_statx(basedir_fd, p.c_str(), AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &path_stat);
+#elif defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+ struct ::stat path_stat;
+ int err = ::fstatat(basedir_fd, p.c_str(), &path_stat, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT);
+#else
+ struct ::stat path_stat;
+ int err = ::lstat(p.c_str(), &path_stat);
+#endif
+
+ if (err != 0)
+ {
+ err = errno;
+ if (ec) // always report errno, even though some
+ ec->assign(err, system::system_category()); // errno values are not status_errors
+
+ if (not_found_error(err)) // these are not errors
+ return fs::file_status(fs::file_not_found, fs::no_perms);
+
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::symlink_status", p, system::error_code(err, system::system_category())));
+
+ return fs::file_status(fs::status_error);
+ }
+
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE)))
+ {
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::symlink_status");
+ return fs::file_status(fs::status_error);
+ }
+#endif
+
+ const mode_t mode = get_mode(path_stat);
+ if (S_ISREG(mode))
+ return fs::file_status(fs::regular_file, static_cast< perms >(mode) & fs::perms_mask);
+ if (S_ISDIR(mode))
+ return fs::file_status(fs::directory_file, static_cast< perms >(mode) & fs::perms_mask);
+ if (S_ISLNK(mode))
+ return fs::file_status(fs::symlink_file, static_cast< perms >(mode) & fs::perms_mask);
+ if (S_ISBLK(mode))
+ return fs::file_status(fs::block_file, static_cast< perms >(mode) & fs::perms_mask);
+ if (S_ISCHR(mode))
+ return fs::file_status(fs::character_file, static_cast< perms >(mode) & fs::perms_mask);
+ if (S_ISFIFO(mode))
+ return fs::file_status(fs::fifo_file, static_cast< perms >(mode) & fs::perms_mask);
+ if (S_ISSOCK(mode))
+ return fs::file_status(fs::socket_file, static_cast< perms >(mode) & fs::perms_mask);
+
+ return fs::file_status(fs::type_unknown);
+}
+
+namespace {
+
+//! Flushes buffered data and attributes written to the file to permanent storage
+inline int full_sync(int fd)
+{
+ while (true)
+ {
+#if defined(__APPLE__) && defined(__MACH__) && defined(F_FULLFSYNC)
+ // Mac OS does not flush data to physical storage with fsync()
+ int err = ::fcntl(fd, F_FULLFSYNC);
+#else
+ int err = ::fsync(fd);
+#endif
+ if (BOOST_UNLIKELY(err < 0))
+ {
+ err = errno;
+ // POSIX says fsync can return EINTR (https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html).
+ // fcntl(F_FULLFSYNC) isn't documented to return EINTR, but it doesn't hurt to check.
+ if (err == EINTR)
+ continue;
+
+ return err;
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
+//! Flushes buffered data written to the file to permanent storage
+inline int data_sync(int fd)
+{
+#if defined(BOOST_FILESYSTEM_HAS_FDATASYNC) && !(defined(__APPLE__) && defined(__MACH__) && defined(F_FULLFSYNC))
+ while (true)
+ {
+ int err = ::fdatasync(fd);
+ if (BOOST_UNLIKELY(err != 0))
+ {
+ err = errno;
+ // POSIX says fsync can return EINTR (https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html).
+ // It doesn't say so for fdatasync, but it is reasonable to expect it as well.
+ if (err == EINTR)
+ continue;
+
+ return err;
+ }
+
+ break;
+ }
+
+ return 0;
+#else
+ return full_sync(fd);
+#endif
+}
+
+//! Hints the filesystem to opportunistically preallocate storage for a file
+inline int preallocate_storage(int file, uintmax_t size)
+{
+#if defined(BOOST_FILESYSTEM_HAS_FALLOCATE)
+ if (BOOST_LIKELY(size > 0 && size <= static_cast< uintmax_t >((std::numeric_limits< off_t >::max)())))
+ {
+ while (true)
+ {
+ // Note: We intentionally use fallocate rather than posix_fallocate to avoid
+ // invoking glibc emulation that writes zeros to the end of the file.
+ // We want this call to act like a hint to the filesystem and an early
+ // check for the free storage space. We don't want to write zeros only
+ // to later overwrite them with the actual data.
+ int err = fallocate(file, FALLOC_FL_KEEP_SIZE, 0, static_cast< off_t >(size));
+ if (BOOST_UNLIKELY(err != 0))
+ {
+ err = errno;
+
+ // Ignore the error if the operation is not supported by the kernel or filesystem
+ if (err == EOPNOTSUPP || err == ENOSYS)
+ break;
+
+ if (err == EINTR)
+ continue;
+
+ return err;
+ }
+
+ break;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+//! copy_file implementation wrapper that preallocates storage for the target file
+template< typename CopyFileData >
+struct copy_file_data_preallocate
+{
+ //! copy_file implementation wrapper that preallocates storage for the target file before invoking the underlying copy implementation
+ static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize)
+ {
+ int err = preallocate_storage(outfile, size);
+ if (BOOST_UNLIKELY(err != 0))
+ return err;
+
+ return CopyFileData::impl(infile, outfile, size, blksize);
+ }
+};
+
+// Min and max buffer sizes are selected to minimize the overhead from system calls.
+// The values are picked based on coreutils cp(1) benchmarking data described here:
+// https://github.com/coreutils/coreutils/blob/d1b0257077c0b0f0ee25087efd46270345d1dd1f/src/ioblksize.h#L23-L72
+BOOST_CONSTEXPR_OR_CONST uint_least32_t min_read_write_buf_size = 8u * 1024u;
+BOOST_CONSTEXPR_OR_CONST uint_least32_t max_read_write_buf_size = 256u * 1024u;
+
+//! copy_file read/write loop implementation
+int copy_file_data_read_write_impl(int infile, int outfile, char* buf, std::size_t buf_size)
+{
+#if defined(BOOST_FILESYSTEM_HAS_POSIX_FADVISE)
+ ::posix_fadvise(infile, 0, 0, POSIX_FADV_SEQUENTIAL);
+#endif
+
+ // Don't use file size to limit the amount of data to copy since some filesystems, like procfs or sysfs,
+ // provide files with generated content and indicate that their size is zero or 4096. Just copy as much data
+ // as we can read from the input file.
+ while (true)
+ {
+ ssize_t sz_read = ::read(infile, buf, buf_size);
+ if (sz_read == 0)
+ break;
+ if (BOOST_UNLIKELY(sz_read < 0))
+ {
+ int err = errno;
+ if (err == EINTR)
+ continue;
+ return err;
+ }
+
+ // Allow for partial writes - see Advanced Unix Programming (2nd Ed.),
+ // Marc Rochkind, Addison-Wesley, 2004, page 94
+ for (ssize_t sz_wrote = 0; sz_wrote < sz_read;)
+ {
+ ssize_t sz = ::write(outfile, buf + sz_wrote, static_cast< std::size_t >(sz_read - sz_wrote));
+ if (BOOST_UNLIKELY(sz < 0))
+ {
+ int err = errno;
+ if (err == EINTR)
+ continue;
+ return err;
+ }
+
+ sz_wrote += sz;
+ }
+ }
+
+ return 0;
+}
+
+//! copy_file implementation that uses read/write loop (fallback using a stack buffer)
+int copy_file_data_read_write_stack_buf(int infile, int outfile)
+{
+ char stack_buf[min_read_write_buf_size];
+ return copy_file_data_read_write_impl(infile, outfile, stack_buf, sizeof(stack_buf));
+}
+
+//! copy_file implementation that uses read/write loop
+int copy_file_data_read_write(int infile, int outfile, uintmax_t size, std::size_t blksize)
+{
+ {
+ uintmax_t buf_sz = size;
+ // Prefer the buffer to be larger than the file size so that we don't have
+ // to perform an extra read if the file fits in the buffer exactly.
+ buf_sz += (buf_sz < ~static_cast< uintmax_t >(0u));
+ if (buf_sz < blksize)
+ buf_sz = blksize;
+ if (buf_sz < min_read_write_buf_size)
+ buf_sz = min_read_write_buf_size;
+ if (buf_sz > max_read_write_buf_size)
+ buf_sz = max_read_write_buf_size;
+ const std::size_t buf_size = static_cast< std::size_t >(boost::core::bit_ceil(static_cast< uint_least32_t >(buf_sz)));
+ std::unique_ptr< char[] > buf(new (std::nothrow) char[buf_size]);
+ if (BOOST_LIKELY(!!buf.get()))
+ return copy_file_data_read_write_impl(infile, outfile, buf.get(), buf_size);
+ }
+
+ return copy_file_data_read_write_stack_buf(infile, outfile);
+}
+
+typedef int copy_file_data_t(int infile, int outfile, uintmax_t size, std::size_t blksize);
+
+//! Pointer to the actual implementation of the copy_file_data implementation
+copy_file_data_t* copy_file_data = &copy_file_data_read_write;
+
+#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE)
+
+//! copy_file_data wrapper that tests if a read/write loop must be used for a given filesystem
+template< typename CopyFileData >
+int check_fs_type(int infile, int outfile, uintmax_t size, std::size_t blksize);
+
+#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE)
+
+#if defined(BOOST_FILESYSTEM_USE_SENDFILE)
+
+struct copy_file_data_sendfile
+{
+ //! copy_file implementation that uses sendfile loop. Requires sendfile to support file descriptors.
+ static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize)
+ {
+ // sendfile will not send more than this amount of data in one call
+ BOOST_CONSTEXPR_OR_CONST std::size_t max_batch_size = 0x7ffff000u;
+ uintmax_t offset = 0u;
+ while (offset < size)
+ {
+ uintmax_t size_left = size - offset;
+ std::size_t size_to_copy = max_batch_size;
+ if (size_left < static_cast< uintmax_t >(max_batch_size))
+ size_to_copy = static_cast< std::size_t >(size_left);
+ ssize_t sz = ::sendfile(outfile, infile, nullptr, size_to_copy);
+ if (BOOST_LIKELY(sz > 0))
+ {
+ offset += sz;
+ }
+ else if (sz < 0)
+ {
+ int err = errno;
+ if (err == EINTR)
+ continue;
+
+ if (offset == 0u)
+ {
+ // sendfile may fail with EINVAL if the underlying filesystem does not support it
+ if (err == EINVAL)
+ {
+ fallback_to_read_write:
+ return copy_file_data_read_write(infile, outfile, size, blksize);
+ }
+
+ if (err == ENOSYS)
+ {
+ filesystem::detail::atomic_store_relaxed(copy_file_data, &copy_file_data_read_write);
+ goto fallback_to_read_write;
+ }
+ }
+
+ return err;
+ }
+ else
+ {
+ // EOF: the input file was truncated while copying was in progress
+ break;
+ }
+ }
+
+ return 0;
+ }
+};
+
+#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE)
+
+#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE)
+
+struct copy_file_data_copy_file_range
+{
+ //! copy_file implementation that uses copy_file_range loop. Requires copy_file_range to support cross-filesystem copying.
+ static int impl(int infile, int outfile, uintmax_t size, std::size_t blksize)
+ {
+ // Although copy_file_range does not document any particular upper limit of one transfer, still use some upper bound to guarantee
+ // that size_t is not overflown in case if off_t is larger and the file size does not fit in size_t.
+ BOOST_CONSTEXPR_OR_CONST std::size_t max_batch_size = 0x7ffff000u;
+ uintmax_t offset = 0u;
+ while (offset < size)
+ {
+ uintmax_t size_left = size - offset;
+ std::size_t size_to_copy = max_batch_size;
+ if (size_left < static_cast< uintmax_t >(max_batch_size))
+ size_to_copy = static_cast< std::size_t >(size_left);
+ // Note: Use syscall directly to avoid depending on libc version. copy_file_range is added in glibc 2.27.
+ // uClibc-ng does not have copy_file_range as of the time of this writing (the latest uClibc-ng release is 1.0.33).
+ loff_t sz = ::syscall(__NR_copy_file_range, infile, (loff_t*)nullptr, outfile, (loff_t*)nullptr, size_to_copy, (unsigned int)0u);
+ if (BOOST_LIKELY(sz > 0))
+ {
+ offset += sz;
+ }
+ else if (sz < 0)
+ {
+ int err = errno;
+ if (err == EINTR)
+ continue;
+
+ if (offset == 0u)
+ {
+ // copy_file_range may fail with EINVAL if the underlying filesystem does not support it.
+ // In some RHEL/CentOS 7.7-7.8 kernel versions, copy_file_range on NFSv4 is also known to return EOPNOTSUPP
+ // if the remote server does not support COPY, despite that it is not a documented error code.
+ // See https://patchwork.kernel.org/project/linux-nfs/patch/20190411183418.4510-1-olga.kornievskaia@gmail.com/
+ // and https://bugzilla.redhat.com/show_bug.cgi?id=1783554.
+ if (err == EINVAL || err == EOPNOTSUPP)
+ {
+#if !defined(BOOST_FILESYSTEM_USE_SENDFILE)
+ fallback_to_read_write:
+#endif
+ return copy_file_data_read_write(infile, outfile, size, blksize);
+ }
+
+ if (err == EXDEV)
+ {
+#if defined(BOOST_FILESYSTEM_USE_SENDFILE)
+ fallback_to_sendfile:
+ return copy_file_data_sendfile::impl(infile, outfile, size, blksize);
+#else
+ goto fallback_to_read_write;
+#endif
+ }
+
+ if (err == ENOSYS)
+ {
+#if defined(BOOST_FILESYSTEM_USE_SENDFILE)
+ filesystem::detail::atomic_store_relaxed(copy_file_data, &check_fs_type< copy_file_data_preallocate< copy_file_data_sendfile > >);
+ goto fallback_to_sendfile;
+#else
+ filesystem::detail::atomic_store_relaxed(copy_file_data, &copy_file_data_read_write);
+ goto fallback_to_read_write;
+#endif
+ }
+ }
+
+ return err;
+ }
+ else
+ {
+ // EOF: the input file was truncated while copying was in progress
+ break;
+ }
+ }
+
+ return 0;
+ }
+};
+
+#endif // defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE)
+
+#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE)
+
+//! copy_file_data wrapper that tests if a read/write loop must be used for a given filesystem
+template< typename CopyFileData >
+int check_fs_type(int infile, int outfile, uintmax_t size, std::size_t blksize)
+{
+ {
+ // Some filesystems have regular files with generated content. Such files have arbitrary size, including zero,
+ // but have actual content. Linux system calls sendfile or copy_file_range will not copy contents of such files,
+ // so we must use a read/write loop to handle them.
+ // https://lore.kernel.org/linux-fsdevel/20210212044405.4120619-1-drinkcat@chromium.org/T/
+ struct statfs sfs;
+ while (true)
+ {
+ int err = ::fstatfs(infile, &sfs);
+ if (BOOST_UNLIKELY(err < 0))
+ {
+ err = errno;
+ if (err == EINTR)
+ continue;
+
+ goto fallback_to_read_write;
+ }
+
+ break;
+ }
+
+ if (BOOST_UNLIKELY(sfs.f_type == PROC_SUPER_MAGIC ||
+ sfs.f_type == SYSFS_MAGIC ||
+ sfs.f_type == TRACEFS_MAGIC ||
+ sfs.f_type == DEBUGFS_MAGIC))
+ {
+ fallback_to_read_write:
+ return copy_file_data_read_write(infile, outfile, size, blksize);
+ }
+ }
+
+ return CopyFileData::impl(infile, outfile, size, blksize);
+}
+
+#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE)
+
+#if defined(linux) || defined(__linux) || defined(__linux__)
+
+//! Initializes copy_file_data implementation pointer
+inline void init_copy_file_data_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver)
+{
+#if defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE)
+ copy_file_data_t* cfd = &copy_file_data_read_write;
+
+#if defined(BOOST_FILESYSTEM_USE_SENDFILE)
+ // sendfile started accepting file descriptors as the target in Linux 2.6.33
+ if (major_ver > 2u || (major_ver == 2u && (minor_ver > 6u || (minor_ver == 6u && patch_ver >= 33u))))
+ cfd = &check_fs_type< copy_file_data_preallocate< copy_file_data_sendfile > >;
+#endif
+
+#if defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE)
+ // Although copy_file_range appeared in Linux 4.5, it did not support cross-filesystem copying until 5.3.
+ // copy_file_data_copy_file_range will fallback to copy_file_data_sendfile if copy_file_range returns EXDEV.
+ if (major_ver > 4u || (major_ver == 4u && minor_ver >= 5u))
+ cfd = &check_fs_type< copy_file_data_preallocate< copy_file_data_copy_file_range > >;
+#endif
+
+ filesystem::detail::atomic_store_relaxed(copy_file_data, cfd);
+#endif // defined(BOOST_FILESYSTEM_USE_SENDFILE) || defined(BOOST_FILESYSTEM_USE_COPY_FILE_RANGE)
+}
+
+#endif // defined(linux) || defined(__linux) || defined(__linux__)
+
+#if defined(linux) || defined(__linux) || defined(__linux__)
+
+struct syscall_initializer
+{
+ syscall_initializer()
+ {
+ struct ::utsname system_info;
+ if (BOOST_UNLIKELY(::uname(&system_info) < 0))
+ return;
+
+ unsigned int major_ver = 0u, minor_ver = 0u, patch_ver = 0u;
+ int count = std::sscanf(system_info.release, "%u.%u.%u", &major_ver, &minor_ver, &patch_ver);
+ if (BOOST_UNLIKELY(count < 3))
+ return;
+
+ init_statx_impl(major_ver, minor_ver, patch_ver);
+ init_copy_file_data_impl(major_ver, minor_ver, patch_ver);
+ init_fill_random_impl(major_ver, minor_ver, patch_ver);
+ }
+};
+
+BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN
+const syscall_initializer syscall_init;
+
+#endif // defined(linux) || defined(__linux) || defined(__linux__)
+
+//! remove() implementation
+inline bool remove_impl
+(
+ path const& p,
+ fs::file_type type,
+ error_code* ec
+#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+ , int basedir_fd = AT_FDCWD
+#endif
+)
+{
+ if (type == fs::file_not_found)
+ return false;
+
+ int res;
+#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+ res = ::unlinkat(basedir_fd, p.c_str(), type == fs::directory_file ? AT_REMOVEDIR : 0);
+#else
+ if (type == fs::directory_file)
+ res = ::rmdir(p.c_str());
+ else
+ res = ::unlink(p.c_str());
+#endif
+
+ if (res != 0)
+ {
+ int err = errno;
+ if (BOOST_UNLIKELY(!not_found_error(err)))
+ emit_error(err, p, ec, "boost::filesystem::remove");
+
+ return false;
+ }
+
+ return true;
+}
+
+//! remove() implementation
+inline bool remove_impl(path const& p, error_code* ec)
+{
+ // Since POSIX remove() is specified to work with either files or directories, in a
+ // perfect world it could just be called. But some important real-world operating
+ // systems (Windows, Mac OS, for example) don't implement the POSIX spec. So
+ // we have to distinguish between files and directories and call corresponding APIs
+ // to remove them.
+
+ error_code local_ec;
+ fs::file_type type = fs::detail::symlink_status_impl(p, &local_ec).type();
+ if (BOOST_UNLIKELY(type == fs::status_error))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove", p, local_ec));
+
+ *ec = local_ec;
+ return false;
+ }
+
+ return fs::detail::remove_impl(p, type, ec);
+}
+
+//! remove_all() implementation
+uintmax_t remove_all_impl
+(
+ path const& p,
+ error_code* ec
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+ , int parentdir_fd = AT_FDCWD
+#endif
+)
+{
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+ fs::path filename;
+ const fs::path* remove_path = &p;
+ if (parentdir_fd != AT_FDCWD)
+ {
+ filename = path_algorithms::filename_v4(p);
+ remove_path = &filename;
+ }
+#endif
+
+ error_code dit_create_ec;
+ for (unsigned int attempt = 0u; attempt < remove_all_directory_replaced_retry_count; ++attempt)
+ {
+ fs::file_type type;
+ {
+ error_code local_ec;
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+ type = fs::detail::symlink_status_impl(*remove_path, &local_ec, parentdir_fd).type();
+#else
+ type = fs::detail::symlink_status_impl(p, &local_ec).type();
+#endif
+
+ if (type == fs::file_not_found)
+ return 0u;
+
+ if (BOOST_UNLIKELY(type == fs::status_error))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec));
+
+ *ec = local_ec;
+ return static_cast< uintmax_t >(-1);
+ }
+ }
+
+ uintmax_t count = 0u;
+ if (type == fs::directory_file) // but not a directory symlink
+ {
+ fs::directory_iterator itr;
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+ fs::detail::directory_iterator_params params{ fs::detail::openat_directory(parentdir_fd, *remove_path, directory_options::_detail_no_follow, dit_create_ec) };
+ int dir_fd = -1;
+ if (BOOST_LIKELY(!dit_create_ec))
+ {
+ // Save dir_fd as constructing the iterator will move the fd into the iterator context
+ dir_fd = params.dir_fd.get();
+ fs::detail::directory_iterator_construct(itr, *remove_path, directory_options::_detail_no_follow, &params, &dit_create_ec);
+ }
+#else
+ fs::detail::directory_iterator_construct
+ (
+ itr,
+ p,
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+ directory_options::_detail_no_follow,
+#else
+ directory_options::none,
+#endif
+ nullptr,
+ &dit_create_ec
+ );
+#endif
+
+ if (BOOST_UNLIKELY(!!dit_create_ec))
+ {
+ if (dit_create_ec == error_code(ENOTDIR, system_category()))
+ continue;
+
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+ // If open(2) with O_NOFOLLOW fails with ELOOP, this means that either the path contains a loop
+ // of symbolic links, or the last element of the path is a symbolic link. Given that lstat(2) above
+ // did not fail, most likely it is the latter case. I.e. between the lstat above and this open call
+ // the filesystem was modified so that the path no longer refers to a directory file (as opposed to a symlink).
+ if (dit_create_ec == error_code(ELOOP, system_category()))
+ continue;
+#endif // defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, dit_create_ec));
+
+ *ec = dit_create_ec;
+ return static_cast< uintmax_t >(-1);
+ }
+
+ const fs::directory_iterator end_dit;
+ while (itr != end_dit)
+ {
+ count += fs::detail::remove_all_impl
+ (
+ itr->path(),
+ ec
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+ , dir_fd
+#endif
+ );
+ if (ec && *ec)
+ return static_cast< uintmax_t >(-1);
+
+ fs::detail::directory_iterator_increment(itr, ec);
+ if (ec && *ec)
+ return static_cast< uintmax_t >(-1);
+ }
+ }
+
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW) && defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+ count += fs::detail::remove_impl(*remove_path, type, ec, parentdir_fd);
+#else
+ count += fs::detail::remove_impl(p, type, ec);
+#endif
+ if (ec && *ec)
+ return static_cast< uintmax_t >(-1);
+
+ return count;
+ }
+
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all: path cannot be opened as a directory", p, dit_create_ec));
+
+ *ec = dit_create_ec;
+ return static_cast< uintmax_t >(-1);
+}
+
+#else // defined(BOOST_POSIX_API)
+
+//--------------------------------------------------------------------------------------//
+// //
+// Windows-specific helpers //
+// //
+//--------------------------------------------------------------------------------------//
+
+//! FILE_BASIC_INFO definition from Windows SDK
+struct file_basic_info
+{
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ DWORD FileAttributes;
+};
+
+//! FILE_DISPOSITION_INFO definition from Windows SDK
+struct file_disposition_info
+{
+ BOOLEAN DeleteFile;
+};
+
+//! FILE_DISPOSITION_INFO_EX definition from Windows SDK
+struct file_disposition_info_ex
+{
+ DWORD Flags;
+};
+
+#ifndef FILE_DISPOSITION_FLAG_DELETE
+#define FILE_DISPOSITION_FLAG_DELETE 0x00000001
+#endif
+// Available since Windows 10 1709
+#ifndef FILE_DISPOSITION_FLAG_POSIX_SEMANTICS
+#define FILE_DISPOSITION_FLAG_POSIX_SEMANTICS 0x00000002
+#endif
+// Available since Windows 10 1809
+#ifndef FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE
+#define FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE 0x00000010
+#endif
+
+// REPARSE_DATA_BUFFER related definitions are found in ntifs.h, which is part of the
+// Windows Device Driver Kit. Since that's inconvenient, the definitions are provided
+// here. See http://msdn.microsoft.com/en-us/library/ms791514.aspx
+struct reparse_data_buffer
+{
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union
+ {
+ /*
+ * In SymbolicLink and MountPoint reparse points, there are two names.
+ * SubstituteName is the effective replacement path for the reparse point.
+ * This is what should be used for path traversal.
+ * PrintName is intended for presentation to the user and may omit some
+ * elements of the path or be absent entirely.
+ *
+ * Examples of substitute and print names:
+ * mklink /D ldrive c:\
+ * SubstituteName: "\??\c:\"
+ * PrintName: "c:\"
+ *
+ * mklink /J ldrive c:\
+ * SubstituteName: "\??\C:\"
+ * PrintName: "c:\"
+ *
+ * junction ldrive c:\
+ * SubstituteName: "\??\C:\"
+ * PrintName: ""
+ *
+ * box.com mounted cloud storage
+ * SubstituteName: "\??\Volume{<UUID>}\"
+ * PrintName: ""
+ */
+ struct
+ {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct
+ {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct
+ {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ };
+};
+
+// Our convenience type for allocating REPARSE_DATA_BUFFER along with sufficient space after it
+union reparse_data_buffer_with_storage
+{
+ reparse_data_buffer rdb;
+ unsigned char storage[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+};
+
+// Windows kernel32.dll functions that may or may not be present
+// must be accessed through pointers
+
+typedef BOOL (WINAPI CreateHardLinkW_t)(
+ /*__in*/ LPCWSTR lpFileName,
+ /*__in*/ LPCWSTR lpExistingFileName,
+ /*__reserved*/ LPSECURITY_ATTRIBUTES lpSecurityAttributes);
+
+CreateHardLinkW_t* create_hard_link_api = nullptr;
+
+typedef BOOLEAN (WINAPI CreateSymbolicLinkW_t)(
+ /*__in*/ LPCWSTR lpSymlinkFileName,
+ /*__in*/ LPCWSTR lpTargetFileName,
+ /*__in*/ DWORD dwFlags);
+
+CreateSymbolicLinkW_t* create_symbolic_link_api = nullptr;
+
+//! SetFileInformationByHandle signature. Available since Windows Vista.
+typedef BOOL (WINAPI SetFileInformationByHandle_t)(
+ /*_In_*/ HANDLE hFile,
+ /*_In_*/ file_info_by_handle_class FileInformationClass, // the actual type is FILE_INFO_BY_HANDLE_CLASS enum
+ /*_In_reads_bytes_(dwBufferSize)*/ LPVOID lpFileInformation,
+ /*_In_*/ DWORD dwBufferSize);
+
+SetFileInformationByHandle_t* set_file_information_by_handle_api = nullptr;
+
+} // unnamed namespace
+
+GetFileInformationByHandleEx_t* get_file_information_by_handle_ex_api = nullptr;
+
+NtCreateFile_t* nt_create_file_api = nullptr;
+NtQueryDirectoryFile_t* nt_query_directory_file_api = nullptr;
+
+namespace {
+
+//! remove() implementation type
+enum remove_impl_type
+{
+ remove_nt5, //!< Use Windows XP API
+ remove_disp, //!< Use FILE_DISPOSITION_INFO (Windows Vista and later)
+ remove_disp_ex_flag_posix_semantics, //!< Use FILE_DISPOSITION_INFO_EX with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS
+ remove_disp_ex_flag_ignore_readonly //!< Use FILE_DISPOSITION_INFO_EX with FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE
+};
+
+remove_impl_type g_remove_impl_type = remove_nt5;
+
+//! Initializes WinAPI function pointers
+BOOST_FILESYSTEM_INIT_FUNC init_winapi_func_ptrs()
+{
+ boost::winapi::HMODULE_ h = boost::winapi::GetModuleHandleW(L"kernel32.dll");
+ if (BOOST_LIKELY(!!h))
+ {
+ GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = (GetFileInformationByHandleEx_t*)boost::winapi::get_proc_address(h, "GetFileInformationByHandleEx");
+ filesystem::detail::atomic_store_relaxed(get_file_information_by_handle_ex_api, get_file_information_by_handle_ex);
+ SetFileInformationByHandle_t* set_file_information_by_handle = (SetFileInformationByHandle_t*)boost::winapi::get_proc_address(h, "SetFileInformationByHandle");
+ filesystem::detail::atomic_store_relaxed(set_file_information_by_handle_api, set_file_information_by_handle);
+ filesystem::detail::atomic_store_relaxed(create_hard_link_api, (CreateHardLinkW_t*)boost::winapi::get_proc_address(h, "CreateHardLinkW"));
+ filesystem::detail::atomic_store_relaxed(create_symbolic_link_api, (CreateSymbolicLinkW_t*)boost::winapi::get_proc_address(h, "CreateSymbolicLinkW"));
+
+ if (get_file_information_by_handle_ex && set_file_information_by_handle)
+ {
+ // Enable the most advanced implementation based on GetFileInformationByHandleEx/SetFileInformationByHandle.
+ // If certain flags are not supported by the OS, the remove() implementation will downgrade accordingly.
+ filesystem::detail::atomic_store_relaxed(g_remove_impl_type, remove_disp_ex_flag_ignore_readonly);
+ }
+ }
+
+ h = boost::winapi::GetModuleHandleW(L"ntdll.dll");
+ if (BOOST_LIKELY(!!h))
+ {
+ filesystem::detail::atomic_store_relaxed(nt_create_file_api, (NtCreateFile_t*)boost::winapi::get_proc_address(h, "NtCreateFile"));
+ filesystem::detail::atomic_store_relaxed(nt_query_directory_file_api, (NtQueryDirectoryFile_t*)boost::winapi::get_proc_address(h, "NtQueryDirectoryFile"));
+ }
+
+ init_directory_iterator_impl();
+
+ return BOOST_FILESYSTEM_INITRETSUCCESS_V;
+}
+
+#if defined(_MSC_VER)
+
+#if _MSC_VER >= 1400
+
+#pragma section(".CRT$XCL", long, read)
+__declspec(allocate(".CRT$XCL")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN
+extern const init_func_ptr_t p_init_winapi_func_ptrs = &init_winapi_func_ptrs;
+
+#else // _MSC_VER >= 1400
+
+#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
+#pragma data_seg(push, old_seg)
+#endif
+#pragma data_seg(".CRT$XCL")
+BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN
+extern const init_func_ptr_t p_init_winapi_func_ptrs = &init_winapi_func_ptrs;
+#pragma data_seg()
+#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
+#pragma data_seg(pop, old_seg)
+#endif
+
+#endif // _MSC_VER >= 1400
+
+#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN)
+//! Makes sure the global initializer pointers are referenced and not removed by linker
+struct globals_retainer
+{
+ const init_func_ptr_t* volatile m_p_init_winapi_func_ptrs;
+
+ globals_retainer() { m_p_init_winapi_func_ptrs = &p_init_winapi_func_ptrs; }
+};
+BOOST_ATTRIBUTE_UNUSED
+const globals_retainer g_globals_retainer;
+#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN)
+
+#else // defined(_MSC_VER)
+
+//! Invokes WinAPI function pointers initialization
+struct winapi_func_ptrs_initializer
+{
+ winapi_func_ptrs_initializer() { init_winapi_func_ptrs(); }
+};
+
+BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN
+const winapi_func_ptrs_initializer winapi_func_ptrs_init;
+
+#endif // defined(_MSC_VER)
+
+
+inline std::wstring wgetenv(const wchar_t* name)
+{
+ // use a separate buffer since C++03 basic_string is not required to be contiguous
+ const DWORD size = ::GetEnvironmentVariableW(name, nullptr, 0);
+ if (size > 0)
+ {
+ std::unique_ptr< wchar_t[] > buf(new wchar_t[size]);
+ if (BOOST_LIKELY(::GetEnvironmentVariableW(name, buf.get(), size) > 0))
+ return std::wstring(buf.get());
+ }
+
+ return std::wstring();
+}
+
+inline bool not_found_error(int errval) noexcept
+{
+ return errval == ERROR_FILE_NOT_FOUND || errval == ERROR_PATH_NOT_FOUND || errval == ERROR_INVALID_NAME // "tools/jam/src/:sys:stat.h", "//foo"
+ || errval == ERROR_INVALID_DRIVE // USB card reader with no card inserted
+ || errval == ERROR_NOT_READY // CD/DVD drive with no disc inserted
+ || errval == ERROR_INVALID_PARAMETER // ":sys:stat.h"
+ || errval == ERROR_BAD_PATHNAME // "//no-host" on Win64
+ || errval == ERROR_BAD_NETPATH // "//no-host" on Win32
+ || errval == ERROR_BAD_NET_NAME; // "//no-host/no-share" on Win10 x64
+}
+
+// these constants come from inspecting some Microsoft sample code
+inline DWORD to_time_t(FILETIME const& ft, std::time_t& t)
+{
+ uint64_t ut = (static_cast< uint64_t >(ft.dwHighDateTime) << 32u) | ft.dwLowDateTime;
+ if (BOOST_UNLIKELY(ut > static_cast< uint64_t >((std::numeric_limits< int64_t >::max)())))
+ return ERROR_INVALID_DATA;
+
+ // On Windows, time_t is signed, and negative values are possible since FILETIME epoch is earlier than POSIX epoch
+ int64_t st = static_cast< int64_t >(ut) / 10000000 - 11644473600ll;
+ if (BOOST_UNLIKELY(st < static_cast< int64_t >((std::numeric_limits< std::time_t >::min)()) ||
+ st > static_cast< int64_t >((std::numeric_limits< std::time_t >::max)())))
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ t = static_cast< std::time_t >(st);
+ return 0u;
+}
+
+inline DWORD to_FILETIME(std::time_t t, FILETIME& ft)
+{
+ // On Windows, time_t is signed, and negative values are possible since FILETIME epoch is earlier than POSIX epoch
+ int64_t st = static_cast< int64_t >(t);
+ if (BOOST_UNLIKELY(st < ((std::numeric_limits< int64_t >::min)() / 10000000 - 11644473600ll) ||
+ st > ((std::numeric_limits< int64_t >::max)() / 10000000 - 11644473600ll)))
+ {
+ return ERROR_INVALID_DATA;
+ }
+
+ st = (st + 11644473600ll) * 10000000;
+ uint64_t ut = static_cast< uint64_t >(st);
+ ft.dwLowDateTime = static_cast< DWORD >(ut);
+ ft.dwHighDateTime = static_cast< DWORD >(ut >> 32u);
+
+ return 0u;
+}
+
+} // unnamed namespace
+
+//! The flag indicates whether OBJ_DONT_REPARSE flag is not supported by the kernel
+static bool g_no_obj_dont_reparse = false;
+
+//! Creates a file handle for a file relative to a previously opened base directory. The file path must be relative and in preferred format.
+boost::winapi::NTSTATUS_ nt_create_file_handle_at
+(
+ unique_handle& out,
+ HANDLE basedir_handle,
+ boost::filesystem::path const& p,
+ ULONG FileAttributes,
+ ACCESS_MASK DesiredAccess,
+ ULONG ShareMode,
+ ULONG CreateDisposition,
+ ULONG CreateOptions
+)
+{
+ NtCreateFile_t* nt_create_file = filesystem::detail::atomic_load_relaxed(nt_create_file_api);
+ if (BOOST_UNLIKELY(!nt_create_file))
+ return STATUS_NOT_IMPLEMENTED;
+
+ unicode_string obj_name = {};
+ obj_name.Buffer = const_cast< wchar_t* >(p.c_str());
+ obj_name.Length = obj_name.MaximumLength = static_cast< USHORT >(p.size() * sizeof(wchar_t));
+
+ object_attributes obj_attrs = {};
+ obj_attrs.Length = sizeof(obj_attrs);
+ obj_attrs.RootDirectory = basedir_handle;
+ obj_attrs.ObjectName = &obj_name;
+
+ obj_attrs.Attributes = OBJ_CASE_INSENSITIVE;
+ if ((CreateOptions & FILE_OPEN_REPARSE_POINT) != 0u && !filesystem::detail::atomic_load_relaxed(g_no_obj_dont_reparse))
+ obj_attrs.Attributes |= OBJ_DONT_REPARSE;
+
+ io_status_block iosb;
+ HANDLE out_handle = INVALID_HANDLE_VALUE;
+ boost::winapi::NTSTATUS_ status = nt_create_file
+ (
+ &out_handle,
+ DesiredAccess,
+ &obj_attrs,
+ &iosb,
+ nullptr, // AllocationSize
+ FileAttributes,
+ ShareMode,
+ CreateDisposition,
+ CreateOptions,
+ nullptr, // EaBuffer
+ 0u // EaLength
+ );
+
+ if (BOOST_UNLIKELY(status == STATUS_INVALID_PARAMETER && (obj_attrs.Attributes & OBJ_DONT_REPARSE) != 0u))
+ {
+ // OBJ_DONT_REPARSE is supported since Windows 10, retry without it
+ filesystem::detail::atomic_store_relaxed(g_no_obj_dont_reparse, true);
+ obj_attrs.Attributes &= ~static_cast< ULONG >(OBJ_DONT_REPARSE);
+
+ status = nt_create_file
+ (
+ &out_handle,
+ DesiredAccess,
+ &obj_attrs,
+ &iosb,
+ nullptr, // AllocationSize
+ FileAttributes,
+ ShareMode,
+ CreateDisposition,
+ CreateOptions,
+ nullptr, // EaBuffer
+ 0u // EaLength
+ );
+ }
+
+ out.reset(out_handle);
+
+ return status;
+}
+
+ULONG get_reparse_point_tag_ioctl(HANDLE h, path const& p, error_code* ec)
+{
+ std::unique_ptr< reparse_data_buffer_with_storage > buf(new (std::nothrow) reparse_data_buffer_with_storage);
+ if (BOOST_UNLIKELY(!buf.get()))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("Cannot allocate memory to query reparse point", p, make_error_code(system::errc::not_enough_memory)));
+
+ *ec = make_error_code(system::errc::not_enough_memory);
+ return 0u;
+ }
+
+ // Query the reparse data
+ DWORD dwRetLen = 0u;
+ BOOL result = ::DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, nullptr, 0, buf.get(), sizeof(*buf), &dwRetLen, nullptr);
+ if (BOOST_UNLIKELY(!result))
+ {
+ DWORD err = ::GetLastError();
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("Failed to query reparse point", p, error_code(err, system_category())));
+
+ ec->assign(err, system_category());
+ return 0u;
+ }
+
+ return buf->rdb.ReparseTag;
+}
+
+namespace {
+
+inline std::size_t get_full_path_name(path const& src, std::size_t len, wchar_t* buf, wchar_t** p)
+{
+ return static_cast< std::size_t >(::GetFullPathNameW(src.c_str(), static_cast< DWORD >(len), buf, p));
+}
+
+inline fs::file_status process_status_failure(DWORD errval, path const& p, error_code* ec)
+{
+ if (ec) // always report errval, even though some
+ ec->assign(errval, system_category()); // errval values are not status_errors
+
+ if (not_found_error(errval))
+ {
+ return fs::file_status(fs::file_not_found, fs::no_perms);
+ }
+ else if (errval == ERROR_SHARING_VIOLATION)
+ {
+ return fs::file_status(fs::type_unknown);
+ }
+
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::status", p, error_code(errval, system_category())));
+
+ return fs::file_status(fs::status_error);
+}
+
+inline fs::file_status process_status_failure(path const& p, error_code* ec)
+{
+ return process_status_failure(::GetLastError(), p, ec);
+}
+
+} // namespace
+
+//! (symlink_)status() by handle implementation
+fs::file_status status_by_handle(HANDLE h, path const& p, error_code* ec)
+{
+ fs::file_type ftype;
+ DWORD attrs;
+ ULONG reparse_tag = 0u;
+ GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api);
+ if (BOOST_LIKELY(get_file_information_by_handle_ex != nullptr))
+ {
+ file_attribute_tag_info info;
+ BOOL res = get_file_information_by_handle_ex(h, file_attribute_tag_info_class, &info, sizeof(info));
+ if (BOOST_UNLIKELY(!res))
+ {
+ // On FAT/exFAT filesystems requesting FILE_ATTRIBUTE_TAG_INFO returns ERROR_INVALID_PARAMETER.
+ // Presumably, this is because these filesystems don't support reparse points, so ReparseTag
+ // cannot be returned. Also check ERROR_NOT_SUPPORTED for good measure. Fall back to the legacy
+ // code path in this case.
+ DWORD err = ::GetLastError();
+ if (err == ERROR_INVALID_PARAMETER || err == ERROR_NOT_SUPPORTED)
+ goto use_get_file_information_by_handle;
+
+ return process_status_failure(err, p, ec);
+ }
+
+ attrs = info.FileAttributes;
+ reparse_tag = info.ReparseTag;
+ }
+ else
+ {
+ use_get_file_information_by_handle:
+ BY_HANDLE_FILE_INFORMATION info;
+ BOOL res = ::GetFileInformationByHandle(h, &info);
+ if (BOOST_UNLIKELY(!res))
+ return process_status_failure(p, ec);
+
+ attrs = info.dwFileAttributes;
+
+ if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u)
+ {
+ reparse_tag = get_reparse_point_tag_ioctl(h, p, ec);
+ if (ec)
+ {
+ if (BOOST_UNLIKELY(!!ec))
+ return fs::file_status(fs::status_error);
+ }
+ }
+ }
+
+ if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) != 0u)
+ {
+ if (reparse_tag == IO_REPARSE_TAG_DEDUP)
+ ftype = fs::regular_file;
+ else if (is_reparse_point_tag_a_symlink(reparse_tag))
+ ftype = fs::symlink_file;
+ else
+ ftype = fs::reparse_file;
+ }
+ else if ((attrs & FILE_ATTRIBUTE_DIRECTORY) != 0u)
+ {
+ ftype = fs::directory_file;
+ }
+ else
+ {
+ ftype = fs::regular_file;
+ }
+
+ return fs::file_status(ftype, make_permissions(p, attrs));
+}
+
+namespace {
+
+//! symlink_status() implementation
+fs::file_status symlink_status_impl(path const& p, error_code* ec)
+{
+ // Normally, we only need FILE_READ_ATTRIBUTES access mode. But SMBv1 reports incorrect
+ // file attributes in GetFileInformationByHandleEx in this case (e.g. it reports FILE_ATTRIBUTE_NORMAL
+ // for a directory in a SMBv1 share), so we add FILE_READ_EA as a workaround.
+ // https://github.com/boostorg/filesystem/issues/282
+ unique_handle h(create_file_handle(
+ p.c_str(),
+ FILE_READ_ATTRIBUTES | FILE_READ_EA,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr, // lpSecurityAttributes
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT));
+
+ if (!h)
+ {
+ // For some system files and folders like "System Volume Information" CreateFileW fails
+ // with ERROR_ACCESS_DENIED. GetFileAttributesW succeeds for such files, so try that.
+ // Though this will only help if the file is not a reparse point (symlink or not).
+ DWORD err = ::GetLastError();
+ if (err == ERROR_ACCESS_DENIED)
+ {
+ DWORD attrs = ::GetFileAttributesW(p.c_str());
+ if (attrs != INVALID_FILE_ATTRIBUTES)
+ {
+ if ((attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0u)
+ return fs::file_status((attrs & FILE_ATTRIBUTE_DIRECTORY) ? fs::directory_file : fs::regular_file, make_permissions(p, attrs));
+ }
+ else
+ {
+ err = ::GetLastError();
+ }
+ }
+
+ return process_status_failure(err, p, ec);
+ }
+
+ return detail::status_by_handle(h.get(), p, ec);
+}
+
+//! status() implementation
+fs::file_status status_impl(path const& p, error_code* ec)
+{
+ // We should first test if the file is a symlink or a reparse point. Resolving some reparse
+ // points by opening the file may fail, and status() should return file_status(reparse_file) in this case.
+ // Which is what symlink_status() returns.
+ fs::file_status st(detail::symlink_status_impl(p, ec));
+ if (st.type() == symlink_file)
+ {
+ // Resolve the symlink
+ unique_handle h(create_file_handle(
+ p.c_str(),
+ FILE_READ_ATTRIBUTES | FILE_READ_EA, // see the comment in symlink_status_impl re. access mode
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr, // lpSecurityAttributes
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS));
+
+ if (!h)
+ return process_status_failure(p, ec);
+
+ st = detail::status_by_handle(h.get(), p, ec);
+ }
+
+ return st;
+}
+
+//! remove() implementation for Windows XP and older
+bool remove_nt5_impl(path const& p, DWORD attrs, error_code* ec)
+{
+ const bool is_directory = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0;
+ const bool is_read_only = (attrs & FILE_ATTRIBUTE_READONLY) != 0;
+ if (is_read_only)
+ {
+ // RemoveDirectoryW and DeleteFileW do not allow to remove a read-only file, so we have to drop the attribute
+ DWORD new_attrs = attrs & ~FILE_ATTRIBUTE_READONLY;
+ BOOL res = ::SetFileAttributesW(p.c_str(), new_attrs);
+ if (BOOST_UNLIKELY(!res))
+ {
+ DWORD err = ::GetLastError();
+ if (!not_found_error(err))
+ emit_error(err, p, ec, "boost::filesystem::remove");
+
+ return false;
+ }
+ }
+
+ BOOL res;
+ if (!is_directory)
+ {
+ // DeleteFileW works for file symlinks by removing the symlink, not the target.
+ res = ::DeleteFileW(p.c_str());
+ }
+ else
+ {
+ // RemoveDirectoryW works for symlinks and junctions by removing the symlink, not the target,
+ // even if the target directory is not empty.
+ // Note that unlike opening the directory with FILE_FLAG_DELETE_ON_CLOSE flag, RemoveDirectoryW
+ // will fail if the directory is not empty.
+ res = ::RemoveDirectoryW(p.c_str());
+ }
+
+ if (BOOST_UNLIKELY(!res))
+ {
+ DWORD err = ::GetLastError();
+ if (!not_found_error(err))
+ {
+ if (is_read_only)
+ {
+ // Try to restore the read-only attribute
+ ::SetFileAttributesW(p.c_str(), attrs);
+ }
+
+ emit_error(err, p, ec, "boost::filesystem::remove");
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+//! remove() by handle implementation for Windows Vista and newer
+DWORD remove_nt6_by_handle(HANDLE handle, remove_impl_type impl)
+{
+ GetFileInformationByHandleEx_t* get_file_information_by_handle_ex = filesystem::detail::atomic_load_relaxed(get_file_information_by_handle_ex_api);
+ SetFileInformationByHandle_t* set_file_information_by_handle = filesystem::detail::atomic_load_relaxed(set_file_information_by_handle_api);
+ DWORD err = 0u;
+ switch (impl)
+ {
+ case remove_disp_ex_flag_ignore_readonly:
+ {
+ file_disposition_info_ex info;
+ info.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS | FILE_DISPOSITION_FLAG_IGNORE_READONLY_ATTRIBUTE;
+ BOOL res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info));
+ if (BOOST_LIKELY(!!res))
+ break;
+
+ err = ::GetLastError();
+ if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED))
+ {
+ // Downgrade to the older implementation
+ impl = remove_disp_ex_flag_posix_semantics;
+ filesystem::detail::atomic_store_relaxed(g_remove_impl_type, impl);
+ }
+ else
+ {
+ break;
+ }
+ }
+ BOOST_FALLTHROUGH;
+
+ case remove_disp_ex_flag_posix_semantics:
+ {
+ file_disposition_info_ex info;
+ info.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS;
+ BOOL res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info));
+ if (BOOST_LIKELY(!!res))
+ {
+ err = 0u;
+ break;
+ }
+
+ err = ::GetLastError();
+ if (err == ERROR_ACCESS_DENIED)
+ {
+ // Check if the file is read-only and reset the attribute
+ file_basic_info basic_info;
+ res = get_file_information_by_handle_ex(handle, file_basic_info_class, &basic_info, sizeof(basic_info));
+ if (BOOST_UNLIKELY(!res || (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0))
+ break; // return ERROR_ACCESS_DENIED
+
+ basic_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
+
+ res = set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info));
+ if (BOOST_UNLIKELY(!res))
+ {
+ err = ::GetLastError();
+ break;
+ }
+
+ // Try to set the flag again
+ res = set_file_information_by_handle(handle, file_disposition_info_ex_class, &info, sizeof(info));
+ if (BOOST_LIKELY(!!res))
+ {
+ err = 0u;
+ break;
+ }
+
+ err = ::GetLastError();
+
+ // Try to restore the read-only flag
+ basic_info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
+ set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info));
+
+ break;
+ }
+ else if (BOOST_UNLIKELY(err == ERROR_INVALID_PARAMETER || err == ERROR_INVALID_FUNCTION || err == ERROR_NOT_SUPPORTED || err == ERROR_CALL_NOT_IMPLEMENTED))
+ {
+ // Downgrade to the older implementation
+ impl = remove_disp;
+ filesystem::detail::atomic_store_relaxed(g_remove_impl_type, impl);
+ }
+ else
+ {
+ break;
+ }
+ }
+ BOOST_FALLTHROUGH;
+
+ default:
+ {
+ file_disposition_info info;
+ info.DeleteFile = true;
+ BOOL res = set_file_information_by_handle(handle, file_disposition_info_class, &info, sizeof(info));
+ if (BOOST_LIKELY(!!res))
+ {
+ err = 0u;
+ break;
+ }
+
+ err = ::GetLastError();
+ if (err == ERROR_ACCESS_DENIED)
+ {
+ // Check if the file is read-only and reset the attribute
+ file_basic_info basic_info;
+ res = get_file_information_by_handle_ex(handle, file_basic_info_class, &basic_info, sizeof(basic_info));
+ if (BOOST_UNLIKELY(!res || (basic_info.FileAttributes & FILE_ATTRIBUTE_READONLY) == 0))
+ break; // return ERROR_ACCESS_DENIED
+
+ basic_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
+
+ res = set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info));
+ if (BOOST_UNLIKELY(!res))
+ {
+ err = ::GetLastError();
+ break;
+ }
+
+ // Try to set the flag again
+ res = set_file_information_by_handle(handle, file_disposition_info_class, &info, sizeof(info));
+ if (BOOST_LIKELY(!!res))
+ {
+ err = 0u;
+ break;
+ }
+
+ err = ::GetLastError();
+
+ // Try to restore the read-only flag
+ basic_info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
+ set_file_information_by_handle(handle, file_basic_info_class, &basic_info, sizeof(basic_info));
+ }
+
+ break;
+ }
+ }
+
+ return err;
+}
+
+//! remove() implementation for Windows Vista and newer
+inline bool remove_nt6_impl(path const& p, remove_impl_type impl, error_code* ec)
+{
+ unique_handle h(create_file_handle(
+ p,
+ DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT));
+ DWORD err = 0u;
+ if (BOOST_UNLIKELY(!h))
+ {
+ err = ::GetLastError();
+
+ return_error:
+ if (!not_found_error(err))
+ emit_error(err, p, ec, "boost::filesystem::remove");
+
+ return false;
+ }
+
+ err = fs::detail::remove_nt6_by_handle(h.get(), impl);
+ if (BOOST_UNLIKELY(err != 0u))
+ goto return_error;
+
+ return true;
+}
+
+//! remove() implementation
+inline bool remove_impl(path const& p, error_code* ec)
+{
+ remove_impl_type impl = fs::detail::atomic_load_relaxed(g_remove_impl_type);
+ if (BOOST_LIKELY(impl != remove_nt5))
+ {
+ return fs::detail::remove_nt6_impl(p, impl, ec);
+ }
+ else
+ {
+ const DWORD attrs = ::GetFileAttributesW(p.c_str());
+ if (BOOST_UNLIKELY(attrs == INVALID_FILE_ATTRIBUTES))
+ {
+ DWORD err = ::GetLastError();
+ if (!not_found_error(err))
+ emit_error(err, p, ec, "boost::filesystem::remove");
+
+ return false;
+ }
+
+ return fs::detail::remove_nt5_impl(p, attrs, ec);
+ }
+}
+
+//! remove_all() by handle implementation for Windows Vista and newer
+uintmax_t remove_all_nt6_by_handle(HANDLE h, path const& p, error_code* ec)
+{
+ error_code local_ec;
+ fs::file_status st(fs::detail::status_by_handle(h, p, &local_ec));
+ if (BOOST_UNLIKELY(st.type() == fs::status_error))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec));
+
+ *ec = local_ec;
+ return static_cast< uintmax_t >(-1);
+ }
+
+ uintmax_t count = 0u;
+ if (st.type() == fs::directory_file)
+ {
+ local_ec.clear();
+
+ fs::directory_iterator itr;
+ directory_iterator_params params;
+ params.dir_handle = h;
+ params.close_handle = false; // the caller will close the handle
+ fs::detail::directory_iterator_construct(itr, p, directory_options::_detail_no_follow, &params, &local_ec);
+ if (BOOST_UNLIKELY(!!local_ec))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, local_ec));
+
+ *ec = local_ec;
+ return static_cast< uintmax_t >(-1);
+ }
+
+ NtCreateFile_t* nt_create_file = filesystem::detail::atomic_load_relaxed(nt_create_file_api);
+ const fs::directory_iterator end_dit;
+ while (itr != end_dit)
+ {
+ fs::path nested_path(itr->path());
+ unique_handle hh;
+ if (BOOST_LIKELY(nt_create_file != nullptr))
+ {
+ // Note: WinAPI methods like CreateFileW implicitly request SYNCHRONIZE access but NtCreateFile doesn't.
+ // Without SYNCHRONIZE access querying file attributes via GetFileInformationByHandleEx fails with ERROR_ACCESS_DENIED.
+ boost::winapi::NTSTATUS_ status = nt_create_file_handle_at
+ (
+ hh,
+ h,
+ path_algorithms::filename_v4(nested_path),
+ 0u, // FileAttributes
+ FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ if (not_found_ntstatus(status))
+ goto next_entry;
+
+ DWORD err = translate_ntstatus(status);
+ emit_error(err, nested_path, ec, "boost::filesystem::remove_all");
+ return static_cast< uintmax_t >(-1);
+ }
+ }
+ else
+ {
+ hh = create_file_handle(
+ nested_path,
+ FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT);
+
+ if (BOOST_UNLIKELY(!hh))
+ {
+ DWORD err = ::GetLastError();
+ if (not_found_error(err))
+ goto next_entry;
+
+ emit_error(err, nested_path, ec, "boost::filesystem::remove_all");
+ return static_cast< uintmax_t >(-1);
+ }
+ }
+
+ count += fs::detail::remove_all_nt6_by_handle(hh.get(), nested_path, ec);
+ if (ec && *ec)
+ return static_cast< uintmax_t >(-1);
+
+ next_entry:
+ fs::detail::directory_iterator_increment(itr, ec);
+ if (ec && *ec)
+ return static_cast< uintmax_t >(-1);
+ }
+ }
+
+ DWORD err = fs::detail::remove_nt6_by_handle(h, fs::detail::atomic_load_relaxed(g_remove_impl_type));
+ if (BOOST_UNLIKELY(err != 0u))
+ {
+ emit_error(err, p, ec, "boost::filesystem::remove_all");
+ return static_cast< uintmax_t >(-1);
+ }
+
+ ++count;
+ return count;
+}
+
+//! remove_all() implementation for Windows XP and older
+uintmax_t remove_all_nt5_impl(path const& p, error_code* ec)
+{
+ error_code dit_create_ec;
+ for (unsigned int attempt = 0u; attempt < remove_all_directory_replaced_retry_count; ++attempt)
+ {
+ const DWORD attrs = ::GetFileAttributesW(p.c_str());
+ if (BOOST_UNLIKELY(attrs == INVALID_FILE_ATTRIBUTES))
+ {
+ DWORD err = ::GetLastError();
+ if (not_found_error(err))
+ return 0u;
+
+ emit_error(err, p, ec, "boost::filesystem::remove_all");
+ return static_cast< uintmax_t >(-1);
+ }
+
+ // Recurse into directories, but not into junctions or directory symlinks
+ const bool recurse = (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0 && (attrs & FILE_ATTRIBUTE_REPARSE_POINT) == 0;
+ uintmax_t count = 0u;
+ if (recurse)
+ {
+ fs::directory_iterator itr;
+ fs::detail::directory_iterator_construct(itr, p, directory_options::_detail_no_follow, nullptr, &dit_create_ec);
+ if (BOOST_UNLIKELY(!!dit_create_ec))
+ {
+ if (dit_create_ec == make_error_condition(system::errc::not_a_directory) ||
+ dit_create_ec == make_error_condition(system::errc::too_many_symbolic_link_levels))
+ {
+ continue;
+ }
+
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all", p, dit_create_ec));
+
+ *ec = dit_create_ec;
+ return static_cast< uintmax_t >(-1);
+ }
+
+ const fs::directory_iterator end_dit;
+ while (itr != end_dit)
+ {
+ count += fs::detail::remove_all_nt5_impl(itr->path(), ec);
+ if (ec && *ec)
+ return static_cast< uintmax_t >(-1);
+
+ fs::detail::directory_iterator_increment(itr, ec);
+ if (ec && *ec)
+ return static_cast< uintmax_t >(-1);
+ }
+ }
+
+ bool removed = fs::detail::remove_nt5_impl(p, attrs, ec);
+ if (ec && *ec)
+ return static_cast< uintmax_t >(-1);
+
+ count += removed;
+ return count;
+ }
+
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::remove_all: path cannot be opened as a directory", p, dit_create_ec));
+
+ *ec = dit_create_ec;
+ return static_cast< uintmax_t >(-1);
+}
+
+//! remove_all() implementation
+inline uintmax_t remove_all_impl(path const& p, error_code* ec)
+{
+ remove_impl_type impl = fs::detail::atomic_load_relaxed(g_remove_impl_type);
+ if (BOOST_LIKELY(impl != remove_nt5))
+ {
+ unique_handle h(create_file_handle(
+ p,
+ FILE_LIST_DIRECTORY | DELETE | FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | SYNCHRONIZE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT));
+
+ if (BOOST_UNLIKELY(!h))
+ {
+ DWORD err = ::GetLastError();
+ if (not_found_error(err))
+ return 0u;
+
+ emit_error(err, p, ec, "boost::filesystem::remove_all");
+ return static_cast< uintmax_t >(-1);
+ }
+
+ return fs::detail::remove_all_nt6_by_handle(h.get(), p, ec);
+ }
+
+ return fs::detail::remove_all_nt5_impl(p, ec);
+}
+
+inline BOOL resize_file_impl(const wchar_t* p, uintmax_t size)
+{
+ unique_handle h(CreateFileW(p, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
+ LARGE_INTEGER sz;
+ sz.QuadPart = size;
+ return !!h && ::SetFilePointerEx(h.get(), sz, 0, FILE_BEGIN) && ::SetEndOfFile(h.get());
+}
+
+//! Converts NT path to a Win32 path
+inline path convert_nt_path_to_win32_path(const wchar_t* nt_path, std::size_t size)
+{
+ // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html
+ // https://stackoverflow.com/questions/23041983/path-prefixes-and
+ //
+ // NT paths can be used to identify practically any named objects, devices, files, local and remote shares, etc.
+ // The path starts with a leading backslash and consists of one or more path elements separated with backslashes.
+ // The set of characters allowed in NT path elements is significantly larger than that of Win32 paths - basically,
+ // any character except the backslash is allowed. Path elements are case-insensitive.
+ //
+ // NT paths that start with the "\??\" prefix are used to indicate the current user's session namespace. The prefix
+ // indicates to the NT object manager to lookup the object relative to "\Sessions\0\DosDevices\[Logon Authentication ID]".
+ //
+ // There is also a special "\Global??\" prefix that refers to the system logon. User's session directory shadows
+ // the system logon directory, so that when the referenced object is not found in the user's namespace,
+ // system logon is looked up instead.
+ //
+ // There is a symlink "Global" in the user's session namespace that refers to the global namespace, so "\??\Global"
+ // effectively resolves to "\Global??". This allows Win32 applications to directly refer to the system objects,
+ // even if shadowed by the current user's logon object.
+ //
+ // NT paths can be used to reference not only local filesystems, but also devices and remote shares identifiable via
+ // UNC paths. For this, there is a special "UNC" device (which is a symlink to "\Device\Mup") in the system logon
+ // namespace, so "\??\UNC\host\share" (or "\??\Global\UNC\host\share", or "\Global??\UNC\host\share") is equivalent
+ // to "\\host\share".
+ //
+ // NT paths are not universally accepted by Win32 applications and APIs. For example, Far supports paths starting
+ // with "\??\" and "\??\Global\" but not with "\Global??\". As of Win10 21H1, File Explorer, cmd.exe and PowerShell
+ // don't support any of these. Given this, and that NT paths have a different set of allowed characters from Win32 paths,
+ // we should normally avoid exposing NT paths to users that expect Win32 paths.
+ //
+ // In Boost.Filesystem we only deal with NT paths that come from reparse points, such as symlinks and mount points,
+ // including directory junctions. It was observed that reparse points created by junction.exe and mklink use the "\??\"
+ // prefix for directory junctions and absolute symlink and unqualified relative path for relative symlinks.
+ // Absolute paths are using drive letters for mounted drives (e.g. "\??\C:\directory"), although it is possible
+ // to create a junction to an directory using a different way of identifying the filesystem (e.g.
+ // "\??\Volume{00000000-0000-0000-0000-000000000000}\directory").
+ // mklink does not support creating junctions pointing to a UNC path. junction.exe does create a junction that
+ // uses a seemingly invalid syntax like "\??\\\host\share", i.e. it basically does not expect an UNC path. It is not known
+ // if reparse points that refer to a UNC path are considered valid.
+ // There are reparse points created as mount points for local and remote filsystems (for example, a cloud storage mounted
+ // in the local filesystem). Such mount points have the form of "\??\Volume{00000000-0000-0000-0000-000000000000}\",
+ // "\??\Harddisk0Partition1\" or "\??\HarddiskVolume1\".
+ // Reparse points that refer directly to a global namespace (through "\??\Global\" or "\Global??\" prefixes) or
+ // devices (e.g. "\Device\HarddiskVolume1") have not been observed so far.
+
+ path win32_path;
+ std::size_t pos = 0u;
+ bool global_namespace = false;
+
+ // Check for the "\??\" prefix
+ if (size >= 4u &&
+ nt_path[0] == path::preferred_separator &&
+ nt_path[1] == questionmark &&
+ nt_path[2] == questionmark &&
+ nt_path[3] == path::preferred_separator)
+ {
+ pos = 4u;
+
+ // Check "Global"
+ if ((size - pos) >= 6u &&
+ (nt_path[pos] == L'G' || nt_path[pos] == L'g') &&
+ (nt_path[pos + 1] == L'l' || nt_path[pos + 1] == L'L') &&
+ (nt_path[pos + 2] == L'o' || nt_path[pos + 2] == L'O') &&
+ (nt_path[pos + 3] == L'b' || nt_path[pos + 3] == L'B') &&
+ (nt_path[pos + 4] == L'a' || nt_path[pos + 4] == L'A') &&
+ (nt_path[pos + 5] == L'l' || nt_path[pos + 5] == L'L'))
+ {
+ if ((size - pos) == 6u)
+ {
+ pos += 6u;
+ global_namespace = true;
+ }
+ else if (detail::is_directory_separator(nt_path[pos + 6u]))
+ {
+ pos += 7u;
+ global_namespace = true;
+ }
+ }
+ }
+ // Check for the "\Global??\" prefix
+ else if (size >= 10u &&
+ nt_path[0] == path::preferred_separator &&
+ (nt_path[1] == L'G' || nt_path[1] == L'g') &&
+ (nt_path[2] == L'l' || nt_path[2] == L'L') &&
+ (nt_path[3] == L'o' || nt_path[3] == L'O') &&
+ (nt_path[4] == L'b' || nt_path[4] == L'B') &&
+ (nt_path[5] == L'a' || nt_path[5] == L'A') &&
+ (nt_path[6] == L'l' || nt_path[6] == L'L') &&
+ nt_path[7] == questionmark &&
+ nt_path[8] == questionmark &&
+ nt_path[9] == path::preferred_separator)
+ {
+ pos = 10u;
+ global_namespace = true;
+ }
+
+ if (pos > 0u)
+ {
+ if ((size - pos) >= 2u &&
+ (
+ // Check if the following is a drive letter
+ (
+ detail::is_letter(nt_path[pos]) && nt_path[pos + 1u] == colon &&
+ ((size - pos) == 2u || detail::is_directory_separator(nt_path[pos + 2u]))
+ ) ||
+ // Check for an "incorrect" syntax for UNC path junction points
+ (
+ detail::is_directory_separator(nt_path[pos]) && detail::is_directory_separator(nt_path[pos + 1u]) &&
+ ((size - pos) == 2u || !detail::is_directory_separator(nt_path[pos + 2u]))
+ )
+ ))
+ {
+ // Strip the NT path prefix
+ goto done;
+ }
+
+ static const wchar_t win32_path_prefix[4u] = { path::preferred_separator, path::preferred_separator, questionmark, path::preferred_separator };
+
+ // Check for a UNC path
+ if ((size - pos) >= 4u &&
+ (nt_path[pos] == L'U' || nt_path[pos] == L'u') &&
+ (nt_path[pos + 1] == L'N' || nt_path[pos + 1] == L'n') &&
+ (nt_path[pos + 2] == L'C' || nt_path[pos + 2] == L'c') &&
+ nt_path[pos + 3] == path::preferred_separator)
+ {
+ win32_path.assign(win32_path_prefix, win32_path_prefix + 2);
+ pos += 4u;
+ goto done;
+ }
+
+ // This is some other NT path, possibly a volume mount point. Replace the NT prefix with a Win32 filesystem prefix "\\?\".
+ win32_path.assign(win32_path_prefix, win32_path_prefix + 4);
+ if (global_namespace)
+ {
+ static const wchar_t win32_path_global_prefix[7u] = { L'G', L'l', L'o', L'b', L'a', L'l', path::preferred_separator };
+ win32_path.concat(win32_path_global_prefix, win32_path_global_prefix + 7);
+ }
+ }
+
+done:
+ win32_path.concat(nt_path + pos, nt_path + size);
+ return win32_path;
+}
+
+#endif // defined(BOOST_POSIX_API)
+
+} // unnamed namespace
+
+} // namespace detail
+
+//--------------------------------------------------------------------------------------//
+// //
+// operations functions declared in operations.hpp //
+// //
+//--------------------------------------------------------------------------------------//
+
+namespace detail {
+
+BOOST_FILESYSTEM_DECL bool possible_large_file_size_support()
+{
+#ifdef BOOST_POSIX_API
+ typedef struct stat struct_stat;
+ return sizeof(struct_stat().st_size) > 4;
+#else
+ return true;
+#endif
+}
+
+BOOST_FILESYSTEM_DECL
+path absolute_v3(path const& p, path const& base, system::error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+ if (p.is_absolute())
+ return p;
+
+ // recursively calling absolute is sub-optimal, but is sure and simple
+ path abs_base = base;
+ if (!base.is_absolute())
+ {
+ path cur_path = detail::current_path(ec);
+ if (ec && *ec)
+ {
+ return_empty_path:
+ return path();
+ }
+
+ if (BOOST_UNLIKELY(!cur_path.is_absolute()))
+ {
+ system::error_code local_ec = system::errc::make_error_code(system::errc::invalid_argument);
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::absolute", p, base, local_ec));
+
+ *ec = local_ec;
+ goto return_empty_path;
+ }
+
+ abs_base = detail::absolute_v3(base, cur_path, ec);
+ if (ec && *ec)
+ goto return_empty_path;
+ }
+
+ if (p.empty())
+ return abs_base;
+
+ path res;
+ if (p.has_root_name())
+ res = p.root_name();
+ else
+ res = abs_base.root_name();
+
+ if (p.has_root_directory())
+ {
+ res.concat(p.root_directory());
+ }
+ else
+ {
+ res.concat(abs_base.root_directory());
+ path_algorithms::append_v4(res, abs_base.relative_path());
+ }
+
+ path p_relative_path(p.relative_path());
+ if (!p_relative_path.empty())
+ path_algorithms::append_v4(res, p_relative_path);
+
+ return res;
+}
+
+BOOST_FILESYSTEM_DECL
+path absolute_v4(path const& p, path const& base, system::error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+ if (p.is_absolute())
+ return p;
+
+ path abs_base = base;
+ if (!base.is_absolute())
+ {
+ path cur_path = detail::current_path(ec);
+ if (ec && *ec)
+ {
+ return_empty_path:
+ return path();
+ }
+
+ if (BOOST_UNLIKELY(!cur_path.is_absolute()))
+ {
+ system::error_code local_ec = system::errc::make_error_code(system::errc::invalid_argument);
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::absolute", p, base, local_ec));
+
+ *ec = local_ec;
+ goto return_empty_path;
+ }
+
+ abs_base = detail::absolute_v4(base, cur_path, ec);
+ if (ec && *ec)
+ goto return_empty_path;
+ }
+
+ path res;
+ if (p.has_root_name())
+ res = p.root_name();
+ else
+ res = abs_base.root_name();
+
+ if (p.has_root_directory())
+ {
+ res.concat(p.root_directory());
+ }
+ else
+ {
+ res.concat(abs_base.root_directory());
+ path_algorithms::append_v4(res, abs_base.relative_path());
+ }
+
+ path_algorithms::append_v4(res, p.relative_path());
+
+ return res;
+}
+
+BOOST_FILESYSTEM_DECL
+path canonical_v3(path const& p, path const& base, system::error_code* ec)
+{
+ path source(detail::absolute_v3(p, base, ec));
+ if (ec && *ec)
+ {
+ return_empty_path:
+ return path();
+ }
+
+ system::error_code local_ec;
+ file_status st(detail::status_impl(source, &local_ec));
+
+ if (st.type() == fs::file_not_found)
+ {
+ local_ec = system::errc::make_error_code(system::errc::no_such_file_or_directory);
+ goto fail_local_ec;
+ }
+ else if (local_ec)
+ {
+ fail_local_ec:
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::canonical", source, local_ec));
+
+ *ec = local_ec;
+ goto return_empty_path;
+ }
+
+ path root(source.root_path());
+ path const& dot_p = dot_path();
+ path const& dot_dot_p = dot_dot_path();
+ unsigned int symlinks_allowed = symloop_max;
+ path result;
+ while (true)
+ {
+ for (path::iterator itr(source.begin()), end(source.end()); itr != end; path_algorithms::increment_v4(itr))
+ {
+ if (path_algorithms::compare_v4(*itr, dot_p) == 0)
+ continue;
+ if (path_algorithms::compare_v4(*itr, dot_dot_p) == 0)
+ {
+ if (path_algorithms::compare_v4(result, root) != 0)
+ result.remove_filename_and_trailing_separators();
+ continue;
+ }
+
+ if (itr->size() == 1u && detail::is_directory_separator(itr->native()[0]))
+ {
+ // Convert generic separator returned by the iterator for the root directory to
+ // the preferred separator. This is important on Windows, as in some cases,
+ // like paths for network shares and cloud storage mount points GetFileAttributesW
+ // will return "file not found" if the path contains forward slashes.
+ result += path::preferred_separator;
+ // We don't need to check for a symlink after adding a separator.
+ continue;
+ }
+
+ path_algorithms::append_v4(result, *itr);
+
+ // If we don't have an absolute path yet then don't check symlink status.
+ // This avoids checking "C:" which is "the current directory on drive C"
+ // and hence not what we want to check/resolve here.
+ if (!result.is_absolute())
+ continue;
+
+ st = detail::symlink_status_impl(result, ec);
+ if (ec && *ec)
+ goto return_empty_path;
+
+ if (is_symlink(st))
+ {
+ if (symlinks_allowed == 0)
+ {
+ local_ec = system::errc::make_error_code(system::errc::too_many_symbolic_link_levels);
+ goto fail_local_ec;
+ }
+
+ --symlinks_allowed;
+
+ path link(detail::read_symlink(result, ec));
+ if (ec && *ec)
+ goto return_empty_path;
+ result.remove_filename_and_trailing_separators();
+
+ if (link.is_absolute())
+ {
+ for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr))
+ {
+ if (path_algorithms::compare_v4(*itr, dot_p) != 0)
+ path_algorithms::append_v4(link, *itr);
+ }
+ source = link;
+ root = source.root_path();
+ }
+ else // link is relative
+ {
+ link.remove_trailing_separator();
+ if (path_algorithms::compare_v4(link, dot_p) == 0)
+ continue;
+
+ path new_source(result);
+ path_algorithms::append_v4(new_source, link);
+ for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr))
+ {
+ if (path_algorithms::compare_v4(*itr, dot_p) != 0)
+ path_algorithms::append_v4(new_source, *itr);
+ }
+ source = new_source;
+ }
+
+ // symlink causes scan to be restarted
+ goto restart_scan;
+ }
+ }
+
+ break;
+
+ restart_scan:
+ result.clear();
+ }
+
+ BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report");
+ return result;
+}
+
+BOOST_FILESYSTEM_DECL
+path canonical_v4(path const& p, path const& base, system::error_code* ec)
+{
+ path source(detail::absolute_v4(p, base, ec));
+ if (ec && *ec)
+ {
+ return_empty_path:
+ return path();
+ }
+
+ system::error_code local_ec;
+ file_status st(detail::status_impl(source, &local_ec));
+
+ if (st.type() == fs::file_not_found)
+ {
+ local_ec = system::errc::make_error_code(system::errc::no_such_file_or_directory);
+ goto fail_local_ec;
+ }
+ else if (local_ec)
+ {
+ fail_local_ec:
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::canonical", source, local_ec));
+
+ *ec = local_ec;
+ goto return_empty_path;
+ }
+
+ path root(source.root_path());
+ path const& dot_p = dot_path();
+ path const& dot_dot_p = dot_dot_path();
+ unsigned int symlinks_allowed = symloop_max;
+ path result;
+ while (true)
+ {
+ for (path::iterator itr(source.begin()), end(source.end()); itr != end; path_algorithms::increment_v4(itr))
+ {
+ if (path_algorithms::compare_v4(*itr, dot_p) == 0)
+ continue;
+ if (path_algorithms::compare_v4(*itr, dot_dot_p) == 0)
+ {
+ if (path_algorithms::compare_v4(result, root) != 0)
+ result.remove_filename_and_trailing_separators();
+ continue;
+ }
+
+ if (itr->size() == 1u && detail::is_directory_separator(itr->native()[0]))
+ {
+ // Convert generic separator returned by the iterator for the root directory to
+ // the preferred separator. This is important on Windows, as in some cases,
+ // like paths for network shares and cloud storage mount points GetFileAttributesW
+ // will return "file not found" if the path contains forward slashes.
+ result += path::preferred_separator;
+ // We don't need to check for a symlink after adding a separator.
+ continue;
+ }
+
+ path_algorithms::append_v4(result, *itr);
+
+ // If we don't have an absolute path yet then don't check symlink status.
+ // This avoids checking "C:" which is "the current directory on drive C"
+ // and hence not what we want to check/resolve here.
+ if (!result.is_absolute())
+ continue;
+
+ st = detail::symlink_status_impl(result, ec);
+ if (ec && *ec)
+ goto return_empty_path;
+
+ if (is_symlink(st))
+ {
+ if (symlinks_allowed == 0)
+ {
+ local_ec = system::errc::make_error_code(system::errc::too_many_symbolic_link_levels);
+ goto fail_local_ec;
+ }
+
+ --symlinks_allowed;
+
+ path link(detail::read_symlink(result, ec));
+ if (ec && *ec)
+ goto return_empty_path;
+ result.remove_filename_and_trailing_separators();
+
+ if (link.is_absolute())
+ {
+ for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr))
+ {
+ if (path_algorithms::compare_v4(*itr, dot_p) != 0)
+ path_algorithms::append_v4(link, *itr);
+ }
+ source = link;
+ root = source.root_path();
+ }
+ else // link is relative
+ {
+ link.remove_trailing_separator();
+ if (path_algorithms::compare_v4(link, dot_p) == 0)
+ continue;
+
+ path new_source(result);
+ path_algorithms::append_v4(new_source, link);
+ for (path_algorithms::increment_v4(itr); itr != end; path_algorithms::increment_v4(itr))
+ {
+ if (path_algorithms::compare_v4(*itr, dot_p) != 0)
+ path_algorithms::append_v4(new_source, *itr);
+ }
+ source = new_source;
+ }
+
+ // symlink causes scan to be restarted
+ goto restart_scan;
+ }
+ }
+
+ break;
+
+ restart_scan:
+ result.clear();
+ }
+
+ BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report");
+ return result;
+}
+
+BOOST_FILESYSTEM_DECL
+void copy(path const& from, path const& to, copy_options options, system::error_code* ec)
+{
+ BOOST_ASSERT((((options & copy_options::overwrite_existing) != copy_options::none) +
+ ((options & copy_options::skip_existing) != copy_options::none) +
+ ((options & copy_options::update_existing) != copy_options::none)) <= 1);
+
+ BOOST_ASSERT((((options & copy_options::copy_symlinks) != copy_options::none) +
+ ((options & copy_options::skip_symlinks) != copy_options::none)) <= 1);
+
+ BOOST_ASSERT((((options & copy_options::directories_only) != copy_options::none) +
+ ((options & copy_options::create_symlinks) != copy_options::none) +
+ ((options & copy_options::create_hard_links) != copy_options::none)) <= 1);
+
+ if (ec)
+ ec->clear();
+
+ file_status from_stat;
+ if ((options & (copy_options::copy_symlinks | copy_options::skip_symlinks | copy_options::create_symlinks)) != copy_options::none)
+ {
+ from_stat = detail::symlink_status_impl(from, ec);
+ }
+ else
+ {
+ from_stat = detail::status_impl(from, ec);
+ }
+
+ if (ec && *ec)
+ return;
+
+ if (!exists(from_stat))
+ {
+ emit_error(BOOST_ERROR_FILE_NOT_FOUND, from, to, ec, "boost::filesystem::copy");
+ return;
+ }
+
+ if (is_symlink(from_stat))
+ {
+ if ((options & copy_options::skip_symlinks) != copy_options::none)
+ return;
+
+ if ((options & copy_options::copy_symlinks) == copy_options::none)
+ goto fail;
+
+ detail::copy_symlink(from, to, ec);
+ }
+ else if (is_regular_file(from_stat))
+ {
+ if ((options & copy_options::directories_only) != copy_options::none)
+ return;
+
+ if ((options & copy_options::create_symlinks) != copy_options::none)
+ {
+ const path* pfrom = &from;
+ path relative_from;
+ if (!from.is_absolute())
+ {
+ // Try to generate a relative path from the target location to the original file
+ path cur_dir = detail::current_path(ec);
+ if (ec && *ec)
+ return;
+ path abs_from = detail::absolute_v4(from.parent_path(), cur_dir, ec);
+ if (ec && *ec)
+ return;
+ path abs_to = to.parent_path();
+ if (!abs_to.is_absolute())
+ {
+ abs_to = detail::absolute_v4(abs_to, cur_dir, ec);
+ if (ec && *ec)
+ return;
+ }
+ relative_from = detail::relative(abs_from, abs_to, ec);
+ if (ec && *ec)
+ return;
+ if (path_algorithms::compare_v4(relative_from, dot_path()) != 0)
+ path_algorithms::append_v4(relative_from, path_algorithms::filename_v4(from));
+ else
+ relative_from = path_algorithms::filename_v4(from);
+ pfrom = &relative_from;
+ }
+ detail::create_symlink(*pfrom, to, ec);
+ return;
+ }
+
+ if ((options & copy_options::create_hard_links) != copy_options::none)
+ {
+ detail::create_hard_link(from, to, ec);
+ return;
+ }
+
+ error_code local_ec;
+ file_status to_stat;
+ if ((options & (copy_options::skip_symlinks | copy_options::create_symlinks)) != copy_options::none)
+ {
+ to_stat = detail::symlink_status_impl(to, &local_ec);
+ }
+ else
+ {
+ to_stat = detail::status_impl(to, &local_ec);
+ }
+
+ // Note: local_ec may be set by (symlink_)status() even in some non-fatal situations, e.g. when the file does not exist.
+ // OTOH, when it returns status_error, then a real error have happened and it must have set local_ec.
+ if (to_stat.type() == fs::status_error)
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec));
+ *ec = local_ec;
+ return;
+ }
+
+ if (is_directory(to_stat))
+ {
+ path target(to);
+ path_algorithms::append_v4(target, path_algorithms::filename_v4(from));
+ detail::copy_file(from, target, options, ec);
+ }
+ else
+ detail::copy_file(from, to, options, ec);
+ }
+ else if (is_directory(from_stat))
+ {
+ error_code local_ec;
+ if ((options & copy_options::create_symlinks) != copy_options::none)
+ {
+ local_ec = make_error_code(system::errc::is_a_directory);
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec));
+ *ec = local_ec;
+ return;
+ }
+
+ file_status to_stat;
+ if ((options & (copy_options::skip_symlinks | copy_options::create_symlinks)) != copy_options::none)
+ {
+ to_stat = detail::symlink_status_impl(to, &local_ec);
+ }
+ else
+ {
+ to_stat = detail::status_impl(to, &local_ec);
+ }
+
+ // Note: ec may be set by (symlink_)status() even in some non-fatal situations, e.g. when the file does not exist.
+ // OTOH, when it returns status_error, then a real error have happened and it must have set local_ec.
+ if (to_stat.type() == fs::status_error)
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::copy", from, to, local_ec));
+ *ec = local_ec;
+ return;
+ }
+
+ if (!exists(to_stat))
+ {
+ detail::create_directory(to, &from, ec);
+ if (ec && *ec)
+ return;
+ }
+
+ if ((options & copy_options::recursive) != copy_options::none || options == copy_options::none)
+ {
+ fs::directory_iterator itr;
+ detail::directory_iterator_construct(itr, from, directory_options::none, nullptr, ec);
+ if (ec && *ec)
+ return;
+
+ const fs::directory_iterator end_dit;
+ while (itr != end_dit)
+ {
+ path const& p = itr->path();
+ {
+ path target(to);
+ path_algorithms::append_v4(target, path_algorithms::filename_v4(p));
+ // Set _detail_recursing flag so that we don't recurse more than for one level deeper into the directory if options are copy_options::none
+ detail::copy(p, target, options | copy_options::_detail_recursing, ec);
+ }
+ if (ec && *ec)
+ return;
+
+ detail::directory_iterator_increment(itr, ec);
+ if (ec && *ec)
+ return;
+ }
+ }
+ }
+ else
+ {
+ fail:
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, from, to, ec, "boost::filesystem::copy");
+ }
+}
+
+BOOST_FILESYSTEM_DECL
+bool copy_file(path const& from, path const& to, copy_options options, error_code* ec)
+{
+ BOOST_ASSERT((((options & copy_options::overwrite_existing) != copy_options::none) +
+ ((options & copy_options::skip_existing) != copy_options::none) +
+ ((options & copy_options::update_existing) != copy_options::none)) <= 1);
+
+ if (ec)
+ ec->clear();
+
+#if defined(BOOST_POSIX_API)
+
+ int err = 0;
+
+ // Note: Declare fd wrappers here so that errno is not clobbered by close() that may be called in fd wrapper destructors
+ boost::scope::unique_fd infile, outfile;
+
+ while (true)
+ {
+ infile.reset(::open(from.c_str(), O_RDONLY | O_CLOEXEC));
+ if (BOOST_UNLIKELY(!infile))
+ {
+ err = errno;
+ if (err == EINTR)
+ continue;
+
+ fail:
+ emit_error(err, from, to, ec, "boost::filesystem::copy_file");
+ return false;
+ }
+
+ break;
+ }
+
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ unsigned int statx_data_mask = STATX_TYPE | STATX_MODE | STATX_INO | STATX_SIZE;
+ if ((options & copy_options::update_existing) != copy_options::none)
+ statx_data_mask |= STATX_MTIME;
+
+ struct ::statx from_stat;
+ if (BOOST_UNLIKELY(invoke_statx(infile.get(), "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &from_stat) < 0))
+ {
+ fail_errno:
+ err = errno;
+ goto fail;
+ }
+
+ if (BOOST_UNLIKELY((from_stat.stx_mask & statx_data_mask) != statx_data_mask))
+ {
+ err = ENOSYS;
+ goto fail;
+ }
+#else
+ struct ::stat from_stat;
+ if (BOOST_UNLIKELY(::fstat(infile.get(), &from_stat) != 0))
+ {
+ fail_errno:
+ err = errno;
+ goto fail;
+ }
+#endif
+
+ const mode_t from_mode = get_mode(from_stat);
+ if (BOOST_UNLIKELY(!S_ISREG(from_mode)))
+ {
+ err = ENOSYS;
+ goto fail;
+ }
+
+ mode_t to_mode = from_mode & fs::perms_mask;
+#if !defined(BOOST_FILESYSTEM_USE_WASI)
+ // Enable writing for the newly created files. Having write permission set is important e.g. for NFS,
+ // which checks the file permission on the server, even if the client's file descriptor supports writing.
+ to_mode |= S_IWUSR;
+#endif
+ int oflag = O_WRONLY | O_CLOEXEC;
+
+ if ((options & copy_options::update_existing) != copy_options::none)
+ {
+ // Try opening the existing file without truncation to test the modification time later
+ while (true)
+ {
+ outfile.reset(::open(to.c_str(), oflag, to_mode));
+ if (!outfile)
+ {
+ err = errno;
+ if (err == EINTR)
+ continue;
+
+ if (err == ENOENT)
+ goto create_outfile;
+
+ goto fail;
+ }
+
+ break;
+ }
+ }
+ else
+ {
+ create_outfile:
+ oflag |= O_CREAT | O_TRUNC;
+ if (((options & copy_options::overwrite_existing) == copy_options::none ||
+ (options & copy_options::skip_existing) != copy_options::none) &&
+ (options & copy_options::update_existing) == copy_options::none)
+ {
+ oflag |= O_EXCL;
+ }
+
+ while (true)
+ {
+ outfile.reset(::open(to.c_str(), oflag, to_mode));
+ if (!outfile)
+ {
+ err = errno;
+ if (err == EINTR)
+ continue;
+
+ if (err == EEXIST && (options & copy_options::skip_existing) != copy_options::none)
+ return false;
+
+ goto fail;
+ }
+
+ break;
+ }
+ }
+
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ statx_data_mask = STATX_TYPE | STATX_MODE | STATX_INO;
+ if ((oflag & O_TRUNC) == 0)
+ {
+ // O_TRUNC is not set if copy_options::update_existing is set and an existing file was opened.
+ statx_data_mask |= STATX_MTIME;
+ }
+
+ struct ::statx to_stat;
+ if (BOOST_UNLIKELY(invoke_statx(outfile.get(), "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, statx_data_mask, &to_stat) < 0))
+ goto fail_errno;
+
+ if (BOOST_UNLIKELY((to_stat.stx_mask & statx_data_mask) != statx_data_mask))
+ {
+ err = ENOSYS;
+ goto fail;
+ }
+#else
+ struct ::stat to_stat;
+ if (BOOST_UNLIKELY(::fstat(outfile.get(), &to_stat) != 0))
+ goto fail_errno;
+#endif
+
+ to_mode = get_mode(to_stat);
+ if (BOOST_UNLIKELY(!S_ISREG(to_mode)))
+ {
+ err = ENOSYS;
+ goto fail;
+ }
+
+ if (BOOST_UNLIKELY(detail::equivalent_stat(from_stat, to_stat)))
+ {
+ err = EEXIST;
+ goto fail;
+ }
+
+ if ((oflag & O_TRUNC) == 0)
+ {
+ // O_TRUNC is not set if copy_options::update_existing is set and an existing file was opened.
+ // We need to check the last write times.
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ if (from_stat.stx_mtime.tv_sec < to_stat.stx_mtime.tv_sec || (from_stat.stx_mtime.tv_sec == to_stat.stx_mtime.tv_sec && from_stat.stx_mtime.tv_nsec <= to_stat.stx_mtime.tv_nsec))
+ return false;
+#elif defined(BOOST_FILESYSTEM_STAT_ST_MTIMENSEC)
+ // Modify time is available with nanosecond precision.
+ if (from_stat.st_mtime < to_stat.st_mtime || (from_stat.st_mtime == to_stat.st_mtime && from_stat.BOOST_FILESYSTEM_STAT_ST_MTIMENSEC <= to_stat.BOOST_FILESYSTEM_STAT_ST_MTIMENSEC))
+ return false;
+#else
+ if (from_stat.st_mtime <= to_stat.st_mtime)
+ return false;
+#endif
+
+ if (BOOST_UNLIKELY(::ftruncate(outfile.get(), 0) != 0))
+ goto fail_errno;
+ }
+
+ // Note: Use block size of the target file since it is most important for writing performance.
+ err = filesystem::detail::atomic_load_relaxed(filesystem::detail::copy_file_data)(infile.get(), outfile.get(), get_size(from_stat), get_blksize(to_stat));
+ if (BOOST_UNLIKELY(err != 0))
+ goto fail; // err already contains the error code
+
+#if !defined(BOOST_FILESYSTEM_USE_WASI)
+ // If we created a new file with an explicitly added S_IWUSR permission,
+ // we may need to update its mode bits to match the source file.
+ if ((to_mode & fs::perms_mask) != (from_mode & fs::perms_mask))
+ {
+ if (BOOST_UNLIKELY(::fchmod(outfile.get(), (from_mode & fs::perms_mask)) != 0 &&
+ (options & copy_options::ignore_attribute_errors) == copy_options::none))
+ {
+ goto fail_errno;
+ }
+ }
+#endif
+
+ if ((options & (copy_options::synchronize_data | copy_options::synchronize)) != copy_options::none)
+ {
+ if ((options & copy_options::synchronize) != copy_options::none)
+ err = full_sync(outfile.get());
+ else
+ err = data_sync(outfile.get());
+
+ if (BOOST_UNLIKELY(err != 0))
+ goto fail;
+ }
+
+ // We have to explicitly close the output file descriptor in order to handle a possible error returned from it. The error may indicate
+ // a failure of a prior write operation.
+ err = close_fd(outfile.get());
+ outfile.release();
+ if (BOOST_UNLIKELY(err < 0))
+ {
+ err = errno;
+ // EINPROGRESS is an allowed error code in future POSIX revisions, according to https://www.austingroupbugs.net/view.php?id=529#c1200.
+ if (err != EINTR && err != EINPROGRESS)
+ goto fail;
+ }
+
+ return true;
+
+#else // defined(BOOST_POSIX_API)
+
+ DWORD copy_flags = 0u;
+ if ((options & copy_options::overwrite_existing) == copy_options::none ||
+ (options & copy_options::skip_existing) != copy_options::none)
+ {
+ copy_flags |= COPY_FILE_FAIL_IF_EXISTS;
+ }
+
+ if ((options & copy_options::update_existing) != copy_options::none)
+ {
+ // Create unique_handle wrappers here so that CloseHandle calls don't clobber error code returned by GetLastError
+ unique_handle hw_from, hw_to;
+
+ // See the comment in last_write_time regarding access rights used here for GetFileTime.
+ hw_from = create_file_handle(
+ from.c_str(),
+ FILE_READ_ATTRIBUTES | FILE_READ_EA,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS);
+
+ FILETIME lwt_from;
+ if (!hw_from)
+ {
+ fail_last_error:
+ DWORD err = ::GetLastError();
+ emit_error(err, from, to, ec, "boost::filesystem::copy_file");
+ return false;
+ }
+
+ if (!::GetFileTime(hw_from.get(), nullptr, nullptr, &lwt_from))
+ goto fail_last_error;
+
+ hw_to = create_file_handle(
+ to.c_str(),
+ FILE_READ_ATTRIBUTES | FILE_READ_EA,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS);
+
+ if (!!hw_to)
+ {
+ FILETIME lwt_to;
+ if (!::GetFileTime(hw_to.get(), nullptr, nullptr, &lwt_to))
+ goto fail_last_error;
+
+ ULONGLONG tfrom = (static_cast< ULONGLONG >(lwt_from.dwHighDateTime) << 32) | static_cast< ULONGLONG >(lwt_from.dwLowDateTime);
+ ULONGLONG tto = (static_cast< ULONGLONG >(lwt_to.dwHighDateTime) << 32) | static_cast< ULONGLONG >(lwt_to.dwLowDateTime);
+ if (tfrom <= tto)
+ return false;
+ }
+
+ copy_flags &= ~static_cast< DWORD >(COPY_FILE_FAIL_IF_EXISTS);
+ }
+
+ struct callback_context
+ {
+ DWORD flush_error;
+ };
+
+ struct local
+ {
+ //! Callback that is called to report progress of \c CopyFileExW
+ static DWORD WINAPI on_copy_file_progress(
+ LARGE_INTEGER total_file_size,
+ LARGE_INTEGER total_bytes_transferred,
+ LARGE_INTEGER stream_size,
+ LARGE_INTEGER stream_bytes_transferred,
+ DWORD stream_number,
+ DWORD callback_reason,
+ HANDLE from_handle,
+ HANDLE to_handle,
+ LPVOID ctx)
+ {
+ // For each stream, CopyFileExW will open a separate pair of file handles, so we need to flush each stream separately.
+ if (stream_bytes_transferred.QuadPart == stream_size.QuadPart)
+ {
+ BOOL res = ::FlushFileBuffers(to_handle);
+ if (BOOST_UNLIKELY(!res))
+ {
+ callback_context* context = static_cast< callback_context* >(ctx);
+ if (BOOST_LIKELY(context->flush_error == 0u))
+ context->flush_error = ::GetLastError();
+ }
+ }
+
+ return PROGRESS_CONTINUE;
+ }
+ };
+
+ callback_context cb_context = {};
+ LPPROGRESS_ROUTINE cb = nullptr;
+ LPVOID cb_ctx = nullptr;
+
+ if ((options & (copy_options::synchronize_data | copy_options::synchronize)) != copy_options::none)
+ {
+ cb = &local::on_copy_file_progress;
+ cb_ctx = &cb_context;
+ }
+
+ BOOL cancelled = FALSE;
+ BOOL res = ::CopyFileExW(from.c_str(), to.c_str(), cb, cb_ctx, &cancelled, copy_flags);
+ DWORD err;
+ if (BOOST_UNLIKELY(!res))
+ {
+ err = ::GetLastError();
+ if ((err == ERROR_FILE_EXISTS || err == ERROR_ALREADY_EXISTS) && (options & copy_options::skip_existing) != copy_options::none)
+ return false;
+
+ copy_failed:
+ emit_error(err, from, to, ec, "boost::filesystem::copy_file");
+ return false;
+ }
+
+ if (BOOST_UNLIKELY(cb_context.flush_error != 0u))
+ {
+ err = cb_context.flush_error;
+ goto copy_failed;
+ }
+
+ return true;
+
+#endif // defined(BOOST_POSIX_API)
+}
+
+BOOST_FILESYSTEM_DECL
+void copy_symlink(path const& existing_symlink, path const& new_symlink, system::error_code* ec)
+{
+ path p(read_symlink(existing_symlink, ec));
+ if (ec && *ec)
+ return;
+ create_symlink(p, new_symlink, ec);
+}
+
+BOOST_FILESYSTEM_DECL
+bool create_directories(path const& p, system::error_code* ec)
+{
+ if (p.empty())
+ {
+ if (!ec)
+ {
+ BOOST_FILESYSTEM_THROW(filesystem_error(
+ "boost::filesystem::create_directories", p,
+ system::errc::make_error_code(system::errc::invalid_argument)));
+ }
+ ec->assign(system::errc::invalid_argument, system::generic_category());
+ return false;
+ }
+
+ if (ec)
+ ec->clear();
+
+ path::const_iterator e(p.end()), it(e);
+ path parent(p);
+ path const& dot_p = dot_path();
+ path const& dot_dot_p = dot_dot_path();
+ error_code local_ec;
+
+ // Find the initial part of the path that exists
+ for (path fname = path_algorithms::filename_v4(parent); parent.has_relative_path(); fname = path_algorithms::filename_v4(parent))
+ {
+ if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0)
+ {
+ file_status existing_status = detail::status_impl(parent, &local_ec);
+
+ if (existing_status.type() == directory_file)
+ {
+ break;
+ }
+ else if (BOOST_UNLIKELY(existing_status.type() == status_error))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directories", p, parent, local_ec));
+ *ec = local_ec;
+ return false;
+ }
+ }
+
+ path_algorithms::decrement_v4(it);
+ parent.remove_filename_and_trailing_separators();
+ }
+
+ // Create missing directories
+ bool created = false;
+ for (; it != e; path_algorithms::increment_v4(it))
+ {
+ path const& fname = *it;
+ path_algorithms::append_v4(parent, fname);
+ if (!fname.empty() && path_algorithms::compare_v4(fname, dot_p) != 0 && path_algorithms::compare_v4(fname, dot_dot_p) != 0)
+ {
+ created = detail::create_directory(parent, nullptr, &local_ec);
+ if (BOOST_UNLIKELY(!!local_ec))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::create_directories", p, parent, local_ec));
+ *ec = local_ec;
+ return false;
+ }
+ }
+ }
+
+ return created;
+}
+
+BOOST_FILESYSTEM_DECL
+bool create_directory(path const& p, const path* existing, error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+#if defined(BOOST_POSIX_API)
+
+ mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
+ if (existing)
+ {
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ struct ::statx existing_stat;
+ if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, existing->c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_MODE, &existing_stat) < 0))
+ {
+ emit_error(errno, p, *existing, ec, "boost::filesystem::create_directory");
+ return false;
+ }
+
+ if (BOOST_UNLIKELY((existing_stat.stx_mask & (STATX_TYPE | STATX_MODE)) != (STATX_TYPE | STATX_MODE)))
+ {
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, *existing, ec, "boost::filesystem::create_directory");
+ return false;
+ }
+#else
+ struct ::stat existing_stat;
+ if (::stat(existing->c_str(), &existing_stat) < 0)
+ {
+ emit_error(errno, p, *existing, ec, "boost::filesystem::create_directory");
+ return false;
+ }
+#endif
+
+ const mode_t existing_mode = get_mode(existing_stat);
+ if (!S_ISDIR(existing_mode))
+ {
+ emit_error(ENOTDIR, p, *existing, ec, "boost::filesystem::create_directory");
+ return false;
+ }
+
+ mode = existing_mode;
+ }
+
+ if (::mkdir(p.c_str(), mode) == 0)
+ return true;
+
+#else // defined(BOOST_POSIX_API)
+
+ BOOL res;
+ if (existing)
+ res = ::CreateDirectoryExW(existing->c_str(), p.c_str(), nullptr);
+ else
+ res = ::CreateDirectoryW(p.c_str(), nullptr);
+
+ if (res)
+ return true;
+
+#endif // defined(BOOST_POSIX_API)
+
+ // attempt to create directory failed
+ err_t errval = BOOST_ERRNO; // save reason for failure
+ error_code dummy;
+
+ if (is_directory(p, dummy))
+ return false;
+
+ // attempt to create directory failed && it doesn't already exist
+ emit_error(errval, p, ec, "boost::filesystem::create_directory");
+ return false;
+}
+
+BOOST_FILESYSTEM_DECL
+void create_directory_symlink(path const& to, path const& from, system::error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+#if defined(BOOST_POSIX_API)
+ int err = ::symlink(to.c_str(), from.c_str());
+ if (BOOST_UNLIKELY(err < 0))
+ {
+ err = errno;
+ emit_error(err, to, from, ec, "boost::filesystem::create_directory_symlink");
+ }
+#else
+ // see if actually supported by Windows runtime dll
+ if (!create_symbolic_link_api)
+ {
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_directory_symlink");
+ return;
+ }
+
+ if (!create_symbolic_link_api(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_DIRECTORY | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))
+ {
+ emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_directory_symlink");
+ }
+#endif
+}
+
+BOOST_FILESYSTEM_DECL
+void create_hard_link(path const& to, path const& from, error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+#if defined(BOOST_POSIX_API)
+ int err = ::link(to.c_str(), from.c_str());
+ if (BOOST_UNLIKELY(err < 0))
+ {
+ err = errno;
+ emit_error(err, to, from, ec, "boost::filesystem::create_hard_link");
+ }
+#else
+ // see if actually supported by Windows runtime dll
+ CreateHardLinkW_t* chl_api = filesystem::detail::atomic_load_relaxed(create_hard_link_api);
+ if (BOOST_UNLIKELY(!chl_api))
+ {
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_hard_link");
+ return;
+ }
+
+ if (BOOST_UNLIKELY(!chl_api(from.c_str(), to.c_str(), nullptr)))
+ {
+ emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_hard_link");
+ }
+#endif
+}
+
+BOOST_FILESYSTEM_DECL
+void create_symlink(path const& to, path const& from, error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+#if defined(BOOST_POSIX_API)
+ int err = ::symlink(to.c_str(), from.c_str());
+ if (BOOST_UNLIKELY(err < 0))
+ {
+ err = errno;
+ emit_error(err, to, from, ec, "boost::filesystem::create_symlink");
+ }
+#else
+ // see if actually supported by Windows runtime dll
+ CreateSymbolicLinkW_t* csl_api = filesystem::detail::atomic_load_relaxed(create_symbolic_link_api);
+ if (BOOST_UNLIKELY(!csl_api))
+ {
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, to, from, ec, "boost::filesystem::create_symlink");
+ return;
+ }
+
+ if (BOOST_UNLIKELY(!csl_api(from.c_str(), to.c_str(), SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)))
+ {
+ emit_error(BOOST_ERRNO, to, from, ec, "boost::filesystem::create_symlink");
+ }
+#endif
+}
+
+BOOST_FILESYSTEM_DECL
+path current_path(error_code* ec)
+{
+#if defined(BOOST_FILESYSTEM_USE_WASI)
+ // Windows CE has no current directory, so everything's relative to the root of the directory tree.
+ // WASI also does not support current path.
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, ec, "boost::filesystem::current_path");
+ return path();
+#elif defined(BOOST_POSIX_API)
+ struct local
+ {
+ static bool getcwd_error(error_code* ec)
+ {
+ const int err = errno;
+ return error((err != ERANGE
+#if defined(__MSL__) && (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
+ // bug in some versions of the Metrowerks C lib on the Mac: wrong errno set
+ && err != 0
+#endif
+ ) ? err : 0,
+ ec, "boost::filesystem::current_path");
+ }
+ };
+
+ path cur;
+ char small_buf[small_path_size];
+ const char* p = ::getcwd(small_buf, sizeof(small_buf));
+ if (BOOST_LIKELY(!!p))
+ {
+ cur = p;
+ if (ec)
+ ec->clear();
+ }
+ else if (BOOST_LIKELY(!local::getcwd_error(ec)))
+ {
+ for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough
+ {
+ if (BOOST_UNLIKELY(path_max > absolute_path_max))
+ {
+ emit_error(ENAMETOOLONG, ec, "boost::filesystem::current_path");
+ break;
+ }
+
+ std::unique_ptr< char[] > buf(new char[path_max]);
+ p = ::getcwd(buf.get(), path_max);
+ if (BOOST_LIKELY(!!p))
+ {
+ cur = buf.get();
+ if (ec)
+ ec->clear();
+ break;
+ }
+ else if (BOOST_UNLIKELY(local::getcwd_error(ec)))
+ {
+ break;
+ }
+ }
+ }
+
+ return cur;
+#else
+ DWORD sz;
+ if ((sz = ::GetCurrentDirectoryW(0, nullptr)) == 0)
+ sz = 1;
+ std::unique_ptr< path::value_type[] > buf(new path::value_type[sz]);
+ error(::GetCurrentDirectoryW(sz, buf.get()) == 0 ? BOOST_ERRNO : 0, ec, "boost::filesystem::current_path");
+ return path(buf.get());
+#endif
+}
+
+BOOST_FILESYSTEM_DECL
+void current_path(path const& p, system::error_code* ec)
+{
+#if defined(BOOST_FILESYSTEM_USE_WASI)
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::current_path");
+#else
+ error(!BOOST_SET_CURRENT_DIRECTORY(p.c_str()) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::current_path");
+#endif
+}
+
+BOOST_FILESYSTEM_DECL
+bool equivalent_v3(path const& p1, path const& p2, system::error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+#if defined(BOOST_POSIX_API)
+
+ // p2 is done first, so any error reported is for p1
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ struct ::statx s2;
+ int e2 = invoke_statx(AT_FDCWD, p2.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s2);
+ if (BOOST_LIKELY(e2 == 0))
+ {
+ if (BOOST_UNLIKELY((s2.stx_mask & STATX_INO) != STATX_INO))
+ {
+ fail_unsupported:
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, p1, p2, ec, "boost::filesystem::equivalent");
+ return false;
+ }
+ }
+
+ struct ::statx s1;
+ int e1 = invoke_statx(AT_FDCWD, p1.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s1);
+ if (BOOST_LIKELY(e1 == 0))
+ {
+ if (BOOST_UNLIKELY((s1.stx_mask & STATX_INO) != STATX_INO))
+ goto fail_unsupported;
+ }
+#else
+ struct ::stat s2;
+ int e2 = ::stat(p2.c_str(), &s2);
+ struct ::stat s1;
+ int e1 = ::stat(p1.c_str(), &s1);
+#endif
+
+ if (BOOST_UNLIKELY(e1 != 0 || e2 != 0))
+ {
+ // if one is invalid and the other isn't then they aren't equivalent,
+ // but if both are invalid then it is an error
+ if (e1 != 0 && e2 != 0)
+ {
+ int err = errno;
+ emit_error(err, p1, p2, ec, "boost::filesystem::equivalent");
+ }
+ return false;
+ }
+
+ return equivalent_stat(s1, s2);
+
+#else // Windows
+
+ // Thanks to Jeremy Maitin-Shepard for much help and for permission to
+ // base the equivalent() implementation on portions of his
+ // file-equivalence-win32.cpp experimental code.
+
+ // Note well: Physical location on external media is part of the
+ // equivalence criteria. If there are no open handles, physical location
+ // can change due to defragmentation or other relocations. Thus handles
+ // must be held open until location information for both paths has
+ // been retrieved.
+
+ // p2 is done first, so any error reported is for p1
+ unique_handle h2(create_file_handle(
+ p2.c_str(),
+ FILE_READ_ATTRIBUTES,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS));
+
+ unique_handle h1(create_file_handle(
+ p1.c_str(),
+ FILE_READ_ATTRIBUTES,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS));
+
+ if (BOOST_UNLIKELY(!h1 || !h2))
+ {
+ // if one is invalid and the other isn't, then they aren't equivalent,
+ // but if both are invalid then it is an error
+ if (!h1 && !h2)
+ error(BOOST_ERRNO, p1, p2, ec, "boost::filesystem::equivalent");
+ return false;
+ }
+
+ // at this point, both handles are known to be valid
+
+ BY_HANDLE_FILE_INFORMATION info1, info2;
+
+ if (error(!::GetFileInformationByHandle(h1.get(), &info1) ? BOOST_ERRNO : 0, p1, p2, ec, "boost::filesystem::equivalent"))
+ return false;
+
+ if (error(!::GetFileInformationByHandle(h2.get(), &info2) ? BOOST_ERRNO : 0, p1, p2, ec, "boost::filesystem::equivalent"))
+ return false;
+
+ // In theory, volume serial numbers are sufficient to distinguish between
+ // devices, but in practice VSN's are sometimes duplicated, so last write
+ // time and file size are also checked.
+ return info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber &&
+ info1.nFileIndexHigh == info2.nFileIndexHigh &&
+ info1.nFileIndexLow == info2.nFileIndexLow &&
+ info1.nFileSizeHigh == info2.nFileSizeHigh &&
+ info1.nFileSizeLow == info2.nFileSizeLow &&
+ info1.ftLastWriteTime.dwLowDateTime == info2.ftLastWriteTime.dwLowDateTime &&
+ info1.ftLastWriteTime.dwHighDateTime == info2.ftLastWriteTime.dwHighDateTime;
+
+#endif
+}
+
+BOOST_FILESYSTEM_DECL
+bool equivalent_v4(path const& p1, path const& p2, system::error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+#if defined(BOOST_POSIX_API)
+
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ struct ::statx s1;
+ int err = invoke_statx(AT_FDCWD, p1.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s1);
+ if (BOOST_UNLIKELY(err != 0))
+ {
+ fail_errno:
+ err = errno;
+ fail_err:
+ emit_error(err, p1, p2, ec, "boost::filesystem::equivalent");
+ return false;
+ }
+
+ if (BOOST_UNLIKELY((s1.stx_mask & STATX_INO) != STATX_INO))
+ {
+ fail_unsupported:
+ err = BOOST_ERROR_NOT_SUPPORTED;
+ goto fail_err;
+ }
+
+ struct ::statx s2;
+ err = invoke_statx(AT_FDCWD, p2.c_str(), AT_NO_AUTOMOUNT, STATX_INO, &s2);
+ if (BOOST_UNLIKELY(err != 0))
+ goto fail_errno;
+
+ if (BOOST_UNLIKELY((s1.stx_mask & STATX_INO) != STATX_INO))
+ goto fail_unsupported;
+#else
+ struct ::stat s1;
+ int err = ::stat(p1.c_str(), &s1);
+ if (BOOST_UNLIKELY(err != 0))
+ {
+ fail_errno:
+ err = errno;
+ emit_error(err, p1, p2, ec, "boost::filesystem::equivalent");
+ return false;
+ }
+
+ struct ::stat s2;
+ err = ::stat(p2.c_str(), &s2);
+ if (BOOST_UNLIKELY(err != 0))
+ goto fail_errno;
+#endif
+
+ return equivalent_stat(s1, s2);
+
+#else // Windows
+
+ // Thanks to Jeremy Maitin-Shepard for much help and for permission to
+ // base the equivalent() implementation on portions of his
+ // file-equivalence-win32.cpp experimental code.
+
+ // Note well: Physical location on external media is part of the
+ // equivalence criteria. If there are no open handles, physical location
+ // can change due to defragmentation or other relocations. Thus handles
+ // must be held open until location information for both paths has
+ // been retrieved.
+
+ unique_handle h1(create_file_handle(
+ p1.c_str(),
+ FILE_READ_ATTRIBUTES,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS));
+ if (BOOST_UNLIKELY(!h1))
+ {
+ fail_errno:
+ err_t err = BOOST_ERRNO;
+ emit_error(err, p1, p2, ec, "boost::filesystem::equivalent");
+ return false;
+ }
+
+ unique_handle h2(create_file_handle(
+ p2.c_str(),
+ FILE_READ_ATTRIBUTES,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS));
+ if (BOOST_UNLIKELY(!h2))
+ goto fail_errno;
+
+ BY_HANDLE_FILE_INFORMATION info1;
+ if (BOOST_UNLIKELY(!::GetFileInformationByHandle(h1.get(), &info1)))
+ goto fail_errno;
+
+ BY_HANDLE_FILE_INFORMATION info2;
+ if (BOOST_UNLIKELY(!::GetFileInformationByHandle(h2.get(), &info2)))
+ goto fail_errno;
+
+ // In theory, volume serial numbers are sufficient to distinguish between
+ // devices, but in practice VSN's are sometimes duplicated, so last write
+ // time and file size are also checked.
+ return info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber &&
+ info1.nFileIndexHigh == info2.nFileIndexHigh &&
+ info1.nFileIndexLow == info2.nFileIndexLow &&
+ info1.nFileSizeHigh == info2.nFileSizeHigh &&
+ info1.nFileSizeLow == info2.nFileSizeLow &&
+ info1.ftLastWriteTime.dwLowDateTime == info2.ftLastWriteTime.dwLowDateTime &&
+ info1.ftLastWriteTime.dwHighDateTime == info2.ftLastWriteTime.dwHighDateTime;
+
+#endif
+}
+
+BOOST_FILESYSTEM_DECL
+uintmax_t file_size(path const& p, error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+#if defined(BOOST_POSIX_API)
+
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ struct ::statx path_stat;
+ int err;
+ if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_TYPE | STATX_SIZE, &path_stat) < 0))
+ {
+ err = errno;
+ fail:
+ emit_error(err, p, ec, "boost::filesystem::file_size");
+ return static_cast< uintmax_t >(-1);
+ }
+
+ if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_SIZE)) != (STATX_TYPE | STATX_SIZE) || !S_ISREG(path_stat.stx_mode)))
+ {
+ err = BOOST_ERROR_NOT_SUPPORTED;
+ goto fail;
+ }
+#else
+ struct ::stat path_stat;
+ int err;
+ if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0))
+ {
+ err = errno;
+ fail:
+ emit_error(err, p, ec, "boost::filesystem::file_size");
+ return static_cast< uintmax_t >(-1);
+ }
+
+ if (BOOST_UNLIKELY(!S_ISREG(path_stat.st_mode)))
+ {
+ err = BOOST_ERROR_NOT_SUPPORTED;
+ goto fail;
+ }
+#endif
+
+ return get_size(path_stat);
+
+#else // defined(BOOST_POSIX_API)
+
+ // assume uintmax_t is 64-bits on all Windows compilers
+
+ unique_handle h(create_file_handle(
+ p.c_str(),
+ FILE_READ_ATTRIBUTES,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS));
+
+ DWORD err;
+ if (BOOST_UNLIKELY(!h))
+ {
+ fail_errno:
+ err = BOOST_ERRNO;
+ fail:
+ emit_error(err, p, ec, "boost::filesystem::file_size");
+ return static_cast< uintmax_t >(-1);
+ }
+
+ BY_HANDLE_FILE_INFORMATION info;
+ if (BOOST_UNLIKELY(!::GetFileInformationByHandle(h.get(), &info)))
+ goto fail_errno;
+
+ if (BOOST_UNLIKELY((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0u))
+ {
+ err = ERROR_NOT_SUPPORTED;
+ goto fail;
+ }
+
+ return (static_cast< uintmax_t >(info.nFileSizeHigh) << 32u) | info.nFileSizeLow;
+
+#endif // defined(BOOST_POSIX_API)
+}
+
+BOOST_FILESYSTEM_DECL
+uintmax_t hard_link_count(path const& p, system::error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+#if defined(BOOST_POSIX_API)
+
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ struct ::statx path_stat;
+ if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_NLINK, &path_stat) < 0))
+ {
+ emit_error(errno, p, ec, "boost::filesystem::hard_link_count");
+ return static_cast< uintmax_t >(-1);
+ }
+
+ if (BOOST_UNLIKELY((path_stat.stx_mask & STATX_NLINK) != STATX_NLINK))
+ {
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::hard_link_count");
+ return static_cast< uintmax_t >(-1);
+ }
+
+ return static_cast< uintmax_t >(path_stat.stx_nlink);
+#else
+ struct ::stat path_stat;
+ if (BOOST_UNLIKELY(::stat(p.c_str(), &path_stat) < 0))
+ {
+ emit_error(errno, p, ec, "boost::filesystem::hard_link_count");
+ return static_cast< uintmax_t >(-1);
+ }
+
+ return static_cast< uintmax_t >(path_stat.st_nlink);
+#endif
+
+#else // defined(BOOST_POSIX_API)
+
+ unique_handle h(create_file_handle(
+ p.c_str(),
+ FILE_READ_ATTRIBUTES,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS));
+
+ if (BOOST_UNLIKELY(!h))
+ {
+ fail_errno:
+ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::hard_link_count");
+ return static_cast< uintmax_t >(-1);
+ }
+
+ // Link count info is only available through GetFileInformationByHandle
+ BY_HANDLE_FILE_INFORMATION info;
+ if (BOOST_UNLIKELY(!::GetFileInformationByHandle(h.get(), &info)))
+ goto fail_errno;
+
+ return static_cast< uintmax_t >(info.nNumberOfLinks);
+
+#endif // defined(BOOST_POSIX_API)
+}
+
+BOOST_FILESYSTEM_DECL
+path initial_path(error_code* ec)
+{
+ static path init_path;
+ if (init_path.empty())
+ init_path = current_path(ec);
+ else if (ec)
+ ec->clear();
+ return init_path;
+}
+
+//! Tests if the directory is empty. Implemented in directory.cpp.
+bool is_empty_directory
+(
+#if defined(BOOST_POSIX_API)
+ boost::scope::unique_fd&& fd,
+#else
+ unique_handle&& h,
+#endif
+ path const& p,
+ error_code* ec
+);
+
+BOOST_FILESYSTEM_DECL
+bool is_empty(path const& p, system::error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+#if defined(BOOST_POSIX_API)
+
+ boost::scope::unique_fd file;
+ int err = 0;
+ while (true)
+ {
+ file.reset(::open(p.c_str(), O_RDONLY | O_CLOEXEC));
+ if (BOOST_UNLIKELY(!file))
+ {
+ err = errno;
+ if (err == EINTR)
+ continue;
+
+ fail:
+ emit_error(err, p, ec, "boost::filesystem::is_empty");
+ return false;
+ }
+
+ break;
+ }
+
+#if defined(BOOST_FILESYSTEM_NO_O_CLOEXEC) && defined(FD_CLOEXEC)
+ if (BOOST_UNLIKELY(::fcntl(file.get(), F_SETFD, FD_CLOEXEC) < 0))
+ {
+ err = errno;
+ goto fail;
+ }
+#endif
+
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ struct ::statx path_stat;
+ if (BOOST_UNLIKELY(invoke_statx(file.get(), "", AT_EMPTY_PATH | AT_NO_AUTOMOUNT, STATX_TYPE | STATX_SIZE, &path_stat) < 0))
+ {
+ err = errno;
+ goto fail;
+ }
+
+ if (BOOST_UNLIKELY((path_stat.stx_mask & (STATX_TYPE | STATX_SIZE)) != (STATX_TYPE | STATX_SIZE)))
+ {
+ err = BOOST_ERROR_NOT_SUPPORTED;
+ goto fail;
+ }
+#else
+ struct ::stat path_stat;
+ if (BOOST_UNLIKELY(::fstat(file.get(), &path_stat) < 0))
+ {
+ err = errno;
+ goto fail;
+ }
+#endif
+
+ const mode_t mode = get_mode(path_stat);
+ if (S_ISDIR(mode))
+ return is_empty_directory(std::move(file), p, ec);
+
+ if (BOOST_UNLIKELY(!S_ISREG(mode)))
+ {
+ err = BOOST_ERROR_NOT_SUPPORTED;
+ goto fail;
+ }
+
+ return get_size(path_stat) == 0u;
+
+#else // defined(BOOST_POSIX_API)
+
+ unique_handle h(create_file_handle(
+ p.c_str(),
+ FILE_READ_ATTRIBUTES | FILE_LIST_DIRECTORY,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS));
+
+ if (BOOST_UNLIKELY(!h))
+ {
+ fail_errno:
+ const DWORD err = BOOST_ERRNO;
+ emit_error(err, p, ec, "boost::filesystem::is_empty");
+ return false;
+ }
+
+ BY_HANDLE_FILE_INFORMATION info;
+ if (BOOST_UNLIKELY(!::GetFileInformationByHandle(h.get(), &info)))
+ goto fail_errno;
+
+ if ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0u)
+ return is_empty_directory(std::move(h), p, ec);
+
+ return (info.nFileSizeHigh | info.nFileSizeLow) == 0u;
+
+#endif // defined(BOOST_POSIX_API)
+}
+
+BOOST_FILESYSTEM_DECL
+std::time_t creation_time(path const& p, system::error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+#if defined(BOOST_POSIX_API)
+
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ struct ::statx stx;
+ if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_BTIME, &stx) < 0))
+ {
+ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time");
+ return (std::numeric_limits< std::time_t >::min)();
+ }
+ if (BOOST_UNLIKELY((stx.stx_mask & STATX_BTIME) != STATX_BTIME))
+ {
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::creation_time");
+ return (std::numeric_limits< std::time_t >::min)();
+ }
+ return stx.stx_btime.tv_sec;
+#elif defined(BOOST_FILESYSTEM_STAT_ST_BIRTHTIME) && defined(BOOST_FILESYSTEM_STAT_ST_BIRTHTIMENSEC)
+ struct ::stat st;
+ if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0))
+ {
+ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::creation_time");
+ return (std::numeric_limits< std::time_t >::min)();
+ }
+ return st.BOOST_FILESYSTEM_STAT_ST_BIRTHTIME;
+#else
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::creation_time");
+ return (std::numeric_limits< std::time_t >::min)();
+#endif
+
+#else // defined(BOOST_POSIX_API)
+
+ // See the comment in last_write_time regarding access rights used here for GetFileTime.
+ unique_handle hw(create_file_handle(
+ p.c_str(),
+ FILE_READ_ATTRIBUTES | FILE_READ_EA,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS));
+
+ DWORD err;
+ if (BOOST_UNLIKELY(!hw))
+ {
+ fail_errno:
+ err = BOOST_ERRNO;
+ fail:
+ emit_error(err, p, ec, "boost::filesystem::creation_time");
+ return (std::numeric_limits< std::time_t >::min)();
+ }
+
+ FILETIME ct;
+ if (BOOST_UNLIKELY(!::GetFileTime(hw.get(), &ct, nullptr, nullptr)))
+ goto fail_errno;
+
+ std::time_t t;
+ err = to_time_t(ct, t);
+ if (BOOST_UNLIKELY(err != 0u))
+ goto fail;
+
+ return t;
+
+#endif // defined(BOOST_POSIX_API)
+}
+
+BOOST_FILESYSTEM_DECL
+std::time_t last_write_time(path const& p, system::error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+#if defined(BOOST_POSIX_API)
+
+#if defined(BOOST_FILESYSTEM_USE_STATX)
+ struct ::statx stx;
+ if (BOOST_UNLIKELY(invoke_statx(AT_FDCWD, p.c_str(), AT_NO_AUTOMOUNT, STATX_MTIME, &stx) < 0))
+ {
+ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time");
+ return (std::numeric_limits< std::time_t >::min)();
+ }
+ if (BOOST_UNLIKELY((stx.stx_mask & STATX_MTIME) != STATX_MTIME))
+ {
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::last_write_time");
+ return (std::numeric_limits< std::time_t >::min)();
+ }
+ return stx.stx_mtime.tv_sec;
+#else
+ struct ::stat st;
+ if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0))
+ {
+ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time");
+ return (std::numeric_limits< std::time_t >::min)();
+ }
+ return st.st_mtime;
+#endif
+
+#else // defined(BOOST_POSIX_API)
+
+ // GetFileTime is documented to require GENERIC_READ access right, but this causes problems if the file
+ // is opened by another process without FILE_SHARE_READ. In practice, FILE_READ_ATTRIBUTES works, and
+ // FILE_READ_EA is also added for good measure, in case if it matters for SMBv1.
+ unique_handle hw(create_file_handle(
+ p.c_str(),
+ FILE_READ_ATTRIBUTES | FILE_READ_EA,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS));
+
+ DWORD err;
+ if (BOOST_UNLIKELY(!hw))
+ {
+ fail_errno:
+ err = BOOST_ERRNO;
+ fail:
+ emit_error(err, p, ec, "boost::filesystem::last_write_time");
+ return (std::numeric_limits< std::time_t >::min)();
+ }
+
+ FILETIME lwt;
+ if (BOOST_UNLIKELY(!::GetFileTime(hw.get(), nullptr, nullptr, &lwt)))
+ goto fail_errno;
+
+ std::time_t t;
+ err = to_time_t(lwt, t);
+ if (BOOST_UNLIKELY(err != 0u))
+ goto fail;
+
+ return t;
+
+#endif // defined(BOOST_POSIX_API)
+}
+
+BOOST_FILESYSTEM_DECL
+void last_write_time(path const& p, const std::time_t new_time, system::error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+#if defined(BOOST_POSIX_API)
+
+#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+
+ struct timespec times[2] = {};
+
+ // Keep the last access time unchanged
+ times[0].tv_nsec = UTIME_OMIT;
+
+ times[1].tv_sec = new_time;
+
+ if (BOOST_UNLIKELY(::utimensat(AT_FDCWD, p.c_str(), times, 0) != 0))
+ {
+ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time");
+ return;
+ }
+
+#else // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+
+ struct ::stat st;
+ if (BOOST_UNLIKELY(::stat(p.c_str(), &st) < 0))
+ {
+ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time");
+ return;
+ }
+
+ ::utimbuf buf;
+ buf.actime = st.st_atime; // utime() updates access time too :-(
+ buf.modtime = new_time;
+ if (BOOST_UNLIKELY(::utime(p.c_str(), &buf) < 0))
+ emit_error(BOOST_ERRNO, p, ec, "boost::filesystem::last_write_time");
+
+#endif // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+
+#else // defined(BOOST_POSIX_API)
+
+ unique_handle hw(create_file_handle(
+ p.c_str(),
+ FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS));
+
+ DWORD err;
+ if (BOOST_UNLIKELY(!hw))
+ {
+ fail_errno:
+ err = BOOST_ERRNO;
+ fail:
+ emit_error(err, p, ec, "boost::filesystem::last_write_time");
+ return;
+ }
+
+ FILETIME lwt;
+ err = to_FILETIME(new_time, lwt);
+ if (BOOST_UNLIKELY(err != 0u))
+ goto fail;
+
+ if (BOOST_UNLIKELY(!::SetFileTime(hw.get(), nullptr, nullptr, &lwt)))
+ goto fail_errno;
+
+#endif // defined(BOOST_POSIX_API)
+}
+
+#ifdef BOOST_POSIX_API
+const perms active_bits(all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit);
+inline mode_t mode_cast(perms prms)
+{
+ return prms & active_bits;
+}
+#endif
+
+BOOST_FILESYSTEM_DECL
+void permissions(path const& p, perms prms, system::error_code* ec)
+{
+ BOOST_ASSERT_MSG(!((prms & add_perms) && (prms & remove_perms)), "add_perms and remove_perms are mutually exclusive");
+
+ if ((prms & add_perms) && (prms & remove_perms)) // precondition failed
+ return;
+
+#if defined(BOOST_FILESYSTEM_USE_WASI)
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::permissions");
+#elif defined(BOOST_POSIX_API)
+ error_code local_ec;
+ file_status current_status((prms & symlink_perms) ? detail::symlink_status_impl(p, &local_ec) : detail::status_impl(p, &local_ec));
+ if (local_ec)
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::permissions", p, local_ec));
+
+ *ec = local_ec;
+ return;
+ }
+
+ if (prms & add_perms)
+ prms |= current_status.permissions();
+ else if (prms & remove_perms)
+ prms = current_status.permissions() & ~prms;
+
+ // OS X <10.10, iOS <8.0 and some other platforms don't support fchmodat().
+ // Solaris (SunPro and gcc) only support fchmodat() on Solaris 11 and higher,
+ // and a runtime check is too much trouble.
+ // Linux does not support permissions on symbolic links and has no plans to
+ // support them in the future. The chmod() code is thus more practical,
+ // rather than always hitting ENOTSUP when sending in AT_SYMLINK_NO_FOLLOW.
+ // - See the 3rd paragraph of
+ // "Symbolic link ownership, permissions, and timestamps" at:
+ // "http://man7.org/linux/man-pages/man7/symlink.7.html"
+ // - See the fchmodat() Linux man page:
+ // "http://man7.org/linux/man-pages/man2/fchmodat.2.html"
+#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) && \
+ !(defined(__SUNPRO_CC) || defined(__sun) || defined(sun)) && \
+ !(defined(linux) || defined(__linux) || defined(__linux__)) && \
+ !(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101000) && \
+ !(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 80000) && \
+ !(defined(__rtems__)) && \
+ !(defined(__QNX__) && (_NTO_VERSION <= 700))
+ if (::fchmodat(AT_FDCWD, p.c_str(), mode_cast(prms), !(prms & symlink_perms) ? 0 : AT_SYMLINK_NOFOLLOW))
+#else // fallback if fchmodat() not supported
+ if (::chmod(p.c_str(), mode_cast(prms)))
+#endif
+ {
+ const int err = errno;
+ if (!ec)
+ {
+ BOOST_FILESYSTEM_THROW(filesystem_error(
+ "boost::filesystem::permissions", p, error_code(err, system::generic_category())));
+ }
+
+ ec->assign(err, system::generic_category());
+ }
+
+#else // Windows
+
+ // if not going to alter FILE_ATTRIBUTE_READONLY, just return
+ if (!(!((prms & (add_perms | remove_perms))) || (prms & (owner_write | group_write | others_write))))
+ return;
+
+ DWORD attr = ::GetFileAttributesW(p.c_str());
+
+ if (error(attr == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions"))
+ return;
+
+ if (prms & add_perms)
+ attr &= ~FILE_ATTRIBUTE_READONLY;
+ else if (prms & remove_perms)
+ attr |= FILE_ATTRIBUTE_READONLY;
+ else if (prms & (owner_write | group_write | others_write))
+ attr &= ~FILE_ATTRIBUTE_READONLY;
+ else
+ attr |= FILE_ATTRIBUTE_READONLY;
+
+ error(::SetFileAttributesW(p.c_str(), attr) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::permissions");
+#endif
+}
+
+BOOST_FILESYSTEM_DECL
+path read_symlink(path const& p, system::error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+ path symlink_path;
+
+#ifdef BOOST_POSIX_API
+ const char* const path_str = p.c_str();
+ char small_buf[small_path_size];
+ ssize_t result = ::readlink(path_str, small_buf, sizeof(small_buf));
+ if (BOOST_UNLIKELY(result < 0))
+ {
+ fail:
+ const int err = errno;
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", p, error_code(err, system_category())));
+
+ ec->assign(err, system_category());
+ }
+ else if (BOOST_LIKELY(static_cast< std::size_t >(result) < sizeof(small_buf)))
+ {
+ symlink_path.assign(small_buf, small_buf + result);
+ }
+ else
+ {
+ for (std::size_t path_max = sizeof(small_buf) * 2u;; path_max *= 2u) // loop 'til buffer large enough
+ {
+ if (BOOST_UNLIKELY(path_max > absolute_path_max))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::read_symlink", p, error_code(ENAMETOOLONG, system_category())));
+
+ ec->assign(ENAMETOOLONG, system_category());
+ break;
+ }
+
+ std::unique_ptr< char[] > buf(new char[path_max]);
+ result = ::readlink(path_str, buf.get(), path_max);
+ if (BOOST_UNLIKELY(result < 0))
+ {
+ goto fail;
+ }
+ else if (BOOST_LIKELY(static_cast< std::size_t >(result) < path_max))
+ {
+ symlink_path.assign(buf.get(), buf.get() + result);
+ break;
+ }
+ }
+ }
+
+#else
+
+ unique_handle h(create_file_handle(
+ p.c_str(),
+ FILE_READ_ATTRIBUTES,
+ FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT));
+
+ DWORD error;
+ if (BOOST_UNLIKELY(!h))
+ {
+ return_last_error:
+ error = ::GetLastError();
+ emit_error(error, p, ec, "boost::filesystem::read_symlink");
+ return symlink_path;
+ }
+
+ std::unique_ptr< reparse_data_buffer_with_storage > buf(new reparse_data_buffer_with_storage);
+ DWORD sz = 0u;
+ if (BOOST_UNLIKELY(!::DeviceIoControl(h.get(), FSCTL_GET_REPARSE_POINT, nullptr, 0, buf.get(), sizeof(*buf), &sz, nullptr)))
+ goto return_last_error;
+
+ const wchar_t* buffer;
+ std::size_t offset, len;
+ switch (buf->rdb.ReparseTag)
+ {
+ case IO_REPARSE_TAG_MOUNT_POINT:
+ buffer = buf->rdb.MountPointReparseBuffer.PathBuffer;
+ offset = buf->rdb.MountPointReparseBuffer.SubstituteNameOffset;
+ len = buf->rdb.MountPointReparseBuffer.SubstituteNameLength;
+ break;
+
+ case IO_REPARSE_TAG_SYMLINK:
+ buffer = buf->rdb.SymbolicLinkReparseBuffer.PathBuffer;
+ offset = buf->rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset;
+ len = buf->rdb.SymbolicLinkReparseBuffer.SubstituteNameLength;
+ // Note: iff info.rdb.SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE
+ // -> resulting path is relative to the source
+ break;
+
+ default:
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "Unknown ReparseTag in boost::filesystem::read_symlink");
+ return symlink_path;
+ }
+
+ symlink_path = convert_nt_path_to_win32_path(buffer + offset / sizeof(wchar_t), len / sizeof(wchar_t));
+#endif
+
+ return symlink_path;
+}
+
+BOOST_FILESYSTEM_DECL
+path relative(path const& p, path const& base, error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+ error_code local_ec;
+ path cur_path;
+ if (!p.is_absolute() || !base.is_absolute())
+ {
+ cur_path = detail::current_path(&local_ec);
+ if (BOOST_UNLIKELY(!!local_ec))
+ {
+ fail_local_ec:
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::relative", p, base, local_ec));
+
+ *ec = local_ec;
+ return path();
+ }
+ }
+
+ path wc_base(detail::weakly_canonical_v4(base, cur_path, &local_ec));
+ if (BOOST_UNLIKELY(!!local_ec))
+ goto fail_local_ec;
+ path wc_p(detail::weakly_canonical_v4(p, cur_path, &local_ec));
+ if (BOOST_UNLIKELY(!!local_ec))
+ goto fail_local_ec;
+ return wc_p.lexically_relative(wc_base);
+}
+
+BOOST_FILESYSTEM_DECL
+bool remove(path const& p, error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+ return detail::remove_impl(p, ec);
+}
+
+BOOST_FILESYSTEM_DECL
+uintmax_t remove_all(path const& p, error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+ return detail::remove_all_impl(p, ec);
+}
+
+BOOST_FILESYSTEM_DECL
+void rename(path const& old_p, path const& new_p, error_code* ec)
+{
+ error(!BOOST_MOVE_FILE(old_p.c_str(), new_p.c_str()) ? BOOST_ERRNO : 0, old_p, new_p, ec, "boost::filesystem::rename");
+}
+
+BOOST_FILESYSTEM_DECL
+void resize_file(path const& p, uintmax_t size, system::error_code* ec)
+{
+#if defined(BOOST_POSIX_API)
+ if (BOOST_UNLIKELY(size > static_cast< uintmax_t >((std::numeric_limits< off_t >::max)())))
+ {
+ emit_error(system::errc::file_too_large, p, ec, "boost::filesystem::resize_file");
+ return;
+ }
+#endif
+ error(!BOOST_RESIZE_FILE(p.c_str(), size) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::resize_file");
+}
+
+BOOST_FILESYSTEM_DECL
+space_info space(path const& p, error_code* ec)
+{
+ space_info info;
+ // Initialize members to -1, as required by C++20 [fs.op.space]/1 in case of error
+ info.capacity = static_cast< uintmax_t >(-1);
+ info.free = static_cast< uintmax_t >(-1);
+ info.available = static_cast< uintmax_t >(-1);
+
+ if (ec)
+ ec->clear();
+
+#if defined(BOOST_FILESYSTEM_USE_WASI)
+
+ emit_error(BOOST_ERROR_NOT_SUPPORTED, p, ec, "boost::filesystem::space");
+
+#elif defined(BOOST_POSIX_API)
+
+ struct BOOST_STATVFS vfs;
+ if (!error(::BOOST_STATVFS(p.c_str(), &vfs) ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::space"))
+ {
+ info.capacity = static_cast< uintmax_t >(vfs.f_blocks) * BOOST_STATVFS_F_FRSIZE;
+ info.free = static_cast< uintmax_t >(vfs.f_bfree) * BOOST_STATVFS_F_FRSIZE;
+ info.available = static_cast< uintmax_t >(vfs.f_bavail) * BOOST_STATVFS_F_FRSIZE;
+ }
+
+#else
+
+ // GetDiskFreeSpaceExW requires a directory path, which is unlike statvfs, which accepts any file.
+ // To work around this, test if the path refers to a directory and use the parent directory if not.
+ error_code local_ec;
+ file_status status = detail::status_impl(p, &local_ec);
+ if (status.type() == fs::status_error || status.type() == fs::file_not_found)
+ {
+ fail_local_ec:
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::space", p, local_ec));
+ *ec = local_ec;
+ return info;
+ }
+
+ path dir_path = p;
+ if (!is_directory(status))
+ {
+ path cur_path = detail::current_path(ec);
+ if (ec && *ec)
+ return info;
+
+ status = detail::symlink_status_impl(p, &local_ec);
+ if (status.type() == fs::status_error)
+ goto fail_local_ec;
+ if (is_symlink(status))
+ {
+ // We need to resolve the symlink so that we report the space for the symlink target
+ dir_path = detail::canonical_v4(p, cur_path, ec);
+ if (ec && *ec)
+ return info;
+ }
+
+ dir_path = dir_path.parent_path();
+ if (dir_path.empty())
+ {
+ // The original path was just a filename, which is a relative path wrt. current directory
+ dir_path = cur_path;
+ }
+ }
+
+ // For UNC names, the path must also include a trailing slash.
+ path::string_type str = dir_path.native();
+ if (str.size() >= 2u && detail::is_directory_separator(str[0]) && detail::is_directory_separator(str[1]) && !detail::is_directory_separator(*(str.end() - 1)))
+ str.push_back(path::preferred_separator);
+
+ ULARGE_INTEGER avail, total, free;
+ if (!error(::GetDiskFreeSpaceExW(str.c_str(), &avail, &total, &free) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::space"))
+ {
+ info.capacity = static_cast< uintmax_t >(total.QuadPart);
+ info.free = static_cast< uintmax_t >(free.QuadPart);
+ info.available = static_cast< uintmax_t >(avail.QuadPart);
+ }
+
+#endif
+
+ return info;
+}
+
+BOOST_FILESYSTEM_DECL
+file_status status(path const& p, error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+ return detail::status_impl(p, ec);
+}
+
+BOOST_FILESYSTEM_DECL
+file_status symlink_status(path const& p, error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+ return detail::symlink_status_impl(p, ec);
+}
+
+// contributed by Jeff Flinn
+BOOST_FILESYSTEM_DECL
+path temp_directory_path(system::error_code* ec)
+{
+ if (ec)
+ ec->clear();
+
+#ifdef BOOST_POSIX_API
+
+ const char* val = nullptr;
+
+ (val = std::getenv("TMPDIR")) ||
+ (val = std::getenv("TMP")) ||
+ (val = std::getenv("TEMP")) ||
+ (val = std::getenv("TEMPDIR"));
+
+#ifdef __ANDROID__
+ const char* default_tmp = "/data/local/tmp";
+#else
+ const char* default_tmp = "/tmp";
+#endif
+ path p((val != nullptr) ? val : default_tmp);
+
+ if (BOOST_UNLIKELY(p.empty()))
+ {
+ fail_not_dir:
+ error(ENOTDIR, p, ec, "boost::filesystem::temp_directory_path");
+ return p;
+ }
+
+ file_status status = detail::status_impl(p, ec);
+ if (BOOST_UNLIKELY(ec && *ec))
+ return path();
+ if (BOOST_UNLIKELY(!is_directory(status)))
+ goto fail_not_dir;
+
+ return p;
+
+#else // Windows
+
+ static const wchar_t* const env_list[] = { L"TMP", L"TEMP", L"LOCALAPPDATA", L"USERPROFILE" };
+ static const wchar_t temp_dir[] = L"Temp";
+
+ path p;
+ for (unsigned int i = 0; i < sizeof(env_list) / sizeof(*env_list); ++i)
+ {
+ std::wstring env = wgetenv(env_list[i]);
+ if (!env.empty())
+ {
+ p = env;
+ if (i >= 2)
+ path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u));
+ error_code lcl_ec;
+ if (exists(p, lcl_ec) && !lcl_ec && is_directory(p, lcl_ec) && !lcl_ec)
+ break;
+ p.clear();
+ }
+ }
+
+ if (p.empty())
+ {
+ // use a separate buffer since in C++03 a string is not required to be contiguous
+ const UINT size = ::GetWindowsDirectoryW(nullptr, 0);
+ if (BOOST_UNLIKELY(size == 0))
+ {
+ getwindir_error:
+ int errval = ::GetLastError();
+ error(errval, ec, "boost::filesystem::temp_directory_path");
+ return path();
+ }
+
+ std::unique_ptr< wchar_t[] > buf(new wchar_t[size]);
+ if (BOOST_UNLIKELY(::GetWindowsDirectoryW(buf.get(), size) == 0))
+ goto getwindir_error;
+
+ p = buf.get(); // do not depend on initial buf size, see ticket #10388
+ path_algorithms::append_v4(p, temp_dir, temp_dir + (sizeof(temp_dir) / sizeof(*temp_dir) - 1u));
+ }
+
+ return p;
+
+#endif
+}
+
+BOOST_FILESYSTEM_DECL
+path system_complete(path const& p, system::error_code* ec)
+{
+#ifdef BOOST_POSIX_API
+
+ if (p.empty() || p.is_absolute())
+ return p;
+
+ path res(current_path());
+ path_algorithms::append_v4(res, p);
+ return res;
+
+#else
+
+ if (p.empty())
+ {
+ if (ec)
+ ec->clear();
+ return p;
+ }
+
+ BOOST_CONSTEXPR_OR_CONST std::size_t buf_size = 128u;
+ wchar_t buf[buf_size];
+ wchar_t* pfn;
+ std::size_t len = get_full_path_name(p, buf_size, buf, &pfn);
+
+ if (error(len == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete"))
+ return path();
+
+ if (len < buf_size) // len does not include null termination character
+ return path(&buf[0]);
+
+ std::unique_ptr< wchar_t[] > big_buf(new wchar_t[len]);
+
+ return error(get_full_path_name(p, len, big_buf.get(), &pfn) == 0 ? BOOST_ERRNO : 0, p, ec, "boost::filesystem::system_complete") ? path() : path(big_buf.get());
+
+#endif
+}
+
+BOOST_FILESYSTEM_DECL
+path weakly_canonical_v3(path const& p, path const& base, system::error_code* ec)
+{
+ path source(detail::absolute_v3(p, base, ec));
+ if (ec && *ec)
+ {
+ return_empty_path:
+ return path();
+ }
+
+ system::error_code local_ec;
+ const path::iterator source_end(source.end());
+
+#if defined(BOOST_POSIX_API)
+
+ path::iterator itr(source_end);
+ path head(source);
+ for (; !head.empty(); path_algorithms::decrement_v4(itr))
+ {
+ file_status head_status(detail::status_impl(head, &local_ec));
+ if (BOOST_UNLIKELY(head_status.type() == fs::status_error))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec));
+
+ *ec = local_ec;
+ goto return_empty_path;
+ }
+
+ if (head_status.type() != fs::file_not_found)
+ break;
+
+ head.remove_filename_and_trailing_separators();
+ }
+
+ path const& dot_p = dot_path();
+ path const& dot_dot_p = dot_dot_path();
+
+#else
+
+ path const& dot_p = dot_path();
+ path const& dot_dot_p = dot_dot_path();
+
+ // On Windows, filesystem APIs such as GetFileAttributesW and CreateFileW perform lexical path normalization
+ // internally. As a result, a path like "c:\a\.." can be reported as present even if "c:\a" is not. This would
+ // break canonical, as symlink_status that it calls internally would report an error that the file at the
+ // intermediate path does not exist. To avoid this, scan the initial path in the forward direction.
+ // Also, operate on paths with preferred separators. This can be important on Windows since GetFileAttributesW
+ // or CreateFileW, which is called in status() may return "file not found" for paths to network shares and
+ // mounted cloud storages that have forward slashes as separators.
+ // Also, avoid querying status of the root name such as \\?\c: as CreateFileW returns ERROR_INVALID_FUNCTION for
+ // such path. Querying the status of a root name such as c: is also not right as this path refers to the current
+ // directory on drive C:, which is not what we want to test for existence anyway.
+ path::iterator itr(source.begin());
+ path head;
+ if (source.has_root_name())
+ {
+ BOOST_ASSERT(itr != source_end);
+ head = *itr;
+ path_algorithms::increment_v4(itr);
+ }
+
+ if (source.has_root_directory())
+ {
+ BOOST_ASSERT(itr != source_end);
+ // Convert generic separator returned by the iterator for the root directory to
+ // the preferred separator.
+ head += path::preferred_separator;
+ path_algorithms::increment_v4(itr);
+ }
+
+ if (!head.empty())
+ {
+ file_status head_status(detail::status_impl(head, &local_ec));
+ if (BOOST_UNLIKELY(head_status.type() == fs::status_error))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec));
+
+ *ec = local_ec;
+ goto return_empty_path;
+ }
+
+ if (head_status.type() == fs::file_not_found)
+ {
+ // If the root path does not exist then no path element exists
+ itr = source.begin();
+ head.clear();
+ goto skip_head;
+ }
+ }
+
+ for (; itr != source_end; path_algorithms::increment_v4(itr))
+ {
+ path const& source_elem = *itr;
+
+ // Avoid querying status of paths containing dot and dot-dot elements, as this will break
+ // if the root name starts with "\\?\".
+ if (path_algorithms::compare_v4(source_elem, dot_p) == 0)
+ continue;
+
+ if (path_algorithms::compare_v4(source_elem, dot_dot_p) == 0)
+ {
+ if (head.has_relative_path())
+ head.remove_filename_and_trailing_separators();
+
+ continue;
+ }
+
+ path_algorithms::append_v4(head, source_elem);
+
+ file_status head_status(detail::status_impl(head, &local_ec));
+ if (BOOST_UNLIKELY(head_status.type() == fs::status_error))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec));
+
+ *ec = local_ec;
+ goto return_empty_path;
+ }
+
+ if (head_status.type() == fs::file_not_found)
+ {
+ head.remove_filename_and_trailing_separators();
+ break;
+ }
+ }
+
+skip_head:;
+
+#endif
+
+ path tail;
+ bool tail_has_dots = false;
+ for (; itr != source_end; path_algorithms::increment_v4(itr))
+ {
+ path const& tail_elem = *itr;
+ path_algorithms::append_v4(tail, tail_elem);
+ // for a later optimization, track if any dot or dot-dot elements are present
+ if (!tail_has_dots && (path_algorithms::compare_v4(tail_elem, dot_p) == 0 || path_algorithms::compare_v4(tail_elem, dot_dot_p) == 0))
+ tail_has_dots = true;
+ }
+
+ head = detail::canonical_v3(head, base, &local_ec);
+ if (BOOST_UNLIKELY(!!local_ec))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec));
+
+ *ec = local_ec;
+ goto return_empty_path;
+ }
+
+ if (BOOST_LIKELY(!tail.empty()))
+ {
+ path_algorithms::append_v4(head, tail);
+
+ // optimization: only normalize if tail had dot or dot-dot element
+ if (tail_has_dots)
+ head = path_algorithms::lexically_normal_v4(head);
+ }
+
+ return head;
+}
+
+BOOST_FILESYSTEM_DECL
+path weakly_canonical_v4(path const& p, path const& base, system::error_code* ec)
+{
+ path source(detail::absolute_v4(p, base, ec));
+ if (ec && *ec)
+ {
+ return_empty_path:
+ return path();
+ }
+
+ system::error_code local_ec;
+ const path::iterator source_end(source.end());
+
+#if defined(BOOST_POSIX_API)
+
+ path::iterator itr(source_end);
+ path head(source);
+ for (; !head.empty(); path_algorithms::decrement_v4(itr))
+ {
+ file_status head_status(detail::status_impl(head, &local_ec));
+ if (BOOST_UNLIKELY(head_status.type() == fs::status_error))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec));
+
+ *ec = local_ec;
+ goto return_empty_path;
+ }
+
+ if (head_status.type() != fs::file_not_found)
+ break;
+
+ head.remove_filename_and_trailing_separators();
+ }
+
+ path const& dot_p = dot_path();
+ path const& dot_dot_p = dot_dot_path();
+
+#else
+
+ path const& dot_p = dot_path();
+ path const& dot_dot_p = dot_dot_path();
+
+ // On Windows, filesystem APIs such as GetFileAttributesW and CreateFileW perform lexical path normalization
+ // internally. As a result, a path like "c:\a\.." can be reported as present even if "c:\a" is not. This would
+ // break canonical, as symlink_status that it calls internally would report an error that the file at the
+ // intermediate path does not exist. To avoid this, scan the initial path in the forward direction.
+ // Also, operate on paths with preferred separators. This can be important on Windows since GetFileAttributesW
+ // or CreateFileW, which is called in status() may return "file not found" for paths to network shares and
+ // mounted cloud storages that have forward slashes as separators.
+ // Also, avoid querying status of the root name such as \\?\c: as CreateFileW returns ERROR_INVALID_FUNCTION for
+ // such path. Querying the status of a root name such as c: is also not right as this path refers to the current
+ // directory on drive C:, which is not what we want to test for existence anyway.
+ path::iterator itr(source.begin());
+ path head;
+ if (source.has_root_name())
+ {
+ BOOST_ASSERT(itr != source_end);
+ head = *itr;
+ path_algorithms::increment_v4(itr);
+ }
+
+ if (source.has_root_directory())
+ {
+ BOOST_ASSERT(itr != source_end);
+ // Convert generic separator returned by the iterator for the root directory to
+ // the preferred separator.
+ head += path::preferred_separator;
+ path_algorithms::increment_v4(itr);
+ }
+
+ if (!head.empty())
+ {
+ file_status head_status(detail::status_impl(head, &local_ec));
+ if (BOOST_UNLIKELY(head_status.type() == fs::status_error))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec));
+
+ *ec = local_ec;
+ goto return_empty_path;
+ }
+
+ if (head_status.type() == fs::file_not_found)
+ {
+ // If the root path does not exist then no path element exists
+ itr = source.begin();
+ head.clear();
+ goto skip_head;
+ }
+ }
+
+ for (; itr != source_end; path_algorithms::increment_v4(itr))
+ {
+ path const& source_elem = *itr;
+
+ // Avoid querying status of paths containing dot and dot-dot elements, as this will break
+ // if the root name starts with "\\?\".
+ if (path_algorithms::compare_v4(source_elem, dot_p) == 0)
+ continue;
+
+ if (path_algorithms::compare_v4(source_elem, dot_dot_p) == 0)
+ {
+ if (head.has_relative_path())
+ head.remove_filename_and_trailing_separators();
+
+ continue;
+ }
+
+ path_algorithms::append_v4(head, source_elem);
+
+ file_status head_status(detail::status_impl(head, &local_ec));
+ if (BOOST_UNLIKELY(head_status.type() == fs::status_error))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec));
+
+ *ec = local_ec;
+ goto return_empty_path;
+ }
+
+ if (head_status.type() == fs::file_not_found)
+ {
+ head.remove_filename_and_trailing_separators();
+ break;
+ }
+ }
+
+skip_head:;
+
+#endif
+
+ path tail;
+ bool tail_has_dots = false;
+ for (; itr != source_end; path_algorithms::increment_v4(itr))
+ {
+ path const& tail_elem = *itr;
+ path_algorithms::append_v4(tail, tail_elem);
+ // for a later optimization, track if any dot or dot-dot elements are present
+ if (!tail_has_dots && (path_algorithms::compare_v4(tail_elem, dot_p) == 0 || path_algorithms::compare_v4(tail_elem, dot_dot_p) == 0))
+ tail_has_dots = true;
+ }
+
+ head = detail::canonical_v4(head, base, &local_ec);
+ if (BOOST_UNLIKELY(!!local_ec))
+ {
+ if (!ec)
+ BOOST_FILESYSTEM_THROW(filesystem_error("boost::filesystem::weakly_canonical", head, local_ec));
+
+ *ec = local_ec;
+ goto return_empty_path;
+ }
+
+ if (BOOST_LIKELY(!tail.empty()))
+ {
+ path_algorithms::append_v4(head, tail);
+
+ // optimization: only normalize if tail had dot or dot-dot element
+ if (tail_has_dots)
+ head = path_algorithms::lexically_normal_v4(head);
+ }
+
+ return head;
+}
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
diff --git a/contrib/restricted/boost/filesystem/src/path.cpp b/contrib/restricted/boost/filesystem/src/path.cpp
new file mode 100644
index 0000000000..82b2c7d520
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/path.cpp
@@ -0,0 +1,1719 @@
+// filesystem path.cpp ------------------------------------------------------------- //
+
+// Copyright Beman Dawes 2008
+// Copyright Andrey Semashev 2021-2024
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+#include "platform_config.hpp"
+
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/detail/path_traits.hpp> // codecvt_error_category()
+#include <boost/system/error_category.hpp> // for BOOST_SYSTEM_HAS_CONSTEXPR
+#include <boost/assert.hpp>
+#include <algorithm>
+#include <iterator>
+#include <utility>
+#include <string>
+#include <cstddef>
+#include <cstring>
+#include <cstdlib> // std::atexit
+
+#ifdef BOOST_WINDOWS_API
+#include "windows_file_codecvt.hpp"
+#include "windows_tools.hpp"
+#include <windows.h>
+#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
+#include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
+#endif
+
+#ifdef BOOST_FILESYSTEM_DEBUG
+#include <iostream>
+#include <iomanip>
+#endif
+
+#include "atomic_tools.hpp"
+#include "private_config.hpp"
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace fs = boost::filesystem;
+
+using boost::filesystem::path;
+
+//--------------------------------------------------------------------------------------//
+// //
+// class path helpers //
+// //
+//--------------------------------------------------------------------------------------//
+
+namespace {
+//------------------------------------------------------------------------------------//
+// miscellaneous class path helpers //
+//------------------------------------------------------------------------------------//
+
+typedef path::value_type value_type;
+typedef path::string_type string_type;
+typedef string_type::size_type size_type;
+
+#ifdef BOOST_WINDOWS_API
+
+const wchar_t dot_path_literal[] = L".";
+const wchar_t dot_dot_path_literal[] = L"..";
+const wchar_t separators[] = L"/\\";
+using boost::filesystem::detail::colon;
+using boost::filesystem::detail::questionmark;
+
+inline bool is_alnum(wchar_t c)
+{
+ return boost::filesystem::detail::is_letter(c) || (c >= L'0' && c <= L'9');
+}
+
+inline bool is_device_name_char(wchar_t c)
+{
+ // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html
+ // Device names are:
+ //
+ // - PRN
+ // - AUX
+ // - NUL
+ // - CON
+ // - LPT[1-9]
+ // - COM[1-9]
+ // - CONIN$
+ // - CONOUT$
+ return is_alnum(c) || c == L'$';
+}
+
+//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found
+inline size_type find_separator(const wchar_t* p, size_type size) noexcept
+{
+ size_type pos = 0u;
+ for (; pos < size; ++pos)
+ {
+ const wchar_t c = p[pos];
+ if (boost::filesystem::detail::is_directory_separator(c))
+ break;
+ }
+ return pos;
+}
+
+#else // BOOST_WINDOWS_API
+
+const char dot_path_literal[] = ".";
+const char dot_dot_path_literal[] = "..";
+const char separators[] = "/";
+
+//! Returns position of the first directory separator in the \a size initial characters of \a p, or \a size if not found
+inline size_type find_separator(const char* p, size_type size) noexcept
+{
+ const char* sep = static_cast< const char* >(std::memchr(p, '/', size));
+ size_type pos = size;
+ if (BOOST_LIKELY(!!sep))
+ pos = sep - p;
+ return pos;
+}
+
+#endif // BOOST_WINDOWS_API
+
+// pos is position of the separator
+bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos);
+
+// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found.
+size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos);
+
+// Returns: starting position of root directory or size if not found. Sets root_name_size to length
+// of the root name if the characters before the returned position (if any) are considered a root name.
+size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size);
+
+// Finds position and size of the first element of the path
+void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size);
+
+// Finds position and size of the first element of the path
+inline void first_element(string_type const& src, size_type& element_pos, size_type& element_size)
+{
+ first_element(src, element_pos, element_size, src.size());
+}
+
+} // unnamed namespace
+
+//--------------------------------------------------------------------------------------//
+// //
+// class path implementation //
+// //
+//--------------------------------------------------------------------------------------//
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+// C++14 provides a mismatch algorithm with four iterator arguments(), but earlier
+// standard libraries didn't, so provide this needed functionality.
+inline std::pair< path::iterator, path::iterator > mismatch(path::iterator it1, path::iterator it1end, path::iterator it2, path::iterator it2end)
+{
+ for (; it1 != it1end && it2 != it2end && path_algorithms::compare_v4(*it1, *it2) == 0;)
+ {
+ path_algorithms::increment_v4(it1);
+ path_algorithms::increment_v4(it2);
+ }
+ return std::make_pair(it1, it2);
+}
+
+// normal --------------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v3(path const& p)
+{
+ const value_type* const pathname = p.m_pathname.c_str();
+ const size_type pathname_size = p.m_pathname.size();
+ size_type root_name_size = 0;
+ size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size);
+ path normal(pathname, pathname + root_name_size);
+
+#if defined(BOOST_WINDOWS_API)
+ for (size_type i = 0; i < root_name_size; ++i)
+ {
+ if (normal.m_pathname[i] == path::separator)
+ normal.m_pathname[i] = path::preferred_separator;
+ }
+#endif
+
+ size_type root_path_size = root_name_size;
+ if (root_dir_pos < pathname_size)
+ {
+ root_path_size = root_dir_pos + 1;
+ normal.m_pathname.push_back(path::preferred_separator);
+ }
+
+ size_type i = root_path_size;
+
+ // Skip redundant directory separators after the root directory
+ while (i < pathname_size && detail::is_directory_separator(pathname[i]))
+ ++i;
+
+ if (i < pathname_size)
+ {
+ bool last_element_was_dot = false;
+ while (true)
+ {
+ {
+ const size_type start_pos = i;
+
+ // Find next separator
+ i += find_separator(pathname + i, pathname_size - i);
+
+ const size_type size = i - start_pos;
+
+ // Skip dot elements
+ if (size == 1u && pathname[start_pos] == path::dot)
+ {
+ last_element_was_dot = true;
+ goto skip_append;
+ }
+
+ last_element_was_dot = false;
+
+ // Process dot dot elements
+ if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size)
+ {
+ // Don't remove previous dot dot elements
+ const size_type normal_size = normal.m_pathname.size();
+ size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size);
+ size_type pos = normal_size - filename_size;
+ if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot)
+ {
+ if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1]))
+ --pos;
+ normal.m_pathname.erase(normal.m_pathname.begin() + pos , normal.m_pathname.end());
+ goto skip_append;
+ }
+ }
+
+ // Append the element
+ path_algorithms::append_separator_if_needed(normal);
+ normal.m_pathname.append(pathname + start_pos, size);
+ }
+
+ skip_append:
+ if (i == pathname_size)
+ break;
+
+ // Skip directory separators, including duplicates
+ while (i < pathname_size && detail::is_directory_separator(pathname[i]))
+ ++i;
+
+ if (i == pathname_size)
+ {
+ // If a path ends with a separator, add a trailing dot element
+ goto append_trailing_dot;
+ }
+ }
+
+ if (normal.empty() || last_element_was_dot)
+ {
+ append_trailing_dot:
+ path_algorithms::append_separator_if_needed(normal);
+ normal.m_pathname.push_back(path::dot);
+ }
+ }
+
+ return normal;
+}
+
+BOOST_FILESYSTEM_DECL path path_algorithms::lexically_normal_v4(path const& p)
+{
+ const value_type* const pathname = p.m_pathname.c_str();
+ const size_type pathname_size = p.m_pathname.size();
+ size_type root_name_size = 0;
+ size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size);
+ path normal(pathname, pathname + root_name_size);
+
+ size_type root_path_size = root_name_size;
+ if (root_dir_pos < pathname_size)
+ {
+ root_path_size = root_dir_pos + 1;
+ normal.m_pathname.push_back(path::preferred_separator);
+ }
+
+ size_type i = root_path_size;
+
+ // Skip redundant directory separators after the root directory
+ while (i < pathname_size && detail::is_directory_separator(pathname[i]))
+ ++i;
+
+ if (i < pathname_size)
+ {
+ while (true)
+ {
+ bool last_element_was_dot = false;
+ {
+ const size_type start_pos = i;
+
+ // Find next separator
+ i += find_separator(pathname + i, pathname_size - i);
+
+ const size_type size = i - start_pos;
+
+ // Skip dot elements
+ if (size == 1u && pathname[start_pos] == path::dot)
+ {
+ last_element_was_dot = true;
+ goto skip_append;
+ }
+
+ // Process dot dot elements
+ if (size == 2u && pathname[start_pos] == path::dot && pathname[start_pos + 1] == path::dot && normal.m_pathname.size() > root_path_size)
+ {
+ // Don't remove previous dot dot elements
+ const size_type normal_size = normal.m_pathname.size();
+ size_type filename_size = find_filename_size(normal.m_pathname, root_path_size, normal_size);
+ size_type pos = normal_size - filename_size;
+ if (filename_size != 2u || normal.m_pathname[pos] != path::dot || normal.m_pathname[pos + 1] != path::dot)
+ {
+ if (pos > root_path_size && detail::is_directory_separator(normal.m_pathname[pos - 1]))
+ --pos;
+ normal.m_pathname.erase(normal.m_pathname.begin() + pos, normal.m_pathname.end());
+ goto skip_append;
+ }
+ }
+
+ // Append the element
+ path_algorithms::append_separator_if_needed(normal);
+ normal.m_pathname.append(pathname + start_pos, size);
+ }
+
+ skip_append:
+ if (i == pathname_size)
+ {
+ // If a path ends with a trailing dot after a directory element, add a trailing separator
+ if (last_element_was_dot && !normal.empty() && !normal.filename_is_dot_dot())
+ path_algorithms::append_separator_if_needed(normal);
+
+ break;
+ }
+
+ // Skip directory separators, including duplicates
+ while (i < pathname_size && detail::is_directory_separator(pathname[i]))
+ ++i;
+
+ if (i == pathname_size)
+ {
+ // If a path ends with a separator, add a trailing separator
+ if (!normal.empty() && !normal.filename_is_dot_dot())
+ path_algorithms::append_separator_if_needed(normal);
+ break;
+ }
+ }
+
+ // If the original path was not empty and normalized ended up being empty, make it a dot
+ if (normal.empty())
+ normal.m_pathname.push_back(path::dot);
+ }
+
+ return normal;
+}
+
+// generic_path ---------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL path path_algorithms::generic_path_v3(path const& p)
+{
+ path tmp;
+ const size_type pathname_size = p.m_pathname.size();
+ tmp.m_pathname.reserve(pathname_size);
+
+ const value_type* const pathname = p.m_pathname.c_str();
+
+ // Don't remove duplicate slashes from the root name
+ size_type root_name_size = 0u;
+ size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size);
+ if (root_name_size > 0u)
+ {
+ tmp.m_pathname.append(pathname, root_name_size);
+#if defined(BOOST_WINDOWS_API)
+ std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/');
+#endif
+ }
+
+ size_type pos = root_name_size;
+ if (root_dir_pos < pathname_size)
+ {
+ tmp.m_pathname.push_back(path::separator);
+ pos = root_dir_pos + 1u;
+ }
+
+ while (pos < pathname_size)
+ {
+ size_type element_size = find_separator(pathname + pos, pathname_size - pos);
+ if (element_size > 0u)
+ {
+ tmp.m_pathname.append(pathname + pos, element_size);
+
+ pos += element_size;
+ if (pos >= pathname_size)
+ break;
+
+ tmp.m_pathname.push_back(path::separator);
+ }
+
+ ++pos;
+ }
+
+ return tmp;
+}
+
+BOOST_FILESYSTEM_DECL path path_algorithms::generic_path_v4(path const& p)
+{
+ path tmp;
+ const size_type pathname_size = p.m_pathname.size();
+ tmp.m_pathname.reserve(pathname_size);
+
+ const value_type* const pathname = p.m_pathname.c_str();
+
+ // Treat root name specially as it may contain backslashes, duplicate ones too,
+ // in case of UNC paths and Windows-specific prefixes.
+ size_type root_name_size = 0u;
+ size_type root_dir_pos = find_root_directory_start(pathname, pathname_size, root_name_size);
+ if (root_name_size > 0u)
+ tmp.m_pathname.append(pathname, root_name_size);
+
+ size_type pos = root_name_size;
+ if (root_dir_pos < pathname_size)
+ {
+ tmp.m_pathname.push_back(path::separator);
+ pos = root_dir_pos + 1u;
+ }
+
+ while (pos < pathname_size)
+ {
+ size_type element_size = find_separator(pathname + pos, pathname_size - pos);
+ if (element_size > 0u)
+ {
+ tmp.m_pathname.append(pathname + pos, element_size);
+
+ pos += element_size;
+ if (pos >= pathname_size)
+ break;
+
+ tmp.m_pathname.push_back(path::separator);
+ }
+
+ ++pos;
+ }
+
+ return tmp;
+}
+
+#if defined(BOOST_WINDOWS_API)
+
+// make_preferred -------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL void path_algorithms::make_preferred_v3(path& p)
+{
+ std::replace(p.m_pathname.begin(), p.m_pathname.end(), L'/', L'\\');
+}
+
+BOOST_FILESYSTEM_DECL void path_algorithms::make_preferred_v4(path& p)
+{
+ const size_type pathname_size = p.m_pathname.size();
+ if (pathname_size > 0u)
+ {
+ value_type* const pathname = &p.m_pathname[0];
+
+ // Avoid converting slashes in the root name
+ size_type root_name_size = 0u;
+ find_root_directory_start(pathname, pathname_size, root_name_size);
+
+ std::replace(pathname + root_name_size, pathname + pathname_size, L'/', L'\\');
+ }
+}
+
+#endif // defined(BOOST_WINDOWS_API)
+
+// append --------------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL void path_algorithms::append_v3(path& p, const value_type* begin, const value_type* end)
+{
+ if (begin != end)
+ {
+ if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size())))
+ {
+ if (!detail::is_directory_separator(*begin))
+ path_algorithms::append_separator_if_needed(p);
+ p.m_pathname.append(begin, end);
+ }
+ else
+ {
+ // overlapping source
+ string_type rhs(begin, end);
+ path_algorithms::append_v3(p, rhs.data(), rhs.data() + rhs.size());
+ }
+ }
+}
+
+BOOST_FILESYSTEM_DECL void path_algorithms::append_v4(path& p, const value_type* begin, const value_type* end)
+{
+ if (begin != end)
+ {
+ if (BOOST_LIKELY(begin < p.m_pathname.data() || begin >= (p.m_pathname.data() + p.m_pathname.size())))
+ {
+ const size_type that_size = end - begin;
+ size_type that_root_name_size = 0;
+ size_type that_root_dir_pos = find_root_directory_start(begin, that_size, that_root_name_size);
+
+ // if (p.is_absolute())
+ if
+ (
+#if defined(BOOST_WINDOWS_API)
+ that_root_name_size > 0 &&
+#endif
+ that_root_dir_pos < that_size
+ )
+ {
+ return_assign:
+ p.assign(begin, end);
+ return;
+ }
+
+ size_type this_root_name_size = 0;
+ find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), this_root_name_size);
+
+ if
+ (
+ that_root_name_size > 0 &&
+ (that_root_name_size != this_root_name_size || std::memcmp(p.m_pathname.c_str(), begin, this_root_name_size * sizeof(value_type)) != 0)
+ )
+ {
+ goto return_assign;
+ }
+
+ if (that_root_dir_pos < that_size)
+ {
+ // Remove root directory (if any) and relative path to replace with those from p
+ p.m_pathname.erase(p.m_pathname.begin() + this_root_name_size, p.m_pathname.end());
+ }
+
+ const value_type* const that_path = begin + that_root_name_size;
+ if (!detail::is_directory_separator(*that_path))
+ path_algorithms::append_separator_if_needed(p);
+ p.m_pathname.append(that_path, end);
+ }
+ else
+ {
+ // overlapping source
+ string_type rhs(begin, end);
+ path_algorithms::append_v4(p, rhs.data(), rhs.data() + rhs.size());
+ }
+ }
+ else if (path_algorithms::has_filename_v4(p))
+ {
+ p.m_pathname.push_back(path::preferred_separator);
+ }
+}
+
+// compare -------------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v3
+(
+ path_detail::path_iterator first1, path_detail::path_iterator const& last1,
+ path_detail::path_iterator first2, path_detail::path_iterator const& last2
+)
+{
+ for (; first1 != last1 && first2 != last2;)
+ {
+ if (first1->native() < first2->native())
+ return -1;
+ if (first2->native() < first1->native())
+ return 1;
+ BOOST_ASSERT(first2->native() == first1->native());
+ path_algorithms::increment_v3(first1);
+ path_algorithms::increment_v3(first2);
+ }
+ if (first1 == last1 && first2 == last2)
+ return 0;
+ return first1 == last1 ? -1 : 1;
+}
+
+BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v4
+(
+ path_detail::path_iterator first1, path_detail::path_iterator const& last1,
+ path_detail::path_iterator first2, path_detail::path_iterator const& last2
+)
+{
+ for (; first1 != last1 && first2 != last2;)
+ {
+ if (first1->native() < first2->native())
+ return -1;
+ if (first2->native() < first1->native())
+ return 1;
+ BOOST_ASSERT(first2->native() == first1->native());
+ path_algorithms::increment_v4(first1);
+ path_algorithms::increment_v4(first2);
+ }
+ if (first1 == last1 && first2 == last2)
+ return 0;
+ return first1 == last1 ? -1 : 1;
+}
+
+BOOST_FILESYSTEM_DECL int path_algorithms::compare_v3(path const& left, path const& right)
+{
+ return path_algorithms::lex_compare_v3(left.begin(), left.end(), right.begin(), right.end());
+}
+
+BOOST_FILESYSTEM_DECL int path_algorithms::compare_v4(path const& left, path const& right)
+{
+ return path_algorithms::lex_compare_v4(left.begin(), left.end(), right.begin(), right.end());
+}
+
+// append_separator_if_needed ------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::append_separator_if_needed(path& p)
+{
+ if (!p.m_pathname.empty() &&
+#ifdef BOOST_WINDOWS_API
+ *(p.m_pathname.end() - 1) != colon &&
+#endif
+ !detail::is_directory_separator(*(p.m_pathname.end() - 1)))
+ {
+ string_type::size_type tmp(p.m_pathname.size());
+ p.m_pathname.push_back(path::preferred_separator);
+ return tmp;
+ }
+ return 0;
+}
+
+// erase_redundant_separator -------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL void path_algorithms::erase_redundant_separator(path& p, string_type::size_type sep_pos)
+{
+ if (sep_pos // a separator was added
+ && sep_pos < p.m_pathname.size() // and something was appended
+ && (p.m_pathname[sep_pos + 1] == path::separator // and it was also separator
+#ifdef BOOST_WINDOWS_API
+ || p.m_pathname[sep_pos + 1] == path::preferred_separator // or preferred_separator
+#endif
+ ))
+ {
+ p.m_pathname.erase(p.m_pathname.begin() + sep_pos); // erase the added separator
+ }
+}
+
+// modifiers -----------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v3(path& p)
+{
+ p.remove_filename_and_trailing_separators();
+}
+
+BOOST_FILESYSTEM_DECL void path_algorithms::remove_filename_v4(path& p)
+{
+ size_type filename_size = path_algorithms::find_filename_v4_size(p);
+ p.m_pathname.erase(p.m_pathname.begin() + (p.m_pathname.size() - filename_size), p.m_pathname.end());
+}
+
+BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v3(path& p, path const& new_extension)
+{
+ // erase existing extension, including the dot, if any
+ size_type ext_pos = p.m_pathname.size() - path_algorithms::extension_v3(p).m_pathname.size();
+ p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end());
+
+ if (!new_extension.empty())
+ {
+ // append new_extension, adding the dot if necessary
+ if (new_extension.m_pathname[0] != path::dot)
+ p.m_pathname.push_back(path::dot);
+ p.m_pathname.append(new_extension.m_pathname);
+ }
+}
+
+BOOST_FILESYSTEM_DECL void path_algorithms::replace_extension_v4(path& p, path const& new_extension)
+{
+ // erase existing extension, including the dot, if any
+ size_type ext_pos = p.m_pathname.size() - path_algorithms::find_extension_v4_size(p);
+ p.m_pathname.erase(p.m_pathname.begin() + ext_pos, p.m_pathname.end());
+
+ if (!new_extension.empty())
+ {
+ // append new_extension, adding the dot if necessary
+ if (new_extension.m_pathname[0] != path::dot)
+ p.m_pathname.push_back(path::dot);
+ p.m_pathname.append(new_extension.m_pathname);
+ }
+}
+
+// decomposition -------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_name_size(path const& p)
+{
+ size_type root_name_size = 0;
+ find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size);
+ return root_name_size;
+}
+
+BOOST_FILESYSTEM_DECL size_type path_algorithms::find_root_path_size(path const& p)
+{
+ size_type root_name_size = 0;
+ size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size);
+
+ size_type size = root_name_size;
+ if (root_dir_pos < p.m_pathname.size())
+ size = root_dir_pos + 1;
+
+ return size;
+}
+
+BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_root_directory(path const& p)
+{
+ substring root_dir;
+ size_type root_name_size = 0;
+ root_dir.pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size);
+ root_dir.size = static_cast< std::size_t >(root_dir.pos < p.m_pathname.size());
+ return root_dir;
+}
+
+BOOST_FILESYSTEM_DECL path_algorithms::substring path_algorithms::find_relative_path(path const& p)
+{
+ size_type root_name_size = 0;
+ size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), p.m_pathname.size(), root_name_size);
+
+ // Skip root name, root directory and any duplicate separators
+ size_type size = root_name_size;
+ if (root_dir_pos < p.m_pathname.size())
+ {
+ size = root_dir_pos + 1;
+
+ for (size_type n = p.m_pathname.size(); size < n; ++size)
+ {
+ if (!detail::is_directory_separator(p.m_pathname[size]))
+ break;
+ }
+ }
+
+ substring rel_path;
+ rel_path.pos = size;
+ rel_path.size = p.m_pathname.size() - size;
+
+ return rel_path;
+}
+
+BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_parent_path_size(path const& p)
+{
+ const size_type size = p.m_pathname.size();
+ size_type root_name_size = 0;
+ size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size);
+
+ size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size);
+ size_type end_pos = size - filename_size;
+ while (true)
+ {
+ if (end_pos <= root_name_size)
+ {
+ // Keep the root name as the parent path if there was a filename
+ if (filename_size == 0)
+ end_pos = 0u;
+ break;
+ }
+
+ --end_pos;
+
+ if (!detail::is_directory_separator(p.m_pathname[end_pos]))
+ {
+ ++end_pos;
+ break;
+ }
+
+ if (end_pos == root_dir_pos)
+ {
+ // Keep the trailing root directory if there was a filename
+ end_pos += filename_size > 0;
+ break;
+ }
+ }
+
+ return end_pos;
+}
+
+BOOST_FILESYSTEM_DECL path path_algorithms::filename_v3(path const& p)
+{
+ const size_type size = p.m_pathname.size();
+ size_type root_name_size = 0;
+ size_type root_dir_pos = find_root_directory_start(p.m_pathname.c_str(), size, root_name_size);
+ size_type filename_size, pos;
+ if (root_dir_pos < size && detail::is_directory_separator(p.m_pathname[size - 1]) && is_root_separator(p.m_pathname, root_dir_pos, size - 1))
+ {
+ // Return root directory
+ pos = root_dir_pos;
+ filename_size = 1u;
+ }
+ else if (root_name_size == size)
+ {
+ // Return root name
+ pos = 0u;
+ filename_size = root_name_size;
+ }
+ else
+ {
+ filename_size = find_filename_size(p.m_pathname, root_name_size, size);
+ pos = size - filename_size;
+ if (filename_size == 0u && pos > root_name_size && detail::is_directory_separator(p.m_pathname[pos - 1]) && !is_root_separator(p.m_pathname, root_dir_pos, pos - 1))
+ return detail::dot_path();
+ }
+
+ const value_type* ptr = p.m_pathname.c_str() + pos;
+ return path(ptr, ptr + filename_size);
+}
+
+BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_filename_v4_size(path const& p)
+{
+ const size_type size = p.m_pathname.size();
+ size_type root_name_size = 0;
+ find_root_directory_start(p.m_pathname.c_str(), size, root_name_size);
+ return find_filename_size(p.m_pathname, root_name_size, size);
+}
+
+BOOST_FILESYSTEM_DECL path path_algorithms::stem_v3(path const& p)
+{
+ path name(path_algorithms::filename_v3(p));
+ if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0)
+ {
+ size_type pos = name.m_pathname.rfind(path::dot);
+ if (pos != string_type::npos)
+ name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end());
+ }
+ return name;
+}
+
+BOOST_FILESYSTEM_DECL path path_algorithms::stem_v4(path const& p)
+{
+ path name(path_algorithms::filename_v4(p));
+ if (path_algorithms::compare_v4(name, detail::dot_path()) != 0 && path_algorithms::compare_v4(name, detail::dot_dot_path()) != 0)
+ {
+ size_type pos = name.m_pathname.rfind(path::dot);
+ if (pos != 0 && pos != string_type::npos)
+ name.m_pathname.erase(name.m_pathname.begin() + pos, name.m_pathname.end());
+ }
+ return name;
+}
+
+BOOST_FILESYSTEM_DECL path path_algorithms::extension_v3(path const& p)
+{
+ path name(path_algorithms::filename_v3(p));
+ if (path_algorithms::compare_v4(name, detail::dot_path()) == 0 || path_algorithms::compare_v4(name, detail::dot_dot_path()) == 0)
+ return path();
+ size_type pos(name.m_pathname.rfind(path::dot));
+ return pos == string_type::npos ? path() : path(name.m_pathname.c_str() + pos);
+}
+
+BOOST_FILESYSTEM_DECL path_algorithms::string_type::size_type path_algorithms::find_extension_v4_size(path const& p)
+{
+ const size_type size = p.m_pathname.size();
+ size_type root_name_size = 0;
+ find_root_directory_start(p.m_pathname.c_str(), size, root_name_size);
+ size_type filename_size = find_filename_size(p.m_pathname, root_name_size, size);
+ size_type filename_pos = size - filename_size;
+ if
+ (
+ filename_size > 0u &&
+ // Check for "." and ".." filenames
+ !(p.m_pathname[filename_pos] == path::dot &&
+ (filename_size == 1u || (filename_size == 2u && p.m_pathname[filename_pos + 1u] == path::dot)))
+ )
+ {
+ size_type ext_pos = size;
+ while (ext_pos > filename_pos)
+ {
+ --ext_pos;
+ if (p.m_pathname[ext_pos] == path::dot)
+ break;
+ }
+
+ if (ext_pos > filename_pos)
+ return size - ext_pos;
+ }
+
+ return 0u;
+}
+
+} // namespace detail
+
+BOOST_FILESYSTEM_DECL path& path::remove_filename_and_trailing_separators()
+{
+ size_type end_pos = detail::path_algorithms::find_parent_path_size(*this);
+ m_pathname.erase(m_pathname.begin() + end_pos, m_pathname.end());
+ return *this;
+}
+
+BOOST_FILESYSTEM_DECL path& path::remove_trailing_separator()
+{
+ if (!m_pathname.empty() && detail::is_directory_separator(m_pathname[m_pathname.size() - 1]))
+ m_pathname.erase(m_pathname.end() - 1);
+ return *this;
+}
+
+BOOST_FILESYSTEM_DECL path& path::replace_filename(path const& replacement)
+{
+ detail::path_algorithms::remove_filename_v4(*this);
+ detail::path_algorithms::append_v4(*this, replacement.m_pathname.data(), replacement.m_pathname.data() + replacement.m_pathname.size());
+ return *this;
+}
+
+// lexical operations --------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL path path::lexically_relative(path const& base) const
+{
+ path::iterator b = begin(), e = end(), base_b = base.begin(), base_e = base.end();
+ std::pair< path::iterator, path::iterator > mm = detail::mismatch(b, e, base_b, base_e);
+ if (mm.first == b && mm.second == base_b)
+ return path();
+ if (mm.first == e && mm.second == base_e)
+ return detail::dot_path();
+
+ std::ptrdiff_t n = 0;
+ for (; mm.second != base_e; detail::path_algorithms::increment_v4(mm.second))
+ {
+ path const& p = *mm.second;
+ if (detail::path_algorithms::compare_v4(p, detail::dot_dot_path()) == 0)
+ --n;
+ else if (!p.empty() && detail::path_algorithms::compare_v4(p, detail::dot_path()) != 0)
+ ++n;
+ }
+ if (n < 0)
+ return path();
+ if (n == 0 && (mm.first == e || mm.first->empty()))
+ return detail::dot_path();
+
+ path tmp;
+ for (; n > 0; --n)
+ detail::path_algorithms::append_v4(tmp, detail::dot_dot_path());
+ for (; mm.first != e; detail::path_algorithms::increment_v4(mm.first))
+ detail::path_algorithms::append_v4(tmp, *mm.first);
+ return tmp;
+}
+
+} // namespace filesystem
+} // namespace boost
+
+//--------------------------------------------------------------------------------------//
+// //
+// class path helpers implementation //
+// //
+//--------------------------------------------------------------------------------------//
+
+namespace {
+
+// is_root_separator ---------------------------------------------------------------//
+
+// pos is position of the separator
+inline bool is_root_separator(string_type const& str, size_type root_dir_pos, size_type pos)
+{
+ BOOST_ASSERT_MSG(pos < str.size() && fs::detail::is_directory_separator(str[pos]), "precondition violation");
+
+ // root_dir_pos points at the leftmost separator, we need to skip any duplicate separators right of root dir
+ while (pos > root_dir_pos && fs::detail::is_directory_separator(str[pos - 1]))
+ --pos;
+
+ return pos == root_dir_pos;
+}
+
+// find_filename_size --------------------------------------------------------------//
+
+// Returns: Size of the filename element that ends at end_pos (which is past-the-end position). 0 if no filename found.
+inline size_type find_filename_size(string_type const& str, size_type root_name_size, size_type end_pos)
+{
+ size_type pos = end_pos;
+ while (pos > root_name_size)
+ {
+ --pos;
+
+ if (fs::detail::is_directory_separator(str[pos]))
+ {
+ ++pos; // filename starts past the separator
+ break;
+ }
+ }
+
+ return end_pos - pos;
+}
+
+// find_root_directory_start -------------------------------------------------------//
+
+// Returns: starting position of root directory or size if not found
+size_type find_root_directory_start(const value_type* path, size_type size, size_type& root_name_size)
+{
+ root_name_size = 0;
+ if (size == 0)
+ return 0;
+
+ bool parsing_root_name = false;
+ size_type pos = 0;
+
+ // case "//", possibly followed by more characters
+ if (fs::detail::is_directory_separator(path[0]))
+ {
+ if (size >= 2 && fs::detail::is_directory_separator(path[1]))
+ {
+ if (size == 2)
+ {
+ // The whole path is just a pair of separators
+ root_name_size = 2;
+ return 2;
+ }
+#ifdef BOOST_WINDOWS_API
+ // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
+ // cases "\\?\" and "\\.\"
+ else if (size >= 4 && (path[2] == questionmark || path[2] == fs::path::dot) && fs::detail::is_directory_separator(path[3]))
+ {
+ parsing_root_name = true;
+ pos += 4;
+ }
+#endif
+ else if (fs::detail::is_directory_separator(path[2]))
+ {
+ // The path starts with three directory separators, which is interpreted as a root directory followed by redundant separators
+ return 0;
+ }
+ else
+ {
+ // case "//net {/}"
+ parsing_root_name = true;
+ pos += 2;
+ goto find_next_separator;
+ }
+ }
+#ifdef BOOST_WINDOWS_API
+ // https://stackoverflow.com/questions/23041983/path-prefixes-and
+ // case "\??\" (NT path prefix)
+ else if (size >= 4 && path[1] == questionmark && path[2] == questionmark && fs::detail::is_directory_separator(path[3]))
+ {
+ parsing_root_name = true;
+ pos += 4;
+ }
+#endif
+ else
+ {
+ // The path starts with a separator, possibly followed by a non-separator character
+ return 0;
+ }
+ }
+
+#ifdef BOOST_WINDOWS_API
+ // case "c:" or "prn:"
+ // Note: There is ambiguity in a "c:x" path interpretation. It could either mean a file "x" located at the current directory for drive C:,
+ // or an alternative stream "x" of a file "c". Windows API resolve this as the former, and so do we.
+ if ((size - pos) >= 2 && fs::detail::is_letter(path[pos]))
+ {
+ size_type i = pos + 1;
+ for (; i < size; ++i)
+ {
+ if (!is_device_name_char(path[i]))
+ break;
+ }
+
+ if (i < size && path[i] == colon)
+ {
+ pos = i + 1;
+ root_name_size = pos;
+ parsing_root_name = false;
+
+ if (pos < size && fs::detail::is_directory_separator(path[pos]))
+ return pos;
+ }
+ }
+#endif
+
+ if (!parsing_root_name)
+ return size;
+
+find_next_separator:
+ pos += find_separator(path + pos, size - pos);
+ if (parsing_root_name)
+ root_name_size = pos;
+
+ return pos;
+}
+
+//--------------------------------------------------------------------------------------//
+// //
+// class path::iterator implementation //
+// //
+//--------------------------------------------------------------------------------------//
+
+// first_element ----------------------------------------------------------------------//
+
+// sets pos and len of first element, excluding extra separators
+// if src.empty(), sets pos,len, to 0,0.
+void first_element(string_type const& src, size_type& element_pos, size_type& element_size, size_type size)
+{
+ element_pos = 0;
+ element_size = 0;
+ if (src.empty())
+ return;
+
+ size_type root_name_size = 0;
+ size_type root_dir_pos = find_root_directory_start(src.c_str(), size, root_name_size);
+
+ // First element is the root name, if there is one
+ if (root_name_size > 0)
+ {
+ element_size = root_name_size;
+ return;
+ }
+
+ // Otherwise, the root directory
+ if (root_dir_pos < size)
+ {
+ element_pos = root_dir_pos;
+ element_size = 1u;
+ return;
+ }
+
+ // Otherwise, the first filename or directory name in a relative path
+ size_type end_pos = src.find_first_of(separators);
+ if (end_pos == string_type::npos)
+ end_pos = src.size();
+ element_size = end_pos;
+}
+
+} // unnamed namespace
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+BOOST_FILESYSTEM_DECL void path_algorithms::increment_v3(path_detail::path_iterator& it)
+{
+ const size_type size = it.m_path_ptr->m_pathname.size();
+ BOOST_ASSERT_MSG(it.m_pos < size, "path::iterator increment past end()");
+
+ // increment to position past current element; if current element is implicit dot,
+ // this will cause m_pos to represent the end iterator
+ it.m_pos += it.m_element.m_pathname.size();
+
+ // if the end is reached, we are done
+ if (it.m_pos >= size)
+ {
+ BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified");
+ it.m_element.clear(); // aids debugging
+ return;
+ }
+
+ // process separator (Windows drive spec is only case not a separator)
+ if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos]))
+ {
+ size_type root_name_size = 0;
+ size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size);
+
+ // detect root directory and set iterator value to the separator if it is
+ if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size)
+ {
+ it.m_element.m_pathname = path::separator; // generic format; see docs
+ return;
+ }
+
+ // skip separators until m_pos points to the start of the next element
+ while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos]))
+ {
+ ++it.m_pos;
+ }
+
+ // detect trailing separator, and treat it as ".", per POSIX spec
+ if (it.m_pos == size &&
+ !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1))
+ {
+ --it.m_pos;
+ it.m_element = detail::dot_path();
+ return;
+ }
+ }
+
+ // get m_element
+ size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos);
+ if (end_pos == string_type::npos)
+ end_pos = size;
+ const path::value_type* p = it.m_path_ptr->m_pathname.c_str();
+ it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos);
+}
+
+BOOST_FILESYSTEM_DECL void path_algorithms::increment_v4(path_detail::path_iterator& it)
+{
+ const size_type size = it.m_path_ptr->m_pathname.size();
+ BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator increment past end()");
+
+ if (it.m_element.m_pathname.empty() && (it.m_pos + 1) == size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos]))
+ {
+ // The iterator was pointing to the last empty element of the path; set to end.
+ it.m_pos = size;
+ return;
+ }
+
+ // increment to position past current element; if current element is implicit dot,
+ // this will cause m_pos to represent the end iterator
+ it.m_pos += it.m_element.m_pathname.size();
+
+ // if the end is reached, we are done
+ if (it.m_pos >= size)
+ {
+ BOOST_ASSERT_MSG(it.m_pos == size, "path::iterator increment after the referenced path was modified");
+ it.m_element.clear(); // aids debugging
+ return;
+ }
+
+ // process separator (Windows drive spec is only case not a separator)
+ if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos]))
+ {
+ size_type root_name_size = 0;
+ size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size);
+
+ // detect root directory and set iterator value to the separator if it is
+ if (it.m_pos == root_dir_pos && it.m_element.m_pathname.size() == root_name_size)
+ {
+ it.m_element.m_pathname = path::separator; // generic format; see docs
+ return;
+ }
+
+ // skip separators until m_pos points to the start of the next element
+ while (it.m_pos != size && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos]))
+ {
+ ++it.m_pos;
+ }
+
+ // detect trailing separator
+ if (it.m_pos == size &&
+ !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1))
+ {
+ --it.m_pos;
+ it.m_element.m_pathname.clear();
+ return;
+ }
+ }
+
+ // get m_element
+ size_type end_pos = it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos);
+ if (end_pos == string_type::npos)
+ end_pos = size;
+ const path::value_type* p = it.m_path_ptr->m_pathname.c_str();
+ it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos);
+}
+
+BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v3(path_detail::path_iterator& it)
+{
+ const size_type size = it.m_path_ptr->m_pathname.size();
+ BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()");
+ BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified");
+
+ size_type root_name_size = 0;
+ size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size);
+
+ if (root_dir_pos < size && it.m_pos == root_dir_pos)
+ {
+ // Was pointing at root directory, decrement to root name
+ set_to_root_name:
+ it.m_pos = 0u;
+ const path::value_type* p = it.m_path_ptr->m_pathname.c_str();
+ it.m_element.m_pathname.assign(p, p + root_name_size);
+ return;
+ }
+
+ // if at end and there was a trailing non-root '/', return "."
+ if (it.m_pos == size &&
+ size > 1 &&
+ detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) &&
+ !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1))
+ {
+ --it.m_pos;
+ it.m_element = detail::dot_path();
+ return;
+ }
+
+ // skip separators unless root directory
+ size_type end_pos = it.m_pos;
+ while (end_pos > root_name_size)
+ {
+ --end_pos;
+
+ if (end_pos == root_dir_pos)
+ {
+ // Decremented to the root directory
+ it.m_pos = end_pos;
+ it.m_element.m_pathname = path::separator; // generic format; see docs
+ return;
+ }
+
+ if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos]))
+ {
+ ++end_pos;
+ break;
+ }
+ }
+
+ if (end_pos <= root_name_size)
+ goto set_to_root_name;
+
+ size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos);
+ it.m_pos = end_pos - filename_size;
+ const path::value_type* p = it.m_path_ptr->m_pathname.c_str();
+ it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos);
+}
+
+BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v4(path_detail::path_iterator& it)
+{
+ const size_type size = it.m_path_ptr->m_pathname.size();
+ BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()");
+ BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator decrement after the referenced path was modified");
+
+ size_type root_name_size = 0;
+ size_type root_dir_pos = find_root_directory_start(it.m_path_ptr->m_pathname.c_str(), size, root_name_size);
+
+ if (root_dir_pos < size && it.m_pos == root_dir_pos)
+ {
+ // Was pointing at root directory, decrement to root name
+ set_to_root_name:
+ it.m_pos = 0u;
+ const path::value_type* p = it.m_path_ptr->m_pathname.c_str();
+ it.m_element.m_pathname.assign(p, p + root_name_size);
+ return;
+ }
+
+ // if at end and there was a trailing '/', return ""
+ if (it.m_pos == size &&
+ size > 1 &&
+ detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos - 1]) &&
+ !is_root_separator(it.m_path_ptr->m_pathname, root_dir_pos, it.m_pos - 1))
+ {
+ --it.m_pos;
+ it.m_element.m_pathname.clear();
+ return;
+ }
+
+ // skip separators unless root directory
+ size_type end_pos = it.m_pos;
+ while (end_pos > root_name_size)
+ {
+ --end_pos;
+
+ if (end_pos == root_dir_pos)
+ {
+ // Decremented to the root directory
+ it.m_pos = end_pos;
+ it.m_element.m_pathname = path::separator; // generic format; see docs
+ return;
+ }
+
+ if (!detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos]))
+ {
+ ++end_pos;
+ break;
+ }
+ }
+
+ if (end_pos <= root_name_size)
+ goto set_to_root_name;
+
+ size_type filename_size = find_filename_size(it.m_path_ptr->m_pathname, root_name_size, end_pos);
+ it.m_pos = end_pos - filename_size;
+ const path::value_type* p = it.m_path_ptr->m_pathname.c_str();
+ it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos);
+}
+
+} // namespace detail
+
+// path iterators ------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL path::iterator path::begin() const
+{
+ iterator itr;
+ itr.m_path_ptr = this;
+
+ size_type element_size;
+ first_element(m_pathname, itr.m_pos, element_size);
+
+ if (element_size > 0)
+ {
+ itr.m_element = m_pathname.substr(itr.m_pos, element_size);
+#ifdef BOOST_WINDOWS_API
+ if (itr.m_element.m_pathname.size() == 1u && itr.m_element.m_pathname[0] == path::preferred_separator)
+ itr.m_element.m_pathname[0] = path::separator;
+#endif
+ }
+
+ return itr;
+}
+
+BOOST_FILESYSTEM_DECL path::iterator path::end() const
+{
+ iterator itr;
+ itr.m_path_ptr = this;
+ itr.m_pos = m_pathname.size();
+ return itr;
+}
+
+} // namespace filesystem
+} // namespace boost
+
+namespace {
+
+//------------------------------------------------------------------------------------//
+// locale helpers //
+//------------------------------------------------------------------------------------//
+
+// Prior versions of these locale and codecvt implementations tried to take advantage
+// of static initialization where possible, kept a local copy of the current codecvt
+// facet (to avoid codecvt() having to call use_facet()), and was not multi-threading
+// safe (again for efficiency).
+//
+// This was error prone, and required different implementation techniques depending
+// on the compiler and also whether static or dynamic linking was used. Furthermore,
+// users could not easily provide their multi-threading safe wrappers because the
+// path interface requires the implementation itself to call codecvt() to obtain the
+// default facet, and the initialization of the static within path_locale() could race.
+//
+// The code below is portable to all platforms, is much simpler, and hopefully will be
+// much more robust. Timing tests (on Windows, using a Visual C++ release build)
+// indicated the current code is roughly 9% slower than the previous code, and that
+// seems a small price to pay for better code that is easier to use.
+
+std::locale default_locale()
+{
+#if defined(BOOST_WINDOWS_API)
+ std::locale global_loc = std::locale();
+ return std::locale(global_loc, new boost::filesystem::detail::windows_file_codecvt());
+#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
+ // "All BSD system functions expect their string parameters to be in UTF-8 encoding
+ // and nothing else." See
+ // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html
+ //
+ // "The kernel will reject any filename that is not a valid UTF-8 string, and it will
+ // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS.
+ // The right way to deal with it would be to always convert the filename to UTF-8
+ // before trying to open/create a file." See
+ // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html
+ //
+ // "How a file name looks at the API level depends on the API. Current Carbon APIs
+ // handle file names as an array of UTF-16 characters; POSIX ones handle them as an
+ // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk
+ // depends on the disk format; HFS+ uses UTF-16, but that's not important in most
+ // cases." See
+ // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html
+ //
+ // Many thanks to Peter Dimov for digging out the above references!
+
+ std::locale global_loc = std::locale();
+ return std::locale(global_loc, new boost::filesystem::detail::utf8_codecvt_facet());
+#else // Other POSIX
+ // ISO C calls std::locale("") "the locale-specific native environment", and this
+ // locale is the default for many POSIX-based operating systems such as Linux.
+ return std::locale("");
+#endif
+}
+
+std::locale* g_path_locale = nullptr;
+
+void schedule_path_locale_cleanup() noexcept;
+
+// std::locale("") construction, needed on non-Apple POSIX systems, can throw
+// (if environmental variables LC_MESSAGES or LANG are wrong, for example), so
+// get_path_locale() provides lazy initialization to ensure that any
+// exceptions occur after main() starts and so can be caught. Furthermore,
+// g_path_locale is only initialized if path::codecvt() or path::imbue() are themselves
+// actually called, ensuring that an exception will only be thrown if std::locale("")
+// is really needed.
+inline std::locale& get_path_locale()
+{
+#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+ atomic_ns::atomic_ref< std::locale* > a(g_path_locale);
+ std::locale* p = a.load(atomic_ns::memory_order_acquire);
+ if (BOOST_UNLIKELY(!p))
+ {
+ std::locale* new_p = new std::locale(default_locale());
+ if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire))
+ {
+ p = new_p;
+ schedule_path_locale_cleanup();
+ }
+ else
+ {
+ delete new_p;
+ }
+ }
+ return *p;
+#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+ std::locale* p = g_path_locale;
+ if (BOOST_UNLIKELY(!p))
+ {
+ g_path_locale = p = new std::locale(default_locale());
+ schedule_path_locale_cleanup();
+ }
+ return *p;
+#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+}
+
+inline std::locale* replace_path_locale(std::locale const& loc)
+{
+ std::locale* new_p = new std::locale(loc);
+#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+ std::locale* p = atomic_ns::atomic_ref< std::locale* >(g_path_locale).exchange(new_p, atomic_ns::memory_order_acq_rel);
+#else
+ std::locale* p = g_path_locale;
+ g_path_locale = new_p;
+#endif
+ if (!p)
+ schedule_path_locale_cleanup();
+ return p;
+}
+
+#if defined(_MSC_VER)
+
+const boost::filesystem::path* g_dot_path = nullptr;
+const boost::filesystem::path* g_dot_dot_path = nullptr;
+
+inline void schedule_path_locale_cleanup() noexcept
+{
+}
+
+inline boost::filesystem::path const& get_dot_path()
+{
+#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+ atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_path);
+ const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire);
+ if (BOOST_UNLIKELY(!p))
+ {
+ const boost::filesystem::path* new_p = new boost::filesystem::path(dot_path_literal);
+ if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire))
+ p = new_p;
+ else
+ delete new_p;
+ }
+ return *p;
+#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+ const boost::filesystem::path* p = g_dot_path;
+ if (BOOST_UNLIKELY(!p))
+ g_dot_path = p = new boost::filesystem::path(dot_path_literal);
+ return *p;
+#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+}
+
+inline boost::filesystem::path const& get_dot_dot_path()
+{
+#if !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+ atomic_ns::atomic_ref< const boost::filesystem::path* > a(g_dot_dot_path);
+ const boost::filesystem::path* p = a.load(atomic_ns::memory_order_acquire);
+ if (BOOST_UNLIKELY(!p))
+ {
+ const boost::filesystem::path* new_p = new boost::filesystem::path(dot_dot_path_literal);
+ if (a.compare_exchange_strong(p, new_p, atomic_ns::memory_order_acq_rel, atomic_ns::memory_order_acquire))
+ p = new_p;
+ else
+ delete new_p;
+ }
+ return *p;
+#else // !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+ const boost::filesystem::path* p = g_dot_dot_path;
+ if (BOOST_UNLIKELY(!p))
+ g_dot_dot_path = p = new boost::filesystem::path(dot_dot_path_literal);
+ return *p;
+#endif // !defined(BOOST_FILESYSTEM_SINGLE_THREADED)
+}
+
+void __cdecl destroy_path_globals()
+{
+ delete g_dot_dot_path;
+ g_dot_dot_path = nullptr;
+ delete g_dot_path;
+ g_dot_path = nullptr;
+ delete g_path_locale;
+ g_path_locale = nullptr;
+}
+
+BOOST_FILESYSTEM_INIT_FUNC init_path_globals()
+{
+#if !defined(BOOST_SYSTEM_HAS_CONSTEXPR)
+ // codecvt_error_category needs to be called early to dynamic-initialize the error category instance
+ boost::filesystem::codecvt_error_category();
+#endif
+ std::atexit(&destroy_path_globals);
+ return BOOST_FILESYSTEM_INITRETSUCCESS_V;
+}
+
+#if _MSC_VER >= 1400
+
+#pragma section(".CRT$XCM", long, read)
+__declspec(allocate(".CRT$XCM")) BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN
+extern const init_func_ptr_t p_init_path_globals = &init_path_globals;
+
+#else // _MSC_VER >= 1400
+
+#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
+#pragma data_seg(push, old_seg)
+#endif
+#pragma data_seg(".CRT$XCM")
+BOOST_ATTRIBUTE_UNUSED BOOST_FILESYSTEM_ATTRIBUTE_RETAIN
+extern const init_func_ptr_t p_init_path_globals = &init_path_globals;
+#pragma data_seg()
+#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
+#pragma data_seg(pop, old_seg)
+#endif
+
+#endif // _MSC_VER >= 1400
+
+#if defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN)
+//! Makes sure the global initializer pointers are referenced and not removed by linker
+struct globals_retainer
+{
+ const init_func_ptr_t* volatile m_p_init_path_globals;
+
+ globals_retainer() { m_p_init_path_globals = &p_init_path_globals; }
+};
+BOOST_ATTRIBUTE_UNUSED
+static const globals_retainer g_globals_retainer;
+#endif // defined(BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN)
+
+#else // defined(_MSC_VER)
+
+struct path_locale_deleter
+{
+ ~path_locale_deleter()
+ {
+ delete g_path_locale;
+ g_path_locale = nullptr;
+ }
+};
+
+#if defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY)
+
+BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY) BOOST_ATTRIBUTE_UNUSED
+const path_locale_deleter g_path_locale_deleter = {};
+BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY)
+const boost::filesystem::path g_dot_path(dot_path_literal);
+BOOST_FILESYSTEM_INIT_PRIORITY(BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY)
+const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal);
+
+inline void schedule_path_locale_cleanup() noexcept
+{
+}
+
+inline boost::filesystem::path const& get_dot_path()
+{
+ return g_dot_path;
+}
+
+inline boost::filesystem::path const& get_dot_dot_path()
+{
+ return g_dot_dot_path;
+}
+
+#else // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY)
+
+inline void schedule_path_locale_cleanup() noexcept
+{
+ BOOST_ATTRIBUTE_UNUSED static const path_locale_deleter g_path_locale_deleter;
+}
+
+inline boost::filesystem::path const& get_dot_path()
+{
+ static const boost::filesystem::path g_dot_path(dot_path_literal);
+ return g_dot_path;
+}
+
+inline boost::filesystem::path const& get_dot_dot_path()
+{
+ static const boost::filesystem::path g_dot_dot_path(dot_dot_path_literal);
+ return g_dot_dot_path;
+}
+
+#endif // defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY)
+
+#endif // defined(_MSC_VER)
+
+} // unnamed namespace
+
+//--------------------------------------------------------------------------------------//
+// path::codecvt() and path::imbue() implementation //
+//--------------------------------------------------------------------------------------//
+
+namespace boost {
+namespace filesystem {
+
+BOOST_FILESYSTEM_DECL path::codecvt_type const& path::codecvt()
+{
+#ifdef BOOST_FILESYSTEM_DEBUG
+ std::cout << "***** path::codecvt() called" << std::endl;
+#endif
+ return std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(get_path_locale());
+}
+
+BOOST_FILESYSTEM_DECL std::locale path::imbue(std::locale const& loc)
+{
+#ifdef BOOST_FILESYSTEM_DEBUG
+ std::cout << "***** path::imbue() called" << std::endl;
+#endif
+ std::locale* p = replace_path_locale(loc);
+ if (BOOST_LIKELY(p != nullptr))
+ {
+ // Note: copying/moving std::locale does not throw
+ std::locale temp(std::move(*p));
+ delete p;
+ return temp;
+ }
+
+ return default_locale();
+}
+
+namespace detail {
+
+BOOST_FILESYSTEM_DECL path const& dot_path()
+{
+ return get_dot_path();
+}
+
+BOOST_FILESYSTEM_DECL path const& dot_dot_path()
+{
+ return get_dot_dot_path();
+}
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
diff --git a/contrib/restricted/boost/filesystem/src/path_traits.cpp b/contrib/restricted/boost/filesystem/src/path_traits.cpp
new file mode 100644
index 0000000000..9a68f25872
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/path_traits.cpp
@@ -0,0 +1,187 @@
+// filesystem path_traits.cpp --------------------------------------------------------//
+
+// Copyright Beman Dawes 2008, 2009
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#include "platform_config.hpp"
+
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/detail/path_traits.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/assert.hpp>
+#include <memory>
+#include <string>
+#include <locale> // for codecvt_base::result
+#include <cwchar> // for mbstate_t
+#include <cstddef>
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace pt = boost::filesystem::detail::path_traits;
+namespace fs = boost::filesystem;
+namespace bs = boost::system;
+
+//--------------------------------------------------------------------------------------//
+// configuration //
+//--------------------------------------------------------------------------------------//
+
+#ifndef BOOST_FILESYSTEM_CODECVT_BUF_SIZE
+#define BOOST_FILESYSTEM_CODECVT_BUF_SIZE 256
+#endif
+
+namespace {
+
+BOOST_CONSTEXPR_OR_CONST std::size_t default_codecvt_buf_size = BOOST_FILESYSTEM_CODECVT_BUF_SIZE;
+
+//--------------------------------------------------------------------------------------//
+// //
+// The public convert() functions do buffer management, and then forward to the //
+// convert_aux() functions for the actual call to the codecvt facet. //
+// //
+//--------------------------------------------------------------------------------------//
+
+//--------------------------------------------------------------------------------------//
+// convert_aux const char* to wstring //
+//--------------------------------------------------------------------------------------//
+
+void convert_aux(const char* from, const char* from_end, wchar_t* to, wchar_t* to_end, std::wstring& target, pt::codecvt_type const& cvt)
+{
+ //std::cout << std::hex
+ // << " from=" << std::size_t(from)
+ // << " from_end=" << std::size_t(from_end)
+ // << " to=" << std::size_t(to)
+ // << " to_end=" << std::size_t(to_end)
+ // << std::endl;
+
+ std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports
+ const char* from_next;
+ wchar_t* to_next;
+
+ std::codecvt_base::result res;
+
+ if ((res = cvt.in(state, from, from_end, from_next, to, to_end, to_next)) != std::codecvt_base::ok)
+ {
+ //std::cout << " result is " << static_cast<int>(res) << std::endl;
+ BOOST_FILESYSTEM_THROW(bs::system_error(res, fs::codecvt_error_category(), "boost::filesystem::path codecvt to wstring"));
+ }
+ target.append(to, to_next);
+}
+
+//--------------------------------------------------------------------------------------//
+// convert_aux const wchar_t* to string //
+//--------------------------------------------------------------------------------------//
+
+void convert_aux(const wchar_t* from, const wchar_t* from_end, char* to, char* to_end, std::string& target, pt::codecvt_type const& cvt)
+{
+ //std::cout << std::hex
+ // << " from=" << std::size_t(from)
+ // << " from_end=" << std::size_t(from_end)
+ // << " to=" << std::size_t(to)
+ // << " to_end=" << std::size_t(to_end)
+ // << std::endl;
+
+ std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports
+ const wchar_t* from_next;
+ char* to_next;
+
+ std::codecvt_base::result res;
+
+ if ((res = cvt.out(state, from, from_end, from_next, to, to_end, to_next)) != std::codecvt_base::ok)
+ {
+ //std::cout << " result is " << static_cast<int>(res) << std::endl;
+ BOOST_FILESYSTEM_THROW(bs::system_error(res, fs::codecvt_error_category(), "boost::filesystem::path codecvt to string"));
+ }
+ target.append(to, to_next);
+}
+
+} // unnamed namespace
+
+//--------------------------------------------------------------------------------------//
+// path_traits //
+//--------------------------------------------------------------------------------------//
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+namespace path_traits {
+
+//--------------------------------------------------------------------------------------//
+// convert const char* to wstring //
+//--------------------------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL
+void convert(const char* from, const char* from_end, std::wstring& to, const codecvt_type* cvt)
+{
+ if (from == from_end)
+ return;
+
+ BOOST_ASSERT(from != nullptr);
+ BOOST_ASSERT(from_end != nullptr);
+
+ if (!cvt)
+ cvt = &fs::path::codecvt();
+
+ std::size_t buf_size = (from_end - from) * 3; // perhaps too large, but that's OK
+
+ // dynamically allocate a buffer only if source is unusually large
+ if (buf_size > default_codecvt_buf_size)
+ {
+ std::unique_ptr< wchar_t[] > buf(new wchar_t[buf_size]);
+ convert_aux(from, from_end, buf.get(), buf.get() + buf_size, to, *cvt);
+ }
+ else
+ {
+ wchar_t buf[default_codecvt_buf_size];
+ convert_aux(from, from_end, buf, buf + default_codecvt_buf_size, to, *cvt);
+ }
+}
+
+//--------------------------------------------------------------------------------------//
+// convert const wchar_t* to string //
+//--------------------------------------------------------------------------------------//
+
+BOOST_FILESYSTEM_DECL
+void convert(const wchar_t* from, const wchar_t* from_end, std::string& to, const codecvt_type* cvt)
+{
+ if (from == from_end)
+ return;
+
+ BOOST_ASSERT(from != nullptr);
+ BOOST_ASSERT(from_end != nullptr);
+
+ if (!cvt)
+ cvt = &fs::path::codecvt();
+
+ // The codecvt length functions may not be implemented, and I don't really
+ // understand them either. Thus this code is just a guess; if it turns
+ // out the buffer is too small then an error will be reported and the code
+ // will have to be fixed.
+ std::size_t buf_size = (from_end - from) * 4; // perhaps too large, but that's OK
+ buf_size += 4; // encodings like shift-JIS need some prefix space
+
+ // dynamically allocate a buffer only if source is unusually large
+ if (buf_size > default_codecvt_buf_size)
+ {
+ std::unique_ptr< char[] > buf(new char[buf_size]);
+ convert_aux(from, from_end, buf.get(), buf.get() + buf_size, to, *cvt);
+ }
+ else
+ {
+ char buf[default_codecvt_buf_size];
+ convert_aux(from, from_end, buf, buf + default_codecvt_buf_size, to, *cvt);
+ }
+}
+
+} // namespace path_traits
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
diff --git a/contrib/restricted/boost/filesystem/src/platform_config.hpp b/contrib/restricted/boost/filesystem/src/platform_config.hpp
new file mode 100644
index 0000000000..941338b0a7
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/platform_config.hpp
@@ -0,0 +1,83 @@
+// platform_config.hpp --------------------------------------------------------------------//
+
+// Copyright 2020 Andrey Semashev
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// See library home page at http://www.boost.org/libs/filesystem
+
+#ifndef BOOST_FILESYSTEM_PLATFORM_CONFIG_HPP_
+#define BOOST_FILESYSTEM_PLATFORM_CONFIG_HPP_
+
+// define 64-bit offset macros BEFORE including boost/config.hpp (see ticket #5355)
+#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ < 24
+// Android fully supports 64-bit file offsets only for API 24 and above.
+//
+// Trying to define _FILE_OFFSET_BITS=64 for APIs below 24
+// leads to compilation failure for one or another reason,
+// depending on target Android API level, Android NDK version,
+// used STL, order of include paths and more.
+// For more information, please see:
+// - https://github.com/boostorg/filesystem/issues/65
+// - https://github.com/boostorg/filesystem/pull/69
+//
+// Android NDK developers consider it the expected behavior.
+// See their official position here:
+// - https://github.com/android-ndk/ndk/issues/501#issuecomment-326447479
+// - https://android.googlesource.com/platform/bionic/+/a34817457feee026e8702a1d2dffe9e92b51d7d1/docs/32-bit-abi.md#32_bit-abi-bugs
+//
+// Thus we do not define _FILE_OFFSET_BITS in such case.
+#else
+// Defining _FILE_OFFSET_BITS=64 should kick in 64-bit off_t's
+// (and thus st_size) on 32-bit systems that provide the Large File
+// Support (LFS) interface, such as Linux, Solaris, and IRIX.
+//
+// At the time of this comment writing (March 2018), on most systems
+// _FILE_OFFSET_BITS=64 definition is harmless:
+// either the definition is supported and enables 64-bit off_t,
+// or the definition is not supported and is ignored, in which case
+// off_t does not change its default size for the target system
+// (which may be 32-bit or 64-bit already).
+// Thus it makes sense to have _FILE_OFFSET_BITS=64 defined by default,
+// instead of listing every system that supports the definition.
+// Those few systems, on which _FILE_OFFSET_BITS=64 is harmful,
+// for example this definition causes compilation failure on those systems,
+// should be exempt from defining _FILE_OFFSET_BITS by adding
+// an appropriate #elif block above with the appropriate comment.
+//
+// _FILE_OFFSET_BITS must be defined before any headers are included
+// to ensure that the definition is available to all included headers.
+// That is required at least on Solaris, and possibly on other
+// systems as well.
+#define _FILE_OFFSET_BITS 64
+#endif
+
+#if defined(__APPLE__) || defined(__MACH__)
+// Enable newer ABI on Mac OS 10.5 and later, which is needed for struct stat to have birthtime members
+#define _DARWIN_USE_64_BIT_INODE 1
+#endif
+
+#ifndef _POSIX_PTHREAD_SEMANTICS
+#define _POSIX_PTHREAD_SEMANTICS // Sun readdir_r() needs this
+#endif
+
+#if !defined(_INCLUDE_STDCSOURCE_199901) && (defined(hpux) || defined(_hpux) || defined(__hpux))
+// For HP-UX, request that WCHAR_MAX and WCHAR_MIN be defined as macros,
+// not casts. See ticket 5048
+#define _INCLUDE_STDCSOURCE_199901
+#endif
+
+#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) || \
+ defined(__CYGWIN__)
+// Define target Windows version macros before including any other headers
+#include <boost/winapi/config.hpp>
+#endif
+
+#ifndef BOOST_SYSTEM_NO_DEPRECATED
+#define BOOST_SYSTEM_NO_DEPRECATED
+#endif
+
+#include <boost/filesystem/config.hpp>
+
+#endif // BOOST_FILESYSTEM_PLATFORM_CONFIG_HPP_
diff --git a/contrib/restricted/boost/filesystem/src/portability.cpp b/contrib/restricted/boost/filesystem/src/portability.cpp
new file mode 100644
index 0000000000..8e0e2e5d98
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/portability.cpp
@@ -0,0 +1,83 @@
+// portability.cpp -------------------------------------------------------------------//
+
+// Copyright 2002-2005 Beman Dawes
+// Use, modification, and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
+// at http://www.boost.org/LICENSE_1_0.txt)
+
+// See library home page at http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#include "platform_config.hpp"
+
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/path.hpp>
+
+#include <cstring> // SGI MIPSpro compilers need this
+#include <string>
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace boost {
+namespace filesystem {
+
+namespace {
+
+BOOST_CONSTEXPR_OR_CONST char windows_invalid_chars[] =
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
+ "<>:\"/\\|";
+
+BOOST_CONSTEXPR_OR_CONST char posix_valid_chars[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-";
+
+} // unnamed namespace
+
+// name_check functions ----------------------------------------------//
+
+#ifdef BOOST_WINDOWS
+BOOST_FILESYSTEM_DECL bool native(std::string const& name)
+{
+ return windows_name(name);
+}
+#else
+BOOST_FILESYSTEM_DECL bool native(std::string const& name)
+{
+ return !name.empty() && name[0] != ' ' && name.find('/') == std::string::npos;
+}
+#endif
+
+BOOST_FILESYSTEM_DECL bool portable_posix_name(std::string const& name)
+{
+ return !name.empty() && name.find_first_not_of(posix_valid_chars, 0, sizeof(posix_valid_chars) - 1) == std::string::npos;
+}
+
+BOOST_FILESYSTEM_DECL bool windows_name(std::string const& name)
+{
+ // note that the terminating '\0' is part of the string - thus the size below
+ // is sizeof(windows_invalid_chars) rather than sizeof(windows_invalid_chars)-1.
+ return !name.empty() && name[0] != ' ' && name.find_first_of(windows_invalid_chars, 0, sizeof(windows_invalid_chars)) == std::string::npos
+ && *(name.end() - 1) != ' ' && (*(name.end() - 1) != '.' || name.size() == 1 || name == "..");
+}
+
+BOOST_FILESYSTEM_DECL bool portable_name(std::string const& name)
+{
+ return !name.empty() && (name == "." || name == ".." || (windows_name(name) && portable_posix_name(name) && name[0] != '.' && name[0] != '-'));
+}
+
+BOOST_FILESYSTEM_DECL bool portable_directory_name(std::string const& name)
+{
+ return name == "." || name == ".." || (portable_name(name) && name.find('.') == std::string::npos);
+}
+
+BOOST_FILESYSTEM_DECL bool portable_file_name(std::string const& name)
+{
+ std::string::size_type pos;
+ return portable_name(name) && name != "." && name != ".." && ((pos = name.find('.')) == std::string::npos || (name.find('.', pos + 1) == std::string::npos && (pos + 5) > name.size()));
+}
+
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
diff --git a/contrib/restricted/boost/filesystem/src/posix_tools.hpp b/contrib/restricted/boost/filesystem/src/posix_tools.hpp
new file mode 100644
index 0000000000..09af4d5889
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/posix_tools.hpp
@@ -0,0 +1,78 @@
+// posix_tools.hpp -------------------------------------------------------------------//
+
+// Copyright 2021-2024 Andrey Semashev
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// See library home page at http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#ifndef BOOST_FILESYSTEM_SRC_POSIX_TOOLS_HPP_
+#define BOOST_FILESYSTEM_SRC_POSIX_TOOLS_HPP_
+
+#include "platform_config.hpp"
+#include <boost/filesystem/config.hpp>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <boost/scope/unique_fd.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/file_status.hpp>
+#include <boost/filesystem/directory.hpp>
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+//! Platform-specific parameters for directory iterator construction
+struct directory_iterator_params
+{
+#if defined(BOOST_FILESYSTEM_HAS_FDOPENDIR_NOFOLLOW)
+ //! File descriptor of the directory to iterate over. If not a negative value, the directory path is only used to generate paths returned by the iterator.
+ boost::scope::unique_fd dir_fd;
+#endif
+};
+
+//! status() implementation
+file_status status_impl
+(
+ path const& p,
+ system::error_code* ec
+#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX)
+ , int basedir_fd = AT_FDCWD
+#endif
+);
+
+//! symlink_status() implementation
+file_status symlink_status_impl
+(
+ path const& p,
+ system::error_code* ec
+#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS) || defined(BOOST_FILESYSTEM_USE_STATX)
+ , int basedir_fd = AT_FDCWD
+#endif
+);
+
+#if defined(BOOST_POSIX_API)
+
+//! Opens a directory file and returns a file descriptor. Returns a negative value in case of error.
+boost::scope::unique_fd open_directory(path const& p, directory_options opts, system::error_code& ec);
+
+#if defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+//! Opens a directory file and returns a file descriptor. Returns a negative value in case of error.
+boost::scope::unique_fd openat_directory(int basedir_fd, path const& p, directory_options opts, system::error_code& ec);
+#endif // defined(BOOST_FILESYSTEM_HAS_POSIX_AT_APIS)
+
+#endif // defined(BOOST_POSIX_API)
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
+
+#endif // BOOST_FILESYSTEM_SRC_POSIX_TOOLS_HPP_
diff --git a/contrib/restricted/boost/filesystem/src/private_config.hpp b/contrib/restricted/boost/filesystem/src/private_config.hpp
new file mode 100644
index 0000000000..c58d245ee1
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/private_config.hpp
@@ -0,0 +1,74 @@
+// private_config.hpp ----------------------------------------------------------------//
+
+// Copyright 2021 Andrey Semashev
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// See library home page at http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#ifndef BOOST_FILESYSTEM_SRC_PRIVATE_CONFIG_HPP_
+#define BOOST_FILESYSTEM_SRC_PRIVATE_CONFIG_HPP_
+
+#include <boost/filesystem/config.hpp>
+
+#if defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY)
+#define BOOST_FILESYSTEM_INIT_PRIORITY(n) __attribute__ ((init_priority(n)))
+#else
+#define BOOST_FILESYSTEM_INIT_PRIORITY(n)
+#endif
+
+// According to https://gcc.gnu.org/bugzilla//show_bug.cgi?id=65115,
+// the default C++ object initializers priority is 65535. We would like to
+// initialize function pointers earlier than that (with lower priority values),
+// before the other global objects initializers are run. Other than this,
+// these priority values are arbitrary.
+#define BOOST_FILESYSTEM_FUNC_PTR_INIT_PRIORITY 32767
+
+// Path globals initialization priority
+#define BOOST_FILESYSTEM_PATH_GLOBALS_INIT_PRIORITY 32768
+
+#if defined(__has_feature) && defined(__has_attribute)
+#if __has_feature(memory_sanitizer) && __has_attribute(no_sanitize)
+#define BOOST_FILESYSTEM_NO_SANITIZE_MEMORY __attribute__ ((no_sanitize("memory")))
+#endif
+#endif // defined(__has_feature) && defined(__has_attribute)
+
+#ifndef BOOST_FILESYSTEM_NO_SANITIZE_MEMORY
+#define BOOST_FILESYSTEM_NO_SANITIZE_MEMORY
+#endif
+
+#if defined(_MSC_VER)
+#if _MSC_VER < 1300 || _MSC_VER > 1900 // 1300 == VC++ 7.0, 1900 == VC++ 14.0
+typedef void (__cdecl* init_func_ptr_t)();
+#define BOOST_FILESYSTEM_INITRETSUCCESS_V
+#define BOOST_FILESYSTEM_INIT_FUNC void __cdecl
+#else
+typedef int (__cdecl* init_func_ptr_t)();
+#define BOOST_FILESYSTEM_INITRETSUCCESS_V 0
+#define BOOST_FILESYSTEM_INIT_FUNC int __cdecl
+#endif
+#else // defined(_MSC_VER)
+typedef void (*init_func_ptr_t)();
+#define BOOST_FILESYSTEM_INITRETSUCCESS_V
+#define BOOST_FILESYSTEM_INIT_FUNC void
+#endif // defined(_MSC_VER)
+
+#if defined(__has_attribute)
+#if __has_attribute(__used__)
+#define BOOST_FILESYSTEM_ATTRIBUTE_RETAIN __attribute__ ((__used__))
+#endif
+#endif
+
+#if !defined(BOOST_FILESYSTEM_ATTRIBUTE_RETAIN) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 402
+#define BOOST_FILESYSTEM_ATTRIBUTE_RETAIN __attribute__ ((__used__))
+#endif
+
+#if !defined(BOOST_FILESYSTEM_ATTRIBUTE_RETAIN)
+#define BOOST_FILESYSTEM_NO_ATTRIBUTE_RETAIN
+#define BOOST_FILESYSTEM_ATTRIBUTE_RETAIN
+#endif
+
+#endif // BOOST_FILESYSTEM_SRC_PRIVATE_CONFIG_HPP_
diff --git a/contrib/restricted/boost/filesystem/src/unique_path.cpp b/contrib/restricted/boost/filesystem/src/unique_path.cpp
new file mode 100644
index 0000000000..e98677fa70
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/unique_path.cpp
@@ -0,0 +1,351 @@
+// filesystem unique_path.cpp --------------------------------------------------------//
+
+// Copyright Beman Dawes 2010
+// Copyright Andrey Semashev 2020, 2024
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#include "platform_config.hpp"
+
+#include <boost/predef/library/c/cloudabi.h>
+#include <boost/predef/os/bsd/open.h>
+#include <boost/predef/os/bsd/free.h>
+
+#ifdef BOOST_POSIX_API
+
+#include <cerrno>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#if !defined(BOOST_FILESYSTEM_DISABLE_ARC4RANDOM)
+#if BOOST_OS_BSD_OPEN >= BOOST_VERSION_NUMBER(2, 1, 0) || \
+ BOOST_OS_BSD_FREE >= BOOST_VERSION_NUMBER(8, 0, 0) || \
+ BOOST_LIB_C_CLOUDABI
+#include <stdlib.h>
+#define BOOST_FILESYSTEM_HAS_ARC4RANDOM
+#endif
+#endif // !defined(BOOST_FILESYSTEM_DISABLE_ARC4RANDOM)
+
+#if !defined(BOOST_FILESYSTEM_DISABLE_GETRANDOM)
+#if (defined(__linux__) || defined(__linux) || defined(linux)) && \
+ (!defined(__ANDROID__) || __ANDROID_API__ >= 28)
+#include <sys/syscall.h>
+#if defined(SYS_getrandom)
+#define BOOST_FILESYSTEM_HAS_GETRANDOM_SYSCALL
+#endif // defined(SYS_getrandom)
+#if defined(__has_include)
+#if __has_include(<sys/random.h>)
+#define BOOST_FILESYSTEM_HAS_GETRANDOM
+#endif
+#elif defined(__GLIBC__)
+#if __GLIBC_PREREQ(2, 25)
+#define BOOST_FILESYSTEM_HAS_GETRANDOM
+#endif
+#endif // BOOST_FILESYSTEM_HAS_GETRANDOM definition
+#if defined(BOOST_FILESYSTEM_HAS_GETRANDOM)
+#include <sys/random.h>
+#endif
+#endif // (defined(__linux__) || defined(__linux) || defined(linux)) && (!defined(__ANDROID__) || __ANDROID_API__ >= 28)
+#endif // !defined(BOOST_FILESYSTEM_DISABLE_GETRANDOM)
+
+#include <boost/scope/unique_fd.hpp>
+#include "posix_tools.hpp"
+
+#else // BOOST_WINDOWS_API
+
+// We use auto-linking below to help users of static builds of Boost.Filesystem to link to whatever Windows SDK library we selected.
+// The dependency information is currently not exposed in CMake config files generated by Boost.Build (https://github.com/boostorg/boost_install/issues/18),
+// which makes it non-trivial for users to discover the libraries they need. This feature is deprecated and may be removed in the future,
+// when the situation with CMake config files improves.
+// Note that the library build system is the principal source of linking the library, which must work regardless of auto-linking.
+#include <boost/predef/platform.h>
+#include <boost/winapi/basic_types.hpp>
+
+#if defined(BOOST_FILESYSTEM_HAS_BCRYPT) // defined on the command line by the project
+#include <boost/winapi/error_codes.hpp>
+#include <boost/winapi/bcrypt.hpp>
+#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && defined(_MSC_VER)
+#pragma comment(lib, "bcrypt.lib")
+#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && defined(_MSC_VER)
+#else // defined(BOOST_FILESYSTEM_HAS_BCRYPT)
+#include <boost/winapi/crypt.hpp>
+#include <boost/winapi/get_last_error.hpp>
+#if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && defined(_MSC_VER)
+#if !defined(_WIN32_WCE)
+#pragma comment(lib, "advapi32.lib")
+#else
+#pragma comment(lib, "coredll.lib")
+#endif
+#endif // !defined(BOOST_FILESYSTEM_NO_DEPRECATED) && defined(_MSC_VER)
+#endif // defined(BOOST_FILESYSTEM_HAS_BCRYPT)
+
+#endif // BOOST_POSIX_API
+
+#include <cstddef>
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/operations.hpp>
+#include "private_config.hpp"
+#include "atomic_tools.hpp"
+#include "error_handling.hpp"
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+#if defined(BOOST_POSIX_API)
+// At least Mac OS X 10.6 and older doesn't support O_CLOEXEC
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+#endif // defined(BOOST_POSIX_API)
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+namespace {
+
+#if defined(BOOST_POSIX_API) && !defined(BOOST_FILESYSTEM_HAS_ARC4RANDOM)
+
+//! Fills buffer with cryptographically random data obtained from /dev/(u)random
+int fill_random_dev_random(void* buf, std::size_t len)
+{
+ boost::scope::unique_fd file;
+ while (true)
+ {
+ file.reset(::open("/dev/urandom", O_RDONLY | O_CLOEXEC));
+ if (!file)
+ {
+ if (errno == EINTR)
+ continue;
+ }
+
+ break;
+ }
+
+ if (!file)
+ {
+ while (true)
+ {
+ file.reset(::open("/dev/random", O_RDONLY | O_CLOEXEC));
+ if (!file)
+ {
+ const int err = errno;
+ if (err == EINTR)
+ continue;
+ return err;
+ }
+
+ break;
+ }
+ }
+
+ std::size_t bytes_read = 0u;
+ while (bytes_read < len)
+ {
+ ssize_t n = ::read(file.get(), buf, len - bytes_read);
+ if (BOOST_UNLIKELY(n < 0))
+ {
+ const int err = errno;
+ if (err == EINTR)
+ continue;
+ return err;
+ }
+
+ bytes_read += n;
+ buf = static_cast< char* >(buf) + n;
+ }
+
+ return 0;
+}
+
+#if defined(BOOST_FILESYSTEM_HAS_GETRANDOM) || defined(BOOST_FILESYSTEM_HAS_GETRANDOM_SYSCALL)
+
+typedef int fill_random_t(void* buf, std::size_t len);
+
+//! Pointer to the implementation of fill_random.
+fill_random_t* fill_random = &fill_random_dev_random;
+
+//! Fills buffer with cryptographically random data obtained from getrandom()
+int fill_random_getrandom(void* buf, std::size_t len)
+{
+ std::size_t bytes_read = 0u;
+ while (bytes_read < len)
+ {
+#if defined(BOOST_FILESYSTEM_HAS_GETRANDOM)
+ ssize_t n = ::getrandom(buf, len - bytes_read, 0u);
+#else
+ ssize_t n = ::syscall(SYS_getrandom, buf, len - bytes_read, 0u);
+#endif
+ if (BOOST_UNLIKELY(n < 0))
+ {
+ const int err = errno;
+ if (err == EINTR)
+ continue;
+
+ if (err == ENOSYS && bytes_read == 0u)
+ {
+ filesystem::detail::atomic_store_relaxed(fill_random, &fill_random_dev_random);
+ return fill_random_dev_random(buf, len);
+ }
+
+ return err;
+ }
+
+ bytes_read += n;
+ buf = static_cast< char* >(buf) + n;
+ }
+
+ return 0;
+}
+
+#endif // defined(BOOST_FILESYSTEM_HAS_GETRANDOM) || defined(BOOST_FILESYSTEM_HAS_GETRANDOM_SYSCALL)
+
+#endif // defined(BOOST_POSIX_API) && !defined(BOOST_FILESYSTEM_HAS_ARC4RANDOM)
+
+void system_crypt_random(void* buf, std::size_t len, boost::system::error_code* ec)
+{
+#if defined(BOOST_POSIX_API)
+
+#if defined(BOOST_FILESYSTEM_HAS_GETRANDOM) || defined(BOOST_FILESYSTEM_HAS_GETRANDOM_SYSCALL)
+
+ int err = filesystem::detail::atomic_load_relaxed(fill_random)(buf, len);
+ if (BOOST_UNLIKELY(err != 0))
+ emit_error(err, ec, "boost::filesystem::unique_path");
+
+#elif defined(BOOST_FILESYSTEM_HAS_ARC4RANDOM)
+
+ arc4random_buf(buf, len);
+
+#else
+
+ int err = fill_random_dev_random(buf, len);
+ if (BOOST_UNLIKELY(err != 0))
+ emit_error(err, ec, "boost::filesystem::unique_path");
+
+#endif
+
+#else // defined(BOOST_POSIX_API)
+
+#if defined(BOOST_FILESYSTEM_HAS_BCRYPT)
+
+ boost::winapi::BCRYPT_ALG_HANDLE_ handle;
+ boost::winapi::NTSTATUS_ status = boost::winapi::BCryptOpenAlgorithmProvider(&handle, boost::winapi::BCRYPT_RNG_ALGORITHM_, nullptr, 0);
+ if (BOOST_UNLIKELY(status != 0))
+ {
+ fail:
+ emit_error(translate_ntstatus(status), ec, "boost::filesystem::unique_path");
+ return;
+ }
+
+ status = boost::winapi::BCryptGenRandom(handle, static_cast< boost::winapi::PUCHAR_ >(buf), static_cast< boost::winapi::ULONG_ >(len), 0);
+
+ boost::winapi::BCryptCloseAlgorithmProvider(handle, 0);
+
+ if (BOOST_UNLIKELY(status != 0))
+ goto fail;
+
+#else // defined(BOOST_FILESYSTEM_HAS_BCRYPT)
+
+ boost::winapi::HCRYPTPROV_ handle;
+ boost::winapi::DWORD_ err = 0u;
+ if (BOOST_UNLIKELY(!boost::winapi::CryptAcquireContextW(&handle, nullptr, nullptr, boost::winapi::PROV_RSA_FULL_, boost::winapi::CRYPT_VERIFYCONTEXT_ | boost::winapi::CRYPT_SILENT_)))
+ {
+ err = boost::winapi::GetLastError();
+
+ fail:
+ emit_error(err, ec, "boost::filesystem::unique_path");
+ return;
+ }
+
+ boost::winapi::BOOL_ gen_ok = boost::winapi::CryptGenRandom(handle, static_cast< boost::winapi::DWORD_ >(len), static_cast< boost::winapi::BYTE_* >(buf));
+
+ if (BOOST_UNLIKELY(!gen_ok))
+ err = boost::winapi::GetLastError();
+
+ boost::winapi::CryptReleaseContext(handle, 0);
+
+ if (BOOST_UNLIKELY(!gen_ok))
+ goto fail;
+
+#endif // defined(BOOST_FILESYSTEM_HAS_BCRYPT)
+
+#endif // defined(BOOST_POSIX_API)
+}
+
+#ifdef BOOST_WINDOWS_API
+BOOST_CONSTEXPR_OR_CONST wchar_t hex[] = L"0123456789abcdef";
+BOOST_CONSTEXPR_OR_CONST wchar_t percent = L'%';
+#else
+BOOST_CONSTEXPR_OR_CONST char hex[] = "0123456789abcdef";
+BOOST_CONSTEXPR_OR_CONST char percent = '%';
+#endif
+
+} // unnamed namespace
+
+#if defined(linux) || defined(__linux) || defined(__linux__)
+
+//! Initializes fill_random implementation pointer
+void init_fill_random_impl(unsigned int major_ver, unsigned int minor_ver, unsigned int patch_ver)
+{
+#if defined(BOOST_FILESYSTEM_HAS_INIT_PRIORITY) && \
+ (defined(BOOST_FILESYSTEM_HAS_GETRANDOM) || defined(BOOST_FILESYSTEM_HAS_GETRANDOM_SYSCALL))
+ fill_random_t* fr = &fill_random_dev_random;
+
+ if (major_ver > 3u || (major_ver == 3u && minor_ver >= 17u))
+ fr = &fill_random_getrandom;
+
+ filesystem::detail::atomic_store_relaxed(fill_random, fr);
+#endif
+}
+
+#endif // defined(linux) || defined(__linux) || defined(__linux__)
+
+BOOST_FILESYSTEM_DECL
+path unique_path(path const& model, system::error_code* ec)
+{
+ // This function used wstring for fear of misidentifying
+ // a part of a multibyte character as a percent sign.
+ // However, double byte encodings only have 80-FF as lead
+ // bytes and 40-7F as trailing bytes, whereas % is 25.
+ // So, use string on POSIX and avoid conversions.
+
+ path::string_type s(model.native());
+
+ char ran[16] = {}; // init to avoid clang static analyzer message
+ // see ticket #8954
+ BOOST_CONSTEXPR_OR_CONST unsigned int max_nibbles = 2u * sizeof(ran); // 4-bits per nibble
+
+ unsigned int nibbles_used = max_nibbles;
+ for (path::string_type::size_type i = 0, n = s.size(); i < n; ++i)
+ {
+ if (s[i] == percent) // digit request
+ {
+ if (nibbles_used == max_nibbles)
+ {
+ system_crypt_random(ran, sizeof(ran), ec);
+ if (ec && *ec)
+ return path();
+ nibbles_used = 0;
+ }
+ unsigned int c = ran[nibbles_used / 2u];
+ c >>= 4u * (nibbles_used++ & 1u); // if odd, shift right 1 nibble
+ s[i] = hex[c & 0xf]; // convert to hex digit and replace
+ }
+ }
+
+ if (ec)
+ ec->clear();
+
+ return s;
+}
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
diff --git a/contrib/restricted/boost/filesystem/src/utf8_codecvt_facet.cpp b/contrib/restricted/boost/filesystem/src/utf8_codecvt_facet.cpp
new file mode 100644
index 0000000000..7e5939bb71
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/utf8_codecvt_facet.cpp
@@ -0,0 +1,29 @@
+// Copyright Vladimir Prus 2004.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt
+// or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include "platform_config.hpp"
+
+#include <boost/filesystem/config.hpp>
+
+#include <boost/filesystem/detail/header.hpp>
+
+#define BOOST_UTF8_BEGIN_NAMESPACE \
+ namespace boost { \
+ namespace filesystem { \
+ namespace detail {
+
+#define BOOST_UTF8_END_NAMESPACE \
+ } \
+ } \
+ }
+#define BOOST_UTF8_DECL BOOST_FILESYSTEM_DECL
+
+#include <boost/detail/utf8_codecvt_facet.ipp>
+
+#undef BOOST_UTF8_BEGIN_NAMESPACE
+#undef BOOST_UTF8_END_NAMESPACE
+#undef BOOST_UTF8_DECL
+
+#include <boost/filesystem/detail/footer.hpp>
diff --git a/contrib/restricted/boost/filesystem/src/windows_file_codecvt.cpp b/contrib/restricted/boost/filesystem/src/windows_file_codecvt.cpp
new file mode 100644
index 0000000000..f86ba5111b
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/windows_file_codecvt.cpp
@@ -0,0 +1,72 @@
+// filesystem windows_file_codecvt.cpp -----------------------------------------//
+
+// Copyright Beman Dawes 2009
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#include "platform_config.hpp"
+
+#include <cwchar> // for mbstate_t
+
+#ifdef BOOST_WINDOWS_API
+
+#include "windows_file_codecvt.hpp"
+
+#include <windows.h>
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+std::codecvt_base::result windows_file_codecvt::do_in(
+ std::mbstate_t&,
+ const char* from, const char* from_end, const char*& from_next,
+ wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const
+{
+ UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
+
+ int count;
+ if ((count = ::MultiByteToWideChar(codepage, MB_PRECOMPOSED, from, static_cast< int >(from_end - from), to, static_cast< int >(to_end - to))) == 0)
+ {
+ return error; // conversion failed
+ }
+
+ from_next = from_end;
+ to_next = to + count;
+ *to_next = L'\0';
+ return ok;
+}
+
+std::codecvt_base::result windows_file_codecvt::do_out(
+ std::mbstate_t&,
+ const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next,
+ char* to, char* to_end, char*& to_next) const
+{
+ UINT codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
+
+ int count;
+ if ((count = ::WideCharToMultiByte(codepage, WC_NO_BEST_FIT_CHARS, from, static_cast< int >(from_end - from), to, static_cast< int >(to_end - to), 0, 0)) == 0)
+ {
+ return error; // conversion failed
+ }
+
+ from_next = from_end;
+ to_next = to + count;
+ *to_next = '\0';
+ return ok;
+}
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
+
+#endif // BOOST_WINDOWS_API
diff --git a/contrib/restricted/boost/filesystem/src/windows_file_codecvt.hpp b/contrib/restricted/boost/filesystem/src/windows_file_codecvt.hpp
new file mode 100644
index 0000000000..e0f0ae6c3a
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/windows_file_codecvt.hpp
@@ -0,0 +1,72 @@
+// filesystem windows_file_codecvt.hpp -----------------------------------------------//
+
+// Copyright Beman Dawes 2009
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// Library home page: http://www.boost.org/libs/filesystem
+
+#ifndef BOOST_FILESYSTEM_WINDOWS_FILE_CODECVT_HPP
+#define BOOST_FILESYSTEM_WINDOWS_FILE_CODECVT_HPP
+
+#include <boost/filesystem/config.hpp>
+
+#ifdef BOOST_WINDOWS_API
+
+#include <boost/config/workaround.hpp>
+#include <cstddef>
+#include <cwchar> // std::mbstate_t
+#include <locale>
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+//------------------------------------------------------------------------------------//
+// //
+// class windows_file_codecvt //
+// //
+// Warning: partial implementation; even do_in and do_out only partially meet the //
+// standard library specifications as the "to" buffer must hold the entire result. //
+// //
+//------------------------------------------------------------------------------------//
+
+class BOOST_SYMBOL_VISIBLE windows_file_codecvt final :
+ public std::codecvt< wchar_t, char, std::mbstate_t >
+{
+public:
+ explicit windows_file_codecvt(std::size_t refs = 0) :
+ std::codecvt< wchar_t, char, std::mbstate_t >(refs)
+ {
+ }
+
+protected:
+ bool do_always_noconv() const noexcept override { return false; }
+
+ // seems safest to assume variable number of characters since we don't
+ // actually know what codepage is active
+ int do_encoding() const noexcept override { return 0; }
+ std::codecvt_base::result do_in(std::mbstate_t& state, const char* from, const char* from_end, const char*& from_next, wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const override;
+ std::codecvt_base::result do_out(std::mbstate_t& state, const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next, char* to, char* to_end, char*& to_next) const override;
+ std::codecvt_base::result do_unshift(std::mbstate_t&, char* /*from*/, char* /*to*/, char*& /*next*/) const override { return ok; }
+ int do_length(std::mbstate_t&, const char* /*from*/, const char* /*from_end*/, std::size_t /*max*/) const
+#if BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600))
+ throw()
+#endif
+ override
+ { return 0; }
+ int do_max_length() const noexcept override { return 0; }
+};
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
+
+#endif // BOOST_WINDOWS_API
+
+#endif // BOOST_FILESYSTEM_WINDOWS_FILE_CODECVT_HPP
diff --git a/contrib/restricted/boost/filesystem/src/windows_tools.hpp b/contrib/restricted/boost/filesystem/src/windows_tools.hpp
new file mode 100644
index 0000000000..c16b61fb48
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/src/windows_tools.hpp
@@ -0,0 +1,310 @@
+// windows_tools.hpp -----------------------------------------------------------------//
+
+// Copyright 2001 Dietmar Kuehl
+// Copyright 2002-2009, 2014 Beman Dawes
+// Copyright 2021-2022 Andrey Semashev
+
+// Distributed under the Boost Software License, Version 1.0.
+// See http://www.boost.org/LICENSE_1_0.txt
+
+// See library home page at http://www.boost.org/libs/filesystem
+
+//--------------------------------------------------------------------------------------//
+
+#ifndef BOOST_FILESYSTEM_SRC_WINDOWS_TOOLS_HPP_
+#define BOOST_FILESYSTEM_SRC_WINDOWS_TOOLS_HPP_
+
+#include <boost/filesystem/config.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/file_status.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/scope/unique_resource.hpp>
+#include <boost/winapi/basic_types.hpp> // NTSTATUS_
+
+#include <windows.h>
+
+#include <boost/filesystem/detail/header.hpp> // must be the last #include
+
+#ifndef IO_REPARSE_TAG_DEDUP
+#define IO_REPARSE_TAG_DEDUP (0x80000013L)
+#endif
+
+#ifndef IO_REPARSE_TAG_MOUNT_POINT
+#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L)
+#endif
+
+#ifndef IO_REPARSE_TAG_SYMLINK
+#define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
+#endif
+
+namespace boost {
+namespace filesystem {
+namespace detail {
+
+//! Deleter for HANDLEs
+struct handle_deleter
+{
+ using result_type = void;
+
+ result_type operator() (HANDLE h) const noexcept
+ {
+ ::CloseHandle(h);
+ }
+};
+
+//! Resource traits for HANDLEs
+struct handle_resource_traits
+{
+ static HANDLE make_default() noexcept
+ {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ static bool is_allocated(HANDLE h) noexcept
+ {
+ return h != INVALID_HANDLE_VALUE && h != nullptr;
+ }
+};
+
+//! Unique HANDLE wrapper
+using unique_handle = boost::scope::unique_resource< HANDLE, handle_deleter, handle_resource_traits >;
+
+BOOST_INLINE_VARIABLE BOOST_CONSTEXPR_OR_CONST wchar_t colon = L':';
+BOOST_INLINE_VARIABLE BOOST_CONSTEXPR_OR_CONST wchar_t questionmark = L'?';
+
+inline bool is_letter(wchar_t c)
+{
+ return (c >= L'A' && c <= L'Z') || (c >= L'a' && c <= L'z');
+}
+
+inline bool equal_extension(wchar_t const* p, wchar_t const (&x1)[5], wchar_t const (&x2)[5])
+{
+ return (p[0] == x1[0] || p[0] == x2[0]) &&
+ (p[1] == x1[1] || p[1] == x2[1]) &&
+ (p[2] == x1[2] || p[2] == x2[2]) &&
+ (p[3] == x1[3] || p[3] == x2[3]) &&
+ p[4] == 0;
+}
+
+inline boost::filesystem::perms make_permissions(boost::filesystem::path const& p, DWORD attr)
+{
+ boost::filesystem::perms prms = boost::filesystem::owner_read | boost::filesystem::group_read | boost::filesystem::others_read;
+ if ((attr & FILE_ATTRIBUTE_READONLY) == 0u)
+ prms |= boost::filesystem::owner_write | boost::filesystem::group_write | boost::filesystem::others_write;
+ boost::filesystem::path ext = detail::path_algorithms::extension_v4(p);
+ wchar_t const* q = ext.c_str();
+ if (equal_extension(q, L".exe", L".EXE") || equal_extension(q, L".com", L".COM") || equal_extension(q, L".bat", L".BAT") || equal_extension(q, L".cmd", L".CMD"))
+ prms |= boost::filesystem::owner_exe | boost::filesystem::group_exe | boost::filesystem::others_exe;
+ return prms;
+}
+
+ULONG get_reparse_point_tag_ioctl(HANDLE h, boost::filesystem::path const& p, boost::system::error_code* ec);
+
+inline bool is_reparse_point_tag_a_symlink(ULONG reparse_point_tag)
+{
+ return reparse_point_tag == IO_REPARSE_TAG_SYMLINK
+ // Issue 9016 asked that NTFS directory junctions be recognized as directories.
+ // That is equivalent to recognizing them as symlinks, and then the normal symlink
+ // mechanism will take care of recognizing them as directories.
+ //
+ // Directory junctions are very similar to symlinks, but have some performance
+ // and other advantages over symlinks. They can be created from the command line
+ // with "mklink /J junction-name target-path".
+ //
+ // Note that mounted filesystems also have the same repartse point tag, which makes
+ // them look like directory symlinks in terms of Boost.Filesystem. read_symlink()
+ // may return a volume path or NT path for such symlinks.
+ || reparse_point_tag == IO_REPARSE_TAG_MOUNT_POINT; // aka "directory junction" or "junction"
+}
+
+//! Platform-specific parameters for directory iterator construction
+struct directory_iterator_params
+{
+ //! Handle of the directory to iterate over. If not \c INVALID_HANDLE_VALUE, the directory path is only used to generate paths returned by the iterator.
+ HANDLE dir_handle;
+ /*!
+ * If \c dir_handle is not \c INVALID_HANDLE_VALUE, specifies whether the directory iterator should close the handle upon destruction.
+ * If \c false, the handle must remain valid for the lifetime of the iterator.
+ */
+ bool close_handle;
+};
+
+//! IO_STATUS_BLOCK definition from Windows SDK.
+struct io_status_block
+{
+ union
+ {
+ boost::winapi::NTSTATUS_ Status;
+ PVOID Pointer;
+ };
+ ULONG_PTR Information;
+};
+
+//! UNICODE_STRING definition from Windows SDK
+struct unicode_string
+{
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Buffer;
+};
+
+//! OBJECT_ATTRIBUTES definition from Windows SDK
+struct object_attributes
+{
+ ULONG Length;
+ HANDLE RootDirectory;
+ unicode_string* ObjectName;
+ ULONG Attributes;
+ PVOID SecurityDescriptor;
+ PVOID SecurityQualityOfService;
+};
+
+#ifndef OBJ_CASE_INSENSITIVE
+#define OBJ_CASE_INSENSITIVE 0x00000040
+#endif
+#ifndef OBJ_DONT_REPARSE
+#define OBJ_DONT_REPARSE 0x00001000
+#endif
+
+#ifndef FILE_SUPERSEDE
+#define FILE_SUPERSEDE 0x00000000
+#endif
+#ifndef FILE_OPEN
+#define FILE_OPEN 0x00000001
+#endif
+#ifndef FILE_CREATE
+#define FILE_CREATE 0x00000002
+#endif
+#ifndef FILE_OPEN_IF
+#define FILE_OPEN_IF 0x00000003
+#endif
+#ifndef FILE_OVERWRITE
+#define FILE_OVERWRITE 0x00000004
+#endif
+#ifndef FILE_OVERWRITE_IF
+#define FILE_OVERWRITE_IF 0x00000005
+#endif
+
+#ifndef FILE_DIRECTORY_FILE
+#define FILE_DIRECTORY_FILE 0x00000001
+#endif
+#ifndef FILE_SYNCHRONOUS_IO_NONALERT
+#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
+#endif
+#ifndef FILE_OPEN_FOR_BACKUP_INTENT
+#define FILE_OPEN_FOR_BACKUP_INTENT 0x00004000
+#endif
+#ifndef FILE_OPEN_REPARSE_POINT
+#define FILE_OPEN_REPARSE_POINT 0x00200000
+#endif
+
+//! NtCreateFile signature. Available since Windows 2000 (probably).
+typedef boost::winapi::NTSTATUS_ (NTAPI NtCreateFile_t)(
+ /*out*/ PHANDLE FileHandle,
+ /*in*/ ACCESS_MASK DesiredAccess,
+ /*in*/ object_attributes* ObjectAttributes,
+ /*out*/ io_status_block* IoStatusBlock,
+ /*in, optional*/ PLARGE_INTEGER AllocationSize,
+ /*in*/ ULONG FileAttributes,
+ /*in*/ ULONG ShareAccess,
+ /*in*/ ULONG CreateDisposition,
+ /*in*/ ULONG CreateOptions,
+ /*in, optional*/ PVOID EaBuffer,
+ /*in*/ ULONG EaLength);
+
+extern NtCreateFile_t* nt_create_file_api;
+
+//! PIO_APC_ROUTINE definition from Windows SDK
+typedef VOID (NTAPI* pio_apc_routine) (PVOID ApcContext, io_status_block* IoStatusBlock, ULONG Reserved);
+
+//! FILE_INFORMATION_CLASS enum entries
+enum file_information_class
+{
+ file_directory_information_class = 1
+};
+
+//! NtQueryDirectoryFile signature. Available since Windows NT 4.0 (probably).
+typedef boost::winapi::NTSTATUS_ (NTAPI NtQueryDirectoryFile_t)(
+ /*in*/ HANDLE FileHandle,
+ /*in, optional*/ HANDLE Event,
+ /*in, optional*/ pio_apc_routine ApcRoutine,
+ /*in, optional*/ PVOID ApcContext,
+ /*out*/ io_status_block* IoStatusBlock,
+ /*out*/ PVOID FileInformation,
+ /*in*/ ULONG Length,
+ /*in*/ file_information_class FileInformationClass,
+ /*in*/ BOOLEAN ReturnSingleEntry,
+ /*in, optional*/ unicode_string* FileName,
+ /*in*/ BOOLEAN RestartScan);
+
+extern NtQueryDirectoryFile_t* nt_query_directory_file_api;
+
+//! FILE_INFO_BY_HANDLE_CLASS enum entries
+enum file_info_by_handle_class
+{
+ file_basic_info_class = 0,
+ file_disposition_info_class = 4,
+ file_attribute_tag_info_class = 9,
+ file_id_both_directory_info_class = 10,
+ file_id_both_directory_restart_info_class = 11,
+ file_full_directory_info_class = 14,
+ file_full_directory_restart_info_class = 15,
+ file_id_extd_directory_info_class = 19,
+ file_id_extd_directory_restart_info_class = 20,
+ file_disposition_info_ex_class = 21
+};
+
+//! FILE_ATTRIBUTE_TAG_INFO definition from Windows SDK
+struct file_attribute_tag_info
+{
+ DWORD FileAttributes;
+ DWORD ReparseTag;
+};
+
+//! GetFileInformationByHandleEx signature. Available since Windows Vista.
+typedef BOOL (WINAPI GetFileInformationByHandleEx_t)(
+ /*__in*/ HANDLE hFile,
+ /*__in*/ file_info_by_handle_class FileInformationClass, // the actual type is FILE_INFO_BY_HANDLE_CLASS enum
+ /*__out_bcount(dwBufferSize)*/ LPVOID lpFileInformation,
+ /*__in*/ DWORD dwBufferSize);
+
+extern GetFileInformationByHandleEx_t* get_file_information_by_handle_ex_api;
+
+//! Creates a file handle
+inline unique_handle create_file_handle
+(
+ boost::filesystem::path const& p,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile = nullptr
+)
+{
+ return unique_handle(::CreateFileW(p.c_str(), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile));
+}
+
+//! Creates a file handle for a file relative to a previously opened base directory. The file path must be relative and in preferred format.
+boost::winapi::NTSTATUS_ nt_create_file_handle_at
+(
+ unique_handle& out,
+ HANDLE basedir_handle,
+ boost::filesystem::path const& p,
+ ULONG FileAttributes,
+ ACCESS_MASK DesiredAccess,
+ ULONG ShareMode,
+ ULONG CreateDisposition,
+ ULONG CreateOptions
+);
+
+//! Returns status of the file identified by an open handle. The path \a p is used to report errors and infer file permissions.
+filesystem::file_status status_by_handle(HANDLE h, path const& p, system::error_code* ec);
+
+} // namespace detail
+} // namespace filesystem
+} // namespace boost
+
+#include <boost/filesystem/detail/footer.hpp>
+
+#endif // BOOST_FILESYSTEM_SRC_WINDOWS_TOOLS_HPP_
diff --git a/contrib/restricted/boost/filesystem/ya.make b/contrib/restricted/boost/filesystem/ya.make
new file mode 100644
index 0000000000..f468ba4980
--- /dev/null
+++ b/contrib/restricted/boost/filesystem/ya.make
@@ -0,0 +1,68 @@
+# Generated by devtools/yamaker from nixpkgs 22.11.
+
+LIBRARY()
+
+LICENSE(BSL-1.0)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+VERSION(1.86.0)
+
+ORIGINAL_SOURCE(https://github.com/boostorg/filesystem/archive/boost-1.86.0.tar.gz)
+
+PEERDIR(
+ contrib/restricted/boost/assert
+ contrib/restricted/boost/atomic
+ contrib/restricted/boost/config
+ contrib/restricted/boost/container_hash
+ contrib/restricted/boost/core
+ contrib/restricted/boost/detail
+ contrib/restricted/boost/io
+ contrib/restricted/boost/iterator
+ contrib/restricted/boost/predef
+ contrib/restricted/boost/scope
+ contrib/restricted/boost/smart_ptr
+ contrib/restricted/boost/system
+ contrib/restricted/boost/type_traits
+ contrib/restricted/boost/winapi
+)
+
+ADDINCL(
+ GLOBAL contrib/restricted/boost/filesystem/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DBOOST_FILESYSTEM_NO_CXX20_ATOMIC_REF
+)
+
+IF (OS_LINUX)
+ CFLAGS(
+ GLOBAL -DBOOST_FILESYSTEM_HAS_POSIX_AT_APIS
+ )
+ENDIF()
+
+IF (DYNAMIC_BOOST)
+ CFLAGS(
+ GLOBAL -DBOOST_FILESYSTEM_DYN_LINK
+ -DBOOST_FILESYSTEM_SOURCE
+ )
+ENDIF()
+
+SRCS(
+ src/codecvt_error_category.cpp
+ src/directory.cpp
+ src/exception.cpp
+ src/operations.cpp
+ src/path.cpp
+ src/path_traits.cpp
+ src/portability.cpp
+ src/unique_path.cpp
+ src/utf8_codecvt_facet.cpp
+ src/windows_file_codecvt.cpp
+)
+
+END()
diff --git a/contrib/restricted/boost/scope/.yandex_meta/devtools.copyrights.report b/contrib/restricted/boost/scope/.yandex_meta/devtools.copyrights.report
new file mode 100644
index 0000000000..25c80d389e
--- /dev/null
+++ b/contrib/restricted/boost/scope/.yandex_meta/devtools.copyrights.report
@@ -0,0 +1,91 @@
+# File format ($ symbol means the beginning of a line):
+#
+# $ # this message
+# $ # =======================
+# $ # comments (all commentaries should starts with some number of spaces and # symbol)
+# $ IGNORE_FILES {file1.ext1} {file2.ext2} - (optional) ignore listed files when generating license macro and credits
+# $ RENAME {original license id} TO {new license id} # user comments - (optional) use {new license id} instead {original license id} in ya.make files
+# $ # user comments
+# $
+# ${action} {license id} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/1/ya.make ./ya/make/2/ya.make
+# ${all_file_action} filename
+# $ # user commentaries (many lines)
+# $ generated description - files with this license, license text... (some number of lines that starts with some number of spaces, do not modify)
+# ${action} {license spdx} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/3/ya.make
+# ${all_file_action} filename
+# $ # user commentaries
+# $ generated description
+# $ ...
+#
+# You can modify action, all_file_action and add commentaries
+# Available actions:
+# keep - keep license in contrib and use in credits
+# skip - skip license
+# remove - remove all files with this license
+# rename - save license text/links into licenses texts file, but not store SPDX into LINCENSE macro. You should store correct license id into devtools.license.spdx.txt file
+#
+# {all file action} records will be generated when license text contains filename that exists on filesystem (in contrib directory)
+# We suppose that that files can contain some license info
+# Available all file actions:
+# FILE_IGNORE - ignore file (do nothing)
+# FILE_INCLUDE - include all file data into licenses text file
+# =======================
+
+KEEP COPYRIGHT_SERVICE_LABEL 3244b00e8ab273a03f19b20a64c26a96
+BELONGS ya.make
+ License text:
+ * Copyright (c) 2023 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/scope/detail/config.hpp [6:6]
+ include/boost/scope/detail/footer.hpp [6:6]
+ include/boost/scope/detail/header.hpp [6:6]
+ include/boost/scope/detail/is_nonnull_default_constructible.hpp [6:6]
+ include/boost/scope/detail/is_not_like.hpp [6:6]
+ include/boost/scope/detail/type_traits/conjunction.hpp [6:6]
+ include/boost/scope/detail/type_traits/disjunction.hpp [6:6]
+ include/boost/scope/detail/type_traits/is_final.hpp [6:6]
+ include/boost/scope/detail/type_traits/is_invocable.hpp [6:6]
+ include/boost/scope/detail/type_traits/is_nothrow_invocable.hpp [6:6]
+ include/boost/scope/detail/type_traits/is_nothrow_swappable.hpp [6:6]
+ include/boost/scope/detail/type_traits/is_swappable.hpp [6:6]
+ include/boost/scope/detail/type_traits/negation.hpp [6:6]
+ include/boost/scope/error_code_checker.hpp [6:6]
+ include/boost/scope/exception_checker.hpp [6:6]
+ include/boost/scope/fd_deleter.hpp [6:6]
+ include/boost/scope/fd_resource_traits.hpp [6:6]
+ include/boost/scope/scope_exit.hpp [6:6]
+ include/boost/scope/unique_fd.hpp [6:6]
+
+KEEP COPYRIGHT_SERVICE_LABEL 3f6ec3343e75c2c0c0e1e8956ffabc65
+BELONGS ya.make
+ License text:
+ * Copyright (c) 2022-2024 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/scope/defer.hpp [6:6]
+ include/boost/scope/unique_resource.hpp [6:6]
+
+KEEP COPYRIGHT_SERVICE_LABEL 45666b61e7d8667b41556a93c064e0e8
+BELONGS ya.make
+ License text:
+ * Copyright (c) 2022 Andrey Semashev
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/boost/scope/detail/compact_storage.hpp [6:6]
+ include/boost/scope/detail/move_or_copy_assign_ref.hpp [6:6]
+ include/boost/scope/detail/move_or_copy_construct_ref.hpp [6:6]
+ include/boost/scope/scope_fail.hpp [6:6]
+ include/boost/scope/scope_success.hpp [6:6]
+ include/boost/scope/unique_resource_fwd.hpp [6:6]
diff --git a/contrib/restricted/boost/scope/.yandex_meta/devtools.licenses.report b/contrib/restricted/boost/scope/.yandex_meta/devtools.licenses.report
new file mode 100644
index 0000000000..6fe13bd0ea
--- /dev/null
+++ b/contrib/restricted/boost/scope/.yandex_meta/devtools.licenses.report
@@ -0,0 +1,108 @@
+# File format ($ symbol means the beginning of a line):
+#
+# $ # this message
+# $ # =======================
+# $ # comments (all commentaries should starts with some number of spaces and # symbol)
+# $ IGNORE_FILES {file1.ext1} {file2.ext2} - (optional) ignore listed files when generating license macro and credits
+# $ RENAME {original license id} TO {new license id} # user comments - (optional) use {new license id} instead {original license id} in ya.make files
+# $ # user comments
+# $
+# ${action} {license id} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/1/ya.make ./ya/make/2/ya.make
+# ${all_file_action} filename
+# $ # user commentaries (many lines)
+# $ generated description - files with this license, license text... (some number of lines that starts with some number of spaces, do not modify)
+# ${action} {license spdx} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/3/ya.make
+# ${all_file_action} filename
+# $ # user commentaries
+# $ generated description
+# $ ...
+#
+# You can modify action, all_file_action and add commentaries
+# Available actions:
+# keep - keep license in contrib and use in credits
+# skip - skip license
+# remove - remove all files with this license
+# rename - save license text/links into licenses texts file, but not store SPDX into LINCENSE macro. You should store correct license id into devtools.license.spdx.txt file
+#
+# {all file action} records will be generated when license text contains filename that exists on filesystem (in contrib directory)
+# We suppose that that files can contain some license info
+# Available all file actions:
+# FILE_IGNORE - ignore file (do nothing)
+# FILE_INCLUDE - include all file data into licenses text file
+# =======================
+
+KEEP BSL-1.0 2077ca9d01c7e6d6029ec1763233c5b0
+BELONGS ya.make
+ License text:
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 100.00
+ Match type : NOTICE
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ include/boost/scope/defer.hpp [2:4]
+ include/boost/scope/detail/compact_storage.hpp [2:4]
+ include/boost/scope/detail/config.hpp [2:4]
+ include/boost/scope/detail/footer.hpp [2:4]
+ include/boost/scope/detail/header.hpp [2:4]
+ include/boost/scope/detail/is_nonnull_default_constructible.hpp [2:4]
+ include/boost/scope/detail/is_not_like.hpp [2:4]
+ include/boost/scope/detail/move_or_copy_assign_ref.hpp [2:4]
+ include/boost/scope/detail/move_or_copy_construct_ref.hpp [2:4]
+ include/boost/scope/detail/type_traits/conjunction.hpp [2:4]
+ include/boost/scope/detail/type_traits/disjunction.hpp [2:4]
+ include/boost/scope/detail/type_traits/is_final.hpp [2:4]
+ include/boost/scope/detail/type_traits/is_invocable.hpp [2:4]
+ include/boost/scope/detail/type_traits/is_nothrow_invocable.hpp [2:4]
+ include/boost/scope/detail/type_traits/is_nothrow_swappable.hpp [2:4]
+ include/boost/scope/detail/type_traits/is_swappable.hpp [2:4]
+ include/boost/scope/detail/type_traits/negation.hpp [2:4]
+ include/boost/scope/error_code_checker.hpp [2:4]
+ include/boost/scope/exception_checker.hpp [2:4]
+ include/boost/scope/fd_deleter.hpp [2:4]
+ include/boost/scope/fd_resource_traits.hpp [2:4]
+ include/boost/scope/scope_exit.hpp [2:4]
+ include/boost/scope/scope_fail.hpp [2:4]
+ include/boost/scope/scope_success.hpp [2:4]
+ include/boost/scope/unique_fd.hpp [2:4]
+ include/boost/scope/unique_resource.hpp [2:4]
+ include/boost/scope/unique_resource_fwd.hpp [2:4]
+
+KEEP BSL-1.0 2c7a3fa82e66676005cd4ee2608fd7d2
+BELONGS ya.make
+ Note: matched license text is too long. Read it in the source files.
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 100.00
+ Match type : TEXT
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ LICENSE [1:23]
+
+KEEP BSL-1.0 49af97cadb10453f2b05003f793e4adc
+BELONGS ya.make
+ License text:
+ Distributed under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt).
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 94.44
+ Match type : NOTICE
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ README.md [28:28]
+
+KEEP BSL-1.0 a5006bb276a0e8fcc0c080cd5a14814e
+BELONGS ya.make
+ Note: matched license text is too long. Read it in the source files.
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 55.00
+ Match type : NOTICE
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ README.md [17:17]
diff --git a/contrib/restricted/boost/scope/.yandex_meta/licenses.list.txt b/contrib/restricted/boost/scope/.yandex_meta/licenses.list.txt
new file mode 100644
index 0000000000..6790a8ddab
--- /dev/null
+++ b/contrib/restricted/boost/scope/.yandex_meta/licenses.list.txt
@@ -0,0 +1,48 @@
+====================BSL-1.0====================
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+
+
+====================BSL-1.0====================
+* Submit your patches as [pull requests](https://github.com/boostorg/scope/compare) against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt).
+
+
+====================BSL-1.0====================
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+====================BSL-1.0====================
+Distributed under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt).
+
+====================COPYRIGHT====================
+ * Copyright (c) 2022 Andrey Semashev
+
+
+====================COPYRIGHT====================
+ * Copyright (c) 2022-2024 Andrey Semashev
+
+
+====================COPYRIGHT====================
+ * Copyright (c) 2023 Andrey Semashev
diff --git a/contrib/restricted/boost/scope/LICENSE b/contrib/restricted/boost/scope/LICENSE
new file mode 100644
index 0000000000..36b7cd93cd
--- /dev/null
+++ b/contrib/restricted/boost/scope/LICENSE
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/contrib/restricted/boost/scope/README.md b/contrib/restricted/boost/scope/README.md
new file mode 100644
index 0000000000..21bc1f403c
--- /dev/null
+++ b/contrib/restricted/boost/scope/README.md
@@ -0,0 +1,28 @@
+# Boost.Scope
+
+Boost.Scope provides a number of scope guard utilities and a `unique_resource` wrapper, similar to those described in
+[C++ Extensions for Library Fundamentals, Version 3](https://github.com/cplusplus/fundamentals-ts/releases/tag/n4908),
+Section 3.3 Scope guard support \[scopeguard\]. The implementation also provides a few non-standard extensions.
+
+### Directories
+
+* **doc** - QuickBook documentation sources
+* **include** - Interface headers of Boost.Scope
+* **test** - Boost.Scope unit tests
+
+### More information
+
+* Read the [documentation](https://www.boost.org/libs/scope/).
+* [Report bugs](https://github.com/boostorg/scope/issues/new). Be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well.
+* Submit your patches as [pull requests](https://github.com/boostorg/scope/compare) against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt).
+
+### Build status
+
+Branch | GitHub Actions| Test Matrix | Dependencies |
+:-------------: | --------------| ----------- | ------------ |
+[`master`](https://github.com/boostorg/scope/tree/master) | [![GitHub Actions](https://github.com/boostorg/scope/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/scope/actions?query=branch%3Amaster) | [![Tests](https://img.shields.io/badge/matrix-master-brightgreen.svg)](https://www.boost.org/development/tests/master/developer/scope.html) | [![Dependencies](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/scope.html)
+[`develop`](https://github.com/boostorg/scope/tree/develop) | [![GitHub Actions](https://github.com/boostorg/scope/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/scope/actions?query=branch%3Adevelop) | [![Tests](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](https://www.boost.org/development/tests/develop/developer/scope.html) | [![Dependencies](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/scope.html)
+
+### License
+
+Distributed under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt).
diff --git a/contrib/restricted/boost/scope/include/boost/scope/defer.hpp b/contrib/restricted/boost/scope/include/boost/scope/defer.hpp
new file mode 100644
index 0000000000..988f976536
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/defer.hpp
@@ -0,0 +1,180 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2022-2024 Andrey Semashev
+ */
+/*!
+ * \file scope/defer.hpp
+ *
+ * This header contains definition of \c defer_guard template.
+ */
+
+#ifndef BOOST_SCOPE_DEFER_HPP_INCLUDED_
+#define BOOST_SCOPE_DEFER_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+#include <boost/scope/detail/is_not_like.hpp>
+#include <boost/scope/detail/move_or_copy_construct_ref.hpp>
+#include <boost/scope/detail/type_traits/conjunction.hpp>
+#include <boost/scope/detail/type_traits/is_nothrow_invocable.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+
+template< typename Func >
+class defer_guard;
+
+namespace detail {
+
+// Workaround for clang < 5.0 which can't pass defer_guard as a template template parameter from within defer_guard definition
+template< typename T >
+using is_not_like_defer_guard = detail::is_not_like< T, defer_guard >;
+
+} // namespace detail
+
+/*!
+ * \brief Defer guard that invokes a function upon leaving the scope.
+ *
+ * The scope guard wraps a function object callable with no arguments
+ * that can be one of:
+ *
+ * \li A user-defined class with a public `operator()`.
+ * \li An lvalue reference to such class.
+ * \li An lvalue reference or pointer to function taking no arguments.
+ *
+ * The defer guard unconditionally invokes the wrapped function object
+ * on destruction.
+ */
+template< typename Func >
+class defer_guard
+{
+//! \cond
+private:
+ struct data
+ {
+ Func m_func;
+
+ template< typename F, typename = typename std::enable_if< std::is_constructible< Func, F >::value >::type >
+ explicit data(F&& func, std::true_type) noexcept :
+ m_func(static_cast< F&& >(func))
+ {
+ }
+
+ template< typename F, typename = typename std::enable_if< std::is_constructible< Func, F >::value >::type >
+ explicit data(F&& func, std::false_type) try :
+ m_func(static_cast< F&& >(func))
+ {
+ }
+ catch (...)
+ {
+ func();
+ }
+ };
+
+ data m_data;
+
+//! \endcond
+public:
+ /*!
+ * \brief Constructs a defer guard with a given callable function object.
+ *
+ * **Requires:** \c Func is constructible from \a func.
+ *
+ * **Effects:** If \c Func is nothrow constructible from `F&&` then constructs \c Func from
+ * `std::forward< F >(func)`, otherwise constructs from `func`.
+ *
+ * If \c Func construction throws, invokes \a func before returning with the exception.
+ *
+ * **Throws:** Nothing, unless construction of the function object throws.
+ *
+ * \param func The callable function object to invoke on destruction.
+ */
+ template<
+ typename F
+ //! \cond
+ , typename = typename std::enable_if< detail::conjunction<
+ std::is_constructible<
+ data,
+ typename detail::move_or_copy_construct_ref< F, Func >::type,
+ typename std::is_nothrow_constructible< Func, typename detail::move_or_copy_construct_ref< F, Func >::type >::type
+ >,
+ detail::is_not_like_defer_guard< F >
+ >::value >::type
+ //! \endcond
+ >
+ defer_guard(F&& func)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
+ std::is_nothrow_constructible<
+ data,
+ typename detail::move_or_copy_construct_ref< F, Func >::type,
+ typename std::is_nothrow_constructible< Func, typename detail::move_or_copy_construct_ref< F, Func >::type >::type
+ >::value
+ )) :
+ m_data
+ (
+ static_cast< typename detail::move_or_copy_construct_ref< F, Func >::type >(func),
+ typename std::is_nothrow_constructible< Func, typename detail::move_or_copy_construct_ref< F, Func >::type >::type()
+ )
+ {
+ }
+
+ defer_guard(defer_guard const&) = delete;
+ defer_guard& operator= (defer_guard const&) = delete;
+
+ /*!
+ * \brief Invokes the wrapped callable function object and destroys the callable.
+ *
+ * **Throws:** Nothing, unless invoking the callable throws.
+ */
+ ~defer_guard() noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_invocable< Func& >::value))
+ {
+ m_data.m_func();
+ }
+};
+
+#if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
+template< typename Func >
+defer_guard(Func) -> defer_guard< Func >;
+#endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
+
+} // namespace scope
+
+//! \cond
+#if defined(BOOST_MSVC)
+#define BOOST_SCOPE_DETAIL_UNIQUE_VAR_TAG __COUNTER__
+#else
+#define BOOST_SCOPE_DETAIL_UNIQUE_VAR_TAG __LINE__
+#endif
+//! \endcond
+
+/*!
+ * \brief The macro creates a uniquely named defer guard.
+ *
+ * The macro should be followed by a function object that should be called
+ * on leaving the current scope. Usage example:
+ *
+ * ```
+ * BOOST_SCOPE_DEFER []
+ * {
+ * std::cout << "Hello world!" << std::endl;
+ * };
+ * ```
+ *
+ * \note Using this macro requires C++17.
+ */
+#define BOOST_SCOPE_DEFER \
+ boost::scope::defer_guard BOOST_JOIN(_boost_defer_guard_, BOOST_SCOPE_DETAIL_UNIQUE_VAR_TAG) =
+
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_DEFER_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/compact_storage.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/compact_storage.hpp
new file mode 100644
index 0000000000..b619e3f7d3
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/compact_storage.hpp
@@ -0,0 +1,102 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2022 Andrey Semashev
+ */
+/*!
+ * \file scope/detail/compact_storage.hpp
+ *
+ * This header contains utility helpers for implementing compact storage
+ * for class members. In particular, it allows to leverage empty base optimization (EBO).
+ */
+
+#ifndef BOOST_SCOPE_DETAIL_COMPACT_STORAGE_HPP_INCLUDED_
+#define BOOST_SCOPE_DETAIL_COMPACT_STORAGE_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+#include <boost/scope/detail/type_traits/is_final.hpp>
+#include <boost/scope/detail/type_traits/negation.hpp>
+#include <boost/scope/detail/type_traits/conjunction.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+//! The class allows to place data members in the tail padding of type \a T if the user's class derives from it
+template<
+ typename T,
+ typename Tag = void,
+ bool = detail::conjunction< std::is_class< T >, detail::negation< detail::is_final< T > > >::value
+>
+class compact_storage :
+ private T
+{
+public:
+ template< typename... Args >
+ constexpr compact_storage(Args&&... args) noexcept(std::is_nothrow_constructible< T, Args... >::value) :
+ T(static_cast< Args&& >(args)...)
+ {
+ }
+
+ compact_storage(compact_storage&&) = default;
+ compact_storage& operator= (compact_storage&&) = default;
+
+ compact_storage(compact_storage const&) = default;
+ compact_storage& operator= (compact_storage const&) = default;
+
+ T& get() noexcept
+ {
+ return *static_cast< T* >(this);
+ }
+
+ T const& get() const noexcept
+ {
+ return *static_cast< const T* >(this);
+ }
+};
+
+template< typename T, typename Tag >
+class compact_storage< T, Tag, false >
+{
+private:
+ T m_data;
+
+public:
+ template< typename... Args >
+ constexpr compact_storage(Args&&... args) noexcept(std::is_nothrow_constructible< T, Args... >::value) :
+ m_data(static_cast< Args&& >(args)...)
+ {
+ }
+
+ compact_storage(compact_storage&&) = default;
+ compact_storage& operator= (compact_storage&&) = default;
+
+ compact_storage(compact_storage const&) = default;
+ compact_storage& operator= (compact_storage const&) = default;
+
+ T& get() noexcept
+ {
+ return m_data;
+ }
+
+ T const& get() const noexcept
+ {
+ return m_data;
+ }
+};
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_DETAIL_COMPACT_STORAGE_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/config.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/config.hpp
new file mode 100644
index 0000000000..26821ea344
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/config.hpp
@@ -0,0 +1,50 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/detail/config.hpp
+ *
+ * This header contains Boost.Scope common configuration.
+ */
+
+#ifndef BOOST_SCOPE_DETAIL_CONFIG_HPP_INCLUDED_
+#define BOOST_SCOPE_DETAIL_CONFIG_HPP_INCLUDED_
+
+#include <boost/config.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+#if !(defined(__cpp_noexcept_function_type) && __cpp_noexcept_function_type >= 201510l) && !defined(_NOEXCEPT_TYPES_SUPPORTED)
+#define BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES
+#endif
+
+#if !defined(BOOST_SCOPE_DETAIL_DOC_ALT)
+#if !defined(BOOST_SCOPE_DOXYGEN)
+#define BOOST_SCOPE_DETAIL_DOC_ALT(alt, ...) __VA_ARGS__
+#else
+#define BOOST_SCOPE_DETAIL_DOC_ALT(alt, ...) alt
+#endif
+#endif
+
+#if !defined(BOOST_SCOPE_DETAIL_DOC_HIDDEN)
+#define BOOST_SCOPE_DETAIL_DOC_HIDDEN(...) BOOST_SCOPE_DETAIL_DOC_ALT(..., __VA_ARGS__)
+#endif
+
+#if !defined(BOOST_SCOPE_DETAIL_DOC)
+#if !defined(BOOST_SCOPE_DOXYGEN)
+#define BOOST_SCOPE_DETAIL_DOC(...)
+#else
+#define BOOST_SCOPE_DETAIL_DOC(...) __VA_ARGS__
+#endif
+#endif
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_DETAIL_CONFIG_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/footer.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/footer.hpp
new file mode 100644
index 0000000000..2d9b12e6ba
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/footer.hpp
@@ -0,0 +1,22 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+
+#if !defined(BOOST_SCOPE_ENABLE_WARNINGS)
+
+#if defined(_MSC_VER) && !defined(__clang__)
+
+#pragma warning(pop)
+
+#elif (defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \
+ && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406) || defined(__clang__)
+
+#pragma GCC diagnostic pop
+
+#endif
+
+#endif // !defined(BOOST_SCOPE_ENABLE_WARNINGS)
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/header.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/header.hpp
new file mode 100644
index 0000000000..fc99f16cf1
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/header.hpp
@@ -0,0 +1,49 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+
+#if !defined(BOOST_SCOPE_ENABLE_WARNINGS)
+
+#if defined(_MSC_VER) && !defined(__clang__)
+
+#pragma warning(push, 3)
+// unreferenced formal parameter
+#pragma warning(disable: 4100)
+// conditional expression is constant
+#pragma warning(disable: 4127)
+// function marked as __forceinline not inlined
+#pragma warning(disable: 4714)
+// decorated name length exceeded, name was truncated
+#pragma warning(disable: 4503)
+// qualifier applied to function type has no meaning; ignored
+#pragma warning(disable: 4180)
+// qualifier applied to reference type; ignored
+#pragma warning(disable: 4181)
+// unreachable code
+#pragma warning(disable: 4702)
+// destructor never returns, potential memory leak
+#pragma warning(disable: 4722)
+
+#elif (defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \
+ && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406) || defined(__clang__)
+
+// Note: clang-cl goes here as well, as it seems to support gcc-style warning control pragmas.
+
+#pragma GCC diagnostic push
+// unused parameter 'arg'
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+// unused function 'foo'
+#pragma GCC diagnostic ignored "-Wunused-function"
+
+#if defined(__clang__)
+// template argument uses unnamed type
+#pragma clang diagnostic ignored "-Wunnamed-type-template-args"
+#endif // defined(__clang__)
+
+#endif
+
+#endif // !defined(BOOST_SCOPE_ENABLE_WARNINGS)
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/is_nonnull_default_constructible.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/is_nonnull_default_constructible.hpp
new file mode 100644
index 0000000000..e6e86474f4
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/is_nonnull_default_constructible.hpp
@@ -0,0 +1,66 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/detail/is_nonnull_default_constructible.hpp
+ *
+ * This header contains definition of \c is_nonnull_default_constructible
+ * and \c is_nothrow_nonnull_default_constructible type traits. The type
+ * traits are useful for preventing default-construction of pointers to
+ * functions where a default-constructed function object is expected.
+ * Without it, default- or value-constructing a pointer to function would
+ * produce a function object that is not callable.
+ */
+
+#ifndef BOOST_SCOPE_DETAIL_IS_NONNULL_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_
+#define BOOST_SCOPE_DETAIL_IS_NONNULL_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+//! The type trait checks if \c T is not a pointer and is default-constructible
+template< typename T >
+struct is_nonnull_default_constructible :
+ public std::is_default_constructible< T >
+{
+};
+
+template< typename T >
+struct is_nonnull_default_constructible< T* > :
+ public std::false_type
+{
+};
+
+//! The type trait checks if \c T is not a pointer and is nothrow-default-constructible
+template< typename T >
+struct is_nothrow_nonnull_default_constructible :
+ public std::is_nothrow_default_constructible< T >
+{
+};
+
+template< typename T >
+struct is_nothrow_nonnull_default_constructible< T* > :
+ public std::false_type
+{
+};
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_DETAIL_IS_NONNULL_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/is_not_like.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/is_not_like.hpp
new file mode 100644
index 0000000000..3f07fa8023
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/is_not_like.hpp
@@ -0,0 +1,49 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/detail/is_not_like.hpp
+ *
+ * This header contains definition of \c is_not_like type trait.
+ */
+
+#ifndef BOOST_SCOPE_DETAIL_IS_NOT_LIKE_HPP_INCLUDED_
+#define BOOST_SCOPE_DETAIL_IS_NOT_LIKE_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+//! The type trait checks if \c T is not a possibly cv-reference-qualified specialization of \c Template
+template< typename T, template< typename... > class Template >
+struct is_not_like : public std::true_type { };
+template< typename T, template< typename... > class Template >
+struct is_not_like< T&, Template > : public is_not_like< T, Template > { };
+template< template< typename... > class Template, typename... Ts >
+struct is_not_like< Template< Ts... >, Template > : public std::false_type { };
+template< template< typename... > class Template, typename... Ts >
+struct is_not_like< const Template< Ts... >, Template > : public std::false_type { };
+template< template< typename... > class Template, typename... Ts >
+struct is_not_like< volatile Template< Ts... >, Template > : public std::false_type { };
+template< template< typename... > class Template, typename... Ts >
+struct is_not_like< const volatile Template< Ts... >, Template > : public std::false_type { };
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_DETAIL_IS_NOT_LIKE_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/move_or_copy_assign_ref.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/move_or_copy_assign_ref.hpp
new file mode 100644
index 0000000000..0e270f8c1b
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/move_or_copy_assign_ref.hpp
@@ -0,0 +1,52 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2022 Andrey Semashev
+ */
+/*!
+ * \file scope/detail/move_or_copy_assign_ref.hpp
+ *
+ * This header contains definition of \c move_or_copy_assign_ref type trait.
+ */
+
+#ifndef BOOST_SCOPE_DETAIL_MOVE_OR_COPY_ASSIGN_REF_HPP_INCLUDED_
+#define BOOST_SCOPE_DETAIL_MOVE_OR_COPY_ASSIGN_REF_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+//! The type trait produces an rvalue reference to \a From if \a To has a non-throwing assignment from a \a From rvalue and an lvalue reference otherwise.
+template< typename From, typename To = From >
+struct move_or_copy_assign_ref
+{
+ using type = typename std::conditional<
+ std::is_nothrow_assignable< To, From >::value,
+ From&&,
+ From const&
+ >::type;
+};
+
+template< typename From, typename To >
+struct move_or_copy_assign_ref< From&, To >
+{
+ using type = From&;
+};
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_DETAIL_MOVE_OR_COPY_ASSIGN_REF_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/move_or_copy_construct_ref.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/move_or_copy_construct_ref.hpp
new file mode 100644
index 0000000000..b3d3796868
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/move_or_copy_construct_ref.hpp
@@ -0,0 +1,52 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2022 Andrey Semashev
+ */
+/*!
+ * \file scope/detail/move_or_copy_construct_ref.hpp
+ *
+ * This header contains definition of \c move_or_copy_construct_ref type trait.
+ */
+
+#ifndef BOOST_SCOPE_DETAIL_MOVE_OR_COPY_CONSTRUCT_REF_HPP_INCLUDED_
+#define BOOST_SCOPE_DETAIL_MOVE_OR_COPY_CONSTRUCT_REF_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+//! The type trait produces an rvalue reference to \a From if \a To has a non-throwing constructor from a \a From rvalue and an lvalue reference otherwise.
+template< typename From, typename To = From >
+struct move_or_copy_construct_ref
+{
+ using type = typename std::conditional<
+ std::is_nothrow_constructible< To, From >::value,
+ From&&,
+ From const&
+ >::type;
+};
+
+template< typename From, typename To >
+struct move_or_copy_construct_ref< From&, To >
+{
+ using type = From&;
+};
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_DETAIL_MOVE_OR_COPY_CONSTRUCT_REF_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/conjunction.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/conjunction.hpp
new file mode 100644
index 0000000000..497f5721d2
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/conjunction.hpp
@@ -0,0 +1,53 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/detail/type_traits/conjunction.hpp
+ *
+ * This header contains definition of \c conjunction type trait.
+ */
+
+#ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_CONJUNCTION_HPP_INCLUDED_
+#define BOOST_SCOPE_DETAIL_TYPE_TRAITS_CONJUNCTION_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+#if (defined(__cpp_lib_logical_traits) && (__cpp_lib_logical_traits >= 201510l)) || \
+ (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (_MSC_FULL_VER >= 190023918) && (BOOST_CXX_VERSION >= 201703l))
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+using std::conjunction;
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#else
+
+#include <boost/type_traits/conjunction.hpp>
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+using boost::conjunction;
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#endif
+
+#endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_CONJUNCTION_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/disjunction.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/disjunction.hpp
new file mode 100644
index 0000000000..af1532dede
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/disjunction.hpp
@@ -0,0 +1,53 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/detail/type_traits/disjunction.hpp
+ *
+ * This header contains definition of \c disjunction type trait.
+ */
+
+#ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_DISJUNCTION_HPP_INCLUDED_
+#define BOOST_SCOPE_DETAIL_TYPE_TRAITS_DISJUNCTION_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+#if (defined(__cpp_lib_logical_traits) && (__cpp_lib_logical_traits >= 201510l)) || \
+ (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (_MSC_FULL_VER >= 190023918) && (BOOST_CXX_VERSION >= 201703l))
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+using std::disjunction;
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#else
+
+#include <boost/type_traits/disjunction.hpp>
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+using boost::disjunction;
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#endif
+
+#endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_DISJUNCTION_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_final.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_final.hpp
new file mode 100644
index 0000000000..57a2bf255b
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_final.hpp
@@ -0,0 +1,53 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/detail/type_traits/is_final.hpp
+ *
+ * This header contains definition of \c is_final type trait.
+ */
+
+#ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_FINAL_HPP_INCLUDED_
+#define BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_FINAL_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+#if (defined(__cpp_lib_is_final) && (__cpp_lib_is_final >= 201402l)) || \
+ (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (BOOST_CXX_VERSION >= 201402l))
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+using std::is_final;
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#else
+
+#include <boost/type_traits/is_final.hpp>
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+using boost::is_final;
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#endif
+
+#endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_FINAL_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_invocable.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_invocable.hpp
new file mode 100644
index 0000000000..987bf1b10b
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_invocable.hpp
@@ -0,0 +1,63 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/detail/type_traits/is_invocable.hpp
+ *
+ * This header contains definition of \c is_invocable type trait.
+ */
+
+#ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_INVOCABLE_HPP_INCLUDED_
+#define BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_INVOCABLE_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+#if (defined(__cpp_lib_is_invocable) && (__cpp_lib_is_invocable >= 201703l)) || \
+ (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (BOOST_CXX_VERSION >= 201703l))
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+using std::is_invocable;
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#else
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+// A simplified implementation that does not support member function pointers
+template< typename Func, typename... Args >
+struct is_invocable_impl
+{
+ template< typename F = Func, typename = decltype(std::declval< F >()(std::declval< Args >()...)) >
+ static std::true_type _check_invocable(int);
+ static std::false_type _check_invocable(...);
+
+ using type = decltype(is_invocable_impl::_check_invocable(0));
+};
+
+template< typename Func, typename... Args >
+struct is_invocable : public is_invocable_impl< Func, Args... >::type { };
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#endif
+
+#endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_INVOCABLE_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_nothrow_invocable.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_nothrow_invocable.hpp
new file mode 100644
index 0000000000..5510a5fb0a
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_nothrow_invocable.hpp
@@ -0,0 +1,69 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/detail/type_traits/is_nothrow_invocable.hpp
+ *
+ * This header contains definition of \c is_nothrow_invocable type trait.
+ */
+
+#ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_NOTHROW_INVOCABLE_HPP_INCLUDED_
+#define BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_NOTHROW_INVOCABLE_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+#if (defined(__cpp_lib_is_invocable) && (__cpp_lib_is_invocable >= 201703l)) || \
+ (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (BOOST_CXX_VERSION >= 201703l))
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+using std::is_nothrow_invocable;
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#else
+
+#include <boost/scope/detail/type_traits/is_invocable.hpp>
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+template< bool, typename Func, typename... Args >
+struct is_nothrow_invocable_impl
+{
+ using type = std::false_type;
+};
+
+template< typename Func, typename... Args >
+struct is_nothrow_invocable_impl< true, Func, Args... >
+{
+ using type = std::integral_constant< bool, noexcept(std::declval< Func >()(std::declval< Args >()...)) >;
+};
+
+template< typename Func, typename... Args >
+struct is_nothrow_invocable :
+ public is_nothrow_invocable_impl< detail::is_invocable< Func, Args... >::value, Func, Args... >::type
+{
+};
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#endif
+
+#endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_NOTHROW_INVOCABLE_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_nothrow_swappable.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_nothrow_swappable.hpp
new file mode 100644
index 0000000000..08e3171655
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_nothrow_swappable.hpp
@@ -0,0 +1,53 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/detail/type_traits/is_nothrow_swappable.hpp
+ *
+ * This header contains definition of \c is_nothrow_swappable type trait.
+ */
+
+#ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_NOTHROW_SWAPPABLE_HPP_INCLUDED_
+#define BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_NOTHROW_SWAPPABLE_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+#if (defined(__cpp_lib_is_swappable) && (__cpp_lib_is_swappable >= 201603l)) || \
+ (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (_MSC_FULL_VER >= 190024210) && (BOOST_CXX_VERSION >= 201703l))
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+using std::is_nothrow_swappable;
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#else
+
+#include <boost/type_traits/is_nothrow_swappable.hpp>
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+using boost::is_nothrow_swappable;
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#endif
+
+#endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_NOTHROW_SWAPPABLE_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_swappable.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_swappable.hpp
new file mode 100644
index 0000000000..c84a147913
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/is_swappable.hpp
@@ -0,0 +1,53 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/detail/type_traits/is_swappable.hpp
+ *
+ * This header contains definition of \c is_swappable type trait.
+ */
+
+#ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_SWAPPABLE_HPP_INCLUDED_
+#define BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_SWAPPABLE_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+#if (defined(__cpp_lib_is_swappable) && (__cpp_lib_is_swappable >= 201603l)) || \
+ (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (_MSC_FULL_VER >= 190024210) && (BOOST_CXX_VERSION >= 201703l))
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+using std::is_swappable;
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#else
+
+#include <boost/type_traits/is_swappable.hpp>
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+using boost::is_swappable;
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#endif
+
+#endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_IS_SWAPPABLE_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/negation.hpp b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/negation.hpp
new file mode 100644
index 0000000000..f78f52f22c
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/detail/type_traits/negation.hpp
@@ -0,0 +1,53 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/detail/type_traits/negation.hpp
+ *
+ * This header contains definition of \c negation type trait.
+ */
+
+#ifndef BOOST_SCOPE_DETAIL_TYPE_TRAITS_NEGATION_HPP_INCLUDED_
+#define BOOST_SCOPE_DETAIL_TYPE_TRAITS_NEGATION_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+#if (defined(__cpp_lib_logical_traits) && (__cpp_lib_logical_traits >= 201510l)) || \
+ (defined(BOOST_MSSTL_VERSION) && (BOOST_MSSTL_VERSION >= 140) && (_MSC_FULL_VER >= 190023918) && (BOOST_CXX_VERSION >= 201703l))
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+using std::negation;
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#else
+
+#include <boost/type_traits/negation.hpp>
+
+namespace boost {
+namespace scope {
+namespace detail {
+
+using boost::negation;
+
+} // namespace detail
+} // namespace scope
+} // namespace boost
+
+#endif
+
+#endif // BOOST_SCOPE_DETAIL_TYPE_TRAITS_NEGATION_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/error_code_checker.hpp b/contrib/restricted/boost/scope/include/boost/scope/error_code_checker.hpp
new file mode 100644
index 0000000000..1481e14f52
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/error_code_checker.hpp
@@ -0,0 +1,103 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/error_code_checker.hpp
+ *
+ * This header contains definition of \c error_code_checker type.
+ */
+
+#ifndef BOOST_SCOPE_ERROR_CODE_CHECKER_HPP_INCLUDED_
+#define BOOST_SCOPE_ERROR_CODE_CHECKER_HPP_INCLUDED_
+
+#include <boost/core/addressof.hpp>
+#include <boost/scope/detail/config.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+
+/*!
+ * \brief A predicate for checking whether an error code indicates error.
+ *
+ * The predicate captures a reference to an external error code object, which it
+ * tests for an error indication when called. The error code object must remain
+ * valid for the whole lifetime duration of the predicate.
+ *
+ * For an error code object `ec`, an expression `!ec` must be valid, never throw exceptions,
+ * and return a value contextually convertible to `bool`. If the returned value converts
+ * to `false`, then this is taken as an error indication, and the predicate returns `true`.
+ * Otherwise, the predicate returns `false`.
+ *
+ * A few examples of error code types:
+ *
+ * \li `std::error_code` or `boost::system::error_code`,
+ * \li `std::expected`, `boost::outcome_v2::basic_outcome` or `boost::outcome_v2::basic_result`,
+ * \li `int`, where the value of 0 indicates no error,
+ * \li `bool`, where the value of `false` indicates no error,
+ * \li `T*`, where a null pointer indicates no error.
+ *
+ * \tparam ErrorCode Error code type.
+ */
+template< typename ErrorCode >
+class error_code_checker
+{
+public:
+ //! Predicate result type
+ using result_type = bool;
+
+private:
+ ErrorCode* m_error_code;
+
+public:
+ /*!
+ * \brief Constructs the predicate.
+ *
+ * Upon construction, the predicate saves a reference to the external error code object.
+ * The referenced object must remain valid for the whole lifetime duration of the predicate.
+ *
+ * **Throws:** Nothing.
+ */
+ explicit error_code_checker(ErrorCode& ec) noexcept :
+ m_error_code(boost::addressof(ec))
+ {
+ }
+
+ /*!
+ * \brief Checks if the error code indicates error.
+ *
+ * **Throws:** Nothing.
+ *
+ * \returns As if `!!ec`, where `ec` is the error code object passed to the predicate constructor.
+ */
+ result_type operator()() const noexcept
+ {
+ return !!(*m_error_code);
+ }
+};
+
+/*!
+ * \brief Creates a predicate for checking whether an exception is being thrown
+ *
+ * **Throws:** Nothing.
+ */
+template< typename ErrorCode >
+inline error_code_checker< ErrorCode > check_error_code(ErrorCode& ec) noexcept
+{
+ return error_code_checker< ErrorCode >(ec);
+}
+
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_ERROR_CODE_CHECKER_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/exception_checker.hpp b/contrib/restricted/boost/scope/include/boost/scope/exception_checker.hpp
new file mode 100644
index 0000000000..a46b4801b7
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/exception_checker.hpp
@@ -0,0 +1,106 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/exception_checker.hpp
+ *
+ * This header contains definition of \c exception_checker type.
+ */
+
+#ifndef BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_
+#define BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_
+
+#include <boost/assert.hpp>
+#include <boost/scope/detail/config.hpp>
+#include <boost/core/uncaught_exceptions.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+
+/*!
+ * \brief A predicate for checking whether an exception is being thrown.
+ *
+ * On construction, the predicate captures the current number of uncaught exceptions,
+ * which it then compares with the number of uncaught exceptions at the point when it
+ * is called. If the number increased then a new exception is detected and the predicate
+ * returns \c true.
+ *
+ * \note This predicate is designed for a specific use case with scope guards created on
+ * the stack. It is incompatible with C++20 coroutines and similar facilities (e.g.
+ * fibers and userspace context switching), where the thread of execution may be
+ * suspended after the predicate captures the number of uncaught exceptions and
+ * then resumed in a different context, where the number of uncaught exceptions
+ * has changed. Similarly, it is incompatible with usage patterns where the predicate
+ * is cached after construction and is invoked after the thread has left the scope
+ * where the predicate was constructed (e.g. when the predicate is stored as a class
+ * data member or a namespace-scope variable).
+ */
+class exception_checker
+{
+public:
+ //! Predicate result type
+ using result_type = bool;
+
+private:
+ unsigned int m_uncaught_count;
+
+public:
+ /*!
+ * \brief Constructs the predicate.
+ *
+ * Upon construction, the predicate saves the current number of uncaught exceptions.
+ * This information will be used when calling the predicate to detect if a new
+ * exception is being thrown.
+ *
+ * **Throws:** Nothing.
+ */
+ exception_checker() noexcept :
+ m_uncaught_count(boost::core::uncaught_exceptions())
+ {
+ }
+
+ /*!
+ * \brief Checks if an exception is being thrown.
+ *
+ * **Throws:** Nothing.
+ *
+ * \returns \c true if the number of uncaught exceptions at the point of call is
+ * greater than that at the point of construction of the predicate,
+ * otherwise \c false.
+ */
+ result_type operator()() const noexcept
+ {
+ const unsigned int uncaught_count = boost::core::uncaught_exceptions();
+ // If this assertion fails, the predicate is likely being used in an unsupported
+ // way, where it is called in a different scope or thread context from where
+ // it was constructed.
+ BOOST_ASSERT((uncaught_count - m_uncaught_count) <= 1u);
+ return uncaught_count > m_uncaught_count;
+ }
+};
+
+/*!
+ * \brief Creates a predicate for checking whether an exception is being thrown
+ *
+ * **Throws:** Nothing.
+ */
+inline exception_checker check_exception() noexcept
+{
+ return exception_checker();
+}
+
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_EXCEPTION_CHECKER_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/fd_deleter.hpp b/contrib/restricted/boost/scope/include/boost/scope/fd_deleter.hpp
new file mode 100644
index 0000000000..92f3ee21f5
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/fd_deleter.hpp
@@ -0,0 +1,82 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/fd_deleter.hpp
+ *
+ * This header contains definition of a deleter function object for
+ * POSIX-like file descriptors for use with \c unique_resource.
+ */
+
+#ifndef BOOST_SCOPE_FD_DELETER_HPP_INCLUDED_
+#define BOOST_SCOPE_FD_DELETER_HPP_INCLUDED_
+
+#include <boost/scope/detail/config.hpp>
+
+#if !defined(BOOST_WINDOWS)
+#include <unistd.h>
+#if defined(hpux) || defined(_hpux) || defined(__hpux)
+#include <cerrno>
+#endif
+#else // !defined(BOOST_WINDOWS)
+#include <io.h>
+#endif // !defined(BOOST_WINDOWS)
+
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+
+//! POSIX-like file descriptor deleter
+struct fd_deleter
+{
+ using result_type = void;
+
+ //! Closes the file descriptor
+ result_type operator() (int fd) const noexcept
+ {
+#if !defined(BOOST_WINDOWS)
+#if defined(hpux) || defined(_hpux) || defined(__hpux)
+ // Some systems don't close the file descriptor in case if the thread is interrupted by a signal and close(2) returns EINTR.
+ // Other (most) systems do close the file descriptor even when when close(2) returns EINTR, and attempting to close it
+ // again could close a different file descriptor that was opened by a different thread.
+ //
+ // Future POSIX standards will likely fix this by introducing posix_close (see https://www.austingroupbugs.net/view.php?id=529)
+ // and prohibiting returning EINTR from close(2), but we still have to support older systems where this new behavior is not available and close(2)
+ // behaves differently between systems.
+ int res;
+ while (true)
+ {
+ res = ::close(fd);
+ if (BOOST_UNLIKELY(res < 0))
+ {
+ int err = errno;
+ if (err == EINTR)
+ continue;
+ }
+
+ break;
+ }
+#else
+ ::close(fd);
+#endif
+#else // !defined(BOOST_WINDOWS)
+ ::_close(fd);
+#endif // !defined(BOOST_WINDOWS)
+ }
+};
+
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_FD_DELETER_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/fd_resource_traits.hpp b/contrib/restricted/boost/scope/include/boost/scope/fd_resource_traits.hpp
new file mode 100644
index 0000000000..76177979ca
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/fd_resource_traits.hpp
@@ -0,0 +1,49 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/fd_resource_traits.hpp
+ *
+ * This header contains definition of \c unique_resource traits
+ * for compatibility with POSIX-like file descriptors.
+ */
+
+#ifndef BOOST_SCOPE_FD_RESOURCE_TRAITS_HPP_INCLUDED_
+#define BOOST_SCOPE_FD_RESOURCE_TRAITS_HPP_INCLUDED_
+
+#include <boost/scope/detail/config.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+
+//! POSIX-like file descriptor resource traits
+struct fd_resource_traits
+{
+ //! Creates a default fd value
+ static int make_default() noexcept
+ {
+ return -1;
+ }
+
+ //! Tests if the fd is allocated (valid)
+ static bool is_allocated(int fd) noexcept
+ {
+ return fd >= 0;
+ }
+};
+
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_FD_RESOURCE_TRAITS_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/scope_exit.hpp b/contrib/restricted/boost/scope/include/boost/scope/scope_exit.hpp
new file mode 100644
index 0000000000..0f03ff4c47
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/scope_exit.hpp
@@ -0,0 +1,560 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/scope_exit.hpp
+ *
+ * This header contains definition of \c scope_exit template.
+ */
+
+#ifndef BOOST_SCOPE_SCOPE_EXIT_HPP_INCLUDED_
+#define BOOST_SCOPE_SCOPE_EXIT_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+#include <boost/scope/detail/is_not_like.hpp>
+#include <boost/scope/detail/compact_storage.hpp>
+#include <boost/scope/detail/move_or_copy_construct_ref.hpp>
+#include <boost/scope/detail/is_nonnull_default_constructible.hpp>
+#include <boost/scope/detail/type_traits/conjunction.hpp>
+#include <boost/scope/detail/type_traits/is_invocable.hpp>
+#include <boost/scope/detail/type_traits/is_nothrow_invocable.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+
+template< typename Func, typename Cond >
+class scope_exit;
+
+namespace detail {
+
+// Workaround for clang < 5.0 which can't pass scope_exit as a template template parameter from within scope_exit definition
+template< typename T >
+using is_not_like_scope_exit = detail::is_not_like< T, scope_exit >;
+
+//! The scope guard used to invoke the condition and action functions in case of exception during scope guard construction
+template< typename Func, typename Cond >
+class init_guard
+{
+private:
+ Func& m_func;
+ Cond& m_cond;
+ bool m_active;
+
+public:
+ init_guard(Func& func, Cond& cond, bool active) noexcept :
+ m_func(func),
+ m_cond(cond),
+ m_active(active)
+ {
+ }
+
+ init_guard(init_guard const&) = delete;
+ init_guard& operator= (init_guard const&) = delete;
+
+ ~init_guard()
+ noexcept(detail::conjunction<
+ detail::is_nothrow_invocable< Func& >,
+ detail::is_nothrow_invocable< Cond& >
+ >::value)
+ {
+ if (m_active && m_cond())
+ m_func();
+ }
+
+ Func&& get_func() noexcept
+ {
+ return static_cast< Func&& >(m_func);
+ }
+
+ Cond&& get_cond() noexcept
+ {
+ return static_cast< Cond&& >(m_cond);
+ }
+
+ void deactivate() noexcept
+ {
+ m_active = false;
+ }
+};
+
+} // namespace detail
+
+/*!
+ * \brief A predicate that always returns \c true.
+ *
+ * This predicate can be used as the default condition function object for
+ * \c scope_exit and similar scope guards.
+ */
+class always_true
+{
+public:
+ //! Predicate result type
+ using result_type = bool;
+
+ /*!
+ * **Throws:** Nothing.
+ *
+ * \returns \c true.
+ */
+ result_type operator()() const noexcept
+ {
+ return true;
+ }
+};
+
+/*!
+ * \brief Scope exit guard that conditionally invokes a function upon leaving the scope.
+ *
+ * The scope guard wraps two function objects: the scope guard action and
+ * a condition for invoking the action. Both function objects must be
+ * callable with no arguments and can be one of:
+ *
+ * \li A user-defined class with a public `operator()`.
+ * \li An lvalue reference to such class.
+ * \li An lvalue reference or pointer to function taking no arguments.
+ *
+ * The condition function object `operator()` must return a value
+ * contextually convertible to \c true, if the action function object
+ * is allowed to be executed, and \c false otherwise. Additionally,
+ * the condition function object `operator()` must not throw, as
+ * otherwise the action function object may not be called.
+ *
+ * The condition function object is optional, and if not specified in
+ * template parameters, the scope guard will operate as if the condition
+ * always returns \c true.
+ *
+ * The scope guard can be in either active or inactive state. By default,
+ * the constructed scope guard is active. When active, and condition
+ * function object returns \c true, the scope guard invokes the wrapped
+ * action function object on destruction. Otherwise, the scope guard
+ * does not call the wrapped action function object.
+ *
+ * The scope guard can be made inactive by moving-from the scope guard
+ * or calling `set_active(false)`. An inactive scope guard can be made
+ * active by calling `set_active(true)`. If a moved-from scope guard
+ * is active on destruction, the behavior is undefined.
+ *
+ * \tparam Func Scope guard action function object type.
+ * \tparam Cond Scope guard condition function object type.
+ */
+template< typename Func, typename Cond = always_true >
+class scope_exit
+{
+//! \cond
+private:
+ struct func_holder :
+ public detail::compact_storage< Func >
+ {
+ using func_base = detail::compact_storage< Func >;
+
+ template<
+ typename F,
+ typename C,
+ typename = typename std::enable_if< std::is_constructible< Func, F >::value >::type
+ >
+ explicit func_holder(F&& func, C&& cond, bool active, std::true_type) noexcept :
+ func_base(static_cast< F&& >(func))
+ {
+ }
+
+ template<
+ typename F,
+ typename C,
+ typename = typename std::enable_if< std::is_constructible< Func, F >::value >::type
+ >
+ explicit func_holder(F&& func, C&& cond, bool active, std::false_type) :
+ func_holder(detail::init_guard< F, C >(func, cond, active))
+ {
+ }
+
+ private:
+ template< typename F, typename C >
+ explicit func_holder(detail::init_guard< F, C >&& init) :
+ func_base(init.get_func())
+ {
+ init.deactivate();
+ }
+ };
+
+ struct cond_holder :
+ public detail::compact_storage< Cond >
+ {
+ using cond_base = detail::compact_storage< Cond >;
+
+ template<
+ typename C,
+ typename = typename std::enable_if< std::is_constructible< Cond, C >::value >::type
+ >
+ explicit cond_holder(C&& cond, Func& func, bool active, std::true_type) noexcept :
+ cond_base(static_cast< C&& >(cond))
+ {
+ }
+
+ template<
+ typename C,
+ typename = typename std::enable_if< std::is_constructible< Cond, C >::value >::type
+ >
+ explicit cond_holder(C&& cond, Func& func, bool active, std::false_type) :
+ cond_holder(detail::init_guard< Func&, C >(func, cond, active))
+ {
+ }
+
+ private:
+ template< typename C >
+ explicit cond_holder(detail::init_guard< Func&, C >&& init) :
+ cond_base(init.get_cond())
+ {
+ init.deactivate();
+ }
+ };
+
+ struct data :
+ public func_holder,
+ public cond_holder
+ {
+ bool m_active;
+
+ template<
+ typename F,
+ typename C,
+ typename = typename std::enable_if< detail::conjunction<
+ std::is_constructible< func_holder, F, C, bool, typename std::is_nothrow_constructible< Func, F >::type >,
+ std::is_constructible< cond_holder, C, Func&, bool, typename std::is_nothrow_constructible< Cond, C >::type >
+ >::value >::type
+ >
+ explicit data(F&& func, C&& cond, bool active)
+ noexcept(detail::conjunction< std::is_nothrow_constructible< Func, F >, std::is_nothrow_constructible< Cond, C > >::value) :
+ func_holder(static_cast< F&& >(func), static_cast< C&& >(cond), active, typename std::is_nothrow_constructible< Func, F >::type()),
+ cond_holder(static_cast< C&& >(cond), func_holder::get(), active, typename std::is_nothrow_constructible< Cond, C >::type()),
+ m_active(active)
+ {
+ }
+
+ Func& get_func() noexcept
+ {
+ return func_holder::get();
+ }
+
+ Func const& get_func() const noexcept
+ {
+ return func_holder::get();
+ }
+
+ Cond& get_cond() noexcept
+ {
+ return cond_holder::get();
+ }
+
+ Cond const& get_cond() const noexcept
+ {
+ return cond_holder::get();
+ }
+
+ bool deactivate() noexcept
+ {
+ bool active = m_active;
+ m_active = false;
+ return active;
+ }
+ };
+
+ data m_data;
+
+//! \endcond
+public:
+ /*!
+ * \brief Constructs a scope guard with a given callable action function object.
+ *
+ * **Requires:** \c Func is constructible from \a func. \c Cond is nothrow default-constructible
+ * and is not a pointer to function.
+ *
+ * \note The requirement for \c Cond default constructor to be non-throwing is to allow for
+ * the condition function object to be called in case if constructing either function
+ * object throws.
+ *
+ * **Effects:** Constructs the scope guard as if by calling
+ * `scope_exit(std::forward< F >(func), Cond(), active)`.
+ *
+ * **Throws:** Nothing, unless construction of the function objects throw.
+ *
+ * \param func The callable action function object to invoke on destruction.
+ * \param active Indicates whether the scope guard should be active upon construction.
+ *
+ * \post `this->active() == active`
+ */
+ template<
+ typename F
+ //! \cond
+ , typename = typename std::enable_if< detail::conjunction<
+ detail::is_nothrow_nonnull_default_constructible< Cond >,
+ std::is_constructible<
+ data,
+ typename detail::move_or_copy_construct_ref< F, Func >::type,
+ typename detail::move_or_copy_construct_ref< Cond >::type,
+ bool
+ >,
+ detail::is_not_like_scope_exit< F >
+ >::value >::type
+ //! \endcond
+ >
+ explicit scope_exit(F&& func, bool active = true)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
+ std::is_nothrow_constructible<
+ data,
+ typename detail::move_or_copy_construct_ref< F, Func >::type,
+ typename detail::move_or_copy_construct_ref< Cond >::type,
+ bool
+ >::value
+ )) :
+ m_data
+ (
+ static_cast< typename detail::move_or_copy_construct_ref< F, Func >::type >(func),
+ static_cast< typename detail::move_or_copy_construct_ref< Cond >::type >(Cond()),
+ active
+ )
+ {
+ }
+
+ /*!
+ * \brief Constructs a scope guard with a given callable action and condition function objects.
+ *
+ * **Requires:** \c Func is constructible from \a func. \c Cond is constructible from \a cond.
+ *
+ * **Effects:** If \c Func is nothrow constructible from `F&&` then constructs \c Func from
+ * `std::forward< F >(func)`, otherwise constructs from `func`. If \c Cond is
+ * nothrow constructible from `C&&` then constructs \c Cond from
+ * `std::forward< C >(cond)`, otherwise constructs from `cond`.
+ *
+ * If \c Func or \c Cond construction throws and \a active is \c true, invokes
+ * \a cond and, if it returns \c true, \a func before returning with the exception.
+ *
+ * **Throws:** Nothing, unless construction of the function objects throw.
+ *
+ * \param func The callable action function object to invoke on destruction.
+ * \param cond The callable condition function object.
+ * \param active Indicates whether the scope guard should be active upon construction.
+ *
+ * \post `this->active() == active`
+ */
+ template<
+ typename F,
+ typename C
+ //! \cond
+ , typename = typename std::enable_if< detail::conjunction<
+ detail::is_invocable< C const& >,
+ std::is_constructible<
+ data,
+ typename detail::move_or_copy_construct_ref< F, Func >::type,
+ typename detail::move_or_copy_construct_ref< C, Cond >::type,
+ bool
+ >
+ >::value >::type
+ //! \endcond
+ >
+ explicit scope_exit(F&& func, C&& cond, bool active = true)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
+ std::is_nothrow_constructible<
+ data,
+ typename detail::move_or_copy_construct_ref< F, Func >::type,
+ typename detail::move_or_copy_construct_ref< C, Cond >::type,
+ bool
+ >::value
+ )) :
+ m_data
+ (
+ static_cast< typename detail::move_or_copy_construct_ref< F, Func >::type >(func),
+ static_cast< typename detail::move_or_copy_construct_ref< C, Cond >::type >(cond),
+ active
+ )
+ {
+ }
+
+ /*!
+ * \brief Move-constructs a scope guard.
+ *
+ * **Requires:** \c Func and \c Cond are nothrow move-constructible or copy-constructible.
+ *
+ * **Effects:** If \c Func is nothrow move-constructible then move-constructs \c Func from
+ * a member of \a that, otherwise copy-constructs \c Func. If \c Cond is nothrow
+ * move-constructible then move-constructs \c Cond from a member of \a that,
+ * otherwise copy-constructs \c Cond.
+ *
+ * If \c Func or \c Cond construction throws and `that.active() == true`, invokes
+ * \c Cond object stored in \a that and, if it returns \c true, \a Func object
+ * (either the newly constructed one, if its construction succeeded, or the original
+ * one stored in \a that) before returning with the exception.
+ *
+ * If the construction succeeds, marks \a that as inactive.
+ *
+ * **Throws:** Nothing, unless move-construction of the function objects throw.
+ *
+ * \param that Move source.
+ *
+ * \post `that.active() == false`
+ */
+ //! \cond
+ template<
+ bool Requires = std::is_constructible<
+ data,
+ typename detail::move_or_copy_construct_ref< Func >::type,
+ typename detail::move_or_copy_construct_ref< Cond >::type,
+ bool
+ >::value,
+ typename = typename std::enable_if< Requires >::type
+ >
+ //! \endcond
+ scope_exit(scope_exit&& that)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
+ std::is_nothrow_constructible<
+ data,
+ typename detail::move_or_copy_construct_ref< Func >::type,
+ typename detail::move_or_copy_construct_ref< Cond >::type,
+ bool
+ >::value
+ )) :
+ m_data
+ (
+ static_cast< typename detail::move_or_copy_construct_ref< Func >::type >(that.m_data.get_func()),
+ static_cast< typename detail::move_or_copy_construct_ref< Cond >::type >(that.m_data.get_cond()),
+ that.m_data.deactivate()
+ )
+ {
+ }
+
+ scope_exit& operator= (scope_exit&&) = delete;
+
+ scope_exit(scope_exit const&) = delete;
+ scope_exit& operator= (scope_exit const&) = delete;
+
+ /*!
+ * \brief If `active() == true`, and invoking the condition function object returns \c true, invokes
+ * the wrapped callable action function object. Destroys the function objects.
+ *
+ * **Throws:** Nothing, unless invoking a function object throws.
+ */
+ ~scope_exit()
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
+ detail::conjunction<
+ detail::is_nothrow_invocable< Func& >,
+ detail::is_nothrow_invocable< Cond& >
+ >::value
+ ))
+ {
+ if (BOOST_LIKELY(m_data.m_active && m_data.get_cond()()))
+ m_data.get_func()();
+ }
+
+ /*!
+ * \brief Returns \c true if the scope guard is active, otherwise \c false.
+ *
+ * \note This method does not call the condition function object specified on construction.
+ *
+ * **Throws:** Nothing.
+ */
+ bool active() const noexcept
+ {
+ return m_data.m_active;
+ }
+
+ /*!
+ * \brief Activates or deactivates the scope guard.
+ *
+ * **Throws:** Nothing.
+ *
+ * \param active The active status to set.
+ *
+ * \post `this->active() == active`
+ */
+ void set_active(bool active) noexcept
+ {
+ m_data.m_active = active;
+ }
+};
+
+#if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
+template< typename Func >
+explicit scope_exit(Func) -> scope_exit< Func >;
+
+template< typename Func >
+explicit scope_exit(Func, bool) -> scope_exit< Func >;
+
+template< typename Func, typename Cond >
+explicit scope_exit(Func, Cond) -> scope_exit< Func, Cond >;
+
+template< typename Func, typename Cond >
+explicit scope_exit(Func, Cond, bool) -> scope_exit< Func, Cond >;
+#endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
+
+/*!
+ * \brief Creates a scope guard with a given action function object.
+ *
+ * **Effects:** Constructs a scope guard as if by calling
+ * `scope_exit< std::decay_t< F > >(std::forward< F >(func), active)`.
+ *
+ * \param func The callable action function object to invoke on destruction.
+ * \param active Indicates whether the scope guard should be active upon construction.
+ */
+template< typename F >
+inline scope_exit< typename std::decay< F >::type > make_scope_exit(F&& func, bool active = true)
+ noexcept(std::is_nothrow_constructible<
+ scope_exit< typename std::decay< F >::type >,
+ F,
+ bool
+ >::value)
+{
+ return scope_exit< typename std::decay< F >::type >(static_cast< F&& >(func), active);
+}
+
+/*!
+ * \brief Creates a conditional scope guard with given callable function objects.
+ *
+ * **Effects:** Constructs a scope guard as if by calling
+ * `scope_exit< std::decay_t< F >, std::decay_t< C > >(
+ * std::forward< F >(func), std::forward< C >(cond), active)`.
+ *
+ * \param func The callable action function object to invoke on destruction.
+ * \param cond The callable condition function object.
+ * \param active Indicates whether the scope guard should be active upon construction.
+ */
+template< typename F, typename C >
+inline
+#if !defined(BOOST_SCOPE_DOXYGEN)
+typename std::enable_if<
+ std::is_constructible<
+ scope_exit< typename std::decay< F >::type, typename std::decay< C >::type >,
+ F,
+ C,
+ bool
+ >::value,
+ scope_exit< typename std::decay< F >::type, typename std::decay< C >::type >
+>::type
+#else
+scope_exit< typename std::decay< F >::type, typename std::decay< C >::type >
+#endif
+make_scope_exit(F&& func, C&& cond, bool active = true)
+ noexcept(std::is_nothrow_constructible<
+ scope_exit< typename std::decay< F >::type, typename std::decay< C >::type >,
+ F,
+ C,
+ bool
+ >::value)
+{
+ return scope_exit< typename std::decay< F >::type, typename std::decay< C >::type >(static_cast< F&& >(func), static_cast< C&& >(cond), active);
+}
+
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_SCOPE_EXIT_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/scope_fail.hpp b/contrib/restricted/boost/scope/include/boost/scope/scope_fail.hpp
new file mode 100644
index 0000000000..a9c2368c57
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/scope_fail.hpp
@@ -0,0 +1,265 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2022 Andrey Semashev
+ */
+/*!
+ * \file scope/scope_fail.hpp
+ *
+ * This header contains definition of \c scope_fail template.
+ */
+
+#ifndef BOOST_SCOPE_SCOPE_FAIL_HPP_INCLUDED_
+#define BOOST_SCOPE_SCOPE_FAIL_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+#include <boost/scope/exception_checker.hpp>
+#include <boost/scope/scope_exit.hpp>
+#include <boost/scope/detail/is_not_like.hpp>
+#include <boost/scope/detail/type_traits/conjunction.hpp>
+#include <boost/scope/detail/type_traits/is_invocable.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+
+template< typename Func, typename Cond >
+class scope_fail;
+
+namespace detail {
+
+// Workaround for clang < 5.0 which can't pass scope_fail as a template template parameter from within scope_fail definition
+template< typename T >
+using is_not_like_scope_fail = detail::is_not_like< T, scope_fail >;
+
+} // namespace detail
+
+/*!
+ * \brief Scope exit guard that invokes a function upon leaving the scope, if
+ * a failure condition is satisfied.
+ *
+ * The scope guard wraps two function objects: the scope guard action and
+ * a failure condition for invoking the action. Both function objects must
+ * be callable with no arguments and can be one of:
+ *
+ * \li A user-defined class with a public `operator()`.
+ * \li An lvalue reference to such class.
+ * \li An lvalue reference or pointer to function taking no arguments.
+ *
+ * The condition function object `operator()` must return a value
+ * contextually convertible to \c true, if the failure is detected and the
+ * action function object is allowed to be executed, and \c false otherwise.
+ * Additionally, the failure condition function object `operator()` must not
+ * throw, as otherwise the action function object may not be called. If not
+ * specified, the default failure condition checks whether the scope is left
+ * due to an exception - the action function object will not be called if
+ * the scope is left normally.
+ *
+ * \sa scope_exit
+ * \sa scope_success
+ *
+ * \tparam Func Scope guard action function object type.
+ * \tparam Cond Scope guard failure condition function object type.
+ */
+template< typename Func, typename Cond = exception_checker >
+class scope_fail :
+ public scope_exit< Func, Cond >
+{
+//! \cond
+private:
+ using base_type = scope_exit< Func, Cond >;
+
+//! \endcond
+public:
+ /*!
+ * \brief Constructs a scope guard with a given callable function object.
+ *
+ * **Requires:** \c Func is constructible from \a func. \c Cond is nothrow default-constructible.
+ *
+ * **Effects:** Constructs the scope guard as if by calling
+ * `scope_fail(std::forward< F >(func), Cond(), active)`.
+ *
+ * **Throws:** Nothing, unless construction of the function objects throw.
+ *
+ * \param func The callable action function object to invoke on destruction.
+ * \param active Indicates whether the scope guard should be active upon construction.
+ *
+ * \post `this->active() == active`
+ */
+ template<
+ typename F
+ //! \cond
+ , typename = typename std::enable_if< detail::conjunction<
+ std::is_constructible< base_type, F, bool >,
+ detail::is_not_like_scope_fail< F >
+ >::value >::type
+ //! \endcond
+ >
+ explicit scope_fail(F&& func, bool active = true)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_constructible< base_type, F, bool >::value)) :
+ base_type(static_cast< F&& >(func), active)
+ {
+ }
+
+ /*!
+ * \brief Constructs a scope guard with a given callable action and failure condition function objects.
+ *
+ * **Requires:** \c Func is constructible from \a func. \c Cond is constructible from \a cond.
+ *
+ * **Effects:** If \c Func is nothrow constructible from `F&&` then constructs \c Func from
+ * `std::forward< F >(func)`, otherwise constructs from `func`. If \c Cond is
+ * nothrow constructible from `C&&` then constructs \c Cond from
+ * `std::forward< C >(cond)`, otherwise constructs from `cond`.
+ *
+ * If \c Func or \c Cond construction throws and \a active is \c true, invokes
+ * \a cond and, if it returns \c true, \a func before returning with the exception.
+ *
+ * **Throws:** Nothing, unless construction of the function objects throw.
+ *
+ * \param func The callable action function object to invoke on destruction.
+ * \param cond The callable failure condition function object.
+ * \param active Indicates whether the scope guard should be active upon construction.
+ *
+ * \post `this->active() == active`
+ */
+ template<
+ typename F,
+ typename C
+ //! \cond
+ , typename = typename std::enable_if< std::is_constructible< base_type, F, C, bool >::value >::type
+ //! \endcond
+ >
+ explicit scope_fail(F&& func, C&& cond, bool active = true)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_constructible< base_type, F, C, bool >::value)) :
+ base_type(static_cast< F&& >(func), static_cast< C&& >(cond), active)
+ {
+ }
+
+ /*!
+ * \brief Move-constructs a scope guard.
+ *
+ * **Requires:** \c Func and \c Cond are nothrow move-constructible or copy-constructible.
+ *
+ * **Effects:** If \c Func is nothrow move-constructible then move-constructs \c Func from
+ * a member of \a that, otherwise copy-constructs \c Func. If \c Cond is nothrow
+ * move-constructible then move-constructs \c Cond from a member of \a that,
+ * otherwise copy-constructs \c Cond.
+ *
+ * If \c Func or \c Cond construction throws and `that.active() == true`, invokes
+ * \c Cond object stored in \a that and, if it returns \c true, \a Func object
+ * (either the newly constructed one, if its construction succeeded, or the original
+ * one stored in \a that) before returning with the exception.
+ *
+ * If the construction succeeds, marks \a that as inactive.
+ *
+ * **Throws:** Nothing, unless move-construction of the function objects throw.
+ *
+ * \param that Move source.
+ *
+ * \post `that.active() == false`
+ */
+ //! \cond
+ template<
+ bool Requires = std::is_move_constructible< base_type >::value,
+ typename = typename std::enable_if< Requires >::type
+ >
+ //! \endcond
+ scope_fail(scope_fail&& that)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_move_constructible< base_type >::value)) :
+ base_type(static_cast< base_type&& >(that))
+ {
+ }
+
+ scope_fail& operator= (scope_fail&&) = delete;
+
+ scope_fail(scope_fail const&) = delete;
+ scope_fail& operator= (scope_fail const&) = delete;
+};
+
+#if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
+template< typename Func >
+explicit scope_fail(Func) -> scope_fail< Func >;
+
+template< typename Func >
+explicit scope_fail(Func, bool) -> scope_fail< Func >;
+
+template<
+ typename Func,
+ typename Cond,
+ typename = typename std::enable_if< detail::is_invocable< Cond const& >::value >::type
+>
+explicit scope_fail(Func, Cond) -> scope_fail< Func, Cond >;
+
+template<
+ typename Func,
+ typename Cond,
+ typename = typename std::enable_if< detail::is_invocable< Cond const& >::value >::type
+>
+explicit scope_fail(Func, Cond, bool) -> scope_fail< Func, Cond >;
+#endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
+
+/*!
+ * \brief Creates a scope fail guard with a given action function object.
+ *
+ * **Effects:** Constructs a scope guard as if by calling
+ * `scope_fail< std::decay_t< F > >(std::forward< F >(func), active)`.
+ *
+ * \param func The callable function object to invoke on destruction.
+ * \param active Indicates whether the scope guard should be active upon construction.
+ */
+template< typename F >
+inline scope_fail< typename std::decay< F >::type > make_scope_fail(F&& func, bool active = true)
+ noexcept(std::is_nothrow_constructible<
+ scope_fail< typename std::decay< F >::type >,
+ F,
+ bool
+ >::value)
+{
+ return scope_fail< typename std::decay< F >::type >(static_cast< F&& >(func), active);
+}
+
+/*!
+ * \brief Creates a scope fail with given callable function objects.
+ *
+ * **Effects:** Constructs a scope guard as if by calling
+ * `scope_fail< std::decay_t< F >, std::decay_t< C > >(
+ * std::forward< F >(func), std::forward< C >(cond), active)`.
+ *
+ * \param func The callable action function object to invoke on destruction.
+ * \param cond The callable failure condition function object.
+ * \param active Indicates whether the scope guard should be active upon construction.
+ */
+template< typename F, typename C >
+inline
+#if !defined(BOOST_SCOPE_DOXYGEN)
+typename std::enable_if<
+ detail::is_invocable< C const& >::value,
+ scope_fail< typename std::decay< F >::type, typename std::decay< C >::type >
+>::type
+#else
+scope_fail< typename std::decay< F >::type, typename std::decay< C >::type >
+#endif
+make_scope_fail(F&& func, C&& cond, bool active = true)
+ noexcept(std::is_nothrow_constructible<
+ scope_fail< typename std::decay< F >::type, typename std::decay< C >::type >,
+ F,
+ C,
+ bool
+ >::value)
+{
+ return scope_fail< typename std::decay< F >::type, typename std::decay< C >::type >(static_cast< F&& >(func), static_cast< C&& >(cond), active);
+}
+
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_SCOPE_FAIL_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/scope_success.hpp b/contrib/restricted/boost/scope/include/boost/scope/scope_success.hpp
new file mode 100644
index 0000000000..a5cd3c160d
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/scope_success.hpp
@@ -0,0 +1,309 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2022 Andrey Semashev
+ */
+/*!
+ * \file scope/scope_success.hpp
+ *
+ * This header contains definition of \c scope_success template.
+ */
+
+#ifndef BOOST_SCOPE_SCOPE_SUCCESS_HPP_INCLUDED_
+#define BOOST_SCOPE_SCOPE_SUCCESS_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+#include <boost/scope/exception_checker.hpp>
+#include <boost/scope/scope_exit.hpp>
+#include <boost/scope/detail/is_not_like.hpp>
+#include <boost/scope/detail/type_traits/conjunction.hpp>
+#include <boost/scope/detail/type_traits/is_invocable.hpp>
+#include <boost/scope/detail/type_traits/is_nothrow_invocable.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+
+template< typename Func, typename Cond >
+class scope_success;
+
+namespace detail {
+
+// Workaround for clang < 5.0 which can't pass scope_success as a template template parameter from within scope_success definition
+template< typename T >
+using is_not_like_scope_success = detail::is_not_like< T, scope_success >;
+
+template< typename Func >
+class logical_not;
+
+template< typename T >
+using is_not_like_logical_not = detail::is_not_like< T, logical_not >;
+
+template< typename Func >
+class logical_not
+{
+public:
+ using result_type = bool;
+
+private:
+ Func m_func;
+
+public:
+ template<
+ bool Requires = std::is_default_constructible< Func >::value,
+ typename = typename std::enable_if< Requires >::type
+ >
+ logical_not() noexcept(std::is_nothrow_default_constructible< Func >::value) :
+ m_func()
+ {
+ }
+
+ template<
+ typename F,
+ typename = typename std::enable_if< detail::conjunction<
+ std::is_constructible< Func, F >,
+ detail::is_not_like_logical_not< F >
+ >::value >::type
+ >
+ explicit logical_not(F&& func) noexcept(std::is_nothrow_constructible< Func, F >::value) :
+ m_func(static_cast< F&& >(func))
+ {
+ }
+
+ result_type operator()() const noexcept(detail::is_nothrow_invocable< Func const& >::value)
+ {
+ return !m_func();
+ }
+};
+
+} // namespace detail
+
+/*!
+ * \brief Scope exit guard that invokes a function upon leaving the scope, if
+ * a failure condition is not satisfied.
+ *
+ * The scope guard wraps two function objects: the scope guard action and
+ * a failure condition for invoking the action. Both function objects must
+ * be callable with no arguments and can be one of:
+ *
+ * \li A user-defined class with a public `operator()`.
+ * \li An lvalue reference to such class.
+ * \li An lvalue reference or pointer to function taking no arguments.
+ *
+ * The condition function object `operator()` must return a value
+ * contextually convertible to \c true, if the failure is detected and the
+ * action function object is not allowed to be executed, and \c false otherwise.
+ * Additionally, the failure condition function object `operator()` must not
+ * throw, as otherwise the action function object may not be called. If not
+ * specified, the default failure condition checks whether the scope is left
+ * due to an exception - the action function object will only be called if
+ * the scope is left normally.
+ *
+ * \sa scope_exit
+ * \sa scope_fail
+ *
+ * \tparam Func Scope guard action function object type.
+ * \tparam Cond Scope guard failure condition function object type.
+ */
+template< typename Func, typename Cond = exception_checker >
+class scope_success :
+ public scope_exit< Func, detail::logical_not< Cond > >
+{
+//! \cond
+private:
+ using base_type = scope_exit< Func, detail::logical_not< Cond > >;
+
+//! \endcond
+public:
+ /*!
+ * \brief Constructs a scope guard with a given callable function object.
+ *
+ * **Requires:** \c Func is constructible from \a func. \c Cond is nothrow default-constructible.
+ *
+ * **Effects:** Constructs the scope guard as if by calling
+ * `scope_success(std::forward< F >(func), Cond(), active)`.
+ *
+ * **Throws:** Nothing, unless construction of the function objects throw.
+ *
+ * \param func The callable action function object to invoke on destruction.
+ * \param active Indicates whether the scope guard should be active upon construction.
+ *
+ * \post `this->active() == active`
+ */
+ template<
+ typename F
+ //! \cond
+ , typename = typename std::enable_if< detail::conjunction<
+ std::is_constructible< base_type, F, bool >,
+ detail::is_not_like_scope_success< F >
+ >::value >::type
+ //! \endcond
+ >
+ explicit scope_success(F&& func, bool active = true)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_constructible< base_type, F, bool >::value)) :
+ base_type(static_cast< F&& >(func), active)
+ {
+ }
+
+ /*!
+ * \brief Constructs a scope guard with a given callable action and failure condition function objects.
+ *
+ * **Requires:** \c Func is constructible from \a func. \c Cond is constructible from \a cond.
+ *
+ * **Effects:** If \c Func is nothrow constructible from `F&&` then constructs \c Func from
+ * `std::forward< F >(func)`, otherwise constructs from `func`. If \c Cond is
+ * nothrow constructible from `C&&` then constructs \c Cond from
+ * `std::forward< C >(cond)`, otherwise constructs from `cond`.
+ *
+ * If \c Func or \c Cond construction throws and \a active is \c true, invokes
+ * \a cond and, if it returns \c true, \a func before returning with the exception.
+ *
+ * **Throws:** Nothing, unless construction of the function objects throw.
+ *
+ * \param func The callable action function object to invoke on destruction.
+ * \param cond The callable failure condition function object.
+ * \param active Indicates whether the scope guard should be active upon construction.
+ *
+ * \post `this->active() == active`
+ */
+ template<
+ typename F,
+ typename C
+ //! \cond
+ , typename = typename std::enable_if< std::is_constructible< base_type, F, C, bool >::value >::type
+ //! \endcond
+ >
+ explicit scope_success(F&& func, C&& cond, bool active = true)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_constructible< base_type, F, C, bool >::value)) :
+ base_type(static_cast< F&& >(func), static_cast< C&& >(cond), active)
+ {
+ }
+
+ /*!
+ * \brief Move-constructs a scope guard.
+ *
+ * **Requires:** \c Func and \c Cond are nothrow move-constructible or copy-constructible.
+ *
+ * **Effects:** If \c Func is nothrow move-constructible then move-constructs \c Func from
+ * a member of \a that, otherwise copy-constructs \c Func. If \c Cond is nothrow
+ * move-constructible then move-constructs \c Cond from a member of \a that,
+ * otherwise copy-constructs \c Cond.
+ *
+ * If \c Func or \c Cond construction throws and `that.active() == true`, invokes
+ * \c Cond object stored in \a that and, if it returns \c true, \a Func object
+ * (either the newly constructed one, if its construction succeeded, or the original
+ * one stored in \a that) before returning with the exception.
+ *
+ * If the construction succeeds, marks \a that as inactive.
+ *
+ * **Throws:** Nothing, unless move-construction of the function objects throw.
+ *
+ * \param that Move source.
+ *
+ * \post `that.active() == false`
+ */
+ //! \cond
+ template<
+ bool Requires = std::is_move_constructible< base_type >::value,
+ typename = typename std::enable_if< Requires >::type
+ >
+ //! \endcond
+ scope_success(scope_success&& that)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_move_constructible< base_type >::value)) :
+ base_type(static_cast< base_type&& >(that))
+ {
+ }
+
+ scope_success& operator= (scope_success&&) = delete;
+
+ scope_success(scope_success const&) = delete;
+ scope_success& operator= (scope_success const&) = delete;
+};
+
+#if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
+template< typename Func >
+explicit scope_success(Func) -> scope_success< Func >;
+
+template< typename Func >
+explicit scope_success(Func, bool) -> scope_success< Func >;
+
+template<
+ typename Func,
+ typename Cond,
+ typename = typename std::enable_if< detail::is_invocable< Cond const& >::value >::type
+>
+explicit scope_success(Func, Cond) -> scope_success< Func, Cond >;
+
+template<
+ typename Func,
+ typename Cond,
+ typename = typename std::enable_if< detail::is_invocable< Cond const& >::value >::type
+>
+explicit scope_success(Func, Cond, bool) -> scope_success< Func, Cond >;
+#endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
+
+/*!
+ * \brief Creates a scope fail guard with a given action function object.
+ *
+ * **Effects:** Constructs a scope guard as if by calling
+ * `scope_success< std::decay_t< F > >(std::forward< F >(func), active)`.
+ *
+ * \param func The callable function object to invoke on destruction.
+ * \param active Indicates whether the scope guard should be active upon construction.
+ */
+template< typename F >
+inline scope_success< typename std::decay< F >::type > make_scope_success(F&& func, bool active = true)
+ noexcept(std::is_nothrow_constructible<
+ scope_success< typename std::decay< F >::type >,
+ F,
+ bool
+ >::value)
+{
+ return scope_success< typename std::decay< F >::type >(static_cast< F&& >(func), active);
+}
+
+/*!
+ * \brief Creates a scope fail with given callable function objects.
+ *
+ * **Effects:** Constructs a scope guard as if by calling
+ * `scope_success< std::decay_t< F >, std::decay_t< C > >(
+ * std::forward< F >(func), std::forward< C >(cond), active)`.
+ *
+ * \param func The callable action function object to invoke on destruction.
+ * \param cond The callable failure condition function object.
+ * \param active Indicates whether the scope guard should be active upon construction.
+ */
+template< typename F, typename C >
+inline
+#if !defined(BOOST_SCOPE_DOXYGEN)
+typename std::enable_if<
+ detail::is_invocable< C const& >::value,
+ scope_success< typename std::decay< F >::type, typename std::decay< C >::type >
+>::type
+#else
+scope_success< typename std::decay< F >::type, typename std::decay< C >::type >
+#endif
+make_scope_success(F&& func, C&& cond, bool active = true)
+ noexcept(std::is_nothrow_constructible<
+ scope_success< typename std::decay< F >::type, typename std::decay< C >::type >,
+ F,
+ C,
+ bool
+ >::value)
+{
+ return scope_success< typename std::decay< F >::type, typename std::decay< C >::type >(static_cast< F&& >(func), static_cast< C&& >(cond), active);
+}
+
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_SCOPE_SUCCESS_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/unique_fd.hpp b/contrib/restricted/boost/scope/include/boost/scope/unique_fd.hpp
new file mode 100644
index 0000000000..305ad38867
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/unique_fd.hpp
@@ -0,0 +1,38 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2023 Andrey Semashev
+ */
+/*!
+ * \file scope/unique_fd.hpp
+ *
+ * This header contains definition of \c unique_fd type.
+ */
+
+#ifndef BOOST_SCOPE_UNIQUE_FD_HPP_INCLUDED_
+#define BOOST_SCOPE_UNIQUE_FD_HPP_INCLUDED_
+
+#include <boost/scope/detail/config.hpp>
+#include <boost/scope/unique_resource.hpp>
+#include <boost/scope/fd_deleter.hpp>
+#include <boost/scope/fd_resource_traits.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+
+//! Unique POSIX-like file descriptor resource
+using unique_fd = unique_resource< int, fd_deleter, fd_resource_traits >;
+
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_UNIQUE_FD_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/unique_resource.hpp b/contrib/restricted/boost/scope/include/boost/scope/unique_resource.hpp
new file mode 100644
index 0000000000..81683c4076
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/unique_resource.hpp
@@ -0,0 +1,1642 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2022-2024 Andrey Semashev
+ */
+/*!
+ * \file scope/unique_resource.hpp
+ *
+ * This header contains definition of \c unique_resource template.
+ */
+
+#ifndef BOOST_SCOPE_UNIQUE_RESOURCE_HPP_INCLUDED_
+#define BOOST_SCOPE_UNIQUE_RESOURCE_HPP_INCLUDED_
+
+#include <new> // for placement new
+#include <type_traits>
+#include <boost/core/addressof.hpp>
+#include <boost/core/invoke_swap.hpp>
+#include <boost/scope/unique_resource_fwd.hpp>
+#include <boost/scope/detail/config.hpp>
+#include <boost/scope/detail/compact_storage.hpp>
+#include <boost/scope/detail/move_or_copy_assign_ref.hpp>
+#include <boost/scope/detail/move_or_copy_construct_ref.hpp>
+#include <boost/scope/detail/is_nonnull_default_constructible.hpp>
+#include <boost/scope/detail/type_traits/is_swappable.hpp>
+#include <boost/scope/detail/type_traits/is_nothrow_swappable.hpp>
+#include <boost/scope/detail/type_traits/is_nothrow_invocable.hpp>
+#include <boost/scope/detail/type_traits/negation.hpp>
+#include <boost/scope/detail/type_traits/conjunction.hpp>
+#include <boost/scope/detail/type_traits/disjunction.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+
+#if !defined(BOOST_NO_CXX17_FOLD_EXPRESSIONS) && !defined(BOOST_NO_CXX17_AUTO_NONTYPE_TEMPLATE_PARAMS)
+
+/*!
+ * \brief Simple resource traits for one or more unallocated resource values.
+ *
+ * This class template generates resource traits for `unique_resource` that specify
+ * one or more unallocated resource values. The first value, specified in the \c DefaultValue
+ * non-type template parameter, is considered the default. The other values, listed in
+ * \c UnallocatedValues, are optional. Any resource values other than \c DefaultValue
+ * or listed in \c UnallocatedValues are considered as allocated.
+ *
+ * In order for the generated resource traits to enable optimized implementation of
+ * `unique_resource`, the resource type must support non-throwing construction and assignment
+ * from, and comparison for (in)equality with \c DefaultValue or any of the resource
+ * values listed in \c UnallocatedValues.
+ */
+template< auto DefaultValue, auto... UnallocatedValues >
+struct unallocated_resource
+{
+ //! Returns the default resource value
+ static decltype(DefaultValue) make_default() noexcept
+ {
+ return DefaultValue;
+ }
+
+ //! Tests if \a res is an allocated resource value
+ template< typename Resource >
+ static bool is_allocated(Resource const& res) noexcept
+ {
+ static_assert(noexcept(res != DefaultValue && (... && (res != UnallocatedValues))),
+ "Invalid unallocated resource value types: comparing resource values with the unallocated values must be noexcept");
+ return res != DefaultValue && (... && (res != UnallocatedValues));
+ }
+};
+
+#endif // !defined(BOOST_NO_CXX17_FOLD_EXPRESSIONS) && !defined(BOOST_NO_CXX17_AUTO_NONTYPE_TEMPLATE_PARAMS)
+
+struct default_resource_t { };
+
+//! Keyword representing default, unallocated resource argument
+BOOST_INLINE_VARIABLE constexpr default_resource_t default_resource = { };
+
+namespace detail {
+
+// The type trait indicates whether \c T is a possibly qualified \c default_resource_t type
+template< typename T >
+struct is_default_resource : public std::false_type { };
+template< >
+struct is_default_resource< default_resource_t > : public std::true_type { };
+template< >
+struct is_default_resource< const default_resource_t > : public std::true_type { };
+template< >
+struct is_default_resource< volatile default_resource_t > : public std::true_type { };
+template< >
+struct is_default_resource< const volatile default_resource_t > : public std::true_type { };
+template< typename T >
+struct is_default_resource< T& > : public is_default_resource< T >::type { };
+
+// Lightweight reference wrapper
+template< typename T >
+class ref_wrapper
+{
+private:
+ T* m_value;
+
+public:
+ explicit
+#if !defined(BOOST_CORE_NO_CONSTEXPR_ADDRESSOF)
+ constexpr
+#endif
+ ref_wrapper(T& value) noexcept :
+ m_value(boost::addressof(value))
+ {
+ }
+
+ ref_wrapper& operator= (T& value) noexcept
+ {
+ m_value = boost::addressof(value);
+ return *this;
+ }
+
+ ref_wrapper(T&&) = delete;
+ ref_wrapper& operator= (T&&) = delete;
+
+ operator T& () const noexcept
+ {
+ return *m_value;
+ }
+
+ template< typename... Args >
+ void operator() (Args&&... args) const noexcept(detail::is_nothrow_invocable< T&, Args&&... >::value)
+ {
+ (*m_value)(static_cast< Args&& >(args)...);
+ }
+};
+
+template< typename T >
+struct wrap_reference
+{
+ using type = T;
+};
+
+template< typename T >
+struct wrap_reference< T& >
+{
+ using type = ref_wrapper< T >;
+};
+
+template< typename Resource, bool UseCompactStorage >
+class resource_holder :
+ public detail::compact_storage< typename wrap_reference< Resource >::type >
+{
+public:
+ using resource_type = Resource;
+ using internal_resource_type = typename wrap_reference< resource_type >::type;
+
+private:
+ using resource_base = detail::compact_storage< internal_resource_type >;
+
+public:
+ template<
+ bool Requires = std::is_default_constructible< internal_resource_type >::value,
+ typename = typename std::enable_if< Requires >::type
+ >
+ constexpr resource_holder() noexcept(std::is_nothrow_default_constructible< internal_resource_type >::value) :
+ resource_base()
+ {
+ }
+
+ template<
+ typename R,
+ typename = typename std::enable_if< std::is_constructible< internal_resource_type, R >::value >::type
+ >
+ explicit resource_holder(R&& res) noexcept(std::is_nothrow_constructible< internal_resource_type, R >::value) :
+ resource_base(static_cast< R&& >(res))
+ {
+ }
+
+ template<
+ typename R,
+ typename D,
+ typename = typename std::enable_if< std::is_constructible< internal_resource_type, R >::value >::type
+ >
+ explicit resource_holder(R&& res, D&& del, bool allocated) noexcept(std::is_nothrow_constructible< internal_resource_type, R >::value) :
+ resource_holder(static_cast< R&& >(res), static_cast< D&& >(del), allocated, typename std::is_nothrow_constructible< resource_type, R >::type())
+ {
+ }
+
+ resource_type& get() noexcept
+ {
+ return resource_base::get();
+ }
+
+ resource_type const& get() const noexcept
+ {
+ return resource_base::get();
+ }
+
+ internal_resource_type& get_internal() noexcept
+ {
+ return resource_base::get();
+ }
+
+ internal_resource_type const& get_internal() const noexcept
+ {
+ return resource_base::get();
+ }
+
+ void move_from(internal_resource_type&& that) noexcept(std::is_nothrow_move_assignable< internal_resource_type >::value)
+ {
+ resource_base::get() = static_cast< internal_resource_type&& >(that);
+ }
+
+private:
+ template< typename R, typename D >
+ explicit resource_holder(R&& res, D&& del, bool allocated, std::true_type) noexcept :
+ resource_base(static_cast< R&& >(res))
+ {
+ }
+
+ template< typename R, typename D >
+ explicit resource_holder(R&& res, D&& del, bool allocated, std::false_type) try :
+ resource_base(res)
+ {
+ }
+ catch (...)
+ {
+ if (allocated)
+ del(res);
+ }
+};
+
+template< typename Resource >
+class resource_holder< Resource, false >
+{
+public:
+ using resource_type = Resource;
+ using internal_resource_type = typename wrap_reference< resource_type >::type;
+
+private:
+ // Note: Not using compact_storage since we will need to reuse storage for this complete object in move_from
+ internal_resource_type m_resource;
+
+public:
+ template<
+ bool Requires = std::is_default_constructible< internal_resource_type >::value,
+ typename = typename std::enable_if< Requires >::type
+ >
+ constexpr resource_holder() noexcept(std::is_nothrow_default_constructible< internal_resource_type >::value) :
+ m_resource()
+ {
+ }
+
+ template<
+ typename R,
+ typename = typename std::enable_if< std::is_constructible< internal_resource_type, R >::value >::type
+ >
+ explicit resource_holder(R&& res) noexcept(std::is_nothrow_constructible< internal_resource_type, R >::value) :
+ m_resource(static_cast< R&& >(res))
+ {
+ }
+
+ template<
+ typename R,
+ typename D,
+ typename = typename std::enable_if< std::is_constructible< internal_resource_type, R >::value >::type
+ >
+ explicit resource_holder(R&& res, D&& del, bool allocated) noexcept(std::is_nothrow_constructible< internal_resource_type, R >::value) :
+ resource_holder(static_cast< R&& >(res), static_cast< D&& >(del), allocated, typename std::is_nothrow_constructible< resource_type, R >::type())
+ {
+ }
+
+ resource_type& get() noexcept
+ {
+ return m_resource;
+ }
+
+ resource_type const& get() const noexcept
+ {
+ return m_resource;
+ }
+
+ internal_resource_type& get_internal() noexcept
+ {
+ return m_resource;
+ }
+
+ internal_resource_type const& get_internal() const noexcept
+ {
+ return m_resource;
+ }
+
+ void move_from(internal_resource_type&& that)
+ noexcept(std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >::value)
+ {
+ internal_resource_type* p = boost::addressof(m_resource);
+ p->~internal_resource_type();
+ new (p) internal_resource_type(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that));
+ }
+
+private:
+ template< typename R, typename D >
+ explicit resource_holder(R&& res, D&& del, bool allocated, std::true_type) noexcept :
+ m_resource(static_cast< R&& >(res))
+ {
+ }
+
+ template< typename R, typename D >
+ explicit resource_holder(R&& res, D&& del, bool allocated, std::false_type) try :
+ m_resource(res)
+ {
+ }
+ catch (...)
+ {
+ if (allocated)
+ del(res);
+ }
+};
+
+template< typename Resource, typename Deleter >
+class deleter_holder :
+ public detail::compact_storage< typename wrap_reference< Deleter >::type >
+{
+public:
+ using resource_type = Resource;
+ using deleter_type = Deleter;
+ using internal_deleter_type = typename wrap_reference< deleter_type >::type;
+
+private:
+ using deleter_base = detail::compact_storage< internal_deleter_type >;
+
+public:
+ template<
+ bool Requires = detail::is_nonnull_default_constructible< internal_deleter_type >::value,
+ typename = typename std::enable_if< Requires >::type
+ >
+ constexpr deleter_holder() noexcept(detail::is_nothrow_nonnull_default_constructible< internal_deleter_type >::value) :
+ deleter_base()
+ {
+ }
+
+ template<
+ typename D,
+ typename = typename std::enable_if< std::is_constructible< internal_deleter_type, D >::value >::type
+ >
+ explicit deleter_holder(D&& del) noexcept(std::is_nothrow_constructible< internal_deleter_type, D >::value) :
+ deleter_base(static_cast< D&& >(del))
+ {
+ }
+
+ template<
+ typename D,
+ typename = typename std::enable_if< std::is_constructible< internal_deleter_type, D >::value >::type
+ >
+ explicit deleter_holder(D&& del, resource_type& res, bool allocated) noexcept(std::is_nothrow_constructible< internal_deleter_type, D >::value) :
+ deleter_holder(static_cast< D&& >(del), res, allocated, typename std::is_nothrow_constructible< internal_deleter_type, D >::type())
+ {
+ }
+
+ deleter_type& get() noexcept
+ {
+ return deleter_base::get();
+ }
+
+ deleter_type const& get() const noexcept
+ {
+ return deleter_base::get();
+ }
+
+ internal_deleter_type& get_internal() noexcept
+ {
+ return deleter_base::get();
+ }
+
+ internal_deleter_type const& get_internal() const noexcept
+ {
+ return deleter_base::get();
+ }
+
+private:
+ template< typename D >
+ explicit deleter_holder(D&& del, resource_type& res, bool allocated, std::true_type) noexcept :
+ deleter_base(static_cast< D&& >(del))
+ {
+ }
+
+ template< typename D >
+ explicit deleter_holder(D&& del, resource_type& res, bool allocated, std::false_type) try :
+ deleter_base(del)
+ {
+ }
+ catch (...)
+ {
+ if (BOOST_LIKELY(allocated))
+ del(res);
+ }
+};
+
+/*
+ * This metafunction indicates whether \c resource_holder should use \c compact_storage
+ * to optimize storage for the resource object. Its definition must be coherent with
+ * `resource_holder::move_from` definition and move constructor implementation in
+ * \c unique_resource_data.
+ *
+ * There is one tricky case with \c unique_resource move constructor, when the resource move
+ * constructor is noexcept and deleter's move and copy constructors are not. It is possible
+ * that \c unique_resource_data move constructor moves the resource into the object being
+ * constructed but fails to construct the deleter. In this case we want to move the resource
+ * back to the original \c unique_resource_data object (which is guaranteed to not throw since
+ * the resource's move constructor is non-throwing).
+ *
+ * However, if we use the move constructor to move the resource back, we need to use placement
+ * new, and this only lets us create a complete object of the resource type, which prohibits
+ * the use of \c compact_storage, as it may create the resource object as a base subobject of
+ * \c compact_storage. Using placement new on a base subobject may corrupt data that is placed
+ * in the trailing padding bits of the resource type.
+ *
+ * To work around this limitation, we also test if move assignment of the resource type is
+ * also non-throwing (which is reasonable to expect, given that the move constructor is
+ * non-throwing). If it is, we can avoid having to destroy and move-construct the resource and
+ * use move-assignment instead. This doesn't require a complete object of the resource type
+ * and allows us to use \c compact_storage. If move assignment is not noexcept then we have
+ * to use the move constructor and disable the \c compact_storage optimization.
+ *
+ * So this trait has to detect (a) whether we are affected by this tricky case of the
+ * \c unique_resource move constructor in the first place and (b) whether we can use move
+ * assignment to move the resource back to the original \c unique_resource object. If we're
+ * not affected or we can use move assignment then we enable \c compact_storage.
+ */
+template< typename Resource, typename Deleter >
+using use_resource_compact_storage = detail::disjunction<
+ std::is_nothrow_move_assignable< typename wrap_reference< Resource >::type >,
+ std::is_nothrow_constructible< typename wrap_reference< Deleter >::type, typename detail::move_or_copy_construct_ref< Deleter >::type >,
+ detail::negation< std::is_nothrow_constructible< typename wrap_reference< Resource >::type, typename detail::move_or_copy_construct_ref< Resource >::type > >
+>;
+
+template< typename Resource, typename Deleter, typename Traits >
+class unique_resource_data :
+ public detail::resource_holder< Resource, use_resource_compact_storage< Resource, Deleter >::value >,
+ public detail::deleter_holder< Resource, Deleter >
+{
+public:
+ using resource_type = Resource;
+ using deleter_type = Deleter;
+ using traits_type = Traits;
+
+private:
+ using resource_holder = detail::resource_holder< resource_type, use_resource_compact_storage< resource_type, deleter_type >::value >;
+ using deleter_holder = detail::deleter_holder< resource_type, deleter_type >;
+ using result_of_make_default = decltype(traits_type::make_default());
+
+public:
+ using internal_resource_type = typename resource_holder::internal_resource_type;
+ using internal_deleter_type = typename deleter_holder::internal_deleter_type;
+
+ static_assert(noexcept(traits_type::make_default()), "Invalid unique_resource resource traits: make_default must be noexcept");
+ static_assert(std::is_nothrow_assignable< internal_resource_type&, result_of_make_default >::value,
+ "Invalid unique_resource resource traits: resource must be nothrow-assignable from the result of make_default");
+ static_assert(noexcept(traits_type::is_allocated(std::declval< resource_type const& >())), "Invalid unique_resource resource traits: is_allocated must be noexcept");
+
+public:
+ template<
+ bool Requires = detail::conjunction<
+ std::is_constructible< resource_holder, result_of_make_default >,
+ std::is_default_constructible< deleter_holder >
+ >::value,
+ typename = typename std::enable_if< Requires >::type
+ >
+ constexpr unique_resource_data()
+ noexcept(detail::conjunction<
+ std::is_nothrow_constructible< resource_holder, result_of_make_default >,
+ std::is_nothrow_default_constructible< deleter_holder >
+ >::value) :
+ resource_holder(traits_type::make_default()),
+ deleter_holder()
+ {
+ }
+
+ unique_resource_data(unique_resource_data const&) = delete;
+ unique_resource_data& operator= (unique_resource_data const&) = delete;
+
+ unique_resource_data(unique_resource_data&& that)
+ noexcept(detail::conjunction<
+ std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >,
+ std::is_nothrow_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >
+ >::value) :
+ unique_resource_data
+ (
+ static_cast< unique_resource_data&& >(that),
+ typename std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >::type(),
+ typename std::is_nothrow_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >::type()
+ )
+ {
+ }
+
+ template<
+ typename D,
+ typename = typename std::enable_if< detail::conjunction<
+ std::is_constructible< resource_holder, result_of_make_default >,
+ std::is_constructible< deleter_holder, D >
+ >::value >::type
+ >
+ explicit unique_resource_data(default_resource_t, D&& del)
+ noexcept(detail::conjunction<
+ std::is_nothrow_constructible< resource_holder, result_of_make_default >,
+ std::is_nothrow_constructible< deleter_holder, D >
+ >::value) :
+ resource_holder(traits_type::make_default()),
+ deleter_holder(static_cast< D&& >(del))
+ {
+ }
+
+ template<
+ typename R,
+ typename D,
+ typename = typename std::enable_if< detail::conjunction<
+ detail::negation< detail::is_default_resource< R > >,
+ std::is_constructible< resource_holder, R, D, bool >,
+ std::is_constructible< deleter_holder, D, resource_type&, bool >
+ >::value >::type
+ >
+ explicit unique_resource_data(R&& res, D&& del)
+ noexcept(detail::conjunction<
+ std::is_nothrow_constructible< resource_holder, R, D, bool >,
+ std::is_nothrow_constructible< deleter_holder, D, resource_type&, bool >
+ >::value) :
+ unique_resource_data(static_cast< R&& >(res), static_cast< D&& >(del), traits_type::is_allocated(res)) // don't forward res to is_allocated to make sure res is not moved-from on resource construction
+ {
+ // Since res may not be of the resource type, the is_allocated call made above may require a type conversion or pick a different overload.
+ // We still require it to be noexcept, as we need to know whether we should deallocate it. Otherwise we may leak the resource.
+ static_assert(noexcept(traits_type::is_allocated(res)), "Invalid unique_resource resource traits: is_allocated must be noexcept");
+ }
+
+ template<
+ bool Requires = detail::conjunction<
+ std::is_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >,
+ std::is_assignable< internal_deleter_type&, typename detail::move_or_copy_assign_ref< deleter_type >::type >
+ >::value
+ >
+ typename std::enable_if< Requires, unique_resource_data& >::type operator= (unique_resource_data&& that)
+ noexcept(detail::conjunction<
+ std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >,
+ std::is_nothrow_assignable< internal_deleter_type&, typename detail::move_or_copy_assign_ref< deleter_type >::type >
+ >::value)
+ {
+ assign(static_cast< unique_resource_data&& >(that), typename std::is_nothrow_move_assignable< internal_deleter_type >::type());
+ return *this;
+ }
+
+ resource_type& get_resource() noexcept
+ {
+ return resource_holder::get();
+ }
+
+ resource_type const& get_resource() const noexcept
+ {
+ return resource_holder::get();
+ }
+
+ internal_resource_type& get_internal_resource() noexcept
+ {
+ return resource_holder::get_internal();
+ }
+
+ internal_resource_type const& get_internal_resource() const noexcept
+ {
+ return resource_holder::get_internal();
+ }
+
+ deleter_type& get_deleter() noexcept
+ {
+ return deleter_holder::get();
+ }
+
+ deleter_type const& get_deleter() const noexcept
+ {
+ return deleter_holder::get();
+ }
+
+ internal_deleter_type& get_internal_deleter() noexcept
+ {
+ return deleter_holder::get_internal();
+ }
+
+ internal_deleter_type const& get_internal_deleter() const noexcept
+ {
+ return deleter_holder::get_internal();
+ }
+
+ bool is_allocated() const noexcept
+ {
+ return traits_type::is_allocated(get_resource());
+ }
+
+ void set_unallocated() noexcept
+ {
+ get_internal_resource() = traits_type::make_default();
+ }
+
+ template< typename R >
+ void assign_resource(R&& res) noexcept(std::is_nothrow_assignable< internal_resource_type&, R >::value)
+ {
+ get_internal_resource() = static_cast< R&& >(res);
+ }
+
+ template<
+ bool Requires = detail::conjunction<
+ detail::is_swappable< internal_resource_type >,
+ detail::is_swappable< internal_deleter_type >,
+ detail::disjunction<
+ detail::is_nothrow_swappable< internal_resource_type >,
+ detail::is_nothrow_swappable< internal_deleter_type >
+ >
+ >::value
+ >
+ typename std::enable_if< Requires >::type swap(unique_resource_data& that)
+ noexcept(detail::conjunction< detail::is_nothrow_swappable< internal_resource_type >, detail::is_nothrow_swappable< internal_deleter_type > >::value)
+ {
+ swap_impl
+ (
+ that,
+ std::integral_constant< bool, detail::is_nothrow_swappable< internal_resource_type >::value >(),
+ std::integral_constant< bool, detail::conjunction<
+ detail::is_nothrow_swappable< internal_resource_type >,
+ detail::is_nothrow_swappable< internal_deleter_type >
+ >::value >()
+ );
+ }
+
+private:
+ unique_resource_data(unique_resource_data&& that, std::true_type, std::true_type) noexcept :
+ resource_holder(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that.get_resource())),
+ deleter_holder(static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(that.get_deleter()))
+ {
+ that.set_unallocated();
+ }
+
+ unique_resource_data(unique_resource_data&& that, std::false_type, std::true_type) :
+ resource_holder(static_cast< resource_type const& >(that.get_resource())),
+ deleter_holder(static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(that.get_deleter()))
+ {
+ that.set_unallocated();
+ }
+
+ unique_resource_data(unique_resource_data&& that, std::true_type, std::false_type) try :
+ resource_holder(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that.get_resource())),
+ deleter_holder(static_cast< deleter_type const& >(that.get_deleter()))
+ {
+ that.set_unallocated();
+ }
+ catch (...)
+ {
+ // Since only the deleter's constructor could have thrown an exception here, move the resource back
+ // to the original unique_resource. This is guaranteed to not throw.
+ that.resource_holder::move_from(static_cast< internal_resource_type&& >(resource_holder::get_internal()));
+ }
+
+ unique_resource_data(unique_resource_data&& that, std::false_type, std::false_type) :
+ resource_holder(static_cast< resource_type const& >(that.get_resource())),
+ deleter_holder(static_cast< deleter_type const& >(that.get_deleter()))
+ {
+ that.set_unallocated();
+ }
+
+ template<
+ typename R,
+ typename D,
+ typename = typename std::enable_if< detail::conjunction<
+ std::is_constructible< resource_holder, R, D, bool >,
+ std::is_constructible< deleter_holder, D, resource_type&, bool >
+ >::value >::type
+ >
+ explicit unique_resource_data(R&& res, D&& del, bool allocated)
+ noexcept(detail::conjunction<
+ std::is_nothrow_constructible< resource_holder, R, D, bool >,
+ std::is_nothrow_constructible< deleter_holder, D, resource_type&, bool >
+ >::value) :
+ resource_holder(static_cast< R&& >(res), static_cast< D&& >(del), allocated),
+ deleter_holder(static_cast< D&& >(del), resource_holder::get(), allocated)
+ {
+ }
+
+ void assign(unique_resource_data&& that, std::true_type)
+ noexcept(std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >::value)
+ {
+ get_internal_resource() = static_cast< typename detail::move_or_copy_assign_ref< resource_type >::type >(that.get_resource());
+ get_internal_deleter() = static_cast< typename detail::move_or_copy_assign_ref< deleter_type >::type >(that.get_deleter());
+
+ that.set_unallocated();
+ }
+
+ void assign(unique_resource_data&& that, std::false_type)
+ {
+ get_internal_deleter() = static_cast< typename detail::move_or_copy_assign_ref< deleter_type >::type >(that.get_deleter());
+ get_internal_resource() = static_cast< typename detail::move_or_copy_assign_ref< resource_type >::type >(that.get_resource());
+
+ that.set_unallocated();
+ }
+
+ void swap_impl(unique_resource_data& that, std::true_type, std::true_type) noexcept
+ {
+ boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
+ boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
+ }
+
+ void swap_impl(unique_resource_data& that, std::true_type, std::false_type)
+ {
+ boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
+ boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
+ }
+
+ void swap_impl(unique_resource_data& that, std::false_type, std::false_type)
+ {
+ boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
+ boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
+ }
+};
+
+template< typename Resource, typename Deleter >
+class unique_resource_data< Resource, Deleter, void > :
+ public detail::resource_holder< Resource, use_resource_compact_storage< Resource, Deleter >::value >,
+ public detail::deleter_holder< Resource, Deleter >
+{
+public:
+ using resource_type = Resource;
+ using deleter_type = Deleter;
+ using traits_type = void;
+
+private:
+ using resource_holder = detail::resource_holder< resource_type, use_resource_compact_storage< resource_type, deleter_type >::value >;
+ using deleter_holder = detail::deleter_holder< resource_type, deleter_type >;
+
+public:
+ using internal_resource_type = typename resource_holder::internal_resource_type;
+ using internal_deleter_type = typename deleter_holder::internal_deleter_type;
+
+private:
+ bool m_allocated;
+
+public:
+ template<
+ bool Requires = detail::conjunction< std::is_default_constructible< resource_holder >, std::is_default_constructible< deleter_holder > >::value,
+ typename = typename std::enable_if< Requires >::type
+ >
+ constexpr unique_resource_data()
+ noexcept(detail::conjunction< std::is_nothrow_default_constructible< resource_holder >, std::is_nothrow_default_constructible< deleter_holder > >::value) :
+ resource_holder(),
+ deleter_holder(),
+ m_allocated(false)
+ {
+ }
+
+ unique_resource_data(unique_resource_data const&) = delete;
+ unique_resource_data& operator= (unique_resource_data const&) = delete;
+
+ template<
+ bool Requires = detail::conjunction<
+ std::is_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >,
+ std::is_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >
+ >::value,
+ typename = typename std::enable_if< Requires >::type
+ >
+ unique_resource_data(unique_resource_data&& that)
+ noexcept(detail::conjunction<
+ std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >,
+ std::is_nothrow_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >
+ >::value) :
+ unique_resource_data
+ (
+ static_cast< unique_resource_data&& >(that),
+ typename std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >::type(),
+ typename std::is_nothrow_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >::type()
+ )
+ {
+ }
+
+ template<
+ typename D,
+ typename = typename std::enable_if< detail::conjunction<
+ std::is_default_constructible< resource_holder >,
+ std::is_constructible< deleter_holder, D >
+ >::value >::type
+ >
+ explicit unique_resource_data(default_resource_t, D&& del)
+ noexcept(detail::conjunction<
+ std::is_nothrow_default_constructible< resource_holder >,
+ std::is_nothrow_constructible< deleter_holder, D >
+ >::value) :
+ resource_holder(),
+ deleter_holder(static_cast< D&& >(del)),
+ m_allocated(false)
+ {
+ }
+
+ template<
+ typename R,
+ typename D,
+ typename = typename std::enable_if< detail::conjunction<
+ detail::negation< detail::is_default_resource< R > >,
+ std::is_constructible< resource_holder, R, D, bool >,
+ std::is_constructible< deleter_holder, D, resource_type&, bool >
+ >::value >::type
+ >
+ explicit unique_resource_data(R&& res, D&& del)
+ noexcept(detail::conjunction<
+ std::is_nothrow_constructible< resource_holder, R, D, bool >,
+ std::is_nothrow_constructible< deleter_holder, D, resource_type&, bool >
+ >::value) :
+ resource_holder(static_cast< R&& >(res), static_cast< D&& >(del), true),
+ deleter_holder(static_cast< D&& >(del), resource_holder::get(), true),
+ m_allocated(true)
+ {
+ }
+
+ template<
+ bool Requires = detail::conjunction<
+ std::is_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >,
+ std::is_assignable< internal_deleter_type&, typename detail::move_or_copy_assign_ref< deleter_type >::type >
+ >::value
+ >
+ typename std::enable_if< Requires, unique_resource_data& >::type operator= (unique_resource_data&& that)
+ noexcept(detail::conjunction<
+ std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >,
+ std::is_nothrow_assignable< internal_deleter_type&, typename detail::move_or_copy_assign_ref< deleter_type >::type >
+ >::value)
+ {
+ assign(static_cast< unique_resource_data&& >(that), typename std::is_nothrow_move_assignable< internal_deleter_type >::type());
+ return *this;
+ }
+
+ resource_type& get_resource() noexcept
+ {
+ return resource_holder::get();
+ }
+
+ resource_type const& get_resource() const noexcept
+ {
+ return resource_holder::get();
+ }
+
+ internal_resource_type& get_internal_resource() noexcept
+ {
+ return resource_holder::get_internal();
+ }
+
+ internal_resource_type const& get_internal_resource() const noexcept
+ {
+ return resource_holder::get_internal();
+ }
+
+ deleter_type& get_deleter() noexcept
+ {
+ return deleter_holder::get();
+ }
+
+ deleter_type const& get_deleter() const noexcept
+ {
+ return deleter_holder::get();
+ }
+
+ internal_deleter_type& get_internal_deleter() noexcept
+ {
+ return deleter_holder::get_internal();
+ }
+
+ internal_deleter_type const& get_internal_deleter() const noexcept
+ {
+ return deleter_holder::get_internal();
+ }
+
+ bool is_allocated() const noexcept
+ {
+ return m_allocated;
+ }
+
+ void set_unallocated() noexcept
+ {
+ m_allocated = false;
+ }
+
+ template< typename R >
+ void assign_resource(R&& res) noexcept(std::is_nothrow_assignable< internal_resource_type&, R >::value)
+ {
+ get_internal_resource() = static_cast< R&& >(res);
+ m_allocated = true;
+ }
+
+ template<
+ bool Requires = detail::conjunction<
+ detail::is_swappable< internal_resource_type >,
+ detail::is_swappable< internal_deleter_type >,
+ detail::disjunction<
+ detail::is_nothrow_swappable< internal_resource_type >,
+ detail::is_nothrow_swappable< internal_deleter_type >
+ >
+ >::value
+ >
+ typename std::enable_if< Requires >::type swap(unique_resource_data& that)
+ noexcept(detail::conjunction< detail::is_nothrow_swappable< internal_resource_type >, detail::is_nothrow_swappable< internal_deleter_type > >::value)
+ {
+ swap_impl
+ (
+ that,
+ std::integral_constant< bool, detail::is_nothrow_swappable< internal_resource_type >::value >(),
+ std::integral_constant< bool, detail::conjunction<
+ detail::is_nothrow_swappable< internal_resource_type >,
+ detail::is_nothrow_swappable< internal_deleter_type >
+ >::value >()
+ );
+ }
+
+private:
+ unique_resource_data(unique_resource_data&& that, std::true_type, std::true_type) noexcept :
+ resource_holder(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that.get_resource())),
+ deleter_holder(static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(that.get_deleter())),
+ m_allocated(that.m_allocated)
+ {
+ that.m_allocated = false;
+ }
+
+ unique_resource_data(unique_resource_data&& that, std::false_type, std::true_type) :
+ resource_holder(static_cast< resource_type const& >(that.get_resource())),
+ deleter_holder(static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(that.get_deleter())),
+ m_allocated(that.m_allocated)
+ {
+ that.m_allocated = false;
+ }
+
+ unique_resource_data(unique_resource_data&& that, std::true_type, std::false_type) try :
+ resource_holder(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that.get_resource())),
+ deleter_holder(static_cast< deleter_type const& >(that.get_deleter())),
+ m_allocated(that.m_allocated)
+ {
+ that.m_allocated = false;
+ }
+ catch (...)
+ {
+ // Since only the deleter's constructor could have thrown an exception here, move the resource back
+ // to the original unique_resource. This is guaranteed to not throw.
+ that.resource_holder::move_from(static_cast< internal_resource_type&& >(resource_holder::get_internal()));
+ }
+
+ unique_resource_data(unique_resource_data&& that, std::false_type, std::false_type) :
+ resource_holder(static_cast< resource_type const& >(that.get_resource())),
+ deleter_holder(static_cast< deleter_type const& >(that.get_deleter())),
+ m_allocated(that.m_allocated)
+ {
+ that.m_allocated = false;
+ }
+
+ void assign(unique_resource_data&& that, std::true_type)
+ noexcept(std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >::value)
+ {
+ get_internal_resource() = static_cast< typename detail::move_or_copy_assign_ref< resource_type >::type >(that.get_resource());
+ get_internal_deleter() = static_cast< typename detail::move_or_copy_assign_ref< deleter_type >::type >(that.get_deleter());
+
+ m_allocated = that.m_allocated;
+ that.m_allocated = false;
+ }
+
+ void assign(unique_resource_data&& that, std::false_type)
+ {
+ get_internal_deleter() = static_cast< typename detail::move_or_copy_assign_ref< deleter_type >::type >(that.get_deleter());
+ get_internal_resource() = static_cast< typename detail::move_or_copy_assign_ref< resource_type >::type >(that.get_resource());
+
+ m_allocated = that.m_allocated;
+ that.m_allocated = false;
+ }
+
+ void swap_impl(unique_resource_data& that, std::true_type, std::true_type) noexcept
+ {
+ boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
+ boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
+ boost::core::invoke_swap(m_allocated, that.m_allocated);
+ }
+
+ void swap_impl(unique_resource_data& that, std::true_type, std::false_type)
+ {
+ boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
+ boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
+ boost::core::invoke_swap(m_allocated, that.m_allocated);
+ }
+
+ void swap_impl(unique_resource_data& that, std::false_type, std::false_type)
+ {
+ boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
+ boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
+ boost::core::invoke_swap(m_allocated, that.m_allocated);
+ }
+};
+
+template< typename T >
+struct is_dereferenceable_impl
+{
+ template< typename U, typename R = decltype(*std::declval< U const& >()) >
+ static std::true_type _is_dereferenceable_check(int);
+ template< typename U >
+ static std::false_type _is_dereferenceable_check(...);
+
+ using type = decltype(is_dereferenceable_impl::_is_dereferenceable_check< T >(0));
+};
+
+template< typename T >
+struct is_dereferenceable : public is_dereferenceable_impl< T >::type { };
+template< >
+struct is_dereferenceable< void* > : public std::false_type { };
+template< >
+struct is_dereferenceable< const void* > : public std::false_type { };
+template< >
+struct is_dereferenceable< volatile void* > : public std::false_type { };
+template< >
+struct is_dereferenceable< const volatile void* > : public std::false_type { };
+template< >
+struct is_dereferenceable< void*& > : public std::false_type { };
+template< >
+struct is_dereferenceable< const void*& > : public std::false_type { };
+template< >
+struct is_dereferenceable< volatile void*& > : public std::false_type { };
+template< >
+struct is_dereferenceable< const volatile void*& > : public std::false_type { };
+template< >
+struct is_dereferenceable< void* const& > : public std::false_type { };
+template< >
+struct is_dereferenceable< const void* const& > : public std::false_type { };
+template< >
+struct is_dereferenceable< volatile void* const& > : public std::false_type { };
+template< >
+struct is_dereferenceable< const volatile void* const& > : public std::false_type { };
+template< >
+struct is_dereferenceable< void* volatile& > : public std::false_type { };
+template< >
+struct is_dereferenceable< const void* volatile& > : public std::false_type { };
+template< >
+struct is_dereferenceable< volatile void* volatile& > : public std::false_type { };
+template< >
+struct is_dereferenceable< const volatile void* volatile& > : public std::false_type { };
+template< >
+struct is_dereferenceable< void* const volatile& > : public std::false_type { };
+template< >
+struct is_dereferenceable< const void* const volatile& > : public std::false_type { };
+template< >
+struct is_dereferenceable< volatile void* const volatile& > : public std::false_type { };
+template< >
+struct is_dereferenceable< const volatile void* const volatile& > : public std::false_type { };
+
+template< typename T, bool = detail::is_dereferenceable< T >::value >
+struct dereference_traits { };
+template< typename T >
+struct dereference_traits< T, true >
+{
+ using result_type = decltype(*std::declval< T const& >());
+ static constexpr bool is_noexcept = noexcept(*std::declval< T const& >());
+};
+
+} // namespace detail
+
+/*!
+ * \brief RAII wrapper for automatically reclaiming arbitrary resources.
+ *
+ * A \c unique_resource object exclusively owns wrapped resource and invokes
+ * the deleter function object on it on destruction. The wrapped resource can have
+ * any type that is:
+ *
+ * \li Move-constructible, where the move constructor is marked as `noexcept`, or
+ * \li Copy-constructible, or
+ * \li An lvalue reference to an object type.
+ *
+ * The deleter must be a function object type that is callable on an lvalue
+ * of the resource type. The deleter must be copy-constructible.
+ *
+ * An optional resource traits template parameter may be specified. Resource
+ * traits can be used to optimize \c unique_resource implementation when
+ * the following conditions are met:
+ *
+ * \li There is at least one value of the resource type that is considered
+ * unallocated (that is, no allocated resource shall be equal to one of
+ * the unallocated resource values). The unallocated resource values need not
+ * be deallocated using the deleter.
+ * \li One of the unallocated resource values can be considered the default.
+ * Constructing the default resource value and assigning it to a resource
+ * object (whether allocated or not) shall not throw exceptions.
+ * \li Resource objects can be tested for being unallocated. Such a test shall
+ * not throw exceptions.
+ *
+ * If specified, the resource traits must be a class type that has the following
+ * public static members:
+ *
+ * \li `R make_default() noexcept` - must return the default resource value such
+ * that `std::is_constructible< Resource, R >::value &&
+ * std::is_nothrow_assignable< Resource&, R >::value` is \c true.
+ * \li `bool is_allocated(Resource const& res) noexcept` - must return \c true
+ * if \c res is not one of the unallocated resource values and \c false
+ * otherwise.
+ *
+ * Note that `is_allocated(make_default())` must always return \c false.
+ *
+ * When resource traits satisfying the above requirements are specified,
+ * \c unique_resource will be able to avoid storing additional indication of
+ * whether the owned resource object needs to be deallocated with the deleter
+ * on destruction. It will use the default resource value to initialize the owned
+ * resource object when \c unique_resource is not in the allocated state.
+ * Additionally, it will be possible to construct \c unique_resource with
+ * unallocated resource values, which will create \c unique_resource objects in
+ * unallocated state (the deleter will not be called on unallocated resource
+ * values).
+ *
+ * \tparam Resource Resource type.
+ * \tparam Deleter Resource deleter function object type.
+ * \tparam Traits Optional resource traits type.
+ */
+template< typename Resource, typename Deleter, typename Traits BOOST_SCOPE_DETAIL_DOC(= void) >
+class unique_resource
+{
+public:
+ //! Resource type
+ using resource_type = Resource;
+ //! Deleter type
+ using deleter_type = Deleter;
+ //! Resource traits
+ using traits_type = Traits;
+
+//! \cond
+private:
+ using data = detail::unique_resource_data< resource_type, deleter_type, traits_type >;
+ using internal_resource_type = typename data::internal_resource_type;
+ using internal_deleter_type = typename data::internal_deleter_type;
+
+ data m_data;
+
+//! \endcond
+public:
+ /*!
+ * \brief Constructs an unallocated unique resource guard.
+ *
+ * **Requires:** Default \c Resource value can be constructed. \c Deleter is default-constructible
+ * and is not a pointer to function.
+ *
+ * **Effects:** Initializes the \c Resource object with the default resource value. Default-constructs
+ * the \c Deleter object.
+ *
+ * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
+ *
+ * \post `this->allocated() == false`
+ */
+ //! \cond
+ template<
+ bool Requires = std::is_default_constructible< data >::value,
+ typename = typename std::enable_if< Requires >::type
+ >
+ //! \endcond
+ constexpr unique_resource() noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_default_constructible< data >::value))
+ {
+ }
+
+ /*!
+ * \brief Constructs an unallocated unique resource guard with the given deleter.
+ *
+ * **Requires:** Default \c Resource value can be constructed and \c Deleter is constructible from \a del.
+ *
+ * **Effects:** Initializes the \c Resource value with the default resource value. If \c Deleter is nothrow
+ * constructible from `D&&` then constructs \c Deleter from `std::forward< D >(del)`,
+ * otherwise constructs from `del`.
+ *
+ * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
+ *
+ * \param res A tag argument indicating default resource value.
+ * \param del Resource deleter function object.
+ *
+ * \post `this->allocated() == false`
+ */
+ template<
+ typename D
+ //! \cond
+ , typename = typename std::enable_if<
+ std::is_constructible< data, default_resource_t, typename detail::move_or_copy_construct_ref< D, deleter_type >::type >::value
+ >::type
+ //! \endcond
+ >
+ unique_resource(default_resource_t res, D&& del)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
+ std::is_nothrow_constructible<
+ data,
+ default_resource_t,
+ typename detail::move_or_copy_construct_ref< D, deleter_type >::type
+ >::value
+ )) :
+ m_data
+ (
+ res,
+ static_cast< typename detail::move_or_copy_construct_ref< D, deleter_type >::type >(del)
+ )
+ {
+ }
+
+ /*!
+ * \brief Constructs a unique resource guard with the given resource and a default-constructed deleter.
+ *
+ * **Requires:** \c Resource is constructible from \a res. \c Deleter is default-constructible and
+ * is not a pointer to function.
+ *
+ * **Effects:** Constructs the unique resource object as if by calling
+ * `unique_resource(std::forward< R >(res), Deleter())`.
+ *
+ * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
+ *
+ * \param res Resource object.
+ */
+ template<
+ typename R
+ //! \cond
+ , typename = typename std::enable_if< detail::conjunction<
+ detail::is_nothrow_nonnull_default_constructible< deleter_type >,
+ std::is_constructible< data, typename detail::move_or_copy_construct_ref< R, resource_type >::type, typename detail::move_or_copy_construct_ref< deleter_type >::type >,
+ detail::disjunction< detail::negation< std::is_reference< resource_type > >, std::is_reference< R > > // prevent binding lvalue-reference resource to an rvalue
+ >::value >::type
+ //! \endcond
+ >
+ explicit unique_resource(R&& res)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
+ std::is_nothrow_constructible<
+ data,
+ typename detail::move_or_copy_construct_ref< R, resource_type >::type,
+ typename detail::move_or_copy_construct_ref< deleter_type >::type
+ >::value
+ )) :
+ m_data
+ (
+ static_cast< typename detail::move_or_copy_construct_ref< R, resource_type >::type >(res),
+ static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(deleter_type())
+ )
+ {
+ }
+
+ /*!
+ * \brief Constructs a unique resource guard with the given resource and deleter.
+ *
+ * **Requires:** \c Resource is constructible from \a res and \c Deleter is constructible from \a del.
+ *
+ * **Effects:** If \c Resource is nothrow constructible from `R&&` then constructs \c Resource
+ * from `std::forward< R >(res)`, otherwise constructs from `res`. If \c Deleter
+ * is nothrow constructible from `D&&` then constructs \c Deleter from
+ * `std::forward< D >(del)`, otherwise constructs from `del`.
+ *
+ * If construction of \c Resource or \c Deleter throws and \a res is not an unallocated resource
+ * value, invokes \a del on \a res (if \c Resource construction failed) or the constructed
+ * \c Resource object (if \c Deleter construction failed).
+ *
+ * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
+ *
+ * \param res Resource object.
+ * \param del Resource deleter function object.
+ *
+ * \post If \a res is an unallocated resource value then `this->allocated() == false`, otherwise
+ * `this->allocated() == true`.
+ */
+ template<
+ typename R,
+ typename D
+ //! \cond
+ , typename = typename std::enable_if< detail::conjunction<
+ std::is_constructible< data, typename detail::move_or_copy_construct_ref< R, resource_type >::type, typename detail::move_or_copy_construct_ref< D, deleter_type >::type >,
+ detail::disjunction< detail::negation< std::is_reference< resource_type > >, std::is_reference< R > > // prevent binding lvalue-reference resource to an rvalue
+ >::value >::type
+ //! \endcond
+ >
+ unique_resource(R&& res, D&& del)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
+ std::is_nothrow_constructible<
+ data,
+ typename detail::move_or_copy_construct_ref< R, resource_type >::type,
+ typename detail::move_or_copy_construct_ref< D, deleter_type >::type
+ >::value
+ )) :
+ m_data
+ (
+ static_cast< typename detail::move_or_copy_construct_ref< R, resource_type >::type >(res),
+ static_cast< typename detail::move_or_copy_construct_ref< D, deleter_type >::type >(del)
+ )
+ {
+ }
+
+ unique_resource(unique_resource const&) = delete;
+ unique_resource& operator= (unique_resource const&) = delete;
+
+ /*!
+ * \brief Move-constructs a unique resource guard.
+ *
+ * **Requires:** \c Resource and \c Deleter are move-constructible.
+ *
+ * **Effects:** If \c Resource is nothrow move-constructible then move-constructs \c Resource,
+ * otherwise copy-constructs. If \c Deleter is nothrow move-constructible then move-constructs
+ * \c Deleter, otherwise copy-constructs. Deactivates the moved-from unique resource object.
+ *
+ * If an exception is thrown during construction, \a that is left in its original state.
+ *
+ * \note This logic ensures that in case of exception the resource is not leaked and remains owned by the
+ * move source.
+ *
+ * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
+ *
+ * \param that Move source.
+ *
+ * \post Let \c allocated be equal to `that.allocated()` prior to the operation. Then
+ * `this->allocated() == allocated` and `that.allocated() == false`.
+ */
+ //! \cond
+ template<
+ bool Requires = std::is_move_constructible< data >::value,
+ typename = typename std::enable_if< Requires >::type
+ >
+ //! \endcond
+ unique_resource(unique_resource&& that) noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_move_constructible< data >::value)) :
+ m_data(static_cast< data&& >(that.m_data))
+ {
+ }
+
+ /*!
+ * \brief Move-assigns a unique resource guard.
+ *
+ * **Requires:** \c Resource and \c Deleter are move-assignable.
+ *
+ * **Effects:** Calls `this->reset()`. Then, if \c Deleter is nothrow move-assignable, move-assigns
+ * the \c Deleter object first and the \c Resource object next. Otherwise, move-assigns
+ * the objects in reverse order. Lastly, deactivates the moved-from unique resource object.
+ *
+ * If an exception is thrown, \a that is left in its original state.
+ *
+ * \note The different orders of assignment ensure that in case of exception the resource is not leaked
+ * and remains owned by the move source.
+ *
+ * **Throws:** Nothing, unless assignment of \c Resource or \c Deleter throws.
+ *
+ * \param that Move source.
+ *
+ * \post Let \c allocated be equal to `that.allocated()` prior to the operation. Then
+ * `this->allocated() == allocated` and `that.allocated() == false`.
+ */
+#if !defined(BOOST_SCOPE_DOXYGEN)
+ template< bool Requires = std::is_move_assignable< data >::value >
+ typename std::enable_if< Requires, unique_resource& >::type
+#else
+ unique_resource&
+#endif
+ operator= (unique_resource&& that)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_move_assignable< data >::value))
+ {
+ reset();
+ m_data = static_cast< data&& >(that.m_data);
+ return *this;
+ }
+
+ /*!
+ * \brief If the resource is allocated, calls the deleter function on it. Destroys the resource and the deleter.
+ *
+ * **Throws:** Nothing, unless invoking the deleter throws.
+ */
+ ~unique_resource() noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_invocable< deleter_type&, resource_type& >::value))
+ {
+ if (BOOST_LIKELY(m_data.is_allocated()))
+ m_data.get_deleter()(m_data.get_resource());
+ }
+
+ /*!
+ * \brief Returns \c true if the resource is allocated and to be reclaimed by the deleter, otherwise \c false.
+ *
+ * \note This method does not test the value of the resource.
+ *
+ * **Throws:** Nothing.
+ */
+ explicit operator bool () const noexcept
+ {
+ return m_data.is_allocated();
+ }
+
+ /*!
+ * \brief Returns \c true if the resource is allocated and to be reclaimed by the deleter, otherwise \c false.
+ *
+ * **Throws:** Nothing.
+ */
+ bool allocated() const noexcept
+ {
+ return m_data.is_allocated();
+ }
+
+ /*!
+ * \brief Returns a reference to the resource object.
+ *
+ * **Throws:** Nothing.
+ */
+ resource_type const& get() const noexcept
+ {
+ return m_data.get_resource();
+ }
+
+ /*!
+ * \brief Returns a reference to the deleter object.
+ *
+ * **Throws:** Nothing.
+ */
+ deleter_type const& get_deleter() const noexcept
+ {
+ return m_data.get_deleter();
+ }
+
+ /*!
+ * \brief Marks the resource as unallocated. Does not call the deleter if the resource was previously allocated.
+ *
+ * **Throws:** Nothing.
+ *
+ * \post `this->allocated() == false`
+ */
+ void release() noexcept
+ {
+ m_data.set_unallocated();
+ }
+
+ /*!
+ * \brief If the resource is allocated, calls the deleter function on it and marks the resource as unallocated.
+ *
+ * **Throws:** Nothing, unless invoking the deleter throws.
+ *
+ * \post `this->allocated() == false`
+ */
+ void reset() noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_invocable< deleter_type&, resource_type& >::value))
+ {
+ if (BOOST_LIKELY(m_data.is_allocated()))
+ {
+ m_data.get_deleter()(m_data.get_resource());
+ m_data.set_unallocated();
+ }
+ }
+
+ /*!
+ * \brief Assigns a new resource object to the unique resource wrapper.
+ *
+ * **Effects:** Calls `this->reset()`. Then, if \c Resource is nothrow assignable from `R&&`,
+ * assigns `std::forward< R >(res)` to the stored resource object, otherwise assigns
+ * `res`.
+ *
+ * If \a res is not an unallocated resource value and an exception is thrown during the operation,
+ * invokes the stored deleter on \a res before returning with the exception.
+ *
+ * **Throws:** Nothing, unless invoking the deleter throws.
+ *
+ * \param res Resource object to assign.
+ *
+ * \post `this->allocated() == false`
+ */
+ template< typename R >
+#if !defined(BOOST_SCOPE_DOXYGEN)
+ typename std::enable_if< detail::conjunction<
+ std::is_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< R, resource_type >::type >,
+ detail::disjunction< detail::negation< std::is_reference< resource_type > >, std::is_reference< R > > // prevent binding lvalue-reference resource to an rvalue
+ >::value >::type
+#else
+ void
+#endif
+ reset(R&& res)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
+ detail::conjunction<
+ detail::is_nothrow_invocable< deleter_type&, resource_type& >,
+ std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< R, resource_type >::type >
+ >::value
+ ))
+ {
+ reset_impl
+ (
+ static_cast< R&& >(res),
+ typename detail::conjunction<
+ detail::is_nothrow_invocable< deleter_type&, resource_type& >,
+ std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< R, resource_type >::type >
+ >::type()
+ );
+ }
+
+ /*!
+ * \brief Invokes indirection on the resource object.
+ *
+ * **Requires:** \c Resource is dereferenceable.
+ *
+ * **Effects:** Returns a reference to the resource object as if by calling `get()`.
+ *
+ * \note If \c Resource is not a pointer type, the compiler will invoke its `operator->`.
+ * Such call sequence will continue until a pointer is obtained.
+ *
+ * **Throws:** Nothing. Note that any implicit subsequent calls to other `operator->`
+ * functions that are caused by this call may have different throw conditions.
+ */
+#if !defined(BOOST_SCOPE_DOXYGEN)
+ template< bool Requires = detail::is_dereferenceable< resource_type >::value >
+ typename std::enable_if< Requires, resource_type const& >::type
+#else
+ resource_type const&
+#endif
+ operator-> () const noexcept
+ {
+ return get();
+ }
+
+ /*!
+ * \brief Dereferences the resource object.
+ *
+ * **Requires:** \c Resource is dereferenceable.
+ *
+ * **Effects:** Returns the result of dereferencing the resource object as if by calling `*get()`.
+ *
+ * **Throws:** Nothing, unless dereferencing the resource object throws.
+ */
+#if !defined(BOOST_SCOPE_DOXYGEN)
+ template< bool Requires = detail::is_dereferenceable< resource_type >::value >
+ typename detail::dereference_traits< resource_type, Requires >::result_type
+#else
+ auto
+#endif
+ operator* () const
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::dereference_traits< resource_type, Requires >::is_noexcept))
+ {
+ return *get();
+ }
+
+ /*!
+ * \brief Swaps two unique resource wrappers.
+ *
+ * **Requires:** \c Resource and \c Deleter are swappable. At least one of \c Resource and \c Deleter
+ * is nothrow swappable.
+ *
+ * **Effects:** Swaps the resource objects and deleter objects stored in `*this` and \a that
+ * as if by calling unqualified `swap` in a context where `std::swap` is
+ * found by overload resolution.
+ *
+ * If an exception is thrown, and the failed swap operation supports strong exception
+ * guarantee, both `*this` and \a that are left in their original states.
+ *
+ * **Throws:** Nothing, unless swapping the resource objects or deleters throw.
+ *
+ * \param that Unique resource wrapper to swap with.
+ */
+#if !defined(BOOST_SCOPE_DOXYGEN)
+ template< bool Requires = detail::is_swappable< data >::value >
+ typename std::enable_if< Requires >::type
+#else
+ void
+#endif
+ swap(unique_resource& that)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_swappable< data >::value))
+ {
+ m_data.swap(that.m_data);
+ }
+
+ /*!
+ * \brief Swaps two unique resource wrappers.
+ *
+ * **Effects:** As if `left.swap(right)`.
+ */
+#if !defined(BOOST_SCOPE_DOXYGEN)
+ template< bool Requires = detail::is_swappable< data >::value >
+ friend typename std::enable_if< Requires >::type
+#else
+ friend void
+#endif
+ swap(unique_resource& left, unique_resource& right)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_swappable< data >::value))
+ {
+ left.swap(right);
+ }
+
+//! \cond
+private:
+ //! Assigns a new resource object to the unique resource wrapper.
+ template< typename R >
+ void reset_impl(R&& res, std::true_type) noexcept
+ {
+ reset();
+ m_data.assign_resource(static_cast< typename detail::move_or_copy_assign_ref< R, resource_type >::type >(res));
+ }
+
+ //! Assigns a new resource object to the unique resource wrapper.
+ template< typename R >
+ void reset_impl(R&& res, std::false_type)
+ {
+ try
+ {
+ reset();
+ m_data.assign_resource(static_cast< typename detail::move_or_copy_assign_ref< R, resource_type >::type >(res));
+ }
+ catch (...)
+ {
+ m_data.get_deleter()(static_cast< R&& >(res));
+ throw;
+ }
+ }
+//! \endcond
+};
+
+#if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
+template<
+ typename Resource,
+ typename Deleter,
+ typename = typename std::enable_if< !detail::is_default_resource< Resource >::value >::type
+>
+unique_resource(Resource, Deleter) -> unique_resource< Resource, Deleter >;
+#endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
+
+/*!
+ * \brief Checks if the resource is valid and creates a \c unique_resource wrapper.
+ *
+ * **Effects:** If the resource \a res is not equal to \a invalid, creates a unique resource wrapper
+ * that is in allocated state and owns \a res. Otherwise creates a unique resource wrapper
+ * in unallocated state.
+ *
+ * \note This function does not call \a del if \a res is equal to \a invalid.
+ *
+ * **Throws:** Nothing, unless \c unique_resource constructor throws.
+ *
+ * \param res Resource to wrap.
+ * \param invalid An invalid value for the resource.
+ * \param del A deleter to invoke on the resource to free it.
+ */
+template< typename Resource, typename Deleter, typename Invalid >
+inline unique_resource< typename std::decay< Resource >::type, typename std::decay< Deleter >::type >
+make_unique_resource_checked(Resource&& res, Invalid const& invalid, Deleter&& del)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
+ detail::conjunction<
+ std::is_nothrow_constructible< typename std::decay< Resource >::type, typename detail::move_or_copy_construct_ref< Resource, typename std::decay< Resource >::type >::type >,
+ std::is_nothrow_constructible< typename std::decay< Deleter >::type, typename detail::move_or_copy_construct_ref< Deleter, typename std::decay< Deleter >::type >::type >
+ >::value
+ ))
+{
+ using unique_resource_type = unique_resource< typename std::decay< Resource >::type, typename std::decay< Deleter >::type >;
+ if (!(res == invalid))
+ return unique_resource_type(static_cast< Resource&& >(res), static_cast< Deleter&& >(del));
+ else
+ return unique_resource_type(default_resource_t(), static_cast< Deleter&& >(del));
+}
+
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_UNIQUE_RESOURCE_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/include/boost/scope/unique_resource_fwd.hpp b/contrib/restricted/boost/scope/include/boost/scope/unique_resource_fwd.hpp
new file mode 100644
index 0000000000..aa9c30ec92
--- /dev/null
+++ b/contrib/restricted/boost/scope/include/boost/scope/unique_resource_fwd.hpp
@@ -0,0 +1,46 @@
+/*
+ * Distributed under the Boost Software License, Version 1.0.
+ * (See accompanying file LICENSE_1_0.txt or copy at
+ * https://www.boost.org/LICENSE_1_0.txt)
+ *
+ * Copyright (c) 2022 Andrey Semashev
+ */
+/*!
+ * \file scope/unique_resource_fwd.hpp
+ *
+ * This header contains forward declaration of \c unique_resource template.
+ */
+
+#ifndef BOOST_SCOPE_UNIQUE_RESOURCE_FWD_HPP_INCLUDED_
+#define BOOST_SCOPE_UNIQUE_RESOURCE_FWD_HPP_INCLUDED_
+
+#include <type_traits>
+#include <boost/scope/detail/config.hpp>
+#include <boost/scope/detail/move_or_copy_construct_ref.hpp>
+#include <boost/scope/detail/type_traits/conjunction.hpp>
+#include <boost/scope/detail/header.hpp>
+
+#ifdef BOOST_HAS_PRAGMA_ONCE
+#pragma once
+#endif
+
+namespace boost {
+namespace scope {
+
+template< typename Resource, typename Deleter, typename Traits = void >
+class unique_resource;
+
+template< typename Resource, typename Deleter, typename Invalid = typename std::decay< Resource >::type >
+unique_resource< typename std::decay< Resource >::type, typename std::decay< Deleter >::type >
+make_unique_resource_checked(Resource&& res, Invalid const& invalid, Deleter&& del)
+ noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::conjunction<
+ std::is_nothrow_constructible< typename std::decay< Resource >::type, typename detail::move_or_copy_construct_ref< Resource, typename std::decay< Resource >::type >::type >,
+ std::is_nothrow_constructible< typename std::decay< Deleter >::type, typename detail::move_or_copy_construct_ref< Deleter, typename std::decay< Deleter >::type >::type >
+ >::value));
+
+} // namespace scope
+} // namespace boost
+
+#include <boost/scope/detail/footer.hpp>
+
+#endif // BOOST_SCOPE_UNIQUE_RESOURCE_FWD_HPP_INCLUDED_
diff --git a/contrib/restricted/boost/scope/ya.make b/contrib/restricted/boost/scope/ya.make
new file mode 100644
index 0000000000..b81b5900fe
--- /dev/null
+++ b/contrib/restricted/boost/scope/ya.make
@@ -0,0 +1,27 @@
+# Generated by devtools/yamaker from nixpkgs 22.11.
+
+LIBRARY()
+
+LICENSE(BSL-1.0)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+VERSION(1.86.0)
+
+ORIGINAL_SOURCE(https://github.com/boostorg/scope/archive/boost-1.86.0.tar.gz)
+
+PEERDIR(
+ contrib/restricted/boost/config
+ contrib/restricted/boost/core
+ contrib/restricted/boost/type_traits
+)
+
+ADDINCL(
+ GLOBAL contrib/restricted/boost/scope/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+END()
diff --git a/contrib/restricted/expected-lite/.yandex_meta/devtools.copyrights.report b/contrib/restricted/expected-lite/.yandex_meta/devtools.copyrights.report
new file mode 100644
index 0000000000..8f9a274352
--- /dev/null
+++ b/contrib/restricted/expected-lite/.yandex_meta/devtools.copyrights.report
@@ -0,0 +1,41 @@
+# File format ($ symbol means the beginning of a line):
+#
+# $ # this message
+# $ # =======================
+# $ # comments (all commentaries should starts with some number of spaces and # symbol)
+# ${action} {license id} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/1/ya.make ./ya/make/2/ya.make
+# ${all_file_action} filename
+# $ # user commentaries (many lines)
+# $ generated description - files with this license, license text... (some number of lines that starts with some number of spaces, do not modify)
+# ${action} {license spdx} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/3/ya.make
+# ${all_file_action} filename
+# $ # user commentaries
+# $ generated description
+# $ ...
+#
+# You can modify action, all_file_action and add commentaries
+# Available actions:
+# keep - keep license in contrib and use in credits
+# skip - skip license
+# remove - remove all files with this license
+# rename - save license text/links into licenses texts file, but not store SPDX into LINCENSE macro. You should store correct license id into devtools.license.spdx.txt file
+#
+# {all file action} records will be generated when license text contains filename that exists on filesystem (in contrib directory)
+# We suppose that that files can contain some license info
+# Available all file actions:
+# FILE_IGNORE - ignore file (do nothing)
+# FILE_INCLUDE - include all file data into licenses text file
+# =======================
+
+KEEP COPYRIGHT_SERVICE_LABEL 81e2e1bd273033f7a382ceaf46d6ae84
+BELONGS ya.make
+ License text:
+ // Copyright (C) 2016-2020 Martin Moene.
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/nonstd/expected.hpp [3:3]
diff --git a/contrib/restricted/expected-lite/.yandex_meta/devtools.licenses.report b/contrib/restricted/expected-lite/.yandex_meta/devtools.licenses.report
new file mode 100644
index 0000000000..e7b3d6ba44
--- /dev/null
+++ b/contrib/restricted/expected-lite/.yandex_meta/devtools.licenses.report
@@ -0,0 +1,79 @@
+# File format ($ symbol means the beginning of a line):
+#
+# $ # this message
+# $ # =======================
+# $ # comments (all commentaries should starts with some number of spaces and # symbol)
+# ${action} {license id} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/1/ya.make ./ya/make/2/ya.make
+# ${all_file_action} filename
+# $ # user commentaries (many lines)
+# $ generated description - files with this license, license text... (some number of lines that starts with some number of spaces, do not modify)
+# ${action} {license spdx} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/3/ya.make
+# ${all_file_action} filename
+# $ # user commentaries
+# $ generated description
+# $ ...
+#
+# You can modify action, all_file_action and add commentaries
+# Available actions:
+# keep - keep license in contrib and use in credits
+# skip - skip license
+# remove - remove all files with this license
+# rename - save license text/links into licenses texts file, but not store SPDX into LINCENSE macro. You should store correct license id into devtools.license.spdx.txt file
+#
+# {all file action} records will be generated when license text contains filename that exists on filesystem (in contrib directory)
+# We suppose that that files can contain some license info
+# Available all file actions:
+# FILE_IGNORE - ignore file (do nothing)
+# FILE_INCLUDE - include all file data into licenses text file
+# =======================
+
+SKIP IPL-1.0 18358e6da236a2ee9e6e43715ed951f6
+BELONGS ya.make
+ # Not a license
+ Note: matched license text is too long. Read it in the source files.
+ Scancode info:
+ Original SPDX id: IPL-1.0
+ Score : 57.14
+ Match type : REFERENCE
+ Links : http://www.opensource.org/licenses/ibmpl.php, https://spdx.org/licenses/IPL-1.0
+ Files with this license:
+ README.md [3:3]
+
+KEEP BSL-1.0 2c7a3fa82e66676005cd4ee2608fd7d2
+BELONGS ya.make
+ Note: matched license text is too long. Read it in the source files.
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 100.00
+ Match type : TEXT
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ LICENSE.txt [1:23]
+
+KEEP BSL-1.0 73a2516db620f6413502ee77bdb4af88
+BELONGS ya.make
+ License text:
+ *expected lite* is distributed under the [Boost Software License](https://github.com/martinmoene/XXXX-lite/blob/master/LICENSE.txt).
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 100.00
+ Match type : NOTICE
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ README.md [76:76]
+
+KEEP BSL-1.0 cccf0dd010adef3878bb56734414eca6
+BELONGS ya.make
+FILE_INCLUDE LICENSE.txt found in files: include/nonstd/expected.hpp at line 6
+ License text:
+ // Distributed under the Boost Software License, Version 1.0.
+ // (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ Scancode info:
+ Original SPDX id: BSL-1.0
+ Score : 100.00
+ Match type : NOTICE
+ Links : http://www.boost.org/LICENSE_1_0.txt, http://www.boost.org/users/license.html, https://spdx.org/licenses/BSL-1.0
+ Files with this license:
+ include/nonstd/expected.hpp [5:6]
diff --git a/contrib/restricted/expected-lite/.yandex_meta/licenses.list.txt b/contrib/restricted/expected-lite/.yandex_meta/licenses.list.txt
new file mode 100644
index 0000000000..481545b760
--- /dev/null
+++ b/contrib/restricted/expected-lite/.yandex_meta/licenses.list.txt
@@ -0,0 +1,62 @@
+====================BSL-1.0====================
+*expected lite* is distributed under the [Boost Software License](https://github.com/martinmoene/XXXX-lite/blob/master/LICENSE.txt).
+
+
+====================BSL-1.0====================
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+
+====================BSL-1.0====================
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+====================COPYRIGHT====================
+// Copyright (C) 2016-2020 Martin Moene.
+
+
+====================File: LICENSE.txt====================
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/contrib/restricted/expected-lite/CHANGES.txt b/contrib/restricted/expected-lite/CHANGES.txt
new file mode 100644
index 0000000000..9c18a5702f
--- /dev/null
+++ b/contrib/restricted/expected-lite/CHANGES.txt
@@ -0,0 +1,5 @@
+Changes for expected lite
+
+version 0.0 2016-03-13
+
+- Initial code commit.
diff --git a/contrib/restricted/expected-lite/LICENSE.txt b/contrib/restricted/expected-lite/LICENSE.txt
new file mode 100644
index 0000000000..36b7cd93cd
--- /dev/null
+++ b/contrib/restricted/expected-lite/LICENSE.txt
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/contrib/restricted/expected-lite/README.md b/contrib/restricted/expected-lite/README.md
new file mode 100644
index 0000000000..bbef2e20f8
--- /dev/null
+++ b/contrib/restricted/expected-lite/README.md
@@ -0,0 +1,506 @@
+# expected lite: expected objects for C++11 and later
+
+[![Language](https://img.shields.io/badge/C%2B%2B-11-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization) [![License](https://img.shields.io/badge/license-BSL-blue.svg)](https://opensource.org/licenses/BSL-1.0) [![Build Status](https://github.com/martinmoene/expected-lite/actions/workflows/ci.yml/badge.svg)](https://github.com/martinmoene/expected-lite/actions/workflows/ci.yml) [![Build status](https://ci.appveyor.com/api/projects/status/sle31w7obrm8lhe1?svg=true)](https://ci.appveyor.com/project/martinmoene/expected-lite) [![Version](https://badge.fury.io/gh/martinmoene%2Fexpected-lite.svg)](https://github.com/martinmoene/expected-lite/releases) [![download](https://img.shields.io/badge/latest-download-blue.svg)](https://raw.githubusercontent.com/martinmoene/expected-lite/master/include/nonstd/expected.hpp) [![Conan](https://img.shields.io/badge/on-conan-blue.svg)](https://conan.io/center/expected-lite) [![Vcpkg](https://img.shields.io/badge/on-vcpkg-blue.svg)](https://vcpkg.link/ports/expected-lite) [![Try it online](https://img.shields.io/badge/on-wandbox-blue.svg)](https://wandbox.org/permlink/MnnwqOtE8ZQ4rRsv) [![Try it on godbolt online](https://img.shields.io/badge/on-godbolt-blue.svg)](https://godbolt.org/z/9BuMZx)
+
+*expected lite* is a single-file header-only library for objects that either represent a valid value or an error that you can pass by value. It is intended for use with C++11 and later. The library is based on the [std:&#58;expected](http://wg21.link/p0323) proposal [1] .
+
+**Contents**
+- [Example usage](#example-usage)
+- [In a nutshell](#in-a-nutshell)
+- [License](#license)
+- [Dependencies](#dependencies)
+- [Installation](#installation)
+- [Synopsis](#synopsis)
+- [Comparison with like types](#comparison)
+- [Reported to work with](#reported-to-work-with)
+- [Implementation notes](#implementation-notes)
+- [Other implementations of expected](#other-implementations-of-expected)
+- [Notes and references](#notes-and-references)
+- [Appendix](#appendix)
+
+## Example usage
+
+```Cpp
+#include "nonstd/expected.hpp"
+
+#include <cstdlib>
+#include <iostream>
+#include <string>
+
+using namespace nonstd;
+using namespace std::literals;
+
+auto to_int( char const * const text ) -> expected<int, std::string>
+{
+ char * pos = nullptr;
+ auto value = strtol( text, &pos, 0 );
+
+ if ( pos != text ) return value;
+ else return make_unexpected( "'"s + text + "' isn't a number" );
+}
+
+int main( int argc, char * argv[] )
+{
+ auto text = argc > 1 ? argv[1] : "42";
+
+ auto ei = to_int( text );
+
+ if ( ei ) std::cout << "'" << text << "' is " << *ei << ", ";
+ else std::cout << "Error: " << ei.error();
+}
+```
+
+### Compile and run
+
+```
+prompt> g++ -std=c++14 -Wall -I../include -o 01-basic.exe 01-basic.cpp && 01-basic.exe 123 && 01-basic.exe abc
+'123' is 123, Error: 'abc' isn't a number
+```
+
+## In a nutshell
+
+**expected lite** is a single-file header-only library to represent value objects that either contain a valid value or an error. The library is a partly implementation of the proposal for [std:&#58;expected](http://wg21.link/p0323) [1,2,3] for use with C++11 and later.
+
+**Some Features and properties of expected lite** are ease of installation (single header), default and explicit construction of an expected, construction and assignment from a value that is convertible to the underlying type, copy- and move-construction and copy- and move-assignment from another expected of the same type, testing for the presence of a value, operators for unchecked access to the value or the error (pointer or reference), value() and value_or() for checked access to the value, relational operators, swap() and various factory functions.
+
+Version 0.7.0 introduces the monadic operations of propsoal [p2505](http://wg21.link/p2505).
+
+*expected lite* shares the approach to in-place tags with [any-lite](https://github.com/martinmoene/any-lite), [optional-lite](https://github.com/martinmoene/optional-lite) and with [variant-lite](https://github.com/martinmoene/variant-lite) and these libraries can be used together.
+
+**Not provided** are reference-type expecteds. *expected lite* doesn't honour triviality of value and error types. *expected lite* doesn't handle overloaded *address of* operators.
+
+For more examples, see [1].
+
+## License
+
+*expected lite* is distributed under the [Boost Software License](https://github.com/martinmoene/XXXX-lite/blob/master/LICENSE.txt).
+
+## Dependencies
+
+*expected lite* has no other dependencies than the [C++ standard library](http://en.cppreference.com/w/cpp/header).
+
+## Installation
+
+*expected lite* is a single-file header-only library. Put `expected.hpp` directly into the project source tree or somewhere reachable from your project.
+
+## Synopsis
+
+**Contents**
+- [Configuration](#configuration)
+- [Types in namespace nonstd](#types-in-namespace-nonstd)
+- [Interface of expected](#interface-of-expected)
+- [Algorithms for expected](#algorithms-for-expected)
+- [Interface of unexpected_type](#interface-of-unexpected_type)
+- [Algorithms for unexpected_type](#algorithms-for-unexpected_type)
+
+### Configuration
+
+#### Tweak header
+
+If the compiler supports [`__has_include()`](https://en.cppreference.com/w/cpp/preprocessor/include), *expected lite* supports the [tweak header](https://vector-of-bool.github.io/2020/10/04/lib-configuration.html) mechanism. Provide your *tweak header* as `nonstd/expected.tweak.hpp` in a folder in the include-search-path. In the tweak header, provide definitions as documented below, like `#define expected_CPLUSPLUS 201103L`.
+
+#### Standard selection macro
+
+\-D<b>nsel\_CPLUSPLUS</b>=199711L
+Define this macro to override the auto-detection of the supported C++ standard, or if your compiler does not set the `__cplusplus` macro correctly.
+
+#### Select `std::expected` or `nonstd::expected`
+
+At default, *expected lite* uses `std::expected` if it is available and lets you use it via namespace `nonstd`. You can however override this default and explicitly request to use `std::expected` or expected lite's `nonstd::expected` as `nonstd::expected` via the following macros.
+
+-D<b>nsel\_CONFIG\_SELECT\_EXPECTED</b>=nsel_EXPECTED_DEFAULT
+Define this to `nsel_EXPECTED_STD` to select `std::expected` as `nonstd::expected`. Define this to `nsel_EXPECTED_NONSTD` to select `nonstd::expected` as `nonstd::expected`. Default is undefined, which has the same effect as defining to `nsel_EXPECTED_DEFAULT`.
+
+-D<b>nsel\_P0323R</b>=7 *(default)*
+Define this to the proposal revision number to control the presence and behavior of features (see tables). Default is 7 for the latest revision.
+
+#### Disable C++ exceptions
+
+-D<b>nsel\_CONFIG\_NO\_EXCEPTIONS</b>=0
+Define this to 1 if you want to compile without exceptions. If not defined, the header tries and detect if exceptions have been disabled (e.g. via `-fno-exceptions` or `/kernel`). Default determined in header.
+
+#### Enable SEH exceptions
+
+-D<b>nsel\_CONFIG\_NO\_EXCEPTIONS\_SEH</b>=0
+Define this to 1 or 0 to control the use of SEH when C++ exceptions are disabled (see above). If not defined, the header tries and detect if SEH is available if C++ exceptions have been disabled (e.g. via `-fno-exceptions` or `/kernel`). Default determined in header.
+
+#### Enable compilation errors
+
+\-D<b>nsel\_CONFIG\_CONFIRMS\_COMPILATION\_ERRORS</b>=0
+Define this macro to 1 to experience the by-design compile-time errors of the library in the test suite. Default is 0.
+
+#### Configure P2505 monadic operations
+
+By default, *expected lite* provides monadic operations as described in [P2505R5](http://wg21.link/p2505r5). You can disable these operations by defining the following macro.
+
+-D<b>nsel\_P2505R</b>=0
+
+You can use the R3 revision of P2505, which lacks `error_or`, and uses `remove_cvref` for transforms, by defining the following macro.
+
+-D<b>nsel\_P2505R</b>=3
+
+### Types in namespace nonstd
+
+| Purpose | Type | Note / Object |
+|-----------------|------|---------------|
+| Expected | template&lt;typename T, typename E = std::exception_ptr><br>class **expected**; | nsel_P0323 <= 2 |
+| Expected | template&lt;typename T, typename E><br>class **expected**; | nsel_P0323 > 2 |
+| Error type | template&lt;typename E><br>class **unexpected_type**; | &nbsp; |
+| Error type | template&lt;><br>class **unexpected_type**&lt;std::exception_ptr>; | nsel_P0323 <= 2 |
+| Error type | template&lt;typename E><br>class **unexpected**; | >= C++17 |
+| Traits | template&lt;typename E><br>struct **is_unexpected**; | nsel_P0323 <= 3 |
+| In-place value construction | struct **in_place_t**; | in_place_t in_place{}; |
+| In-place error construction | struct **in_place_unexpected_t**; | in_place_unexpected_t<br>unexpect{}; |
+| In-place error construction | struct **in_place_unexpected_t**; | in_place_unexpected_t<br>in_place_unexpected{}; |
+| Error reporting | class **bad_expected_access**; |&nbsp; |
+
+### Interface of expected
+
+| Kind | Method | Result |
+|--------------|-------------------------------------------------------------------------|--------|
+| Construction | [constexpr] **expected**() noexcept(...) | an object with default value |
+| &nbsp; | [constexpr] **expected**( expected const & other ) | initialize to contents of other |
+| &nbsp; | [constexpr] **expected**( expected && other ) | move contents from other |
+| &nbsp; | [constexpr] **expected**( value_type const & value ) | initialize to value |
+| &nbsp; | [constexpr] **expected**( value_type && value ) noexcept(...) | move from value |
+| &nbsp; | [constexpr] explicit **expected**( in_place_t, Args&&... args ) | construct value in-place from args |
+| &nbsp; | [constexpr] explicit **expected**( in_place_t,<br>&emsp;std::initializer_list&lt;U> il, Args&&... args ) | construct value in-place from args |
+| &nbsp; | [constexpr] **expected**( unexpected_type<E> const & error ) | initialize to error |
+| &nbsp; | [constexpr] **expected**( unexpected_type<E> && error ) | move from error |
+| &nbsp; | [constexpr] explicit **expected**( in_place_unexpected_t,<br>&emsp;Args&&... args ) | construct error in-place from args |
+| &nbsp; | [constexpr] explicit **expected**( in_place_unexpected_t,<br>&emsp;std::initializer_list&lt;U> il, Args&&... args )| construct error in-place from args |
+| Destruction | ~**expected**() | destruct current content |
+| Assignment | expected **operator=**( expected const & other ) | assign contents of other;<br>destruct current content, if any |
+| &nbsp; | expected & **operator=**( expected && other ) noexcept(...) | move contents of other |
+| &nbsp; | expected & **operator=**( U && v ) | move value from v |
+| &nbsp; | expected & **operator=**( unexpected_type<E> const & u ) | initialize to unexpected |
+| &nbsp; | expected & **operator=**( unexpected_type<E> && u ) | move from unexpected |
+| &nbsp; | template&lt;typename... Args><br>void **emplace**( Args &&... args ) | emplace from args |
+| &nbsp; | template&lt;typename U, typename... Args><br>void **emplace**( std::initializer_list&lt;U> il, Args &&... args ) | emplace from args |
+| Swap | void **swap**( expected & other ) noexcept | swap with other |
+| Observers | constexpr value_type const \* **operator->**() const | pointer to current content (const);<br>must contain value |
+| &nbsp; | value_type \* **operator->**() | pointer to current content (non-const);<br>must contain value |
+| &nbsp; | constexpr value_type const & **operator \***() const & | the current content (const ref);<br>must contain value |
+| &nbsp; | constexpr value_type && **operator \***() && | the current content (non-const ref);<br>must contain value |
+| &nbsp; | constexpr explicit operator **bool**() const noexcept | true if contains value |
+| &nbsp; | constexpr **has_value**() const noexcept | true if contains value |
+| &nbsp; | constexpr value_type const & **value**() const & | current content (const ref);<br>see [note 1](#note1) |
+| &nbsp; | value_type & **value**() & | current content (non-const ref);<br>see [note 1](#note1) |
+| &nbsp; | constexpr value_type && **value**() && | move from current content;<br>see [note 1](#note1) |
+| &nbsp; | constexpr error_type const & **error**() const & | current error (const ref);<br>must contain error |
+| &nbsp; | error_type & **error**() & | current error (non-const ref);<br>must contain error |
+| &nbsp; | constexpr error_type && **error**() && | move from current error;<br>must contain error |
+| &nbsp; | constexpr unexpected_type<E> **get_unexpected**() const | the error as unexpected&lt;>;<br>must contain error |
+| &nbsp; | template&lt;typename Ex><br>bool **has_exception**() const | true of contains exception (as base) |
+| &nbsp; | value_type **value_or**( U && v ) const & | value or move from v |
+| &nbsp; | value_type **value_or**( U && v ) && | move from value or move from v |
+| &nbsp; | constexpr error_type **error_or**( G && e ) const & | return current error or v [requires nsel_P2505R >= 4] |
+| &nbsp; | constexpr error_type **error_or**( G && e ) && | move from current error or from v [requires nsel_P2505R >=4] |
+| Monadic operations<br>(requires nsel_P2505R >= 3) | constexpr auto **and_then**( F && f ) & G| return f(value()) if has value, otherwise the error |
+| &nbsp; | constexpr auto **and_then**( F && f ) const & | return f(value()) if has value, otherwise the error |
+| &nbsp; | constexpr auto **and_then**( F && f ) && | return f(std::move(value())) if has value, otherwise the error |
+| &nbsp; | constexpr auto **and_then**( F && f ) const && | return f(std::move(value())) if has value, otherwise the error |
+| &nbsp; | constexpr auto **or_else**( F && f ) & | return the value, or f(error()) if there is no value |
+| &nbsp; | constexpr auto **or_else**( F && f ) const & | return the value, or f(error()) if there is no value |
+| &nbsp; | constexpr auto **or_else**( F && f ) && | return the value, or f(std::move(error())) if there is no value |
+| &nbsp; | constexpr auto **or_else**( F && f ) const && | return the value, or f(std::move(error())) if there is no value |
+| &nbsp; | constexpr auto **transform**( F && f ) & | return f(value()) wrapped if has value, otherwise the error |
+| &nbsp; | constexpr auto **transform**( F && f ) const & | return f(value()) wrapped if has value, otherwise the error |
+| &nbsp; | constexpr auto **transform**( F && f ) && | return f(std::move(value())) wrapped if has value, otherwise the error |
+| &nbsp; | constexpr auto **transform**( F && f ) const && | return f(std::move(value())) wrapped if has value, otherwise the error |
+| &nbsp; | constexpr auto **transform_error**( F && f ) & | return the value if has value, or f(error()) otherwise |
+| &nbsp; | constexpr auto **transform_error**( F && f ) const & | return the value if has value, or f(error()) otherwise |
+| &nbsp; | constexpr auto **transform_error**( F && f ) && | return the value if has value, or f(std::move(error())) otherwise |
+| &nbsp; | constexpr auto **transform_error**( F && f ) const && | return the value if has value, or f(std::move(error())) otherwise |
+| &nbsp; | ... | &nbsp; |
+
+<a id="note1"></a>Note 1: checked access: if no content, for std::exception_ptr rethrows error(), otherwise throws bad_expected_access(error()).
+
+### Algorithms for expected
+
+| Kind | Function |
+|---------------------------------|----------|
+| Comparison with expected | &nbsp; |
+| ==&ensp;!= | template&lt;typename T1, typename E1, typename T2, typename E2><br>constexpr bool operator ***op***(<br>&emsp;expected&lt;T1,E1> const & x,<br>&emsp;expected&lt;T2,E2> const & y ) |
+| Comparison with expected | nsel_P0323R <= 2 |
+| <&ensp;>&ensp;<=&ensp;>= | template&lt;typename T, typename E><br>constexpr bool operator ***op***(<br>&emsp;expected&lt;T,E> const & x,<br>&emsp;expected&lt;T,E> const & y ) |
+| Comparison with unexpected_type | &nbsp; |
+| ==&ensp;!= | template&lt;typename T1, typename E1, typename E2><br>constexpr bool operator ***op***(<br>&emsp;expected&lt;T1,E1> const & x,<br>&emsp;unexpected_type&lt;E2> const & u ) |
+| &nbsp; | template&lt;typename T1, typename E1, typename E2><br>constexpr bool operator ***op***(<br>&emsp;unexpected_type&lt;E2> const & u,<br>&emsp;expected&lt;T1,E1> const & x ) |
+| Comparison with unexpected_type | nsel_P0323R <= 2 |
+| <&ensp;>&ensp;<=&ensp;>= | template&lt;typename T, typename E><br>constexpr bool operator ***op***(<br>&emsp;expected&lt;T,E> const & x,<br>&emsp;unexpected_type&lt;E> const & u ) |
+| &nbsp; | template&lt;typename T, typename E><br>constexpr bool operator ***op***(<br>&emsp;unexpected_type&lt;E> const & u,<br>&emsp;expected&lt;T,E> const & x ) |
+| Comparison with T | &nbsp; |
+| ==&ensp;!= | template&lt;typename T, typename E><br>constexpr bool operator ***op***(<br>&emsp;expected&lt;T,E> const & x,<br>&emsp;T const & v ) |
+| &nbsp; | template&lt;typename T, typename E><br>constexpr bool operator ***op***(<br>&emsp;T const & v,<br>&emsp;expected&lt;T,E> const & x ) |
+| Comparison with T | nsel_P0323R <= 2 |
+| <&ensp;>&ensp;<=&ensp;>= | template&lt;typename T, typename E><br>constexpr bool operator ***op***(<br>&emsp;expected&lt;T,E> const & x,<br>&emsp;T const & v ) |
+| &nbsp; | template&lt;typename T, typename E><br>constexpr bool operator ***op***(<br>&emsp;T const & v,<br>&emsp;expected&lt;T,E> const & x ) |
+| Specialized algorithms | &nbsp; |
+| Swap | template&lt;typename T, typename E><br>void **swap**(<br>&emsp;expected&lt;T,E> & x,<br>&emsp;expected&lt;T,E> & y )&emsp;noexcept( noexcept( x.swap(y) ) ) |
+| Make expected from | nsel_P0323R <= 3 |
+| &emsp;Value | template&lt;typename T><br>constexpr auto **make_expected**( T && v ) -><br>&emsp;expected< typename std::decay&lt;T>::type> |
+| &emsp;Nothing | auto **make_expected**() -> expected&lt;void> |
+| &emsp;Current exception | template&lt;typename T><br>constexpr auto **make_expected_from_current_exception**() -> expected&lt;T> |
+| &emsp;Exception | template&lt;typename T><br>auto **make_expected_from_exception**( std::exception_ptr v ) -> expected&lt;T>|
+| &emsp;Error | template&lt;typename T, typename E><br>constexpr auto **make_expected_from_error**( E e ) -><br>&emsp;expected&lt;T, typename std::decay&lt;E>::type> |
+| &emsp;Call | template&lt;typename F><br>auto **make_expected_from_call**( F f ) -><br>&emsp;expected< typename std::result_of&lt;F()>::type>|
+| &emsp;Call, void specialization | template&lt;typename F><br>auto **make_expected_from_call**( F f ) -> expected&lt;void> |
+
+### Interface of unexpected_type
+
+| Kind | Method | Result |
+|--------------|-----------------------------------------------------------|--------|
+| Construction | **unexpected_type**() = delete; | no default construction |
+| &nbsp; | constexpr explicit **unexpected_type**( E const & error ) | copy-constructed from an E |
+| &nbsp; | constexpr explicit **unexpected_type**( E && error ) | move-constructed from an E |
+| Observers | constexpr error_type const & **error**() const | can observe contained error |
+| &nbsp; | error_type & **error**() | can modify contained error |
+| deprecated | constexpr error_type const & **value**() const | can observe contained error |
+| deprecated | error_type & **value**() | can modify contained error |
+
+### Algorithms for unexpected_type
+
+| Kind | Function |
+|-------------------------------|----------|
+| Comparison with unexpected | &nbsp; |
+| ==&ensp;!= | template&lt;typename E><br>constexpr bool operator ***op***(<br>&emsp;unexpected_type&lt;E> const & x,<br>&emsp;unexpected_type&lt;E> const & y ) |
+| Comparison with unexpected | nsel_P0323R <= 2 |
+| <&ensp;>&ensp;<=&ensp;>= | template&lt;typename E><br>constexpr bool operator ***op***(<br>&emsp;unexpected_type&lt;E> const & x,<br>&emsp;unexpected_type&lt;E> const & y ) |
+| Comparison with exception_ptr | &nbsp; |
+| ==&ensp;!= | constexpr bool operator ***op***(<br>&emsp;unexpected_type&lt;std::exception_ptr> const & x,<br>&emsp;unexpected_type&lt;std::exception_ptr> const & y ) |
+| Comparison with exception_ptr | nsel_P0323R <= 2 |
+| <&ensp;>&ensp;<=&ensp;>= | constexpr bool operator ***op***(<br>&emsp;unexpected_type&lt;std::exception_ptr> const & x,<br>&emsp;unexpected_type&lt;std::exception_ptr> const & y ) |
+| Specialized algorithms | &nbsp; |
+| Make unexpected from | &nbsp; |
+| &emsp;Error | template&lt;typename E><br>[constexpr] auto **make_unexpected**( E && v) -><br>&emsp;unexpected_type< typename std::decay&lt;E>::type>|
+| Make unexpected from | nsel_P0323R <= 3 |
+| &emsp;Current exception | [constexpr] auto **make_unexpected_from_current_exception**() -><br>&emsp;unexpected_type< std::exception_ptr>|
+
+<a id="comparison"></a>
+## Comparison with like types
+
+|Feature |<br>std::pair|std:: optional |std:: expected |nonstd:: expected |Boost. Expected |Nonco expected |Andrei Expected |Hagan required |
+|----------------------|-------------|---------------|---------------|------------------|----------------|---------------|----------------|---------------|
+|More information | see [14] | see [5] | see [1] | this work | see [4] | see [7] | see [8] | see [13] |
+| | | | | | | | | |
+| C++03 | yes | no | no | no/not yet | no (union) | no | no | yes |
+| C++11 | yes | no | no | yes | yes | yes | yes | yes |
+| C++14 | yes | no | no | yes | yes | yes | yes | yes |
+| C++17 | yes | yes | no | yes | yes | yes | yes | yes |
+| | | | | | | | | |
+|DefaultConstructible | T param | yes | yes | yes | yes | no | no | no |
+|In-place construction | no | yes | yes | yes | yes | yes | no | no |
+|Literal type | yes | yes | yes | yes | yes | no | no | no |
+| | | | | | | | | |
+|Disengaged information| possible | no | yes | yes | yes | yes | yes | no |
+|Vary disengaged type | yes | no | yes | yes | yes | no | no | no |
+|Engaged nonuse throws | no | no | no | no | error_traits | no | no | yes |
+|Disengaged use throws | no | yes, value() | yes, value() | yes, value() | yes,<br>value()| yes,<br>get() | yes,<br>get() | n/a |
+| | | | | | | | | |
+|Proxy (rel.ops) | no | yes | yes | yes | yes | no | no | no |
+|References | no | yes | no/not yet | no/not yet | no/not yet | yes | no | no |
+|Chained visitor(s) | no | no | yes | yes | yes | no | no | no |
+
+Note 1: std:&#58;*experimental*:&#58;expected
+
+Note 2: sources for [Nonco expected](https://github.com/martinmoene/spike-expected/tree/master/nonco), [Andrei Expected](https://github.com/martinmoene/spike-expected/tree/master/alexandrescu) and [Hagan required](https://github.com/martinmoene/spike-expected/tree/master/hagan) can befound in the [spike-expected](https://github.com/martinmoene/spike-expected) repository.
+
+## Reported to work with
+
+TBD
+
+## Implementation notes
+
+TBD
+
+## Other implementations of expected
+
+- Simon Brand. [C++11/14/17 std::expected with functional-style extensions](https://github.com/TartanLlama/expected). Single-header.
+- Isabella Muerte. [MNMLSTC Core](https://github.com/mnmlstc/core) (C++11).
+- Vicente J. Botet Escriba. [stdmake's expected](https://github.com/viboes/std-make/tree/master/include/experimental/fundamental/v3/expected) (C++17).
+- Facebook. [ Folly's Expected.h](https://github.com/facebook/folly/blob/master/folly/Expected.h) (C++14).
+
+## Notes and references
+
+[1] Vicente J. Botet Escriba. [p0323 - A proposal to add a utility class to represent expected object (latest)](http://wg21.link/p0323) (HTML). ([r12](http://wg21.link/p0323r12), [r11](http://wg21.link/p0323r11), [r10](http://wg21.link/p0323r10), [r9](http://wg21.link/p0323r9), [r8](http://wg21.link/p0323r8), [r7](http://wg21.link/p0323r7), [r6](http://wg21.link/p0323r6), [r5](http://wg21.link/p0323r5), [r4](http://wg21.link/p0323r4), [r3](http://wg21.link/p0323r3), [r2](http://wg21.link/p0323r2), [r1](http://wg21.link/n4109), [r0](http://wg21.link/n4015), [draft](https://github.com/viboes/std-make/blob/master/doc/proposal/expected/DXXXXR0_expected.pdf)).
+
+[2] Vicente J. Botet Escriba. [JASEL: Just a simple experimental library for C++](https://github.com/viboes/std-make). Reference implementation of [expected](https://github.com/viboes/std-make/tree/master/include/experimental/fundamental/v3/expected).
+
+[3] Vicente J. Botet Escriba. [Expected - An exception-friendly Error Monad](https://www.youtube.com/watch?v=Zdlt1rgYdMQ). C++Now 2014. 24 September 2014.
+
+[4] Pierre Talbot. [Boost.Expected. Unofficial Boost candidate](http://www.google-melange.com/gsoc/proposal/review/google/gsoc2013/trademark/25002). 5 May 2013. [GitHub](https://github.com/TrademarkPewPew/Boost.Expected), [GSoC 2013 Proposal](http://www.google-melange.com/gsoc/proposal/review/google/gsoc2013/trademark/25002), [boost@lists.boost.org](http://permalink.gmane.org/gmane.comp.lib.boost.devel/240056 ).
+
+[5] Fernando Cacciola and Andrzej Krzemieński. [A proposal to add a utility class to represent optional objects (Revision 4)](http://isocpp.org/files/papers/N3672.html). ISO/IEC JTC1 SC22 WG21 N3672 2013-04-19.
+
+[6] Andrzej Krzemieński, [Optional library implementation in C++11](https://github.com/akrzemi1/Optional/).
+
+[7] Anto Nonco. [Extending expected<T> to deal with references](http://anto-nonco.blogspot.nl/2013/03/extending-expected-to-deal-with.html). 27 May 2013.
+
+[8] Andrei Alexandrescu. Systematic Error Handling in C++. Prepared for The C++and Beyond Seminar 2012. [Video](http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C). [Slides](http://sdrv.ms/RXjNPR).
+
+[9] Andrei Alexandrescu. [Choose your Poison: Exceptions or Error Codes? (PDF)](http://accu.org/content/conf2007/Alexandrescu-Choose_Your_Poison.pdf). ACCU Conference 2007.
+
+[10] Andrei Alexandrescu. [The Power of None (PPT)](http://nwcpp.org/static/talks/2006/The_Power_of_None.ppt). Northwest C++ Users' Group. [May 17th, 2006](http://nwcpp.org/may-2006.html).
+
+[11] Jon Jagger. [A Return Type That Doesn't Like Being Ignored](http://accu.org/var/uploads/journals/overload53-FINAL.pdf#page=18). Overload issue 53, February 2003.
+
+[12] Andrei Alexandrescu. [Error Handling in C++: Are we inching towards a total solution?](http://accu.org/index.php/conferences/2002/speakers2002). ACCU Conference 2002.
+
+[13] Ken Hagan et al. [Exploding return codes](https://groups.google.com/d/msg/comp.lang.c++.moderated/BkZqPfoq3ys/H_PMR8Sat4oJ). comp.lang.c++.moderated. 11 February 2000.
+
+[14] [std::pair](http://en.cppreference.com/w/cpp/utility/pair). cppreference.com
+
+[15] Niall Douglas. [Outcome](https://ned14.github.io/outcome/). Very lightweight outcome&lt;T> and result&lt;T> (non-Boost edition).
+
+[16] Niall Douglas. [p0762 - Concerns about expected&lt;T, E> from the Boost.Outcome peer review](http://wg21.link/p0762). 15 October 2017.
+
+[17] Jeff Garland. [p2505 - Monadic Functions for `std::expected`](http://wg21.link/p2505) (HTML). ([r0](http://wg21.link/p2505r0), [r1](http://wg21.link/p2505r1), [r2](http://wg21.link/p2505r2), [r3](http://wg21.link/p2505r3), [r4](http://wg21.link/p2505r4), [r5](http://wg21.link/p2505r5)).
+
+## Appendix
+
+### A.1 Compile-time information
+
+The version of *expected lite* is available via tag `[.version]`. The following tags are available for information on the compiler and on the C++ standard library used: `[.compiler]`, `[.stdc++]`, `[.stdlanguage]` and `[.stdlibrary]`.
+
+### A.2 Expected lite test specification
+
+<details>
+<summary>click to expand</summary>
+<p>
+
+```Text
+unexpected_type: Disallows default construction
+unexpected_type: Allows to copy-construct from unexpected_type, default
+unexpected_type: Allows to move-construct from unexpected_type, default
+unexpected_type: Allows to in-place-construct
+unexpected_type: Allows to in-place-construct from initializer_list
+unexpected_type: Allows to copy-construct from error_type
+unexpected_type: Allows to move-construct from error_type
+unexpected_type: Allows to copy-construct from unexpected_type, explicit converting
+unexpected_type: Allows to copy-construct from unexpected_type, non-explicit converting
+unexpected_type: Allows to move-construct from unexpected_type, explicit converting
+unexpected_type: Allows to move-construct from unexpected_type, non-explicit converting
+unexpected_type: Allows to copy-assign from unexpected_type, default
+unexpected_type: Allows to move-assign from unexpected_type, default
+unexpected_type: Allows to copy-assign from unexpected_type, converting
+unexpected_type: Allows to move-assign from unexpected, converting
+unexpected_type: Allows to observe its value via a l-value reference
+unexpected_type: Allows to observe its value via a r-value reference
+unexpected_type: Allows to modify its value via a l-value reference
+unexpected_type: Allows to be swapped
+unexpected_type<std::exception_ptr>: Disallows default construction
+unexpected_type<std::exception_ptr>: Allows to copy-construct from error_type
+unexpected_type<std::exception_ptr>: Allows to move-construct from error_type
+unexpected_type<std::exception_ptr>: Allows to copy-construct from an exception
+unexpected_type<std::exception_ptr>: Allows to observe its value
+unexpected_type<std::exception_ptr>: Allows to modify its value
+unexpected_type: Provides relational operators
+unexpected_type: Provides relational operators, std::exception_ptr specialization
+make_unexpected(): Allows to create an unexpected_type<E> from an E
+unexpected: C++17 and later provide unexpected_type as unexpected
+bad_expected_access: Disallows default construction
+bad_expected_access: Allows construction from error_type
+bad_expected_access: Allows to observe its error
+bad_expected_access: Allows to change its error
+bad_expected_access: Provides non-empty what()
+expected: Allows to default construct
+expected: Allows to default construct from noncopyable, noncopyable value type
+expected: Allows to default construct from noncopyable, noncopyable error type
+expected: Allows to copy-construct from expected: value
+expected: Allows to copy-construct from expected: error
+expected: Allows to move-construct from expected: value
+expected: Allows to move-construct from expected: error
+expected: Allows to copy-construct from expected; value, explicit converting
+expected: Allows to copy-construct from expected; error, explicit converting
+expected: Allows to copy-construct from expected; value, non-explicit converting
+expected: Allows to copy-construct from expected; error, non-explicit converting
+expected: Allows to move-construct from expected; value, explicit converting
+expected: Allows to move-construct from expected; error, explicit converting
+expected: Allows to move-construct from expected; value, non-explicit converting
+expected: Allows to move-construct from expected; error, non-explicit converting
+expected: Allows to forward-construct from value, explicit converting
+expected: Allows to forward-construct from value, non-explicit converting
+expected: Allows to in-place-construct value
+expected: Allows to in-place-construct value from initializer_list
+expected: Allows to copy-construct from unexpected, explicit converting
+expected: Allows to copy-construct from unexpected, non-explicit converting
+expected: Allows to move-construct from unexpected, explicit converting
+expected: Allows to move-construct from unexpected, non-explicit converting
+expected: Allows to in-place-construct error
+expected: Allows to in-place-construct error from initializer_list
+expected: Allows to copy-assign from expected, value
+expected: Allows to copy-assign from expected, error
+expected: Allows to move-assign from expected, value
+expected: Allows to move-assign from expected, error
+expected: Allows to forward-assign from value
+expected: Allows to copy-assign from unexpected
+expected: Allows to move-assign from unexpected
+expected: Allows to move-assign from move-only unexpected
+expected: Allows to emplace value
+expected: Allows to emplace value from initializer_list
+expected: Allows to be swapped
+expected: Allows to observe its value via a pointer
+expected: Allows to observe its value via a pointer to constant
+expected: Allows to modify its value via a pointer
+expected: Allows to observe its value via a l-value reference
+expected: Allows to observe its value via a r-value reference
+expected: Allows to modify its value via a l-value reference
+expected: Allows to modify its value via a r-value reference
+expected: Allows to observe if it contains a value (or error)
+expected: Allows to observe its value
+expected: Allows to modify its value
+expected: Allows to move its value
+expected: Allows to observe its error
+expected: Allows to modify its error
+expected: Allows to move its error
+expected: Allows to observe its error as unexpected
+expected: Allows to query if it contains an exception of a specific base type
+expected: Allows to observe its value if available, or obtain a specified value otherwise
+expected: Allows to move its value if available, or obtain a specified value otherwise
+expected: Throws bad_expected_access on value access when disengaged
+expected: Allows to observe its unexpected value, or fallback to the specified value with error_or [monadic p2505r4]
+expected: Allows to map value with and_then [monadic p2505r3]
+expected: Allows to map unexpected with or_else [monadic p2505r3]
+expected: Allows to transform value [monadic p2505r3]
+expected: Allows to map errors with transform_error [monadic p2505r3]
+expected<void>: Allows to default-construct
+expected<void>: Allows to copy-construct from expected<void>: value
+expected<void>: Allows to copy-construct from expected<void>: error
+expected<void>: Allows to move-construct from expected<void>: value
+expected<void>: Allows to move-construct from expected<void>: error
+expected<void>: Allows to in-place-construct
+expected<void>: Allows to copy-construct from unexpected, explicit converting
+expected<void>: Allows to copy-construct from unexpected, non-explicit converting
+expected<void>: Allows to move-construct from unexpected, explicit converting
+expected<void>: Allows to move-construct from unexpected, non-explicit converting
+expected<void>: Allows to in-place-construct unexpected_type
+expected<void>: Allows to in-place-construct error from initializer_list
+expected<void>: Allows to copy-assign from expected, value
+expected<void>: Allows to copy-assign from expected, error
+expected<void>: Allows to move-assign from expected, value
+expected<void>: Allows to move-assign from expected, error
+expected<void>: Allows to emplace value
+expected<void>: Allows to be swapped
+expected<void>: Allows to observe if it contains a value (or error)
+expected<void>: Allows to observe its value
+expected<void>: Allows to observe its error
+expected<void>: Allows to modify its error
+expected<void>: Allows to move its error
+expected<void>: Allows to observe its error as unexpected
+expected<void>: Allows to query if it contains an exception of a specific base type
+expected<void>: Throws bad_expected_access on value access when disengaged
+expected<void>: Allows to observe unexpected value, or fallback to a default value with error_or [monadic p2505r4]
+expected<void>: Allows to call argless functions with and_then [monadic p2505r3]
+expected<void>: Allows to map to expected or unexpected with or_else [monadic p2505r3]
+expected<void>: Allows to assign a new expected value using transform [monadic p2505r3]
+expected<void>: Allows to map unexpected error value via transform_error [monadic p2505r3]
+operators: Provides expected relational operators
+operators: Provides expected relational operators (void)
+swap: Allows expected to be swapped
+std::hash: Allows to compute hash value for expected
+tweak header: reads tweak header if supported [tweak]
+```
+
+</p>
+</details>
diff --git a/contrib/restricted/expected-lite/include/nonstd/expected.hpp b/contrib/restricted/expected-lite/include/nonstd/expected.hpp
new file mode 100644
index 0000000000..588ba1a22e
--- /dev/null
+++ b/contrib/restricted/expected-lite/include/nonstd/expected.hpp
@@ -0,0 +1,3555 @@
+// This version targets C++11 and later.
+//
+// Copyright (C) 2016-2020 Martin Moene.
+//
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// expected lite is based on:
+// A proposal to add a utility class to represent expected monad
+// by Vicente J. Botet Escriba and Pierre Talbot. http:://wg21.link/p0323
+
+#ifndef NONSTD_EXPECTED_LITE_HPP
+#define NONSTD_EXPECTED_LITE_HPP
+
+#define expected_lite_MAJOR 0
+#define expected_lite_MINOR 8
+#define expected_lite_PATCH 0
+
+#define expected_lite_VERSION expected_STRINGIFY(expected_lite_MAJOR) "." expected_STRINGIFY(expected_lite_MINOR) "." expected_STRINGIFY(expected_lite_PATCH)
+
+#define expected_STRINGIFY( x ) expected_STRINGIFY_( x )
+#define expected_STRINGIFY_( x ) #x
+
+// expected-lite configuration:
+
+#define nsel_EXPECTED_DEFAULT 0
+#define nsel_EXPECTED_NONSTD 1
+#define nsel_EXPECTED_STD 2
+
+// tweak header support:
+
+#ifdef __has_include
+# if __has_include(<nonstd/expected.tweak.hpp>)
+# error #include <nonstd/expected.tweak.hpp>
+# endif
+#define expected_HAVE_TWEAK_HEADER 1
+#else
+#define expected_HAVE_TWEAK_HEADER 0
+//# pragma message("expected.hpp: Note: Tweak header not supported.")
+#endif
+
+// expected selection and configuration:
+
+#if !defined( nsel_CONFIG_SELECT_EXPECTED )
+# define nsel_CONFIG_SELECT_EXPECTED ( nsel_HAVE_STD_EXPECTED ? nsel_EXPECTED_STD : nsel_EXPECTED_NONSTD )
+#endif
+
+// Proposal revisions:
+//
+// DXXXXR0: --
+// N4015 : -2 (2014-05-26)
+// N4109 : -1 (2014-06-29)
+// P0323R0: 0 (2016-05-28)
+// P0323R1: 1 (2016-10-12)
+// -------:
+// P0323R2: 2 (2017-06-15)
+// P0323R3: 3 (2017-10-15)
+// P0323R4: 4 (2017-11-26)
+// P0323R5: 5 (2018-02-08)
+// P0323R6: 6 (2018-04-02)
+// P0323R7: 7 (2018-06-22) *
+//
+// expected-lite uses 2 and higher
+
+#ifndef nsel_P0323R
+# define nsel_P0323R 7
+#endif
+
+// Monadic operations proposal revisions:
+//
+// P2505R0: 0 (2021-12-12)
+// P2505R1: 1 (2022-02-10)
+// P2505R2: 2 (2022-04-15)
+// P2505R3: 3 (2022-06-05)
+// P2505R4: 4 (2022-06-15)
+// P2505R5: 5 (2022-09-20) *
+//
+// expected-lite uses 5
+
+#ifndef nsel_P2505R
+# define nsel_P2505R 5
+#endif
+
+// Control presence of C++ exception handling (try and auto discover):
+
+#ifndef nsel_CONFIG_NO_EXCEPTIONS
+# if defined(_MSC_VER)
+# include <cstddef> // for _HAS_EXCEPTIONS
+# endif
+# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS)
+# define nsel_CONFIG_NO_EXCEPTIONS 0
+# else
+# define nsel_CONFIG_NO_EXCEPTIONS 1
+# endif
+#endif
+
+// at default use SEH with MSVC for no C++ exceptions
+
+#ifndef nsel_CONFIG_NO_EXCEPTIONS_SEH
+# define nsel_CONFIG_NO_EXCEPTIONS_SEH ( nsel_CONFIG_NO_EXCEPTIONS && _MSC_VER )
+#endif
+
+// C++ language version detection (C++23 is speculative):
+// Note: VC14.0/1900 (VS2015) lacks too much from C++14.
+
+#ifndef nsel_CPLUSPLUS
+# if defined(_MSVC_LANG ) && !defined(__clang__)
+# define nsel_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )
+# else
+# define nsel_CPLUSPLUS __cplusplus
+# endif
+#endif
+
+#define nsel_CPP98_OR_GREATER ( nsel_CPLUSPLUS >= 199711L )
+#define nsel_CPP11_OR_GREATER ( nsel_CPLUSPLUS >= 201103L )
+#define nsel_CPP14_OR_GREATER ( nsel_CPLUSPLUS >= 201402L )
+#define nsel_CPP17_OR_GREATER ( nsel_CPLUSPLUS >= 201703L )
+#define nsel_CPP20_OR_GREATER ( nsel_CPLUSPLUS >= 202002L )
+#define nsel_CPP23_OR_GREATER ( nsel_CPLUSPLUS >= 202300L )
+
+// Use C++23 std::expected if available and requested:
+
+#if nsel_CPP23_OR_GREATER && defined(__has_include )
+# if __has_include( <expected> )
+# define nsel_HAVE_STD_EXPECTED 1
+# else
+# define nsel_HAVE_STD_EXPECTED 0
+# endif
+#else
+# define nsel_HAVE_STD_EXPECTED 0
+#endif
+
+#define nsel_USES_STD_EXPECTED ( (nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_STD) || ((nsel_CONFIG_SELECT_EXPECTED == nsel_EXPECTED_DEFAULT) && nsel_HAVE_STD_EXPECTED) )
+
+//
+// in_place: code duplicated in any-lite, expected-lite, expected-lite, value-ptr-lite, variant-lite:
+//
+
+#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES
+#define nonstd_lite_HAVE_IN_PLACE_TYPES 1
+
+// C++17 std::in_place in <utility>:
+
+#if nsel_CPP17_OR_GREATER
+
+#include <utility>
+
+namespace nonstd {
+
+using std::in_place;
+using std::in_place_type;
+using std::in_place_index;
+using std::in_place_t;
+using std::in_place_type_t;
+using std::in_place_index_t;
+
+#define nonstd_lite_in_place_t( T) std::in_place_t
+#define nonstd_lite_in_place_type_t( T) std::in_place_type_t<T>
+#define nonstd_lite_in_place_index_t(K) std::in_place_index_t<K>
+
+#define nonstd_lite_in_place( T) std::in_place_t{}
+#define nonstd_lite_in_place_type( T) std::in_place_type_t<T>{}
+#define nonstd_lite_in_place_index(K) std::in_place_index_t<K>{}
+
+} // namespace nonstd
+
+#else // nsel_CPP17_OR_GREATER
+
+#include <cstddef>
+
+namespace nonstd {
+namespace detail {
+
+template< class T >
+struct in_place_type_tag {};
+
+template< std::size_t K >
+struct in_place_index_tag {};
+
+} // namespace detail
+
+struct in_place_t {};
+
+template< class T >
+inline in_place_t in_place( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
+{
+ return in_place_t();
+}
+
+template< std::size_t K >
+inline in_place_t in_place( detail::in_place_index_tag<K> = detail::in_place_index_tag<K>() )
+{
+ return in_place_t();
+}
+
+template< class T >
+inline in_place_t in_place_type( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
+{
+ return in_place_t();
+}
+
+template< std::size_t K >
+inline in_place_t in_place_index( detail::in_place_index_tag<K> = detail::in_place_index_tag<K>() )
+{
+ return in_place_t();
+}
+
+// mimic templated typedef:
+
+#define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
+#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
+#define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag<K> )
+
+#define nonstd_lite_in_place( T) nonstd::in_place_type<T>
+#define nonstd_lite_in_place_type( T) nonstd::in_place_type<T>
+#define nonstd_lite_in_place_index(K) nonstd::in_place_index<K>
+
+} // namespace nonstd
+
+#endif // nsel_CPP17_OR_GREATER
+#endif // nonstd_lite_HAVE_IN_PLACE_TYPES
+
+//
+// Using std::expected:
+//
+
+#if nsel_USES_STD_EXPECTED
+
+#error #include <expected>
+
+namespace nonstd {
+
+ using std::expected;
+ using std::unexpected;
+ using std::bad_expected_access;
+ using std::unexpect_t;
+ using std::unexpect;
+
+ //[[deprecated("replace unexpected_type with unexpected")]]
+
+ template< typename E >
+ using unexpected_type = unexpected<E>;
+
+ // Unconditionally provide make_unexpected():
+
+ template< typename E>
+ constexpr auto make_unexpected( E && value ) -> unexpected< typename std::decay<E>::type >
+ {
+ return unexpected< typename std::decay<E>::type >( std::forward<E>(value) );
+ }
+} // namespace nonstd
+
+#else // nsel_USES_STD_EXPECTED
+
+#include <cassert>
+#include <exception>
+#include <functional>
+#include <initializer_list>
+#include <memory>
+#include <new>
+#include <system_error>
+#include <type_traits>
+#include <utility>
+
+// additional includes:
+
+#if nsel_CONFIG_NO_EXCEPTIONS
+# if nsel_CONFIG_NO_EXCEPTIONS_SEH
+# include <windows.h> // for ExceptionCodes
+# else
+// already included: <cassert>
+# endif
+#else
+# include <stdexcept>
+#endif
+
+// C++ feature usage:
+
+#if nsel_CPP11_OR_GREATER
+# define nsel_constexpr constexpr
+#else
+# define nsel_constexpr /*constexpr*/
+#endif
+
+#if nsel_CPP14_OR_GREATER
+# define nsel_constexpr14 constexpr
+#else
+# define nsel_constexpr14 /*constexpr*/
+#endif
+
+#if nsel_CPP17_OR_GREATER
+# define nsel_inline17 inline
+#else
+# define nsel_inline17 /*inline*/
+#endif
+
+// Compiler versions:
+//
+// MSVC++ 6.0 _MSC_VER == 1200 nsel_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0)
+// MSVC++ 7.0 _MSC_VER == 1300 nsel_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002)
+// MSVC++ 7.1 _MSC_VER == 1310 nsel_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003)
+// MSVC++ 8.0 _MSC_VER == 1400 nsel_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005)
+// MSVC++ 9.0 _MSC_VER == 1500 nsel_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008)
+// MSVC++ 10.0 _MSC_VER == 1600 nsel_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010)
+// MSVC++ 11.0 _MSC_VER == 1700 nsel_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012)
+// MSVC++ 12.0 _MSC_VER == 1800 nsel_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013)
+// MSVC++ 14.0 _MSC_VER == 1900 nsel_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015)
+// MSVC++ 14.1 _MSC_VER >= 1910 nsel_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017)
+// MSVC++ 14.2 _MSC_VER >= 1920 nsel_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019)
+
+#if defined(_MSC_VER) && !defined(__clang__)
+# define nsel_COMPILER_MSVC_VER (_MSC_VER )
+# define nsel_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900)) )
+#else
+# define nsel_COMPILER_MSVC_VER 0
+# define nsel_COMPILER_MSVC_VERSION 0
+#endif
+
+#define nsel_COMPILER_VERSION( major, minor, patch ) ( 10 * ( 10 * (major) + (minor) ) + (patch) )
+
+#if defined(__clang__)
+# define nsel_COMPILER_CLANG_VERSION nsel_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
+#else
+# define nsel_COMPILER_CLANG_VERSION 0
+#endif
+
+#if defined(__GNUC__) && !defined(__clang__)
+# define nsel_COMPILER_GNUC_VERSION nsel_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
+#else
+# define nsel_COMPILER_GNUC_VERSION 0
+#endif
+
+// half-open range [lo..hi):
+//#define nsel_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )
+
+// Method enabling
+
+#define nsel_REQUIRES_0(...) \
+ template< bool B = (__VA_ARGS__), typename std::enable_if<B, int>::type = 0 >
+
+#define nsel_REQUIRES_T(...) \
+ , typename std::enable_if< (__VA_ARGS__), int >::type = 0
+
+#define nsel_REQUIRES_R(R, ...) \
+ typename std::enable_if< (__VA_ARGS__), R>::type
+
+#define nsel_REQUIRES_A(...) \
+ , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr
+
+// Clang, GNUC, MSVC warning suppression macros:
+
+#ifdef __clang__
+# pragma clang diagnostic push
+#elif defined __GNUC__
+# pragma GCC diagnostic push
+#endif // __clang__
+
+#if nsel_COMPILER_MSVC_VERSION >= 140
+# define nsel_DISABLE_MSVC_WARNINGS(codes) __pragma( warning(push) ) __pragma( warning(disable: codes) )
+#else
+# define nsel_DISABLE_MSVC_WARNINGS(codes)
+#endif
+
+#ifdef __clang__
+# define nsel_RESTORE_WARNINGS() _Pragma("clang diagnostic pop")
+# define nsel_RESTORE_MSVC_WARNINGS()
+#elif defined __GNUC__
+# define nsel_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop")
+# define nsel_RESTORE_MSVC_WARNINGS()
+#elif nsel_COMPILER_MSVC_VERSION >= 140
+# define nsel_RESTORE_WARNINGS() __pragma( warning( pop ) )
+# define nsel_RESTORE_MSVC_WARNINGS() nsel_RESTORE_WARNINGS()
+#else
+# define nsel_RESTORE_WARNINGS()
+# define nsel_RESTORE_MSVC_WARNINGS()
+#endif
+
+// Suppress the following MSVC (GSL) warnings:
+// - C26409: Avoid calling new and delete explicitly, use std::make_unique<T> instead (r.11)
+
+nsel_DISABLE_MSVC_WARNINGS( 26409 )
+
+// Presence of language and library features:
+
+#ifdef _HAS_CPP0X
+# define nsel_HAS_CPP0X _HAS_CPP0X
+#else
+# define nsel_HAS_CPP0X 0
+#endif
+
+// Presence of language and library features:
+
+#define nsel_CPP17_000 (nsel_CPP17_OR_GREATER)
+
+// Presence of C++17 language features:
+
+#define nsel_HAVE_DEPRECATED nsel_CPP17_000
+
+// C++ feature usage:
+
+#if nsel_HAVE_DEPRECATED
+# define nsel_deprecated(msg) [[deprecated(msg)]]
+#else
+# define nsel_deprecated(msg) /*[[deprecated]]*/
+#endif
+
+//
+// expected:
+//
+
+namespace nonstd { namespace expected_lite {
+
+// type traits C++17:
+
+namespace std17 {
+
+#if nsel_CPP17_OR_GREATER
+
+using std::conjunction;
+using std::is_swappable;
+using std::is_nothrow_swappable;
+
+#else // nsel_CPP17_OR_GREATER
+
+namespace detail {
+
+using std::swap;
+
+struct is_swappable
+{
+ template< typename T, typename = decltype( swap( std::declval<T&>(), std::declval<T&>() ) ) >
+ static std::true_type test( int /* unused */);
+
+ template< typename >
+ static std::false_type test(...);
+};
+
+struct is_nothrow_swappable
+{
+ // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015):
+
+ template< typename T >
+ static constexpr bool satisfies()
+ {
+ return noexcept( swap( std::declval<T&>(), std::declval<T&>() ) );
+ }
+
+ template< typename T >
+ static auto test( int ) -> std::integral_constant<bool, satisfies<T>()>{}
+
+ template< typename >
+ static auto test(...) -> std::false_type;
+};
+} // namespace detail
+
+// is [nothrow] swappable:
+
+template< typename T >
+struct is_swappable : decltype( detail::is_swappable::test<T>(0) ){};
+
+template< typename T >
+struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test<T>(0) ){};
+
+// conjunction:
+
+template< typename... > struct conjunction : std::true_type{};
+template< typename B1 > struct conjunction<B1> : B1{};
+
+template< typename B1, typename... Bn >
+struct conjunction<B1, Bn...> : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type{};
+
+#endif // nsel_CPP17_OR_GREATER
+
+} // namespace std17
+
+// type traits C++20:
+
+namespace std20 {
+
+#if defined(__cpp_lib_remove_cvref)
+
+using std::remove_cvref;
+
+#else
+
+template< typename T >
+struct remove_cvref
+{
+ typedef typename std::remove_cv< typename std::remove_reference<T>::type >::type type;
+};
+
+#endif
+
+} // namespace std20
+
+// forward declaration:
+
+template< typename T, typename E >
+class expected;
+
+namespace detail {
+
+#if nsel_P2505R >= 3
+template< typename T >
+struct is_expected : std::false_type {};
+
+template< typename T, typename E >
+struct is_expected< expected< T, E > > : std::true_type {};
+#endif // nsel_P2505R >= 3
+
+/// discriminated union to hold value or 'error'.
+
+template< typename T, typename E >
+class storage_t_noncopy_nonmove_impl
+{
+ template< typename, typename > friend class nonstd::expected_lite::expected;
+
+public:
+ using value_type = T;
+ using error_type = E;
+
+ // no-op construction
+ storage_t_noncopy_nonmove_impl() {}
+ ~storage_t_noncopy_nonmove_impl() {}
+
+ explicit storage_t_noncopy_nonmove_impl( bool has_value )
+ : m_has_value( has_value )
+ {}
+
+ void construct_value()
+ {
+ new( &m_value ) value_type();
+ }
+
+ // void construct_value( value_type const & e )
+ // {
+ // new( &m_value ) value_type( e );
+ // }
+
+ // void construct_value( value_type && e )
+ // {
+ // new( &m_value ) value_type( std::move( e ) );
+ // }
+
+ template< class... Args >
+ void emplace_value( Args&&... args )
+ {
+ new( &m_value ) value_type( std::forward<Args>(args)...);
+ }
+
+ template< class U, class... Args >
+ void emplace_value( std::initializer_list<U> il, Args&&... args )
+ {
+ new( &m_value ) value_type( il, std::forward<Args>(args)... );
+ }
+
+ void destruct_value()
+ {
+ m_value.~value_type();
+ }
+
+ // void construct_error( error_type const & e )
+ // {
+ // // new( &m_error ) error_type( e );
+ // }
+
+ // void construct_error( error_type && e )
+ // {
+ // // new( &m_error ) error_type( std::move( e ) );
+ // }
+
+ template< class... Args >
+ void emplace_error( Args&&... args )
+ {
+ new( &m_error ) error_type( std::forward<Args>(args)...);
+ }
+
+ template< class U, class... Args >
+ void emplace_error( std::initializer_list<U> il, Args&&... args )
+ {
+ new( &m_error ) error_type( il, std::forward<Args>(args)... );
+ }
+
+ void destruct_error()
+ {
+ m_error.~error_type();
+ }
+
+ constexpr value_type const & value() const &
+ {
+ return m_value;
+ }
+
+ value_type & value() &
+ {
+ return m_value;
+ }
+
+ constexpr value_type const && value() const &&
+ {
+ return std::move( m_value );
+ }
+
+ nsel_constexpr14 value_type && value() &&
+ {
+ return std::move( m_value );
+ }
+
+ value_type const * value_ptr() const
+ {
+ return &m_value;
+ }
+
+ value_type * value_ptr()
+ {
+ return &m_value;
+ }
+
+ error_type const & error() const &
+ {
+ return m_error;
+ }
+
+ error_type & error() &
+ {
+ return m_error;
+ }
+
+ constexpr error_type const && error() const &&
+ {
+ return std::move( m_error );
+ }
+
+ nsel_constexpr14 error_type && error() &&
+ {
+ return std::move( m_error );
+ }
+
+ bool has_value() const
+ {
+ return m_has_value;
+ }
+
+ void set_has_value( bool v )
+ {
+ m_has_value = v;
+ }
+
+private:
+ union
+ {
+ value_type m_value;
+ error_type m_error;
+ };
+
+ bool m_has_value = false;
+};
+
+template< typename T, typename E >
+class storage_t_impl
+{
+ template< typename, typename > friend class nonstd::expected_lite::expected;
+
+public:
+ using value_type = T;
+ using error_type = E;
+
+ // no-op construction
+ storage_t_impl() {}
+ ~storage_t_impl() {}
+
+ explicit storage_t_impl( bool has_value )
+ : m_has_value( has_value )
+ {}
+
+ void construct_value()
+ {
+ new( &m_value ) value_type();
+ }
+
+ void construct_value( value_type const & e )
+ {
+ new( &m_value ) value_type( e );
+ }
+
+ void construct_value( value_type && e )
+ {
+ new( &m_value ) value_type( std::move( e ) );
+ }
+
+ template< class... Args >
+ void emplace_value( Args&&... args )
+ {
+ new( &m_value ) value_type( std::forward<Args>(args)...);
+ }
+
+ template< class U, class... Args >
+ void emplace_value( std::initializer_list<U> il, Args&&... args )
+ {
+ new( &m_value ) value_type( il, std::forward<Args>(args)... );
+ }
+
+ void destruct_value()
+ {
+ m_value.~value_type();
+ }
+
+ void construct_error( error_type const & e )
+ {
+ new( &m_error ) error_type( e );
+ }
+
+ void construct_error( error_type && e )
+ {
+ new( &m_error ) error_type( std::move( e ) );
+ }
+
+ template< class... Args >
+ void emplace_error( Args&&... args )
+ {
+ new( &m_error ) error_type( std::forward<Args>(args)...);
+ }
+
+ template< class U, class... Args >
+ void emplace_error( std::initializer_list<U> il, Args&&... args )
+ {
+ new( &m_error ) error_type( il, std::forward<Args>(args)... );
+ }
+
+ void destruct_error()
+ {
+ m_error.~error_type();
+ }
+
+ constexpr value_type const & value() const &
+ {
+ return m_value;
+ }
+
+ value_type & value() &
+ {
+ return m_value;
+ }
+
+ constexpr value_type const && value() const &&
+ {
+ return std::move( m_value );
+ }
+
+ nsel_constexpr14 value_type && value() &&
+ {
+ return std::move( m_value );
+ }
+
+ value_type const * value_ptr() const
+ {
+ return &m_value;
+ }
+
+ value_type * value_ptr()
+ {
+ return &m_value;
+ }
+
+ error_type const & error() const &
+ {
+ return m_error;
+ }
+
+ error_type & error() &
+ {
+ return m_error;
+ }
+
+ constexpr error_type const && error() const &&
+ {
+ return std::move( m_error );
+ }
+
+ nsel_constexpr14 error_type && error() &&
+ {
+ return std::move( m_error );
+ }
+
+ bool has_value() const
+ {
+ return m_has_value;
+ }
+
+ void set_has_value( bool v )
+ {
+ m_has_value = v;
+ }
+
+private:
+ union
+ {
+ value_type m_value;
+ error_type m_error;
+ };
+
+ bool m_has_value = false;
+};
+
+/// discriminated union to hold only 'error'.
+
+template< typename E >
+struct storage_t_impl<void, E>
+{
+ template< typename, typename > friend class nonstd::expected_lite::expected;
+
+public:
+ using value_type = void;
+ using error_type = E;
+
+ // no-op construction
+ storage_t_impl() {}
+ ~storage_t_impl() {}
+
+ explicit storage_t_impl( bool has_value )
+ : m_has_value( has_value )
+ {}
+
+ void construct_error( error_type const & e )
+ {
+ new( &m_error ) error_type( e );
+ }
+
+ void construct_error( error_type && e )
+ {
+ new( &m_error ) error_type( std::move( e ) );
+ }
+
+ template< class... Args >
+ void emplace_error( Args&&... args )
+ {
+ new( &m_error ) error_type( std::forward<Args>(args)...);
+ }
+
+ template< class U, class... Args >
+ void emplace_error( std::initializer_list<U> il, Args&&... args )
+ {
+ new( &m_error ) error_type( il, std::forward<Args>(args)... );
+ }
+
+ void destruct_error()
+ {
+ m_error.~error_type();
+ }
+
+ error_type const & error() const &
+ {
+ return m_error;
+ }
+
+ error_type & error() &
+ {
+ return m_error;
+ }
+
+ constexpr error_type const && error() const &&
+ {
+ return std::move( m_error );
+ }
+
+ nsel_constexpr14 error_type && error() &&
+ {
+ return std::move( m_error );
+ }
+
+ bool has_value() const
+ {
+ return m_has_value;
+ }
+
+ void set_has_value( bool v )
+ {
+ m_has_value = v;
+ }
+
+private:
+ union
+ {
+ char m_dummy;
+ error_type m_error;
+ };
+
+ bool m_has_value = false;
+};
+
+template< typename T, typename E, bool isConstructable, bool isMoveable >
+class storage_t
+{
+public:
+};
+
+template< typename T, typename E >
+class storage_t<T, E, false, false> : public storage_t_noncopy_nonmove_impl<T, E>
+{
+public:
+ storage_t() = default;
+ ~storage_t() = default;
+
+ explicit storage_t( bool has_value )
+ : storage_t_noncopy_nonmove_impl<T, E>( has_value )
+ {}
+
+ storage_t( storage_t const & other ) = delete;
+ storage_t( storage_t && other ) = delete;
+
+};
+
+template< typename T, typename E >
+class storage_t<T, E, true, true> : public storage_t_impl<T, E>
+{
+public:
+ storage_t() = default;
+ ~storage_t() = default;
+
+ explicit storage_t( bool has_value )
+ : storage_t_impl<T, E>( has_value )
+ {}
+
+ storage_t( storage_t const & other )
+ : storage_t_impl<T, E>( other.has_value() )
+ {
+ if ( this->has_value() ) this->construct_value( other.value() );
+ else this->construct_error( other.error() );
+ }
+
+ storage_t(storage_t && other )
+ : storage_t_impl<T, E>( other.has_value() )
+ {
+ if ( this->has_value() ) this->construct_value( std::move( other.value() ) );
+ else this->construct_error( std::move( other.error() ) );
+ }
+};
+
+template< typename E >
+class storage_t<void, E, true, true> : public storage_t_impl<void, E>
+{
+public:
+ storage_t() = default;
+ ~storage_t() = default;
+
+ explicit storage_t( bool has_value )
+ : storage_t_impl<void, E>( has_value )
+ {}
+
+ storage_t( storage_t const & other )
+ : storage_t_impl<void, E>( other.has_value() )
+ {
+ if ( this->has_value() ) ;
+ else this->construct_error( other.error() );
+ }
+
+ storage_t(storage_t && other )
+ : storage_t_impl<void, E>( other.has_value() )
+ {
+ if ( this->has_value() ) ;
+ else this->construct_error( std::move( other.error() ) );
+ }
+};
+
+template< typename T, typename E >
+class storage_t<T, E, true, false> : public storage_t_impl<T, E>
+{
+public:
+ storage_t() = default;
+ ~storage_t() = default;
+
+ explicit storage_t( bool has_value )
+ : storage_t_impl<T, E>( has_value )
+ {}
+
+ storage_t( storage_t const & other )
+ : storage_t_impl<T, E>(other.has_value())
+ {
+ if ( this->has_value() ) this->construct_value( other.value() );
+ else this->construct_error( other.error() );
+ }
+
+ storage_t( storage_t && other ) = delete;
+};
+
+template< typename E >
+class storage_t<void, E, true, false> : public storage_t_impl<void, E>
+{
+public:
+ storage_t() = default;
+ ~storage_t() = default;
+
+ explicit storage_t( bool has_value )
+ : storage_t_impl<void, E>( has_value )
+ {}
+
+ storage_t( storage_t const & other )
+ : storage_t_impl<void, E>(other.has_value())
+ {
+ if ( this->has_value() ) ;
+ else this->construct_error( other.error() );
+ }
+
+ storage_t( storage_t && other ) = delete;
+};
+
+template< typename T, typename E >
+class storage_t<T, E, false, true> : public storage_t_impl<T, E>
+{
+public:
+ storage_t() = default;
+ ~storage_t() = default;
+
+ explicit storage_t( bool has_value )
+ : storage_t_impl<T, E>( has_value )
+ {}
+
+ storage_t( storage_t const & other ) = delete;
+
+ storage_t( storage_t && other )
+ : storage_t_impl<T, E>( other.has_value() )
+ {
+ if ( this->has_value() ) this->construct_value( std::move( other.value() ) );
+ else this->construct_error( std::move( other.error() ) );
+ }
+};
+
+template< typename E >
+class storage_t<void, E, false, true> : public storage_t_impl<void, E>
+{
+public:
+ storage_t() = default;
+ ~storage_t() = default;
+
+ explicit storage_t( bool has_value )
+ : storage_t_impl<void, E>( has_value )
+ {}
+
+ storage_t( storage_t const & other ) = delete;
+
+ storage_t( storage_t && other )
+ : storage_t_impl<void, E>( other.has_value() )
+ {
+ if ( this->has_value() ) ;
+ else this->construct_error( std::move( other.error() ) );
+ }
+};
+
+#if nsel_P2505R >= 3
+// C++11 invoke implementation
+template< typename >
+struct is_reference_wrapper : std::false_type {};
+template< typename T >
+struct is_reference_wrapper< std::reference_wrapper< T > > : std::true_type {};
+
+template< typename FnT, typename ClassT, typename ObjectT, typename... Args
+ nsel_REQUIRES_T(
+ std::is_function<FnT>::value
+ && ( std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value
+ || std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value )
+ )
+>
+nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args )
+ noexcept( noexcept( (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )... ) ) )
+ -> decltype( (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )...) )
+{
+ return (std::forward< ObjectT >( obj ).*memfnptr)( std::forward< Args >( args )... );
+}
+
+template< typename FnT, typename ClassT, typename ObjectT, typename... Args
+ nsel_REQUIRES_T(
+ std::is_function<FnT>::value
+ && is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value
+ )
+>
+nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args )
+ noexcept( noexcept( (obj.get().*memfnptr)( std::forward< Args >( args ) ... ) ) )
+ -> decltype( (obj.get().*memfnptr)( std::forward< Args >( args ) ... ) )
+{
+ return (obj.get().*memfnptr)( std::forward< Args >( args ) ... );
+}
+
+template< typename FnT, typename ClassT, typename ObjectT, typename... Args
+ nsel_REQUIRES_T(
+ std::is_function<FnT>::value
+ && !std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value
+ && !std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value
+ && !is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value
+ )
+>
+nsel_constexpr auto invoke_member_function_impl( FnT ClassT::* memfnptr, ObjectT && obj, Args && ... args )
+ noexcept( noexcept( ((*std::forward< ObjectT >( obj )).*memfnptr)( std::forward< Args >( args ) ... ) ) )
+ -> decltype( ((*std::forward< ObjectT >( obj )).*memfnptr)( std::forward< Args >( args ) ... ) )
+{
+ return ((*std::forward<ObjectT>(obj)).*memfnptr)( std::forward< Args >( args ) ... );
+}
+
+template< typename MemberT, typename ClassT, typename ObjectT
+ nsel_REQUIRES_T(
+ std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value
+ || std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value
+ )
+>
+nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj )
+ noexcept( noexcept( std::forward< ObjectT >( obj ).*memobjptr ) )
+ -> decltype( std::forward< ObjectT >( obj ).*memobjptr )
+{
+ return std::forward< ObjectT >( obj ).*memobjptr;
+}
+
+template< typename MemberT, typename ClassT, typename ObjectT
+ nsel_REQUIRES_T(
+ is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value
+ )
+>
+nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj )
+ noexcept( noexcept( obj.get().*memobjptr ) )
+ -> decltype( obj.get().*memobjptr )
+{
+ return obj.get().*memobjptr;
+}
+
+template< typename MemberT, typename ClassT, typename ObjectT
+ nsel_REQUIRES_T(
+ !std::is_same< ClassT, typename std20::remove_cvref< ObjectT >::type >::value
+ && !std::is_base_of< ClassT, typename std20::remove_cvref< ObjectT >::type >::value
+ && !is_reference_wrapper< typename std20::remove_cvref< ObjectT >::type >::value
+ )
+>
+nsel_constexpr auto invoke_member_object_impl( MemberT ClassT::* memobjptr, ObjectT && obj )
+ noexcept( noexcept( (*std::forward< ObjectT >( obj )).*memobjptr ) )
+ -> decltype( (*std::forward< ObjectT >( obj )).*memobjptr )
+{
+ return (*std::forward< ObjectT >( obj )).*memobjptr;
+}
+
+template< typename F, typename... Args
+ nsel_REQUIRES_T(
+ std::is_member_function_pointer< typename std20::remove_cvref< F >::type >::value
+ )
+>
+nsel_constexpr auto invoke( F && f, Args && ... args )
+ noexcept( noexcept( invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) )
+ -> decltype( invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) )
+{
+ return invoke_member_function_impl( std::forward< F >( f ), std::forward< Args >( args ) ... );
+}
+
+template< typename F, typename... Args
+ nsel_REQUIRES_T(
+ std::is_member_object_pointer< typename std20::remove_cvref< F >::type >::value
+ )
+>
+nsel_constexpr auto invoke( F && f, Args && ... args )
+ noexcept( noexcept( invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) ) )
+ -> decltype( invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... ) )
+{
+ return invoke_member_object_impl( std::forward< F >( f ), std::forward< Args >( args ) ... );
+}
+
+template< typename F, typename... Args
+ nsel_REQUIRES_T(
+ !std::is_member_function_pointer< typename std20::remove_cvref< F >::type >::value
+ && !std::is_member_object_pointer< typename std20::remove_cvref< F >::type >::value
+ )
+>
+nsel_constexpr auto invoke( F && f, Args && ... args )
+ noexcept( noexcept( std::forward< F >( f )( std::forward< Args >( args ) ... ) ) )
+ -> decltype( std::forward< F >( f )( std::forward< Args >( args ) ... ) )
+{
+ return std::forward< F >( f )( std::forward< Args >( args ) ... );
+}
+
+template< typename F, typename ... Args >
+using invoke_result_nocvref_t = typename std20::remove_cvref< decltype( invoke( std::declval< F >(), std::declval< Args >()... ) ) >::type;
+
+#if nsel_P2505R >= 5
+template< typename F, typename ... Args >
+using transform_invoke_result_t = typename std::remove_cv< decltype( invoke( std::declval< F >(), std::declval< Args >()... ) ) >::type;
+#else
+template< typename F, typename ... Args >
+using transform_invoke_result_t = invoke_result_nocvref_t
+#endif // nsel_P2505R >= 5
+
+template< typename T >
+struct valid_expected_value_type : std::integral_constant< bool, std::is_destructible< T >::value && !std::is_reference< T >::value && !std::is_array< T >::value > {};
+
+#endif // nsel_P2505R >= 3
+} // namespace detail
+
+/// x.x.5 Unexpected object type; unexpected_type; C++17 and later can also use aliased type unexpected.
+
+#if nsel_P0323R <= 2
+template< typename E = std::exception_ptr >
+class unexpected_type
+#else
+template< typename E >
+class unexpected_type
+#endif // nsel_P0323R
+{
+public:
+ using error_type = E;
+
+ // x.x.5.2.1 Constructors
+
+// unexpected_type() = delete;
+
+ constexpr unexpected_type( unexpected_type const & ) = default;
+ constexpr unexpected_type( unexpected_type && ) = default;
+
+ template< typename... Args
+ nsel_REQUIRES_T(
+ std::is_constructible<E, Args&&...>::value
+ )
+ >
+ constexpr explicit unexpected_type( nonstd_lite_in_place_t(E), Args &&... args )
+ : m_error( std::forward<Args>( args )...)
+ {}
+
+ template< typename U, typename... Args
+ nsel_REQUIRES_T(
+ std::is_constructible<E, std::initializer_list<U>, Args&&...>::value
+ )
+ >
+ constexpr explicit unexpected_type( nonstd_lite_in_place_t(E), std::initializer_list<U> il, Args &&... args )
+ : m_error( il, std::forward<Args>( args )...)
+ {}
+
+ template< typename E2
+ nsel_REQUIRES_T(
+ std::is_constructible<E,E2>::value
+ && !std::is_same< typename std20::remove_cvref<E2>::type, nonstd_lite_in_place_t(E2) >::value
+ && !std::is_same< typename std20::remove_cvref<E2>::type, unexpected_type >::value
+ )
+ >
+ constexpr explicit unexpected_type( E2 && error )
+ : m_error( std::forward<E2>( error ) )
+ {}
+
+ template< typename E2
+ nsel_REQUIRES_T(
+ std::is_constructible< E, E2>::value
+ && !std::is_constructible<E, unexpected_type<E2> & >::value
+ && !std::is_constructible<E, unexpected_type<E2> >::value
+ && !std::is_constructible<E, unexpected_type<E2> const & >::value
+ && !std::is_constructible<E, unexpected_type<E2> const >::value
+ && !std::is_convertible< unexpected_type<E2> &, E>::value
+ && !std::is_convertible< unexpected_type<E2> , E>::value
+ && !std::is_convertible< unexpected_type<E2> const &, E>::value
+ && !std::is_convertible< unexpected_type<E2> const , E>::value
+ && !std::is_convertible< E2 const &, E>::value /*=> explicit */
+ )
+ >
+ constexpr explicit unexpected_type( unexpected_type<E2> const & error )
+ : m_error( E{ error.error() } )
+ {}
+
+ template< typename E2
+ nsel_REQUIRES_T(
+ std::is_constructible< E, E2>::value
+ && !std::is_constructible<E, unexpected_type<E2> & >::value
+ && !std::is_constructible<E, unexpected_type<E2> >::value
+ && !std::is_constructible<E, unexpected_type<E2> const & >::value
+ && !std::is_constructible<E, unexpected_type<E2> const >::value
+ && !std::is_convertible< unexpected_type<E2> &, E>::value
+ && !std::is_convertible< unexpected_type<E2> , E>::value
+ && !std::is_convertible< unexpected_type<E2> const &, E>::value
+ && !std::is_convertible< unexpected_type<E2> const , E>::value
+ && std::is_convertible< E2 const &, E>::value /*=> explicit */
+ )
+ >
+ constexpr /*non-explicit*/ unexpected_type( unexpected_type<E2> const & error )
+ : m_error( error.error() )
+ {}
+
+ template< typename E2
+ nsel_REQUIRES_T(
+ std::is_constructible< E, E2>::value
+ && !std::is_constructible<E, unexpected_type<E2> & >::value
+ && !std::is_constructible<E, unexpected_type<E2> >::value
+ && !std::is_constructible<E, unexpected_type<E2> const & >::value
+ && !std::is_constructible<E, unexpected_type<E2> const >::value
+ && !std::is_convertible< unexpected_type<E2> &, E>::value
+ && !std::is_convertible< unexpected_type<E2> , E>::value
+ && !std::is_convertible< unexpected_type<E2> const &, E>::value
+ && !std::is_convertible< unexpected_type<E2> const , E>::value
+ && !std::is_convertible< E2 const &, E>::value /*=> explicit */
+ )
+ >
+ constexpr explicit unexpected_type( unexpected_type<E2> && error )
+ : m_error( E{ std::move( error.error() ) } )
+ {}
+
+ template< typename E2
+ nsel_REQUIRES_T(
+ std::is_constructible< E, E2>::value
+ && !std::is_constructible<E, unexpected_type<E2> & >::value
+ && !std::is_constructible<E, unexpected_type<E2> >::value
+ && !std::is_constructible<E, unexpected_type<E2> const & >::value
+ && !std::is_constructible<E, unexpected_type<E2> const >::value
+ && !std::is_convertible< unexpected_type<E2> &, E>::value
+ && !std::is_convertible< unexpected_type<E2> , E>::value
+ && !std::is_convertible< unexpected_type<E2> const &, E>::value
+ && !std::is_convertible< unexpected_type<E2> const , E>::value
+ && std::is_convertible< E2 const &, E>::value /*=> non-explicit */
+ )
+ >
+ constexpr /*non-explicit*/ unexpected_type( unexpected_type<E2> && error )
+ : m_error( std::move( error.error() ) )
+ {}
+
+ // x.x.5.2.2 Assignment
+
+ nsel_constexpr14 unexpected_type& operator=( unexpected_type const & ) = default;
+ nsel_constexpr14 unexpected_type& operator=( unexpected_type && ) = default;
+
+ template< typename E2 = E >
+ nsel_constexpr14 unexpected_type & operator=( unexpected_type<E2> const & other )
+ {
+ unexpected_type{ other.error() }.swap( *this );
+ return *this;
+ }
+
+ template< typename E2 = E >
+ nsel_constexpr14 unexpected_type & operator=( unexpected_type<E2> && other )
+ {
+ unexpected_type{ std::move( other.error() ) }.swap( *this );
+ return *this;
+ }
+
+ // x.x.5.2.3 Observers
+
+ nsel_constexpr14 E & error() & noexcept
+ {
+ return m_error;
+ }
+
+ constexpr E const & error() const & noexcept
+ {
+ return m_error;
+ }
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+
+ nsel_constexpr14 E && error() && noexcept
+ {
+ return std::move( m_error );
+ }
+
+ constexpr E const && error() const && noexcept
+ {
+ return std::move( m_error );
+ }
+
+#endif
+
+ // x.x.5.2.3 Observers - deprecated
+
+ nsel_deprecated("replace value() with error()")
+
+ nsel_constexpr14 E & value() & noexcept
+ {
+ return m_error;
+ }
+
+ nsel_deprecated("replace value() with error()")
+
+ constexpr E const & value() const & noexcept
+ {
+ return m_error;
+ }
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+
+ nsel_deprecated("replace value() with error()")
+
+ nsel_constexpr14 E && value() && noexcept
+ {
+ return std::move( m_error );
+ }
+
+ nsel_deprecated("replace value() with error()")
+
+ constexpr E const && value() const && noexcept
+ {
+ return std::move( m_error );
+ }
+
+#endif
+
+ // x.x.5.2.4 Swap
+
+ template< typename U=E >
+ nsel_REQUIRES_R( void,
+ std17::is_swappable<U>::value
+ )
+ swap( unexpected_type & other ) noexcept (
+ std17::is_nothrow_swappable<U>::value
+ )
+ {
+ using std::swap;
+ swap( m_error, other.m_error );
+ }
+
+ // TODO: ??? unexpected_type: in-class friend operator==, !=
+
+private:
+ error_type m_error;
+};
+
+#if nsel_CPP17_OR_GREATER
+
+/// template deduction guide:
+
+template< typename E >
+unexpected_type( E ) -> unexpected_type< E >;
+
+#endif
+
+/// class unexpected_type, std::exception_ptr specialization (P0323R2)
+
+#if !nsel_CONFIG_NO_EXCEPTIONS
+#if nsel_P0323R <= 2
+
+// TODO: Should expected be specialized for particular E types such as exception_ptr and how?
+// See p0323r7 2.1. Ergonomics, http://wg21.link/p0323
+template<>
+class unexpected_type< std::exception_ptr >
+{
+public:
+ using error_type = std::exception_ptr;
+
+ unexpected_type() = delete;
+
+ ~unexpected_type(){}
+
+ explicit unexpected_type( std::exception_ptr const & error )
+ : m_error( error )
+ {}
+
+ explicit unexpected_type(std::exception_ptr && error )
+ : m_error( std::move( error ) )
+ {}
+
+ template< typename E >
+ explicit unexpected_type( E error )
+ : m_error( std::make_exception_ptr( error ) )
+ {}
+
+ std::exception_ptr const & value() const
+ {
+ return m_error;
+ }
+
+ std::exception_ptr & value()
+ {
+ return m_error;
+ }
+
+private:
+ std::exception_ptr m_error;
+};
+
+#endif // nsel_P0323R
+#endif // !nsel_CONFIG_NO_EXCEPTIONS
+
+/// x.x.4, Unexpected equality operators
+
+template< typename E1, typename E2 >
+constexpr bool operator==( unexpected_type<E1> const & x, unexpected_type<E2> const & y )
+{
+ return x.error() == y.error();
+}
+
+template< typename E1, typename E2 >
+constexpr bool operator!=( unexpected_type<E1> const & x, unexpected_type<E2> const & y )
+{
+ return ! ( x == y );
+}
+
+#if nsel_P0323R <= 2
+
+template< typename E >
+constexpr bool operator<( unexpected_type<E> const & x, unexpected_type<E> const & y )
+{
+ return x.error() < y.error();
+}
+
+template< typename E >
+constexpr bool operator>( unexpected_type<E> const & x, unexpected_type<E> const & y )
+{
+ return ( y < x );
+}
+
+template< typename E >
+constexpr bool operator<=( unexpected_type<E> const & x, unexpected_type<E> const & y )
+{
+ return ! ( y < x );
+}
+
+template< typename E >
+constexpr bool operator>=( unexpected_type<E> const & x, unexpected_type<E> const & y )
+{
+ return ! ( x < y );
+}
+
+#endif // nsel_P0323R
+
+/// x.x.5 Specialized algorithms
+
+template< typename E
+ nsel_REQUIRES_T(
+ std17::is_swappable<E>::value
+ )
+>
+void swap( unexpected_type<E> & x, unexpected_type<E> & y) noexcept ( noexcept ( x.swap(y) ) )
+{
+ x.swap( y );
+}
+
+#if nsel_P0323R <= 2
+
+// unexpected: relational operators for std::exception_ptr:
+
+inline constexpr bool operator<( unexpected_type<std::exception_ptr> const & /*x*/, unexpected_type<std::exception_ptr> const & /*y*/ )
+{
+ return false;
+}
+
+inline constexpr bool operator>( unexpected_type<std::exception_ptr> const & /*x*/, unexpected_type<std::exception_ptr> const & /*y*/ )
+{
+ return false;
+}
+
+inline constexpr bool operator<=( unexpected_type<std::exception_ptr> const & x, unexpected_type<std::exception_ptr> const & y )
+{
+ return ( x == y );
+}
+
+inline constexpr bool operator>=( unexpected_type<std::exception_ptr> const & x, unexpected_type<std::exception_ptr> const & y )
+{
+ return ( x == y );
+}
+
+#endif // nsel_P0323R
+
+// unexpected: traits
+
+#if nsel_P0323R <= 3
+
+template< typename E>
+struct is_unexpected : std::false_type {};
+
+template< typename E>
+struct is_unexpected< unexpected_type<E> > : std::true_type {};
+
+#endif // nsel_P0323R
+
+// unexpected: factory
+
+// keep make_unexpected() removed in p0323r2 for pre-C++17:
+
+template< typename E>
+nsel_constexpr14 auto
+make_unexpected( E && value ) -> unexpected_type< typename std::decay<E>::type >
+{
+ return unexpected_type< typename std::decay<E>::type >( std::forward<E>(value) );
+}
+
+#if nsel_P0323R <= 3
+
+/*nsel_constexpr14*/ auto inline
+make_unexpected_from_current_exception() -> unexpected_type< std::exception_ptr >
+{
+ return unexpected_type< std::exception_ptr >( std::current_exception() );
+}
+
+#endif // nsel_P0323R
+
+/// x.x.6, x.x.7 expected access error
+
+template< typename E >
+class bad_expected_access;
+
+/// x.x.7 bad_expected_access<void>: expected access error
+
+template <>
+class bad_expected_access< void > : public std::exception
+{
+public:
+ explicit bad_expected_access()
+ : std::exception()
+ {}
+};
+
+/// x.x.6 bad_expected_access: expected access error
+
+#if !nsel_CONFIG_NO_EXCEPTIONS
+
+template< typename E >
+class bad_expected_access : public bad_expected_access< void >
+{
+public:
+ using error_type = E;
+
+ explicit bad_expected_access( error_type error )
+ : m_error( error )
+ {}
+
+ virtual char const * what() const noexcept override
+ {
+ return "bad_expected_access";
+ }
+
+ nsel_constexpr14 error_type & error() &
+ {
+ return m_error;
+ }
+
+ constexpr error_type const & error() const &
+ {
+ return m_error;
+ }
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+
+ nsel_constexpr14 error_type && error() &&
+ {
+ return std::move( m_error );
+ }
+
+ constexpr error_type const && error() const &&
+ {
+ return std::move( m_error );
+ }
+
+#endif
+
+private:
+ error_type m_error;
+};
+
+#endif // nsel_CONFIG_NO_EXCEPTIONS
+
+/// x.x.8 unexpect tag, in_place_unexpected tag: construct an error
+
+struct unexpect_t{};
+using in_place_unexpected_t = unexpect_t;
+
+nsel_inline17 constexpr unexpect_t unexpect{};
+nsel_inline17 constexpr unexpect_t in_place_unexpected{};
+
+/// class error_traits
+
+#if nsel_CONFIG_NO_EXCEPTIONS
+
+namespace detail {
+ inline bool text( char const * /*text*/ ) { return true; }
+}
+
+template< typename Error >
+struct error_traits
+{
+ static void rethrow( Error const & /*e*/ )
+ {
+#if nsel_CONFIG_NO_EXCEPTIONS_SEH
+ RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL );
+#else
+ assert( false && detail::text("throw bad_expected_access<Error>{ e };") );
+#endif
+ }
+};
+
+template<>
+struct error_traits< std::exception_ptr >
+{
+ static void rethrow( std::exception_ptr const & /*e*/ )
+ {
+#if nsel_CONFIG_NO_EXCEPTIONS_SEH
+ RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL );
+#else
+ assert( false && detail::text("throw bad_expected_access<std::exception_ptr>{ e };") );
+#endif
+ }
+};
+
+template<>
+struct error_traits< std::error_code >
+{
+ static void rethrow( std::error_code const & /*e*/ )
+ {
+#if nsel_CONFIG_NO_EXCEPTIONS_SEH
+ RaiseException( EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL );
+#else
+ assert( false && detail::text("throw std::system_error( e );") );
+#endif
+ }
+};
+
+#else // nsel_CONFIG_NO_EXCEPTIONS
+
+template< typename Error >
+struct error_traits
+{
+ static void rethrow( Error const & e )
+ {
+ throw bad_expected_access<Error>{ e };
+ }
+};
+
+template<>
+struct error_traits< std::exception_ptr >
+{
+ static void rethrow( std::exception_ptr const & e )
+ {
+ std::rethrow_exception( e );
+ }
+};
+
+template<>
+struct error_traits< std::error_code >
+{
+ static void rethrow( std::error_code const & e )
+ {
+ throw std::system_error( e );
+ }
+};
+
+#endif // nsel_CONFIG_NO_EXCEPTIONS
+
+#if nsel_P2505R >= 3
+namespace detail {
+
+// from https://en.cppreference.com/w/cpp/utility/expected/unexpected:
+// "the type of the unexpected value. The type must not be an array type, a non-object type, a specialization of std::unexpected, or a cv-qualified type."
+template< typename T >
+struct valid_unexpected_type : std::integral_constant< bool,
+ std::is_same< T, typename std20::remove_cvref< T >::type >::value
+ && std::is_object< T >::value
+ && !std::is_array< T >::value
+> {};
+
+template< typename T >
+struct valid_unexpected_type< unexpected_type< T > > : std::false_type {};
+
+} // namespace detail
+#endif // nsel_P2505R >= 3
+
+} // namespace expected_lite
+
+// provide nonstd::unexpected_type:
+
+using expected_lite::unexpected_type;
+
+namespace expected_lite {
+
+/// class expected
+
+#if nsel_P0323R <= 2
+template< typename T, typename E = std::exception_ptr >
+class expected
+#else
+template< typename T, typename E >
+class expected
+#endif // nsel_P0323R
+{
+private:
+ template< typename, typename > friend class expected;
+
+public:
+ using value_type = T;
+ using error_type = E;
+ using unexpected_type = nonstd::unexpected_type<E>;
+
+ template< typename U >
+ struct rebind
+ {
+ using type = expected<U, error_type>;
+ };
+
+ // x.x.4.1 constructors
+
+ nsel_REQUIRES_0(
+ std::is_default_constructible<T>::value
+ )
+ nsel_constexpr14 expected()
+ : contained( true )
+ {
+ contained.construct_value();
+ }
+
+ nsel_constexpr14 expected( expected const & ) = default;
+ nsel_constexpr14 expected( expected && ) = default;
+
+ template< typename U, typename G
+ nsel_REQUIRES_T(
+ std::is_constructible< T, U const &>::value
+ && std::is_constructible<E, G const &>::value
+ && !std::is_constructible<T, expected<U, G> & >::value
+ && !std::is_constructible<T, expected<U, G> && >::value
+ && !std::is_constructible<T, expected<U, G> const & >::value
+ && !std::is_constructible<T, expected<U, G> const && >::value
+ && !std::is_convertible< expected<U, G> & , T>::value
+ && !std::is_convertible< expected<U, G> &&, T>::value
+ && !std::is_convertible< expected<U, G> const & , T>::value
+ && !std::is_convertible< expected<U, G> const &&, T>::value
+ && (!std::is_convertible<U const &, T>::value || !std::is_convertible<G const &, E>::value ) /*=> explicit */
+ )
+ >
+ nsel_constexpr14 explicit expected( expected<U, G> const & other )
+ : contained( other.has_value() )
+ {
+ if ( has_value() ) contained.construct_value( T{ other.contained.value() } );
+ else contained.construct_error( E{ other.contained.error() } );
+ }
+
+ template< typename U, typename G
+ nsel_REQUIRES_T(
+ std::is_constructible< T, U const &>::value
+ && std::is_constructible<E, G const &>::value
+ && !std::is_constructible<T, expected<U, G> & >::value
+ && !std::is_constructible<T, expected<U, G> && >::value
+ && !std::is_constructible<T, expected<U, G> const & >::value
+ && !std::is_constructible<T, expected<U, G> const && >::value
+ && !std::is_convertible< expected<U, G> & , T>::value
+ && !std::is_convertible< expected<U, G> &&, T>::value
+ && !std::is_convertible< expected<U, G> const &, T>::value
+ && !std::is_convertible< expected<U, G> const &&, T>::value
+ && !(!std::is_convertible<U const &, T>::value || !std::is_convertible<G const &, E>::value ) /*=> non-explicit */
+ )
+ >
+ nsel_constexpr14 /*non-explicit*/ expected( expected<U, G> const & other )
+ : contained( other.has_value() )
+ {
+ if ( has_value() ) contained.construct_value( other.contained.value() );
+ else contained.construct_error( other.contained.error() );
+ }
+
+ template< typename U, typename G
+ nsel_REQUIRES_T(
+ std::is_constructible< T, U>::value
+ && std::is_constructible<E, G>::value
+ && !std::is_constructible<T, expected<U, G> & >::value
+ && !std::is_constructible<T, expected<U, G> && >::value
+ && !std::is_constructible<T, expected<U, G> const & >::value
+ && !std::is_constructible<T, expected<U, G> const && >::value
+ && !std::is_convertible< expected<U, G> & , T>::value
+ && !std::is_convertible< expected<U, G> &&, T>::value
+ && !std::is_convertible< expected<U, G> const & , T>::value
+ && !std::is_convertible< expected<U, G> const &&, T>::value
+ && (!std::is_convertible<U, T>::value || !std::is_convertible<G, E>::value ) /*=> explicit */
+ )
+ >
+ nsel_constexpr14 explicit expected( expected<U, G> && other )
+ : contained( other.has_value() )
+ {
+ if ( has_value() ) contained.construct_value( T{ std::move( other.contained.value() ) } );
+ else contained.construct_error( E{ std::move( other.contained.error() ) } );
+ }
+
+ template< typename U, typename G
+ nsel_REQUIRES_T(
+ std::is_constructible< T, U>::value
+ && std::is_constructible<E, G>::value
+ && !std::is_constructible<T, expected<U, G> & >::value
+ && !std::is_constructible<T, expected<U, G> && >::value
+ && !std::is_constructible<T, expected<U, G> const & >::value
+ && !std::is_constructible<T, expected<U, G> const && >::value
+ && !std::is_convertible< expected<U, G> & , T>::value
+ && !std::is_convertible< expected<U, G> &&, T>::value
+ && !std::is_convertible< expected<U, G> const & , T>::value
+ && !std::is_convertible< expected<U, G> const &&, T>::value
+ && !(!std::is_convertible<U, T>::value || !std::is_convertible<G, E>::value ) /*=> non-explicit */
+ )
+ >
+ nsel_constexpr14 /*non-explicit*/ expected( expected<U, G> && other )
+ : contained( other.has_value() )
+ {
+ if ( has_value() ) contained.construct_value( std::move( other.contained.value() ) );
+ else contained.construct_error( std::move( other.contained.error() ) );
+ }
+
+ template< typename U = T
+ nsel_REQUIRES_T(
+ std::is_copy_constructible<U>::value
+ )
+ >
+ nsel_constexpr14 expected( value_type const & value )
+ : contained( true )
+ {
+ contained.construct_value( value );
+ }
+
+ template< typename U = T
+ nsel_REQUIRES_T(
+ std::is_constructible<T,U&&>::value
+ && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
+ && !std::is_same< expected<T,E> , typename std20::remove_cvref<U>::type>::value
+ && !std::is_same<nonstd::unexpected_type<E>, typename std20::remove_cvref<U>::type>::value
+ && !std::is_convertible<U&&,T>::value /*=> explicit */
+ )
+ >
+ nsel_constexpr14 explicit expected( U && value ) noexcept
+ (
+ std::is_nothrow_move_constructible<U>::value &&
+ std::is_nothrow_move_constructible<E>::value
+ )
+ : contained( true )
+ {
+ contained.construct_value( T{ std::forward<U>( value ) } );
+ }
+
+ template< typename U = T
+ nsel_REQUIRES_T(
+ std::is_constructible<T,U&&>::value
+ && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value
+ && !std::is_same< expected<T,E> , typename std20::remove_cvref<U>::type>::value
+ && !std::is_same<nonstd::unexpected_type<E>, typename std20::remove_cvref<U>::type>::value
+ && std::is_convertible<U&&,T>::value /*=> non-explicit */
+ )
+ >
+ nsel_constexpr14 /*non-explicit*/ expected( U && value ) noexcept
+ (
+ std::is_nothrow_move_constructible<U>::value &&
+ std::is_nothrow_move_constructible<E>::value
+ )
+ : contained( true )
+ {
+ contained.construct_value( std::forward<U>( value ) );
+ }
+
+ // construct error:
+
+ template< typename G = E
+ nsel_REQUIRES_T(
+ std::is_constructible<E, G const & >::value
+ && !std::is_convertible< G const &, E>::value /*=> explicit */
+ )
+ >
+ nsel_constexpr14 explicit expected( nonstd::unexpected_type<G> const & error )
+ : contained( false )
+ {
+ contained.construct_error( E{ error.error() } );
+ }
+
+ template< typename G = E
+ nsel_REQUIRES_T(
+ std::is_constructible<E, G const & >::value
+ && std::is_convertible< G const &, E>::value /*=> non-explicit */
+ )
+ >
+ nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type<G> const & error )
+ : contained( false )
+ {
+ contained.construct_error( error.error() );
+ }
+
+ template< typename G = E
+ nsel_REQUIRES_T(
+ std::is_constructible<E, G&& >::value
+ && !std::is_convertible< G&&, E>::value /*=> explicit */
+ )
+ >
+ nsel_constexpr14 explicit expected( nonstd::unexpected_type<G> && error )
+ : contained( false )
+ {
+ contained.construct_error( E{ std::move( error.error() ) } );
+ }
+
+ template< typename G = E
+ nsel_REQUIRES_T(
+ std::is_constructible<E, G&& >::value
+ && std::is_convertible< G&&, E>::value /*=> non-explicit */
+ )
+ >
+ nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type<G> && error )
+ : contained( false )
+ {
+ contained.construct_error( std::move( error.error() ) );
+ }
+
+ // in-place construction, value
+
+ template< typename... Args
+ nsel_REQUIRES_T(
+ std::is_constructible<T, Args&&...>::value
+ )
+ >
+ nsel_constexpr14 explicit expected( nonstd_lite_in_place_t(T), Args&&... args )
+ : contained( true )
+ {
+ contained.emplace_value( std::forward<Args>( args )... );
+ }
+
+ template< typename U, typename... Args
+ nsel_REQUIRES_T(
+ std::is_constructible<T, std::initializer_list<U>, Args&&...>::value
+ )
+ >
+ nsel_constexpr14 explicit expected( nonstd_lite_in_place_t(T), std::initializer_list<U> il, Args&&... args )
+ : contained( true )
+ {
+ contained.emplace_value( il, std::forward<Args>( args )... );
+ }
+
+ // in-place construction, error
+
+ template< typename... Args
+ nsel_REQUIRES_T(
+ std::is_constructible<E, Args&&...>::value
+ )
+ >
+ nsel_constexpr14 explicit expected( unexpect_t, Args&&... args )
+ : contained( false )
+ {
+ contained.emplace_error( std::forward<Args>( args )... );
+ }
+
+ template< typename U, typename... Args
+ nsel_REQUIRES_T(
+ std::is_constructible<E, std::initializer_list<U>, Args&&...>::value
+ )
+ >
+ nsel_constexpr14 explicit expected( unexpect_t, std::initializer_list<U> il, Args&&... args )
+ : contained( false )
+ {
+ contained.emplace_error( il, std::forward<Args>( args )... );
+ }
+
+ // x.x.4.2 destructor
+
+ // TODO: ~expected: triviality
+ // Effects: If T is not cv void and is_trivially_destructible_v<T> is false and bool(*this), calls val.~T(). If is_trivially_destructible_v<E> is false and !bool(*this), calls unexpect.~unexpected<E>().
+ // Remarks: If either T is cv void or is_trivially_destructible_v<T> is true, and is_trivially_destructible_v<E> is true, then this destructor shall be a trivial destructor.
+
+ ~expected()
+ {
+ if ( has_value() ) contained.destruct_value();
+ else contained.destruct_error();
+ }
+
+ // x.x.4.3 assignment
+
+ expected & operator=( expected const & other )
+ {
+ expected( other ).swap( *this );
+ return *this;
+ }
+
+ expected & operator=( expected && other ) noexcept
+ (
+ std::is_nothrow_move_constructible< T>::value
+ && std::is_nothrow_move_assignable< T>::value
+ && std::is_nothrow_move_constructible<E>::value // added for missing
+ && std::is_nothrow_move_assignable< E>::value ) // nothrow above
+ {
+ expected( std::move( other ) ).swap( *this );
+ return *this;
+ }
+
+ template< typename U
+ nsel_REQUIRES_T(
+ !std::is_same<expected<T,E>, typename std20::remove_cvref<U>::type>::value
+ && std17::conjunction<std::is_scalar<T>, std::is_same<T, std::decay<U>> >::value
+ && std::is_constructible<T ,U>::value
+ && std::is_assignable< T&,U>::value
+ && std::is_nothrow_move_constructible<E>::value )
+ >
+ expected & operator=( U && value )
+ {
+ expected( std::forward<U>( value ) ).swap( *this );
+ return *this;
+ }
+
+ template< typename G = E
+ nsel_REQUIRES_T(
+ std::is_constructible<E, G const&>::value &&
+ std::is_copy_constructible<G>::value // TODO: std::is_nothrow_copy_constructible<G>
+ && std::is_copy_assignable<G>::value
+ )
+ >
+ expected & operator=( nonstd::unexpected_type<G> const & error )
+ {
+ expected( unexpect, error.error() ).swap( *this );
+ return *this;
+ }
+
+ template< typename G = E
+ nsel_REQUIRES_T(
+ std::is_constructible<E, G&&>::value &&
+ std::is_move_constructible<G>::value // TODO: std::is_nothrow_move_constructible<G>
+ && std::is_move_assignable<G>::value
+ )
+ >
+ expected & operator=( nonstd::unexpected_type<G> && error )
+ {
+ expected( unexpect, std::move( error.error() ) ).swap( *this );
+ return *this;
+ }
+
+ template< typename... Args
+ nsel_REQUIRES_T(
+ std::is_nothrow_constructible<T, Args&&...>::value
+ )
+ >
+ value_type & emplace( Args &&... args )
+ {
+ expected( nonstd_lite_in_place(T), std::forward<Args>(args)... ).swap( *this );
+ return value();
+ }
+
+ template< typename U, typename... Args
+ nsel_REQUIRES_T(
+ std::is_nothrow_constructible<T, std::initializer_list<U>&, Args&&...>::value
+ )
+ >
+ value_type & emplace( std::initializer_list<U> il, Args &&... args )
+ {
+ expected( nonstd_lite_in_place(T), il, std::forward<Args>(args)... ).swap( *this );
+ return value();
+ }
+
+ // x.x.4.4 swap
+
+ template< typename U=T, typename G=E >
+ nsel_REQUIRES_R( void,
+ std17::is_swappable< U>::value
+ && std17::is_swappable<G>::value
+ && ( std::is_move_constructible<U>::value || std::is_move_constructible<G>::value )
+ )
+ swap( expected & other ) noexcept
+ (
+ std::is_nothrow_move_constructible<T>::value && std17::is_nothrow_swappable<T&>::value &&
+ std::is_nothrow_move_constructible<E>::value && std17::is_nothrow_swappable<E&>::value
+ )
+ {
+ using std::swap;
+
+ if ( bool(*this) && bool(other) ) { swap( contained.value(), other.contained.value() ); }
+ else if ( ! bool(*this) && ! bool(other) ) { swap( contained.error(), other.contained.error() ); }
+ else if ( bool(*this) && ! bool(other) ) { error_type t( std::move( other.error() ) );
+ other.contained.destruct_error();
+ other.contained.construct_value( std::move( contained.value() ) );
+ contained.destruct_value();
+ contained.construct_error( std::move( t ) );
+ bool has_value = contained.has_value();
+ bool other_has_value = other.has_value();
+ other.contained.set_has_value(has_value);
+ contained.set_has_value(other_has_value);
+ }
+ else if ( ! bool(*this) && bool(other) ) { other.swap( *this ); }
+ }
+
+ // x.x.4.5 observers
+
+ constexpr value_type const * operator ->() const
+ {
+ return assert( has_value() ), contained.value_ptr();
+ }
+
+ value_type * operator ->()
+ {
+ return assert( has_value() ), contained.value_ptr();
+ }
+
+ constexpr value_type const & operator *() const &
+ {
+ return assert( has_value() ), contained.value();
+ }
+
+ value_type & operator *() &
+ {
+ return assert( has_value() ), contained.value();
+ }
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+
+ constexpr value_type const && operator *() const &&
+ {
+ return std::move( ( assert( has_value() ), contained.value() ) );
+ }
+
+ nsel_constexpr14 value_type && operator *() &&
+ {
+ return std::move( ( assert( has_value() ), contained.value() ) );
+ }
+
+#endif
+
+ constexpr explicit operator bool() const noexcept
+ {
+ return has_value();
+ }
+
+ constexpr bool has_value() const noexcept
+ {
+ return contained.has_value();
+ }
+
+ nsel_DISABLE_MSVC_WARNINGS( 4702 ) // warning C4702: unreachable code, see issue 65.
+
+ constexpr value_type const & value() const &
+ {
+ return has_value()
+ ? ( contained.value() )
+ : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
+ }
+
+ value_type & value() &
+ {
+ return has_value()
+ ? ( contained.value() )
+ : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
+ }
+ nsel_RESTORE_MSVC_WARNINGS()
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+
+ constexpr value_type const && value() const &&
+ {
+ return std::move( has_value()
+ ? ( contained.value() )
+ : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() ) );
+ }
+
+ nsel_constexpr14 value_type && value() &&
+ {
+ return std::move( has_value()
+ ? ( contained.value() )
+ : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() ) );
+ }
+
+#endif
+
+ constexpr error_type const & error() const &
+ {
+ return assert( ! has_value() ), contained.error();
+ }
+
+ error_type & error() &
+ {
+ return assert( ! has_value() ), contained.error();
+ }
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+
+ constexpr error_type const && error() const &&
+ {
+ return std::move( ( assert( ! has_value() ), contained.error() ) );
+ }
+
+ error_type && error() &&
+ {
+ return std::move( ( assert( ! has_value() ), contained.error() ) );
+ }
+
+#endif
+
+ constexpr unexpected_type get_unexpected() const
+ {
+ return make_unexpected( contained.error() );
+ }
+
+ template< typename Ex >
+ bool has_exception() const
+ {
+ using ContainedEx = typename std::remove_reference< decltype( get_unexpected().value() ) >::type;
+ return ! has_value() && std::is_base_of< Ex, ContainedEx>::value;
+ }
+
+ template< typename U
+ nsel_REQUIRES_T(
+ std::is_copy_constructible< T>::value
+ && std::is_convertible<U&&, T>::value
+ )
+ >
+ value_type value_or( U && v ) const &
+ {
+ return has_value()
+ ? contained.value()
+ : static_cast<T>( std::forward<U>( v ) );
+ }
+
+ template< typename U
+ nsel_REQUIRES_T(
+ std::is_move_constructible< T>::value
+ && std::is_convertible<U&&, T>::value
+ )
+ >
+ value_type value_or( U && v ) &&
+ {
+ return has_value()
+ ? std::move( contained.value() )
+ : static_cast<T>( std::forward<U>( v ) );
+ }
+
+#if nsel_P2505R >= 4
+ template< typename G = E
+ nsel_REQUIRES_T(
+ std::is_copy_constructible< E >::value
+ && std::is_convertible< G, E >::value
+ )
+ >
+ nsel_constexpr error_type error_or( G && e ) const &
+ {
+ return has_value()
+ ? static_cast< E >( std::forward< G >( e ) )
+ : contained.error();
+ }
+
+ template< typename G = E
+ nsel_REQUIRES_T(
+ std::is_move_constructible< E >::value
+ && std::is_convertible< G, E >::value
+ )
+ >
+ nsel_constexpr14 error_type error_or( G && e ) &&
+ {
+ return has_value()
+ ? static_cast< E >( std::forward< G >( e ) )
+ : std::move( contained.error() );
+ }
+#endif // nsel_P2505R >= 4
+
+#if nsel_P2505R >= 3
+ // Monadic operations (P2505)
+ template< typename F
+ nsel_REQUIRES_T(
+ detail::is_expected < detail::invoke_result_nocvref_t< F, value_type & > > ::value
+ && std::is_same< typename detail::invoke_result_nocvref_t< F, value_type & >::error_type, error_type >::value
+ && std::is_constructible< error_type, error_type & >::value
+ )
+ >
+ nsel_constexpr14 detail::invoke_result_nocvref_t< F, value_type & > and_then( F && f ) &
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F, value_type & >( detail::invoke( std::forward< F >( f ), value() ) )
+ : detail::invoke_result_nocvref_t< F, value_type & >( unexpect, error() );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F, const value_type & > >::value
+ && std::is_same< typename detail::invoke_result_nocvref_t< F, const value_type & >::error_type, error_type >::value
+ && std::is_constructible< error_type, const error_type & >::value
+ )
+ >
+ nsel_constexpr detail::invoke_result_nocvref_t< F, const value_type & > and_then( F && f ) const &
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F, const value_type & >( detail::invoke( std::forward< F >( f ), value() ) )
+ : detail::invoke_result_nocvref_t< F, const value_type & >( unexpect, error() );
+ }
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F, value_type && > >::value
+ && std::is_same< typename detail::invoke_result_nocvref_t< F, value_type && >::error_type, error_type >::value
+ && std::is_constructible< error_type, error_type && >::value
+ )
+ >
+ nsel_constexpr14 detail::invoke_result_nocvref_t< F, value_type && > and_then( F && f ) &&
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F, value_type && >( detail::invoke( std::forward< F >( f ), std::move( value() ) ) )
+ : detail::invoke_result_nocvref_t< F, value_type && >( unexpect, std::move( error() ) );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F, const value_type && > >::value
+ && std::is_same< typename detail::invoke_result_nocvref_t< F, const value_type & >::error_type, error_type >::value
+ && std::is_constructible< error_type, const error_type && >::value
+ )
+ >
+ nsel_constexpr detail::invoke_result_nocvref_t< F, const value_type && > and_then( F && f ) const &&
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F, const value_type && >( detail::invoke( std::forward< F >( f ), std::move( value() ) ) )
+ : detail::invoke_result_nocvref_t< F, const value_type && >( unexpect, std::move( error() ) );
+ }
+#endif
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F, error_type & > >::value
+ && std::is_same< typename detail::invoke_result_nocvref_t< F, error_type & >::value_type, value_type >::value
+ && std::is_constructible< value_type, value_type & >::value
+ )
+ >
+ nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type & > or_else( F && f ) &
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F, error_type & >( value() )
+ : detail::invoke_result_nocvref_t< F, error_type & >( detail::invoke( std::forward< F >( f ), error() ) );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F, const error_type & > >::value
+ && std::is_same< typename detail::invoke_result_nocvref_t< F, const error_type & >::value_type, value_type >::value
+ && std::is_constructible< value_type, const value_type & >::value
+ )
+ >
+ nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type & > or_else( F && f ) const &
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F, const error_type & >( value() )
+ : detail::invoke_result_nocvref_t< F, const error_type & >( detail::invoke( std::forward< F >( f ), error() ) );
+ }
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F, error_type && > >::value
+ && std::is_same< typename detail::invoke_result_nocvref_t< F, error_type && >::value_type, value_type >::value
+ && std::is_constructible< value_type, value_type && >::value
+ )
+ >
+ nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type && > or_else( F && f ) &&
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F, error_type && >( std::move( value() ) )
+ : detail::invoke_result_nocvref_t< F, error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F, const error_type && > >::value
+ && std::is_same< typename detail::invoke_result_nocvref_t< F, const error_type && >::value_type, value_type >::value
+ && std::is_constructible< value_type, const value_type && >::value
+ )
+ >
+ nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type && > or_else( F && f ) const &&
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F, const error_type && >( std::move( value() ) )
+ : detail::invoke_result_nocvref_t< F, const error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
+ }
+#endif
+
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, error_type & >::value
+ && !std::is_void< detail::transform_invoke_result_t< F, value_type & > >::value
+ && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, value_type & > >::value
+ )
+ >
+ nsel_constexpr14 expected< detail::transform_invoke_result_t< F, value_type & >, error_type > transform( F && f ) &
+ {
+ return has_value()
+ ? expected< detail::transform_invoke_result_t< F, value_type & >, error_type >( detail::invoke( std::forward< F >( f ), **this ) )
+ : make_unexpected( error() );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, error_type & >::value
+ && std::is_void< detail::transform_invoke_result_t< F, value_type & > >::value
+ )
+ >
+ nsel_constexpr14 expected< void, error_type > transform( F && f ) &
+ {
+ return has_value()
+ ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() )
+ : make_unexpected( error() );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, const error_type & >::value
+ && !std::is_void< detail::transform_invoke_result_t< F, const value_type & > >::value
+ && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, const value_type & > >::value
+ )
+ >
+ nsel_constexpr expected< detail::transform_invoke_result_t< F, const value_type & >, error_type > transform( F && f ) const &
+ {
+ return has_value()
+ ? expected< detail::transform_invoke_result_t< F, const value_type & >, error_type >( detail::invoke( std::forward< F >( f ), **this ) )
+ : make_unexpected( error() );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, const error_type & >::value
+ && std::is_void< detail::transform_invoke_result_t< F, const value_type & > >::value
+ )
+ >
+ nsel_constexpr expected< void, error_type > transform( F && f ) const &
+ {
+ return has_value()
+ ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() )
+ : make_unexpected( error() );
+ }
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, error_type && >::value
+ && !std::is_void< detail::transform_invoke_result_t< F, value_type && > >::value
+ && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, value_type && > >::value
+ )
+ >
+ nsel_constexpr14 expected< detail::transform_invoke_result_t< F, value_type && >, error_type > transform( F && f ) &&
+ {
+ return has_value()
+ ? expected< detail::transform_invoke_result_t< F, value_type && >, error_type >( detail::invoke( std::forward< F >( f ), std::move( **this ) ) )
+ : make_unexpected( std::move( error() ) );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, error_type && >::value
+ && std::is_void< detail::transform_invoke_result_t< F, value_type && > >::value
+ )
+ >
+ nsel_constexpr14 expected< void, error_type > transform( F && f ) &&
+ {
+ return has_value()
+ ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() )
+ : make_unexpected( std::move( error() ) );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, const error_type && >::value
+ && !std::is_void< detail::transform_invoke_result_t< F, const value_type && > >::value
+ && detail::valid_expected_value_type< detail::transform_invoke_result_t< F, const value_type && > >::value
+ )
+ >
+ nsel_constexpr expected< detail::transform_invoke_result_t< F, const value_type && >, error_type > transform( F && f ) const &&
+ {
+ return has_value()
+ ? expected< detail::transform_invoke_result_t< F, const value_type && >, error_type >( detail::invoke( std::forward< F >( f ), std::move( **this ) ) )
+ : make_unexpected( std::move( error() ) );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, const error_type && >::value
+ && std::is_void< detail::transform_invoke_result_t< F, const value_type && > >::value
+ )
+ >
+ nsel_constexpr expected< void, error_type > transform( F && f ) const &&
+ {
+ return has_value()
+ ? ( detail::invoke( std::forward< F >( f ), **this ), expected< void, error_type >() )
+ : make_unexpected( std::move( error() ) );
+ }
+#endif
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::valid_unexpected_type< detail::transform_invoke_result_t< F, error_type & > >::value
+ && std::is_constructible< value_type, value_type & >::value
+ )
+ >
+ nsel_constexpr14 expected< value_type, detail::transform_invoke_result_t< F, error_type & > > transform_error( F && f ) &
+ {
+ return has_value()
+ ? expected< value_type, detail::transform_invoke_result_t< F, error_type & > >( in_place, **this )
+ : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::valid_unexpected_type< detail::transform_invoke_result_t< F, const error_type & > >::value
+ && std::is_constructible< value_type, const value_type & >::value
+ )
+ >
+ nsel_constexpr expected< value_type, detail::transform_invoke_result_t< F, const error_type & > > transform_error( F && f ) const &
+ {
+ return has_value()
+ ? expected< value_type, detail::transform_invoke_result_t< F, const error_type & > >( in_place, **this )
+ : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) );
+ }
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::valid_unexpected_type< detail::transform_invoke_result_t< F, error_type && > >::value
+ && std::is_constructible< value_type, value_type && >::value
+ )
+ >
+ nsel_constexpr14 expected< value_type, detail::transform_invoke_result_t< F, error_type && > > transform_error( F && f ) &&
+ {
+ return has_value()
+ ? expected< value_type, detail::transform_invoke_result_t< F, error_type && > >( in_place, std::move( **this ) )
+ : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::valid_unexpected_type< detail::transform_invoke_result_t< F, const error_type && > >::value
+ && std::is_constructible< value_type, const value_type && >::value
+ )
+ >
+ nsel_constexpr expected< value_type, detail::transform_invoke_result_t< F, const error_type && > > transform_error( F && f ) const &&
+ {
+ return has_value()
+ ? expected< value_type, detail::transform_invoke_result_t< F, const error_type && > >( in_place, std::move( **this ) )
+ : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
+ }
+#endif
+#endif // nsel_P2505R >= 3
+ // unwrap()
+
+// template <class U, class E>
+// constexpr expected<U,E> expected<expected<U,E>,E>::unwrap() const&;
+
+// template <class T, class E>
+// constexpr expected<T,E> expected<T,E>::unwrap() const&;
+
+// template <class U, class E>
+// expected<U,E> expected<expected<U,E>, E>::unwrap() &&;
+
+// template <class T, class E>
+// template expected<T,E> expected<T,E>::unwrap() &&;
+
+ // factories
+
+// template< typename Ex, typename F>
+// expected<T,E> catch_exception(F&& f);
+
+// template< typename F>
+// expected<decltype(func(declval<T>())),E> map(F&& func) ;
+
+// template< typename F>
+// 'see below' bind(F&& func);
+
+// template< typename F>
+// expected<T,E> catch_error(F&& f);
+
+// template< typename F>
+// 'see below' then(F&& func);
+
+private:
+ detail::storage_t
+ <
+ T
+ ,E
+ , std::is_copy_constructible<T>::value && std::is_copy_constructible<E>::value
+ , std::is_move_constructible<T>::value && std::is_move_constructible<E>::value
+ >
+ contained;
+};
+
+/// class expected, void specialization
+
+template< typename E >
+class expected<void, E>
+{
+private:
+ template< typename, typename > friend class expected;
+
+public:
+ using value_type = void;
+ using error_type = E;
+ using unexpected_type = nonstd::unexpected_type<E>;
+
+ // x.x.4.1 constructors
+
+ constexpr expected() noexcept
+ : contained( true )
+ {}
+
+ nsel_constexpr14 expected( expected const & other ) = default;
+ nsel_constexpr14 expected( expected && other ) = default;
+
+ constexpr explicit expected( nonstd_lite_in_place_t(void) )
+ : contained( true )
+ {}
+
+ template< typename G = E
+ nsel_REQUIRES_T(
+ !std::is_convertible<G const &, E>::value /*=> explicit */
+ )
+ >
+ nsel_constexpr14 explicit expected( nonstd::unexpected_type<G> const & error )
+ : contained( false )
+ {
+ contained.construct_error( E{ error.error() } );
+ }
+
+ template< typename G = E
+ nsel_REQUIRES_T(
+ std::is_convertible<G const &, E>::value /*=> non-explicit */
+ )
+ >
+ nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type<G> const & error )
+ : contained( false )
+ {
+ contained.construct_error( error.error() );
+ }
+
+ template< typename G = E
+ nsel_REQUIRES_T(
+ !std::is_convertible<G&&, E>::value /*=> explicit */
+ )
+ >
+ nsel_constexpr14 explicit expected( nonstd::unexpected_type<G> && error )
+ : contained( false )
+ {
+ contained.construct_error( E{ std::move( error.error() ) } );
+ }
+
+ template< typename G = E
+ nsel_REQUIRES_T(
+ std::is_convertible<G&&, E>::value /*=> non-explicit */
+ )
+ >
+ nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type<G> && error )
+ : contained( false )
+ {
+ contained.construct_error( std::move( error.error() ) );
+ }
+
+ template< typename... Args
+ nsel_REQUIRES_T(
+ std::is_constructible<E, Args&&...>::value
+ )
+ >
+ nsel_constexpr14 explicit expected( unexpect_t, Args&&... args )
+ : contained( false )
+ {
+ contained.emplace_error( std::forward<Args>( args )... );
+ }
+
+ template< typename U, typename... Args
+ nsel_REQUIRES_T(
+ std::is_constructible<E, std::initializer_list<U>, Args&&...>::value
+ )
+ >
+ nsel_constexpr14 explicit expected( unexpect_t, std::initializer_list<U> il, Args&&... args )
+ : contained( false )
+ {
+ contained.emplace_error( il, std::forward<Args>( args )... );
+ }
+
+ // destructor
+
+ ~expected()
+ {
+ if ( ! has_value() )
+ {
+ contained.destruct_error();
+ }
+ }
+
+ // x.x.4.3 assignment
+
+ expected & operator=( expected const & other )
+ {
+ expected( other ).swap( *this );
+ return *this;
+ }
+
+ expected & operator=( expected && other ) noexcept
+ (
+ std::is_nothrow_move_assignable<E>::value &&
+ std::is_nothrow_move_constructible<E>::value )
+ {
+ expected( std::move( other ) ).swap( *this );
+ return *this;
+ }
+
+ void emplace()
+ {
+ expected().swap( *this );
+ }
+
+ // x.x.4.4 swap
+
+ template< typename G = E >
+ nsel_REQUIRES_R( void,
+ std17::is_swappable<G>::value
+ && std::is_move_constructible<G>::value
+ )
+ swap( expected & other ) noexcept
+ (
+ std::is_nothrow_move_constructible<E>::value && std17::is_nothrow_swappable<E&>::value
+ )
+ {
+ using std::swap;
+
+ if ( ! bool(*this) && ! bool(other) ) { swap( contained.error(), other.contained.error() ); }
+ else if ( bool(*this) && ! bool(other) ) { contained.construct_error( std::move( other.error() ) );
+ bool has_value = contained.has_value();
+ bool other_has_value = other.has_value();
+ other.contained.set_has_value(has_value);
+ contained.set_has_value(other_has_value);
+ }
+ else if ( ! bool(*this) && bool(other) ) { other.swap( *this ); }
+ }
+
+ // x.x.4.5 observers
+
+ constexpr explicit operator bool() const noexcept
+ {
+ return has_value();
+ }
+
+ constexpr bool has_value() const noexcept
+ {
+ return contained.has_value();
+ }
+
+ void value() const
+ {
+ if ( ! has_value() )
+ {
+ error_traits<error_type>::rethrow( contained.error() );
+ }
+ }
+
+ constexpr error_type const & error() const &
+ {
+ return assert( ! has_value() ), contained.error();
+ }
+
+ error_type & error() &
+ {
+ return assert( ! has_value() ), contained.error();
+ }
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+
+ constexpr error_type const && error() const &&
+ {
+ return std::move( ( assert( ! has_value() ), contained.error() ) );
+ }
+
+ error_type && error() &&
+ {
+ return std::move( ( assert( ! has_value() ), contained.error() ) );
+ }
+
+#endif
+
+ constexpr unexpected_type get_unexpected() const
+ {
+ return make_unexpected( contained.error() );
+ }
+
+ template< typename Ex >
+ bool has_exception() const
+ {
+ using ContainedEx = typename std::remove_reference< decltype( get_unexpected().value() ) >::type;
+ return ! has_value() && std::is_base_of< Ex, ContainedEx>::value;
+ }
+
+#if nsel_P2505R >= 4
+ template< typename G = E
+ nsel_REQUIRES_T(
+ std::is_copy_constructible< E >::value
+ && std::is_convertible< G, E >::value
+ )
+ >
+ nsel_constexpr error_type error_or( G && e ) const &
+ {
+ return has_value()
+ ? static_cast< E >( std::forward< G >( e ) )
+ : contained.error();
+ }
+
+ template< typename G = E
+ nsel_REQUIRES_T(
+ std::is_move_constructible< E >::value
+ && std::is_convertible< G, E >::value
+ )
+ >
+ nsel_constexpr14 error_type error_or( G && e ) &&
+ {
+ return has_value()
+ ? static_cast< E >( std::forward< G >( e ) )
+ : std::move( contained.error() );
+ }
+#endif // nsel_P2505R >= 4
+
+#if nsel_P2505R >= 3
+ // Monadic operations (P2505)
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F > >::value
+ && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value
+ && std::is_constructible< error_type, error_type & >::value
+ )
+ >
+ nsel_constexpr14 detail::invoke_result_nocvref_t< F > and_then( F && f ) &
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) )
+ : detail::invoke_result_nocvref_t< F >( unexpect, error() );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F > >::value
+ && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value
+ && std::is_constructible< error_type, const error_type & >::value
+ )
+ >
+ nsel_constexpr detail::invoke_result_nocvref_t< F > and_then( F && f ) const &
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) )
+ : detail::invoke_result_nocvref_t< F >( unexpect, error() );
+ }
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F > >::value
+ && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value
+ && std::is_constructible< error_type, error_type && >::value
+ )
+ >
+ nsel_constexpr14 detail::invoke_result_nocvref_t< F > and_then( F && f ) &&
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) )
+ : detail::invoke_result_nocvref_t< F >( unexpect, std::move( error() ) );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F > >::value
+ && std::is_same< typename detail::invoke_result_nocvref_t< F >::error_type, error_type >::value
+ && std::is_constructible< error_type, const error_type && >::value
+ )
+ >
+ nsel_constexpr detail::invoke_result_nocvref_t< F > and_then( F && f ) const &&
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F >( detail::invoke( std::forward< F >( f ) ) )
+ : detail::invoke_result_nocvref_t< F >( unexpect, std::move( error() ) );
+ }
+#endif
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F, error_type & > >::value
+ && std::is_void< typename detail::invoke_result_nocvref_t< F, error_type & >::value_type >::value
+ )
+ >
+ nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type & > or_else( F && f ) &
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F, error_type & >()
+ : detail::invoke_result_nocvref_t< F, error_type & >( detail::invoke( std::forward< F >( f ), error() ) );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F, const error_type & > >::value
+ && std::is_void< typename detail::invoke_result_nocvref_t< F, const error_type & >::value_type >::value
+ )
+ >
+ nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type & > or_else( F && f ) const &
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F, const error_type & >()
+ : detail::invoke_result_nocvref_t< F, const error_type & >( detail::invoke( std::forward< F >( f ), error() ) );
+ }
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F, error_type && > >::value
+ && std::is_void< typename detail::invoke_result_nocvref_t< F, error_type && >::value_type >::value
+ )
+ >
+ nsel_constexpr14 detail::invoke_result_nocvref_t< F, error_type && > or_else( F && f ) &&
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F, error_type && >()
+ : detail::invoke_result_nocvref_t< F, error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::is_expected< detail::invoke_result_nocvref_t< F, const error_type && > >::value
+ && std::is_void< typename detail::invoke_result_nocvref_t< F, const error_type && >::value_type >::value
+ )
+ >
+ nsel_constexpr detail::invoke_result_nocvref_t< F, const error_type && > or_else( F && f ) const &&
+ {
+ return has_value()
+ ? detail::invoke_result_nocvref_t< F, const error_type && >()
+ : detail::invoke_result_nocvref_t< F, const error_type && >( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
+ }
+#endif
+
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, error_type & >::value
+ && !std::is_void< detail::transform_invoke_result_t< F > >::value
+ )
+ >
+ nsel_constexpr14 expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) &
+ {
+ return has_value()
+ ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) )
+ : make_unexpected( error() );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, error_type & >::value
+ && std::is_void< detail::transform_invoke_result_t< F > >::value
+ )
+ >
+ nsel_constexpr14 expected< void, error_type > transform( F && f ) &
+ {
+ return has_value()
+ ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() )
+ : make_unexpected( error() );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, const error_type & >::value
+ && !std::is_void< detail::transform_invoke_result_t< F > >::value
+ )
+ >
+ nsel_constexpr expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) const &
+ {
+ return has_value()
+ ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) )
+ : make_unexpected( error() );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, const error_type & >::value
+ && std::is_void< detail::transform_invoke_result_t< F > >::value
+ )
+ >
+ nsel_constexpr expected< void, error_type > transform( F && f ) const &
+ {
+ return has_value()
+ ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() )
+ : make_unexpected( error() );
+ }
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, error_type && >::value
+ && !std::is_void< detail::transform_invoke_result_t< F > >::value
+ )
+ >
+ nsel_constexpr14 expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) &&
+ {
+ return has_value()
+ ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) )
+ : make_unexpected( error() );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, error_type && >::value
+ && std::is_void< detail::transform_invoke_result_t< F > >::value
+ )
+ >
+ nsel_constexpr14 expected< void, error_type > transform( F && f ) &&
+ {
+ return has_value()
+ ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() )
+ : make_unexpected( error() );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, const error_type && >::value
+ && !std::is_void< detail::transform_invoke_result_t< F > >::value
+ )
+ >
+ nsel_constexpr expected< detail::transform_invoke_result_t< F >, error_type > transform( F && f ) const &&
+ {
+ return has_value()
+ ? expected< detail::transform_invoke_result_t< F >, error_type >( detail::invoke( std::forward< F >( f ) ) )
+ : make_unexpected( error() );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ std::is_constructible< error_type, const error_type && >::value
+ && std::is_void< detail::transform_invoke_result_t< F > >::value
+ )
+ >
+ nsel_constexpr expected< void, error_type > transform( F && f ) const &&
+ {
+ return has_value()
+ ? ( detail::invoke( std::forward< F >( f ) ), expected< void, error_type >() )
+ : make_unexpected( error() );
+ }
+#endif
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::valid_unexpected_type< detail::transform_invoke_result_t< F, error_type & > >::value
+ )
+ >
+ nsel_constexpr14 expected< void, detail::transform_invoke_result_t< F, error_type & > > transform_error( F && f ) &
+ {
+ return has_value()
+ ? expected< void, detail::transform_invoke_result_t< F, error_type & > >()
+ : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::valid_unexpected_type< detail::transform_invoke_result_t< F, const error_type & > >::value
+ )
+ >
+ nsel_constexpr expected< void, detail::transform_invoke_result_t< F, const error_type & > > transform_error( F && f ) const &
+ {
+ return has_value()
+ ? expected< void, detail::transform_invoke_result_t< F, const error_type & > >()
+ : make_unexpected( detail::invoke( std::forward< F >( f ), error() ) );
+ }
+
+#if !nsel_COMPILER_GNUC_VERSION || nsel_COMPILER_GNUC_VERSION >= 490
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::valid_unexpected_type< detail::transform_invoke_result_t< F, error_type && > >::value
+ )
+ >
+ nsel_constexpr14 expected< void, detail::transform_invoke_result_t< F, error_type && > > transform_error( F && f ) &&
+ {
+ return has_value()
+ ? expected< void, detail::transform_invoke_result_t< F, error_type && > >()
+ : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
+ }
+
+ template<typename F
+ nsel_REQUIRES_T(
+ detail::valid_unexpected_type< detail::transform_invoke_result_t< F, const error_type && > >::value
+ )
+ >
+ nsel_constexpr expected< void, detail::transform_invoke_result_t< F, const error_type && > > transform_error( F && f ) const &&
+ {
+ return has_value()
+ ? expected< void, detail::transform_invoke_result_t< F, const error_type && > >()
+ : make_unexpected( detail::invoke( std::forward< F >( f ), std::move( error() ) ) );
+ }
+#endif
+#endif // nsel_P2505R >= 3
+
+// template constexpr 'see below' unwrap() const&;
+//
+// template 'see below' unwrap() &&;
+
+ // factories
+
+// template< typename Ex, typename F>
+// expected<void,E> catch_exception(F&& f);
+//
+// template< typename F>
+// expected<decltype(func()), E> map(F&& func) ;
+//
+// template< typename F>
+// 'see below' bind(F&& func) ;
+//
+// template< typename F>
+// expected<void,E> catch_error(F&& f);
+//
+// template< typename F>
+// 'see below' then(F&& func);
+
+private:
+ detail::storage_t
+ <
+ void
+ , E
+ , std::is_copy_constructible<E>::value
+ , std::is_move_constructible<E>::value
+ >
+ contained;
+};
+
+// x.x.4.6 expected<>: comparison operators
+
+template< typename T1, typename E1, typename T2, typename E2
+ nsel_REQUIRES_T(
+ !std::is_void<T1>::value && !std::is_void<T2>::value
+ )
+>
+constexpr bool operator==( expected<T1,E1> const & x, expected<T2,E2> const & y )
+{
+ return bool(x) != bool(y) ? false : bool(x) ? *x == *y : x.error() == y.error();
+}
+
+template< typename T1, typename E1, typename T2, typename E2
+ nsel_REQUIRES_T(
+ std::is_void<T1>::value && std::is_void<T2>::value
+ )
+>
+constexpr bool operator==( expected<T1,E1> const & x, expected<T2,E2> const & y )
+{
+ return bool(x) != bool(y) ? false : bool(x) || static_cast<bool>( x.error() == y.error() );
+}
+
+template< typename T1, typename E1, typename T2, typename E2 >
+constexpr bool operator!=( expected<T1,E1> const & x, expected<T2,E2> const & y )
+{
+ return !(x == y);
+}
+
+#if nsel_P0323R <= 2
+
+template< typename T, typename E >
+constexpr bool operator<( expected<T,E> const & x, expected<T,E> const & y )
+{
+ return (!y) ? false : (!x) ? true : *x < *y;
+}
+
+template< typename T, typename E >
+constexpr bool operator>( expected<T,E> const & x, expected<T,E> const & y )
+{
+ return (y < x);
+}
+
+template< typename T, typename E >
+constexpr bool operator<=( expected<T,E> const & x, expected<T,E> const & y )
+{
+ return !(y < x);
+}
+
+template< typename T, typename E >
+constexpr bool operator>=( expected<T,E> const & x, expected<T,E> const & y )
+{
+ return !(x < y);
+}
+
+#endif
+
+// x.x.4.7 expected: comparison with T
+
+template< typename T1, typename E1, typename T2
+ nsel_REQUIRES_T(
+ !std::is_void<T1>::value
+ )
+>
+constexpr bool operator==( expected<T1,E1> const & x, T2 const & v )
+{
+ return bool(x) ? *x == v : false;
+}
+
+template< typename T1, typename E1, typename T2
+ nsel_REQUIRES_T(
+ !std::is_void<T1>::value
+ )
+>
+constexpr bool operator==(T2 const & v, expected<T1,E1> const & x )
+{
+ return bool(x) ? v == *x : false;
+}
+
+template< typename T1, typename E1, typename T2 >
+constexpr bool operator!=( expected<T1,E1> const & x, T2 const & v )
+{
+ return bool(x) ? *x != v : true;
+}
+
+template< typename T1, typename E1, typename T2 >
+constexpr bool operator!=( T2 const & v, expected<T1,E1> const & x )
+{
+ return bool(x) ? v != *x : true;
+}
+
+#if nsel_P0323R <= 2
+
+template< typename T, typename E >
+constexpr bool operator<( expected<T,E> const & x, T const & v )
+{
+ return bool(x) ? *x < v : true;
+}
+
+template< typename T, typename E >
+constexpr bool operator<( T const & v, expected<T,E> const & x )
+{
+ return bool(x) ? v < *x : false;
+}
+
+template< typename T, typename E >
+constexpr bool operator>( T const & v, expected<T,E> const & x )
+{
+ return bool(x) ? *x < v : false;
+}
+
+template< typename T, typename E >
+constexpr bool operator>( expected<T,E> const & x, T const & v )
+{
+ return bool(x) ? v < *x : false;
+}
+
+template< typename T, typename E >
+constexpr bool operator<=( T const & v, expected<T,E> const & x )
+{
+ return bool(x) ? ! ( *x < v ) : false;
+}
+
+template< typename T, typename E >
+constexpr bool operator<=( expected<T,E> const & x, T const & v )
+{
+ return bool(x) ? ! ( v < *x ) : true;
+}
+
+template< typename T, typename E >
+constexpr bool operator>=( expected<T,E> const & x, T const & v )
+{
+ return bool(x) ? ! ( *x < v ) : false;
+}
+
+template< typename T, typename E >
+constexpr bool operator>=( T const & v, expected<T,E> const & x )
+{
+ return bool(x) ? ! ( v < *x ) : true;
+}
+
+#endif // nsel_P0323R
+
+// x.x.4.8 expected: comparison with unexpected_type
+
+template< typename T1, typename E1 , typename E2 >
+constexpr bool operator==( expected<T1,E1> const & x, unexpected_type<E2> const & u )
+{
+ return (!x) ? x.get_unexpected() == u : false;
+}
+
+template< typename T1, typename E1 , typename E2 >
+constexpr bool operator==( unexpected_type<E2> const & u, expected<T1,E1> const & x )
+{
+ return ( x == u );
+}
+
+template< typename T1, typename E1 , typename E2 >
+constexpr bool operator!=( expected<T1,E1> const & x, unexpected_type<E2> const & u )
+{
+ return ! ( x == u );
+}
+
+template< typename T1, typename E1 , typename E2 >
+constexpr bool operator!=( unexpected_type<E2> const & u, expected<T1,E1> const & x )
+{
+ return ! ( x == u );
+}
+
+#if nsel_P0323R <= 2
+
+template< typename T, typename E >
+constexpr bool operator<( expected<T,E> const & x, unexpected_type<E> const & u )
+{
+ return (!x) ? ( x.get_unexpected() < u ) : false;
+}
+
+template< typename T, typename E >
+constexpr bool operator<( unexpected_type<E> const & u, expected<T,E> const & x )
+{
+ return (!x) ? ( u < x.get_unexpected() ) : true ;
+}
+
+template< typename T, typename E >
+constexpr bool operator>( expected<T,E> const & x, unexpected_type<E> const & u )
+{
+ return ( u < x );
+}
+
+template< typename T, typename E >
+constexpr bool operator>( unexpected_type<E> const & u, expected<T,E> const & x )
+{
+ return ( x < u );
+}
+
+template< typename T, typename E >
+constexpr bool operator<=( expected<T,E> const & x, unexpected_type<E> const & u )
+{
+ return ! ( u < x );
+}
+
+template< typename T, typename E >
+constexpr bool operator<=( unexpected_type<E> const & u, expected<T,E> const & x)
+{
+ return ! ( x < u );
+}
+
+template< typename T, typename E >
+constexpr bool operator>=( expected<T,E> const & x, unexpected_type<E> const & u )
+{
+ return ! ( u > x );
+}
+
+template< typename T, typename E >
+constexpr bool operator>=( unexpected_type<E> const & u, expected<T,E> const & x )
+{
+ return ! ( x > u );
+}
+
+#endif // nsel_P0323R
+
+/// x.x.x Specialized algorithms
+
+template< typename T, typename E
+ nsel_REQUIRES_T(
+ ( std::is_void<T>::value || std::is_move_constructible<T>::value )
+ && std::is_move_constructible<E>::value
+ && std17::is_swappable<T>::value
+ && std17::is_swappable<E>::value )
+>
+void swap( expected<T,E> & x, expected<T,E> & y ) noexcept ( noexcept ( x.swap(y) ) )
+{
+ x.swap( y );
+}
+
+#if nsel_P0323R <= 3
+
+template< typename T >
+constexpr auto make_expected( T && v ) -> expected< typename std::decay<T>::type >
+{
+ return expected< typename std::decay<T>::type >( std::forward<T>( v ) );
+}
+
+// expected<void> specialization:
+
+auto inline make_expected() -> expected<void>
+{
+ return expected<void>( in_place );
+}
+
+template< typename T >
+constexpr auto make_expected_from_current_exception() -> expected<T>
+{
+ return expected<T>( make_unexpected_from_current_exception() );
+}
+
+template< typename T >
+auto make_expected_from_exception( std::exception_ptr v ) -> expected<T>
+{
+ return expected<T>( unexpected_type<std::exception_ptr>( std::forward<std::exception_ptr>( v ) ) );
+}
+
+template< typename T, typename E >
+constexpr auto make_expected_from_error( E e ) -> expected<T, typename std::decay<E>::type>
+{
+ return expected<T, typename std::decay<E>::type>( make_unexpected( e ) );
+}
+
+template< typename F
+ nsel_REQUIRES_T( ! std::is_same<typename std::result_of<F()>::type, void>::value )
+>
+/*nsel_constexpr14*/
+auto make_expected_from_call( F f ) -> expected< typename std::result_of<F()>::type >
+{
+ try
+ {
+ return make_expected( f() );
+ }
+ catch (...)
+ {
+ return make_unexpected_from_current_exception();
+ }
+}
+
+template< typename F
+ nsel_REQUIRES_T( std::is_same<typename std::result_of<F()>::type, void>::value )
+>
+/*nsel_constexpr14*/
+auto make_expected_from_call( F f ) -> expected<void>
+{
+ try
+ {
+ f();
+ return make_expected();
+ }
+ catch (...)
+ {
+ return make_unexpected_from_current_exception();
+ }
+}
+
+#endif // nsel_P0323R
+
+} // namespace expected_lite
+
+using namespace expected_lite;
+
+// using expected_lite::expected;
+// using ...
+
+} // namespace nonstd
+
+namespace std {
+
+// expected: hash support
+
+template< typename T, typename E >
+struct hash< nonstd::expected<T,E> >
+{
+ using result_type = std::size_t;
+ using argument_type = nonstd::expected<T,E>;
+
+ constexpr result_type operator()(argument_type const & arg) const
+ {
+ return arg ? std::hash<T>{}(*arg) : result_type{};
+ }
+};
+
+// TBD - ?? remove? see spec.
+template< typename T, typename E >
+struct hash< nonstd::expected<T&,E> >
+{
+ using result_type = std::size_t;
+ using argument_type = nonstd::expected<T&,E>;
+
+ constexpr result_type operator()(argument_type const & arg) const
+ {
+ return arg ? std::hash<T>{}(*arg) : result_type{};
+ }
+};
+
+// TBD - implement
+// bool(e), hash<expected<void,E>>()(e) shall evaluate to the hashing true;
+// otherwise it evaluates to an unspecified value if E is exception_ptr or
+// a combination of hashing false and hash<E>()(e.error()).
+
+template< typename E >
+struct hash< nonstd::expected<void,E> >
+{
+};
+
+} // namespace std
+
+namespace nonstd {
+
+// void unexpected() is deprecated && removed in C++17
+
+#if nsel_CPP17_OR_GREATER || nsel_COMPILER_MSVC_VERSION > 141
+template< typename E >
+using unexpected = unexpected_type<E>;
+#endif
+
+} // namespace nonstd
+
+#undef nsel_REQUIRES
+#undef nsel_REQUIRES_0
+#undef nsel_REQUIRES_T
+
+nsel_RESTORE_WARNINGS()
+
+#endif // nsel_USES_STD_EXPECTED
+
+#endif // NONSTD_EXPECTED_LITE_HPP
diff --git a/contrib/restricted/expected-lite/ya.make b/contrib/restricted/expected-lite/ya.make
new file mode 100644
index 0000000000..21762a23a3
--- /dev/null
+++ b/contrib/restricted/expected-lite/ya.make
@@ -0,0 +1,13 @@
+# Generated by devtools/yamaker from nixpkgs 22.11.
+
+LIBRARY()
+
+LICENSE(BSL-1.0)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+VERSION(0.8.0)
+
+ORIGINAL_SOURCE(https://github.com/martinmoene/expected-lite/archive/v0.8.0.tar.gz)
+
+END()