]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/histogram/test/utility_allocator.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / histogram / test / utility_allocator.hpp
1 // Copyright 2018 Hans Dembinski
2 //
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7 #include <algorithm>
8 #include <boost/core/lightweight_test.hpp>
9 #include <boost/core/typeinfo.hpp>
10 #include <boost/histogram/detail/type_name.hpp>
11 #include <boost/throw_exception.hpp>
12 #include <initializer_list>
13 #include <iostream>
14 #include <unordered_map>
15 #include <utility>
16
17 struct tracing_allocator_db : std::pair<int, int> {
18 template <class T>
19 auto& at() {
20 return map_[&BOOST_CORE_TYPEID(T)];
21 }
22
23 void clear() {
24 map_.clear();
25 this->first = 0;
26 this->second = 0;
27 }
28
29 int failure_countdown = -1;
30 bool tracing = false;
31
32 template <class... Ts>
33 void log(Ts&&... ts) {
34 if (!tracing) return;
35 // fold trick
36 (void)std::initializer_list<int>{(std::cerr << ts, 0)...};
37 std::cerr << std::endl;
38 }
39
40 std::size_t size() const { return map_.size(); }
41
42 private:
43 using map_t = std::unordered_map<const boost::core::typeinfo*, std::pair<int, int>>;
44 map_t map_;
45 };
46
47 template <class T>
48 struct tracing_allocator {
49 using value_type = T;
50
51 tracing_allocator_db* db = nullptr;
52
53 tracing_allocator() noexcept = default;
54 tracing_allocator(const tracing_allocator&) noexcept = default;
55 tracing_allocator(tracing_allocator&&) noexcept = default;
56
57 tracing_allocator(tracing_allocator_db& x) noexcept : db(&x) {}
58 template <class U>
59 tracing_allocator(const tracing_allocator<U>& a) noexcept : db(a.db) {}
60 template <class U>
61 tracing_allocator& operator=(const tracing_allocator<U>& a) noexcept {
62 db = a.db;
63 return *this;
64 }
65 ~tracing_allocator() noexcept {}
66
67 T* allocate(std::size_t n) {
68 if (db) {
69 if (db->failure_countdown >= 0) {
70 const auto count = db->failure_countdown--;
71 db->log("allocator +", n, " ", boost::histogram::detail::type_name<T>(),
72 " [failure in ", count, "]");
73 if (count == 0) BOOST_THROW_EXCEPTION(std::bad_alloc{});
74 } else
75 db->log("allocator +", n, " ", boost::histogram::detail::type_name<T>());
76 auto& p = db->at<T>();
77 p.first += static_cast<int>(n);
78 p.second += static_cast<int>(n);
79 db->first += static_cast<int>(n * sizeof(T));
80 db->second += static_cast<int>(n * sizeof(T));
81 }
82 return static_cast<T*>(::operator new(n * sizeof(T)));
83 }
84
85 void deallocate(T* p, std::size_t n) {
86 if (db) {
87 db->at<T>().first -= static_cast<int>(n);
88 db->first -= static_cast<int>(n * sizeof(T));
89 db->log("allocator -", n, " ", boost::histogram::detail::type_name<T>());
90 }
91 ::operator delete((void*)p);
92 }
93
94 template <class... Ts>
95 void construct(T* p, Ts&&... ts) {
96 if (db) {
97 if (db->failure_countdown >= 0) {
98 const auto count = db->failure_countdown--;
99 db->log("allocator construct ", boost::histogram::detail::type_name<T>(),
100 "[ failure in ", count, "]");
101 if (count == 0) BOOST_THROW_EXCEPTION(std::bad_alloc{});
102 } else
103 db->log("allocator construct ", boost::histogram::detail::type_name<T>());
104 }
105 ::new (static_cast<void*>(p)) T(std::forward<Ts>(ts)...);
106 }
107
108 void destroy(T* p) {
109 if (db) db->log("allocator destroy ", boost::histogram::detail::type_name<T>());
110 p->~T();
111 }
112 };
113
114 template <class T, class U>
115 constexpr bool operator==(const tracing_allocator<T>&,
116 const tracing_allocator<U>&) noexcept {
117 return true;
118 }
119
120 template <class T, class U>
121 constexpr bool operator!=(const tracing_allocator<T>& t,
122 const tracing_allocator<U>& u) noexcept {
123 return !operator==(t, u);
124 }