diff options
author | snaury <snaury@yandex-team.com> | 2024-10-16 12:16:48 +0300 |
---|---|---|
committer | snaury <snaury@yandex-team.com> | 2024-10-16 12:32:13 +0300 |
commit | e0fb25470a47f0c243091ed28bf54a186f732f6a (patch) | |
tree | e85dfe628401f4f21749ab95b9d711242e3b49cd /contrib/restricted | |
parent | b3b4a0b9681eb0981f9958a426c95a53f79169a7 (diff) | |
download | ydb-e0fb25470a47f0c243091ed28bf54a186f732f6a.tar.gz |
ydblib: add jinja2cpp
commit_hash:f3563041f6f6f7443e75fc99acd2c967d0debb04
Diffstat (limited to 'contrib/restricted')
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, ¶ms, 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, ¶ms, 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, ¶ms, &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, ¶ms, &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 = ©_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, ©_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, ©_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 = ©_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, ¶ms, &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, ¶ms, &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::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::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<typename T, typename E = std::exception_ptr><br>class **expected**; | nsel_P0323 <= 2 | +| Expected | template<typename T, typename E><br>class **expected**; | nsel_P0323 > 2 | +| Error type | template<typename E><br>class **unexpected_type**; | | +| Error type | template<><br>class **unexpected_type**<std::exception_ptr>; | nsel_P0323 <= 2 | +| Error type | template<typename E><br>class **unexpected**; | >= C++17 | +| Traits | template<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**; | | + +### Interface of expected + +| Kind | Method | Result | +|--------------|-------------------------------------------------------------------------|--------| +| Construction | [constexpr] **expected**() noexcept(...) | an object with default value | +| | [constexpr] **expected**( expected const & other ) | initialize to contents of other | +| | [constexpr] **expected**( expected && other ) | move contents from other | +| | [constexpr] **expected**( value_type const & value ) | initialize to value | +| | [constexpr] **expected**( value_type && value ) noexcept(...) | move from value | +| | [constexpr] explicit **expected**( in_place_t, Args&&... args ) | construct value in-place from args | +| | [constexpr] explicit **expected**( in_place_t,<br> std::initializer_list<U> il, Args&&... args ) | construct value in-place from args | +| | [constexpr] **expected**( unexpected_type<E> const & error ) | initialize to error | +| | [constexpr] **expected**( unexpected_type<E> && error ) | move from error | +| | [constexpr] explicit **expected**( in_place_unexpected_t,<br> Args&&... args ) | construct error in-place from args | +| | [constexpr] explicit **expected**( in_place_unexpected_t,<br> std::initializer_list<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 | +| | expected & **operator=**( expected && other ) noexcept(...) | move contents of other | +| | expected & **operator=**( U && v ) | move value from v | +| | expected & **operator=**( unexpected_type<E> const & u ) | initialize to unexpected | +| | expected & **operator=**( unexpected_type<E> && u ) | move from unexpected | +| | template<typename... Args><br>void **emplace**( Args &&... args ) | emplace from args | +| | template<typename U, typename... Args><br>void **emplace**( std::initializer_list<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 | +| | value_type \* **operator->**() | pointer to current content (non-const);<br>must contain value | +| | constexpr value_type const & **operator \***() const & | the current content (const ref);<br>must contain value | +| | constexpr value_type && **operator \***() && | the current content (non-const ref);<br>must contain value | +| | constexpr explicit operator **bool**() const noexcept | true if contains value | +| | constexpr **has_value**() const noexcept | true if contains value | +| | constexpr value_type const & **value**() const & | current content (const ref);<br>see [note 1](#note1) | +| | value_type & **value**() & | current content (non-const ref);<br>see [note 1](#note1) | +| | constexpr value_type && **value**() && | move from current content;<br>see [note 1](#note1) | +| | constexpr error_type const & **error**() const & | current error (const ref);<br>must contain error | +| | error_type & **error**() & | current error (non-const ref);<br>must contain error | +| | constexpr error_type && **error**() && | move from current error;<br>must contain error | +| | constexpr unexpected_type<E> **get_unexpected**() const | the error as unexpected<>;<br>must contain error | +| | template<typename Ex><br>bool **has_exception**() const | true of contains exception (as base) | +| | value_type **value_or**( U && v ) const & | value or move from v | +| | value_type **value_or**( U && v ) && | move from value or move from v | +| | constexpr error_type **error_or**( G && e ) const & | return current error or v [requires nsel_P2505R >= 4] | +| | 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 | +| | constexpr auto **and_then**( F && f ) const & | return f(value()) if has value, otherwise the error | +| | constexpr auto **and_then**( F && f ) && | return f(std::move(value())) if has value, otherwise the error | +| | constexpr auto **and_then**( F && f ) const && | return f(std::move(value())) if has value, otherwise the error | +| | constexpr auto **or_else**( F && f ) & | return the value, or f(error()) if there is no value | +| | constexpr auto **or_else**( F && f ) const & | return the value, or f(error()) if there is no value | +| | constexpr auto **or_else**( F && f ) && | return the value, or f(std::move(error())) if there is no value | +| | constexpr auto **or_else**( F && f ) const && | return the value, or f(std::move(error())) if there is no value | +| | constexpr auto **transform**( F && f ) & | return f(value()) wrapped if has value, otherwise the error | +| | constexpr auto **transform**( F && f ) const & | return f(value()) wrapped if has value, otherwise the error | +| | constexpr auto **transform**( F && f ) && | return f(std::move(value())) wrapped if has value, otherwise the error | +| | constexpr auto **transform**( F && f ) const && | return f(std::move(value())) wrapped if has value, otherwise the error | +| | constexpr auto **transform_error**( F && f ) & | return the value if has value, or f(error()) otherwise | +| | constexpr auto **transform_error**( F && f ) const & | return the value if has value, or f(error()) otherwise | +| | constexpr auto **transform_error**( F && f ) && | return the value if has value, or f(std::move(error())) otherwise | +| | constexpr auto **transform_error**( F && f ) const && | return the value if has value, or f(std::move(error())) otherwise | +| | ... | | + +<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 | | +| == != | template<typename T1, typename E1, typename T2, typename E2><br>constexpr bool operator ***op***(<br> expected<T1,E1> const & x,<br> expected<T2,E2> const & y ) | +| Comparison with expected | nsel_P0323R <= 2 | +| < > <= >= | template<typename T, typename E><br>constexpr bool operator ***op***(<br> expected<T,E> const & x,<br> expected<T,E> const & y ) | +| Comparison with unexpected_type | | +| == != | template<typename T1, typename E1, typename E2><br>constexpr bool operator ***op***(<br> expected<T1,E1> const & x,<br> unexpected_type<E2> const & u ) | +| | template<typename T1, typename E1, typename E2><br>constexpr bool operator ***op***(<br> unexpected_type<E2> const & u,<br> expected<T1,E1> const & x ) | +| Comparison with unexpected_type | nsel_P0323R <= 2 | +| < > <= >= | template<typename T, typename E><br>constexpr bool operator ***op***(<br> expected<T,E> const & x,<br> unexpected_type<E> const & u ) | +| | template<typename T, typename E><br>constexpr bool operator ***op***(<br> unexpected_type<E> const & u,<br> expected<T,E> const & x ) | +| Comparison with T | | +| == != | template<typename T, typename E><br>constexpr bool operator ***op***(<br> expected<T,E> const & x,<br> T const & v ) | +| | template<typename T, typename E><br>constexpr bool operator ***op***(<br> T const & v,<br> expected<T,E> const & x ) | +| Comparison with T | nsel_P0323R <= 2 | +| < > <= >= | template<typename T, typename E><br>constexpr bool operator ***op***(<br> expected<T,E> const & x,<br> T const & v ) | +| | template<typename T, typename E><br>constexpr bool operator ***op***(<br> T const & v,<br> expected<T,E> const & x ) | +| Specialized algorithms | | +| Swap | template<typename T, typename E><br>void **swap**(<br> expected<T,E> & x,<br> expected<T,E> & y ) noexcept( noexcept( x.swap(y) ) ) | +| Make expected from | nsel_P0323R <= 3 | +|  Value | template<typename T><br>constexpr auto **make_expected**( T && v ) -><br> expected< typename std::decay<T>::type> | +|  Nothing | auto **make_expected**() -> expected<void> | +|  Current exception | template<typename T><br>constexpr auto **make_expected_from_current_exception**() -> expected<T> | +|  Exception | template<typename T><br>auto **make_expected_from_exception**( std::exception_ptr v ) -> expected<T>| +|  Error | template<typename T, typename E><br>constexpr auto **make_expected_from_error**( E e ) -><br> expected<T, typename std::decay<E>::type> | +|  Call | template<typename F><br>auto **make_expected_from_call**( F f ) -><br> expected< typename std::result_of<F()>::type>| +|  Call, void specialization | template<typename F><br>auto **make_expected_from_call**( F f ) -> expected<void> | + +### Interface of unexpected_type + +| Kind | Method | Result | +|--------------|-----------------------------------------------------------|--------| +| Construction | **unexpected_type**() = delete; | no default construction | +| | constexpr explicit **unexpected_type**( E const & error ) | copy-constructed from an E | +| | constexpr explicit **unexpected_type**( E && error ) | move-constructed from an E | +| Observers | constexpr error_type const & **error**() const | can observe contained error | +| | 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 | | +| == != | template<typename E><br>constexpr bool operator ***op***(<br> unexpected_type<E> const & x,<br> unexpected_type<E> const & y ) | +| Comparison with unexpected | nsel_P0323R <= 2 | +| < > <= >= | template<typename E><br>constexpr bool operator ***op***(<br> unexpected_type<E> const & x,<br> unexpected_type<E> const & y ) | +| Comparison with exception_ptr | | +| == != | constexpr bool operator ***op***(<br> unexpected_type<std::exception_ptr> const & x,<br> unexpected_type<std::exception_ptr> const & y ) | +| Comparison with exception_ptr | nsel_P0323R <= 2 | +| < > <= >= | constexpr bool operator ***op***(<br> unexpected_type<std::exception_ptr> const & x,<br> unexpected_type<std::exception_ptr> const & y ) | +| Specialized algorithms | | +| Make unexpected from | | +|  Error | template<typename E><br>[constexpr] auto **make_unexpected**( E && v) -><br> unexpected_type< typename std::decay<E>::type>| +| Make unexpected from | nsel_P0323R <= 3 | +|  Current exception | [constexpr] auto **make_unexpected_from_current_exception**() -><br> 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::*experimental*::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<T> and result<T> (non-Boost edition). + +[16] Niall Douglas. [p0762 - Concerns about expected<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() |