1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef BERBERIS_BASE_FOREVER_POOL_H_
18 #define BERBERIS_BASE_FOREVER_POOL_H_
19 
20 #include <cstddef>
21 
22 #include "berberis/base/forever_alloc.h"
23 #include "berberis/base/lock_free_stack.h"
24 
25 namespace berberis {
26 
27 // Memory pool to be used by berberis runtime.
28 // To be used for small objects of few different types.
29 // Thread-safe, signal-safe, reentrant.
30 // Singleton interface (no non-static members).
31 template <typename T>
32 class ForeverPool {
33  public:
Alloc()34   static T* Alloc() {
35     Node* p = g_free_list_.Pop();
36     if (p) {
37       return reinterpret_cast<T*>(p);
38     }
39     return reinterpret_cast<T*>(AllocateForever(sizeof(Node), alignof(Node)));
40   }
41 
Free(T * p)42   static void Free(T* p) { g_free_list_.Push(reinterpret_cast<Node*>(p)); }
43 
44  private:
45   // LockFreeStack requires 'next' data member.
46   union Node {
47     Node* next;
48     T value;
49   };
50 
51   static LockFreeStack<Node> g_free_list_;
52 
53   ForeverPool() = delete;
54 };
55 
56 template <typename T>
57 LockFreeStack<typename ForeverPool<T>::Node> ForeverPool<T>::g_free_list_;
58 
59 // Allocator for STL containers on top of berberis runtime's memory pool.
60 // ATTENTION: if allocate/deallocate more than 1 element at once, memory is NOT reused!
61 template <class T>
62 class ForeverPoolAllocator {
63  public:
64   using value_type = T;
65 
ForeverPoolAllocator()66   ForeverPoolAllocator() {}
67 
68   template <typename U>
ForeverPoolAllocator(const ForeverPoolAllocator<U> &)69   ForeverPoolAllocator(const ForeverPoolAllocator<U>&) {}
70 
allocate(size_t n)71   T* allocate(size_t n) {
72     if (n == 1) {
73       return ForeverPool<T>::Alloc();
74     } else {
75       // ATTENTION: allocate directly from underlying ForeverAllocator!
76       return static_cast<T*>(AllocateForever(n * sizeof(T), alignof(T)));
77     }
78   }
79 
deallocate(T * p,size_t n)80   void deallocate(T* p, size_t n) {
81     if (n == 1) {
82       ForeverPool<T>::Free(p);
83     } else {
84       // ATTENTION: waste!
85     }
86   }
87 
88   bool operator==(const ForeverPoolAllocator<T>&) const { return true; }
89 
90   bool operator!=(const ForeverPoolAllocator<T>&) const { return false; }
91 };
92 
93 }  // namespace berberis
94 
95 #endif  // BERBERIS_BASE_FOREVER_POOL_H_
96