// -*- c++ -*- #pragma once #include #include namespace std { // [C++11 25.2] Non-modifying sequence operations struct __less { template bool operator()(const T& x, const T& y) const { return x < y; } }; template bool all_of(InputIterator first, InputIterator last, Predicate pred) { for (; first != last; ++first) if (!pred(*first)) return false; return true; } template bool any_of(InputIterator first, InputIterator last, Predicate pred) { for (; first != last; ++first) if (pred(*first)) return true; return false; } template bool none_of(InputIterator first, InputIterator last, Predicate pred) { for (; first != last; ++first) if (pred(*first)) return false; return true; } template 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 const T& min(const T& a, const T& b) { if (b < a) return b; return a; } template const T& min(const T& a, const T& b, Compare comp) { if (Compare(b, a)) return b; return a; } template const T& max(const T& a, const T& b) { if (a < b) return b; return a; } template 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 OutputIterator move(InputIterator first, InputIterator last, OutputIterator result) { while (first != last) *result++ = std::move(*first++); return result; } template 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 void fill(ForwardIterator first, ForwardIterator last, const T& value) { for (; first != last; ++first) *first = value; } template typename enable_if::value, void>::type fill(T* first, T* last, const T& value) { memset(first, value, last - first); } // [C++11 25.4.1] Sorting template 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 void sort(RandomAccessIterator first, RandomAccessIterator last) { sort(first, last, __less()); } template 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 bool is_sorted(ForwardIterator first, ForwardIterator last) { return is_sorted_until(first, last, __less()) == last; } template bool is_sorted(ForwardIterator first, ForwardIterator last, Compare comp) { return is_sorted_until(first, last, comp) == last; } template 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 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 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 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 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 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 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 void push_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp) { __move_up(first, last - first - 1, last - first, comp); } template void push_heap(RandomAccessIterator first, RandomAccessIterator last) { push_heap(first, last, __less()); } template 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 void pop_heap(RandomAccessIterator first, RandomAccessIterator last) { pop_heap(first, last, __less()); } template 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 void make_heap(RandomAccessIterator first, RandomAccessIterator last) { make_heap(first, last, __less()); } template void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp) { for (; first != last; --last) pop_heap(first, last, comp); } template void sort_heap(RandomAccessIterator first, RandomAccessIterator last) { sort_heap(first, last, __less()); } template 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 bool is_heap(RandomAccessIterator first, RandomAccessIterator last) { return is_heap_until(first, last, __less()) == last; } template bool is_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp) { return is_heap_until(first, last, comp) == last; } template RandomAccessIterator is_heap_until(RandomAccessIterator first, RandomAccessIterator last) { return is_heap_until(first, last, __less()); } } #if 0 #include #include int main(int argc, char **argv) { std::vector 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