|
Simple C++ Algorithms
|
Classes | |
| class | slice_of |
the underlying type returned by slice() representing a subset of a container More... | |
| class | const_slice_of |
| const variation of slice_of More... | |
Functions | |
| template<typename C > | |
| size_t | size (C &&c) |
return an iterable container's size, regardless if it implements a size() method More... | |
| template<typename C > | |
| auto | pointers (C &c) |
| copy the addresses of elements in a container to a new container More... | |
| template<typename C > | |
| auto | pointers (const C &c) |
| template<typename C > | |
| auto | values (C &&c) |
| return a container of deep value copies (never pointers) from a container of values or pointers More... | |
| template<typename C > | |
| auto | slice (C &&c, size_t idx, size_t len) |
create a slice_of object from a container which allows iteration over a subset of another container More... | |
| template<typename C > | |
| auto | slice (const C &c, size_t idx, size_t len) |
create a const_slice_of object from a container which allows iteration over a subset of another container More... | |
| template<typename C > | |
| auto | slice (C &c, size_t idx, size_t len) |
create a const_slice_of object from a container which allows iteration over a subset of another container More... | |
| template<typename C > | |
| auto | mslice (C &&c, size_t idx, size_t len) |
create a mutable slice_of object which allows iteration of a subset of another container More... | |
| template<typename C > | |
| auto | mslice (C &c, size_t idx, size_t len) |
| template<typename C , typename C2 , typename... Cs> | |
| auto | group (C &&c, C2 &&c2, Cs &&... cs) |
| assemble a container containing all elements of two or more containers More... | |
| template<typename C > | |
| auto | reverse (C &&c) |
| return a container where the order of elements is the reverse of the input container More... | |
| template<typename C , typename F > | |
| auto | sort (C &&c, F &&cmp) |
| return a container whose elements are sorted based on a comparison Callable More... | |
| template<typename F , typename C > | |
| auto | filter (F &&f, C &&c) |
| return a filtered container of elements More... | |
| template<typename F , typename C , typename... Cs> | |
| auto | map (F &&f, C &&c, Cs &&... cs) |
| evaluate function with the elements of containers grouped by index and return a container filled with the results of each function call More... | |
| template<typename F , typename Result , typename C , typename... Cs> | |
| auto | fold (F &&f, Result &&init, C &&c, Cs &&... cs) |
| perform a calculation on the elements of containers grouped by index More... | |
| template<typename F , typename C , typename... Cs> | |
| void | each (F &&f, C &&c, Cs &&... cs) |
| evaluate function with the elements of containers grouped by index More... | |
| template<typename F , typename C , typename... Cs> | |
| bool | all (F &&f, C &&c, Cs &&... cs) |
evaluate if a function returns true with all the elements of containers grouped by index More... | |
| template<typename F , typename C , typename... Cs> | |
| bool | some (F &&f, C &&c, Cs &&... cs) |
evaluate if a function returns true with at least one of the elements of containers grouped by index More... | |
A NOTE ON API DESIGN
As a note, much of the complexity of these templates is caused by more effort being put into usability, rather than implementing minimalist algorithms.
The algorithms defined in the c++ standard library typically deal with iterators rather than containers. Instead, this library's data processing algorithms accept iterable objects/containers as arguments and return iterable containers. This leaves the smallest amount of work for the user and reduces risk of exception throwing bugs. This also helps the user avoid making trivial efficiency mistakes when writing algorithm code.
In c++, vectors typically outperform other container types, so algorithms in this library convert to them internally and return them as the result.
PROVIDED ALGORITHMS
The algorithms in this header library are intended for general usecases and composability (the results of one algorithm can often be used as an argument in another). They are not exhaustive, but should cover the majority of simple data processing usecases.
Algorithms and Objects provided by this header:
size() method| bool sca::all | ( | F && | f, |
| C && | c, | ||
| Cs &&... | cs | ||
| ) |
evaluate if a function returns true with all the elements of containers grouped by index
Evaluation ends when traversible element in container c has been iterated.
Each container can contain a different value type as long as the value type can be passed to the function.
| f | a predicate function applied to elements of input containers |
| c | the first container whose elements will have f applied to |
| cs | the optional remaining containers whose elements will have f applied to |
true if f returns true for all iterated elements, else false | void sca::each | ( | F && | f, |
| C && | c, | ||
| Cs &&... | cs | ||
| ) |
evaluate function with the elements of containers grouped by index
Evaluation ends when traversible element in container c has been iterated.
No value is returned from this function, any changes are side effects of executing the function.
Each container can contain a different value type as long as the value type can be passed to the function.
| f | a function to call |
| c | the first container |
| cs... | the remaining containers |
| auto sca::filter | ( | F && | f, |
| C && | c | ||
| ) |
return a filtered container of elements
| f | a predicate function which gets applied to each element of the input container |
| c | the input container |
true | auto sca::fold | ( | F && | f, |
| Result && | init, | ||
| C && | c, | ||
| Cs &&... | cs | ||
| ) |
perform a calculation on the elements of containers grouped by index
Evaluation ends when every traversible element in container c has been iterated.
The argument function must accept the current calculated value as its first argument, and the elements of the argument containers stored in the current iteration. The value returned by the function becomes the new current calculated value, which be subsequently passed as an argument to the calculation function in the next iteration. When iteration completes fold() will return the final return value of the calculation function.
Each container can contain a different value type as long as the value type can be passed to the calculation function.
| f | the calculation function |
| init | the initial value of the calculation being performed |
| c | the first container whose elements will be calculated |
| cs | optional additional containers whose elements will also be calculated |
| auto sca::group | ( | C && | c, |
| C2 && | c2, | ||
| Cs &&... | cs | ||
| ) |
assemble a container containing all elements of two or more containers
| c | the first container whose elements should be grouped together with the others |
| c2 | the second container whose elements should be grouped together with the others |
| cs | optional, additional containers whose elements should be grouped together with the others |
| auto sca::map | ( | F && | f, |
| C && | c, | ||
| Cs &&... | cs | ||
| ) |
evaluate function with the elements of containers grouped by index and return a container filled with the results of each function call
Evaluation begins at index 0, and ends when every traversible element in container c has been iterated. It returns an std::vector<T> (where T is the deduced return value of user function f) containing the result of every invocation of user function f.
Each container can contain a different value type as long as the value type can be passed to the function.
| f | a function to call |
| c | the first container |
| cs... | the remaining containers |
| auto sca::mslice | ( | C && | c, |
| size_t | idx, | ||
| size_t | len | ||
| ) |
create a mutable slice_of object which allows iteration of a subset of another container
This is the mutable reference implementation of the algorithm, returning a slice_of. This can be dangerous when used inline carelessly, as it will be treated as an rvalue by algorithms causing unexpected swaps. Best usage is to explicitly save the result of this method as an lvalue before usage:
| idx | starting index of the range of values |
| len | length of range represented by slice |
| c | container to take slice of |
| auto sca::pointers | ( | C & | c | ) |
copy the addresses of elements in a container to a new container
This a helper mechanism for ensuring all calculations on data are by reference to a specific set of values. This can be used to simplify operations on large sets of data so that downstream calculations like filter() and map() never have to consider reference value categories.
This algorithm also useful when sorting data in-place without modifying the source data's container positions (std::sort()), while still being able to reference the original data within the sorted set. Furthermore, any kind of sort operation when applied to pointers is very fast.
It may be beneficial to apply pointers() to the result of slice(), to only operate on the necessary subset of elements.
| c | container of elements |
| auto sca::reverse | ( | C && | c | ) |
return a container where the order of elements is the reverse of the input container
| c | an input container |
| size_t sca::size | ( | C && | c | ) |
return an iterable container's size, regardless if it implements a size() method
| c | a container |
| auto sca::slice | ( | C && | c, |
| size_t | idx, | ||
| size_t | len | ||
| ) |
create a slice_of object from a container which allows iteration over a subset of another container
This implementation only gets selected when the input container is an rvalue. The slice_of object will keep the original container in memory as long as the slice_of object exists.
Typical usecase is to use auto as the returned variable's type:
Or to use the slice inline:
| idx | starting index of the range of values |
| len | length of range represented by slice |
| c | container to take slice of |
| auto sca::slice | ( | C & | c, |
| size_t | idx, | ||
| size_t | len | ||
| ) |
create a const_slice_of object from a container which allows iteration over a subset of another container
This is the lvalue reference implementation. Must return a const_slice_of in order to prevent inline uses of the slice() from treating the returned object as an rvalue. If a mutable slice_of object is required, call mslice() instead.
| auto sca::slice | ( | const C & | c, |
| size_t | idx, | ||
| size_t | len | ||
| ) |
create a const_slice_of object from a container which allows iteration over a subset of another container
This is the const lvalue reference implementation.
| bool sca::some | ( | F && | f, |
| C && | c, | ||
| Cs &&... | cs | ||
| ) |
evaluate if a function returns true with at least one of the elements of containers grouped by index
Evaluation ends when traversible element in container c has been iterated.
Each container can contain a different value type as long as the value type can be passed to the function.
| f | a predicate function applied to elements of input containers |
| c | the first container whose elements will have f applied to |
| cs | the optional remaining containers whose elements will have f applied to |
true if f returns true for at least one iterated element, else false | auto sca::sort | ( | C && | c, |
| F && | cmp | ||
| ) |
return a container whose elements are sorted based on a comparison Callable
| c | container whose elements will be copied and sorted in the output |
| cmp | a function which must accept two elements from the container and return a boolean |
| auto sca::values | ( | C && | c | ) |
return a container of deep value copies (never pointers) from a container of values or pointers
If input argument is a container of pointers, those pointers are dereferenced before copying.
Useful when operations on the result of a call to sca::pointers() are complete and a copy of pointed values is required. It is also useful when copying an arbitrary container or slice into a vector.
| c | a container of values or pointers |