llvm/llvm/include/llvm/ADT/fallible_iterator.h

//===--- 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