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)
|
cmake_minimum_required(VERSION 3.11 FATAL_ERROR)
|
||||||
|
|
||||||
if(NOT DEFINED PROJECT_NAME)
|
if(NOT DEFINED PROJECT_NAME)
|
||||||
set(BUILD_AS_STANDALONE ON)
|
set(E2D_BUILD_AS_STANDALONE ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
project(enduro2d)
|
project(enduro2d)
|
||||||
@@ -9,7 +9,7 @@ project(enduro2d)
|
|||||||
set(E2D_SYSTEM_NAME ${CMAKE_SYSTEM_NAME})
|
set(E2D_SYSTEM_NAME ${CMAKE_SYSTEM_NAME})
|
||||||
set(E2D_ROOT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
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_SYSTEM_NAME ${E2D_SYSTEM_NAME} PARENT_SCOPE)
|
||||||
set(E2D_ROOT_DIRECTORY ${E2D_ROOT_DIRECTORY} PARENT_SCOPE)
|
set(E2D_ROOT_DIRECTORY ${E2D_ROOT_DIRECTORY} PARENT_SCOPE)
|
||||||
endif()
|
endif()
|
||||||
@@ -153,6 +153,10 @@ set(USE_EMBEDDED_CURL ON CACHE INTERNAL "" FORCE)
|
|||||||
add_subdirectory(modules/curly.hpp)
|
add_subdirectory(modules/curly.hpp)
|
||||||
set_target_properties(curly.hpp libcurl PROPERTIES FOLDER modules)
|
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_INSTALL OFF CACHE INTERNAL "" FORCE)
|
||||||
set(GLFW_BUILD_DOCS OFF CACHE INTERNAL "" FORCE)
|
set(GLFW_BUILD_DOCS OFF CACHE INTERNAL "" FORCE)
|
||||||
set(GLFW_BUILD_TESTS 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})
|
${E2D_3RDPARTY})
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME}
|
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}
|
target_link_libraries(${PROJECT_NAME}
|
||||||
PRIVATE bass
|
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 "_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/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
|
namespace e2d
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,10 +12,10 @@
|
|||||||
|
|
||||||
#include <curly.hpp/curly.hpp>
|
#include <curly.hpp/curly.hpp>
|
||||||
|
|
||||||
#include <3rdparty/promise.hpp/invoke.hpp>
|
#include <promise.hpp/invoke.hpp>
|
||||||
#include <3rdparty/promise.hpp/jobber.hpp>
|
#include <promise.hpp/jobber.hpp>
|
||||||
#include <3rdparty/promise.hpp/promise.hpp>
|
#include <promise.hpp/promise.hpp>
|
||||||
#include <3rdparty/promise.hpp/scheduler.hpp>
|
#include <promise.hpp/scheduler.hpp>
|
||||||
|
|
||||||
namespace e2d
|
namespace e2d
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include "../core/_all.hpp"
|
#include "../core/_all.hpp"
|
||||||
|
|
||||||
#include <3rdparty/ecs.hpp/ecs.hpp>
|
#include <ecs.hpp/ecs.hpp>
|
||||||
|
|
||||||
namespace e2d
|
namespace e2d
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,9 +2,6 @@
|
|||||||
SCRIPT_DIR=`dirname "$BASH_SOURCE"`
|
SCRIPT_DIR=`dirname "$BASH_SOURCE"`
|
||||||
cloc \
|
cloc \
|
||||||
$SCRIPT_DIR/../headers/enduro2d \
|
$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/../sources/enduro2d \
|
||||||
$SCRIPT_DIR/../samples/sources \
|
$SCRIPT_DIR/../samples/sources \
|
||||||
$SCRIPT_DIR/../untests/sources
|
$SCRIPT_DIR/../untests/sources
|
||||||
|
|||||||
@@ -2,7 +2,4 @@
|
|||||||
SCRIPT_DIR=`dirname "$BASH_SOURCE"`
|
SCRIPT_DIR=`dirname "$BASH_SOURCE"`
|
||||||
cloc \
|
cloc \
|
||||||
$SCRIPT_DIR/../headers/enduro2d \
|
$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/../sources/enduro2d
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
SCRIPT_DIR=`dirname "$BASH_SOURCE"`
|
SCRIPT_DIR=`dirname "$BASH_SOURCE"`
|
||||||
cloc \
|
cloc $SCRIPT_DIR/../headers/enduro2d
|
||||||
$SCRIPT_DIR/../headers/enduro2d \
|
|
||||||
$SCRIPT_DIR/../headers/3rdparty/ecs.hpp \
|
|
||||||
$SCRIPT_DIR/../headers/3rdparty/flat.hpp \
|
|
||||||
$SCRIPT_DIR/../headers/3rdparty/promise.hpp \
|
|
||||||
|
|||||||
@@ -20,12 +20,6 @@ git submodule update --remote
|
|||||||
mkdir -p $UNTESTS_DIR/catch
|
mkdir -p $UNTESTS_DIR/catch
|
||||||
cp -fv $MODULES_DIR/catch2/single_include/catch2/catch.hpp $UNTESTS_DIR/catch/catch.hpp
|
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
|
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.cpp $SOURCES_RDPARTY_DIR/imgui/imgui.cpp
|
||||||
cp -fv $MODULES_DIR/imgui/imgui.h $SOURCES_RDPARTY_DIR/imgui/imgui.h
|
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.c $SOURCES_RDPARTY_DIR/miniz/miniz_zip.c
|
||||||
cp -fv $MODULES_DIR/miniz/miniz_zip.h $SOURCES_RDPARTY_DIR/miniz/miniz_zip.h
|
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
|
mkdir -p $HEADERS_RDPARTY_DIR/pugixml
|
||||||
cp -rfv $MODULES_DIR/pugixml/src/. $HEADERS_RDPARTY_DIR/pugixml/
|
cp -rfv $MODULES_DIR/pugixml/src/. $HEADERS_RDPARTY_DIR/pugixml/
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user