mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
775 lines
24 KiB
C++
775 lines
24 KiB
C++
//===--- STLExtras.h - additions to the STL ---------------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
/// \file Provides STL-style algorithms for convenience.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_BASIC_INTERLEAVE_H
|
|
#define SWIFT_BASIC_INTERLEAVE_H
|
|
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "llvm/ADT/Optional.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <functional>
|
|
#include <iterator>
|
|
#include <numeric>
|
|
#include <type_traits>
|
|
#include <unordered_set>
|
|
|
|
namespace swift {
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Function Traits
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
template <class T>
|
|
struct function_traits : function_traits<decltype(&T::operator())> {};
|
|
|
|
// function
|
|
template <class R, class... Args> struct function_traits<R(Args...)> {
|
|
using result_type = R;
|
|
using argument_types = std::tuple<Args...>;
|
|
};
|
|
|
|
// function pointer
|
|
template <class R, class... Args> struct function_traits<R (*)(Args...)> {
|
|
using result_type = R;
|
|
using argument_types = std::tuple<Args...>;
|
|
};
|
|
|
|
// std::function
|
|
template <class R, class... Args>
|
|
struct function_traits<std::function<R(Args...)>> {
|
|
using result_type = R;
|
|
using argument_types = std::tuple<Args...>;
|
|
};
|
|
|
|
// pointer-to-member-function (i.e., operator()'s)
|
|
template <class T, class R, class... Args>
|
|
struct function_traits<R (T::*)(Args...)> {
|
|
using result_type = R;
|
|
using argument_types = std::tuple<Args...>;
|
|
};
|
|
|
|
template <class T, class R, class... Args>
|
|
struct function_traits<R (T::*)(Args...) const> {
|
|
using result_type = R;
|
|
using argument_types = std::tuple<Args...>;
|
|
};
|
|
|
|
/// @{
|
|
|
|
/// The equivalent of std::for_each, but for two lists at once.
|
|
template <typename InputIt1, typename InputIt2, typename BinaryFunction>
|
|
inline void for_each(InputIt1 I1, InputIt1 E1, InputIt2 I2, BinaryFunction f) {
|
|
while (I1 != E1) {
|
|
f(*I1, *I2);
|
|
++I1; ++I2;
|
|
}
|
|
}
|
|
|
|
template <typename Container1, typename Container2, typename BinaryFunction>
|
|
inline void for_each(const Container1 &c1, const Container2 &c2,
|
|
BinaryFunction f) {
|
|
assert(c1.size() == c2.size());
|
|
for_each(c1.begin(), c1.end(), c2.begin(), f);
|
|
}
|
|
|
|
/// The equivalent of std::for_each, but for three lists at once.
|
|
template <typename InputIt1, typename InputIt2, typename InputIt3,
|
|
typename TernaryFunction>
|
|
inline void for_each3(InputIt1 I1, InputIt1 E1, InputIt2 I2, InputIt3 I3,
|
|
TernaryFunction f) {
|
|
while (I1 != E1) {
|
|
f(*I1, *I2, *I3);
|
|
++I1; ++I2; ++I3;
|
|
}
|
|
}
|
|
|
|
template <typename Container1, typename Container2, typename Container3,
|
|
typename TernaryFunction>
|
|
inline void for_each3(const Container1 &c1, const Container2 &c2,
|
|
const Container3 &c3,
|
|
TernaryFunction f) {
|
|
assert(c1.size() == c2.size());
|
|
assert(c2.size() == c3.size());
|
|
for_each3(c1.begin(), c1.end(), c2.begin(), c3.begin(), f);
|
|
}
|
|
|
|
/// The equivalent of std::for_each, but visits the set union of two sorted
|
|
/// lists without allocating additional memory.
|
|
///
|
|
/// This has the following requirements:
|
|
///
|
|
/// 1. The ranges must be sorted.
|
|
/// 2. The elements must have the same type.
|
|
/// 3. There are no duplicate elements.
|
|
/// 4. All elements must be comparable with std::less.
|
|
template <typename InputIt1, typename InputIt2, typename BinaryFunction>
|
|
inline void set_union_for_each(InputIt1 I1, InputIt1 E1, InputIt2 I2,
|
|
InputIt2 E2, BinaryFunction f) {
|
|
static_assert(
|
|
std::is_same<
|
|
typename std::iterator_traits<InputIt1>::value_type,
|
|
typename std::iterator_traits<InputIt2>::value_type
|
|
>::value,
|
|
"Expected both iterator types to have the same underlying value type");
|
|
|
|
using RefTy = typename std::iterator_traits<InputIt1>::reference;
|
|
|
|
while (true) {
|
|
// If we have reached the end of either list, visit the rest of the other
|
|
// list, We do not need to worry about duplicates since each array we know
|
|
// is unique.
|
|
if (I1 == E1) {
|
|
std::for_each(I2, E2, f);
|
|
return;
|
|
}
|
|
|
|
if (I2 == E2) {
|
|
std::for_each(I1, E1, f);
|
|
return;
|
|
}
|
|
|
|
// If I1 < I2, then visit I1 and continue.
|
|
if (std::less<RefTy>()(*I1, *I2)) {
|
|
f(*I1);
|
|
++I1;
|
|
continue;
|
|
}
|
|
|
|
// If I2 < I1, visit I2 and continue.
|
|
if (std::less<RefTy>()(*I2, *I1)) {
|
|
f(*I2);
|
|
++I2;
|
|
continue;
|
|
}
|
|
|
|
// Otherwise, we know that I1 and I2 equal. We know that we can only have
|
|
// one of each element in each list, so we can just visit I1 and continue.
|
|
f(*I1);
|
|
++I1;
|
|
++I2;
|
|
}
|
|
}
|
|
|
|
/// A container adapter for set_union_for_each.
|
|
///
|
|
/// To see the requirements upon the containers, please see the iterator based
|
|
/// set_union_for_each.
|
|
template <typename Container1, typename Container2, typename UnaryFunction>
|
|
inline void set_union_for_each(const Container1 &C1, const Container2 &C2,
|
|
UnaryFunction f) {
|
|
// Make sure that our iterators have the same value type.
|
|
static_assert(
|
|
std::is_same<
|
|
typename std::iterator_traits<
|
|
typename Container1::iterator
|
|
>::value_type,
|
|
typename std::iterator_traits<
|
|
typename Container2::iterator
|
|
>::value_type
|
|
>::value,
|
|
"Expected both containers to have the same iterator value type");
|
|
set_union_for_each(C1.begin(), C1.end(), C2.begin(), C2.end(), f);
|
|
}
|
|
|
|
/// If \p it is equal to \p end, then return \p defaultIter. Otherwise, return
|
|
/// std::next(\p it).
|
|
template <typename Iterator>
|
|
inline Iterator next_or_default(Iterator it, Iterator end,
|
|
Iterator defaultIter) {
|
|
return (it == end) ? defaultIter : std::next(it);
|
|
}
|
|
|
|
/// If \p it is equal to \p begin, then return \p defaultIter. Otherwise, return
|
|
/// std::prev(\p it).
|
|
template <typename Iterator>
|
|
inline Iterator prev_or_default(Iterator it, Iterator begin,
|
|
Iterator defaultIter) {
|
|
return (it == begin) ? defaultIter : std::prev(it);
|
|
}
|
|
|
|
/// Takes an iterator and an iterator pointing to the end of the iterator range.
|
|
/// If the iterator already points to the end of its range, simply return it,
|
|
/// otherwise return the next element.
|
|
template <typename Iterator>
|
|
inline Iterator next_or_end(Iterator it, Iterator end) {
|
|
return next_or_default(it, end, end);
|
|
}
|
|
|
|
template <typename Iterator>
|
|
inline Iterator prev_or_begin(Iterator it, Iterator begin) {
|
|
return prev_or_default(it, begin, begin);
|
|
}
|
|
|
|
/// @}
|
|
|
|
/// An iterator that walks a linked list of objects until it reaches
|
|
/// a null pointer.
|
|
template <class T, T* (&getNext)(T*)>
|
|
class LinkedListIterator {
|
|
T *Pointer;
|
|
public:
|
|
using iterator_category = std::forward_iterator_tag;
|
|
using value_type = T *;
|
|
using reference = T *;
|
|
using pointer = void;
|
|
|
|
/// Returns an iterator range starting from the given pointer and
|
|
/// running until it reaches a null pointer.
|
|
static llvm::iterator_range<LinkedListIterator> rangeBeginning(T *pointer) {
|
|
return {pointer, nullptr};
|
|
}
|
|
|
|
constexpr LinkedListIterator(T *pointer) : Pointer(pointer) {}
|
|
|
|
T *operator*() const {
|
|
assert(Pointer && "dereferencing a null iterator");
|
|
return Pointer;
|
|
}
|
|
|
|
LinkedListIterator &operator++() {
|
|
Pointer = getNext(Pointer);
|
|
return *this;
|
|
}
|
|
LinkedListIterator operator++(int) {
|
|
auto copy = *this;
|
|
Pointer = getNext(Pointer);
|
|
return copy;
|
|
}
|
|
|
|
friend bool operator==(LinkedListIterator lhs, LinkedListIterator rhs) {
|
|
return lhs.Pointer == rhs.Pointer;
|
|
}
|
|
friend bool operator!=(LinkedListIterator lhs, LinkedListIterator rhs) {
|
|
return lhs.Pointer != rhs.Pointer;
|
|
}
|
|
};
|
|
|
|
/// An iterator that transforms the result of an underlying bidirectional
|
|
/// iterator with a given operation.
|
|
///
|
|
/// Slightly different semantics from llvm::map_iterator, but we should
|
|
/// probably figure out how to merge them eventually.
|
|
///
|
|
/// \tparam Iterator the underlying iterator.
|
|
///
|
|
/// \tparam Operation A function object that transforms the underlying
|
|
/// sequence's values into the new sequence's values.
|
|
template<typename Iterator, typename Operation>
|
|
class TransformIterator {
|
|
Iterator Current;
|
|
|
|
/// FIXME: Could optimize away this storage with EBCO tricks.
|
|
Operation Op;
|
|
|
|
/// The underlying reference type, which will be passed to the
|
|
/// operation.
|
|
using OpTraits = function_traits<Operation>;
|
|
|
|
public:
|
|
using iterator_category = std::bidirectional_iterator_tag;
|
|
using value_type = typename OpTraits::result_type;
|
|
using reference = value_type;
|
|
using pointer = void; // FIXME: Should provide a pointer proxy.
|
|
using difference_type =
|
|
typename std::iterator_traits<Iterator>::difference_type;
|
|
|
|
/// Construct a new transforming iterator for the given iterator
|
|
/// and operation.
|
|
TransformIterator(Iterator current, Operation op)
|
|
: Current(current), Op(op) { }
|
|
|
|
reference operator*() const {
|
|
return Op(*Current);
|
|
}
|
|
|
|
TransformIterator &operator++() {
|
|
++Current;
|
|
return *this;
|
|
}
|
|
|
|
TransformIterator operator++(int) {
|
|
TransformIterator old = *this;
|
|
++*this;
|
|
return old;
|
|
}
|
|
|
|
TransformIterator &operator--() {
|
|
--Current;
|
|
return *this;
|
|
}
|
|
|
|
TransformIterator operator--(int) {
|
|
TransformIterator old = *this;
|
|
--*this;
|
|
return old;
|
|
}
|
|
|
|
friend bool operator==(TransformIterator lhs, TransformIterator rhs) {
|
|
return lhs.Current == rhs.Current;
|
|
}
|
|
friend bool operator!=(TransformIterator lhs, TransformIterator rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
};
|
|
|
|
/// Create a new transform iterator.
|
|
template<typename Iterator, typename Operation>
|
|
inline TransformIterator<Iterator, Operation>
|
|
makeTransformIterator(Iterator current, Operation op) {
|
|
return TransformIterator<Iterator, Operation>(current, op);
|
|
}
|
|
|
|
/// A range transformed by a specific predicate.
|
|
template<typename Range, typename Operation>
|
|
class TransformRange {
|
|
Range Rng;
|
|
Operation Op;
|
|
|
|
public:
|
|
using iterator = TransformIterator<decltype(Rng.begin()), Operation>;
|
|
|
|
TransformRange(Range range, Operation op)
|
|
: Rng(range), Op(op) { }
|
|
|
|
iterator begin() const { return iterator(Rng.begin(), Op); }
|
|
iterator end() const { return iterator(Rng.end(), Op); }
|
|
bool empty() const { return begin() == end(); }
|
|
|
|
// The dummy template parameter keeps 'size()' from being eagerly
|
|
// instantiated.
|
|
template <typename Dummy = Range>
|
|
typename function_traits<decltype(&Dummy::size)>::result_type
|
|
size() const {
|
|
return Rng.size();
|
|
}
|
|
|
|
template <typename Index>
|
|
typename function_traits<Operation>::result_type
|
|
operator[](Index index) const {
|
|
return Op(Rng[index]);
|
|
}
|
|
|
|
typename std::iterator_traits<iterator>::value_type front() const {
|
|
assert(!empty() && "Front of empty range");
|
|
return *begin();
|
|
}
|
|
};
|
|
|
|
/// Create a new transform range.
|
|
template<typename Range, typename Operation>
|
|
inline TransformRange<Range, Operation>
|
|
makeTransformRange(Range range, Operation op) {
|
|
return TransformRange<Range, Operation>(range, op);
|
|
}
|
|
|
|
/// An iterator that filters and transforms the results of an
|
|
/// underlying forward iterator based on a transformation from the underlying
|
|
/// value type to an optional result type.
|
|
///
|
|
/// \tparam Iterator the underlying iterator.
|
|
///
|
|
/// \tparam OptionalTransform A function object that maps a value of
|
|
/// the underlying iterator type to an optional containing a value of
|
|
/// the resulting sequence, or an empty optional if this item should
|
|
/// be skipped.
|
|
template<typename Iterator, typename OptionalTransform>
|
|
class OptionalTransformIterator {
|
|
Iterator Current, End;
|
|
|
|
/// FIXME: Could optimize away this storage with EBCO tricks.
|
|
OptionalTransform Op;
|
|
|
|
/// Skip any non-matching elements.
|
|
void skipNonMatching() {
|
|
while (Current != End && !Op(*Current))
|
|
++Current;
|
|
}
|
|
|
|
using UnderlyingReference =
|
|
typename std::iterator_traits<Iterator>::reference;
|
|
|
|
using ResultReference =
|
|
typename std::result_of<OptionalTransform(UnderlyingReference)>::type;
|
|
|
|
public:
|
|
/// Used to indicate when the current iterator has already been
|
|
/// "primed", meaning that it's at the end or points to a value that
|
|
/// satisfies the transform.
|
|
enum PrimedT { Primed };
|
|
|
|
using iterator_category = std::forward_iterator_tag;
|
|
using reference = typename ResultReference::value_type;
|
|
using value_type = typename ResultReference::value_type;
|
|
using pointer = void; // FIXME: should add a proxy here.
|
|
using difference_type =
|
|
typename std::iterator_traits<Iterator>::difference_type;
|
|
|
|
/// Construct a new optional transform iterator for the given
|
|
/// iterator range and operation.
|
|
OptionalTransformIterator(Iterator current, Iterator end,
|
|
OptionalTransform op)
|
|
: Current(current), End(end), Op(op)
|
|
{
|
|
// Prime the iterator.
|
|
skipNonMatching();
|
|
}
|
|
|
|
/// Construct a new optional transform iterator for the given iterator range
|
|
/// and operation, where the iterator range has already been
|
|
/// "primed" by ensuring that it is empty or the current iterator
|
|
/// points to something that matches the operation.
|
|
OptionalTransformIterator(Iterator current, Iterator end,
|
|
OptionalTransform op, PrimedT)
|
|
: Current(current), End(end), Op(op)
|
|
{
|
|
// Assert that the iterators have already been primed.
|
|
assert((Current == End || Op(*Current)) && "Not primed!");
|
|
}
|
|
|
|
reference operator*() const {
|
|
return *Op(*Current);
|
|
}
|
|
|
|
reference operator*() { return *Op(*Current); }
|
|
|
|
OptionalTransformIterator &operator++() {
|
|
++Current;
|
|
skipNonMatching();
|
|
return *this;
|
|
}
|
|
|
|
OptionalTransformIterator operator++(int) {
|
|
OptionalTransformIterator old = *this;
|
|
++*this;
|
|
return old;
|
|
}
|
|
|
|
friend bool operator==(OptionalTransformIterator lhs,
|
|
OptionalTransformIterator rhs) {
|
|
return lhs.Current == rhs.Current;
|
|
}
|
|
friend bool operator!=(OptionalTransformIterator lhs,
|
|
OptionalTransformIterator rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
};
|
|
|
|
/// Create a new filter iterator.
|
|
template<typename Iterator, typename OptionalTransform>
|
|
inline OptionalTransformIterator<Iterator, OptionalTransform>
|
|
makeOptionalTransformIterator(Iterator current, Iterator end,
|
|
OptionalTransform op) {
|
|
return OptionalTransformIterator<Iterator, OptionalTransform>(current, end,
|
|
op);
|
|
}
|
|
|
|
/// A range filtered and transformed by the optional transform.
|
|
template <typename Range, typename OptionalTransform,
|
|
typename Iterator = decltype(std::declval<Range>().begin())>
|
|
class OptionalTransformRange {
|
|
|
|
Iterator First, Last;
|
|
OptionalTransform Op;
|
|
|
|
public:
|
|
using iterator = OptionalTransformIterator<Iterator, OptionalTransform>;
|
|
|
|
OptionalTransformRange(Range range, OptionalTransform op)
|
|
: First(range.begin()), Last(range.end()), Op(op)
|
|
{
|
|
// Prime the sequence.
|
|
while (First != Last && !Op(*First))
|
|
++First;
|
|
}
|
|
|
|
iterator begin() const {
|
|
return iterator(First, Last, Op, iterator::Primed);
|
|
}
|
|
|
|
iterator end() const {
|
|
return iterator(Last, Last, Op, iterator::Primed);
|
|
}
|
|
|
|
bool empty() const { return First == Last; }
|
|
|
|
typename std::iterator_traits<iterator>::value_type front() const {
|
|
assert(!empty() && "Front of empty range");
|
|
return *begin();
|
|
}
|
|
};
|
|
|
|
/// Create a new filter range.
|
|
template<typename Range, typename OptionalTransform>
|
|
inline OptionalTransformRange<Range, OptionalTransform>
|
|
makeOptionalTransformRange(Range range, OptionalTransform op) {
|
|
return OptionalTransformRange<Range, OptionalTransform>(range, op);
|
|
}
|
|
|
|
/// Function object that attempts a downcast to a subclass, wrapping
|
|
/// the result in an optional to indicate success or failure.
|
|
template<typename Subclass>
|
|
struct DowncastAsOptional {
|
|
template <typename Superclass>
|
|
auto operator()(Superclass &value) const
|
|
-> llvm::Optional<decltype(llvm::cast<Subclass>(value))> {
|
|
if (auto result = llvm::dyn_cast<Subclass>(value))
|
|
return result;
|
|
|
|
return None;
|
|
}
|
|
|
|
template <typename Superclass>
|
|
auto operator()(const Superclass &value) const
|
|
-> llvm::Optional<decltype(llvm::cast<Subclass>(value))> {
|
|
if (auto result = llvm::dyn_cast<Subclass>(value))
|
|
return result;
|
|
|
|
return None;
|
|
}
|
|
};
|
|
|
|
template<typename Subclass, typename Iterator>
|
|
using DowncastFilterIterator
|
|
= OptionalTransformIterator<Iterator, DowncastAsOptional<Subclass>>;
|
|
|
|
template<typename Subclass, typename Iterator>
|
|
inline DowncastFilterIterator<Subclass, Iterator>
|
|
makeDowncastFilterIterator(Iterator current, Iterator end) {
|
|
DowncastAsOptional<Subclass> op;
|
|
return DowncastFilterIterator<Subclass, Iterator>(current, end, op);
|
|
}
|
|
|
|
template<typename Subclass, typename Range>
|
|
class DowncastFilterRange
|
|
: public OptionalTransformRange<Range, DowncastAsOptional<Subclass>> {
|
|
|
|
using Inherited = OptionalTransformRange<Range, DowncastAsOptional<Subclass>>;
|
|
|
|
public:
|
|
DowncastFilterRange(Range range)
|
|
: Inherited(range, DowncastAsOptional<Subclass>()) { }
|
|
};
|
|
|
|
template<typename Subclass, typename Range>
|
|
DowncastFilterRange<Subclass, Range>
|
|
makeDowncastFilterRange(Range range) {
|
|
return DowncastFilterRange<Subclass, Range>(range);
|
|
}
|
|
|
|
/// Sorts and then uniques a container with random access iterators and an erase
|
|
/// method that removes a range specified by random access iterators.
|
|
template <typename Container>
|
|
void sortUnique(
|
|
Container &C,
|
|
typename std::enable_if<
|
|
std::is_same<typename std::iterator_traits<
|
|
typename Container::iterator>::iterator_category,
|
|
std::random_access_iterator_tag>::value,
|
|
void>::type * = nullptr) {
|
|
std::sort(C.begin(), C.end());
|
|
C.erase(std::unique(C.begin(), C.end()), C.end());
|
|
}
|
|
|
|
/// Sorts and then uniques a container with random access iterators and an erase
|
|
/// method that removes a range specified by random access iterators.
|
|
template <typename Container, typename Comparator>
|
|
void sortUnique(
|
|
Container &C,
|
|
Comparator Cmp,
|
|
typename std::enable_if<
|
|
std::is_same<typename std::iterator_traits<
|
|
typename Container::iterator>::iterator_category,
|
|
std::random_access_iterator_tag>::value,
|
|
void>::type * = nullptr) {
|
|
std::sort(C.begin(), C.end(), Cmp);
|
|
C.erase(std::unique(C.begin(), C.end()), C.end());
|
|
}
|
|
|
|
/// Returns true if [II, IE) is a sorted and uniqued array. Returns false
|
|
/// otherwise.
|
|
template <typename IterTy>
|
|
inline bool is_sorted_and_uniqued(IterTy II, IterTy IE) {
|
|
using RefTy = typename std::iterator_traits<IterTy>::reference;
|
|
|
|
// The empty list is always sorted and uniqued.
|
|
if (II == IE)
|
|
return true;
|
|
|
|
// The list of one element is always sorted and uniqued.
|
|
auto LastI = II;
|
|
++II;
|
|
if (II == IE)
|
|
return true;
|
|
|
|
// Otherwise, until we reach the end of the list...
|
|
while (II != IE) {
|
|
// If LastI is greater than II then we know that our array is not sorted. If
|
|
// LastI equals II, then we know that our array is not unique. If both of
|
|
// those are conditions are false, then visit the next iterator element.
|
|
if (std::greater_equal<RefTy>()(*LastI, *II)) {
|
|
// Return false otherwise.
|
|
return false;
|
|
}
|
|
|
|
LastI = II;
|
|
++II;
|
|
}
|
|
|
|
// Success!
|
|
return true;
|
|
}
|
|
|
|
template <typename Container>
|
|
inline bool is_sorted_and_uniqued(const Container &C) {
|
|
return is_sorted_and_uniqued(C.begin(), C.end());
|
|
}
|
|
|
|
template <typename Container, typename T, typename BinaryOperation>
|
|
inline T accumulate(const Container &C, T init, BinaryOperation op) {
|
|
return std::accumulate(C.begin(), C.end(), init, op);
|
|
}
|
|
|
|
template <typename Container, typename T>
|
|
inline bool binary_search(const Container &C, const T &value) {
|
|
return std::binary_search(C.begin(), C.end(), value);
|
|
}
|
|
|
|
template <typename Container, typename T, typename BinaryOperation>
|
|
inline bool binary_search(const Container &C, const T &value, BinaryOperation op) {
|
|
return std::binary_search(C.begin(), C.end(), value, op);
|
|
}
|
|
|
|
/// Returns true if the range defined by \p mainBegin ..< \p mainEnd starts with
|
|
/// the same elements as the range defined by \p prefixBegin ..< \p prefixEnd.
|
|
///
|
|
/// This includes cases where the prefix range is empty, as well as when the two
|
|
/// ranges are the same length and contain the same elements.
|
|
template <typename MainInputIterator, typename PrefixInputIterator>
|
|
inline bool hasPrefix(MainInputIterator mainBegin,
|
|
const MainInputIterator mainEnd,
|
|
PrefixInputIterator prefixBegin,
|
|
const PrefixInputIterator prefixEnd) {
|
|
while (prefixBegin != prefixEnd) {
|
|
// If "main" is shorter than "prefix", it does not start with "prefix".
|
|
if (mainBegin == mainEnd)
|
|
return false;
|
|
// If there's a mismatch, "main" does not start with "prefix".
|
|
if (*mainBegin != *prefixBegin)
|
|
return false;
|
|
++prefixBegin;
|
|
++mainBegin;
|
|
}
|
|
// If we checked every element of "prefix", "main" does start with "prefix".
|
|
return true;
|
|
}
|
|
|
|
/// Provides default implementations of !=, <=, >, and >= based on == and <.
|
|
template <typename T>
|
|
class RelationalOperationsBase {
|
|
public:
|
|
friend bool operator>(const T &left, const T &right) {
|
|
return right < left;
|
|
}
|
|
friend bool operator>=(const T &left, const T &right) {
|
|
return !(left < right);
|
|
}
|
|
friend bool operator<=(const T &left, const T &right) {
|
|
return !(right < left);
|
|
}
|
|
friend bool operator!=(const T &left, const T &right) {
|
|
return !(left == right);
|
|
}
|
|
};
|
|
|
|
/// Cast a pointer to \c U to a pointer to a supertype \c T.
|
|
/// Example: Wobulator *w = up_cast<Wobulator>(coloredWobulator)
|
|
/// Useful with ?: where each arm is a different subtype.
|
|
/// If \c U is not a subtype of \c T, the compiler will complain.
|
|
template <typename T, typename U>
|
|
T *up_cast(U *ptr) { return ptr; }
|
|
|
|
/// Removes all runs of values that match \p pred from the range of \p begin
|
|
/// to \p end.
|
|
///
|
|
/// This is similar to std::unique, but std::unique leaves the first value in
|
|
/// place in a run of matching values, whereas this code removes all of them.
|
|
///
|
|
/// \returns The new end iterator for the container. You should erase elements
|
|
/// between this value and the existing end of the container.
|
|
template <typename Iterator, typename BinaryPredicate>
|
|
Iterator removeAdjacentIf(const Iterator first, const Iterator last,
|
|
BinaryPredicate pred) {
|
|
using element_reference_t =
|
|
typename std::iterator_traits<Iterator>::reference;
|
|
|
|
auto nextOverlap = std::adjacent_find(first, last, pred);
|
|
auto insertionPoint = nextOverlap;
|
|
while (nextOverlap != last) {
|
|
// We want to erase *all* the matching elements. There could be three or
|
|
// more of them. Search for the end of the run.
|
|
auto lastOverlapInRun =
|
|
std::adjacent_find(std::next(nextOverlap), last,
|
|
[&pred](element_reference_t left,
|
|
element_reference_t right) -> bool {
|
|
return !pred(left, right);
|
|
});
|
|
// If we get the end iterator back, that means all remaining elements match.
|
|
// If we don't, that means (lastOverlapInRun+1) is part of a different run.
|
|
if (lastOverlapInRun != last)
|
|
++lastOverlapInRun;
|
|
|
|
nextOverlap = std::adjacent_find(lastOverlapInRun, last, pred);
|
|
insertionPoint = std::move(lastOverlapInRun, nextOverlap, insertionPoint);
|
|
}
|
|
|
|
return insertionPoint;
|
|
}
|
|
|
|
namespace detail {
|
|
template <bool...> struct bool_pack;
|
|
} // namespace detail
|
|
|
|
template <bool... b>
|
|
using all_true =
|
|
std::is_same<detail::bool_pack<b..., true>, detail::bool_pack<true, b...>>;
|
|
|
|
/// traits class for checking whether Ts consists only of compound types.
|
|
template <class... Ts>
|
|
using are_all_compound = all_true<std::is_compound<Ts>::value...>;
|
|
|
|
/// Erase all elements in \p c that match the given predicate \p pred.
|
|
// FIXME: Remove this when C++20 is the new baseline.
|
|
template <class Key, class Hash, class KeyEqual, class Alloc, class Pred>
|
|
typename std::unordered_set<Key, Hash, KeyEqual, Alloc>::size_type
|
|
erase_if(std::unordered_set<Key, Hash, KeyEqual, Alloc> &c, Pred pred) {
|
|
auto startingSize = c.size();
|
|
for (auto i = c.begin(), last = c.end(); i != last;) {
|
|
if (pred(*i)) {
|
|
i = c.erase(i);
|
|
} else {
|
|
++i;
|
|
}
|
|
}
|
|
return startingSize - c.size();
|
|
}
|
|
|
|
} // end namespace swift
|
|
|
|
#endif // SWIFT_BASIC_INTERLEAVE_H
|