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