Skip to content

Commit b717f83

Browse files
authored
[libc++] Don't use std::allocator inside <any> (#161061)
There isn't much of a reason to use the allocator abstraction facilities inside `<any>`. We can improve compile times a bit by avoiding them and using `__libcpp_{,de}allocate` directly. IMO this also significantly improves readability here.
1 parent f2de174 commit b717f83

File tree

4 files changed

+101
-157
lines changed

4 files changed

+101
-157
lines changed

libcxx/include/any

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,8 @@ namespace std {
8484
# include <__cxx03/__config>
8585
#else
8686
# include <__config>
87-
# include <__memory/allocator.h>
88-
# include <__memory/allocator_destructor.h>
89-
# include <__memory/allocator_traits.h>
90-
# include <__memory/unique_ptr.h>
87+
# include <__memory/construct_at.h>
88+
# include <__new/allocate.h>
9189
# include <__type_traits/add_cv_quals.h>
9290
# include <__type_traits/add_pointer.h>
9391
# include <__type_traits/aligned_storage.h>
@@ -103,6 +101,7 @@ namespace std {
103101
# include <__type_traits/remove_cv.h>
104102
# include <__type_traits/remove_cvref.h>
105103
# include <__type_traits/remove_reference.h>
104+
# include <__utility/exception_guard.h>
106105
# include <__utility/forward.h>
107106
# include <__utility/in_place.h>
108107
# include <__utility/move.h>
@@ -339,22 +338,14 @@ struct _SmallHandler {
339338

340339
template <class... _Args>
341340
_LIBCPP_HIDE_FROM_ABI static _Tp& __create(any& __dest, _Args&&... __args) {
342-
typedef allocator<_Tp> _Alloc;
343-
typedef allocator_traits<_Alloc> _ATraits;
344-
_Alloc __a;
345-
_Tp* __ret = static_cast<_Tp*>(static_cast<void*>(&__dest.__s_.__buf));
346-
_ATraits::construct(__a, __ret, std::forward<_Args>(__args)...);
341+
auto __ret = std::__construct_at(reinterpret_cast<_Tp*>(&__dest.__s_.__buf), std::forward<_Args>(__args)...);
347342
__dest.__h_ = &_SmallHandler::__handle;
348343
return *__ret;
349344
}
350345

351346
private:
352347
_LIBCPP_HIDE_FROM_ABI static void __destroy(any& __this) {
353-
typedef allocator<_Tp> _Alloc;
354-
typedef allocator_traits<_Alloc> _ATraits;
355-
_Alloc __a;
356-
_Tp* __p = static_cast<_Tp*>(static_cast<void*>(&__this.__s_.__buf));
357-
_ATraits::destroy(__a, __p);
348+
std::__destroy_at(reinterpret_cast<_Tp*>(&__this.__s_.__buf));
358349
__this.__h_ = nullptr;
359350
}
360351

@@ -406,26 +397,20 @@ struct _LargeHandler {
406397

407398
template <class... _Args>
408399
_LIBCPP_HIDE_FROM_ABI static _Tp& __create(any& __dest, _Args&&... __args) {
409-
typedef allocator<_Tp> _Alloc;
410-
typedef allocator_traits<_Alloc> _ATraits;
411-
typedef __allocator_destructor<_Alloc> _Dp;
412-
_Alloc __a;
413-
unique_ptr<_Tp, _Dp> __hold(_ATraits::allocate(__a, 1), _Dp(__a, 1));
414-
_Tp* __ret = __hold.get();
415-
_ATraits::construct(__a, __ret, std::forward<_Args>(__args)...);
416-
__dest.__s_.__ptr = __hold.release();
400+
_Tp* __ptr = static_cast<_Tp*>(std::__libcpp_allocate<_Tp>(__element_count(1)));
401+
std::__exception_guard __guard([&] { std::__libcpp_deallocate<_Tp>(__ptr, __element_count(1)); });
402+
std::__construct_at(__ptr, std::forward<_Args>(__args)...);
403+
__guard.__complete();
404+
__dest.__s_.__ptr = __ptr;
417405
__dest.__h_ = &_LargeHandler::__handle;
418-
return *__ret;
406+
return *__ptr;
419407
}
420408

421409
private:
422410
_LIBCPP_HIDE_FROM_ABI static void __destroy(any& __this) {
423-
typedef allocator<_Tp> _Alloc;
424-
typedef allocator_traits<_Alloc> _ATraits;
425-
_Alloc __a;
426411
_Tp* __p = static_cast<_Tp*>(__this.__s_.__ptr);
427-
_ATraits::destroy(__a, __p);
428-
_ATraits::deallocate(__a, __p, 1);
412+
std::__destroy_at(__p);
413+
std::__libcpp_deallocate<_Tp>(__p, __element_count(1));
429414
__this.__h_ = nullptr;
430415
}
431416

@@ -613,6 +598,11 @@ _LIBCPP_POP_MACROS
613598
# include <type_traits>
614599
# include <variant>
615600
# endif
601+
602+
# if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 23
603+
# include <cstring>
604+
# include <limits>
605+
# endif
616606
#endif // __cplusplus < 201103L && defined(_LIBCPP_USE_FROZEN_CXX03_HEADERS)
617607

618608
#endif // _LIBCPP_ANY

libcxx/test/libcxx/transitive_includes/cxx26.csv

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ algorithm ratio
1414
algorithm tuple
1515
algorithm version
1616
any cstdint
17-
any cstring
1817
any initializer_list
19-
any limits
2018
any typeinfo
2119
any version
2220
array cctype

libcxx/test/libcxx/utilities/any/allocator.pass.cpp

Lines changed: 0 additions & 127 deletions
This file was deleted.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
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+
// UNSUPPORTED: c++03, c++11, c++14
10+
11+
// <any>
12+
13+
// Check that we're consistently using the same allocation functions to
14+
// allocate/deallocate/construct/destroy objects in std::any.
15+
// See https://llvm.org/PR45099 for details.
16+
17+
#include <any>
18+
#include <cassert>
19+
#include <cstddef>
20+
#include <new>
21+
22+
// Make sure we don't fit in std::any's SBO
23+
int allocated_count = 0;
24+
int constructed_count = 0;
25+
26+
struct Large {
27+
Large() { ++constructed_count; }
28+
29+
Large(const Large&) { ++constructed_count; }
30+
31+
~Large() { --constructed_count; }
32+
33+
char big[sizeof(std::any) + 1];
34+
35+
static void* operator new(size_t n) {
36+
++allocated_count;
37+
return ::operator new(n);
38+
}
39+
40+
static void operator delete(void* ptr) {
41+
--allocated_count;
42+
::operator delete(ptr);
43+
}
44+
};
45+
46+
// Make sure we fit in std::any's SBO
47+
struct Small {
48+
Small() { ++constructed_count; }
49+
50+
Small(const Small&) { ++constructed_count; }
51+
52+
~Small() { --constructed_count; }
53+
54+
static void* operator new(size_t n) {
55+
++allocated_count;
56+
return ::operator new(n);
57+
}
58+
59+
static void operator delete(void* ptr) {
60+
--allocated_count;
61+
::operator delete(ptr);
62+
}
63+
};
64+
65+
int main(int, char**) {
66+
// Test large types
67+
{
68+
[[maybe_unused]] std::any a = Large();
69+
assert(constructed_count == 1);
70+
}
71+
assert(allocated_count == 0);
72+
assert(constructed_count == 0);
73+
74+
// Test small types
75+
{
76+
[[maybe_unused]] std::any a = Small();
77+
assert(constructed_count == 1);
78+
}
79+
assert(allocated_count == 0);
80+
assert(constructed_count == 0);
81+
82+
return 0;
83+
}

0 commit comments

Comments
 (0)