Hybrid ICN (hICN) plugin  v21.06-rc0-4-g18fa668
fixed_block_allocator.h
1 /*
2  * Copyright (c) 2019 Cisco and/or its affiliates.
3  */
4 
5 #pragma once
6 
7 #include <hicn/transport/portability/c_portability.h>
8 #include <hicn/transport/utils/singleton.h>
9 #include <hicn/transport/utils/spinlock.h>
10 #include <stdint.h>
11 
12 #include <cassert>
13 #include <cstdlib>
14 #include <memory>
15 
16 namespace utils {
17 template <std::size_t SIZE = 512, std::size_t OBJECTS = 4096>
19  : public utils::Singleton<FixedBlockAllocator<SIZE, OBJECTS>> {
20  friend class utils::Singleton<FixedBlockAllocator<SIZE, OBJECTS>>;
21 
22  public:
24  for (auto& p : p_pools_) {
25  delete[] p;
26  }
27  }
28 
29  void* allocateBlock(size_t size = SIZE) {
30  assert(size <= SIZE);
31  uint32_t index;
32 
33  SpinLock::Acquire locked(lock_);
34  void* p_block = pop();
35  if (!p_block) {
36  if (TRANSPORT_EXPECT_FALSE(current_pool_index_ >= max_objects_)) {
37  // Allocate new memory block
38  p_pools_.emplace_front(
39  new typename std::aligned_storage<SIZE>::type[max_objects_]);
40  // reset current_pool_index_
41  current_pool_index_ = 0;
42  }
43 
44  auto& latest = p_pools_.front();
45  index = current_pool_index_++;
46  blocks_in_use_++;
47  allocations_++;
48  p_block = (void*)&latest[index];
49  }
50 
51  return p_block;
52  }
53 
54  void deallocateBlock(void* pBlock) {
55  SpinLock::Acquire locked(lock_);
56  push(pBlock);
57  blocks_in_use_--;
58  deallocations_++;
59  }
60 
61  public:
62  std::size_t blockSize() { return block_size_; }
63 
64  uint32_t blockCount() { return block_count_; }
65 
66  uint32_t blocksInUse() { return blocks_in_use_; }
67 
68  uint32_t allocations() { return allocations_; }
69 
70  uint32_t deallocations() { return deallocations_; }
71 
72  private:
74  : block_size_(SIZE),
75  object_size_(SIZE),
76  max_objects_(OBJECTS),
77  p_head_(NULL),
78  current_pool_index_(0),
79  block_count_(0),
80  blocks_in_use_(0),
81  allocations_(0),
82  deallocations_(0) {
83  static_assert(SIZE >= sizeof(long*), "SIZE must be at least 8 bytes");
84  p_pools_.emplace_front(
85  new typename std::aligned_storage<SIZE>::type[max_objects_]);
86  }
87 
88  void push(void* p_memory) {
89  Block* p_block = (Block*)p_memory;
90  p_block->p_next = p_head_;
91  p_head_ = p_block;
92  }
93 
94  void* pop() {
95  Block* p_block = nullptr;
96 
97  if (p_head_) {
98  p_block = p_head_;
99  p_head_ = p_head_->p_next;
100  }
101 
102  return (void*)p_block;
103  }
104 
105  struct Block {
106  Block* p_next;
107  };
108 
109  static std::unique_ptr<FixedBlockAllocator> instance_;
110 
111  const std::size_t block_size_;
112  const std::size_t object_size_;
113  const std::size_t max_objects_;
114 
115  Block* p_head_;
116  uint32_t current_pool_index_;
117  std::list<typename std::aligned_storage<SIZE>::type*> p_pools_;
118  uint32_t block_count_;
119  uint32_t blocks_in_use_;
120  uint32_t allocations_;
121  uint32_t deallocations_;
122 
123  SpinLock lock_;
124 };
125 
126 template <std::size_t A, std::size_t B>
127 std::unique_ptr<FixedBlockAllocator<A, B>>
129 
133 template <typename T, typename Pool>
140  template <typename U, typename P>
141  friend class STLAllocator;
142 
143  public:
144  using size_type = std::size_t;
145  using difference_type = ptrdiff_t;
146  using pointer = T*;
147  using const_pointer = const T*;
148  using reference = T&;
149  using const_reference = const T&;
150  using value_type = T;
151 
152  STLAllocator(pointer memory, Pool* memory_pool)
153  : memory_(memory), pool_(memory_pool) {}
154 
155  ~STLAllocator() {}
156 
157  template <typename U>
158  STLAllocator(const STLAllocator<U, Pool>& other) {
159  memory_ = other.memory_;
160  pool_ = other.pool_;
161  }
162 
163  template <typename U>
164  struct rebind {
166  };
167 
168  pointer address(reference x) const { return &x; }
169  const_pointer address(const_reference x) const { return &x; }
170 
171  pointer allocate(size_type n, pointer hint = 0) {
172  return static_cast<pointer>(memory_);
173  }
174 
175  void deallocate(pointer p, size_type n) { pool_->deallocateBlock(memory_); }
176 
177  template <typename... Args>
178  void construct(pointer p, Args&&... args) {
179  new (static_cast<pointer>(p)) T(std::forward<Args>(args)...);
180  }
181 
182  void destroy(pointer p) { p->~T(); }
183 
184  private:
185  void* memory_;
186  Pool* pool_;
187 };
188 
189 template <typename T, typename U, typename V>
190 inline bool operator==(const STLAllocator<T, V>&, const STLAllocator<U, V>&) {
191  return true;
192 }
193 
194 template <typename T, typename U, typename V>
195 inline bool operator!=(const STLAllocator<T, V>& a,
196  const STLAllocator<U, V>& b) {
197  return !(a == b);
198 }
199 
200 } // namespace utils
utils::STLAllocator
Definition: fixed_block_allocator.h:134
utils::STLAllocator::rebind
Definition: fixed_block_allocator.h:164
utils::FixedBlockAllocator
Definition: fixed_block_allocator.h:18
utils::SpinLock
Definition: spinlock.h:22
utils::STLAllocator::STLAllocator
friend class STLAllocator
Definition: fixed_block_allocator.h:141
utils::SpinLock::Acquire
Definition: spinlock.h:24
utils::Singleton
Definition: singleton.h:23