You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
440 lines
11 KiB
440 lines
11 KiB
// -*- c++ -*-
|
|
|
|
#pragma once
|
|
|
|
#include <litc.h>
|
|
#include <utility>
|
|
|
|
namespace std {
|
|
// [C++11 25.2] Non-modifying sequence operations
|
|
struct __less
|
|
{
|
|
template <class T> bool operator()(const T& x, const T& y) const
|
|
{
|
|
return x < y;
|
|
}
|
|
};
|
|
|
|
template <class InputIterator, class Predicate>
|
|
bool all_of(InputIterator first, InputIterator last, Predicate pred)
|
|
{
|
|
for (; first != last; ++first)
|
|
if (!pred(*first))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
template <class InputIterator, class Predicate>
|
|
bool any_of(InputIterator first, InputIterator last, Predicate pred)
|
|
{
|
|
for (; first != last; ++first)
|
|
if (pred(*first))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
template <class InputIterator, class Predicate>
|
|
bool none_of(InputIterator first, InputIterator last, Predicate pred)
|
|
{
|
|
for (; first != last; ++first)
|
|
if (pred(*first))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
template<class InputIterator, class T>
|
|
InputIterator find(InputIterator first, InputIterator last,
|
|
const T& value)
|
|
{
|
|
for (; first != last; ++first)
|
|
if (*first == value)
|
|
break;
|
|
return first;
|
|
}
|
|
|
|
// [C++11 25.4.7] Minimum and maximum
|
|
template<class T>
|
|
const T& min(const T& a, const T& b)
|
|
{
|
|
if (b < a)
|
|
return b;
|
|
return a;
|
|
}
|
|
|
|
template<class T, class Compare>
|
|
const T& min(const T& a, const T& b, Compare comp)
|
|
{
|
|
if (Compare(b, a))
|
|
return b;
|
|
return a;
|
|
}
|
|
|
|
template<class T>
|
|
const T& max(const T& a, const T& b)
|
|
{
|
|
if (a < b)
|
|
return b;
|
|
return a;
|
|
}
|
|
|
|
template<class T, class Compare>
|
|
const T& max(const T& a, const T& b, Compare comp)
|
|
{
|
|
if (Compare(a, b))
|
|
return b;
|
|
return a;
|
|
}
|
|
|
|
// [C++11 25.3.2] Move
|
|
template<class InputIterator, class OutputIterator>
|
|
OutputIterator move(InputIterator first, InputIterator last,
|
|
OutputIterator result)
|
|
{
|
|
while (first != last)
|
|
*result++ = std::move(*first++);
|
|
return result;
|
|
}
|
|
|
|
template<class BidirectionalIterator1, class BidirectionalIterator2>
|
|
BidirectionalIterator2 move_backward(BidirectionalIterator1 first,
|
|
BidirectionalIterator1 last,
|
|
BidirectionalIterator2 result)
|
|
{
|
|
while (first != last)
|
|
*(--result) = std::move(*(--last));
|
|
return result;
|
|
}
|
|
|
|
// [C++11 25.3.6] Fill
|
|
template<class ForwardIterator, class T>
|
|
void fill(ForwardIterator first, ForwardIterator last, const T& value)
|
|
{
|
|
for (; first != last; ++first)
|
|
*first = value;
|
|
}
|
|
|
|
template<class T>
|
|
typename enable_if<sizeof(T) == 1 && is_integral<T>::value, void>::type
|
|
fill(T* first, T* last, const T& value)
|
|
{
|
|
memset(first, value, last - first);
|
|
}
|
|
|
|
// [C++11 25.4.1] Sorting
|
|
template<class RandomAccessIterator, class Compare>
|
|
void sort(RandomAccessIterator first, RandomAccessIterator last,
|
|
Compare comp)
|
|
{
|
|
auto dist = last - first;
|
|
if (dist <= 1)
|
|
return;
|
|
// Move pivot to the end
|
|
auto pivot = last;
|
|
--pivot;
|
|
std::swap(*(first + dist / 2), *pivot);
|
|
// Partition
|
|
auto store = first;
|
|
for (auto it = first; it != pivot; ++it) {
|
|
if (comp(*it, *pivot)) {
|
|
std::swap(*store, *it);
|
|
++store;
|
|
}
|
|
}
|
|
// Move pivot to final location
|
|
std::swap(*store, *pivot);
|
|
// Sort partitions
|
|
sort(first, store, comp);
|
|
++store;
|
|
sort(store, last, comp);
|
|
}
|
|
|
|
template<class RandomAccessIterator>
|
|
void sort(RandomAccessIterator first, RandomAccessIterator last)
|
|
{
|
|
sort(first, last, __less());
|
|
}
|
|
|
|
template<class ForwardIterator, class Compare>
|
|
ForwardIterator is_sorted_until(ForwardIterator first, ForwardIterator last,
|
|
Compare comp)
|
|
{
|
|
if (last - first < 2)
|
|
return last;
|
|
ForwardIterator next = first;
|
|
for (++next; next != last; ++next, ++first)
|
|
if (comp(*next, *first))
|
|
break;
|
|
return next;
|
|
}
|
|
|
|
template<class ForwardIterator>
|
|
bool is_sorted(ForwardIterator first, ForwardIterator last)
|
|
{
|
|
return is_sorted_until(first, last, __less()) == last;
|
|
}
|
|
|
|
template<class ForwardIterator, class Compare>
|
|
bool is_sorted(ForwardIterator first, ForwardIterator last,
|
|
Compare comp)
|
|
{
|
|
return is_sorted_until(first, last, comp) == last;
|
|
}
|
|
|
|
template<class ForwardIterator>
|
|
ForwardIterator is_sorted_until(ForwardIterator first, ForwardIterator last)
|
|
{
|
|
return is_sorted_until(first, last, __less());
|
|
}
|
|
|
|
// [C++11 25.4.3] Binary search
|
|
|
|
// Returns an iterator pointing to @c value, or, if @c value isn't
|
|
// present, an iterator pointing to @c value's successor. @c comp
|
|
// must take a dereferenced iterator and value and return true if
|
|
// the first is strictly less than the second.
|
|
//
|
|
// 0 2 4 <- Collection
|
|
// 1 2 <- Values that return 2
|
|
template<class ForwardIterator, class T, class Compare>
|
|
ForwardIterator
|
|
lower_bound(ForwardIterator first, ForwardIterator last,
|
|
const T& value, Compare comp)
|
|
{
|
|
auto dist = last - first;
|
|
while (dist > 0) {
|
|
auto mid = first;
|
|
mid += dist / 2;
|
|
if (comp(*mid, value)) {
|
|
first = mid;
|
|
++first;
|
|
dist = dist - dist / 2 - 1;
|
|
} else {
|
|
dist /= 2;
|
|
}
|
|
}
|
|
return first;
|
|
}
|
|
|
|
template<class ForwardIterator, class T>
|
|
ForwardIterator
|
|
lower_bound(ForwardIterator first, ForwardIterator last,
|
|
const T& value)
|
|
{
|
|
return lower_bound(first, last, value,
|
|
[](const T& a, const T& b) { return a < b; });
|
|
}
|
|
|
|
// Returns an iterator pointing to @c value's successor. @c comp
|
|
// must take value and a dereferenced iterator and return true if
|
|
// the first is strictly less than the second.
|
|
//
|
|
// 0 2 4 <- Collection
|
|
// 0 1 <- Values that return 2
|
|
template<class ForwardIterator, class T, class Compare>
|
|
ForwardIterator
|
|
upper_bound(ForwardIterator first, ForwardIterator last,
|
|
const T& value, Compare comp)
|
|
{
|
|
auto dist = last - first;
|
|
while (dist > 0) {
|
|
auto mid = first;
|
|
mid += dist / 2;
|
|
if (comp(value, *mid)) {
|
|
dist /= 2;
|
|
} else {
|
|
first = mid;
|
|
++first;
|
|
dist = dist - dist / 2 - 1;
|
|
}
|
|
}
|
|
return first;
|
|
}
|
|
|
|
template<class ForwardIterator, class T>
|
|
ForwardIterator
|
|
upper_bound(ForwardIterator first, ForwardIterator last,
|
|
const T& value)
|
|
{
|
|
return upper_bound(first, last, value,
|
|
[](const T& a, const T& b) { return a < b; });
|
|
}
|
|
|
|
// [C++11 25.4.6] Heap operations
|
|
|
|
// Move *(first + pos) up the heap to the correct position
|
|
template<class RandomAccessIterator, class Compare, class Distance>
|
|
void
|
|
__move_up(RandomAccessIterator first, Distance pos, Distance len, Compare comp)
|
|
{
|
|
auto val = std::move(*(first + pos));
|
|
Distance parent;
|
|
// Shift values down until we find the place to insert val
|
|
while (parent = (pos - 1) / 2, pos > 0 && comp(*(first + parent), val)) {
|
|
*(first + pos) = std::move(*(first + parent));
|
|
pos = parent;
|
|
}
|
|
// Insert val
|
|
*(first + pos) = std::move(val);
|
|
}
|
|
|
|
// Move *(first + pos) down the heap to the correct position
|
|
template<class RandomAccessIterator, class Compare, class Distance>
|
|
void
|
|
__move_down(RandomAccessIterator first, Distance pos, Distance len,
|
|
Compare comp)
|
|
{
|
|
auto val = std::move(*(first + pos));
|
|
while (true) {
|
|
// Set childpos to the larger of the children of pos
|
|
Distance childpos = 2 * pos + 1;
|
|
Distance rightpos = childpos + 1;
|
|
if (rightpos < len && !comp(*(first + rightpos), *(first + childpos)))
|
|
childpos = rightpos;
|
|
// If we hit the bottom or val is > than the largest child, we've
|
|
// found our hole
|
|
if (childpos >= len || comp(*(first + childpos), val)) {
|
|
*(first + pos) = std::move(val);
|
|
return;
|
|
}
|
|
// Move the child up the tree
|
|
*(first + pos) = std::move(*(first + childpos));
|
|
// Move the hole down the tree
|
|
pos = childpos;
|
|
}
|
|
}
|
|
|
|
template<class RandomAccessIterator, class Compare>
|
|
void
|
|
push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
|
|
{
|
|
__move_up(first, last - first - 1, last - first, comp);
|
|
}
|
|
|
|
template<class RandomAccessIterator>
|
|
void
|
|
push_heap(RandomAccessIterator first, RandomAccessIterator last)
|
|
{
|
|
push_heap(first, last, __less());
|
|
}
|
|
|
|
template<class RandomAccessIterator, class Compare>
|
|
void
|
|
pop_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
|
|
{
|
|
if (last - first <= 1)
|
|
return;
|
|
--last;
|
|
std::swap(*first, *last);
|
|
__move_down(first, decltype(last - first)(0), last - first, comp);
|
|
}
|
|
|
|
template<class RandomAccessIterator>
|
|
void
|
|
pop_heap(RandomAccessIterator first, RandomAccessIterator last)
|
|
{
|
|
pop_heap(first, last, __less());
|
|
}
|
|
|
|
template<class RandomAccessIterator, class Compare>
|
|
void
|
|
make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
|
|
{
|
|
auto len = last - first;
|
|
// To avoid problems if i is unsigned, i is one more than the real index
|
|
for (auto i = len / 2; i > 0; --i)
|
|
__move_down(first, i - 1, len, comp);
|
|
}
|
|
|
|
template<class RandomAccessIterator>
|
|
void
|
|
make_heap(RandomAccessIterator first, RandomAccessIterator last)
|
|
{
|
|
make_heap(first, last, __less());
|
|
}
|
|
|
|
template<class RandomAccessIterator, class Compare>
|
|
void
|
|
sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
|
|
{
|
|
for (; first != last; --last)
|
|
pop_heap(first, last, comp);
|
|
}
|
|
|
|
template<class RandomAccessIterator>
|
|
void
|
|
sort_heap(RandomAccessIterator first, RandomAccessIterator last)
|
|
{
|
|
sort_heap(first, last, __less());
|
|
}
|
|
|
|
template<class RandomAccessIterator, class Compare>
|
|
RandomAccessIterator
|
|
is_heap_until(RandomAccessIterator first, RandomAccessIterator last,
|
|
Compare comp)
|
|
{
|
|
if (first == last)
|
|
return last;
|
|
RandomAccessIterator pos = first + 1;
|
|
for (; pos != last; ++pos) {
|
|
RandomAccessIterator parent = first + (pos - first - 1) / 2;
|
|
if (comp(*parent, *pos))
|
|
break;
|
|
}
|
|
return pos;
|
|
}
|
|
|
|
template<class RandomAccessIterator>
|
|
bool
|
|
is_heap(RandomAccessIterator first, RandomAccessIterator last)
|
|
{
|
|
return is_heap_until(first, last, __less()) == last;
|
|
}
|
|
|
|
template<class RandomAccessIterator, class Compare>
|
|
bool
|
|
is_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
|
|
{
|
|
return is_heap_until(first, last, comp) == last;
|
|
}
|
|
|
|
template<class RandomAccessIterator>
|
|
RandomAccessIterator
|
|
is_heap_until(RandomAccessIterator first, RandomAccessIterator last)
|
|
{
|
|
return is_heap_until(first, last, __less());
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
#include <cassert>
|
|
#include <vector>
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
std::vector<int> vec;
|
|
for (int t = 0; t < 1000; ++t) {
|
|
vec.clear();
|
|
for (int i = 0; i < 100; ++i) {
|
|
vec.push_back(rand() % 100);
|
|
push_heap(vec.begin(), vec.end());
|
|
assert(is_heap(vec.begin(), vec.end()));
|
|
}
|
|
while (!vec.empty()) {
|
|
pop_heap(vec.begin(), vec.end());
|
|
vec.pop_back();
|
|
assert(is_heap(vec.begin(), vec.end()));
|
|
}
|
|
|
|
for (int i = 0; i < 100; ++i)
|
|
vec.push_back(rand() % 100);
|
|
make_heap(vec.begin(), vec.end());
|
|
assert(is_heap(vec.begin(), vec.end()));
|
|
|
|
sort_heap(vec.begin(), vec.end());
|
|
for (int i = 0; i < vec.size() - 1; ++i)
|
|
assert(vec[i] <= vec[i+1]);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|