Imported Upstream version 1.72.0
[platform/upstream/boost.git] / 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/config.hpp>
9 #include <boost/core/lightweight_test.hpp>
10 #include <boost/core/typeinfo.hpp>
11 #include <boost/histogram/detail/type_name.hpp>
12 #include <boost/throw_exception.hpp>
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     log_impl(std::forward<Ts>(ts)...);
36     std::cerr << std::endl;
37   }
38
39   std::size_t size() const { return map_.size(); }
40
41 private:
42   using map_t = std::unordered_map<const boost::core::typeinfo*, std::pair<int, int>>;
43   map_t map_;
44
45   BOOST_ATTRIBUTE_UNUSED inline void log_impl() {}
46
47   template <class T, class... Ts>
48   void log_impl(T&& t, Ts&&... ts) {
49     std::cerr << t;
50     log_impl(std::forward<Ts>(ts)...);
51   }
52 };
53
54 template <class T>
55 struct tracing_allocator {
56   using value_type = T;
57
58   tracing_allocator_db* db = nullptr;
59
60   tracing_allocator() noexcept = default;
61   tracing_allocator(const tracing_allocator&) noexcept = default;
62   tracing_allocator(tracing_allocator&&) noexcept = default;
63
64   tracing_allocator(tracing_allocator_db& x) noexcept : db(&x) {}
65   template <class U>
66   tracing_allocator(const tracing_allocator<U>& a) noexcept : db(a.db) {}
67   template <class U>
68   tracing_allocator& operator=(const tracing_allocator<U>& a) noexcept {
69     db = a.db;
70     return *this;
71   }
72   ~tracing_allocator() noexcept {}
73
74   T* allocate(std::size_t n) {
75     if (db) {
76       if (db->failure_countdown >= 0) {
77         const auto count = db->failure_countdown--;
78         db->log("allocator +", n, " ", boost::histogram::detail::type_name<T>(),
79                 " [failure in ", count, "]");
80         if (count == 0) BOOST_THROW_EXCEPTION(std::bad_alloc{});
81       } else
82         db->log("allocator +", n, " ", boost::histogram::detail::type_name<T>());
83       auto& p = db->at<T>();
84       p.first += static_cast<int>(n);
85       p.second += static_cast<int>(n);
86       db->first += static_cast<int>(n * sizeof(T));
87       db->second += static_cast<int>(n * sizeof(T));
88     }
89     return static_cast<T*>(::operator new(n * sizeof(T)));
90   }
91
92   void deallocate(T* p, std::size_t n) {
93     if (db) {
94       db->at<T>().first -= static_cast<int>(n);
95       db->first -= static_cast<int>(n * sizeof(T));
96       db->log("allocator -", n, " ", boost::histogram::detail::type_name<T>());
97     }
98     ::operator delete((void*)p);
99   }
100
101   template <class... Ts>
102   void construct(T* p, Ts&&... ts) {
103     if (db) {
104       if (db->failure_countdown >= 0) {
105         const auto count = db->failure_countdown--;
106         db->log("allocator construct ", boost::histogram::detail::type_name<T>(),
107                 "[ failure in ", count, "]");
108         if (count == 0) BOOST_THROW_EXCEPTION(std::bad_alloc{});
109       } else
110         db->log("allocator construct ", boost::histogram::detail::type_name<T>());
111     }
112     ::new (static_cast<void*>(p)) T(std::forward<Ts>(ts)...);
113   }
114
115   void destroy(T* p) {
116     if (db) db->log("allocator destroy ", boost::histogram::detail::type_name<T>());
117     p->~T();
118   }
119 };
120
121 template <class T, class U>
122 constexpr bool operator==(const tracing_allocator<T>&,
123                           const tracing_allocator<U>&) noexcept {
124   return true;
125 }
126
127 template <class T, class U>
128 constexpr bool operator!=(const tracing_allocator<T>& t,
129                           const tracing_allocator<U>& u) noexcept {
130   return !operator==(t, u);
131 }