mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-13 15:48:11 +07:00
link blackmatov libraries without copy headers to 3rdparty
This commit is contained in:
@@ -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
|
||||
|
||||
2521
headers/3rdparty/ecs.hpp/ecs.hpp
vendored
2521
headers/3rdparty/ecs.hpp/ecs.hpp
vendored
File diff suppressed because it is too large
Load Diff
25
headers/3rdparty/flat.hpp/detail/eq_compare.hpp
vendored
25
headers/3rdparty/flat.hpp/detail/eq_compare.hpp
vendored
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
38
headers/3rdparty/flat.hpp/detail/is_sorted.hpp
vendored
38
headers/3rdparty/flat.hpp/detail/is_sorted.hpp
vendored
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
51
headers/3rdparty/flat.hpp/flat_fwd.hpp
vendored
51
headers/3rdparty/flat.hpp/flat_fwd.hpp
vendored
@@ -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;
|
||||
}
|
||||
792
headers/3rdparty/flat.hpp/flat_map.hpp
vendored
792
headers/3rdparty/flat.hpp/flat_map.hpp
vendored
@@ -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);
|
||||
}
|
||||
}
|
||||
677
headers/3rdparty/flat.hpp/flat_multimap.hpp
vendored
677
headers/3rdparty/flat.hpp/flat_multimap.hpp
vendored
@@ -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);
|
||||
}
|
||||
}
|
||||
586
headers/3rdparty/flat.hpp/flat_multiset.hpp
vendored
586
headers/3rdparty/flat.hpp/flat_multiset.hpp
vendored
@@ -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);
|
||||
}
|
||||
}
|
||||
659
headers/3rdparty/flat.hpp/flat_set.hpp
vendored
659
headers/3rdparty/flat.hpp/flat_set.hpp
vendored
@@ -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);
|
||||
}
|
||||
}
|
||||
248
headers/3rdparty/promise.hpp/invoke.hpp
vendored
248
headers/3rdparty/promise.hpp/invoke.hpp
vendored
@@ -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
|
||||
427
headers/3rdparty/promise.hpp/jobber.hpp
vendored
427
headers/3rdparty/promise.hpp/jobber.hpp
vendored
@@ -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_;
|
||||
}
|
||||
}
|
||||
1306
headers/3rdparty/promise.hpp/promise.hpp
vendored
1306
headers/3rdparty/promise.hpp/promise.hpp
vendored
File diff suppressed because it is too large
Load Diff
335
headers/3rdparty/promise.hpp/scheduler.hpp
vendored
335
headers/3rdparty/promise.hpp/scheduler.hpp
vendored
@@ -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_;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include "../core/_all.hpp"
|
||||
|
||||
#include <3rdparty/ecs.hpp/ecs.hpp>
|
||||
#include <ecs.hpp/ecs.hpp>
|
||||
|
||||
namespace e2d
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user