#include "common.hpp"
int main() {
// # min
//
// # max
{
assert(std::min(0.1, 0.2) == 0.1);
assert(std::max(0.1, 0.2) == 0.2);
}
// # sort
{
std::vector v{2, 0, 1};
std::sort(v.begin(), v.end());
std::vector v1 = {0, 1, 2};
assert((v == std::vector{0, 1, 2}));
}
// # reverse
{
std::vector v{2, 0, 1};
std::reverse(v.begin(), v.end());
assert((v == std::vector{1, 0, 2}));
}
// # swap
//
// Does things equivalent to:
//
// template void swap (T& a, T& b)
// {
// T c(a); a=b; b=c;
// }
//
// However stdlib can specialize it to do operations more efficiently.
//
// Some stdlib classes implement swap as a method.
//
// Particularly important because of the copy and swap idiom.
// # random_shuffle
{
std::vector v{2, 0, 1};
std::random_shuffle(v.begin(), v.end());
}
#if __cplusplus >= 201703L
// # sample
//
// https://stackoverflow.com/questions/6942273/how-to-get-a-random-element-from-a-c-container/42484107#42484107
{
const std::vector in{1, 2, 3, 5, 7};
std::vector out;
size_t nelems = 3;
std::sample(in.begin(), in.end(), std::back_inserter(out),
nelems, std::mt19937{std::random_device{}()});
std::set in_set{std::begin(in), std::end(in)};
std::set out_set{std::begin(out), std::end(out)};
// The sample elements are distinct.
assert(out_set.size() == nelems);
// The sample elements came from the input.
std::set intersect;
std::set_intersection(
in.begin(), in.end(), out.begin(), out.end(),
std::inserter(intersect, intersect.begin())
);
assert(intersect.size() == nelems);
//for (auto i : out)
// std::cout << i << std::endl;
}
#endif
// # equal
//
// Compares ranges of two containers.
//
// Vs memcmp:
// https://stackoverflow.com/questions/39262496/why-is-stdequal-much-slower-than-a-hand-rolled-loop-for-two-small-stdarray
{
std::vector v1{0, 1, 2 };
std::vector v2{ 1, 2, 3};
assert(std::equal(v1.begin() + 1, v1.end(), v2.begin()));
}
// # copy
//
// Vs memcpy: can compile down to an assembly optimized memcpy for arrays apparently, so just always use this:
// https://stackoverflow.com/questions/4707012/is-it-better-to-use-stdmemcpy-or-stdcopy-in-terms-to-performance
//
// Handles overlap in the correct direction: https://stackoverflow.com/questions/1952972/does-stdcopy-handle-overlapping-ranges/53487672#53487672
{
// Newbie basic class usage.
{
std::vector v{0, 1, 2, 3, 4};
std::vector v2(v.size(), v.size());
std::copy(v.begin() + 1, v.end() - 1, v2.begin() + 2);
assert(v2 == std::vector({5, 5, 1, 2, 3}));
}
// # std::begin
//
// # std::end
//
// Array usage.
//
// https://stackoverflow.com/questions/7593086/why-use-non-member-begin-and-end-functions-in-c11
{
int v1[]{0, 1, 2, 3, 4};
int v2[]{5, 5, 5, 5, 5};
int v3[]{5, 5, 1, 2, 3};
std::copy(std::begin(v1) + 1, std::end(v1) - 1, std::begin(v2) + 2);
assert(std::equal(std::begin(v2), std::end(v2), std::begin(v3)));
// Pointer usage.
auto p1 = &v1[0];
auto p2 = &v2[0];
auto p3 = &v3[0];
std::copy(p1 + 1, p1 + 4, p2 + 2);
// Nah. Why.
// https://stackoverflow.com/questions/26909429/stdbegin-and-stdend-not-working-with-pointers-and-reference-why
//std::copy(std::begin(p1) + 1, std::begin(p1) + 4, std::begin(p2) + 2);
}
// Therefore, a more elegant class approach that uses exact same syntax as arrays.
{
std::vector v1{0, 1, 2, 3, 4};
std::vector v2{5, 5, 5, 5, 5};
std::vector v3{5, 5, 1, 2, 3};
std::copy(std::begin(v1) + 1, std::end(v1) - 1, std::begin(v2) + 2);
assert(std::equal(std::begin(v2), std::end(v2), std::begin(v3)));
}
}
// # accumulate
//
// Sum over range with operator+
//
// Also has functional versions http://www.cplusplus.com/reference/numeric/accumulate/
{
{
std::vector v{2, 0, 1};
assert(std::accumulate(v.begin(), v.end(), 0) == 3);
assert(std::accumulate(v.begin(), v.end(), 10) == 13);
}
// The functional version can be used to add up arrays.
// http://stackoverflow.com/questions/26941943/how-to-add-all-numbers-in-an-array-c
{
int a[] = {1, 3, 5, 7, 9};
assert(std::accumulate(std::begin(a), std::end(a), 0, std::plus()) == 25);
}
}
// # find
//
// Return iterator to first found element.
{
std::vector v{2,0,1};
unsigned int pos;
pos = std::find(v.begin(), v.end(), 0) - v.begin();
assert(pos == 1);
pos = std::find(v.begin(), v.end(), 1) - v.begin();
assert(pos == 2);
pos = std::find(v.begin(), v.end(), 2) - v.begin();
assert(pos == 0);
pos = std::find(v.begin(), v.end(), 3) - v.begin(); //end() returned
assert(pos == v.size());
}
// # find_if
//
// Like find, but using an arbitrary condition on each element instead of equality.
//
// Consider usage with C++11 lambdas and functional.
{
std::vector v{2, 0, 1};
assert(std::find_if (v.begin(), v.end(), odd) == --v.end());
}
// # binary_search
//
// Container must be already sorted.
//
// Log complexity.
//
// Only states if the element is present or not, but does not get its position.
//
// If you want to get the position of those items, use `equal_range`, `lower_bound` or `upper_bound`.
{
std::vector v{0, 1, 2};
assert(std::binary_search(v.begin(), v.end(), 1) == true);
assert(std::binary_search(v.begin(), v.end(), 3) == false);
assert(std::binary_search(v.begin(), v.end() - 1, 2) == false);
}
// # lower_bound
//
// Finds first element in container which is not less than val.
{
std::vector v{0, 2, 3};
auto it = std::lower_bound(v.begin(), v.end(), 1);
assert(it - v.begin() == 1);
}
// # upper_bound
//
// Finds first element in container is greater than val.
{
std::vector v{0, 1, 2};
auto it = std::upper_bound(v.begin(), v.end(), 1);
assert(it - v.begin() == 2);
}
// # equal_range
//
// Finds first and last location of a value iniside a ranged container.
//
// Return values are the same as lower_bound and upper_bound.
//
// log complexity.
{
std::vector v{0, 1, 1, 2};
std::vector::iterator begin, end;
std::tie(begin, end) = std::equal_range(v.begin(), v.end(), 1);
assert(begin - v.begin() == 1);
assert(end - v.begin() == 3);
}
// # count
{
std::vector v{2,1,2};
assert(std::count(v.begin(), v.end(), 0) == 0);
assert(std::count(v.begin(), v.end(), 1) == 1);
assert(std::count(v.begin(), v.end(), 2) == 2);
}
// # max_element
//
// # min_element
{
std::vector v{2,0,1};
assert(*std::max_element(v.begin(), v.end()) == 2);
assert(*std::min_element(v.begin(), v.end()) == 0);
}
// # advance
//
// Advance iterator by given number.
//
// If random access, simply adds + N.
//
// Else, calls `++` N times.
//
// Advantage over `+`: only random access containers support `+`,
// but this works for any container, allowing one to write more general code.
//
// Beware however that this operation will be slow for non random access containers.
{
std::vector v{0, 1, 2};
auto it = v.begin();
std::advance(it, 2);
assert(*it == 2);
}
#if __cplusplus >= 201103L
// # next
//
// Same as advance, but returns a new iterator instead of modifying the old one.
{
std::vector v{0, 1, 2};
auto it(v.begin());
auto itNext = std::next(it, 2);
assert(*it == 0);
assert(*itNext == 2);
}
#endif
// # remove_if
//
// Remove if a given function evaluates to true on an element.
{
{
std::vector v{0, 1, 2, 3, 4};
auto end = v.end();
v.erase(std::remove_if(v.begin(), end, odd), end);
assert((v == std::vector{0, 2, 4}));
}
// Common combo with lambdas
{
std::vector v{0, 1, 2, 3, 4};
auto end = v.end();
v.erase(
std::remove_if(
v.begin(),
end,
[](int i) {return i % 2 == 1;}
),
end
);
assert((v == std::vector{0, 2, 4}));
}
}
// # transform
//
// Replace elements by output of a function.
{
std::vector v{0, 1, 2};
std::transform(
v.begin(),
v.end(),
v.begin(),
[](int i) {return i * i;}
);
assert((v == std::vector{0, 1, 4}));
}
}