diff --git a/CMakeLists.txt b/CMakeLists.txt index 192c8655..768b5022 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,7 +121,7 @@ target_link_libraries(BandageIo PRIVATE Qt6::Gui Qt6::Widgets foonathan::lexy) # FIXME: Untagle this add_library(BandageLib STATIC ${LIB_SOURCES} ${FORMS} graphsearch/graphsearchers.cpp) -target_link_libraries(BandageLib PRIVATE BandageLayout BandageIo Qt6::Concurrent Qt6::Widgets Qt6::Svg ${bandage_zlib}) +target_link_libraries(BandageLib PRIVATE BandageLayout BandageIo llvmSupport Qt6::Concurrent Qt6::Widgets Qt6::Svg ${bandage_zlib}) target_include_directories(BandageLib INTERFACE ".") add_library(BandageCLI STATIC ${CLI_SOURCES}) diff --git a/graph/assemblygraph.cpp b/graph/assemblygraph.cpp index cb8ed4d0..2505a9fd 100644 --- a/graph/assemblygraph.cpp +++ b/graph/assemblygraph.cpp @@ -100,7 +100,7 @@ void AssemblyGraph::cleanUp() { m_nodeColors.clear(); m_nodeLabels.clear(); m_nodeCSVData.clear(); - + clearGraphInfo(); } @@ -377,7 +377,7 @@ bool AssemblyGraph::loadCSV(const QString &filename, QStringList *columns, QStri QStringList cols = utils::splitCsv(in.readLine(), sep); QString nodeName(cols[0]); - + std::vector nodes; // See if this is a path name // Match using unique prefix of path name. This allows us to load segmented SPAdes @@ -501,16 +501,13 @@ QString AssemblyGraph::getNodeNameFromString(QString string) const // Returns true if successful, false if not. bool AssemblyGraph::loadGraphFromFile(const QString& filename) { cleanUp(); - + auto builder = io::AssemblyGraphBuilder::get(filename); if (!builder) return false; - - try { - builder->build(*this); - } catch (...) { + + if (auto E = builder->build(*this)) return false; - } determineGraphInfo(); diff --git a/graph/assemblygraphbuilder.cpp b/graph/assemblygraphbuilder.cpp index dd399cde..de0918bc 100644 --- a/graph/assemblygraphbuilder.cpp +++ b/graph/assemblygraphbuilder.cpp @@ -26,6 +26,7 @@ #include "io/fileutils.h" #include "seq/sequence.hpp" +#include #include #include @@ -249,7 +250,9 @@ namespace io { return (graph.m_deBruijnGraphNodes[nodeName] = new DeBruijnNode(nodeName.c_str(), nodeDepth, sequence)); } - static auto + using NodePair = std::pair; + + static llvm::Expected addSegmentPair(const std::string &nodeName, double nodeDepth, Sequence sequence, AssemblyGraph &graph) { @@ -257,17 +260,17 @@ namespace io { auto *nodePtr = maybeAddSegment(nodeName, nodeDepth, sequence, graph); if (!nodePtr) - throw AssemblyGraphError("Duplicate segment named: " + nodeName); + return llvm::createStringError("Duplicate segment named: " + nodeName); auto oppositeNodePtr = maybeAddSegment(getOppositeNodeName(nodeName), nodeDepth, sequence.GetReverseComplement(), graph); if (!oppositeNodePtr) - throw AssemblyGraphError("Duplicate segment named: " + oppositeNodeName); + return llvm::createStringError("Duplicate segment named: " + oppositeNodeName); nodePtr->setReverseComplement(oppositeNodePtr); oppositeNodePtr->setReverseComplement(nodePtr); - return std::make_pair(nodePtr, oppositeNodePtr); + return std::pair{nodePtr, oppositeNodePtr}; } // Add placeholder @@ -306,8 +309,8 @@ namespace io { return false; } - bool handleSegment(const gfa::segment &record, - AssemblyGraph &graph) { + llvm::Expected handleSegment(const gfa::segment &record, + AssemblyGraph &graph) { bool sequencesAreMissing = false; std::string nodeName{record.name}; @@ -355,7 +358,11 @@ namespace io { } // FIXME: get rid of copies and QString's - auto [nodePtr, oppositeNodePtr] = addSegmentPair(nodeName, nodeDepth, sequence, graph); + auto nodePairOrErr = addSegmentPair(nodeName, nodeDepth, sequence, graph); + if (!nodePairOrErr) + return nodePairOrErr.takeError(); + + auto [nodePtr, oppositeNodePtr] = nodePairOrErr.get(); auto lb = gfa::getTag("LB", record.tags); auto l2 = gfa::getTag("L2", record.tags); @@ -372,32 +379,44 @@ namespace io { return sequencesAreMissing; } - static DeBruijnNode *getNode(const std::string &name, - AssemblyGraph &graph) { + static llvm::Expected getNode(const std::string &name, + AssemblyGraph &graph) { auto nodeIt = graph.m_deBruijnGraphNodes.find(name); if (nodeIt != graph.m_deBruijnGraphNodes.end()) return *nodeIt; // Add placeholder - DeBruijnNode *nodePtr, *oppositeNodePtr; - std::tie(nodePtr, oppositeNodePtr) = addSegmentPair(name, graph); + auto nodePairOrErr = addSegmentPair(name, graph); + if (!nodePairOrErr) + return nodePairOrErr.takeError(); - return nodePtr; + return nodePairOrErr.get().first; } - auto addLink(const std::string &fromNode, - const std::string &toNode, - const std::vector &tags, - AssemblyGraph &graph) { + using EdgePair = std::pair; + + llvm::Expected addLink(const std::string &fromNode, + const std::string &toNode, + const std::vector &tags, + AssemblyGraph &graph) { // Get source / dest nodes (or create placeholders to fill in) - DeBruijnNode *fromNodePtr = getNode(fromNode, graph); - DeBruijnNode *toNodePtr = getNode(toNode, graph); + DeBruijnNode *fromNodePtr, *toNodePtr; + + if (auto nodeOrErr = getNode(fromNode, graph)) + fromNodePtr = *nodeOrErr; + else + return nodeOrErr.takeError(); + + if (auto nodeOrErr = getNode(toNode, graph)) + toNodePtr = *nodeOrErr; + else + return nodeOrErr.takeError(); DeBruijnEdge *edgePtr = nullptr, *rcEdgePtr = nullptr; // Ignore dups, hifiasm seems to create them if (graph.m_deBruijnGraphEdges.count({fromNodePtr, toNodePtr})) - return std::make_pair(edgePtr, rcEdgePtr); + return std::pair{ nullptr, nullptr }; edgePtr = new DeBruijnEdge(fromNodePtr, toNodePtr); @@ -442,20 +461,24 @@ namespace io { maybeAddTags(rcEdgePtr, graph.m_edgeTags, tags, false); - return std::make_pair(edgePtr, rcEdgePtr); + return std::pair{edgePtr, rcEdgePtr}; } - void handleLink(const gfa::link &record, - AssemblyGraph &graph) { + llvm::Error handleLink(const gfa::link &record, + AssemblyGraph &graph) { std::string fromNode{record.lhs}; fromNode.push_back(record.lhs_revcomp ? '-' : '+'); std::string toNode{record.rhs}; toNode.push_back(record.rhs_revcomp ? '-' : '+'); - auto [edgePtr, rcEdgePtr] = - addLink(fromNode, toNode, record.tags, graph); + DeBruijnEdge *edgePtr, *rcEdgePtr; + if (auto edgePairOrErr = addLink(fromNode, toNode, record.tags, graph)) { + std::tie(edgePtr, rcEdgePtr) = *edgePairOrErr; + } else + return edgePairOrErr.takeError(); + if (!edgePtr) - return; + return llvm::Error::success(); const auto &overlap = record.overlap; size_t overlapLength = 0; @@ -472,20 +495,23 @@ namespace io { rcEdgePtr->setOverlap(edgePtr->getOverlap()); rcEdgePtr->setOverlapType(edgePtr->getOverlapType()); } + + return llvm::Error::success(); } - void handleGapLink(const gfa::gaplink &record, - AssemblyGraph &graph) { + llvm::Error handleGapLink(const gfa::gaplink &record, + AssemblyGraph &graph) { // FIXME: get rid of severe duplication! std::string fromNode{record.lhs}; fromNode.push_back(record.lhs_revcomp ? '-' : '+'); std::string toNode{record.rhs}; toNode.push_back(record.rhs_revcomp ? '-' : '+'); - auto [edgePtr, rcEdgePtr] = - addLink(fromNode, toNode, record.tags, graph); - if (!edgePtr) - return; + DeBruijnEdge *edgePtr, *rcEdgePtr; + if (auto edgePairOrErr = addLink(fromNode, toNode, record.tags, graph)) { + std::tie(edgePtr, rcEdgePtr) = *edgePairOrErr; + } else + return edgePairOrErr.takeError(); edgePtr->setOverlap(record.distance == std::numeric_limits::min() ? 0 : record.distance); edgePtr->setOverlapType(JUMP); @@ -502,10 +528,12 @@ namespace io { graph.setCustomStyle(edgePtr, Qt::DashLine); if (!graph.hasCustomStyle(rcEdgePtr)) graph.setCustomStyle(rcEdgePtr, Qt::DashLine); + + return llvm::Error::success(); } - void handlePath(const gfa::path &record, - AssemblyGraph &graph) { + llvm::Error handlePath(const gfa::path &record, + AssemblyGraph &graph) { std::vector pathNodes; pathNodes.reserve(record.segments.size()); @@ -515,14 +543,17 @@ namespace io { if (p.nodes().size() != pathNodes.size()) { // We were unable to build path through the graph, likely the input // file is invalid - throw AssemblyGraphError(std::string("malformed path string, cannot reconstruct path through the graph")); + return llvm::createStringError(llvm::Twine("malformed path string for path '") + + record.name + "', cannot reconstruct path through the graph"); } graph.m_deBruijnGraphPaths.emplace(record.name, std::move(p)); + + return llvm::Error::success(); } - void handleWalk(const gfa::walk &record, - AssemblyGraph &graph) { + llvm::Error handleWalk(const gfa::walk &record, + AssemblyGraph &graph) { std::vector walkNodes; walkNodes.reserve(record.Walk.size()); @@ -536,7 +567,7 @@ namespace io { else if (orientation == '<') nodeName.push_back('-'); else - throw AssemblyGraphError(std::string("invalid walk string: ").append(node)); + return llvm::createStringError(llvm::Twine("invalid walk string: ") + node); walkNodes.push_back(graph.m_deBruijnGraphNodes.at(nodeName)); } @@ -545,7 +576,8 @@ namespace io { if (p.nodes().size() != walkNodes.size()) { // We were unable to build path through the graph, likely the input // file is invalid - throw AssemblyGraphError(std::string("malformed walk string, cannot reconstruct walk through the graph")); + return llvm::createStringError(llvm::Twine("malformed walk string for walk '") + + record.SeqId + "', cannot reconstruct path through the graph"); } unsigned len = p.getLength(); @@ -556,12 +588,14 @@ namespace io { Walk{std::string(record.SampleId), seqStart, seqEnd, record.HapIndex, std::move(p)}); + + return llvm::Error::success(); } public: using AssemblyGraphBuilder::AssemblyGraphBuilder; - bool build(AssemblyGraph &graph) override { + llvm::Error build(AssemblyGraph &graph) override { graph.m_filename = fileName_; bool sequencesAreMissing = false; @@ -569,7 +603,7 @@ namespace io { std::unique_ptr::type, decltype(&gzclose)> fp(gzopen(fileName_.toStdString().c_str(), "r"), gzclose); if (!fp) - throw AssemblyGraphError("failed to open file: " + fileName_.toStdString()); + return llvm::createStringError("failed tp open file: " + fileName_.toStdString()); size_t i = 0; char *line = nullptr; @@ -583,28 +617,39 @@ namespace io { if (!result) continue; - std::visit([&](const auto &record) { + llvm::Error E = + std::visit([&](const auto &record) { using T = std::decay_t; if constexpr (std::is_same_v) { - sequencesAreMissing |= handleSegment(record, graph); + if (auto valueOrError = handleSegment(record, graph)) + sequencesAreMissing |= *valueOrError; + else + return valueOrError.takeError(); } else if constexpr (std::is_same_v) { - handleLink(record, graph); + if (auto E = handleLink(record, graph)) + return E; } else if constexpr (std::is_same_v) { - handleGapLink(record, graph); + if (auto E = handleGapLink(record, graph)) + return E; } else if constexpr (std::is_same_v) { - handlePath(record, graph); + if (auto E = handlePath(record, graph)) + return E; } else if constexpr (std::is_same_v) { - handleWalk(record, graph); + if (auto E = handleWalk(record, graph)) + return E; } + return llvm::Error(llvm::Error::success()); }, *result); + if (E) + return E; } graph.m_sequencesLoadedFromFasta = NOT_TRIED; if (sequencesAreMissing) attemptToLoadSequencesFromFasta(graph); - return true; + return llvm::Error::success(); } }; @@ -653,7 +698,7 @@ namespace io { return name; } - bool build(AssemblyGraph &graph) override { + llvm::Error build(AssemblyGraph &graph) override { graph.m_filename = fileName_; graph.m_depthTag = ""; @@ -718,7 +763,7 @@ namespace io { circularNodeNames.push_back(name); if (name.length() < 1) - throw "load error"; + return llvm::createStringError("load error"); auto node = new DeBruijnNode(name, depth, sequence); graph.m_deBruijnGraphNodes.emplace(name.toStdString(), node); @@ -731,14 +776,14 @@ namespace io { graph.createDeBruijnEdge(circularNodeName, circularNodeName, 0, EXACT_OVERLAP); } - return true; + return llvm::Error::success(); } }; class FastgAssemblyGraphBuilder : public AssemblyGraphBuilder { using AssemblyGraphBuilder::AssemblyGraphBuilder; - bool build(AssemblyGraph &graph) override { + llvm::Error build(AssemblyGraph &graph) override { graph.m_filename = fileName_; graph.m_depthTag = "KC"; @@ -774,7 +819,7 @@ namespace io { QStringList thisNodeDetails = thisNode.split("_"); if (thisNodeDetails.size() < 6) - throw "load error"; + return llvm::createStringError("load error"); nodeName = thisNodeDetails.at(1); if (negativeNode) @@ -782,7 +827,7 @@ namespace io { else nodeName += "+"; if (graph.m_deBruijnGraphNodes.count(nodeName.toStdString())) - throw "load error"; + return llvm::createStringError("load error"); QString nodeDepthString = thisNodeDetails.at(5); if (negativeNode) { @@ -813,7 +858,7 @@ namespace io { QStringList edgeNodeDetails = edgeNode.split("_"); if (edgeNodeDetails.size() < 2) - throw "load error"; + return llvm::createStringError("load error"); QString edgeNodeName = edgeNodeDetails.at(1); if (negativeNode) @@ -865,9 +910,9 @@ namespace io { graph.autoDetermineAllEdgesExactOverlap(); if (graph.m_deBruijnGraphNodes.empty()) - throw "load error"; + return llvm::createStringError("load error"); - return true; + return llvm::Error::success(); } }; @@ -879,7 +924,7 @@ namespace io { class AsqgAssemblyGraphBuilder : public AssemblyGraphBuilder { using AssemblyGraphBuilder::AssemblyGraphBuilder; - bool build(AssemblyGraph &graph) override { + llvm::Error build(AssemblyGraph &graph) override { graph.m_filename = fileName_; graph.m_depthTag = ""; @@ -902,7 +947,7 @@ namespace io { // Lines beginning with "VT" are sequence (node) lines if (lineParts.at(0) == "VT") { if (lineParts.size() < 3) - throw "load error"; + return llvm::createStringError("load error"); // We treat all nodes in this file as positive nodes and add "+" to the end of their names. QString nodeName = lineParts.at(1); @@ -925,11 +970,11 @@ namespace io { // Instead, we save the starting and ending nodes and make the edges after // we're done looking at the file. if (lineParts.size() < 2) - throw "load error"; + return llvm::createStringError("load error"); QStringList edgeParts = lineParts[1].split(" "); if (edgeParts.size() < 8) - throw "load error"; + return llvm::createStringError("load error"); QString s1Name = edgeParts.at(0); QString s2Name = edgeParts.at(1); @@ -1002,16 +1047,19 @@ namespace io { } if (graph.m_deBruijnGraphNodes.empty()) - throw "load error"; + return llvm::createStringError("load error"); - return badEdgeCount == 0; + if (badEdgeCount) + return llvm::createStringError("load error"); + + return llvm::Error::success(); } }; class TrinityAssemblyGraphBuilder : public AssemblyGraphBuilder { using AssemblyGraphBuilder::AssemblyGraphBuilder; - bool build(AssemblyGraph &graph) override { + llvm::Error build(AssemblyGraph &graph) override { graph.m_filename = fileName_; graph.m_depthTag = ""; @@ -1039,13 +1087,13 @@ namespace io { //or "TRINITY_GG", "TR" or "GG", then that will be trimmed off. if (name.length() < 4) - throw "load error"; + return llvm::createStringError("load error"); int componentStartIndex = name.indexOf(QRegularExpression("c\\d+_")); int componentEndIndex = name.indexOf("_", componentStartIndex); if (componentStartIndex < 0 || componentEndIndex < 0) - throw "load error"; + return llvm::createStringError("load error"); QString component = name.left(componentEndIndex); if (component.startsWith("TRINITY_DN") || component.startsWith("TRINITY_GG")) @@ -1054,16 +1102,16 @@ namespace io { component = component.remove(0, 2); if (component.length() < 2) - throw "load error"; + return llvm::createStringError("load error"); int pathStartIndex = name.indexOf("path=[") + 6; int pathEndIndex = name.indexOf("]", pathStartIndex); if (pathStartIndex < 0 || pathEndIndex < 0) - throw "load error"; + return llvm::createStringError("load error"); int pathLength = pathEndIndex - pathStartIndex; QString path = name.mid(pathStartIndex, pathLength); if (path.size() == 0) - throw "load error"; + return llvm::createStringError("load error"); QStringList pathParts = path.split(" "); @@ -1073,7 +1121,7 @@ namespace io { const QString &pathPart = pathParts.at(i); QStringList nodeParts = pathPart.split(":"); if (nodeParts.size() < 2) - throw "load error"; + return llvm::createStringError("load error"); //Most node numbers will be formatted simply as the number, but some //(I don't know why) have '@' and the start and '@!' at the end. In @@ -1090,7 +1138,7 @@ namespace io { QStringList nodeRangeParts = nodeRange.split("-"); if (nodeRangeParts.size() < 2) - throw "load error"; + return llvm::createStringError("load error"); int nodeRangeStart = nodeRangeParts.at(0).toInt(); int nodeRangeEnd = nodeRangeParts.at(1).toInt(); @@ -1136,9 +1184,9 @@ namespace io { graph.setAllEdgesExactOverlap(0); if (graph.m_deBruijnGraphNodes.empty()) - throw "load error"; + return llvm::createStringError("load error"); - return true; + return llvm::Error::success(); } }; diff --git a/graph/io.h b/graph/io.h index 3a833fba..071dbaf9 100644 --- a/graph/io.h +++ b/graph/io.h @@ -17,6 +17,8 @@ #pragma once +#include "llvm/Support/Error.h" + #include #include @@ -25,7 +27,7 @@ class AssemblyGraph; namespace io { class AssemblyGraphBuilder { public: - virtual bool build(AssemblyGraph &graph) = 0; + virtual llvm::Error build(AssemblyGraph &graph) = 0; virtual ~AssemblyGraphBuilder() = default; static std::unique_ptr get(const QString &fullFileName); diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index b22e7afa..b926a934 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -22,3 +22,6 @@ else() FetchContent_MakeAvailable(zlib_ng) set(bandage_zlib zlibstatic PARENT_SCOPE) endif() + +include_directories(.) +add_subdirectory(llvm) diff --git a/thirdparty/llvm/ADT/ArrayRef.h b/thirdparty/llvm/ADT/ArrayRef.h new file mode 100644 index 00000000..b9ee868a --- /dev/null +++ b/thirdparty/llvm/ADT/ArrayRef.h @@ -0,0 +1,561 @@ +//===- ArrayRef.h - Array Reference Wrapper ---------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ARRAYREF_H +#define LLVM_ADT_ARRAYREF_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Compiler.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace llvm { + template class [[nodiscard]] MutableArrayRef; + + /// ArrayRef - Represent a constant reference to an array (0 or more elements + /// consecutively in memory), i.e. a start pointer and a length. It allows + /// various APIs to take consecutive elements easily and conveniently. + /// + /// This class does not own the underlying data, it is expected to be used in + /// situations where the data resides in some other buffer, whose lifetime + /// extends past that of the ArrayRef. For this reason, it is not in general + /// safe to store an ArrayRef. + /// + /// This is intended to be trivially copyable, so it should be passed by + /// value. + template + class LLVM_GSL_POINTER [[nodiscard]] ArrayRef { + public: + using value_type = T; + using pointer = value_type *; + using const_pointer = const value_type *; + using reference = value_type &; + using const_reference = const value_type &; + using iterator = const_pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using size_type = size_t; + using difference_type = ptrdiff_t; + + private: + /// The start of the array, in an external buffer. + const T *Data = nullptr; + + /// The number of elements. + size_type Length = 0; + + public: + /// @name Constructors + /// @{ + + /// Construct an empty ArrayRef. + /*implicit*/ ArrayRef() = default; + + /// Construct an empty ArrayRef from std::nullopt. + /*implicit*/ ArrayRef(std::nullopt_t) {} + + /// Construct an ArrayRef from a single element. + /*implicit*/ ArrayRef(const T &OneElt) + : Data(&OneElt), Length(1) {} + + /// Construct an ArrayRef from a pointer and length. + constexpr /*implicit*/ ArrayRef(const T *data, size_t length) + : Data(data), Length(length) {} + + /// Construct an ArrayRef from a range. + constexpr ArrayRef(const T *begin, const T *end) + : Data(begin), Length(end - begin) { + assert(begin <= end); + } + + /// Construct an ArrayRef from a SmallVector. This is templated in order to + /// avoid instantiating SmallVectorTemplateCommon whenever we + /// copy-construct an ArrayRef. + template + /*implicit*/ ArrayRef(const SmallVectorTemplateCommon &Vec) + : Data(Vec.data()), Length(Vec.size()) { + } + + /// Construct an ArrayRef from a std::vector. + template + /*implicit*/ ArrayRef(const std::vector &Vec) + : Data(Vec.data()), Length(Vec.size()) {} + + /// Construct an ArrayRef from a std::array + template + /*implicit*/ constexpr ArrayRef(const std::array &Arr) + : Data(Arr.data()), Length(N) {} + + /// Construct an ArrayRef from a C array. + template + /*implicit*/ constexpr ArrayRef(const T (&Arr)[N]) : Data(Arr), Length(N) {} + + /// Construct an ArrayRef from a std::initializer_list. +#if LLVM_GNUC_PREREQ(9, 0, 0) +// Disable gcc's warning in this constructor as it generates an enormous amount +// of messages. Anyone using ArrayRef should already be aware of the fact that +// it does not do lifetime extension. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Winit-list-lifetime" +#endif + constexpr /*implicit*/ ArrayRef(const std::initializer_list &Vec) + : Data(Vec.begin() == Vec.end() ? (T *)nullptr : Vec.begin()), + Length(Vec.size()) {} +#if LLVM_GNUC_PREREQ(9, 0, 0) +#pragma GCC diagnostic pop +#endif + + /// Construct an ArrayRef from ArrayRef. This uses SFINAE to + /// ensure that only ArrayRefs of pointers can be converted. + template + ArrayRef(const ArrayRef &A, + std::enable_if_t::value> + * = nullptr) + : Data(A.data()), Length(A.size()) {} + + /// Construct an ArrayRef from a SmallVector. This is + /// templated in order to avoid instantiating SmallVectorTemplateCommon + /// whenever we copy-construct an ArrayRef. + template + /*implicit*/ ArrayRef( + const SmallVectorTemplateCommon &Vec, + std::enable_if_t::value> * = + nullptr) + : Data(Vec.data()), Length(Vec.size()) {} + + /// Construct an ArrayRef from std::vector. This uses SFINAE + /// to ensure that only vectors of pointers can be converted. + template + ArrayRef(const std::vector &Vec, + std::enable_if_t::value> + * = nullptr) + : Data(Vec.data()), Length(Vec.size()) {} + + /// @} + /// @name Simple Operations + /// @{ + + iterator begin() const { return Data; } + iterator end() const { return Data + Length; } + + reverse_iterator rbegin() const { return reverse_iterator(end()); } + reverse_iterator rend() const { return reverse_iterator(begin()); } + + /// empty - Check if the array is empty. + bool empty() const { return Length == 0; } + + const T *data() const { return Data; } + + /// size - Get the array size. + size_t size() const { return Length; } + + /// front - Get the first element. + const T &front() const { + assert(!empty()); + return Data[0]; + } + + /// back - Get the last element. + const T &back() const { + assert(!empty()); + return Data[Length-1]; + } + + // copy - Allocate copy in Allocator and return ArrayRef to it. + template MutableArrayRef copy(Allocator &A) { + T *Buff = A.template Allocate(Length); + std::uninitialized_copy(begin(), end(), Buff); + return MutableArrayRef(Buff, Length); + } + + /// equals - Check for element-wise equality. + bool equals(ArrayRef RHS) const { + if (Length != RHS.Length) + return false; + return std::equal(begin(), end(), RHS.begin()); + } + + /// slice(n, m) - Chop off the first N elements of the array, and keep M + /// elements in the array. + ArrayRef slice(size_t N, size_t M) const { + assert(N+M <= size() && "Invalid specifier"); + return ArrayRef(data()+N, M); + } + + /// slice(n) - Chop off the first N elements of the array. + ArrayRef slice(size_t N) const { return slice(N, size() - N); } + + /// Drop the first \p N elements of the array. + ArrayRef drop_front(size_t N = 1) const { + assert(size() >= N && "Dropping more elements than exist"); + return slice(N, size() - N); + } + + /// Drop the last \p N elements of the array. + ArrayRef drop_back(size_t N = 1) const { + assert(size() >= N && "Dropping more elements than exist"); + return slice(0, size() - N); + } + + /// Return a copy of *this with the first N elements satisfying the + /// given predicate removed. + template ArrayRef drop_while(PredicateT Pred) const { + return ArrayRef(find_if_not(*this, Pred), end()); + } + + /// Return a copy of *this with the first N elements not satisfying + /// the given predicate removed. + template ArrayRef drop_until(PredicateT Pred) const { + return ArrayRef(find_if(*this, Pred), end()); + } + + /// Return a copy of *this with only the first \p N elements. + ArrayRef take_front(size_t N = 1) const { + if (N >= size()) + return *this; + return drop_back(size() - N); + } + + /// Return a copy of *this with only the last \p N elements. + ArrayRef take_back(size_t N = 1) const { + if (N >= size()) + return *this; + return drop_front(size() - N); + } + + /// Return the first N elements of this Array that satisfy the given + /// predicate. + template ArrayRef take_while(PredicateT Pred) const { + return ArrayRef(begin(), find_if_not(*this, Pred)); + } + + /// Return the first N elements of this Array that don't satisfy the + /// given predicate. + template ArrayRef take_until(PredicateT Pred) const { + return ArrayRef(begin(), find_if(*this, Pred)); + } + + /// @} + /// @name Operator Overloads + /// @{ + const T &operator[](size_t Index) const { + assert(Index < Length && "Invalid index!"); + return Data[Index]; + } + + /// Disallow accidental assignment from a temporary. + /// + /// The declaration here is extra complicated so that "arrayRef = {}" + /// continues to select the move assignment operator. + template + std::enable_if_t::value, ArrayRef> & + operator=(U &&Temporary) = delete; + + /// Disallow accidental assignment from a temporary. + /// + /// The declaration here is extra complicated so that "arrayRef = {}" + /// continues to select the move assignment operator. + template + std::enable_if_t::value, ArrayRef> & + operator=(std::initializer_list) = delete; + + /// @} + /// @name Expensive Operations + /// @{ + std::vector vec() const { + return std::vector(Data, Data+Length); + } + + /// @} + /// @name Conversion operators + /// @{ + operator std::vector() const { + return std::vector(Data, Data+Length); + } + + /// @} + }; + + /// MutableArrayRef - Represent a mutable reference to an array (0 or more + /// elements consecutively in memory), i.e. a start pointer and a length. It + /// allows various APIs to take and modify consecutive elements easily and + /// conveniently. + /// + /// This class does not own the underlying data, it is expected to be used in + /// situations where the data resides in some other buffer, whose lifetime + /// extends past that of the MutableArrayRef. For this reason, it is not in + /// general safe to store a MutableArrayRef. + /// + /// This is intended to be trivially copyable, so it should be passed by + /// value. + template + class [[nodiscard]] MutableArrayRef : public ArrayRef { + public: + using value_type = T; + using pointer = value_type *; + using const_pointer = const value_type *; + using reference = value_type &; + using const_reference = const value_type &; + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using size_type = size_t; + using difference_type = ptrdiff_t; + + /// Construct an empty MutableArrayRef. + /*implicit*/ MutableArrayRef() = default; + + /// Construct an empty MutableArrayRef from std::nullopt. + /*implicit*/ MutableArrayRef(std::nullopt_t) : ArrayRef() {} + + /// Construct a MutableArrayRef from a single element. + /*implicit*/ MutableArrayRef(T &OneElt) : ArrayRef(OneElt) {} + + /// Construct a MutableArrayRef from a pointer and length. + /*implicit*/ MutableArrayRef(T *data, size_t length) + : ArrayRef(data, length) {} + + /// Construct a MutableArrayRef from a range. + MutableArrayRef(T *begin, T *end) : ArrayRef(begin, end) {} + + /// Construct a MutableArrayRef from a SmallVector. + /*implicit*/ MutableArrayRef(SmallVectorImpl &Vec) + : ArrayRef(Vec) {} + + /// Construct a MutableArrayRef from a std::vector. + /*implicit*/ MutableArrayRef(std::vector &Vec) + : ArrayRef(Vec) {} + + /// Construct a MutableArrayRef from a std::array + template + /*implicit*/ constexpr MutableArrayRef(std::array &Arr) + : ArrayRef(Arr) {} + + /// Construct a MutableArrayRef from a C array. + template + /*implicit*/ constexpr MutableArrayRef(T (&Arr)[N]) : ArrayRef(Arr) {} + + T *data() const { return const_cast(ArrayRef::data()); } + + iterator begin() const { return data(); } + iterator end() const { return data() + this->size(); } + + reverse_iterator rbegin() const { return reverse_iterator(end()); } + reverse_iterator rend() const { return reverse_iterator(begin()); } + + /// front - Get the first element. + T &front() const { + assert(!this->empty()); + return data()[0]; + } + + /// back - Get the last element. + T &back() const { + assert(!this->empty()); + return data()[this->size()-1]; + } + + /// slice(n, m) - Chop off the first N elements of the array, and keep M + /// elements in the array. + MutableArrayRef slice(size_t N, size_t M) const { + assert(N + M <= this->size() && "Invalid specifier"); + return MutableArrayRef(this->data() + N, M); + } + + /// slice(n) - Chop off the first N elements of the array. + MutableArrayRef slice(size_t N) const { + return slice(N, this->size() - N); + } + + /// Drop the first \p N elements of the array. + MutableArrayRef drop_front(size_t N = 1) const { + assert(this->size() >= N && "Dropping more elements than exist"); + return slice(N, this->size() - N); + } + + MutableArrayRef drop_back(size_t N = 1) const { + assert(this->size() >= N && "Dropping more elements than exist"); + return slice(0, this->size() - N); + } + + /// Return a copy of *this with the first N elements satisfying the + /// given predicate removed. + template + MutableArrayRef drop_while(PredicateT Pred) const { + return MutableArrayRef(find_if_not(*this, Pred), end()); + } + + /// Return a copy of *this with the first N elements not satisfying + /// the given predicate removed. + template + MutableArrayRef drop_until(PredicateT Pred) const { + return MutableArrayRef(find_if(*this, Pred), end()); + } + + /// Return a copy of *this with only the first \p N elements. + MutableArrayRef take_front(size_t N = 1) const { + if (N >= this->size()) + return *this; + return drop_back(this->size() - N); + } + + /// Return a copy of *this with only the last \p N elements. + MutableArrayRef take_back(size_t N = 1) const { + if (N >= this->size()) + return *this; + return drop_front(this->size() - N); + } + + /// Return the first N elements of this Array that satisfy the given + /// predicate. + template + MutableArrayRef take_while(PredicateT Pred) const { + return MutableArrayRef(begin(), find_if_not(*this, Pred)); + } + + /// Return the first N elements of this Array that don't satisfy the + /// given predicate. + template + MutableArrayRef take_until(PredicateT Pred) const { + return MutableArrayRef(begin(), find_if(*this, Pred)); + } + + /// @} + /// @name Operator Overloads + /// @{ + T &operator[](size_t Index) const { + assert(Index < this->size() && "Invalid index!"); + return data()[Index]; + } + }; + + /// This is a MutableArrayRef that owns its array. + template class OwningArrayRef : public MutableArrayRef { + public: + OwningArrayRef() = default; + OwningArrayRef(size_t Size) : MutableArrayRef(new T[Size], Size) {} + + OwningArrayRef(ArrayRef Data) + : MutableArrayRef(new T[Data.size()], Data.size()) { + std::copy(Data.begin(), Data.end(), this->begin()); + } + + OwningArrayRef(OwningArrayRef &&Other) { *this = std::move(Other); } + + OwningArrayRef &operator=(OwningArrayRef &&Other) { + delete[] this->data(); + this->MutableArrayRef::operator=(Other); + Other.MutableArrayRef::operator=(MutableArrayRef()); + return *this; + } + + ~OwningArrayRef() { delete[] this->data(); } + }; + + /// @name ArrayRef Deduction guides + /// @{ + /// Deduction guide to construct an ArrayRef from a single element. + template ArrayRef(const T &OneElt) -> ArrayRef; + + /// Deduction guide to construct an ArrayRef from a pointer and length + template ArrayRef(const T *data, size_t length) -> ArrayRef; + + /// Deduction guide to construct an ArrayRef from a range + template ArrayRef(const T *data, const T *end) -> ArrayRef; + + /// Deduction guide to construct an ArrayRef from a SmallVector + template ArrayRef(const SmallVectorImpl &Vec) -> ArrayRef; + + /// Deduction guide to construct an ArrayRef from a SmallVector + template + ArrayRef(const SmallVector &Vec) -> ArrayRef; + + /// Deduction guide to construct an ArrayRef from a std::vector + template ArrayRef(const std::vector &Vec) -> ArrayRef; + + /// Deduction guide to construct an ArrayRef from a std::array + template + ArrayRef(const std::array &Vec) -> ArrayRef; + + /// Deduction guide to construct an ArrayRef from an ArrayRef (const) + template ArrayRef(const ArrayRef &Vec) -> ArrayRef; + + /// Deduction guide to construct an ArrayRef from an ArrayRef + template ArrayRef(ArrayRef &Vec) -> ArrayRef; + + /// Deduction guide to construct an ArrayRef from a C array. + template ArrayRef(const T (&Arr)[N]) -> ArrayRef; + + /// @} + + /// @name MutableArrayRef Deduction guides + /// @{ + /// Deduction guide to construct a `MutableArrayRef` from a single element + template MutableArrayRef(T &OneElt) -> MutableArrayRef; + + /// Deduction guide to construct a `MutableArrayRef` from a pointer and + /// length. + template + MutableArrayRef(T *data, size_t length) -> MutableArrayRef; + + /// Deduction guide to construct a `MutableArrayRef` from a `SmallVector`. + template + MutableArrayRef(SmallVectorImpl &Vec) -> MutableArrayRef; + + template + MutableArrayRef(SmallVector &Vec) -> MutableArrayRef; + + /// Deduction guide to construct a `MutableArrayRef` from a `std::vector`. + template MutableArrayRef(std::vector &Vec) -> MutableArrayRef; + + /// Deduction guide to construct a `MutableArrayRef` from a `std::array`. + template + MutableArrayRef(std::array &Vec) -> MutableArrayRef; + + /// Deduction guide to construct a `MutableArrayRef` from a C array. + template + MutableArrayRef(T (&Arr)[N]) -> MutableArrayRef; + + /// @} + /// @name ArrayRef Comparison Operators + /// @{ + + template + inline bool operator==(ArrayRef LHS, ArrayRef RHS) { + return LHS.equals(RHS); + } + + template + inline bool operator==(SmallVectorImpl &LHS, ArrayRef RHS) { + return ArrayRef(LHS).equals(RHS); + } + + template + inline bool operator!=(ArrayRef LHS, ArrayRef RHS) { + return !(LHS == RHS); + } + + template + inline bool operator!=(SmallVectorImpl &LHS, ArrayRef RHS) { + return !(LHS == RHS); + } + + /// @} +} // end namespace llvm + +#endif // LLVM_ADT_ARRAYREF_H diff --git a/thirdparty/llvm/ADT/STLExtras.h b/thirdparty/llvm/ADT/STLExtras.h new file mode 100644 index 00000000..03fb3b46 --- /dev/null +++ b/thirdparty/llvm/ADT/STLExtras.h @@ -0,0 +1,2566 @@ +//===- llvm/ADT/STLExtras.h - Useful STL related functions ------*- 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains some templates that are useful if you are working with +/// the STL at all. +/// +/// No library is required when using these functions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_STLEXTRAS_H +#define LLVM_ADT_STLEXTRAS_H + +#include "llvm/ADT/ADL.h" +#include "llvm/ADT/STLForwardCompat.h" +#include "llvm/ADT/STLFunctionalExtras.h" +#include "llvm/ADT/iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/ErrorHandling.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef EXPENSIVE_CHECKS +#include // for std::mt19937 +#endif + +namespace llvm { + +//===----------------------------------------------------------------------===// +// Extra additions to +//===----------------------------------------------------------------------===// + +template struct make_const_ptr { + using type = std::add_pointer_t>; +}; + +template struct make_const_ref { + using type = std::add_lvalue_reference_t>; +}; + +namespace detail { +template class Op, class... Args> struct detector { + using value_t = std::false_type; +}; +template