• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
attracing_allocator_db19   auto& at() {
20     return map_[&BOOST_CORE_TYPEID(T)];
21   }
22 
cleartracing_allocator_db23   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>
logtracing_allocator_db33   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 
sizetracing_allocator_db40   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 
tracing_allocatortracing_allocator57   tracing_allocator(tracing_allocator_db& x) noexcept : db(&x) {}
58   template <class U>
tracing_allocatortracing_allocator59   tracing_allocator(const tracing_allocator<U>& a) noexcept : db(a.db) {}
60   template <class U>
operator =tracing_allocator61   tracing_allocator& operator=(const tracing_allocator<U>& a) noexcept {
62     db = a.db;
63     return *this;
64   }
~tracing_allocatortracing_allocator65   ~tracing_allocator() noexcept {}
66 
allocatetracing_allocator67   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 
deallocatetracing_allocator85   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>
constructtracing_allocator95   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 
destroytracing_allocator108   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>
operator ==(const tracing_allocator<T> &,const tracing_allocator<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>
operator !=(const tracing_allocator<T> & t,const tracing_allocator<U> & u)121 constexpr bool operator!=(const tracing_allocator<T>& t,
122                           const tracing_allocator<U>& u) noexcept {
123   return !operator==(t, u);
124 }
125