• 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_EQ_CLASSES_HPP
17 #define _PANDA_VERIFIER_EQ_CLASSES_HPP
18 
19 #include "lazy.h"
20 #include "abstract_index.h"
21 
22 #include "runtime/include/mem/panda_containers.h"
23 
24 #include <limits>
25 
26 namespace panda::verifier {
27 /*
28 todo:
29 optimization: tree-organization
30 each classentry is either: fixed index, or pointer to other classindex.
31 each classentry has refcounter
32 when object class is determined, after finding actual class, object class set
33 to this classindex and refcounts of classentry of prev class and new one recalculated.
34 when refcount == 0 class is disposed
35 
36 introduce flatten operation
37 */
38 
39 template <typename T>
40 class EqClass;
41 
42 template <>
43 class EqClass<size_t> {
44 public:
45     using Idx = AbstractIndex<size_t, EqClass>;
46 
47     class ClassIndex : public Idx {
48     public:
49         ClassIndex &operator=(size_t val)
50         {
51             Idx::operator=(val);
52             return *this;
53         }
54     };
55 
56     class ObjIndex : public Idx {
57     public:
58         ObjIndex &operator=(size_t val)
59         {
60             Idx::operator=(val);
61             return *this;
62         }
63     };
64 
65     struct ClassEntry {
66         size_t Size = 0;
67         ObjIndex Head;
68         ObjIndex Tail;
69     };
70 
71     struct ObjectEntry {
72         ClassIndex Class;
73         ObjIndex Next;
74         ObjIndex Prev;
75     };
76 
ClsEntry(ClassIndex cls)77     ClassEntry &ClsEntry(ClassIndex cls)
78     {
79         return EqClasses_[cls];
80     }
81 
ClsEntry(ClassIndex cls)82     const ClassEntry &ClsEntry(ClassIndex cls) const
83     {
84         return EqClasses_[cls];
85     }
86 
NewClassIndex()87     ClassIndex NewClassIndex()
88     {
89         ClassIndex cls;
90         if (!FreeClassIndices_.empty()) {
91             cls = FreeClassIndices_.back();
92             FreeClassIndices_.pop_back();
93         } else {
94             cls = EqClasses_.size();
95             EqClasses_.push_back({});
96         }
97         return cls;
98     }
99 
DisposeClassIndex(ClassIndex idx)100     void DisposeClassIndex(ClassIndex idx)
101     {
102         auto &entry = ClsEntry(idx);
103         entry.Head.Invalidate();
104         entry.Tail.Invalidate();
105         entry.Size = 0;
106         FreeClassIndices_.push_back(idx);
107     }
108 
ObjEntry(ObjIndex idx)109     ObjectEntry &ObjEntry(ObjIndex idx)
110     {
111         return Objects_[idx];
112     }
113 
ObjEntry(ObjIndex idx)114     const ObjectEntry &ObjEntry(ObjIndex idx) const
115     {
116         return Objects_[idx];
117     }
118 
ObjClass(ObjIndex idx)119     ClassIndex ObjClass(ObjIndex idx) const
120     {
121         return Objects_[idx].Class;
122     }
123 
JoinClasses(ClassIndex lhs_class,ClassIndex rhs_class)124     ClassIndex JoinClasses(ClassIndex lhs_class, ClassIndex rhs_class)
125     {
126         if (lhs_class == rhs_class) {
127             return lhs_class;
128         }
129         auto [lhs, rhs] =
130             (lhs_class < rhs_class ? std::tuple {lhs_class, rhs_class} : std::tuple {rhs_class, lhs_class});
131         auto &lhs_cls_entry = ClsEntry(lhs);
132         auto &rhs_cls_entry = ClsEntry(rhs);
133         auto &lhs_tail_obj_entry = ObjEntry(lhs_cls_entry.Tail);
134         auto &rhs_head_obj_entry = ObjEntry(rhs_cls_entry.Head);
135         lhs_tail_obj_entry.Next = rhs_cls_entry.Head;
136         rhs_head_obj_entry.Prev = lhs_cls_entry.Tail;
137         lhs_cls_entry.Tail = rhs_cls_entry.Tail;
138         lhs_cls_entry.Size += rhs_cls_entry.Size;
139         auto obj = lhs_tail_obj_entry.Next;
140         while (obj.IsValid()) {
141             auto &obj_entry = ObjEntry(obj);
142             obj_entry.Class = lhs;
143             obj = obj_entry.Next;
144         }
145         DisposeClassIndex(rhs);
146         return lhs;
147     }
148 
NewObjIndex()149     ObjIndex NewObjIndex()
150     {
151         ObjIndex obj;
152         if (!FreeObjIndices_.empty()) {
153             obj = FreeObjIndices_.back();
154             FreeObjIndices_.pop_back();
155         } else {
156             obj = Objects_.size();
157             Objects_.push_back({});
158         }
159         ClassIndex cls = NewClassIndex();
160         auto &cls_entry = ClsEntry(cls);
161         cls_entry.Head = cls_entry.Tail = obj;
162         ++cls_entry.Size;
163         ObjEntry(obj).Class = cls;
164         return obj;
165     }
166 
DisposeObjIndex(ObjIndex obj)167     void DisposeObjIndex(ObjIndex obj)
168     {
169         if (!obj.IsValid()) {
170             return;
171         }
172         auto cls = ObjClass(obj);
173         auto &cls_entry = ClsEntry(cls);
174         auto &obj_entry = ObjEntry(obj);
175         auto &prev = obj_entry.Prev;
176         auto &next = obj_entry.Next;
177         if (prev.IsValid()) {
178             ObjEntry(prev).Next = next;
179         }
180         if (next.IsValid()) {
181             ObjEntry(next).Prev = prev;
182         }
183         if (cls_entry.Head == obj) {
184             cls_entry.Head = next;
185         }
186         if (cls_entry.Tail == obj) {
187             cls_entry.Tail = prev;
188         }
189         --cls_entry.Size;
190         if (cls_entry.Size == 0) {
191             DisposeClassIndex(cls);
192         }
193         obj_entry.Next.Invalidate();
194         obj_entry.Prev.Invalidate();
195         obj_entry.Class.Invalidate();
196         FreeObjIndices_.push_back(obj);
197     }
198 
199     template <typename F>
EquateLazy(F fetcher)200     void EquateLazy(F fetcher)
201     {
202         if (auto obj = fetcher()) {
203             ClassIndex cls = ObjClass(*obj);
204             ForEach(fetcher, [this, &cls](ObjIndex object) { cls = JoinClasses(cls, ObjClass(object)); });
205         }
206     }
207 
208     template <typename It>
Equate(It begin,It end)209     void Equate(It begin, It end)
210     {
211         if (begin == end) {
212             return;
213         }
214         It it = begin;
215         ClassIndex cls = ObjClass(*it++);
216         for (; it != end; ++it) {
217             cls = JoinClasses(cls, ObjClass(*it));
218         }
219     }
220 
Equate(std::initializer_list<ObjIndex> objects)221     void Equate(std::initializer_list<ObjIndex> objects)
222     {
223         Equate(objects.begin(), objects.end());
224     }
225 
AllEqualToLazy(ObjIndex idx)226     auto AllEqualToLazy(ObjIndex idx)
227     {
228         ClassIndex cls = ObjClass(idx);
229         ObjIndex obj = ClsEntry(cls).Head;
230         return [this, obj]() mutable -> std::optional<ObjIndex> {
231             auto o = obj;
232             if (obj.IsValid()) {
233                 obj = ObjEntry(obj).Next;
234                 return o;
235             }
236             return {};
237         };
238     }
239 
240     template <typename F>
IsAllEqualLazy(F fetcher)241     bool IsAllEqualLazy(F fetcher)
242     {
243         if (auto obj = fetcher()) {
244             ClassIndex cls = ObjClass(*obj);
245             return FoldLeft(fetcher, true,
246                             [this, cls](bool result, ObjIndex object) { return result && cls == ObjClass(object); });
247         }
248         return true;
249     }
250 
251     template <typename It>
IsAllEqual(It begin,It end)252     bool IsAllEqual(It begin, It end)
253     {
254         if (begin == end) {
255             return true;
256         }
257         It it = begin;
258         ClassIndex cls = ObjClass(*it++);
259         for (; it != end; ++it) {
260             if (cls != ObjClass(*it)) {
261                 return false;
262             }
263         }
264         return true;
265     }
266 
IsAllEqual(std::initializer_list<ObjIndex> objects)267     bool IsAllEqual(std::initializer_list<ObjIndex> objects)
268     {
269         return IsAllEqual(objects.begin(), objects.end());
270     }
271 
ClassSizeOf(ObjIndex obj)272     size_t ClassSizeOf(ObjIndex obj) const
273     {
274         return ClsEntry(ObjClass(obj)).Size;
275     }
276 
AmountOfUsedObjIndices()277     size_t AmountOfUsedObjIndices() const
278     {
279         return Objects_.size() - FreeObjIndices_.size();
280     }
281 
AmountOfUsedClassIndices()282     size_t AmountOfUsedClassIndices() const
283     {
284         return EqClasses_.size() - FreeClassIndices_.size();
285     }
286 
shrink_to_fit()287     void shrink_to_fit()
288     {
289         // todo:
290         // 1. get tail indices from EqClasses_ & Object_
291         // 2. remove them from FreeClassIndices_ & FreeObjIndices_
292         // 3. optimize all vectors in capacity
293     }
294 
295 private:
296     PandaVector<ClassIndex> FreeClassIndices_;
297     PandaVector<ObjIndex> FreeObjIndices_;
298     PandaVector<ClassEntry> EqClasses_;
299     PandaVector<ObjectEntry> Objects_;
300 };
301 }  // namespace panda::verifier
302 
303 namespace std {
304 template <>
305 struct hash<panda::verifier::EqClass<size_t>::ObjIndex> {
306     size_t operator()(const panda::verifier::EqClass<size_t>::ObjIndex &idx) const
307     {
308         return panda::verifier::StdHash(
309             static_cast<panda::verifier::AbstractIndex<size_t, panda::verifier::EqClass<size_t>>>(idx));
310     }
311 };
312 }  // namespace std
313 
314 namespace panda::verifier {
315 template <typename Obj>
316 class EqClass : private EqClass<size_t> {
317 public:
318     using Base = EqClass<size_t>;
319 
320     std::optional<ObjIndex> GetIndex(const Obj &obj) const
321     {
322         auto it = ObjToIndex_.find(obj);
323         if (it != ObjToIndex_.end()) {
324             return it->second;
325         }
326         return {};
327     }
328 
329     ObjIndex GetIndexOrCreate(const Obj &obj)
330     {
331         if (auto i = GetIndex(obj)) {
332             return *i;
333         }
334         auto idx = Base::NewObjIndex();
335         ObjToIndex_[obj] = idx;
336         return idx;
337     }
338 
339     void DisposeObject(const Obj &obj)
340     {
341         ObjIndex idx = GetIndexOrCreate(obj);
342         ObjToIndex_.erase(obj);
343         IndexToObj_.erase(idx);
344         Base::DisposeObjIndex(idx);
345     }
346 
347     template <typename F>
348     void EquateLazy(F fetcher)
349     {
350         Base::EquateLazy(Transform(fetcher, [this](const Obj &obj) { return GetIndexOrCreate(obj); }));
351     }
352 
353     template <typename It>
354     void Equate(It begin, It end)
355     {
356         Base::EquateLazy([this, &begin, end]() -> std::optional<ObjIndex> {
357             if (begin != end) {
358                 return GetIndexOrCreate(*begin++);
359             }
360             return {};
361         });
362     }
363 
364     void Equate(std::initializer_list<Obj> objects)
365     {
366         Equate(objects.begin(), objects.end());
367     }
368 
369     auto AllEqualToLazy(const Obj &obj)
370     {
371         return Transform(Base::AllEqualToLazy(GetIndexOrCreate(obj)),
372                          [this](ObjIndex idx) { return IndexToObj_[idx]; });
373     }
374 
375     template <typename F>
376     bool IsAllEqualLazy(F fetcher)
377     {
378         return Base::IsAllEqualLazy(Transform(fetcher, [this](const Obj &obj) { return GetIndexOrCreate(obj); }));
379     }
380 
381     template <typename It>
382     bool IsAllEqual(It begin, It end)
383     {
384         return Base::IsAllEqualLazy([this, &begin, end]() -> std::optional<ObjIndex> {
385             if (begin != end) {
386                 return GetIndexOrCreate(*begin++);
387             }
388             return {};
389         });
390     }
391 
392     bool IsAllEqual(std::initializer_list<Obj> objects)
393     {
394         return IsAllEqual(objects.begin(), objects.end());
395     }
396 
397     size_t ClassSizeOf(const Obj &obj) const
398     {
399         if (auto idx = GetIndex(obj)) {
400             return Base::ClassSizeOf(*idx);
401         }
402         return 0;
403     }
404 
405 private:
406     PandaUnorderedMap<Obj, ObjIndex> ObjToIndex_;
407     PandaUnorderedMap<ObjIndex, Obj> IndexToObj_;
408 };
409 }  // namespace panda::verifier
410 
411 #endif  // !_PANDA_VERIFIER_EQ_CLASSES_HPP
412