utility_allocator.hpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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. #include <algorithm>
  7. #include <boost/config.hpp>
  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 <iostream>
  13. #include <unordered_map>
  14. #include <utility>
  15. struct tracing_allocator_db : std::pair<int, int> {
  16. template <class T>
  17. auto& at() {
  18. return map_[&BOOST_CORE_TYPEID(T)];
  19. }
  20. void clear() {
  21. map_.clear();
  22. this->first = 0;
  23. this->second = 0;
  24. }
  25. int failure_countdown = -1;
  26. bool tracing = false;
  27. template <class... Ts>
  28. void log(Ts&&... ts) {
  29. if (!tracing) return;
  30. log_impl(std::forward<Ts>(ts)...);
  31. std::cerr << std::endl;
  32. }
  33. std::size_t size() const { return map_.size(); }
  34. private:
  35. using map_t = std::unordered_map<const boost::core::typeinfo*, std::pair<int, int>>;
  36. map_t map_;
  37. BOOST_ATTRIBUTE_UNUSED inline void log_impl() {}
  38. template <class T, class... Ts>
  39. void log_impl(T&& t, Ts&&... ts) {
  40. std::cerr << t;
  41. log_impl(std::forward<Ts>(ts)...);
  42. }
  43. };
  44. template <class T>
  45. struct tracing_allocator {
  46. using value_type = T;
  47. tracing_allocator_db* db = nullptr;
  48. tracing_allocator() noexcept = default;
  49. tracing_allocator(const tracing_allocator&) noexcept = default;
  50. tracing_allocator(tracing_allocator&&) noexcept = default;
  51. tracing_allocator(tracing_allocator_db& x) noexcept : db(&x) {}
  52. template <class U>
  53. tracing_allocator(const tracing_allocator<U>& a) noexcept : db(a.db) {}
  54. template <class U>
  55. tracing_allocator& operator=(const tracing_allocator<U>& a) noexcept {
  56. db = a.db;
  57. return *this;
  58. }
  59. ~tracing_allocator() noexcept {}
  60. T* allocate(std::size_t n) {
  61. if (db) {
  62. if (db->failure_countdown >= 0) {
  63. const auto count = db->failure_countdown--;
  64. db->log("allocator +", n, " ", boost::histogram::detail::type_name<T>(),
  65. " [failure in ", count, "]");
  66. if (count == 0) BOOST_THROW_EXCEPTION(std::bad_alloc{});
  67. } else
  68. db->log("allocator +", n, " ", boost::histogram::detail::type_name<T>());
  69. auto& p = db->at<T>();
  70. p.first += static_cast<int>(n);
  71. p.second += static_cast<int>(n);
  72. db->first += static_cast<int>(n * sizeof(T));
  73. db->second += static_cast<int>(n * sizeof(T));
  74. }
  75. return static_cast<T*>(::operator new(n * sizeof(T)));
  76. }
  77. void deallocate(T* p, std::size_t n) {
  78. if (db) {
  79. db->at<T>().first -= static_cast<int>(n);
  80. db->first -= static_cast<int>(n * sizeof(T));
  81. db->log("allocator -", n, " ", boost::histogram::detail::type_name<T>());
  82. }
  83. ::operator delete((void*)p);
  84. }
  85. template <class... Ts>
  86. void construct(T* p, Ts&&... ts) {
  87. if (db) {
  88. if (db->failure_countdown >= 0) {
  89. const auto count = db->failure_countdown--;
  90. db->log("allocator construct ", boost::histogram::detail::type_name<T>(),
  91. "[ failure in ", count, "]");
  92. if (count == 0) BOOST_THROW_EXCEPTION(std::bad_alloc{});
  93. } else
  94. db->log("allocator construct ", boost::histogram::detail::type_name<T>());
  95. }
  96. ::new (static_cast<void*>(p)) T(std::forward<Ts>(ts)...);
  97. }
  98. void destroy(T* p) {
  99. if (db) db->log("allocator destroy ", boost::histogram::detail::type_name<T>());
  100. p->~T();
  101. }
  102. };
  103. template <class T, class U>
  104. constexpr bool operator==(const tracing_allocator<T>&,
  105. const tracing_allocator<U>&) noexcept {
  106. return true;
  107. }
  108. template <class T, class U>
  109. constexpr bool operator!=(const tracing_allocator<T>& t,
  110. const tracing_allocator<U>& u) noexcept {
  111. return !operator==(t, u);
  112. }