| //===- record_section_tracker.h -- for fixed-sized record sects -*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // RecordSectionsTracker: Responsible for managing sections of metadata records |
| // with fixed sizes. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef ORC_RT_RECORD_SECTION_TRACKER_H |
| #define ORC_RT_RECORD_SECTION_TRACKER_H |
| |
| #include "error.h" |
| #include "executor_address.h" |
| #include <algorithm> |
| #include <vector> |
| |
| namespace orc_rt { |
| |
| /// Used to manage sections of fixed-sized metadata records (e.g. pointer |
| /// sections, selector refs, etc.) |
| template <typename RecordElement> class RecordSectionsTracker { |
| public: |
| /// Add a section to the "new" list. |
| void add(span<RecordElement> Sec) { New.push_back(std::move(Sec)); } |
| |
| /// Returns true if there are new sections to process. |
| bool hasNewSections() const { return !New.empty(); } |
| |
| /// Returns the number of new sections to process. |
| size_t numNewSections() const { return New.size(); } |
| |
| /// Process all new sections. |
| template <typename ProcessSectionFunc> |
| std::enable_if_t<std::is_void_v< |
| std::invoke_result_t<ProcessSectionFunc, span<RecordElement>>>> |
| processNewSections(ProcessSectionFunc &&ProcessSection) { |
| for (auto &Sec : New) |
| ProcessSection(Sec); |
| moveNewToProcessed(); |
| } |
| |
| /// Proces all new sections with a fallible handler. |
| /// |
| /// Successfully handled sections will be moved to the Processed |
| /// list. |
| template <typename ProcessSectionFunc> |
| std::enable_if_t< |
| std::is_same_v< |
| Error, std::invoke_result_t<ProcessSectionFunc, span<RecordElement>>>, |
| Error> |
| processNewSections(ProcessSectionFunc &&ProcessSection) { |
| for (size_t I = 0; I != New.size(); ++I) { |
| if (auto Err = ProcessSection(New[I])) { |
| for (size_t J = 0; J != I; ++J) |
| Processed.push_back(New[J]); |
| New.erase(New.begin(), New.begin() + I); |
| return Err; |
| } |
| } |
| moveNewToProcessed(); |
| return Error::success(); |
| } |
| |
| /// Move all sections back to New for reprocessing. |
| void reset() { |
| moveNewToProcessed(); |
| New = std::move(Processed); |
| } |
| |
| /// Remove the section with the given range. |
| bool removeIfPresent(ExecutorAddrRange R) { |
| if (removeIfPresent(New, R)) |
| return true; |
| return removeIfPresent(Processed, R); |
| } |
| |
| private: |
| void moveNewToProcessed() { |
| if (Processed.empty()) |
| Processed = std::move(New); |
| else { |
| Processed.reserve(Processed.size() + New.size()); |
| std::copy(New.begin(), New.end(), std::back_inserter(Processed)); |
| New.clear(); |
| } |
| } |
| |
| bool removeIfPresent(std::vector<span<RecordElement>> &V, |
| ExecutorAddrRange R) { |
| auto RI = std::find_if( |
| V.rbegin(), V.rend(), |
| [RS = R.toSpan<RecordElement>()](const span<RecordElement> &E) { |
| return E.data() == RS.data(); |
| }); |
| if (RI != V.rend()) { |
| V.erase(std::next(RI).base()); |
| return true; |
| } |
| return false; |
| } |
| |
| std::vector<span<RecordElement>> Processed; |
| std::vector<span<RecordElement>> New; |
| }; |
| |
| } // namespace orc_rt |
| |
| #endif // ORC_RT_RECORD_SECTION_TRACKER_H |