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 <iterator>
21#include <vector>
22
23namespace orc_rt {
24
25/// Used to manage sections of fixed-sized metadata records (e.g. pointer
26/// sections, selector refs, etc.)
27template <typename RecordElement> class RecordSectionsTracker {
28public:
29 /// Add a section to the "new" list.
30 void add(span<RecordElement> Sec) { New.push_back(std::move(Sec)); }
31
32 /// Returns true if there are new sections to process.
33 bool hasNewSections() const { return !New.empty(); }
34
35 /// Returns the number of new sections to process.
36 size_t numNewSections() const { return New.size(); }
37
38 /// Process all new sections.
39 template <typename ProcessSectionFunc>
40 std::enable_if_t<std::is_void_v<
41 std::invoke_result_t<ProcessSectionFunc, span<RecordElement>>>>
42 processNewSections(ProcessSectionFunc &&ProcessSection) {
43 for (auto &Sec : New)
44 ProcessSection(Sec);
45 moveNewToProcessed();
46 }
47
48 /// Proces all new sections with a fallible handler.
49 ///
50 /// Successfully handled sections will be moved to the Processed
51 /// list.
52 template <typename ProcessSectionFunc>
53 std::enable_if_t<
54 std::is_same_v<
55 Error, std::invoke_result_t<ProcessSectionFunc, span<RecordElement>>>,
56 Error>
57 processNewSections(ProcessSectionFunc &&ProcessSection) {
58 for (size_t I = 0; I != New.size(); ++I) {
59 if (auto Err = ProcessSection(New[I])) {
60 for (size_t J = 0; J != I; ++J)
61 Processed.push_back(New[J]);
62 New.erase(New.begin(), New.begin() + I);
63 return Err;
64 }
65 }
66 moveNewToProcessed();
67 return Error::success();
68 }
69
70 /// Move all sections back to New for reprocessing.
71 void reset() {
72 moveNewToProcessed();
73 New = std::move(Processed);
74 }
75
76 /// Remove the section with the given range.
77 bool removeIfPresent(ExecutorAddrRange R) {
78 if (removeIfPresent(New, R))
79 return true;
80 return removeIfPresent(Processed, R);
81 }
82
83private:
84 void moveNewToProcessed() {
85 if (Processed.empty())
86 Processed = std::move(New);
87 else {
88 Processed.reserve(Processed.size() + New.size());
89 std::copy(New.begin(), New.end(), std::back_inserter(Processed));
90 New.clear();
91 }
92 }
93
94 bool removeIfPresent(std::vector<span<RecordElement>> &V,
95 ExecutorAddrRange R) {
96 auto RI = std::find_if(
97 V.rbegin(), V.rend(),
98 [RS = R.toSpan<RecordElement>()](const span<RecordElement> &E) {
99 return E.data() == RS.data();
100 });
101 if (RI != V.rend()) {
102 V.erase(std::next(RI).base());
103 return true;
104 }
105 return false;
106 }
107
108 std::vector<span<RecordElement>> Processed;
109 std::vector<span<RecordElement>> New;
110};
111
112} // namespace orc_rt
113
114#endif // ORC_RT_RECORD_SECTION_TRACKER_H
115