• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef PANDA_VERIFIER_UTIL_OBJ_POOL_HPP_
17 #define PANDA_VERIFIER_UTIL_OBJ_POOL_HPP_
18 
19 #include "macros.h"
20 
21 #include <cstdint>
22 #include <optional>
23 #include <utility>
24 
25 namespace panda::verifier {
26 
27 template <typename T, template <typename...> class Vector, typename InitializerType = void (*)(T &, std::size_t),
28           typename CleanerType = void (*)(T &)>
29 class ObjPool {
30 public:
31     class Accessor {
32     public:
Accessor()33         Accessor() : idx {0}, pool {nullptr}, prev {nullptr}, next {nullptr} {}
Accessor(std::size_t index,ObjPool * obj_pool)34         Accessor(std::size_t index, ObjPool *obj_pool) : idx {index}, pool {obj_pool}, prev {nullptr}, next {nullptr}
35         {
36             Insert();
37         }
Accessor(const Accessor & p)38         Accessor(const Accessor &p) : idx {p.idx}, pool {p.pool}, prev {nullptr}, next {nullptr}
39         {
40             Insert();
41         }
Accessor(Accessor && p)42         Accessor(Accessor &&p) : idx {p.idx}, pool {p.pool}, prev {p.prev}, next {p.next}
43         {
44             p.Reset();
45             Rebind();
46         }
47         Accessor &operator=(const Accessor &p)
48         {
49             Erase();
50             Reset();
51             idx = p.idx;
52             pool = p.pool;
53             Insert();
54             return *this;
55         }
56         Accessor &operator=(Accessor &&p)
57         {
58             Erase();
59             idx = p.idx;
60             pool = p.pool;
61             prev = p.prev;
62             next = p.next;
63             p.Reset();
64             Rebind();
65             return *this;
66         }
~Accessor()67         ~Accessor()
68         {
69             Erase();
70         }
71         T &operator*()
72         {
73             return pool->Storage[idx];
74         }
75         const T &operator*() const
76         {
77             return pool->Storage[idx];
78         }
79         operator bool() const
80         {
81             return pool != nullptr;
82         }
Free()83         void Free()
84         {
85             Erase();
86             Reset();
87         }
88 
89     private:
Reset()90         void Reset()
91         {
92             idx = 0;
93             pool = nullptr;
94             prev = nullptr;
95             next = nullptr;
96         }
Insert()97         void Insert()
98         {
99             if (pool != nullptr) {
100                 next = pool->Accessors[idx];
101                 if (next != nullptr)
102                     next->prev = this;
103                 pool->Accessors[idx] = this;
104             }
105         }
Erase()106         void Erase()
107         {
108             if (pool != nullptr) {
109                 if (prev == nullptr) {
110                     pool->Accessors[idx] = next;
111                     if (pool->Accessors[idx] == nullptr) {
112                         pool->Cleaner(pool->Storage[idx]);
113                         pool->Free.push_back(idx);
114                     }
115                 } else
116                     prev->next = next;
117                 if (next != nullptr)
118                     next->prev = prev;
119             }
120         }
Rebind()121         void Rebind()
122         {
123             if (pool != nullptr) {
124                 if (prev != nullptr)
125                     prev->next = this;
126                 else
127                     pool->Accessors[idx] = this;
128                 if (next != nullptr)
129                     next->prev = this;
130             }
131         }
132 
133         std::size_t idx;
134         ObjPool *pool;
135         Accessor *prev;
136         Accessor *next;
137 
138         friend class ObjPool;
139     };
140 
ObjPool(InitializerType initializer,CleanerType cleaner)141     ObjPool(InitializerType initializer, CleanerType cleaner) : Initializer {initializer}, Cleaner {cleaner} {}
ObjPool(InitializerType initializer)142     ObjPool(InitializerType initializer) : Initializer {initializer}, Cleaner {[](T &) { return; }} {}
ObjPool()143     ObjPool() : Initializer {[](T &, std::size_t) { return; }}, Cleaner {[](T &) { return; }} {}
144 
145     ~ObjPool() = default;
146 
147     DEFAULT_MOVE_SEMANTIC(ObjPool);
148     DEFAULT_COPY_SEMANTIC(ObjPool);
149 
New()150     Accessor New()
151     {
152         std::size_t idx;
153         if (FreeCount() > 0) {
154             idx = Free.back();
155             Free.pop_back();
156         } else {
157             idx = Storage.size();
158             Storage.emplace_back();
159             Accessors.emplace_back(nullptr);
160         }
161         Initializer(Storage[idx], idx);
162         return Accessor {idx, this};
163     }
164 
FreeCount()165     std::size_t FreeCount() const
166     {
167         return Free.size();
168     }
169 
Count()170     std::size_t Count() const
171     {
172         return Storage.size();
173     }
174 
AccCount()175     std::size_t AccCount() const
176     {
177         size_t count = 0;
178         for (auto el : Accessors) {
179             Accessor *acc = el;
180             while (acc != nullptr) {
181                 ++count;
182                 acc = acc->next;
183             }
184         }
185         return count;
186     }
187 
AllObjects()188     auto AllObjects()
189     {
190         thread_local size_t idx = 0;
191         return [this]() -> std::optional<Accessor> {
192             while (idx < Storage.size() && Accessors[idx] == nullptr) {
193                 ++idx;
194             }
195             if (idx >= Storage.size()) {
196                 idx = 0;
197                 return std::nullopt;
198             }
199             return {Accessor {idx++, this}};
200         };
201     }
202 
ShrinkToFit()203     void ShrinkToFit()
204     {
205         size_t idx1 = 0;
206         size_t idx2 = Storage.size() - 1;
207         while (idx1 < idx2) {
208             while ((idx1 < idx2) && (Accessors[idx1] != nullptr))
209                 ++idx1;
210             while ((idx1 < idx2) && (Accessors[idx2] == nullptr))
211                 --idx2;
212             if (idx1 < idx2) {
213                 Storage[idx1] = std::move(Storage[idx2]);
214                 Accessors[idx1] = Accessors[idx2];
215                 Accessor *acc = Accessors[idx1];
216                 while (acc != nullptr) {
217                     acc->idx = idx1;
218                     acc = acc->next;
219                 }
220                 --idx2;
221             }
222         }
223         if (Accessors[idx1] != nullptr)
224             ++idx1;
225         Storage.resize(idx1);
226         Storage.shrink_to_fit();
227         Accessors.resize(idx1);
228         Accessors.shrink_to_fit();
229         Free.clear();
230         Free.shrink_to_fit();
231     }
232 
233 private:
234     InitializerType Initializer;
235     CleanerType Cleaner;
236 
237     Vector<T> Storage;
238     Vector<std::size_t> Free;
239     Vector<Accessor *> Accessors;
240 };
241 
242 }  // namespace panda::verifier
243 
244 #endif  // !PANDA_VERIFIER_UTIL_OBJ_POOL_HPP_
245