1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef _LIBCPP___UTILITY_TRANSACTION_H
10 #define _LIBCPP___UTILITY_TRANSACTION_H
11 
12 #include <__config>
13 #include <__utility/exchange.h>
14 #include <__utility/move.h>
15 #include <type_traits>
16 
17 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
18 #  pragma GCC system_header
19 #endif
20 
21 _LIBCPP_BEGIN_NAMESPACE_STD
22 
23 // __transaction is a helper class for writing code with the strong exception guarantee.
24 //
25 // When writing code that can throw an exception, one can store rollback instructions in a
26 // transaction so that if an exception is thrown at any point during the lifetime of the
27 // transaction, it will be rolled back automatically. When the transaction is done, one
28 // must mark it as being complete so it isn't rolled back when the transaction is destroyed.
29 //
30 // Transactions are not default constructible, they can't be copied or assigned to, but
31 // they can be moved around for convenience.
32 //
33 // __transaction can help greatly simplify code that would normally be cluttered by
34 // `#if _LIBCPP_NO_EXCEPTIONS`. For example:
35 //
36 //    template <class Iterator, class Size, class OutputIterator>
37 //    Iterator uninitialized_copy_n(Iterator iter, Size n, OutputIterator out) {
38 //        typedef typename iterator_traits<Iterator>::value_type value_type;
39 //        __transaction transaction([start=out, &out] {
40 //            std::destroy(start, out);
41 //        });
42 //
43 //        for (; n > 0; ++iter, ++out, --n) {
44 //            ::new ((void*)std::addressof(*out)) value_type(*iter);
45 //        }
46 //        transaction.__complete();
47 //        return out;
48 //    }
49 //
50 template <class _Rollback>
51 struct __transaction {
52     __transaction() = delete;
53 
54     _LIBCPP_HIDE_FROM_ABI
__transaction__transaction55     _LIBCPP_CONSTEXPR_AFTER_CXX17 explicit __transaction(_Rollback __rollback)
56         : __rollback_(_VSTD::move(__rollback))
57         , __completed_(false)
58     { }
59 
60     _LIBCPP_HIDE_FROM_ABI
__transaction__transaction61     _LIBCPP_CONSTEXPR_AFTER_CXX17 __transaction(__transaction&& __other)
62         _NOEXCEPT_(is_nothrow_move_constructible<_Rollback>::value)
63         : __rollback_(_VSTD::move(__other.__rollback_))
64         , __completed_(__other.__completed_)
65     {
66         __other.__completed_ = true;
67     }
68 
69     __transaction(__transaction const&) = delete;
70     __transaction& operator=(__transaction const&) = delete;
71     __transaction& operator=(__transaction&&) = delete;
72 
73     _LIBCPP_HIDE_FROM_ABI
__complete__transaction74     _LIBCPP_CONSTEXPR_AFTER_CXX17 void __complete() _NOEXCEPT {
75         __completed_ = true;
76     }
77 
78     _LIBCPP_HIDE_FROM_ABI
~__transaction__transaction79     _LIBCPP_CONSTEXPR_AFTER_CXX17 ~__transaction() {
80         if (!__completed_)
81             __rollback_();
82     }
83 
84 private:
85     _Rollback __rollback_;
86     bool __completed_;
87 };
88 
89 template <class _Rollback>
__make_transaction(_Rollback __rollback)90 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __transaction<_Rollback> __make_transaction(_Rollback __rollback) {
91   return __transaction<_Rollback>(std::move(__rollback));
92 }
93 
94 _LIBCPP_END_NAMESPACE_STD
95 
96 #endif // _LIBCPP___UTILITY_TRANSACTION_H
97