1 | //===- record_section_tracker.h -- for fixed-sized record sects -*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // RecordSectionsTracker: Responsible for managing sections of metadata records |
10 | // with fixed sizes. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef ORC_RT_RECORD_SECTION_TRACKER_H |
15 | #define ORC_RT_RECORD_SECTION_TRACKER_H |
16 | |
17 | #include "error.h" |
18 | #include "executor_address.h" |
19 | #include <algorithm> |
20 | #include <vector> |
21 | |
22 | namespace orc_rt { |
23 | |
24 | /// Used to manage sections of fixed-sized metadata records (e.g. pointer |
25 | /// sections, selector refs, etc.) |
26 | template <typename RecordElement> class RecordSectionsTracker { |
27 | public: |
28 | /// Add a section to the "new" list. |
29 | void add(span<RecordElement> Sec) { New.push_back(std::move(Sec)); } |
30 | |
31 | /// Returns true if there are new sections to process. |
32 | bool hasNewSections() const { return !New.empty(); } |
33 | |
34 | /// Returns the number of new sections to process. |
35 | size_t numNewSections() const { return New.size(); } |
36 | |
37 | /// Process all new sections. |
38 | template <typename ProcessSectionFunc> |
39 | std::enable_if_t<std::is_void_v< |
40 | std::invoke_result_t<ProcessSectionFunc, span<RecordElement>>>> |
41 | processNewSections(ProcessSectionFunc &&ProcessSection) { |
42 | for (auto &Sec : New) |
43 | ProcessSection(Sec); |
44 | moveNewToProcessed(); |
45 | } |
46 | |
47 | /// Proces all new sections with a fallible handler. |
48 | /// |
49 | /// Successfully handled sections will be moved to the Processed |
50 | /// list. |
51 | template <typename ProcessSectionFunc> |
52 | std::enable_if_t< |
53 | std::is_same_v< |
54 | Error, std::invoke_result_t<ProcessSectionFunc, span<RecordElement>>>, |
55 | Error> |
56 | processNewSections(ProcessSectionFunc &&ProcessSection) { |
57 | for (size_t I = 0; I != New.size(); ++I) { |
58 | if (auto Err = ProcessSection(New[I])) { |
59 | for (size_t J = 0; J != I; ++J) |
60 | Processed.push_back(New[J]); |
61 | New.erase(New.begin(), New.begin() + I); |
62 | return Err; |
63 | } |
64 | } |
65 | moveNewToProcessed(); |
66 | return Error::success(); |
67 | } |
68 | |
69 | /// Move all sections back to New for reprocessing. |
70 | void reset() { |
71 | moveNewToProcessed(); |
72 | New = std::move(Processed); |
73 | } |
74 | |
75 | /// Remove the section with the given range. |
76 | bool removeIfPresent(ExecutorAddrRange R) { |
77 | if (removeIfPresent(New, R)) |
78 | return true; |
79 | return removeIfPresent(Processed, R); |
80 | } |
81 | |
82 | private: |
83 | void moveNewToProcessed() { |
84 | if (Processed.empty()) |
85 | Processed = std::move(New); |
86 | else { |
87 | Processed.reserve(Processed.size() + New.size()); |
88 | std::copy(New.begin(), New.end(), std::back_inserter(Processed)); |
89 | New.clear(); |
90 | } |
91 | } |
92 | |
93 | bool removeIfPresent(std::vector<span<RecordElement>> &V, |
94 | ExecutorAddrRange R) { |
95 | auto RI = std::find_if( |
96 | V.rbegin(), V.rend(), |
97 | [RS = R.toSpan<RecordElement>()](const span<RecordElement> &E) { |
98 | return E.data() == RS.data(); |
99 | }); |
100 | if (RI != V.rend()) { |
101 | V.erase(std::next(RI).base()); |
102 | return true; |
103 | } |
104 | return false; |
105 | } |
106 | |
107 | std::vector<span<RecordElement>> Processed; |
108 | std::vector<span<RecordElement>> New; |
109 | }; |
110 | |
111 | } // namespace orc_rt |
112 | |
113 | #endif // ORC_RT_RECORD_SECTION_TRACKER_H |
114 | |