Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / test / support / count_new.h
blobb6424850101625be84cfafc3f7ac39d0a4925ada
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 //===----------------------------------------------------------------------===//
9 #ifndef COUNT_NEW_H
10 #define COUNT_NEW_H
12 #include <algorithm>
13 #include <cassert>
14 #include <cerrno>
15 #include <cstdlib>
16 #include <new>
17 #include <type_traits>
19 #include "test_macros.h"
21 #if defined(TEST_HAS_SANITIZERS)
22 #define DISABLE_NEW_COUNT
23 #endif
25 namespace detail
27 TEST_NORETURN
28 inline void throw_bad_alloc_helper() {
29 #ifndef TEST_HAS_NO_EXCEPTIONS
30 throw std::bad_alloc();
31 #else
32 std::abort();
33 #endif
37 class MemCounter
39 public:
40 // Make MemCounter super hard to accidentally construct or copy.
41 class MemCounterCtorArg_ {};
42 explicit MemCounter(MemCounterCtorArg_) { reset(); }
44 private:
45 MemCounter(MemCounter const &);
46 MemCounter & operator=(MemCounter const &);
48 public:
49 // All checks return true when disable_checking is enabled.
50 static const bool disable_checking;
52 // Disallow any allocations from occurring. Useful for testing that
53 // code doesn't perform any allocations.
54 bool disable_allocations;
56 // number of allocations to throw after. Default (unsigned)-1. If
57 // throw_after has the default value it will never be decremented.
58 static const unsigned never_throw_value = static_cast<unsigned>(-1);
59 unsigned throw_after;
61 int outstanding_new;
62 int new_called;
63 int delete_called;
64 int aligned_new_called;
65 int aligned_delete_called;
66 std::size_t last_new_size;
67 std::size_t last_new_align;
68 std::size_t last_delete_align;
70 int outstanding_array_new;
71 int new_array_called;
72 int delete_array_called;
73 int aligned_new_array_called;
74 int aligned_delete_array_called;
75 std::size_t last_new_array_size;
76 std::size_t last_new_array_align;
77 std::size_t last_delete_array_align;
79 public:
80 void newCalled(std::size_t s)
82 assert(disable_allocations == false);
83 if (throw_after == 0) {
84 throw_after = never_throw_value;
85 detail::throw_bad_alloc_helper();
86 } else if (throw_after != never_throw_value) {
87 --throw_after;
89 ++new_called;
90 ++outstanding_new;
91 last_new_size = s;
94 void alignedNewCalled(std::size_t s, std::size_t a) {
95 newCalled(s);
96 ++aligned_new_called;
97 last_new_align = a;
100 void deleteCalled(void * p)
102 assert(p);
103 --outstanding_new;
104 ++delete_called;
107 void alignedDeleteCalled(void *p, std::size_t a) {
108 deleteCalled(p);
109 ++aligned_delete_called;
110 last_delete_align = a;
113 void newArrayCalled(std::size_t s)
115 assert(disable_allocations == false);
116 if (throw_after == 0) {
117 throw_after = never_throw_value;
118 detail::throw_bad_alloc_helper();
119 } else {
120 // don't decrement throw_after here. newCalled will end up doing that.
122 ++outstanding_array_new;
123 ++new_array_called;
124 last_new_array_size = s;
127 void alignedNewArrayCalled(std::size_t s, std::size_t a) {
128 newArrayCalled(s);
129 ++aligned_new_array_called;
130 last_new_array_align = a;
133 void deleteArrayCalled(void * p)
135 assert(p);
136 --outstanding_array_new;
137 ++delete_array_called;
140 void alignedDeleteArrayCalled(void * p, std::size_t a) {
141 deleteArrayCalled(p);
142 ++aligned_delete_array_called;
143 last_delete_array_align = a;
146 void disableAllocations()
148 disable_allocations = true;
151 void enableAllocations()
153 disable_allocations = false;
156 void reset()
158 disable_allocations = false;
159 throw_after = never_throw_value;
161 outstanding_new = 0;
162 new_called = 0;
163 delete_called = 0;
164 aligned_new_called = 0;
165 aligned_delete_called = 0;
166 last_new_size = 0;
167 last_new_align = 0;
169 outstanding_array_new = 0;
170 new_array_called = 0;
171 delete_array_called = 0;
172 aligned_new_array_called = 0;
173 aligned_delete_array_called = 0;
174 last_new_array_size = 0;
175 last_new_array_align = 0;
178 public:
179 bool checkOutstandingNewEq(int n) const
181 return disable_checking || n == outstanding_new;
184 bool checkOutstandingNewNotEq(int n) const
186 return disable_checking || n != outstanding_new;
189 bool checkNewCalledEq(int n) const
191 return disable_checking || n == new_called;
194 bool checkNewCalledNotEq(int n) const
196 return disable_checking || n != new_called;
199 bool checkNewCalledGreaterThan(int n) const
201 return disable_checking || new_called > n;
204 bool checkDeleteCalledEq(int n) const
206 return disable_checking || n == delete_called;
209 bool checkDeleteCalledNotEq(int n) const
211 return disable_checking || n != delete_called;
214 bool checkDeleteCalledGreaterThan(int n) const
216 return disable_checking || delete_called > n;
219 bool checkAlignedNewCalledEq(int n) const
221 return disable_checking || n == aligned_new_called;
224 bool checkAlignedNewCalledNotEq(int n) const
226 return disable_checking || n != aligned_new_called;
229 bool checkAlignedNewCalledGreaterThan(int n) const
231 return disable_checking || aligned_new_called > n;
234 bool checkAlignedDeleteCalledEq(int n) const
236 return disable_checking || n == aligned_delete_called;
239 bool checkAlignedDeleteCalledNotEq(int n) const
241 return disable_checking || n != aligned_delete_called;
244 bool checkLastNewSizeEq(std::size_t n) const
246 return disable_checking || n == last_new_size;
249 bool checkLastNewSizeNotEq(std::size_t n) const
251 return disable_checking || n != last_new_size;
254 bool checkLastNewSizeGe(std::size_t n) const
256 return disable_checking || last_new_size >= n;
259 bool checkLastNewAlignEq(std::size_t n) const
261 return disable_checking || n == last_new_align;
264 bool checkLastNewAlignNotEq(std::size_t n) const
266 return disable_checking || n != last_new_align;
269 bool checkLastNewAlignGe(std::size_t n) const
271 return disable_checking || last_new_align >= n;
274 bool checkLastDeleteAlignEq(std::size_t n) const
276 return disable_checking || n == last_delete_align;
279 bool checkLastDeleteAlignNotEq(std::size_t n) const
281 return disable_checking || n != last_delete_align;
284 bool checkOutstandingArrayNewEq(int n) const
286 return disable_checking || n == outstanding_array_new;
289 bool checkOutstandingArrayNewNotEq(int n) const
291 return disable_checking || n != outstanding_array_new;
294 bool checkNewArrayCalledEq(int n) const
296 return disable_checking || n == new_array_called;
299 bool checkNewArrayCalledNotEq(int n) const
301 return disable_checking || n != new_array_called;
304 bool checkDeleteArrayCalledEq(int n) const
306 return disable_checking || n == delete_array_called;
309 bool checkDeleteArrayCalledNotEq(int n) const
311 return disable_checking || n != delete_array_called;
314 bool checkAlignedNewArrayCalledEq(int n) const
316 return disable_checking || n == aligned_new_array_called;
319 bool checkAlignedNewArrayCalledNotEq(int n) const
321 return disable_checking || n != aligned_new_array_called;
324 bool checkAlignedNewArrayCalledGreaterThan(int n) const
326 return disable_checking || aligned_new_array_called > n;
329 bool checkAlignedDeleteArrayCalledEq(int n) const
331 return disable_checking || n == aligned_delete_array_called;
334 bool checkAlignedDeleteArrayCalledNotEq(int n) const
336 return disable_checking || n != aligned_delete_array_called;
339 bool checkLastNewArraySizeEq(std::size_t n) const
341 return disable_checking || n == last_new_array_size;
344 bool checkLastNewArraySizeNotEq(std::size_t n) const
346 return disable_checking || n != last_new_array_size;
349 bool checkLastNewArrayAlignEq(std::size_t n) const
351 return disable_checking || n == last_new_array_align;
354 bool checkLastNewArrayAlignNotEq(std::size_t n) const
356 return disable_checking || n != last_new_array_align;
360 #ifdef DISABLE_NEW_COUNT
361 const bool MemCounter::disable_checking = true;
362 #else
363 const bool MemCounter::disable_checking = false;
364 #endif
366 TEST_DIAGNOSTIC_PUSH
367 TEST_MSVC_DIAGNOSTIC_IGNORED(4640) // '%s' construction of local static object is not thread safe (/Zc:threadSafeInit-)
368 inline MemCounter* getGlobalMemCounter() {
369 static MemCounter counter((MemCounter::MemCounterCtorArg_()));
370 return &counter;
372 TEST_DIAGNOSTIC_POP
374 MemCounter &globalMemCounter = *getGlobalMemCounter();
376 #ifndef DISABLE_NEW_COUNT
377 void* operator new(std::size_t s) TEST_THROW_SPEC(std::bad_alloc)
379 getGlobalMemCounter()->newCalled(s);
380 void* ret = std::malloc(s);
381 if (ret == nullptr)
382 detail::throw_bad_alloc_helper();
383 return ret;
386 void operator delete(void* p) TEST_NOEXCEPT
388 getGlobalMemCounter()->deleteCalled(p);
389 std::free(p);
392 void* operator new[](std::size_t s) TEST_THROW_SPEC(std::bad_alloc)
394 getGlobalMemCounter()->newArrayCalled(s);
395 return operator new(s);
398 void operator delete[](void* p) TEST_NOEXCEPT
400 getGlobalMemCounter()->deleteArrayCalled(p);
401 operator delete(p);
404 #ifndef TEST_HAS_NO_ALIGNED_ALLOCATION
405 #if defined(_LIBCPP_MSVCRT_LIKE) || \
406 (!defined(_LIBCPP_VERSION) && defined(_WIN32))
407 #define USE_ALIGNED_ALLOC
408 #endif
410 void* operator new(std::size_t s, std::align_val_t av) TEST_THROW_SPEC(std::bad_alloc) {
411 const std::size_t a = static_cast<std::size_t>(av);
412 getGlobalMemCounter()->alignedNewCalled(s, a);
413 void *ret = nullptr;
414 #ifdef USE_ALIGNED_ALLOC
415 ret = _aligned_malloc(s, a);
416 #else
417 assert(posix_memalign(&ret, std::max(a, sizeof(void*)), s) != EINVAL);
418 #endif
419 if (ret == nullptr)
420 detail::throw_bad_alloc_helper();
421 return ret;
424 void operator delete(void *p, std::align_val_t av) TEST_NOEXCEPT {
425 const std::size_t a = static_cast<std::size_t>(av);
426 getGlobalMemCounter()->alignedDeleteCalled(p, a);
427 if (p) {
428 #ifdef USE_ALIGNED_ALLOC
429 ::_aligned_free(p);
430 #else
431 ::free(p);
432 #endif
436 void* operator new[](std::size_t s, std::align_val_t av) TEST_THROW_SPEC(std::bad_alloc) {
437 const std::size_t a = static_cast<std::size_t>(av);
438 getGlobalMemCounter()->alignedNewArrayCalled(s, a);
439 return operator new(s, av);
442 void operator delete[](void *p, std::align_val_t av) TEST_NOEXCEPT {
443 const std::size_t a = static_cast<std::size_t>(av);
444 getGlobalMemCounter()->alignedDeleteArrayCalled(p, a);
445 return operator delete(p, av);
448 #endif // TEST_HAS_NO_ALIGNED_ALLOCATION
450 #endif // DISABLE_NEW_COUNT
452 struct DisableAllocationGuard {
453 explicit DisableAllocationGuard(bool disable = true) : m_disabled(disable)
455 // Don't re-disable if already disabled.
456 if (globalMemCounter.disable_allocations == true) m_disabled = false;
457 if (m_disabled) globalMemCounter.disableAllocations();
460 void release() {
461 if (m_disabled) globalMemCounter.enableAllocations();
462 m_disabled = false;
465 ~DisableAllocationGuard() {
466 release();
469 private:
470 bool m_disabled;
472 DisableAllocationGuard(DisableAllocationGuard const&);
473 DisableAllocationGuard& operator=(DisableAllocationGuard const&);
476 #if TEST_STD_VER >= 20
478 struct ConstexprDisableAllocationGuard {
479 TEST_CONSTEXPR_CXX14 explicit ConstexprDisableAllocationGuard(bool disable = true) : m_disabled(disable)
481 if (!TEST_IS_CONSTANT_EVALUATED) {
482 // Don't re-disable if already disabled.
483 if (globalMemCounter.disable_allocations == true) m_disabled = false;
484 if (m_disabled) globalMemCounter.disableAllocations();
485 } else {
486 m_disabled = false;
490 TEST_CONSTEXPR_CXX14 void release() {
491 if (!TEST_IS_CONSTANT_EVALUATED) {
492 if (m_disabled) globalMemCounter.enableAllocations();
493 m_disabled = false;
497 TEST_CONSTEXPR_CXX20 ~ConstexprDisableAllocationGuard() {
498 release();
501 private:
502 bool m_disabled;
504 ConstexprDisableAllocationGuard(ConstexprDisableAllocationGuard const&);
505 ConstexprDisableAllocationGuard& operator=(ConstexprDisableAllocationGuard const&);
508 #endif
510 struct RequireAllocationGuard {
511 explicit RequireAllocationGuard(std::size_t RequireAtLeast = 1)
512 : m_req_alloc(RequireAtLeast),
513 m_new_count_on_init(globalMemCounter.new_called),
514 m_outstanding_new_on_init(globalMemCounter.outstanding_new),
515 m_exactly(false)
519 void requireAtLeast(std::size_t N) { m_req_alloc = N; m_exactly = false; }
520 void requireExactly(std::size_t N) { m_req_alloc = N; m_exactly = true; }
522 ~RequireAllocationGuard() {
523 assert(globalMemCounter.checkOutstandingNewEq(static_cast<int>(m_outstanding_new_on_init)));
524 std::size_t Expect = m_new_count_on_init + m_req_alloc;
525 assert(globalMemCounter.checkNewCalledEq(static_cast<int>(Expect)) ||
526 (!m_exactly && globalMemCounter.checkNewCalledGreaterThan(static_cast<int>(Expect))));
529 private:
530 std::size_t m_req_alloc;
531 const std::size_t m_new_count_on_init;
532 const std::size_t m_outstanding_new_on_init;
533 bool m_exactly;
534 RequireAllocationGuard(RequireAllocationGuard const&);
535 RequireAllocationGuard& operator=(RequireAllocationGuard const&);
538 #endif /* COUNT_NEW_H */