//===--- fallible_iterator.h - Wrapper for fallible iterators ---*- 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_FALLIBLE_ITERATOR_H #define LLVM_ADT_FALLIBLE_ITERATOR_H #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Error.h" #include <type_traits> namespace llvm { /// A wrapper class for fallible iterators. /// /// The fallible_iterator template wraps an underlying iterator-like class /// whose increment and decrement operations are replaced with fallible versions /// like: /// /// @code{.cpp} /// Error inc(); /// Error dec(); /// @endcode /// /// It produces an interface that is (mostly) compatible with a traditional /// c++ iterator, including ++ and -- operators that do not fail. /// /// Instances of the wrapper are constructed with an instance of the /// underlying iterator and (for non-end iterators) a reference to an Error /// instance. If the underlying increment/decrement operations fail, the Error /// is returned via this reference, and the resulting iterator value set to an /// end-of-range sentinel value. This enables the following loop idiom: /// /// @code{.cpp} /// class Archive { // E.g. Potentially malformed on-disk archive /// public: /// fallible_iterator<ArchiveChildItr> children_begin(Error &Err); /// fallible_iterator<ArchiveChildItr> children_end(); /// iterator_range<fallible_iterator<ArchiveChildItr>> /// children(Error &Err) { /// return make_range(children_begin(Err), children_end()); /// //... /// }; /// /// void walk(Archive &A) { /// Error Err = Error::success(); /// for (auto &C : A.children(Err)) { /// // Loop body only entered when increment succeeds. /// } /// if (Err) { /// // handle error. /// } /// } /// @endcode /// /// The wrapper marks the referenced Error as unchecked after each increment /// and/or decrement operation, and clears the unchecked flag when a non-end /// value is compared against end (since, by the increment invariant, not being /// an end value proves that there was no error, and is equivalent to checking /// that the Error is success). This allows early exits from the loop body /// without requiring redundant error checks. template <typename Underlying> class fallible_iterator { … }; /// Convenience wrapper to make a fallible_iterator value from an instance /// of an underlying iterator and an Error reference. template <typename Underlying> fallible_iterator<Underlying> make_fallible_itr(Underlying I, Error &Err) { … } /// Convenience wrapper to make a fallible_iterator end value from an instance /// of an underlying iterator. template <typename Underlying> fallible_iterator<Underlying> make_fallible_end(Underlying E) { … } template <typename Underlying> iterator_range<fallible_iterator<Underlying>> make_fallible_range(Underlying I, Underlying E, Error &Err) { … } } // end namespace llvm #endif // LLVM_ADT_FALLIBLE_ITERATOR_H