link blackmatov libraries without copy headers to 3rdparty

This commit is contained in:
2019-07-17 03:31:56 +07:00
parent aaae8f2a72
commit 07b8d1707b
22 changed files with 21 additions and 7782 deletions

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.11 FATAL_ERROR)
if(NOT DEFINED PROJECT_NAME)
set(BUILD_AS_STANDALONE ON)
set(E2D_BUILD_AS_STANDALONE ON)
endif()
project(enduro2d)
@@ -9,7 +9,7 @@ project(enduro2d)
set(E2D_SYSTEM_NAME ${CMAKE_SYSTEM_NAME})
set(E2D_ROOT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
if(NOT BUILD_AS_STANDALONE)
if(NOT E2D_BUILD_AS_STANDALONE)
set(E2D_SYSTEM_NAME ${E2D_SYSTEM_NAME} PARENT_SCOPE)
set(E2D_ROOT_DIRECTORY ${E2D_ROOT_DIRECTORY} PARENT_SCOPE)
endif()
@@ -153,6 +153,10 @@ set(USE_EMBEDDED_CURL ON CACHE INTERNAL "" FORCE)
add_subdirectory(modules/curly.hpp)
set_target_properties(curly.hpp libcurl PROPERTIES FOLDER modules)
add_subdirectory(modules/ecs.hpp)
add_subdirectory(modules/flat.hpp)
add_subdirectory(modules/promise.hpp)
set(GLFW_INSTALL OFF CACHE INTERNAL "" FORCE)
set(GLFW_BUILD_DOCS OFF CACHE INTERNAL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE INTERNAL "" FORCE)
@@ -249,7 +253,10 @@ source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES
${E2D_3RDPARTY})
target_link_libraries(${PROJECT_NAME}
PUBLIC curly.hpp)
PUBLIC curly.hpp
PUBLIC ecs.hpp
PUBLIC flat.hpp
PUBLIC promise.hpp)
target_link_libraries(${PROJECT_NAME}
PRIVATE bass

File diff suppressed because it is too large Load Diff

View File

@@ -1,25 +0,0 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/flat.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
namespace flat_hpp::detail
{
template < typename Compare >
class eq_compare : public Compare {
public:
eq_compare() = default;
eq_compare(const Compare& compare)
: Compare(compare) {}
template < typename L, typename R >
bool operator()(const L& l, const R& r) const {
return !Compare::operator()(l, r)
&& !Compare::operator()(r, l);
}
};
}

View File

@@ -1,38 +0,0 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/flat.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
namespace flat_hpp::detail
{
template < typename Iter, typename Compare >
bool is_sorted(Iter first, Iter last, Compare comp) {
if ( first != last ) {
Iter next = first;
while ( ++next != last ) {
if ( comp(*next, *first) ) {
return false;
}
++first;
}
}
return true;
}
template < typename Iter, typename Compare >
bool is_sorted_unique(Iter first, Iter last, Compare comp) {
if ( first != last ){
Iter next = first;
while ( ++next != last ) {
if ( !comp(*first, *next) ) {
return false;
}
++first;
}
}
return true;
}
}

View File

@@ -1,23 +0,0 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/flat.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include <type_traits>
namespace flat_hpp::detail
{
template < typename T, typename U, typename = void >
struct is_transparent
: std::false_type {};
template < typename T, typename U >
struct is_transparent<T, U, std::void_t<typename T::is_transparent>>
: std::true_type {};
template < typename T, typename U >
inline constexpr bool is_transparent_v = is_transparent<T, U>::value;
}

View File

@@ -1,62 +0,0 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/flat.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "is_transparent.hpp"
namespace flat_hpp::detail
{
template < typename Pair, typename Compare >
class pair_compare : public Compare {
public:
pair_compare() = default;
pair_compare(const Compare& compare)
: Compare(compare) {}
bool operator()(
const typename Pair::first_type& l,
const typename Pair::first_type& r) const
{
return Compare::operator()(l, r);
}
bool operator()(const Pair& l, const Pair& r) const {
return Compare::operator()(l.first, r.first);
}
bool operator()(
const typename Pair::first_type& l,
const Pair& r) const
{
return Compare::operator()(l, r.first);
}
bool operator()(
const Pair& l,
const typename Pair::first_type& r) const
{
return Compare::operator()(l.first, r);
}
template < typename K >
std::enable_if_t<
is_transparent_v<Compare, K>,
bool>
operator()(const K& l, const Pair& r) const {
return Compare::operator()(l, r.first);
}
template < typename K >
std::enable_if_t<
is_transparent_v<Compare, K>,
bool>
operator()(const Pair& l, const K& r) const {
return Compare::operator()(l.first, r);
}
};
}

View File

@@ -1,51 +0,0 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/flat.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include <vector>
#include <cassert>
#include <utility>
#include <algorithm>
#include <functional>
#include <type_traits>
#include <initializer_list>
#include "detail/is_sorted.hpp"
#include "detail/eq_compare.hpp"
#include "detail/pair_compare.hpp"
#include "detail/is_transparent.hpp"
namespace flat_hpp
{
struct sorted_range_t {};
inline constexpr sorted_range_t sorted_range = sorted_range_t();
struct sorted_unique_range_t : public sorted_range_t {};
inline constexpr sorted_unique_range_t sorted_unique_range = sorted_unique_range_t();
template < typename Key
, typename Compare = std::less<Key>
, typename Container = std::vector<Key> >
class flat_set;
template < typename Key
, typename Compare = std::less<Key>
, typename Container = std::vector<Key> >
class flat_multiset;
template < typename Key
, typename Value
, typename Compare = std::less<Key>
, typename Container = std::vector<std::pair<Key, Value>> >
class flat_map;
template < typename Key
, typename Value
, typename Compare = std::less<Key>
, typename Container = std::vector<std::pair<Key, Value>> >
class flat_multimap;
}

View File

@@ -1,792 +0,0 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/flat.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "flat_fwd.hpp"
namespace flat_hpp
{
template < typename Key
, typename Value
, typename Compare
, typename Container >
class flat_map
: private detail::pair_compare<
typename Container::value_type,
Compare>
{
using base_type = detail::pair_compare<
typename Container::value_type,
Compare>;
public:
using key_type = Key;
using mapped_type = Value;
using value_type = typename Container::value_type;
using size_type = typename Container::size_type;
using difference_type = typename Container::difference_type;
using key_compare = Compare;
using container_type = Container;
using reference = typename Container::reference;
using const_reference = typename Container::const_reference;
using pointer = typename Container::pointer;
using const_pointer = typename Container::const_pointer;
using iterator = typename Container::iterator;
using const_iterator = typename Container::const_iterator;
using reverse_iterator = typename Container::reverse_iterator;
using const_reverse_iterator = typename Container::const_reverse_iterator;
class value_compare : private key_compare {
public:
bool operator()(const value_type& l, const value_type& r) const {
return key_compare::operator()(l.first, r.first);
}
protected:
friend class flat_map;
explicit value_compare(key_compare compare)
: key_compare(std::move(compare)) {}
};
public:
flat_map()
noexcept(std::is_nothrow_default_constructible_v<base_type>
&& std::is_nothrow_default_constructible_v<container_type>) {}
explicit flat_map(const Compare& c)
: base_type(c) {}
template < typename Allocator >
explicit flat_map(const Allocator& a)
: data_(a) {}
template < typename Allocator >
flat_map(const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {}
template < typename InputIter >
flat_map(InputIter first, InputIter last) {
from_range_(first, last);
}
template < typename InputIter >
flat_map(sorted_range_t, InputIter first, InputIter last) {
from_range_(sorted_range, first, last);
}
template < typename InputIter >
flat_map(sorted_unique_range_t, InputIter first, InputIter last) {
from_range_(sorted_unique_range, first, last);
}
template < typename InputIter >
flat_map(InputIter first, InputIter last, const Compare& c)
: base_type(c) {
from_range_(first, last);
}
template < typename InputIter >
flat_map(sorted_range_t, InputIter first, InputIter last, const Compare& c)
: base_type(c) {
from_range_(sorted_range, first, last);
}
template < typename InputIter >
flat_map(sorted_unique_range_t, InputIter first, InputIter last, const Compare& c)
: base_type(c) {
from_range_(sorted_unique_range, first, last);
}
template < typename InputIter, typename Allocator >
flat_map(InputIter first, InputIter last, const Allocator& a)
: data_(a) {
from_range_(first, last);
}
template < typename InputIter, typename Allocator >
flat_map(sorted_range_t, InputIter first, InputIter last, const Allocator& a)
: data_(a) {
from_range_(sorted_range, first, last);
}
template < typename InputIter, typename Allocator >
flat_map(sorted_unique_range_t, InputIter first, InputIter last, const Allocator& a)
: data_(a) {
from_range_(sorted_unique_range, first, last);
}
template < typename InputIter, typename Allocator >
flat_map(InputIter first, InputIter last, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(first, last);
}
template < typename InputIter, typename Allocator >
flat_map(sorted_range_t, InputIter first, InputIter last, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(sorted_range, first, last);
}
template < typename InputIter, typename Allocator >
flat_map(sorted_unique_range_t, InputIter first, InputIter last, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(sorted_unique_range, first, last);
}
flat_map(std::initializer_list<value_type> ilist) {
from_range_(ilist.begin(), ilist.end());
}
flat_map(sorted_range_t, std::initializer_list<value_type> ilist) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
flat_map(sorted_unique_range_t, std::initializer_list<value_type> ilist) {
from_range_(sorted_unique_range, ilist.begin(), ilist.end());
}
flat_map(std::initializer_list<value_type> ilist, const Compare& c)
: base_type(c) {
from_range_(ilist.begin(), ilist.end());
}
flat_map(sorted_range_t, std::initializer_list<value_type> ilist, const Compare& c)
: base_type(c) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
flat_map(sorted_unique_range_t, std::initializer_list<value_type> ilist, const Compare& c)
: base_type(c) {
from_range_(sorted_unique_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_map(std::initializer_list<value_type> ilist, const Allocator& a)
: data_(a) {
from_range_(ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_map(sorted_range_t, std::initializer_list<value_type> ilist, const Allocator& a)
: data_(a) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_map(sorted_unique_range_t, std::initializer_list<value_type> ilist, const Allocator& a)
: data_(a) {
from_range_(sorted_unique_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_map(std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_map(sorted_range_t, std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_map(sorted_unique_range_t, std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(sorted_unique_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_map(flat_map&& other, const Allocator& a)
: base_type(static_cast<base_type&&>(other))
, data_(std::move(other.data_), a) {}
template < typename Allocator >
flat_map(const flat_map& other, const Allocator& a)
: base_type(static_cast<const base_type&>(other))
, data_(other.data_, a) {}
flat_map(flat_map&& other) = default;
flat_map(const flat_map& other) = default;
flat_map& operator=(flat_map&& other) = default;
flat_map& operator=(const flat_map& other) = default;
flat_map& operator=(std::initializer_list<value_type> ilist) {
flat_map(ilist).swap(*this);
return *this;
}
iterator begin()
noexcept(noexcept(std::declval<container_type&>().begin())) {
return data_.begin();
}
const_iterator begin() const
noexcept(noexcept(std::declval<const container_type&>().begin())) {
return data_.begin();
}
const_iterator cbegin() const
noexcept(noexcept(std::declval<const container_type&>().cbegin())) {
return data_.cbegin();
}
iterator end()
noexcept(noexcept(std::declval<container_type&>().end())) {
return data_.end();
}
const_iterator end() const
noexcept(noexcept(std::declval<const container_type&>().end())) {
return data_.end();
}
const_iterator cend() const
noexcept(noexcept(std::declval<const container_type&>().cend())) {
return data_.cend();
}
reverse_iterator rbegin()
noexcept(noexcept(std::declval<container_type&>().rbegin())) {
return data_.rbegin();
}
const_reverse_iterator rbegin() const
noexcept(noexcept(std::declval<const container_type&>().rbegin())) {
return data_.rbegin();
}
const_reverse_iterator crbegin() const
noexcept(noexcept(std::declval<const container_type&>().crbegin())) {
return data_.crbegin();
}
reverse_iterator rend()
noexcept(noexcept(std::declval<container_type&>().rend())) {
return data_.rend();
}
const_reverse_iterator rend() const
noexcept(noexcept(std::declval<const container_type&>().rend())) {
return data_.rend();
}
const_reverse_iterator crend() const
noexcept(noexcept(std::declval<const container_type&>().crend())) {
return data_.crend();
}
bool empty() const
noexcept(noexcept(std::declval<const container_type&>().empty())) {
return data_.empty();
}
size_type size() const
noexcept(noexcept(std::declval<const container_type&>().size())) {
return data_.size();
}
size_type max_size() const
noexcept(noexcept(std::declval<const container_type&>().max_size())) {
return data_.max_size();
}
size_type capacity() const
noexcept(noexcept(std::declval<const container_type&>().capacity())) {
return data_.capacity();
}
void reserve(size_type ncapacity) {
data_.reserve(ncapacity);
}
void shrink_to_fit() {
data_.shrink_to_fit();
}
mapped_type& operator[](key_type&& key) {
const iterator iter = find(key);
return iter != end()
? iter->second
: emplace(std::move(key), mapped_type()).first->second;
}
mapped_type& operator[](const key_type& key) {
const iterator iter = find(key);
return iter != end()
? iter->second
: emplace(key, mapped_type()).first->second;
}
mapped_type& at(const key_type& key) {
const iterator iter = find(key);
if ( iter != end() ) {
return iter->second;
}
throw std::out_of_range("flat_map::at: key not found");
}
const mapped_type& at(const key_type& key) const {
const const_iterator iter = find(key);
if ( iter != end() ) {
return iter->second;
}
throw std::out_of_range("flat_map::at: key not found");
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
mapped_type&>
at(const K& key) {
const iterator iter = find(key);
if ( iter != end() ) {
return iter->second;
}
throw std::out_of_range("flat_map::at: key not found");
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
const mapped_type&>
at(const K& key) const {
const const_iterator iter = find(key);
if ( iter != end() ) {
return iter->second;
}
throw std::out_of_range("flat_map::at: key not found");
}
std::pair<iterator, bool> insert(value_type&& value) {
const iterator iter = lower_bound(value.first);
return iter == end() || this->operator()(value, *iter)
? std::make_pair(data_.insert(iter, std::move(value)), true)
: std::make_pair(iter, false);
}
std::pair<iterator, bool> insert(const value_type& value) {
const iterator iter = lower_bound(value.first);
return iter == end() || this->operator()(value, *iter)
? std::make_pair(data_.insert(iter, value), true)
: std::make_pair(iter, false);
}
iterator insert(const_iterator hint, value_type&& value) {
return (hint == begin() || this->operator()(*(hint - 1), value))
&& (hint == end() || this->operator()(value, *hint))
? data_.insert(hint, std::move(value))
: insert(std::move(value)).first;
}
iterator insert(const_iterator hint, const value_type& value) {
return (hint == begin() || this->operator()(*(hint - 1), value))
&& (hint == end() || this->operator()(value, *hint))
? data_.insert(hint, value)
: insert(value).first;
}
template < typename TT >
std::pair<iterator, bool> insert_or_assign(key_type&& key, TT&& value) {
iterator iter = lower_bound(key);
if ( iter == end() || this->operator()(key, *iter) ) {
iter = emplace_hint(iter, std::move(key), std::forward<TT>(value));
return {iter, true};
}
(*iter).second = std::forward<TT>(value);
return {iter, false};
}
template < typename TT >
std::pair<iterator, bool> insert_or_assign(const key_type& key, TT&& value) {
iterator iter = lower_bound(key);
if ( iter == end() || this->operator()(key, *iter) ) {
iter = emplace_hint(iter, key, std::forward<TT>(value));
return {iter, true};
}
(*iter).second = std::forward<TT>(value);
return {iter, false};
}
template < typename InputIter >
void insert(InputIter first, InputIter last) {
insert_range_(first, last);
}
template < typename InputIter >
void insert(sorted_range_t, InputIter first, InputIter last) {
insert_range_(sorted_range, first, last);
}
void insert(std::initializer_list<value_type> ilist) {
insert_range_(ilist.begin(), ilist.end());
}
void insert(sorted_range_t, std::initializer_list<value_type> ilist) {
insert_range_(sorted_range, ilist.begin(), ilist.end());
}
template < typename... Args >
std::pair<iterator, bool> emplace(Args&&... args) {
return insert(value_type(std::forward<Args>(args)...));
}
template < typename... Args >
iterator emplace_hint(const_iterator hint, Args&&... args) {
return insert(hint, value_type(std::forward<Args>(args)...));
}
template < typename... Args >
std::pair<iterator, bool> try_emplace(key_type&& key, Args&&... args) {
iterator iter = lower_bound(key);
if ( iter == end() || this->operator()(key, *iter) ) {
iter = emplace_hint(iter, std::move(key), std::forward<Args>(args)...);
return {iter, true};
}
return {iter, false};
}
template < typename... Args >
std::pair<iterator, bool> try_emplace(const key_type& key, Args&&... args) {
iterator iter = lower_bound(key);
if ( iter == end() || this->operator()(key, *iter) ) {
iter = emplace_hint(iter, key, std::forward<Args>(args)...);
return {iter, true};
}
return {iter, false};
}
void clear()
noexcept(noexcept(std::declval<container_type&>().clear())) {
data_.clear();
}
iterator erase(const_iterator iter) {
return data_.erase(iter);
}
iterator erase(const_iterator first, const_iterator last) {
return data_.erase(first, last);
}
size_type erase(const key_type& key) {
const const_iterator iter = find(key);
return iter != end()
? (erase(iter), 1)
: 0;
}
void swap(flat_map& other)
noexcept(std::is_nothrow_swappable_v<base_type>
&& std::is_nothrow_swappable_v<container_type>)
{
using std::swap;
swap(
static_cast<base_type&>(*this),
static_cast<base_type&>(other));
swap(data_, other.data_);
}
size_type count(const key_type& key) const {
const const_iterator iter = find(key);
return iter != end() ? 1 : 0;
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
size_type>
count(const K& key) const {
const const_iterator iter = find(key);
return iter != end() ? 1 : 0;
}
iterator find(const key_type& key) {
const iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
const_iterator find(const key_type& key) const {
const const_iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
iterator>
find(const K& key) {
const iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
const_iterator>
find(const K& key) const {
const const_iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
bool contains(const key_type& key) const {
return find(key) != end();
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
bool>
contains(const K& key) const {
return find(key) != end();
}
std::pair<iterator, iterator> equal_range(const key_type& key) {
const base_type& comp = *this;
return std::equal_range(begin(), end(), key, comp);
}
std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
const base_type& comp = *this;
return std::equal_range(begin(), end(), key, comp);
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
std::pair<iterator, iterator>>
equal_range(const K& key) {
const base_type& comp = *this;
return std::equal_range(begin(), end(), key, comp);
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
std::pair<const_iterator, const_iterator>>
equal_range(const K& key) const {
const base_type& comp = *this;
return std::equal_range(begin(), end(), key, comp);
}
iterator lower_bound(const key_type& key) {
const base_type& comp = *this;
return std::lower_bound(begin(), end(), key, comp);
}
const_iterator lower_bound(const key_type& key) const {
const base_type& comp = *this;
return std::lower_bound(begin(), end(), key, comp);
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
iterator>
lower_bound(const K& key) {
const base_type& comp = *this;
return std::lower_bound(begin(), end(), key, comp);
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
const_iterator>
lower_bound(const K& key) const {
const base_type& comp = *this;
return std::lower_bound(begin(), end(), key, comp);
}
iterator upper_bound(const key_type& key) {
const base_type& comp = *this;
return std::upper_bound(begin(), end(), key, comp);
}
const_iterator upper_bound(const key_type& key) const {
const base_type& comp = *this;
return std::upper_bound(begin(), end(), key, comp);
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
iterator>
upper_bound(const K& key) {
const base_type& comp = *this;
return std::upper_bound(begin(), end(), key, comp);
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
const_iterator>
upper_bound(const K& key) const {
const base_type& comp = *this;
return std::upper_bound(begin(), end(), key, comp);
}
key_compare key_comp() const {
return *this;
}
value_compare value_comp() const {
return value_compare(key_comp());
}
private:
template < typename Iter >
void from_range_(Iter first, Iter last) {
assert(data_.empty());
data_.insert(data_.end(), first, last);
std::sort(data_.begin(), data_.end(), value_comp());
data_.erase(
std::unique(data_.begin(), data_.end(),
detail::eq_compare<value_compare>(value_comp())),
data_.end());
}
template < typename Iter >
void from_range_(sorted_range_t, Iter first, Iter last) {
assert(data_.empty());
assert(detail::is_sorted(first, last, value_comp()));
data_.insert(data_.end(), first, last);
data_.erase(
std::unique(data_.begin(), data_.end(),
detail::eq_compare<value_compare>(value_comp())),
data_.end());
}
template < typename Iter >
void from_range_(sorted_unique_range_t, Iter first, Iter last) {
assert(data_.empty());
assert(detail::is_sorted_unique(first, last, value_comp()));
data_.insert(data_.end(), first, last);
}
private:
template < typename Iter >
void insert_range_(Iter first, Iter last) {
const auto mid_iter = data_.insert(data_.end(), first, last);
std::sort(mid_iter, data_.end(), value_comp());
std::inplace_merge(data_.begin(), mid_iter, data_.end(), value_comp());
data_.erase(
std::unique(data_.begin(), data_.end(),
detail::eq_compare<value_compare>(value_comp())),
data_.end());
}
template < typename Iter >
void insert_range_(sorted_range_t, Iter first, Iter last) {
assert(detail::is_sorted(first, last, value_comp()));
const auto mid_iter = data_.insert(data_.end(), first, last);
std::inplace_merge(data_.begin(), mid_iter, data_.end(), value_comp());
data_.erase(
std::unique(data_.begin(), data_.end(),
detail::eq_compare<value_compare>(value_comp())),
data_.end());
}
private:
container_type data_;
};
}
namespace flat_hpp
{
template < typename Key
, typename Value
, typename Compare
, typename Container >
void swap(
flat_map<Key, Value, Compare, Container>& l,
flat_map<Key, Value, Compare, Container>& r)
noexcept(noexcept(l.swap(r)))
{
l.swap(r);
}
template < typename Key
, typename Value
, typename Compare
, typename Container >
bool operator==(
const flat_map<Key, Value, Compare, Container>& l,
const flat_map<Key, Value, Compare, Container>& r)
{
return l.size() == r.size()
&& std::equal(l.begin(), l.end(), r.begin());
}
template < typename Key
, typename Value
, typename Compare
, typename Container >
bool operator!=(
const flat_map<Key, Value, Compare, Container>& l,
const flat_map<Key, Value, Compare, Container>& r)
{
return !(l == r);
}
template < typename Key
, typename Value
, typename Compare
, typename Container >
bool operator<(
const flat_map<Key, Value, Compare, Container>& l,
const flat_map<Key, Value, Compare, Container>& r)
{
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
}
template < typename Key
, typename Value
, typename Compare
, typename Container >
bool operator>(
const flat_map<Key, Value, Compare, Container>& l,
const flat_map<Key, Value, Compare, Container>& r)
{
return r < l;
}
template < typename Key
, typename Value
, typename Compare
, typename Container >
bool operator<=(
const flat_map<Key, Value, Compare, Container>& l,
const flat_map<Key, Value, Compare, Container>& r)
{
return !(r < l);
}
template < typename Key
, typename Value
, typename Compare
, typename Container >
bool operator>=(
const flat_map<Key, Value, Compare, Container>& l,
const flat_map<Key, Value, Compare, Container>& r)
{
return !(l < r);
}
}

View File

@@ -1,677 +0,0 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/flat.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "flat_fwd.hpp"
namespace flat_hpp
{
template < typename Key
, typename Value
, typename Compare
, typename Container >
class flat_multimap
: private detail::pair_compare<
typename Container::value_type,
Compare>
{
using base_type = detail::pair_compare<
typename Container::value_type,
Compare>;
public:
using key_type = Key;
using mapped_type = Value;
using value_type = typename Container::value_type;
using size_type = typename Container::size_type;
using difference_type = typename Container::difference_type;
using key_compare = Compare;
using container_type = Container;
using reference = typename Container::reference;
using const_reference = typename Container::const_reference;
using pointer = typename Container::pointer;
using const_pointer = typename Container::const_pointer;
using iterator = typename Container::iterator;
using const_iterator = typename Container::const_iterator;
using reverse_iterator = typename Container::reverse_iterator;
using const_reverse_iterator = typename Container::const_reverse_iterator;
class value_compare : private key_compare {
public:
bool operator()(const value_type& l, const value_type& r) const {
return key_compare::operator()(l.first, r.first);
}
protected:
friend class flat_multimap;
explicit value_compare(key_compare compare)
: key_compare(std::move(compare)) {}
};
public:
flat_multimap()
noexcept(std::is_nothrow_default_constructible_v<base_type>
&& std::is_nothrow_default_constructible_v<container_type>) {}
explicit flat_multimap(const Compare& c)
: base_type(c) {}
template < typename Allocator >
explicit flat_multimap(const Allocator& a)
: data_(a) {}
template < typename Allocator >
flat_multimap(const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {}
template < typename InputIter >
flat_multimap(InputIter first, InputIter last) {
from_range_(first, last);
}
template < typename InputIter >
flat_multimap(sorted_range_t, InputIter first, InputIter last) {
from_range_(sorted_range, first, last);
}
template < typename InputIter >
flat_multimap(InputIter first, InputIter last, const Compare& c)
: base_type(c) {
from_range_(first, last);
}
template < typename InputIter >
flat_multimap(sorted_range_t, InputIter first, InputIter last, const Compare& c)
: base_type(c) {
from_range_(sorted_range, first, last);
}
template < typename InputIter, typename Allocator >
flat_multimap(InputIter first, InputIter last, const Allocator& a)
: data_(a) {
from_range_(first, last);
}
template < typename InputIter, typename Allocator >
flat_multimap(sorted_range_t, InputIter first, InputIter last, const Allocator& a)
: data_(a) {
from_range_(sorted_range, first, last);
}
template < typename InputIter, typename Allocator >
flat_multimap(InputIter first, InputIter last, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(first, last);
}
template < typename InputIter, typename Allocator >
flat_multimap(sorted_range_t, InputIter first, InputIter last, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(sorted_range, first, last);
}
flat_multimap(std::initializer_list<value_type> ilist) {
from_range_(ilist.begin(), ilist.end());
}
flat_multimap(sorted_range_t, std::initializer_list<value_type> ilist) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
flat_multimap(std::initializer_list<value_type> ilist, const Compare& c)
: base_type(c) {
from_range_(ilist.begin(), ilist.end());
}
flat_multimap(sorted_range_t, std::initializer_list<value_type> ilist, const Compare& c)
: base_type(c) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_multimap(std::initializer_list<value_type> ilist, const Allocator& a)
: data_(a) {
from_range_(ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_multimap(sorted_range_t, std::initializer_list<value_type> ilist, const Allocator& a)
: data_(a) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_multimap(std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_multimap(sorted_range_t, std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_multimap(flat_multimap&& other, const Allocator& a)
: base_type(static_cast<base_type&&>(other))
, data_(std::move(other.data_), a) {}
template < typename Allocator >
flat_multimap(const flat_multimap& other, const Allocator& a)
: base_type(static_cast<const base_type&>(other))
, data_(other.data_, a) {}
flat_multimap(flat_multimap&& other) = default;
flat_multimap(const flat_multimap& other) = default;
flat_multimap& operator=(flat_multimap&& other) = default;
flat_multimap& operator=(const flat_multimap& other) = default;
flat_multimap& operator=(std::initializer_list<value_type> ilist) {
flat_multimap(ilist).swap(*this);
return *this;
}
iterator begin()
noexcept(noexcept(std::declval<container_type&>().begin())) {
return data_.begin();
}
const_iterator begin() const
noexcept(noexcept(std::declval<const container_type&>().begin())) {
return data_.begin();
}
const_iterator cbegin() const
noexcept(noexcept(std::declval<const container_type&>().cbegin())) {
return data_.cbegin();
}
iterator end()
noexcept(noexcept(std::declval<container_type&>().end())) {
return data_.end();
}
const_iterator end() const
noexcept(noexcept(std::declval<const container_type&>().end())) {
return data_.end();
}
const_iterator cend() const
noexcept(noexcept(std::declval<const container_type&>().cend())) {
return data_.cend();
}
reverse_iterator rbegin()
noexcept(noexcept(std::declval<container_type&>().rbegin())) {
return data_.rbegin();
}
const_reverse_iterator rbegin() const
noexcept(noexcept(std::declval<const container_type&>().rbegin())) {
return data_.rbegin();
}
const_reverse_iterator crbegin() const
noexcept(noexcept(std::declval<const container_type&>().crbegin())) {
return data_.crbegin();
}
reverse_iterator rend()
noexcept(noexcept(std::declval<container_type&>().rend())) {
return data_.rend();
}
const_reverse_iterator rend() const
noexcept(noexcept(std::declval<const container_type&>().rend())) {
return data_.rend();
}
const_reverse_iterator crend() const
noexcept(noexcept(std::declval<const container_type&>().crend())) {
return data_.crend();
}
bool empty() const
noexcept(noexcept(std::declval<const container_type&>().empty())) {
return data_.empty();
}
size_type size() const
noexcept(noexcept(std::declval<const container_type&>().size())) {
return data_.size();
}
size_type max_size() const
noexcept(noexcept(std::declval<const container_type&>().max_size())) {
return data_.max_size();
}
size_type capacity() const
noexcept(noexcept(std::declval<const container_type&>().capacity())) {
return data_.capacity();
}
void reserve(size_type ncapacity) {
data_.reserve(ncapacity);
}
void shrink_to_fit() {
data_.shrink_to_fit();
}
mapped_type& operator[](key_type&& key) {
const iterator iter = find(key);
return iter != end()
? iter->second
: emplace(std::move(key), mapped_type())->second;
}
mapped_type& operator[](const key_type& key) {
const iterator iter = find(key);
return iter != end()
? iter->second
: emplace(key, mapped_type())->second;
}
mapped_type& at(const key_type& key) {
const iterator iter = find(key);
if ( iter != end() ) {
return iter->second;
}
throw std::out_of_range("flat_multimap::at: key not found");
}
const mapped_type& at(const key_type& key) const {
const const_iterator iter = find(key);
if ( iter != end() ) {
return iter->second;
}
throw std::out_of_range("flat_multimap::at: key not found");
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
mapped_type&>
at(const K& key) {
const iterator iter = find(key);
if ( iter != end() ) {
return iter->second;
}
throw std::out_of_range("flat_multimap::at: key not found");
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
const mapped_type&>
at(const K& key) const {
const const_iterator iter = find(key);
if ( iter != end() ) {
return iter->second;
}
throw std::out_of_range("flat_multimap::at: key not found");
}
iterator insert(value_type&& value) {
const iterator iter = upper_bound(value.first);
return data_.insert(iter, std::move(value));
}
iterator insert(const value_type& value) {
const iterator iter = upper_bound(value.first);
return data_.insert(iter, value);
}
iterator insert(const_iterator hint, value_type&& value) {
return (hint == begin() || !this->operator()(value, *(hint - 1)))
&& (hint == end() || !this->operator()(*hint, value))
? data_.insert(hint, std::move(value))
: insert(std::move(value));
}
iterator insert(const_iterator hint, const value_type& value) {
return (hint == begin() || !this->operator()(value, *(hint - 1)))
&& (hint == end() || !this->operator()(*hint, value))
? data_.insert(hint, value)
: insert(value);
}
template < typename InputIter >
void insert(InputIter first, InputIter last) {
insert_range_(first, last);
}
template < typename InputIter >
void insert(sorted_range_t, InputIter first, InputIter last) {
insert_range_(sorted_range, first, last);
}
void insert(std::initializer_list<value_type> ilist) {
insert_range_(ilist.begin(), ilist.end());
}
void insert(sorted_range_t, std::initializer_list<value_type> ilist) {
insert_range_(sorted_range, ilist.begin(), ilist.end());
}
template < typename... Args >
iterator emplace(Args&&... args) {
return insert(value_type(std::forward<Args>(args)...));
}
template < typename... Args >
iterator emplace_hint(const_iterator hint, Args&&... args) {
return insert(hint, value_type(std::forward<Args>(args)...));
}
void clear()
noexcept(noexcept(std::declval<container_type&>().clear())) {
data_.clear();
}
iterator erase(const_iterator iter) {
return data_.erase(iter);
}
iterator erase(const_iterator first, const_iterator last) {
return data_.erase(first, last);
}
size_type erase(const key_type& key) {
const auto p = equal_range(key);
size_type r = std::distance(p.first, p.second);
erase(p.first, p.second);
return r;
}
void swap(flat_multimap& other)
noexcept(std::is_nothrow_swappable_v<base_type>
&& std::is_nothrow_swappable_v<container_type>)
{
using std::swap;
swap(
static_cast<base_type&>(*this),
static_cast<base_type&>(other));
swap(data_, other.data_);
}
size_type count(const key_type& key) const {
const auto p = equal_range(key);
return std::distance(p.first, p.second);
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
size_type>
count(const K& key) const {
const auto p = equal_range(key);
return std::distance(p.first, p.second);
}
iterator find(const key_type& key) {
const iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
const_iterator find(const key_type& key) const {
const const_iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
iterator>
find(const K& key) {
const iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
const_iterator>
find(const K& key) const {
const const_iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
bool contains(const key_type& key) const {
return find(key) != end();
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
bool>
contains(const K& key) const {
return find(key) != end();
}
std::pair<iterator, iterator> equal_range(const key_type& key) {
const base_type& comp = *this;
return std::equal_range(begin(), end(), key, comp);
}
std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
const base_type& comp = *this;
return std::equal_range(begin(), end(), key, comp);
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
std::pair<iterator, iterator>>
equal_range(const K& key) {
const base_type& comp = *this;
return std::equal_range(begin(), end(), key, comp);
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
std::pair<const_iterator, const_iterator>>
equal_range(const K& key) const {
const base_type& comp = *this;
return std::equal_range(begin(), end(), key, comp);
}
iterator lower_bound(const key_type& key) {
const base_type& comp = *this;
return std::lower_bound(begin(), end(), key, comp);
}
const_iterator lower_bound(const key_type& key) const {
const base_type& comp = *this;
return std::lower_bound(begin(), end(), key, comp);
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
iterator>
lower_bound(const K& key) {
const base_type& comp = *this;
return std::lower_bound(begin(), end(), key, comp);
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
const_iterator>
lower_bound(const K& key) const {
const base_type& comp = *this;
return std::lower_bound(begin(), end(), key, comp);
}
iterator upper_bound(const key_type& key) {
const base_type& comp = *this;
return std::upper_bound(begin(), end(), key, comp);
}
const_iterator upper_bound(const key_type& key) const {
const base_type& comp = *this;
return std::upper_bound(begin(), end(), key, comp);
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
iterator>
upper_bound(const K& key) {
const base_type& comp = *this;
return std::upper_bound(begin(), end(), key, comp);
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
const_iterator>
upper_bound(const K& key) const {
const base_type& comp = *this;
return std::upper_bound(begin(), end(), key, comp);
}
key_compare key_comp() const {
return *this;
}
value_compare value_comp() const {
return value_compare(key_comp());
}
private:
template < typename Iter >
void from_range_(Iter first, Iter last) {
assert(data_.empty());
data_.insert(data_.end(), first, last);
std::sort(data_.begin(), data_.end(), value_comp());
}
template < typename Iter >
void from_range_(sorted_range_t, Iter first, Iter last) {
assert(data_.empty());
assert(detail::is_sorted(first, last, value_comp()));
data_.insert(data_.end(), first, last);
}
private:
template < typename Iter >
void insert_range_(Iter first, Iter last) {
const auto mid_iter = data_.insert(data_.end(), first, last);
std::sort(mid_iter, data_.end(), value_comp());
std::inplace_merge(data_.begin(), mid_iter, data_.end(), value_comp());
}
template < typename Iter >
void insert_range_(sorted_range_t, Iter first, Iter last) {
assert(detail::is_sorted(first, last, value_comp()));
const auto mid_iter = data_.insert(data_.end(), first, last);
std::inplace_merge(data_.begin(), mid_iter, data_.end(), value_comp());
}
private:
container_type data_;
};
}
namespace flat_hpp
{
template < typename Key
, typename Value
, typename Compare
, typename Container >
void swap(
flat_multimap<Key, Value, Compare, Container>& l,
flat_multimap<Key, Value, Compare, Container>& r)
noexcept(noexcept(l.swap(r)))
{
l.swap(r);
}
template < typename Key
, typename Value
, typename Compare
, typename Container >
bool operator==(
const flat_multimap<Key, Value, Compare, Container>& l,
const flat_multimap<Key, Value, Compare, Container>& r)
{
return l.size() == r.size()
&& std::equal(l.begin(), l.end(), r.begin());
}
template < typename Key
, typename Value
, typename Compare
, typename Container >
bool operator!=(
const flat_multimap<Key, Value, Compare, Container>& l,
const flat_multimap<Key, Value, Compare, Container>& r)
{
return !(l == r);
}
template < typename Key
, typename Value
, typename Compare
, typename Container >
bool operator<(
const flat_multimap<Key, Value, Compare, Container>& l,
const flat_multimap<Key, Value, Compare, Container>& r)
{
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
}
template < typename Key
, typename Value
, typename Compare
, typename Container >
bool operator>(
const flat_multimap<Key, Value, Compare, Container>& l,
const flat_multimap<Key, Value, Compare, Container>& r)
{
return r < l;
}
template < typename Key
, typename Value
, typename Compare
, typename Container >
bool operator<=(
const flat_multimap<Key, Value, Compare, Container>& l,
const flat_multimap<Key, Value, Compare, Container>& r)
{
return !(r < l);
}
template < typename Key
, typename Value
, typename Compare
, typename Container >
bool operator>=(
const flat_multimap<Key, Value, Compare, Container>& l,
const flat_multimap<Key, Value, Compare, Container>& r)
{
return !(l < r);
}
}

View File

@@ -1,586 +0,0 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/flat.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "flat_fwd.hpp"
namespace flat_hpp
{
template < typename Key
, typename Compare
, typename Container >
class flat_multiset : private Compare {
using base_type = Compare;
public:
using key_type = Key;
using value_type = Key;
using size_type = typename Container::size_type;
using difference_type = typename Container::difference_type;
using key_compare = Compare;
using value_compare = Compare;
using container_type = Container;
using reference = typename Container::reference;
using const_reference = typename Container::const_reference;
using pointer = typename Container::pointer;
using const_pointer = typename Container::const_pointer;
using iterator = typename Container::const_iterator;
using const_iterator = typename Container::const_iterator;
using reverse_iterator = typename Container::const_reverse_iterator;
using const_reverse_iterator = typename Container::const_reverse_iterator;
public:
flat_multiset()
noexcept(std::is_nothrow_default_constructible_v<base_type>
&& std::is_nothrow_default_constructible_v<container_type>) {}
explicit flat_multiset(const Compare& c)
: base_type(c) {}
template < typename Allocator >
explicit flat_multiset(const Allocator& a)
: data_(a) {}
template < typename Allocator >
flat_multiset(const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {}
template < typename InputIter >
flat_multiset(InputIter first, InputIter last) {
from_range_(first, last);
}
template < typename InputIter >
flat_multiset(sorted_range_t, InputIter first, InputIter last) {
from_range_(sorted_range, first, last);
}
template < typename InputIter >
flat_multiset(InputIter first, InputIter last, const Compare& c)
: base_type(c) {
from_range_(first, last);
}
template < typename InputIter >
flat_multiset(sorted_range_t, InputIter first, InputIter last, const Compare& c)
: base_type(c) {
from_range_(sorted_range, first, last);
}
template < typename InputIter, typename Allocator >
flat_multiset(InputIter first, InputIter last, const Allocator& a)
: data_(a) {
from_range_(first, last);
}
template < typename InputIter, typename Allocator >
flat_multiset(sorted_range_t, InputIter first, InputIter last, const Allocator& a)
: data_(a) {
from_range_(sorted_range, first, last);
}
template < typename InputIter, typename Allocator >
flat_multiset(InputIter first, InputIter last, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(first, last);
}
template < typename InputIter, typename Allocator >
flat_multiset(sorted_range_t, InputIter first, InputIter last, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(sorted_range, first, last);
}
flat_multiset(std::initializer_list<value_type> ilist) {
from_range_(ilist.begin(), ilist.end());
}
flat_multiset(sorted_range_t, std::initializer_list<value_type> ilist) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
flat_multiset(std::initializer_list<value_type> ilist, const Compare& c)
: base_type(c) {
from_range_(ilist.begin(), ilist.end());
}
flat_multiset(sorted_range_t, std::initializer_list<value_type> ilist, const Compare& c)
: base_type(c) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_multiset(std::initializer_list<value_type> ilist, const Allocator& a)
: data_(a) {
from_range_(ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_multiset(sorted_range_t, std::initializer_list<value_type> ilist, const Allocator& a)
: data_(a) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_multiset(std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_multiset(sorted_range_t, std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_multiset(flat_multiset&& other, const Allocator& a)
: base_type(static_cast<base_type&&>(other))
, data_(std::move(other.data_), a) {}
template < typename Allocator >
flat_multiset(const flat_multiset& other, const Allocator& a)
: base_type(static_cast<const base_type&>(other))
, data_(other.data_, a) {}
flat_multiset(flat_multiset&& other) = default;
flat_multiset(const flat_multiset& other) = default;
flat_multiset& operator=(flat_multiset&& other) = default;
flat_multiset& operator=(const flat_multiset& other) = default;
flat_multiset& operator=(std::initializer_list<value_type> ilist) {
flat_multiset(ilist).swap(*this);
return *this;
}
iterator begin()
noexcept(noexcept(std::declval<container_type&>().begin())) {
return data_.begin();
}
const_iterator begin() const
noexcept(noexcept(std::declval<const container_type&>().begin())) {
return data_.begin();
}
const_iterator cbegin() const
noexcept(noexcept(std::declval<const container_type&>().cbegin())) {
return data_.cbegin();
}
iterator end()
noexcept(noexcept(std::declval<container_type&>().end())) {
return data_.end();
}
const_iterator end() const
noexcept(noexcept(std::declval<const container_type&>().end())) {
return data_.end();
}
const_iterator cend() const
noexcept(noexcept(std::declval<const container_type&>().cend())) {
return data_.cend();
}
reverse_iterator rbegin()
noexcept(noexcept(std::declval<container_type&>().rbegin())) {
return data_.rbegin();
}
const_reverse_iterator rbegin() const
noexcept(noexcept(std::declval<const container_type&>().rbegin())) {
return data_.rbegin();
}
const_reverse_iterator crbegin() const
noexcept(noexcept(std::declval<const container_type&>().crbegin())) {
return data_.crbegin();
}
reverse_iterator rend()
noexcept(noexcept(std::declval<container_type&>().rend())) {
return data_.rend();
}
const_reverse_iterator rend() const
noexcept(noexcept(std::declval<const container_type&>().rend())) {
return data_.rend();
}
const_reverse_iterator crend() const
noexcept(noexcept(std::declval<const container_type&>().crend())) {
return data_.crend();
}
bool empty() const
noexcept(noexcept(std::declval<const container_type&>().empty())) {
return data_.empty();
}
size_type size() const
noexcept(noexcept(std::declval<const container_type&>().size())) {
return data_.size();
}
size_type max_size() const
noexcept(noexcept(std::declval<const container_type&>().max_size())) {
return data_.max_size();
}
size_type capacity() const
noexcept(noexcept(std::declval<const container_type&>().capacity())) {
return data_.capacity();
}
void reserve(size_type ncapacity) {
data_.reserve(ncapacity);
}
void shrink_to_fit() {
data_.shrink_to_fit();
}
iterator insert(value_type&& value) {
const iterator iter = upper_bound(value);
return data_.insert(iter, std::move(value));
}
iterator insert(const value_type& value) {
const iterator iter = upper_bound(value);
return data_.insert(iter, value);
}
iterator insert(const_iterator hint, value_type&& value) {
return (hint == begin() || !this->operator()(value, *(hint - 1)))
&& (hint == end() || !this->operator()(*hint, value))
? data_.insert(hint, std::move(value))
: insert(std::move(value));
}
iterator insert(const_iterator hint, const value_type& value) {
return (hint == begin() || !this->operator()(value, *(hint - 1)))
&& (hint == end() || !this->operator()(*hint, value))
? data_.insert(hint, value)
: insert(value);
}
template < typename InputIter >
void insert(InputIter first, InputIter last) {
insert_range_(first, last);
}
template < typename InputIter >
void insert(sorted_range_t, InputIter first, InputIter last) {
insert_range_(sorted_range, first, last);
}
void insert(std::initializer_list<value_type> ilist) {
insert_range_(ilist.begin(), ilist.end());
}
void insert(sorted_range_t, std::initializer_list<value_type> ilist) {
insert_range_(sorted_range, ilist.begin(), ilist.end());
}
template < typename... Args >
iterator emplace(Args&&... args) {
return insert(value_type(std::forward<Args>(args)...));
}
template < typename... Args >
iterator emplace_hint(const_iterator hint, Args&&... args) {
return insert(hint, value_type(std::forward<Args>(args)...));
}
void clear()
noexcept(noexcept(std::declval<container_type&>().clear())) {
data_.clear();
}
iterator erase(const_iterator iter) {
return data_.erase(iter);
}
iterator erase(const_iterator first, const_iterator last) {
return data_.erase(first, last);
}
size_type erase(const key_type& key) {
const auto p = equal_range(key);
size_type r = std::distance(p.first, p.second);
erase(p.first, p.second);
return r;
}
void swap(flat_multiset& other)
noexcept(std::is_nothrow_swappable_v<base_type>
&& std::is_nothrow_swappable_v<container_type>)
{
using std::swap;
swap(
static_cast<base_type&>(*this),
static_cast<base_type&>(other));
swap(data_, other.data_);
}
size_type count(const key_type& key) const {
const auto p = equal_range(key);
return std::distance(p.first, p.second);
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
size_type>
count(const K& key) const {
const auto p = equal_range(key);
return std::distance(p.first, p.second);
}
iterator find(const key_type& key) {
const iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
const_iterator find(const key_type& key) const {
const const_iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
iterator>
find(const K& key) {
const iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
const_iterator>
find(const K& key) const {
const const_iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
bool contains(const key_type& key) const {
return find(key) != end();
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
bool>
contains(const K& key) const {
return find(key) != end();
}
std::pair<iterator, iterator> equal_range(const key_type& key) {
return std::equal_range(begin(), end(), key, key_comp());
}
std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
return std::equal_range(begin(), end(), key, key_comp());
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
std::pair<iterator, iterator>>
equal_range(const K& key) {
return std::equal_range(begin(), end(), key, key_comp());
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
std::pair<const_iterator, const_iterator>>
equal_range(const K& key) const {
return std::equal_range(begin(), end(), key, key_comp());
}
iterator lower_bound(const key_type& key) {
return std::lower_bound(begin(), end(), key, key_comp());
}
const_iterator lower_bound(const key_type& key) const {
return std::lower_bound(begin(), end(), key, key_comp());
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
iterator>
lower_bound(const K& key) {
return std::lower_bound(begin(), end(), key, key_comp());
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
const_iterator>
lower_bound(const K& key) const {
return std::lower_bound(begin(), end(), key, key_comp());
}
iterator upper_bound(const key_type& key) {
return std::upper_bound(begin(), end(), key, key_comp());
}
const_iterator upper_bound(const key_type& key) const {
return std::upper_bound(begin(), end(), key, key_comp());
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
iterator>
upper_bound(const K& key) {
return std::upper_bound(begin(), end(), key, key_comp());
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
const_iterator>
upper_bound(const K& key) const {
return std::upper_bound(begin(), end(), key, key_comp());
}
key_compare key_comp() const {
return *this;
}
value_compare value_comp() const {
return value_compare(key_comp());
}
private:
template < typename Iter >
void from_range_(Iter first, Iter last) {
assert(data_.empty());
data_.insert(data_.end(), first, last);
std::sort(data_.begin(), data_.end(), key_comp());
}
template < typename Iter >
void from_range_(sorted_range_t, Iter first, Iter last) {
assert(data_.empty());
assert(detail::is_sorted(first, last, key_comp()));
data_.insert(data_.end(), first, last);
}
private:
template < typename Iter >
void insert_range_(Iter first, Iter last) {
const auto mid_iter = data_.insert(data_.end(), first, last);
std::sort(mid_iter, data_.end(), key_comp());
std::inplace_merge(data_.begin(), mid_iter, data_.end(), key_comp());
}
template < typename Iter >
void insert_range_(sorted_range_t, Iter first, Iter last) {
assert(detail::is_sorted(first, last, key_comp()));
const auto mid_iter = data_.insert(data_.end(), first, last);
std::inplace_merge(data_.begin(), mid_iter, data_.end(), key_comp());
}
private:
container_type data_;
};
}
namespace flat_hpp
{
template < typename Key
, typename Compare
, typename Container >
void swap(
flat_multiset<Key, Compare, Container>& l,
flat_multiset<Key, Compare, Container>& r)
noexcept(noexcept(l.swap(r)))
{
l.swap(r);
}
template < typename Key
, typename Compare
, typename Container >
bool operator==(
const flat_multiset<Key, Compare, Container>& l,
const flat_multiset<Key, Compare, Container>& r)
{
return l.size() == r.size()
&& std::equal(l.begin(), l.end(), r.begin());
}
template < typename Key
, typename Compare
, typename Container >
bool operator!=(
const flat_multiset<Key, Compare, Container>& l,
const flat_multiset<Key, Compare, Container>& r)
{
return !(l == r);
}
template < typename Key
, typename Compare
, typename Container >
bool operator<(
const flat_multiset<Key, Compare, Container>& l,
const flat_multiset<Key, Compare, Container>& r)
{
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
}
template < typename Key
, typename Compare
, typename Container >
bool operator>(
const flat_multiset<Key, Compare, Container>& l,
const flat_multiset<Key, Compare, Container>& r)
{
return r < l;
}
template < typename Key
, typename Compare
, typename Container >
bool operator<=(
const flat_multiset<Key, Compare, Container>& l,
const flat_multiset<Key, Compare, Container>& r)
{
return !(r < l);
}
template < typename Key
, typename Compare
, typename Container >
bool operator>=(
const flat_multiset<Key, Compare, Container>& l,
const flat_multiset<Key, Compare, Container>& r)
{
return !(l < r);
}
}

View File

@@ -1,659 +0,0 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/flat.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include "flat_fwd.hpp"
namespace flat_hpp
{
template < typename Key
, typename Compare
, typename Container >
class flat_set : private Compare {
using base_type = Compare;
public:
using key_type = Key;
using value_type = Key;
using size_type = typename Container::size_type;
using difference_type = typename Container::difference_type;
using key_compare = Compare;
using value_compare = Compare;
using container_type = Container;
using reference = typename Container::reference;
using const_reference = typename Container::const_reference;
using pointer = typename Container::pointer;
using const_pointer = typename Container::const_pointer;
using iterator = typename Container::const_iterator;
using const_iterator = typename Container::const_iterator;
using reverse_iterator = typename Container::const_reverse_iterator;
using const_reverse_iterator = typename Container::const_reverse_iterator;
public:
flat_set()
noexcept(std::is_nothrow_default_constructible_v<base_type>
&& std::is_nothrow_default_constructible_v<container_type>) {}
explicit flat_set(const Compare& c)
: base_type(c) {}
template < typename Allocator >
explicit flat_set(const Allocator& a)
: data_(a) {}
template < typename Allocator >
flat_set(const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {}
template < typename InputIter >
flat_set(InputIter first, InputIter last) {
from_range_(first, last);
}
template < typename InputIter >
flat_set(sorted_range_t, InputIter first, InputIter last) {
from_range_(sorted_range, first, last);
}
template < typename InputIter >
flat_set(sorted_unique_range_t, InputIter first, InputIter last) {
from_range_(sorted_unique_range, first, last);
}
template < typename InputIter >
flat_set(InputIter first, InputIter last, const Compare& c)
: base_type(c) {
from_range_(first, last);
}
template < typename InputIter >
flat_set(sorted_range_t, InputIter first, InputIter last, const Compare& c)
: base_type(c) {
from_range_(sorted_range, first, last);
}
template < typename InputIter >
flat_set(sorted_unique_range_t, InputIter first, InputIter last, const Compare& c)
: base_type(c) {
from_range_(sorted_unique_range, first, last);
}
template < typename InputIter, typename Allocator >
flat_set(InputIter first, InputIter last, const Allocator& a)
: data_(a) {
from_range_(first, last);
}
template < typename InputIter, typename Allocator >
flat_set(sorted_range_t, InputIter first, InputIter last, const Allocator& a)
: data_(a) {
from_range_(sorted_range, first, last);
}
template < typename InputIter, typename Allocator >
flat_set(sorted_unique_range_t, InputIter first, InputIter last, const Allocator& a)
: data_(a) {
from_range_(sorted_unique_range, first, last);
}
template < typename InputIter, typename Allocator >
flat_set(InputIter first, InputIter last, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(first, last);
}
template < typename InputIter, typename Allocator >
flat_set(sorted_range_t, InputIter first, InputIter last, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(sorted_range, first, last);
}
template < typename InputIter, typename Allocator >
flat_set(sorted_unique_range_t, InputIter first, InputIter last, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(sorted_unique_range, first, last);
}
flat_set(std::initializer_list<value_type> ilist) {
from_range_(ilist.begin(), ilist.end());
}
flat_set(sorted_range_t, std::initializer_list<value_type> ilist) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
flat_set(sorted_unique_range_t, std::initializer_list<value_type> ilist) {
from_range_(sorted_unique_range, ilist.begin(), ilist.end());
}
flat_set(std::initializer_list<value_type> ilist, const Compare& c)
: base_type(c) {
from_range_(ilist.begin(), ilist.end());
}
flat_set(sorted_range_t, std::initializer_list<value_type> ilist, const Compare& c)
: base_type(c) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
flat_set(sorted_unique_range_t, std::initializer_list<value_type> ilist, const Compare& c)
: base_type(c) {
from_range_(sorted_unique_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_set(std::initializer_list<value_type> ilist, const Allocator& a)
: data_(a) {
from_range_(ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_set(sorted_range_t, std::initializer_list<value_type> ilist, const Allocator& a)
: data_(a) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_set(sorted_unique_range_t, std::initializer_list<value_type> ilist, const Allocator& a)
: data_(a) {
from_range_(sorted_unique_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_set(std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_set(sorted_range_t, std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(sorted_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_set(sorted_unique_range_t, std::initializer_list<value_type> ilist, const Compare& c, const Allocator& a)
: base_type(c)
, data_(a) {
from_range_(sorted_unique_range, ilist.begin(), ilist.end());
}
template < typename Allocator >
flat_set(flat_set&& other, const Allocator& a)
: base_type(static_cast<base_type&&>(other))
, data_(std::move(other.data_), a) {}
template < typename Allocator >
flat_set(const flat_set& other, const Allocator& a)
: base_type(static_cast<const base_type&>(other))
, data_(other.data_, a) {}
flat_set(flat_set&& other) = default;
flat_set(const flat_set& other) = default;
flat_set& operator=(flat_set&& other) = default;
flat_set& operator=(const flat_set& other) = default;
flat_set& operator=(std::initializer_list<value_type> ilist) {
flat_set(ilist).swap(*this);
return *this;
}
iterator begin()
noexcept(noexcept(std::declval<container_type&>().begin())) {
return data_.begin();
}
const_iterator begin() const
noexcept(noexcept(std::declval<const container_type&>().begin())) {
return data_.begin();
}
const_iterator cbegin() const
noexcept(noexcept(std::declval<const container_type&>().cbegin())) {
return data_.cbegin();
}
iterator end()
noexcept(noexcept(std::declval<container_type&>().end())) {
return data_.end();
}
const_iterator end() const
noexcept(noexcept(std::declval<const container_type&>().end())) {
return data_.end();
}
const_iterator cend() const
noexcept(noexcept(std::declval<const container_type&>().cend())) {
return data_.cend();
}
reverse_iterator rbegin()
noexcept(noexcept(std::declval<container_type&>().rbegin())) {
return data_.rbegin();
}
const_reverse_iterator rbegin() const
noexcept(noexcept(std::declval<const container_type&>().rbegin())) {
return data_.rbegin();
}
const_reverse_iterator crbegin() const
noexcept(noexcept(std::declval<const container_type&>().crbegin())) {
return data_.crbegin();
}
reverse_iterator rend()
noexcept(noexcept(std::declval<container_type&>().rend())) {
return data_.rend();
}
const_reverse_iterator rend() const
noexcept(noexcept(std::declval<const container_type&>().rend())) {
return data_.rend();
}
const_reverse_iterator crend() const
noexcept(noexcept(std::declval<const container_type&>().crend())) {
return data_.crend();
}
bool empty() const
noexcept(noexcept(std::declval<const container_type&>().empty())) {
return data_.empty();
}
size_type size() const
noexcept(noexcept(std::declval<const container_type&>().size())) {
return data_.size();
}
size_type max_size() const
noexcept(noexcept(std::declval<const container_type&>().max_size())) {
return data_.max_size();
}
size_type capacity() const
noexcept(noexcept(std::declval<const container_type&>().capacity())) {
return data_.capacity();
}
void reserve(size_type ncapacity) {
data_.reserve(ncapacity);
}
void shrink_to_fit() {
data_.shrink_to_fit();
}
std::pair<iterator, bool> insert(value_type&& value) {
const iterator iter = lower_bound(value);
return iter == end() || this->operator()(value, *iter)
? std::make_pair(data_.insert(iter, std::move(value)), true)
: std::make_pair(iter, false);
}
std::pair<iterator, bool> insert(const value_type& value) {
const iterator iter = lower_bound(value);
return iter == end() || this->operator()(value, *iter)
? std::make_pair(data_.insert(iter, value), true)
: std::make_pair(iter, false);
}
iterator insert(const_iterator hint, value_type&& value) {
return (hint == begin() || this->operator()(*(hint - 1), value))
&& (hint == end() || this->operator()(value, *hint))
? data_.insert(hint, std::move(value))
: insert(std::move(value)).first;
}
iterator insert(const_iterator hint, const value_type& value) {
return (hint == begin() || this->operator()(*(hint - 1), value))
&& (hint == end() || this->operator()(value, *hint))
? data_.insert(hint, value)
: insert(value).first;
}
template < typename InputIter >
void insert(InputIter first, InputIter last) {
insert_range_(first, last);
}
template < typename InputIter >
void insert(sorted_range_t, InputIter first, InputIter last) {
insert_range_(sorted_range, first, last);
}
void insert(std::initializer_list<value_type> ilist) {
insert_range_(ilist.begin(), ilist.end());
}
void insert(sorted_range_t, std::initializer_list<value_type> ilist) {
insert_range_(sorted_range, ilist.begin(), ilist.end());
}
template < typename... Args >
std::pair<iterator, bool> emplace(Args&&... args) {
return insert(value_type(std::forward<Args>(args)...));
}
template < typename... Args >
iterator emplace_hint(const_iterator hint, Args&&... args) {
return insert(hint, value_type(std::forward<Args>(args)...));
}
void clear()
noexcept(noexcept(std::declval<container_type&>().clear())) {
data_.clear();
}
iterator erase(const_iterator iter) {
return data_.erase(iter);
}
iterator erase(const_iterator first, const_iterator last) {
return data_.erase(first, last);
}
size_type erase(const key_type& key) {
const const_iterator iter = find(key);
return iter != end()
? (erase(iter), 1)
: 0;
}
void swap(flat_set& other)
noexcept(std::is_nothrow_swappable_v<base_type>
&& std::is_nothrow_swappable_v<container_type>)
{
using std::swap;
swap(
static_cast<base_type&>(*this),
static_cast<base_type&>(other));
swap(data_, other.data_);
}
size_type count(const key_type& key) const {
const const_iterator iter = find(key);
return iter != end() ? 1 : 0;
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
size_type>
count(const K& key) const {
const const_iterator iter = find(key);
return iter != end() ? 1 : 0;
}
iterator find(const key_type& key) {
const iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
const_iterator find(const key_type& key) const {
const const_iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
iterator>
find(const K& key) {
const iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
const_iterator>
find(const K& key) const {
const const_iterator iter = lower_bound(key);
return iter != end() && !this->operator()(key, *iter)
? iter
: end();
}
bool contains(const key_type& key) const {
return find(key) != end();
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
bool>
contains(const K& key) const {
return find(key) != end();
}
std::pair<iterator, iterator> equal_range(const key_type& key) {
return std::equal_range(begin(), end(), key, key_comp());
}
std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const {
return std::equal_range(begin(), end(), key, key_comp());
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
std::pair<iterator, iterator>>
equal_range(const K& key) {
return std::equal_range(begin(), end(), key, key_comp());
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
std::pair<const_iterator, const_iterator>>
equal_range(const K& key) const {
return std::equal_range(begin(), end(), key, key_comp());
}
iterator lower_bound(const key_type& key) {
return std::lower_bound(begin(), end(), key, key_comp());
}
const_iterator lower_bound(const key_type& key) const {
return std::lower_bound(begin(), end(), key, key_comp());
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
iterator>
lower_bound(const K& key) {
return std::lower_bound(begin(), end(), key, key_comp());
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
const_iterator>
lower_bound(const K& key) const {
return std::lower_bound(begin(), end(), key, key_comp());
}
iterator upper_bound(const key_type& key) {
return std::upper_bound(begin(), end(), key, key_comp());
}
const_iterator upper_bound(const key_type& key) const {
return std::upper_bound(begin(), end(), key, key_comp());
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
iterator>
upper_bound(const K& key) {
return std::upper_bound(begin(), end(), key, key_comp());
}
template < typename K >
std::enable_if_t<
detail::is_transparent_v<Compare, K>,
const_iterator>
upper_bound(const K& key) const {
return std::upper_bound(begin(), end(), key, key_comp());
}
key_compare key_comp() const {
return *this;
}
value_compare value_comp() const {
return value_compare(key_comp());
}
private:
template < typename Iter >
void from_range_(Iter first, Iter last) {
assert(data_.empty());
data_.insert(data_.end(), first, last);
std::sort(data_.begin(), data_.end(), key_comp());
data_.erase(
std::unique(data_.begin(), data_.end(),
detail::eq_compare<key_compare>(key_comp())),
data_.end());
}
template < typename Iter >
void from_range_(sorted_range_t, Iter first, Iter last) {
assert(data_.empty());
assert(detail::is_sorted(first, last, key_comp()));
data_.insert(data_.end(), first, last);
data_.erase(
std::unique(data_.begin(), data_.end(),
detail::eq_compare<key_compare>(key_comp())),
data_.end());
}
template < typename Iter >
void from_range_(sorted_unique_range_t, Iter first, Iter last) {
assert(data_.empty());
assert(detail::is_sorted_unique(first, last, key_comp()));
data_.insert(data_.end(), first, last);
}
private:
template < typename Iter >
void insert_range_(Iter first, Iter last) {
const auto mid_iter = data_.insert(data_.end(), first, last);
std::sort(mid_iter, data_.end(), key_comp());
std::inplace_merge(data_.begin(), mid_iter, data_.end(), key_comp());
data_.erase(
std::unique(data_.begin(), data_.end(),
detail::eq_compare<key_compare>(key_comp())),
data_.end());
}
template < typename Iter >
void insert_range_(sorted_range_t, Iter first, Iter last) {
assert(detail::is_sorted(first, last, key_comp()));
const auto mid_iter = data_.insert(data_.end(), first, last);
std::inplace_merge(data_.begin(), mid_iter, data_.end(), key_comp());
data_.erase(
std::unique(data_.begin(), data_.end(),
detail::eq_compare<key_compare>(key_comp())),
data_.end());
}
private:
container_type data_;
};
}
namespace flat_hpp
{
template < typename Key
, typename Compare
, typename Container >
void swap(
flat_set<Key, Compare, Container>& l,
flat_set<Key, Compare, Container>& r)
noexcept(noexcept(l.swap(r)))
{
l.swap(r);
}
template < typename Key
, typename Compare
, typename Container >
bool operator==(
const flat_set<Key, Compare, Container>& l,
const flat_set<Key, Compare, Container>& r)
{
return l.size() == r.size()
&& std::equal(l.begin(), l.end(), r.begin());
}
template < typename Key
, typename Compare
, typename Container >
bool operator!=(
const flat_set<Key, Compare, Container>& l,
const flat_set<Key, Compare, Container>& r)
{
return !(l == r);
}
template < typename Key
, typename Compare
, typename Container >
bool operator<(
const flat_set<Key, Compare, Container>& l,
const flat_set<Key, Compare, Container>& r)
{
return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
}
template < typename Key
, typename Compare
, typename Container >
bool operator>(
const flat_set<Key, Compare, Container>& l,
const flat_set<Key, Compare, Container>& r)
{
return r < l;
}
template < typename Key
, typename Compare
, typename Container >
bool operator<=(
const flat_set<Key, Compare, Container>& l,
const flat_set<Key, Compare, Container>& r)
{
return !(r < l);
}
template < typename Key
, typename Compare
, typename Container >
bool operator>=(
const flat_set<Key, Compare, Container>& l,
const flat_set<Key, Compare, Container>& r)
{
return !(l < r);
}
}

View File

@@ -1,248 +0,0 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/invoke.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include <tuple>
#include <utility>
#include <functional>
#include <type_traits>
#define INVOKE_HPP_NOEXCEPT_RETURN(...) \
noexcept(noexcept(__VA_ARGS__)) { return __VA_ARGS__; }
#define INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(...) \
noexcept(noexcept(__VA_ARGS__)) -> decltype (__VA_ARGS__) { return __VA_ARGS__; }
//
// void_t
//
namespace invoke_hpp
{
namespace impl
{
template < typename... Args >
struct make_void {
using type = void;
};
}
template < typename... Args >
using void_t = typename impl::make_void<Args...>::type;
}
//
// is_reference_wrapper
//
namespace invoke_hpp
{
namespace impl
{
template < typename T >
struct is_reference_wrapper_impl
: std::false_type {};
template < typename U >
struct is_reference_wrapper_impl<std::reference_wrapper<U>>
: std::true_type {};
}
template < typename T >
struct is_reference_wrapper
: impl::is_reference_wrapper_impl<std::remove_cv_t<T>> {};
}
//
// invoke
//
namespace invoke_hpp
{
namespace impl
{
//
// invoke_member_object_impl
//
template
<
typename Base, typename F, typename Derived,
typename std::enable_if_t<std::is_base_of<Base, std::decay_t<Derived>>::value, int> = 0
>
constexpr auto invoke_member_object_impl(F Base::* f, Derived&& ref)
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
std::forward<Derived>(ref).*f)
template
<
typename Base, typename F, typename RefWrap,
typename std::enable_if_t<is_reference_wrapper<std::decay_t<RefWrap>>::value, int> = 0
>
constexpr auto invoke_member_object_impl(F Base::* f, RefWrap&& ref)
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
ref.get().*f)
template
<
typename Base, typename F, typename Pointer,
typename std::enable_if_t<
!std::is_base_of<Base, std::decay_t<Pointer>>::value &&
!is_reference_wrapper<std::decay_t<Pointer>>::value
, int> = 0
>
constexpr auto invoke_member_object_impl(F Base::* f, Pointer&& ptr)
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
(*std::forward<Pointer>(ptr)).*f)
//
// invoke_member_function_impl
//
template
<
typename Base, typename F, typename Derived, typename... Args,
typename std::enable_if_t<std::is_base_of<Base, std::decay_t<Derived>>::value, int> = 0
>
constexpr auto invoke_member_function_impl(F Base::* f, Derived&& ref, Args&&... args)
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
(std::forward<Derived>(ref).*f)(std::forward<Args>(args)...))
template
<
typename Base, typename F, typename RefWrap, typename... Args,
typename std::enable_if_t<is_reference_wrapper<std::decay_t<RefWrap>>::value, int> = 0
>
constexpr auto invoke_member_function_impl(F Base::* f, RefWrap&& ref, Args&&... args)
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
(ref.get().*f)(std::forward<Args>(args)...))
template
<
typename Base, typename F, typename Pointer, typename... Args,
typename std::enable_if_t<
!std::is_base_of<Base, std::decay_t<Pointer>>::value &&
!is_reference_wrapper<std::decay_t<Pointer>>::value
, int> = 0
>
constexpr auto invoke_member_function_impl(F Base::* f, Pointer&& ptr, Args&&... args)
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
((*std::forward<Pointer>(ptr)).*f)(std::forward<Args>(args)...))
}
template
<
typename F, typename... Args,
typename std::enable_if_t<!std::is_member_pointer<std::decay_t<F>>::value, int> = 0
>
constexpr auto invoke(F&& f, Args&&... args)
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
std::forward<F>(f)(std::forward<Args>(args)...))
template
<
typename F, typename T,
typename std::enable_if_t<std::is_member_object_pointer<std::decay_t<F>>::value, int> = 0
>
constexpr auto invoke(F&& f, T&& t)
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
impl::invoke_member_object_impl(std::forward<F>(f), std::forward<T>(t)))
template
<
typename F, typename... Args,
typename std::enable_if_t<std::is_member_function_pointer<std::decay_t<F>>::value, int> = 0
>
constexpr auto invoke(F&& f, Args&&... args)
INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN(
impl::invoke_member_function_impl(std::forward<F>(f), std::forward<Args>(args)...))
}
//
// invoke_result
//
namespace invoke_hpp
{
namespace impl
{
struct invoke_result_impl_tag {};
template < typename Void, typename F, typename... Args >
struct invoke_result_impl {};
template < typename F, typename... Args >
struct invoke_result_impl<void_t<invoke_result_impl_tag, decltype(invoke_hpp::invoke(std::declval<F>(), std::declval<Args>()...))>, F, Args...> {
using type = decltype(invoke_hpp::invoke(std::declval<F>(), std::declval<Args>()...));
};
}
template < typename F, typename... Args >
struct invoke_result
: impl::invoke_result_impl<void, F, Args...> {};
template < typename F, typename... Args >
using invoke_result_t = typename invoke_result<F, Args...>::type;
}
//
// is_invocable
//
namespace invoke_hpp
{
namespace impl
{
struct is_invocable_r_impl_tag {};
template < typename Void, typename R, typename F, typename... Args >
struct is_invocable_r_impl
: std::false_type {};
template < typename R, typename F, typename... Args >
struct is_invocable_r_impl<void_t<is_invocable_r_impl_tag, invoke_result_t<F, Args...>>, R, F, Args...>
: std::conditional_t<
std::is_void<R>::value,
std::true_type,
std::is_convertible<invoke_result_t<F, Args...>, R>> {};
}
template < typename R, typename F, typename... Args >
struct is_invocable_r
: impl::is_invocable_r_impl<void, R, F, Args...> {};
template < typename F, typename... Args >
using is_invocable = is_invocable_r<void, F, Args...>;
}
//
// apply
//
namespace invoke_hpp
{
namespace impl
{
template < typename F, typename Tuple, std::size_t... I >
constexpr decltype(auto) apply_impl(F&& f, Tuple&& args, std::index_sequence<I...>)
INVOKE_HPP_NOEXCEPT_RETURN(
invoke_hpp::invoke(
std::forward<F>(f),
std::get<I>(std::forward<Tuple>(args))...))
}
template < typename F, typename Tuple >
constexpr decltype(auto) apply(F&& f, Tuple&& args)
INVOKE_HPP_NOEXCEPT_RETURN(
impl::apply_impl(
std::forward<F>(f),
std::forward<Tuple>(args),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>()))
}
#undef INVOKE_HPP_NOEXCEPT_RETURN
#undef INVOKE_HPP_NOEXCEPT_DECLTYPE_RETURN

View File

@@ -1,427 +0,0 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/promise.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include <cstdint>
#include <cassert>
#include <tuple>
#include <mutex>
#include <atomic>
#include <thread>
#include <chrono>
#include <memory>
#include <vector>
#include <utility>
#include <exception>
#include <stdexcept>
#include <type_traits>
#include <condition_variable>
#include "promise.hpp"
namespace jobber_hpp
{
using namespace promise_hpp;
enum class jobber_priority {
lowest,
below_normal,
normal,
above_normal,
highest
};
enum class jobber_wait_status {
no_timeout,
cancelled,
timeout
};
class jobber_cancelled_exception : public std::runtime_error {
public:
jobber_cancelled_exception()
: std::runtime_error("jobber has stopped working") {}
};
class jobber final : private detail::noncopyable {
public:
explicit jobber(std::size_t threads);
~jobber() noexcept;
using active_wait_result_t = std::pair<
jobber_wait_status,
std::size_t>;
template < typename F, typename... Args >
using async_invoke_result_t = invoke_hpp::invoke_result_t<
std::decay_t<F>,
std::decay_t<Args>...>;
template < typename F, typename... Args
, typename R = async_invoke_result_t<F, Args...> >
promise<R> async(F&& f, Args&&... args);
template < typename F, typename... Args
, typename R = async_invoke_result_t<F, Args...> >
promise<R> async(jobber_priority priority, F&& f, Args&&... args);
void pause() noexcept;
void resume() noexcept;
bool is_paused() const noexcept;
jobber_wait_status wait_all() const noexcept;
active_wait_result_t active_wait_all() noexcept;
active_wait_result_t active_wait_one() noexcept;
template < typename Rep, typename Period >
jobber_wait_status wait_all_for(
const std::chrono::duration<Rep, Period>& timeout_duration) const;
template < typename Clock, typename Duration >
jobber_wait_status wait_all_until(
const std::chrono::time_point<Clock, Duration>& timeout_time) const;
template < typename Rep, typename Period >
active_wait_result_t active_wait_all_for(
const std::chrono::duration<Rep, Period>& timeout_duration);
template < typename Clock, typename Duration >
active_wait_result_t active_wait_all_until(
const std::chrono::time_point<Clock, Duration>& timeout_time);
private:
class task;
using task_ptr = std::unique_ptr<task>;
template < typename R, typename F, typename... Args >
class concrete_task;
private:
void push_task_(jobber_priority priority, task_ptr task);
task_ptr pop_task_() noexcept;
void shutdown_() noexcept;
void worker_main_() noexcept;
void process_task_(std::unique_lock<std::mutex> lock) noexcept;
private:
std::vector<std::thread> threads_;
std::vector<std::pair<jobber_priority, task_ptr>> tasks_;
std::atomic<bool> paused_{false};
std::atomic<bool> cancelled_{false};
std::atomic<std::size_t> active_task_count_{0};
mutable std::mutex tasks_mutex_;
mutable std::condition_variable cond_var_;
};
class jobber::task : private noncopyable {
public:
virtual ~task() noexcept = default;
virtual void run() noexcept = 0;
virtual void cancel() noexcept = 0;
};
template < typename R, typename F, typename... Args >
class jobber::concrete_task : public task {
F f_;
std::tuple<Args...> args_;
promise<R> promise_;
public:
template < typename U >
concrete_task(U&& u, std::tuple<Args...>&& args);
void run() noexcept final;
void cancel() noexcept final;
promise<R> future() noexcept;
};
template < typename F, typename... Args >
class jobber::concrete_task<void, F, Args...> : public task {
F f_;
std::tuple<Args...> args_;
promise<void> promise_;
public:
template < typename U >
concrete_task(U&& u, std::tuple<Args...>&& args);
void run() noexcept final;
void cancel() noexcept final;
promise<void> future() noexcept;
};
}
namespace jobber_hpp
{
inline jobber::jobber(std::size_t threads) {
try {
threads_.resize(threads);
for ( std::thread& thread : threads_ ) {
thread = std::thread(&jobber::worker_main_, this);
}
} catch (...) {
shutdown_();
throw;
}
}
inline jobber::~jobber() noexcept {
shutdown_();
}
template < typename F, typename... Args, typename R >
promise<R> jobber::async(F&& f, Args&&... args) {
return async(
jobber_priority::normal,
std::forward<F>(f),
std::forward<Args>(args)...);
}
template < typename F, typename... Args, typename R >
promise<R> jobber::async(jobber_priority priority, F&& f, Args&&... args) {
using task_t = concrete_task<
R,
std::decay_t<F>,
std::decay_t<Args>...>;
std::unique_ptr<task_t> task = std::make_unique<task_t>(
std::forward<F>(f),
std::make_tuple(std::forward<Args>(args)...));
promise<R> future = task->future();
std::lock_guard<std::mutex> guard(tasks_mutex_);
push_task_(priority, std::move(task));
return future;
}
inline void jobber::pause() noexcept {
std::lock_guard<std::mutex> guard(tasks_mutex_);
paused_.store(true);
cond_var_.notify_all();
}
inline void jobber::resume() noexcept {
std::lock_guard<std::mutex> guard(tasks_mutex_);
paused_.store(false);
cond_var_.notify_all();
}
inline bool jobber::is_paused() const noexcept {
return paused_;
}
inline jobber_wait_status jobber::wait_all() const noexcept {
std::unique_lock<std::mutex> lock(tasks_mutex_);
cond_var_.wait(lock, [this](){
return cancelled_ || !active_task_count_;
});
return cancelled_
? jobber_wait_status::cancelled
: jobber_wait_status::no_timeout;
}
inline jobber::active_wait_result_t jobber::active_wait_all() noexcept {
std::size_t processed_tasks = 0;
while ( !cancelled_ && active_task_count_ ) {
std::unique_lock<std::mutex> lock(tasks_mutex_);
cond_var_.wait(lock, [this](){
return cancelled_ || !active_task_count_ || !tasks_.empty();
});
if ( !tasks_.empty() ) {
process_task_(std::move(lock));
++processed_tasks;
}
}
return std::make_pair(
cancelled_
? jobber_wait_status::cancelled
: jobber_wait_status::no_timeout,
processed_tasks);
}
inline jobber::active_wait_result_t jobber::active_wait_one() noexcept {
std::unique_lock<std::mutex> lock(tasks_mutex_);
if ( cancelled_ ) {
return std::make_pair(jobber_wait_status::cancelled, 0u);
}
if ( tasks_.empty() ) {
return std::make_pair(jobber_wait_status::no_timeout, 0u);
}
process_task_(std::move(lock));
return std::make_pair(jobber_wait_status::no_timeout, 1u);
}
template < typename Rep, typename Period >
jobber_wait_status jobber::wait_all_for(
const std::chrono::duration<Rep, Period>& timeout_duration) const
{
return wait_all_until(
std::chrono::steady_clock::now() + timeout_duration);
}
template < typename Clock, typename Duration >
jobber_wait_status jobber::wait_all_until(
const std::chrono::time_point<Clock, Duration>& timeout_time) const
{
std::unique_lock<std::mutex> lock(tasks_mutex_);
return cond_var_.wait_until(lock, timeout_time, [this](){
return cancelled_ || !active_task_count_;
}) ? jobber_wait_status::no_timeout
: jobber_wait_status::timeout;
}
template < typename Rep, typename Period >
jobber::active_wait_result_t jobber::active_wait_all_for(
const std::chrono::duration<Rep, Period>& timeout_duration)
{
return active_wait_all_until(
std::chrono::steady_clock::now() + timeout_duration);
}
template < typename Clock, typename Duration >
jobber::active_wait_result_t jobber::active_wait_all_until(
const std::chrono::time_point<Clock, Duration>& timeout_time)
{
std::size_t processed_tasks = 0;
while ( !cancelled_ && active_task_count_ ) {
if ( !(Clock::now() < timeout_time) ) {
return std::make_pair(
jobber_wait_status::timeout,
processed_tasks);
}
std::unique_lock<std::mutex> lock(tasks_mutex_);
cond_var_.wait_until(lock, timeout_time, [this](){
return cancelled_ || !active_task_count_ || !tasks_.empty();
});
if ( !tasks_.empty() ) {
process_task_(std::move(lock));
++processed_tasks;
}
}
return std::make_pair(
cancelled_
? jobber_wait_status::cancelled
: jobber_wait_status::no_timeout,
processed_tasks);
}
inline void jobber::push_task_(jobber_priority priority, task_ptr task) {
tasks_.emplace_back(priority, std::move(task));
std::push_heap(tasks_.begin(), tasks_.end());
++active_task_count_;
cond_var_.notify_one();
}
inline jobber::task_ptr jobber::pop_task_() noexcept {
if ( !tasks_.empty() ) {
std::pop_heap(tasks_.begin(), tasks_.end());
task_ptr task = std::move(tasks_.back().second);
tasks_.pop_back();
return task;
}
return nullptr;
}
inline void jobber::shutdown_() noexcept {
{
std::lock_guard<std::mutex> guard(tasks_mutex_);
while ( !tasks_.empty() ) {
task_ptr task = pop_task_();
if ( task ) {
task->cancel();
--active_task_count_;
}
}
cancelled_.store(true);
cond_var_.notify_all();
}
for ( std::thread& thread : threads_ ) {
if ( thread.joinable() ) {
thread.join();
}
}
}
inline void jobber::worker_main_() noexcept {
while ( true ) {
std::unique_lock<std::mutex> lock(tasks_mutex_);
cond_var_.wait(lock, [this](){
return cancelled_ || (!paused_ && !tasks_.empty());
});
if ( cancelled_ ) {
break;
}
process_task_(std::move(lock));
}
}
inline void jobber::process_task_(std::unique_lock<std::mutex> lock) noexcept {
assert(lock.owns_lock());
task_ptr task = pop_task_();
if ( task ) {
lock.unlock();
task->run();
lock.lock();
--active_task_count_;
cond_var_.notify_all();
}
}
}
namespace jobber_hpp
{
//
// concrete_task<R, F, Args...>
//
template < typename R, typename F, typename... Args >
template < typename U >
jobber::concrete_task<R, F, Args...>::concrete_task(U&& u, std::tuple<Args...>&& args)
: f_(std::forward<U>(u))
, args_(std::move(args)) {}
template < typename R, typename F, typename... Args >
void jobber::concrete_task<R, F, Args...>::run() noexcept {
try {
R value = invoke_hpp::apply(std::move(f_), std::move(args_));
promise_.resolve(std::move(value));
} catch (...) {
promise_.reject(std::current_exception());
}
}
template < typename R, typename F, typename... Args >
void jobber::concrete_task<R, F, Args...>::cancel() noexcept {
promise_.reject(jobber_cancelled_exception());
}
template < typename R, typename F, typename... Args >
promise<R> jobber::concrete_task<R, F, Args...>::future() noexcept {
return promise_;
}
//
// concrete_task<void, F, Args...>
//
template < typename F, typename... Args >
template < typename U >
jobber::concrete_task<void, F, Args...>::concrete_task(U&& u, std::tuple<Args...>&& args)
: f_(std::forward<U>(u))
, args_(std::move(args)) {}
template < typename F, typename... Args >
void jobber::concrete_task<void, F, Args...>::run() noexcept {
try {
invoke_hpp::apply(std::move(f_), std::move(args_));
promise_.resolve();
} catch (...) {
promise_.reject(std::current_exception());
}
}
template < typename F, typename... Args >
void jobber::concrete_task<void, F, Args...>::cancel() noexcept {
promise_.reject(jobber_cancelled_exception());
}
template < typename F, typename... Args >
promise<void> jobber::concrete_task<void, F, Args...>::future() noexcept {
return promise_;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,335 +0,0 @@
/*******************************************************************************
* This file is part of the "https://github.com/blackmatov/promise.hpp"
* For conditions of distribution and use, see copyright notice in LICENSE.md
* Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com)
******************************************************************************/
#pragma once
#include <cstdint>
#include <cassert>
#include <tuple>
#include <mutex>
#include <atomic>
#include <chrono>
#include <memory>
#include <vector>
#include <utility>
#include <exception>
#include <stdexcept>
#include <type_traits>
#include <condition_variable>
#include "promise.hpp"
namespace scheduler_hpp
{
using namespace promise_hpp;
enum class scheduler_priority {
lowest,
below_normal,
normal,
above_normal,
highest
};
enum class scheduler_processing_status {
done,
timeout,
cancelled
};
class scheduler_cancelled_exception : public std::runtime_error {
public:
scheduler_cancelled_exception()
: std::runtime_error("scheduler has stopped working") {}
};
class scheduler final : private detail::noncopyable {
public:
scheduler();
~scheduler() noexcept;
using processing_result_t = std::pair<
scheduler_processing_status,
std::size_t>;
template < typename F, typename... Args >
using schedule_invoke_result_t = invoke_hpp::invoke_result_t<
std::decay_t<F>,
std::decay_t<Args>...>;
template < typename F, typename... Args
, typename R = schedule_invoke_result_t<F, Args...> >
promise<R> schedule(F&& f, Args&&... args);
template < typename F, typename... Args
, typename R = schedule_invoke_result_t<F, Args...> >
promise<R> schedule(scheduler_priority scheduler_priority, F&& f, Args&&... args);
processing_result_t process_one_task() noexcept;
processing_result_t process_all_tasks() noexcept;
template < typename Rep, typename Period >
processing_result_t process_tasks_for(
const std::chrono::duration<Rep, Period>& timeout_duration) noexcept;
template < typename Clock, typename Duration >
processing_result_t process_tasks_until(
const std::chrono::time_point<Clock, Duration>& timeout_time) noexcept;
private:
class task;
using task_ptr = std::unique_ptr<task>;
template < typename R, typename F, typename... Args >
class concrete_task;
private:
void push_task_(scheduler_priority scheduler_priority, task_ptr task);
task_ptr pop_task_() noexcept;
void shutdown_() noexcept;
void process_task_(std::unique_lock<std::mutex> lock) noexcept;
private:
std::vector<std::pair<scheduler_priority, task_ptr>> tasks_;
std::atomic<bool> cancelled_{false};
std::atomic<std::size_t> active_task_count_{0};
mutable std::mutex tasks_mutex_;
mutable std::condition_variable cond_var_;
};
class scheduler::task : private noncopyable {
public:
virtual ~task() noexcept = default;
virtual void run() noexcept = 0;
virtual void cancel() noexcept = 0;
};
template < typename R, typename F, typename... Args >
class scheduler::concrete_task : public task {
F f_;
std::tuple<Args...> args_;
promise<R> promise_;
public:
template < typename U >
concrete_task(U&& u, std::tuple<Args...>&& args);
void run() noexcept final;
void cancel() noexcept final;
promise<R> future() noexcept;
};
template < typename F, typename... Args >
class scheduler::concrete_task<void, F, Args...> : public task {
F f_;
std::tuple<Args...> args_;
promise<void> promise_;
public:
template < typename U >
concrete_task(U&& u, std::tuple<Args...>&& args);
void run() noexcept final;
void cancel() noexcept final;
promise<void> future() noexcept;
};
}
namespace scheduler_hpp
{
inline scheduler::scheduler() = default;
inline scheduler::~scheduler() noexcept {
shutdown_();
}
template < typename F, typename... Args, typename R >
promise<R> scheduler::schedule(F&& f, Args&&... args) {
return schedule(
scheduler_priority::normal,
std::forward<F>(f),
std::forward<Args>(args)...);
}
template < typename F, typename... Args, typename R >
promise<R> scheduler::schedule(scheduler_priority priority, F&& f, Args&&... args) {
using task_t = concrete_task<
R,
std::decay_t<F>,
std::decay_t<Args>...>;
std::unique_ptr<task_t> task = std::make_unique<task_t>(
std::forward<F>(f),
std::make_tuple(std::forward<Args>(args)...));
promise<R> future = task->future();
std::lock_guard<std::mutex> guard(tasks_mutex_);
push_task_(priority, std::move(task));
return future;
}
inline scheduler::processing_result_t scheduler::process_one_task() noexcept {
std::unique_lock<std::mutex> lock(tasks_mutex_);
if ( cancelled_ ) {
return std::make_pair(scheduler_processing_status::cancelled, 0u);
}
if ( tasks_.empty() ) {
return std::make_pair(scheduler_processing_status::done, 0u);
}
process_task_(std::move(lock));
return std::make_pair(scheduler_processing_status::done, 1u);
}
inline scheduler::processing_result_t scheduler::process_all_tasks() noexcept {
std::size_t processed_tasks = 0;
while ( !cancelled_ && active_task_count_ ) {
std::unique_lock<std::mutex> lock(tasks_mutex_);
cond_var_.wait(lock, [this](){
return cancelled_ || !active_task_count_ || !tasks_.empty();
});
if ( !tasks_.empty() ) {
process_task_(std::move(lock));
++processed_tasks;
}
}
return std::make_pair(
cancelled_
? scheduler_processing_status::cancelled
: scheduler_processing_status::done,
processed_tasks);
}
template < typename Rep, typename Period >
scheduler::processing_result_t scheduler::process_tasks_for(
const std::chrono::duration<Rep, Period>& timeout_duration) noexcept
{
return process_tasks_until(
std::chrono::steady_clock::now() + timeout_duration);
}
template < typename Clock, typename Duration >
scheduler::processing_result_t scheduler::process_tasks_until(
const std::chrono::time_point<Clock, Duration>& timeout_time) noexcept
{
std::size_t processed_tasks = 0;
while ( !cancelled_ && active_task_count_ ) {
if ( !(Clock::now() < timeout_time) ) {
return std::make_pair(
scheduler_processing_status::timeout,
processed_tasks);
}
std::unique_lock<std::mutex> lock(tasks_mutex_);
cond_var_.wait_until(lock, timeout_time, [this](){
return cancelled_ || !active_task_count_ || !tasks_.empty();
});
if ( !tasks_.empty() ) {
process_task_(std::move(lock));
++processed_tasks;
}
}
return std::make_pair(
cancelled_
? scheduler_processing_status::cancelled
: scheduler_processing_status::done,
processed_tasks);
}
inline void scheduler::push_task_(scheduler_priority priority, task_ptr task) {
tasks_.emplace_back(priority, std::move(task));
std::push_heap(tasks_.begin(), tasks_.end());
++active_task_count_;
cond_var_.notify_one();
}
inline scheduler::task_ptr scheduler::pop_task_() noexcept {
if ( !tasks_.empty() ) {
std::pop_heap(tasks_.begin(), tasks_.end());
task_ptr task = std::move(tasks_.back().second);
tasks_.pop_back();
return task;
}
return nullptr;
}
inline void scheduler::shutdown_() noexcept {
std::lock_guard<std::mutex> guard(tasks_mutex_);
while ( !tasks_.empty() ) {
task_ptr task = pop_task_();
if ( task ) {
task->cancel();
--active_task_count_;
}
}
cancelled_.store(true);
cond_var_.notify_all();
}
inline void scheduler::process_task_(std::unique_lock<std::mutex> lock) noexcept {
assert(lock.owns_lock());
task_ptr task = pop_task_();
if ( task ) {
lock.unlock();
task->run();
lock.lock();
--active_task_count_;
cond_var_.notify_all();
}
}
}
namespace scheduler_hpp
{
//
// concrete_task<R, F, Args...>
//
template < typename R, typename F, typename... Args >
template < typename U >
scheduler::concrete_task<R, F, Args...>::concrete_task(U&& u, std::tuple<Args...>&& args)
: f_(std::forward<U>(u))
, args_(std::move(args)) {}
template < typename R, typename F, typename... Args >
void scheduler::concrete_task<R, F, Args...>::run() noexcept {
try {
R value = invoke_hpp::apply(std::move(f_), std::move(args_));
promise_.resolve(std::move(value));
} catch (...) {
promise_.reject(std::current_exception());
}
}
template < typename R, typename F, typename... Args >
void scheduler::concrete_task<R, F, Args...>::cancel() noexcept {
promise_.reject(scheduler_cancelled_exception());
}
template < typename R, typename F, typename... Args >
promise<R> scheduler::concrete_task<R, F, Args...>::future() noexcept {
return promise_;
}
//
// concrete_task<void, F, Args...>
//
template < typename F, typename... Args >
template < typename U >
scheduler::concrete_task<void, F, Args...>::concrete_task(U&& u, std::tuple<Args...>&& args)
: f_(std::forward<U>(u))
, args_(std::move(args)) {}
template < typename F, typename... Args >
void scheduler::concrete_task<void, F, Args...>::run() noexcept {
try {
invoke_hpp::apply(std::move(f_), std::move(args_));
promise_.resolve();
} catch (...) {
promise_.reject(std::current_exception());
}
}
template < typename F, typename... Args >
void scheduler::concrete_task<void, F, Args...>::cancel() noexcept {
promise_.reject(scheduler_cancelled_exception());
}
template < typename F, typename... Args >
promise<void> scheduler::concrete_task<void, F, Args...>::future() noexcept {
return promise_;
}
}

View File

@@ -8,11 +8,12 @@
#include "_base.hpp"
#include <flat.hpp/flat_set.hpp>
#include <flat.hpp/flat_map.hpp>
#include <flat.hpp/flat_multiset.hpp>
#include <flat.hpp/flat_multimap.hpp>
#include <3rdparty/variant/variant.hpp>
#include <3rdparty/flat.hpp/flat_set.hpp>
#include <3rdparty/flat.hpp/flat_map.hpp>
#include <3rdparty/flat.hpp/flat_multiset.hpp>
#include <3rdparty/flat.hpp/flat_multimap.hpp>
namespace e2d
{

View File

@@ -12,10 +12,10 @@
#include <curly.hpp/curly.hpp>
#include <3rdparty/promise.hpp/invoke.hpp>
#include <3rdparty/promise.hpp/jobber.hpp>
#include <3rdparty/promise.hpp/promise.hpp>
#include <3rdparty/promise.hpp/scheduler.hpp>
#include <promise.hpp/invoke.hpp>
#include <promise.hpp/jobber.hpp>
#include <promise.hpp/promise.hpp>
#include <promise.hpp/scheduler.hpp>
namespace e2d
{

View File

@@ -8,7 +8,7 @@
#include "../core/_all.hpp"
#include <3rdparty/ecs.hpp/ecs.hpp>
#include <ecs.hpp/ecs.hpp>
namespace e2d
{

View File

@@ -2,9 +2,6 @@
SCRIPT_DIR=`dirname "$BASH_SOURCE"`
cloc \
$SCRIPT_DIR/../headers/enduro2d \
$SCRIPT_DIR/../headers/3rdparty/ecs.hpp \
$SCRIPT_DIR/../headers/3rdparty/flat.hpp \
$SCRIPT_DIR/../headers/3rdparty/promise.hpp \
$SCRIPT_DIR/../sources/enduro2d \
$SCRIPT_DIR/../samples/sources \
$SCRIPT_DIR/../untests/sources

View File

@@ -2,7 +2,4 @@
SCRIPT_DIR=`dirname "$BASH_SOURCE"`
cloc \
$SCRIPT_DIR/../headers/enduro2d \
$SCRIPT_DIR/../headers/3rdparty/ecs.hpp \
$SCRIPT_DIR/../headers/3rdparty/flat.hpp \
$SCRIPT_DIR/../headers/3rdparty/promise.hpp \
$SCRIPT_DIR/../sources/enduro2d

View File

@@ -1,7 +1,3 @@
#!/bin/bash
SCRIPT_DIR=`dirname "$BASH_SOURCE"`
cloc \
$SCRIPT_DIR/../headers/enduro2d \
$SCRIPT_DIR/../headers/3rdparty/ecs.hpp \
$SCRIPT_DIR/../headers/3rdparty/flat.hpp \
$SCRIPT_DIR/../headers/3rdparty/promise.hpp \
cloc $SCRIPT_DIR/../headers/enduro2d

View File

@@ -20,12 +20,6 @@ git submodule update --remote
mkdir -p $UNTESTS_DIR/catch
cp -fv $MODULES_DIR/catch2/single_include/catch2/catch.hpp $UNTESTS_DIR/catch/catch.hpp
mkdir -p $HEADERS_RDPARTY_DIR/ecs.hpp
cp -rfv $MODULES_DIR/ecs.hpp/headers/ecs.hpp/. $HEADERS_RDPARTY_DIR/ecs.hpp/
mkdir -p $HEADERS_RDPARTY_DIR/flat.hpp
cp -rfv $MODULES_DIR/flat.hpp/headers/flat.hpp/. $HEADERS_RDPARTY_DIR/flat.hpp/
mkdir -p $SOURCES_RDPARTY_DIR/imgui
cp -fv $MODULES_DIR/imgui/imgui.cpp $SOURCES_RDPARTY_DIR/imgui/imgui.cpp
cp -fv $MODULES_DIR/imgui/imgui.h $SOURCES_RDPARTY_DIR/imgui/imgui.h
@@ -48,9 +42,6 @@ cp -fv $MODULES_DIR/miniz/miniz_tinfl.h $SOURCES_RDPARTY_DIR/miniz/miniz_tinfl.h
cp -fv $MODULES_DIR/miniz/miniz_zip.c $SOURCES_RDPARTY_DIR/miniz/miniz_zip.c
cp -fv $MODULES_DIR/miniz/miniz_zip.h $SOURCES_RDPARTY_DIR/miniz/miniz_zip.h
mkdir -p $HEADERS_RDPARTY_DIR/promise.hpp
cp -rfv $MODULES_DIR/promise.hpp/headers/promise.hpp/. $HEADERS_RDPARTY_DIR/promise.hpp/
mkdir -p $HEADERS_RDPARTY_DIR/pugixml
cp -rfv $MODULES_DIR/pugixml/src/. $HEADERS_RDPARTY_DIR/pugixml/