Sources Pipelines Documentation

Allocators  
operators.hpp
1 // Copyright (c) 2016 Lukasz Laszko
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 #pragma once
6 
7 #include <boost/utils/backtrace.hpp>
8 #include <boost/utils/nop_unique_ptr.hpp>
9 
10 #include <memory>
11 #include <new>
12 #include <unordered_map>
13 #include <utility>
14 #include <stdexcept>
15 
16 
17 // DEFINE_ALLOCATOR macro
18 #ifndef DEFINE_ALLOCATOR
19 #define DEFINE_ALLOCATOR_FULL(allocator_type, backtrace_enabled) \
20 \
21 using registered_allocator_type = allocator_type; \
22 using size_map_key_type = void*; \
23 using size_map_value_type = std::size_t; \
24 using size_map_type = std::unordered_map< \
25  size_map_key_type, \
26  size_map_value_type, \
27  std::hash<size_map_key_type>, \
28  std::equal_to<size_map_key_type>>; \
29 \
30 boost::memory::mallocator default_allocator; \
31 thread_local boost::utils::nop_unique_ptr<allocator_type> allocator_handle; \
32 thread_local boost::utils::nop_unique_ptr<size_map_type> size_map_handle; \
33 thread_local bool allocation_pending { false }; \
34 \
35 void* operator new(std::size_t sz) \
36 { \
37  if (allocator_handle && !allocation_pending) \
38  { \
39  if (backtrace_enabled) \
40  { \
41  boost::utils::backtrace bt; \
42  std::cerr << "++++ custom allocator at " << std::endl; \
43  std::cerr << bt << std::endl; \
44  } \
45  allocation_pending = true; \
46  auto block = allocator_handle->allocate(sz); \
47  size_map_handle.operator *()[block.address] = block.size; \
48  allocation_pending = false; \
49  return block.address; \
50  } \
51  else \
52  { \
53  if (backtrace_enabled) \
54  { \
55  boost::utils::backtrace bt; \
56  std::cerr << "++++ default allocator at " << std::endl; \
57  std::cerr << bt << std::endl; \
58  } \
59  auto block = default_allocator.allocate(sz); \
60  return block.address; \
61  } \
62 } \
63 \
64 void operator delete(void* ptr) noexcept \
65 { \
66  if (allocator_handle) \
67  { \
68  auto search_result = size_map_handle->find(ptr); \
69  if (search_result != size_map_handle->end()) \
70  { \
71  memory_block block { ptr, search_result->second }; \
72  allocator_handle->deallocate(block); \
73  } \
74  } \
75  else \
76  { \
77  memory_block block { ptr, 1ul }; \
78  default_allocator.deallocate(block); \
79  } \
80 }
81 
82 #define DEFINE_ALLOCATOR(allocator_type) \
83  DEFINE_ALLOCATOR_FULL(allocator_type, false)
84 
85 #define DEFINE_ALLOCATOR_WITH_TRACE(allocator_type) \
86  DEFINE_ALLOCATOR_FULL(allocator_type, true)
87 
88 #endif
89 
90 // INIT_ALLOCATOR macro
91 #define INIT_ALLOCATOR() \
92 do { \
93  size_map_type size_map; \
94  registered_allocator_type allocator; \
95  allocator_handle.reset(&allocator); \
96  size_map_handle.reset(&size_map); \
97 } while (0)
98 
99 // TEARDOWN_ALLOCATOR macro
100 #define TEARDOWN_ALLOCATOR() \
101 do { \
102  size_map_handle.release(); \
103  allocator_handle.release(); \
104 } while (0)
105 
106