blob: e8e81efcf718b42512952bb0363bcc02f860b366 [file] [log] [blame]
// Copyright 2022 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
//
// -----------------------------------------------------------------------------
// File: algorithm.h
// -----------------------------------------------------------------------------
//
// This header file provides Container-based versions of algorithmic functions
// within the C++ standard library, based on a subset of
// absl/algorithm/container.h. The following standard library sets of functions
// are covered within this file:
//
// * <algorithm> functions
//
// The standard library functions operate on iterator ranges; the functions
// within this API operate on containers, though many return iterator ranges.
//
// All functions within this API are CamelCase instead of their std::
// snake_case counterparts. Calls such as `pw::containers::Foo(container, ...)
// are equivalent to std:: functions such as
// `std::foo(std::begin(cont), std::end(cont), ...)`. Functions that act on
// iterators but not conceptually on iterator ranges (e.g. `std::iter_swap`)
// have no equivalent here.
//
// For template parameter and variable naming, `C` indicates the container type
// to which the function is applied, `Pred` indicates the predicate object type
// to be used by the function and `T` indicates the applicable element type.
//
// This was forked from
// https://cs.opensource.google/abseil/abseil-cpp/+/main:absl/algorithm/algorithm.h;drc=12bc53e0318d80569270a5b26ccbc62b52022b89
#pragma once
#include <algorithm>
#include <utility>
#include "pw_containers/internal/algorithm_internal.h"
namespace pw::containers {
//------------------------------------------------------------------------------
// <algorithm> Non-modifying sequence operations
//------------------------------------------------------------------------------
// AllOf()
//
// Container-based version of the <algorithm> `std::all_of()` function to
// test if all elements within a container satisfy a condition.
template <typename C, typename Pred>
bool AllOf(const C& c, Pred&& pred) {
return std::all_of(std::begin(c), std::end(c), std::forward<Pred>(pred));
}
// AnyOf()
//
// Container-based version of the <algorithm> `std::any_of()` function to
// test if any element in a container fulfills a condition.
template <typename C, typename Pred>
bool AnyOf(const C& c, Pred&& pred) {
return std::any_of(std::begin(c), std::end(c), std::forward<Pred>(pred));
}
// NoneOf()
//
// Container-based version of the <algorithm> `std::none_of()` function to
// test if no elements in a container fulfill a condition.
template <typename C, typename Pred>
bool NoneOf(const C& c, Pred&& pred) {
return std::none_of(std::begin(c), std::end(c), std::forward<Pred>(pred));
}
// ForEach()
//
// Container-based version of the <algorithm> `std::for_each()` function to
// apply a function to a container's elements.
template <typename C, typename Function>
std::decay_t<Function> ForEach(C&& c, Function&& f) {
return std::for_each(std::begin(c), std::end(c), std::forward<Function>(f));
}
// Find()
//
// Container-based version of the <algorithm> `std::find()` function to find
// the first element containing the passed value within a container value.
template <typename C, typename T>
internal_algorithm::ContainerIter<C> Find(C& c, T&& value) {
return std::find(std::begin(c), std::end(c), std::forward<T>(value));
}
// FindIf()
//
// Container-based version of the <algorithm> `std::find_if()` function to find
// the first element in a container matching the given condition.
template <typename C, typename Pred>
internal_algorithm::ContainerIter<C> FindIf(C& c, Pred&& pred) {
return std::find_if(std::begin(c), std::end(c), std::forward<Pred>(pred));
}
// FindIfNot()
//
// Container-based version of the <algorithm> `std::find_if_not()` function to
// find the first element in a container not matching the given condition.
template <typename C, typename Pred>
internal_algorithm::ContainerIter<C> FindIfNot(C& c, Pred&& pred) {
return std::find_if_not(std::begin(c), std::end(c), std::forward<Pred>(pred));
}
// FindEnd()
//
// Container-based version of the <algorithm> `std::find_end()` function to
// find the last subsequence within a container.
template <typename Sequence1, typename Sequence2>
internal_algorithm::ContainerIter<Sequence1> FindEnd(Sequence1& sequence,
Sequence2& subsequence) {
return std::find_end(std::begin(sequence),
std::end(sequence),
std::begin(subsequence),
std::end(subsequence));
}
// Overload of FindEnd() for using a predicate evaluation other than `==` as
// the function's test condition.
template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
internal_algorithm::ContainerIter<Sequence1> FindEnd(Sequence1& sequence,
Sequence2& subsequence,
BinaryPredicate&& pred) {
return std::find_end(std::begin(sequence),
std::end(sequence),
std::begin(subsequence),
std::end(subsequence),
std::forward<BinaryPredicate>(pred));
}
// FindFirstOf()
//
// Container-based version of the <algorithm> `std::find_first_of()` function to
// find the first element within the container that is also within the options
// container.
template <typename C1, typename C2>
internal_algorithm::ContainerIter<C1> FindFirstOf(C1& container, C2& options) {
return std::find_first_of(std::begin(container),
std::end(container),
std::begin(options),
std::end(options));
}
// Overload of FindFirstOf() for using a predicate evaluation other than
// `==` as the function's test condition.
template <typename C1, typename C2, typename BinaryPredicate>
internal_algorithm::ContainerIter<C1> FindFirstOf(C1& container,
C2& options,
BinaryPredicate&& pred) {
return std::find_first_of(std::begin(container),
std::end(container),
std::begin(options),
std::end(options),
std::forward<BinaryPredicate>(pred));
}
// AdjacentFind()
//
// Container-based version of the <algorithm> `std::adjacent_find()` function to
// find equal adjacent elements within a container.
template <typename Sequence>
internal_algorithm::ContainerIter<Sequence> AdjacentFind(Sequence& sequence) {
return std::adjacent_find(std::begin(sequence), std::end(sequence));
}
// Overload of AdjacentFind() for using a predicate evaluation other than
// `==` as the function's test condition.
template <typename Sequence, typename BinaryPredicate>
internal_algorithm::ContainerIter<Sequence> AdjacentFind(
Sequence& sequence, BinaryPredicate&& pred) {
return std::adjacent_find(std::begin(sequence),
std::end(sequence),
std::forward<BinaryPredicate>(pred));
}
// Count()
//
// Container-based version of the <algorithm> `std::count()` function to count
// values that match within a container.
template <typename C, typename T>
internal_algorithm::ContainerDifferenceType<const C> Count(const C& c,
T&& value) {
return std::count(std::begin(c), std::end(c), std::forward<T>(value));
}
// CountIOf()
//
// Container-based version of the <algorithm> `std::count_if()` function to
// count values matching a condition within a container.
template <typename C, typename Pred>
internal_algorithm::ContainerDifferenceType<const C> CountIf(const C& c,
Pred&& pred) {
return std::count_if(std::begin(c), std::end(c), std::forward<Pred>(pred));
}
// Mismatch()
//
// Container-based version of the <algorithm> `std::mismatch()` function to
// return the first element where two ordered containers differ. Applies `==` to
// the first N elements of `c1` and `c2`, where N = min(size(c1), size(c2)).
template <typename C1, typename C2>
internal_algorithm::ContainerIterPairType<C1, C2> Mismatch(C1& c1, C2& c2) {
auto first1 = std::begin(c1);
auto last1 = std::end(c1);
auto first2 = std::begin(c2);
auto last2 = std::end(c2);
for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
// Negates equality because Cpp17EqualityComparable doesn't require clients
// to overload both `operator==` and `operator!=`.
if (!(*first1 == *first2)) {
break;
}
}
return std::make_pair(first1, first2);
}
// Overload of Mismatch() for using a predicate evaluation other than `==` as
// the function's test condition. Applies `pred`to the first N elements of `c1`
// and `c2`, where N = min(size(c1), size(c2)).
template <typename C1, typename C2, typename BinaryPredicate>
internal_algorithm::ContainerIterPairType<C1, C2> Mismatch(
C1& c1, C2& c2, BinaryPredicate pred) {
auto first1 = std::begin(c1);
auto last1 = std::end(c1);
auto first2 = std::begin(c2);
auto last2 = std::end(c2);
for (; first1 != last1 && first2 != last2; ++first1, (void)++first2) {
if (!pred(*first1, *first2)) {
break;
}
}
return std::make_pair(first1, first2);
}
// Equal()
//
// Container-based version of the <algorithm> `std::equal()` function to
// test whether two containers are equal.
//
// NOTE: the semantics of Equal() are slightly different than those of
// equal(): while the latter iterates over the second container only up to the
// size of the first container, Equal() also checks whether the container
// sizes are equal. This better matches expectations about Equal() based on
// its signature.
//
// Example:
// vector v1 = <1, 2, 3>;
// vector v2 = <1, 2, 3, 4>;
// equal(std::begin(v1), std::end(v1), std::begin(v2)) returns true
// Equal(v1, v2) returns false
template <typename C1, typename C2>
bool Equal(const C1& c1, const C2& c2) {
return ((std::size(c1) == std::size(c2)) &&
std::equal(std::begin(c1), std::end(c1), std::begin(c2)));
}
// Overload of Equal() for using a predicate evaluation other than `==` as
// the function's test condition.
template <typename C1, typename C2, typename BinaryPredicate>
bool Equal(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
return ((std::size(c1) == std::size(c2)) &&
std::equal(std::begin(c1),
std::end(c1),
std::begin(c2),
std::forward<BinaryPredicate>(pred)));
}
// IsPermutation()
//
// Container-based version of the <algorithm> `std::is_permutation()` function
// to test whether a container is a permutation of another.
template <typename C1, typename C2>
bool IsPermutation(const C1& c1, const C2& c2) {
using std::begin;
using std::end;
return c1.size() == c2.size() &&
std::is_permutation(begin(c1), end(c1), begin(c2));
}
// Overload of IsPermutation() for using a predicate evaluation other than
// `==` as the function's test condition.
template <typename C1, typename C2, typename BinaryPredicate>
bool IsPermutation(const C1& c1, const C2& c2, BinaryPredicate&& pred) {
using std::begin;
using std::end;
return c1.size() == c2.size() &&
std::is_permutation(begin(c1),
end(c1),
begin(c2),
std::forward<BinaryPredicate>(pred));
}
// Search()
//
// Container-based version of the <algorithm> `std::search()` function to search
// a container for a subsequence.
template <typename Sequence1, typename Sequence2>
internal_algorithm::ContainerIter<Sequence1> Search(Sequence1& sequence,
Sequence2& subsequence) {
return std::search(std::begin(sequence),
std::end(sequence),
std::begin(subsequence),
std::end(subsequence));
}
// Overload of Search() for using a predicate evaluation other than
// `==` as the function's test condition.
template <typename Sequence1, typename Sequence2, typename BinaryPredicate>
internal_algorithm::ContainerIter<Sequence1> Search(Sequence1& sequence,
Sequence2& subsequence,
BinaryPredicate&& pred) {
return std::search(std::begin(sequence),
std::end(sequence),
std::begin(subsequence),
std::end(subsequence),
std::forward<BinaryPredicate>(pred));
}
// SearchN()
//
// Container-based version of the <algorithm> `std::search_n()` function to
// search a container for the first sequence of N elements.
template <typename Sequence, typename Size, typename T>
internal_algorithm::ContainerIter<Sequence> SearchN(Sequence& sequence,
Size count,
T&& value) {
return std::search_n(
std::begin(sequence), std::end(sequence), count, std::forward<T>(value));
}
// Overload of SearchN() for using a predicate evaluation other than
// `==` as the function's test condition.
template <typename Sequence,
typename Size,
typename T,
typename BinaryPredicate>
internal_algorithm::ContainerIter<Sequence> SearchN(Sequence& sequence,
Size count,
T&& value,
BinaryPredicate&& pred) {
return std::search_n(std::begin(sequence),
std::end(sequence),
count,
std::forward<T>(value),
std::forward<BinaryPredicate>(pred));
}
} // namespace pw::containers