Utilities#

pw_containers: Generic collections of objects for embedded devices

In addition to containers, this module includes some types and functions for working with containers and the data within them.

pw::containers::FilteredView#

template<typename Container, typename Filter>
class FilteredView#

pw::containers::FilteredView provides a view of a container with only elements that match the specified filter. This class is similar to C++20’s std::ranges::filter_view.

FilteredView works with any container with an incrementable iterator. The back() function currently requires a bidirectional iterator.

To create a FilteredView, pass a container and a filter predicate, which may be any callable type including a function pointer, lambda, or pw::Function.

std::array<int, 99> kNumbers = {3, 1, 4, 1, ...};

for (int n : FilteredView(kNumbers, [](int v) { return v % 2 == 0; })) {
  PW_LOG_INFO("This number is even: %d", n);
}

pw::containers::WrappedIterator#

pw::containers::WrappedIterator is a class that makes it easy to wrap an existing iterator type. It reduces boilerplate by providing operator++, operator--, operator==, operator!=, and the standard iterator aliases (difference_type, value_type, etc.). It does not provide the dereference operator; that must be supplied by a derived class.

Example#

To use it, create a class that derives from WrappedIterator and define operator*() and operator->() as appropriate. The new iterator might apply a transformation to or access a member of the values provided by the original iterator. The following example defines an iterator that multiplies the values in an array by 2.

 1using pw::containers::WrappedIterator;
 2
 3// Multiplies values in a std::array by two.
 4class DoubleIterator : public WrappedIterator<DoubleIterator, const int*, int> {
 5 public:
 6  constexpr DoubleIterator(const int* it) : WrappedIterator(it) {}
 7  int operator*() const { return value() * 2; }
 8};
 9
10// Returns twice the sum of the elements in a array of integers.
11template <size_t kArraySize>
12int DoubleSum(const std::array<int, kArraySize>& c) {
13  int sum = 0;
14  for (DoubleIterator it(c.data()); it != DoubleIterator(c.data() + c.size());
15       ++it) {
16    // The iterator yields doubles instead of the original values.
17    sum += *it;
18  }
19  return sum;
20}

Basic functional programming#

WrappedIterator may be used in concert with FilteredView to create a view that iterates over a matching values in a container and applies a transformation to the values. For example, it could be used with FilteredView to filter a list of packets and yield only one field from the packet.

The combination of FilteredView and WrappedIterator provides some basic functional programming features similar to (though much more cumbersome than) generator expressions (or filter/map) in Python or streams in Java 8. WrappedIterator and FilteredView require no memory allocation, which is helpful when memory is too constrained to process the items into a new container.

pw::containers::to_array#

pw::containers::to_array is a C++14-compatible implementation of C++20’s std::to_array. In C++20, it is an alias for std::to_array. It converts a C array to a std::array.

pw_containers/algorithm.h#

This header file provides container-based versions of algorithmic functions within the C++ standard library, based on pw_containers. 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)

template<typename C, typename Pred>
bool pw::containers::AllOf(const C &c, Pred &&pred)#

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 pw::containers::AnyOf(const C &c, Pred &&pred)#

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 pw::containers::NoneOf(const C &c, Pred &&pred)#

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 Function>
std::decay_t<Function> pw::containers::ForEach(C &&c, Function &&f)#

Container-based version of the <algorithm> std::for_each() function to apply a function to a container’s elements.

template<typename C, typename T>
internal_algorithm::ContainerIter<C> pw::containers::Find(C &c, T &&value)#

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 Pred>
internal_algorithm::ContainerIter<C> pw::containers::FindIf(C &c, Pred &&pred)#

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> pw::containers::FindIfNot(C &c, Pred &&pred)#

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 Sequence1, typename Sequence2>
internal_algorithm::ContainerIter<Sequence1> pw::containers::FindEnd(
Sequence1 &sequence,
Sequence2 &subsequence,
)#

Container-based version of the <algorithm> std::find_end() function to find the last subsequence within a container.

template<typename Sequence1, typename Sequence2, typename BinaryPredicate>
internal_algorithm::ContainerIter<Sequence1> pw::containers::FindEnd(
Sequence1 &sequence,
Sequence2 &subsequence,
BinaryPredicate &&pred,
)#

Overload of FindEnd() for using a predicate evaluation other than == as the function’s test condition.

template<typename C1, typename C2>
internal_algorithm::ContainerIter<C1> pw::containers::FindFirstOf(
C1 &container,
C2 &options,
)#

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, typename BinaryPredicate>
internal_algorithm::ContainerIter<C1> pw::containers::FindFirstOf(
C1 &container,
C2 &options,
BinaryPredicate &&pred,
)#

Overload of FindFirstOf() for using a predicate evaluation other than == as the function’s test condition.

template<typename Sequence>
internal_algorithm::ContainerIter<Sequence> pw::containers::AdjacentFind(Sequence &sequence)#

Container-based version of the <algorithm> std::adjacent_find() function to find equal adjacent elements within a container.

template<typename Sequence, typename BinaryPredicate>
internal_algorithm::ContainerIter<Sequence> pw::containers::AdjacentFind(
Sequence &sequence,
BinaryPredicate &&pred,
)#

Overload of AdjacentFind() for using a predicate evaluation other than == as the function’s test condition.

template<typename C, typename T>
internal_algorithm::ContainerDifferenceType<const C> pw::containers::Count(
const C &c,
T &&value,
)#

Container-based version of the <algorithm> std::count() function to count values that match within a container.

template<typename C, typename Pred>
internal_algorithm::ContainerDifferenceType<const C> pw::containers::CountIf(
const C &c,
Pred &&pred,
)#

Container-based version of the <algorithm> std::count_if() function to count values matching a condition within a container.

template<typename C1, typename C2>
internal_algorithm::ContainerIterPairType<C1, C2> pw::containers::Mismatch(C1 &c1, C2 &c2)#

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, typename BinaryPredicate>
internal_algorithm::ContainerIterPairType<C1, C2> pw::containers::Mismatch(
C1 &c1,
C2 &c2,
BinaryPredicate pred,
)#

Overload of Mismatch() for using a predicate evaluation other than == as the function’s test condition. Applies predto the first N elements of c1 and c2, where N = min(size(c1), size(c2)).

template<typename C1, typename C2>
bool pw::containers::Equal(const C1 &c1, const C2 &c2)#

Container-based version of the <algorithm> std::equal() function to test whether two containers are equal.

vector v1 = <1, 2, 3>;
vector v2 = <1, 2, 3, 4>;
EXPECT_TRUE(equal(std::begin(v1), std::end(v1), std::begin(v2)));
EXPECT_FALSE(Equal(v1, v2));

Note

The semantics of Equal() are slightly different than those of std::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.

template<typename C1, typename C2, typename BinaryPredicate>
bool pw::containers::Equal(
const C1 &c1,
const C2 &c2,
BinaryPredicate &&pred,
)#

Overload of Equal() for using a predicate evaluation other than == as the function’s test condition.

template<typename C1, typename C2>
bool pw::containers::IsPermutation(const C1 &c1, const C2 &c2)#

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, typename BinaryPredicate>
bool pw::containers::IsPermutation(
const C1 &c1,
const C2 &c2,
BinaryPredicate &&pred,
)#

Overload of IsPermutation() for using a predicate evaluation other than == as the function’s test condition.

template<typename Sequence1, typename Sequence2>
internal_algorithm::ContainerIter<Sequence1> pw::containers::Search(
Sequence1 &sequence,
Sequence2 &subsequence,
)#

Container-based version of the <algorithm> std::search() function to search a container for a subsequence.

template<typename Sequence1, typename Sequence2, typename BinaryPredicate>
internal_algorithm::ContainerIter<Sequence1> pw::containers::Search(
Sequence1 &sequence,
Sequence2 &subsequence,
BinaryPredicate &&pred,
)#

Overload of Search() for using a predicate evaluation other than == as the function’s test condition.

template<typename Sequence, typename Size, typename T>
internal_algorithm::ContainerIter<Sequence> pw::containers::SearchN(
Sequence &sequence,
Size count,
T &&value,
)#

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, typename BinaryPredicate>
internal_algorithm::ContainerIter<Sequence> pw::containers::SearchN(
Sequence &sequence,
Size count,
T &&value,
BinaryPredicate &&pred,
)#

Overload of SearchN() for using a predicate evaluation other than == as the function’s test condition.