Skip to content

Commit

Permalink
[libc++] Introduce a standalone __scope_guard and use it in <string>
Browse files Browse the repository at this point in the history
  • Loading branch information
philnik777 committed Nov 11, 2024
1 parent 4c4db3c commit 7b015a0
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 12 deletions.
1 change: 1 addition & 0 deletions libcxx/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,7 @@ set(files
__utility/priority_tag.h
__utility/private_constructor_tag.h
__utility/rel_ops.h
__utility/scope_guard.h
__utility/small_buffer.h
__utility/swap.h
__utility/to_underlying.h
Expand Down
1 change: 1 addition & 0 deletions libcxx/include/__flat_map/flat_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
#include <__type_traits/maybe_const.h>
#include <__utility/exception_guard.h>
#include <__utility/pair.h>
#include <__utility/scope_guard.h>
#include <__vector/vector.h>
#include <initializer_list>
#include <stdexcept>
Expand Down
6 changes: 0 additions & 6 deletions libcxx/include/__utility/exception_guard.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __exception_guard<_Rollback> __make_exce
return __exception_guard<_Rollback>(std::move(__rollback));
}

template <class _Rollback>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __exception_guard_exceptions<_Rollback>
__make_scope_guard(_Rollback __rollback) {
return __exception_guard_exceptions<_Rollback>(std::move(__rollback));
}

_LIBCPP_END_NAMESPACE_STD

_LIBCPP_POP_MACROS
Expand Down
60 changes: 60 additions & 0 deletions libcxx/include/__utility/scope_guard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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_SCOPE_GUARD_H
#define _LIBCPP___UTILITY_SCOPE_GUARD_H

#include <__assert>
#include <__config>
#include <__utility/move.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_PUSH_MACROS
#include <__undef_macros>

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _Func>
class __scope_guard {
_Func __func_;
bool __moved_from_;

public:
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR __scope_guard(_Func __func) : __func_(std::move(__func)) {}
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 ~__scope_guard() { __func_(); }

__scope_guard(const __scope_guard&) = delete;

// C++17 has mandatory RVO, so we don't need the move constructor anymore to make __make_scope_guard work.
#if _LIBCPP_STD_VER <= 14
__scope_guard(__scope_guard&& __other) : __func_(__other.__func_) {
_LIBCPP_ASSERT_INTERNAL(!__other.__moved_from_, "Cannot move twice from __scope_guard");
__other.__moved_from_ = true;
}
#else
__scope_guard(__scope_guard&&) = delete;
#endif

__scope_guard& operator=(const __scope_guard&) = delete;
__scope_guard& operator=(__scope_guard&&) = delete;
};

template <class _Func>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __scope_guard<_Func> __make_scope_guard(_Func __func) {
return __scope_guard<_Func>(std::move(__func));
}

_LIBCPP_END_NAMESPACE_STD

_LIBCPP_POP_MACROS

#endif // _LIBCPP___UTILITY_SCOPE_GUARD_H
1 change: 1 addition & 0 deletions libcxx/include/module.modulemap
Original file line number Diff line number Diff line change
Expand Up @@ -2003,6 +2003,7 @@ module std [system] {
module priority_tag { header "__utility/priority_tag.h" }
module private_constructor_tag { header "__utility/private_constructor_tag.h" }
module rel_ops { header "__utility/rel_ops.h" }
module scope_guard { header "__utility/scope_guard.h" }
module small_buffer { header "__utility/small_buffer.h" }
module swap { header "__utility/swap.h" }
module to_underlying { header "__utility/to_underlying.h" }
Expand Down
21 changes: 15 additions & 6 deletions libcxx/include/string
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,7 @@ basic_string<char32_t> operator""s( const char32_t *str, size_t len );
#include <__utility/forward.h>
#include <__utility/is_pointer_in_range.h>
#include <__utility/move.h>
#include <__utility/scope_guard.h>
#include <__utility/swap.h>
#include <__utility/unreachable.h>
#include <climits>
Expand Down Expand Up @@ -929,6 +930,15 @@ private:

_LIBCPP_COMPRESSED_PAIR(__rep, __rep_, allocator_type, __alloc_);

// annotate the string with its size() at scope exit. The string has to be in a valid state at that point.
struct __annotate_new_size {
basic_string& __str_;

_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __annotate_new_size(basic_string& __str) : __str_(__str) {}

_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void operator()() { __str_.__annotate_new(__str_.size()); }
};

// Construct a string with the given allocator and enough storage to hold `__size` characters, but
// don't initialize the characters. The contents of the string, including the null terminator, must be
// initialized separately.
Expand Down Expand Up @@ -2171,6 +2181,7 @@ private:
__alloc_ = __str.__alloc_;
} else {
__annotate_delete();
auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
allocator_type __a = __str.__alloc_;
auto __allocation = std::__allocate_at_least(__a, __str.__get_long_cap());
__begin_lifetime(__allocation.ptr, __allocation.count);
Expand All @@ -2180,7 +2191,6 @@ private:
__set_long_pointer(__allocation.ptr);
__set_long_cap(__allocation.count);
__set_long_size(__str.size());
__annotate_new(__get_long_size());
}
}
}
Expand Down Expand Up @@ -2508,6 +2518,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__
size_type __cap =
__old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1;
__annotate_delete();
auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
auto __allocation = std::__allocate_at_least(__alloc_, __cap + 1);
pointer __p = __allocation.ptr;
__begin_lifetime(__p, __allocation.count);
Expand All @@ -2526,7 +2537,6 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__
__old_sz = __n_copy + __n_add + __sec_cp_sz;
__set_long_size(__old_sz);
traits_type::assign(__p[__old_sz], value_type());
__annotate_new(__old_sz);
}

// __grow_by is deprecated because it does not set the size. It may not update the size when the size is changed, and it
Expand All @@ -2550,7 +2560,6 @@ _LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Trait
pointer __old_p = __get_pointer();
size_type __cap =
__old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1;
__annotate_delete();
auto __allocation = std::__allocate_at_least(__alloc_, __cap + 1);
pointer __p = __allocation.ptr;
__begin_lifetime(__p, __allocation.count);
Expand All @@ -2575,11 +2584,12 @@ basic_string<_CharT, _Traits, _Allocator>::__grow_by_without_replace(
size_type __n_copy,
size_type __n_del,
size_type __n_add) {
__annotate_delete();
auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
__grow_by(__old_cap, __delta_cap, __old_sz, __n_copy, __n_del, __n_add);
_LIBCPP_SUPPRESS_DEPRECATED_POP
__set_long_size(__old_sz - __n_del + __n_add);
__annotate_new(__old_sz - __n_del + __n_add);
}

// assign
Expand Down Expand Up @@ -3364,6 +3374,7 @@ template <class _CharT, class _Traits, class _Allocator>
inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void
basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target_capacity) {
__annotate_delete();
auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
size_type __cap = capacity();
size_type __sz = size();

Expand Down Expand Up @@ -3395,7 +3406,6 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target
// due to swapping the elements.
if (__allocation.count - 1 > __target_capacity) {
__alloc_traits::deallocate(__alloc_, __allocation.ptr, __allocation.count);
__annotate_new(__sz); // Undoes the __annotate_delete()
return;
}
__new_data = __allocation.ptr;
Expand All @@ -3420,7 +3430,6 @@ basic_string<_CharT, _Traits, _Allocator>::__shrink_or_extend(size_type __target
__set_long_pointer(__new_data);
} else
__set_short_size(__sz);
__annotate_new(__sz);
}

template <class _CharT, class _Traits, class _Allocator>
Expand Down

0 comments on commit 7b015a0

Please sign in to comment.