Program Listing for File sorted.hpp¶
↰ Return to documentation for file (include/util/sorted.hpp)
// SPDX-FileCopyrightText: 2021 Christian Göhring <mostsig@gmail.com>
// SPDX-License-Identifier: MIT
#ifndef THAT_THIS_UTIL_SORTED_HEADER_IS_ALREADY_INCLUDED
#define THAT_THIS_UTIL_SORTED_HEADER_IS_ALREADY_INCLUDED
#include <algorithm>
#include <array>
#include <forward_list>
#include <functional>
#include <list>
#include <memory>
#include <vector>
#ifdef UTIL_ASSERT
#include <util/assert.hpp>
#endif
namespace util {
template <class Container, class Compare = std::less<typename Container::value_type>>
class sorted {
public:
using value_type = typename Container::value_type;
using size_type = typename Container::size_type;
using const_reference = const value_type&;
using const_pointer = const value_type*;
using const_iterator = typename Container::const_iterator;
using is_forward_list =
std::is_same<Container, std::forward_list<value_type, typename Container::allocator_type>>;
using is_list =
std::is_same<Container, std::list<value_type, typename Container::allocator_type>>;
sorted() noexcept = default;
~sorted() = default;
sorted(const sorted&) = default;
sorted(sorted&&) noexcept = default;
auto operator=(const sorted&) -> sorted& = default;
auto operator=(sorted&&) noexcept -> sorted& = default;
template <class OtherContainer>
explicit sorted(const OtherContainer& container);
template <class InputIt>
sorted(InputIt begin, InputIt end);
sorted(std::initializer_list<value_type> ilist);
// element access
auto at(size_type pos) const -> const_reference;
auto operator[](size_type pos) const -> const_reference;
auto front() const -> const_reference;
auto back() const -> const_reference;
auto data() const noexcept -> const_pointer;
// iterators
auto begin() const noexcept -> const_iterator;
auto cbegin() const noexcept -> const_iterator;
auto end() const noexcept -> const_iterator;
auto cend() const noexcept -> const_iterator;
// capacity and size
auto empty() const noexcept -> bool;
auto size() const noexcept -> size_type;
auto max_size() const noexcept -> size_type;
auto capacity() const noexcept -> size_type;
void reserve(size_type new_cap);
void shrink_to_fit();
void resize(size_type count);
void resize(size_type count, const_reference value);
// modifiers
void clear() noexcept;
auto insert(const_reference value) -> const_iterator;
auto insert(value_type&& value) -> const_iterator;
auto insert(std::initializer_list<value_type> ilist) -> const_iterator;
template <class InputIt>
void insert(InputIt first, InputIt last);
template <class... Args>
auto emplace(Args&&... args) -> const_iterator;
auto erase(const_iterator pos) -> const_iterator;
auto erase(const_iterator first, const_iterator last) -> const_iterator;
void pop_back();
void pop_front();
void swap(sorted& other);
private:
Compare comp = Compare();
Container container;
};
template <class T, class Allocator = std::allocator<T>>
using sorted_forward_list = sorted<std::forward_list<T, Allocator>>;
template <class T, class Allocator = std::allocator<T>>
using sorted_list = sorted<std::list<T, Allocator>>;
template <class T, class Allocator = std::allocator<T>>
using sorted_vector = sorted<std::vector<T, Allocator>>;
template <class Container, class Compare>
template <class OtherContainer>
sorted<Container, Compare>::sorted(const OtherContainer& container)
: sorted(container.begin(), container.end()) {}
template <class Container, class Compare>
template <class InputIt>
sorted<Container, Compare>::sorted(InputIt begin, InputIt end) {
if constexpr (is_forward_list::value) {
container.assign(begin, end);
container.sort(comp);
} else {
for (; begin != end; ++begin) {
container.insert(std::lower_bound(container.begin(), container.end(), *begin, comp),
*begin);
}
}
}
template <class Container, class Compare>
sorted<Container, Compare>::sorted(std::initializer_list<value_type> ilist)
: sorted(std::begin(ilist), std::end(ilist)) {}
template <class Container, class Compare>
auto sorted<Container, Compare>::at(size_type pos) const -> const_reference {
if (pos >= size()) {
throw std::out_of_range{"pos is out of range"};
}
if constexpr (is_forward_list::value || is_list::value) {
auto it = container.begin();
while (pos--) {
++it;
}
return *it;
} else {
return container.at(pos);
}
}
template <class Container, class Compare>
auto sorted<Container, Compare>::operator[](size_type pos) const -> const_reference {
#ifdef UTIL_ASSERT
util_assert(pos < size());
#endif // UTIL_ASSERT
if constexpr (is_forward_list::value || is_list::value) {
auto it = container.begin();
while (pos--) {
++it;
}
return *it;
} else {
return container.operator[](pos);
}
}
template <class Container, class Compare>
auto sorted<Container, Compare>::front() const -> const_reference {
return container.front();
}
template <class Container, class Compare>
auto sorted<Container, Compare>::back() const -> const_reference {
return container.back();
}
template <class Container, class Compare>
auto sorted<Container, Compare>::data() const noexcept -> const_pointer {
return container.data();
}
template <class Container, class Compare>
auto sorted<Container, Compare>::size() const noexcept -> size_type {
if constexpr (is_forward_list::value) {
size_type size = 0;
for (auto it = container.begin(), end = container.end(); it != end; ++it) {
++size;
}
return size;
} else {
return container.size();
}
}
template <class Container, class Compare>
auto sorted<Container, Compare>::capacity() const noexcept -> size_type {
if constexpr (is_forward_list::value || is_list::value) {
return container.max_size();
} else {
return container.capacity();
}
}
template <class Container, class Compare>
void sorted<Container, Compare>::clear() noexcept {
container.clear();
}
template <class Container, class Compare>
auto sorted<Container, Compare>::insert(const_reference value) -> const_iterator {
if constexpr (is_forward_list::value) {
container.push_back(value);
container.sort(comp);
} else {
return const_iterator(
container.insert(std::lower_bound(container.begin(), container.end()), value, comp));
}
}
template <class Container, class Compare>
auto sorted<Container, Compare>::insert(value_type&& value) -> const_iterator {
if constexpr (is_forward_list::value) {
auto it = container.begin();
if (comp(value, *it)) {
container.push_front(std::move(value));
return container.cbegin();
}
for (auto next = ++container.begin(), end = container.end(); next != end; ++next, ++it) {
if (comp(value, *next)) {
return const_iterator(container.insert_after(it, std::move(value)));
}
}
return const_iterator(container.insert_after(it, std::move(value)));
} else {
return const_iterator(container.insert(
std::lower_bound(container.begin(), container.end(), std::move(value), comp),
std::move(value)));
}
}
} // namespace util
#endif // THAT_THIS_UTIL_SORTED_HEADER_IS_ALREADY_INCLUDED