[libc++] Add a helper class to write code with the strong exception guarantee

__transaction is a helper class that allows rolling back code in case an
exception is thrown. The main goal is to reduce the clutter when code
needs to be guarded with `#if _LIBCPP_NO_EXCEPTIONS`.

Differential Revision: https://reviews.llvm.org/D115730

NOKEYCHECK=True
GitOrigin-RevId: 37e6bd8bc8da29ad485547a683c6685254d4011d
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index e0801c7..f7e459b 100644
--- a/include/CMakeLists.txt
+++ b/include/CMakeLists.txt
@@ -358,6 +358,7 @@
   __utility/rel_ops.h
   __utility/swap.h
   __utility/to_underlying.h
+  __utility/transaction.h
   __variant/monostate.h
   algorithm
   any
diff --git a/include/__utility/transaction.h b/include/__utility/transaction.h
new file mode 100644
index 0000000..5bc3a50
--- /dev/null
+++ b/include/__utility/transaction.h
@@ -0,0 +1,91 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___UTILITY_TRANSACTION_H
+#define _LIBCPP___UTILITY_TRANSACTION_H
+
+#include <__config>
+#include <__utility/exchange.h>
+#include <__utility/move.h>
+#include <type_traits>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// __transaction is a helper class for writing code with the strong exception guarantee.
+//
+// When writing code that can throw an exception, one can store rollback instructions in a
+// transaction so that if an exception is thrown at any point during the lifetime of the
+// transaction, it will be rolled back automatically. When the transaction is done, one
+// must mark it as being complete so it isn't rolled back when the transaction is destroyed.
+//
+// Transactions are not default constructible, they can't be copied or assigned to, but
+// they can be moved around for convenience.
+//
+// __transaction can help greatly simplify code that would normally be cluttered by
+// `#if _LIBCPP_NO_EXCEPTIONS`. For example:
+//
+//    template <class Iterator, class Size, class OutputIterator>
+//    Iterator uninitialized_copy_n(Iterator iter, Size n, OutputIterator out) {
+//        typedef typename iterator_traits<Iterator>::value_type value_type;
+//        __transaction transaction([start=out, &out] {
+//            std::destroy(start, out);
+//        });
+//
+//        for (; n > 0; ++iter, ++out, --n) {
+//            ::new ((void*)std::addressof(*out)) value_type(*iter);
+//        }
+//        transaction.__complete();
+//        return out;
+//    }
+//
+template <class _Rollback>
+struct __transaction {
+    __transaction() = delete;
+
+    _LIBCPP_HIDE_FROM_ABI
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 explicit __transaction(_Rollback __rollback)
+        : __rollback_(_VSTD::move(__rollback))
+        , __completed_(false)
+    { }
+
+    _LIBCPP_HIDE_FROM_ABI
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 __transaction(__transaction&& __other)
+        _NOEXCEPT_(is_nothrow_move_constructible<_Rollback>::value)
+        : __rollback_(_VSTD::move(__other.__rollback_))
+        , __completed_(__other.__completed_)
+    {
+        __other.__completed_ = true;
+    }
+
+    __transaction(__transaction const&) = delete;
+    __transaction& operator=(__transaction const&) = delete;
+    __transaction& operator=(__transaction&&) = delete;
+
+    _LIBCPP_HIDE_FROM_ABI
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 void __complete() _NOEXCEPT {
+        __completed_ = true;
+    }
+
+    _LIBCPP_HIDE_FROM_ABI
+    _LIBCPP_CONSTEXPR_AFTER_CXX17 ~__transaction() {
+        if (!__completed_)
+            __rollback_();
+    }
+
+private:
+    _Rollback __rollback_;
+    bool __completed_;
+};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___UTILITY_TRANSACTION_H
diff --git a/include/module.modulemap b/include/module.modulemap
index 12e0a15..fa4170b 100644
--- a/include/module.modulemap
+++ b/include/module.modulemap
@@ -916,6 +916,7 @@
       module rel_ops             { private header "__utility/rel_ops.h" }
       module swap                { private header "__utility/swap.h" }
       module to_underlying       { private header "__utility/to_underlying.h" }
+      module transaction         { private header "__utility/transaction.h" }
     }
   }
   module valarray {
diff --git a/include/utility b/include/utility
index ac8470e..9ab7b8e 100644
--- a/include/utility
+++ b/include/utility
@@ -231,6 +231,7 @@
 #include <__utility/rel_ops.h>
 #include <__utility/swap.h>
 #include <__utility/to_underlying.h>
+#include <__utility/transaction.h>
 #include <compare>
 #include <initializer_list>
 #include <version>