Feature/variant_collection (#26)
* added variant_collection
* added variant_collection
* avoided &* on null pointers
* made (non-public) fixed_variant ctor explicit
* tested higher-arity visit
* implemented visit<void>
* fixed {boost::variant2|std}::variant insertion
* fixed lookup issues with invoke_visit
* removed unneeded constexpr qualifiers
* s/typeid_/index
* reverted c6bc62f6d2 as Clang 5.0 didnt seem to like it
* reinstated c6bc62f6d2
* dropped -std=c++1z for Clang 5.0
* updated docs and examples
* added boost::poly_collection::visit_by_index
* typo
* explicit cted tuple in make_iota_tuple
* changed function name to see if it helps with mangling-related Clang 3.8 ICE
* rewritten make_iota_tuple to try to make Clang 3.8 happier
* added boost::variant_collection_of
@@ -347,7 +347,7 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
|||||||
linux_pipeline(
|
linux_pipeline(
|
||||||
"Linux 18.04 Clang 5.0",
|
"Linux 18.04 Clang 5.0",
|
||||||
"cppalliance/droneubuntu1804:1",
|
"cppalliance/droneubuntu1804:1",
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-5.0', CXXSTD: '11,14,1z' },
|
{ TOOLSET: 'clang', COMPILER: 'clang++-5.0', CXXSTD: '11,14' },
|
||||||
"clang-5.0",
|
"clang-5.0",
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ jobs:
|
|||||||
install: clang-4.0
|
install: clang-4.0
|
||||||
- toolset: clang
|
- toolset: clang
|
||||||
compiler: clang++-5.0
|
compiler: clang++-5.0
|
||||||
cxxstd: "11,14,1z"
|
cxxstd: "11,14"
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
container: ubuntu:18.04
|
container: ubuntu:18.04
|
||||||
install: clang-5.0
|
install: clang-5.0
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
[/
|
||||||
|
Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
|
(See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
]
|
||||||
|
|
||||||
|
[template closed_poly_collection_synopsis[class_name template_header value_type type_index]
|
||||||
|
``[template_header]``
|
||||||
|
class ``[class_name]``
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.types ['// types:]]``
|
||||||
|
|
||||||
|
using value_type=``[value_type]``;
|
||||||
|
using allocator_type=Allocator;
|
||||||
|
using size_type=std::size_t;
|
||||||
|
using difference_type=std::ptrdiff_t;
|
||||||
|
using reference=value_type&;
|
||||||
|
using const_reference=const value_type&;
|
||||||
|
using pointer=typename std::allocator_traits<Allocator>::pointer;
|
||||||
|
using const_pointer=typename std::allocator_traits<Allocator>::const_pointer;
|
||||||
|
using _type_index_=``[type_index]``;
|
||||||
|
using iterator=``/implementation-defined/``;
|
||||||
|
using const_iterator=``/implementation-defined/``;
|
||||||
|
using _local_base_iterator_=``/implementation-defined/``;
|
||||||
|
using _const_local_base_iterator_=``/implementation-defined/``;
|
||||||
|
template<typename T> using _local_iterator_=``/implementation-defined/``;
|
||||||
|
template<typename T> using _const_local_iterator_=``/implementation-defined/``;
|
||||||
|
class _const_base_segment_info_;
|
||||||
|
class _base_segment_info_;
|
||||||
|
template<typename T> class _const_segment_info_;
|
||||||
|
template<typename T> class _segment_info_;
|
||||||
|
using _base_segment_info_iterator_=``/implementation-defined/``;
|
||||||
|
using _const_base_segment_info_iterator_=``/implementation-defined/``;
|
||||||
|
class _const_segment_traversal_info_;
|
||||||
|
class _segment_traversal_info_;
|
||||||
|
|
||||||
|
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.construct_copy_destroy ['// construct/destroy/copy:]]``
|
||||||
|
|
||||||
|
``[class_name]``();
|
||||||
|
``[class_name]``(const ``[class_name]``&);
|
||||||
|
``[class_name]``(``[class_name]``&&);
|
||||||
|
explicit ``[class_name]``(const allocator_type& al);
|
||||||
|
``[class_name]``(const ``[class_name]``& x,const allocator_type& al);
|
||||||
|
``[class_name]``(``[class_name]``&& x,const allocator_type& al);
|
||||||
|
template<typename InputIterator>
|
||||||
|
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.construct_copy_destroy.range_construction [class_name]]``(
|
||||||
|
InputIterator first,InputIterator last,
|
||||||
|
const allocator_type& al=allocator_type{});
|
||||||
|
|
||||||
|
``[class_name]``& operator=(const ``[class_name]``&);
|
||||||
|
``[class_name]``& operator=(``[class_name]``&&);
|
||||||
|
|
||||||
|
allocator_type get_allocator()const noexcept;
|
||||||
|
|
||||||
|
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.iterators ['// iterators:]]``
|
||||||
|
|
||||||
|
iterator _begin_()noexcept;
|
||||||
|
iterator _end_()noexcept;
|
||||||
|
const_iterator _begin_()const noexcept;
|
||||||
|
const_iterator _end_()const noexcept;
|
||||||
|
const_iterator _cbegin_()const noexcept;
|
||||||
|
const_iterator _cend_()const noexcept;
|
||||||
|
|
||||||
|
local_base_iterator _begin_(const type_index& info);
|
||||||
|
local_base_iterator _end_(const type_index& info);
|
||||||
|
const_local_base_iterator _begin_(const type_index& info)const;
|
||||||
|
const_local_base_iterator _end_(const type_index& info)const;
|
||||||
|
const_local_base_iterator _cbegin_(const type_index& info)const;
|
||||||
|
const_local_base_iterator _cend_(const type_index& info)const;
|
||||||
|
|
||||||
|
template<typename T> local_iterator<T> _begin_();
|
||||||
|
template<typename T> local_iterator<T> _end_();
|
||||||
|
template<typename T> const_local_iterator<T> _begin_()const;
|
||||||
|
template<typename T> const_local_iterator<T> _end_()const;
|
||||||
|
template<typename T> const_local_iterator<T> _cbegin_()const;
|
||||||
|
template<typename T> const_local_iterator<T> _cend_()const;
|
||||||
|
|
||||||
|
base_segment_info _segment_(const type_index& info);
|
||||||
|
const_base_segment_info _segment_(const type_index& info)const;
|
||||||
|
template<typename T> segment_info<T> _segment_();
|
||||||
|
template<typename T> const_segment_info<T> _segment_()const;
|
||||||
|
|
||||||
|
segment_traversal_info _segment_traversal_()noexcept;
|
||||||
|
const_segment_traversal_info _segment_traversal_()const noexcept;
|
||||||
|
|
||||||
|
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.capacity ['// capacity:]]``
|
||||||
|
|
||||||
|
bool empty()const noexcept;
|
||||||
|
bool _empty_(const type_index& info)const;
|
||||||
|
template<typename T> bool _empty_()const;
|
||||||
|
|
||||||
|
size_type size()const noexcept;
|
||||||
|
size_type _size_(const type_index& info)const;
|
||||||
|
template<typename T> size_type _size_()const;
|
||||||
|
|
||||||
|
size_type _max_size_(const type_index& info)const;
|
||||||
|
template<typename T> size_type _max_size_()const;
|
||||||
|
|
||||||
|
size_type _capacity_(const type_index& info)const;
|
||||||
|
template<typename T> size_type _capacity_()const;
|
||||||
|
|
||||||
|
void _reserve_(size_type n);
|
||||||
|
void _reserve_(const type_index& info,size_type n);
|
||||||
|
template<typename T>void _reserve_(size_type n);
|
||||||
|
|
||||||
|
void _shrink_to_fit_();
|
||||||
|
void _shrink_to_fit_(const type_index& info);
|
||||||
|
template<typename T> void _shrink_to_fit_();
|
||||||
|
|
||||||
|
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.modifiers ['// modifiers:]]``
|
||||||
|
|
||||||
|
template<typename T,typename... Args>
|
||||||
|
iterator _emplace_(Args&&... args);
|
||||||
|
|
||||||
|
template<typename T,typename... Args>
|
||||||
|
iterator _emplace_hint_(const_iterator hint,Args&&... args);
|
||||||
|
|
||||||
|
template<typename T,typename LocalIterator,typename... Args>
|
||||||
|
auto _emplace_pos_(LocalIterator pos,Args&&... args);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
iterator _insert_(T&& x);
|
||||||
|
|
||||||
|
template<typename CollectionIterator,typename T>
|
||||||
|
auto _insert_hint_(CollectionIterator hint,T&& x);
|
||||||
|
|
||||||
|
template<typename InputIterator>
|
||||||
|
void _insert_range_(InputIterator first,InputIterator last);
|
||||||
|
|
||||||
|
template<typename CollectionIterator,typename InputIterator>
|
||||||
|
void _insert_hint_range_(CollectionIterator hint,InputIterator first,InputIterator last);
|
||||||
|
|
||||||
|
template<typename CollectionIterator>
|
||||||
|
auto _erase_(CollectionIterator pos);
|
||||||
|
|
||||||
|
template<typename CollectionIterator>
|
||||||
|
auto _erase_(CollectionIterator first,CollectionIterator last);
|
||||||
|
|
||||||
|
void _clear_()noexcept;
|
||||||
|
void _clear_(const type_index& info);
|
||||||
|
template<typename T> void _clear_();
|
||||||
|
|
||||||
|
void swap(``[class_name]``& x);
|
||||||
|
};
|
||||||
|
]
|
||||||
|
After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 25 KiB |
@@ -1,7 +1,7 @@
|
|||||||
[library Boost.PolyCollection
|
[library Boost.PolyCollection
|
||||||
[quickbook 1.6]
|
[quickbook 1.6]
|
||||||
[authors [López Muñoz, Joaquín M]]
|
[authors [López Muñoz, Joaquín M]]
|
||||||
[copyright 2016-2021 Joaquín M López Muñoz]
|
[copyright 2016-2024 Joaquín M López Muñoz]
|
||||||
[category containers]
|
[category containers]
|
||||||
[id poly_collection]
|
[id poly_collection]
|
||||||
[dirname poly_collection]
|
[dirname poly_collection]
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
[def _Boost.TypeErasure_ [@boost:/libs/type_erasure Boost.TypeErasure]]
|
[def _Boost.TypeErasure_ [@boost:/libs/type_erasure Boost.TypeErasure]]
|
||||||
[def _Boost.TypeIndex_ [@boost:/libs/type_index Boost.TypeIndex]]
|
[def _Boost.TypeIndex_ [@boost:/libs/type_index Boost.TypeIndex]]
|
||||||
|
[def _Boost.Variant2_ [@boost:/libs/variant2 Boost.Variant2]]
|
||||||
[def _CopyConstructible_ [@http://en.cppreference.com/w/cpp/named_req/CopyConstructible [* `CopyConstructible`]]]
|
[def _CopyConstructible_ [@http://en.cppreference.com/w/cpp/named_req/CopyConstructible [* `CopyConstructible`]]]
|
||||||
[def _duck_typing_ [@https://en.wikipedia.org/wiki/Duck_typing ['duck typing]]]
|
[def _duck_typing_ [@https://en.wikipedia.org/wiki/Duck_typing ['duck typing]]]
|
||||||
[def _EqualityComparable_ [@http://en.cppreference.com/w/cpp/named_req/EqualityComparable [* `EqualityComparable`]]]
|
[def _EqualityComparable_ [@http://en.cppreference.com/w/cpp/named_req/EqualityComparable [* `EqualityComparable`]]]
|
||||||
@@ -25,6 +26,7 @@
|
|||||||
[def _MoveAssignable_ [@http://en.cppreference.com/w/cpp/named_req/MoveAssignable [* `MoveAssignable`]]]
|
[def _MoveAssignable_ [@http://en.cppreference.com/w/cpp/named_req/MoveAssignable [* `MoveAssignable`]]]
|
||||||
[def _std::for_each_ [@http://en.cppreference.com/w/cpp/algorithm/for_each `std::for_each`]]
|
[def _std::for_each_ [@http://en.cppreference.com/w/cpp/algorithm/for_each `std::for_each`]]
|
||||||
[def _std::function_ [@http://en.cppreference.com/w/cpp/utility/functional/function `std::function`]]
|
[def _std::function_ [@http://en.cppreference.com/w/cpp/utility/functional/function `std::function`]]
|
||||||
|
[def _std::variant_ [@https://en.cppreference.com/w/cpp/utility/variant `std::variant`]]
|
||||||
[def _std::unordered_multiset_ [@http://en.cppreference.com/w/cpp/container/unordered_multiset `std::unordered_multiset`]]
|
[def _std::unordered_multiset_ [@http://en.cppreference.com/w/cpp/container/unordered_multiset `std::unordered_multiset`]]
|
||||||
[def _RandomAccessIterator_ [@http://en.cppreference.com/w/cpp/named_req/RandomAccessIterator [* `RandomAccessIterator`]]]
|
[def _RandomAccessIterator_ [@http://en.cppreference.com/w/cpp/named_req/RandomAccessIterator [* `RandomAccessIterator`]]]
|
||||||
|
|
||||||
@@ -50,19 +52,22 @@ lower execution speed.
|
|||||||
|
|
||||||
When the particular traversal order is not relevant to the user application,
|
When the particular traversal order is not relevant to the user application,
|
||||||
Boost.PolyCollection proposes an alternative data structure that restores memory
|
Boost.PolyCollection proposes an alternative data structure that restores memory
|
||||||
contiguity and packs elements according to their concrete type. Three container
|
contiguity and packs elements according to their concrete type. Four container
|
||||||
class templates are provided:
|
class templates are provided:
|
||||||
|
|
||||||
* `boost::base_collection`
|
* `boost::base_collection`
|
||||||
* `boost::function_collection`
|
* `boost::function_collection`
|
||||||
* `boost::any_collection`
|
* `boost::any_collection`
|
||||||
|
* `boost::variant_collection`
|
||||||
|
|
||||||
respectively dealing with three different types of dynamic polymorphism
|
respectively dealing with four different types of dynamic polymorphism
|
||||||
available in C++:
|
available in C++:
|
||||||
|
|
||||||
* Classic base/derived or OOP polymorphism.
|
* Classic base/derived or OOP polymorphism.
|
||||||
* Function wrapping in the spirit of _std::function_.
|
* Function wrapping in the spirit of _std::function_.
|
||||||
* So-called _duck_typing_ as implemented by _Boost.TypeErasure_.
|
* So-called _duck_typing_ as implemented by _Boost.TypeErasure_.
|
||||||
|
* /Closed polymorphism/ where the list of acceptable types is specified
|
||||||
|
at compile time as in a _std::variant_.
|
||||||
|
|
||||||
The interface of these containers closely follows that of standard containers.
|
The interface of these containers closely follows that of standard containers.
|
||||||
Additionally, the library provides versions of many of the standard library
|
Additionally, the library provides versions of many of the standard library
|
||||||
@@ -157,14 +162,24 @@ for C++. Under the hood, duck typing requires pointer indirection and virtual
|
|||||||
call implementation techniques analogous to those of OOP, and so there are
|
call implementation techniques analogous to those of OOP, and so there are
|
||||||
the same opportunities for efficient container data structures as we have
|
the same opportunities for efficient container data structures as we have
|
||||||
described.
|
described.
|
||||||
|
* /Closed polymorphism/ is the case where the acceptable types are specified
|
||||||
|
at compile time. _std::variant_ and _Boost.Variant2_ are prominent examples
|
||||||
|
of closed polymorphism with underlying types (called /alternatives/)
|
||||||
|
being accessed through
|
||||||
|
[@https://en.cppreference.com/w/cpp/utility/variant/visit2 visitation].
|
||||||
|
Typical implementations of closed polymorphism do not involve dynamic allocation
|
||||||
|
(alternatives are stored `union` style in shared storage), but grouping
|
||||||
|
same-type objects together still provides performance and space advantages.
|
||||||
|
|
||||||
Boost.PolyCollection provides three different container class templates
|
Boost.PolyCollection provides four different container class templates
|
||||||
dealing with OOP, `std::function`-like polymorphism and duck typing as
|
dealing with OOP, `std::function`-like polymorphism, duck typing as
|
||||||
implemented by Boost.TypeErasure:
|
implemented by Boost.TypeErasure, and closed polymorphism in the spirit of
|
||||||
|
`std::variant`:
|
||||||
|
|
||||||
* `boost::base_collection`
|
* `boost::base_collection`
|
||||||
* `boost::function_collection`
|
* `boost::function_collection`
|
||||||
* `boost::any_collection`
|
* `boost::any_collection`
|
||||||
|
* `boost::variant_collection`
|
||||||
|
|
||||||
The interfaces of these containers are mostly the same and follow the usual
|
The interfaces of these containers are mostly the same and follow the usual
|
||||||
conventions of standard library containers.
|
conventions of standard library containers.
|
||||||
@@ -370,11 +385,55 @@ but a similarly behaving entity
|
|||||||
`boost::type_erasure::any<Concept2,boost::type_erasure::_self&>` for some
|
`boost::type_erasure::any<Concept2,boost::type_erasure::_self&>` for some
|
||||||
internally defined `Concept2` that extends `Concept`.].
|
internally defined `Concept2` that extends `Concept`.].
|
||||||
In any case, we are not accessing sprites through an abstract `sprite&`
|
In any case, we are not accessing sprites through an abstract `sprite&`
|
||||||
anymore, so we could as well dismantle the virtual hierarchy and implement
|
anymore, so we could in principle dismantle the virtual hierarchy and implement
|
||||||
each type autonomously: this is left as an exercise to the reader.
|
each type autonomously: this is left as an exercise to the reader.
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
[section `boost::variant_collection`]
|
||||||
|
|
||||||
|
[import ../example/basic_variant.cpp]
|
||||||
|
(Code samples from [@boost:/libs/poly_collection/example/basic_variant.cpp `basic_variant.cpp`].
|
||||||
|
C++17 is used for the `overloaded` utility.)
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
At this point where we have such an heterogeneous list of unrelated types, we
|
||||||
|
may as well specify them at compile time:
|
||||||
|
|
||||||
|
[basic_variant_1]
|
||||||
|
|
||||||
|
`boost::mp11::mp_list` is needed to syntactically distinguish the types that
|
||||||
|
go in the collection from the (defaulted) allocator argument that comes next.
|
||||||
|
If no special allocator is specified, the alias template `variant_collection_of` provides
|
||||||
|
a sligthly more convenient syntax:
|
||||||
|
|
||||||
|
[basic_variant_2]
|
||||||
|
|
||||||
|
`boost::variant_collection` behaves as a `std::vector` of _std::variant_'''s''',
|
||||||
|
except that objects of the same type are grouped together. Access to the objects
|
||||||
|
is done through /visitation/:
|
||||||
|
|
||||||
|
[basic_variant_3]
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
[pre
|
||||||
|
warrior 1,warrior 4,juggernaut 2,goblin 0,elf 3,"stamina: 10,000","game over",'''[pop-up 1]''','''[pop-up 2]'''
|
||||||
|
]
|
||||||
|
|
||||||
|
The alternative visitation function `visit_by_index` may be more convenient in that
|
||||||
|
it doesn't require that we build an overloaded visitor:
|
||||||
|
|
||||||
|
[basic_variant_4]
|
||||||
|
|
||||||
|
Note that types are traversed in the exact same order as specified. The `value_type`
|
||||||
|
of a `boost::variant_collection<boost::mp11:mp_list<Ts..>>` behaves as a
|
||||||
|
`std::variant<Ts..>`, with some obvious restrictions such as the impossibility
|
||||||
|
of changing the type of the contained object (for instance, the equivalent of
|
||||||
|
[@https://en.cppreference.com/w/cpp/utility/variant/emplace `std::variant::emplace`]
|
||||||
|
is not provided).
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Deeper into the segmented nature of Boost.PolyCollection]
|
[section Deeper into the segmented nature of Boost.PolyCollection]
|
||||||
@@ -435,6 +494,12 @@ expected to be much less frequent with `boost::function_collection` and
|
|||||||
|
|
||||||
[segmented_structure_4]
|
[segmented_structure_4]
|
||||||
|
|
||||||
|
[note `boost::variant_collection` handles type registration differently: as the
|
||||||
|
acceptable types are specified at compile time, their associated segments
|
||||||
|
are automatically created upon construction of the collection;
|
||||||
|
consequently, `is_registered` and `register_types` are not provided.
|
||||||
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Segment-specific interface]
|
[section Segment-specific interface]
|
||||||
@@ -448,7 +513,12 @@ refer to the elements of a given segment by providing either their type or
|
|||||||
Note that any of these (except
|
Note that any of these (except
|
||||||
[link poly_collection.tutorial.deeper_into_the_segmented_nature.reserve `reserve`])
|
[link poly_collection.tutorial.deeper_into_the_segmented_nature.reserve `reserve`])
|
||||||
will throw `boost::poly_collection::unregistered_type` if the type is not
|
will throw `boost::poly_collection::unregistered_type` if the type is not
|
||||||
registered. Segment-specific addressability also includes traversal:
|
registered. In the case of `boost::variant_collection`, we use the /index number/ of
|
||||||
|
the type rather than `typeid()`:
|
||||||
|
|
||||||
|
[segmented_structure_6]
|
||||||
|
|
||||||
|
Segment-specific addressability also includes traversal:
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
@@ -456,7 +526,7 @@ registered. Segment-specific addressability also includes traversal:
|
|||||||
|
|
||||||
The following runs only over the `warrior`s of the collection:
|
The following runs only over the `warrior`s of the collection:
|
||||||
|
|
||||||
[segmented_structure_6]
|
[segmented_structure_7]
|
||||||
|
|
||||||
Output:
|
Output:
|
||||||
|
|
||||||
@@ -475,11 +545,11 @@ whole-collection iterators only model _ForwardIterator_.
|
|||||||
A terser range-based `for` loop can be used with the convenience `segment`
|
A terser range-based `for` loop can be used with the convenience `segment`
|
||||||
member function:
|
member function:
|
||||||
|
|
||||||
[segmented_structure_7]
|
[segmented_structure_8]
|
||||||
|
|
||||||
Even more powerful than `local_base_iterator` is `local_iterator<T>`:
|
Even more powerful than `local_base_iterator` is `local_iterator<T>`:
|
||||||
|
|
||||||
[segmented_structure_8]
|
[segmented_structure_9]
|
||||||
|
|
||||||
This appends a `"super"` prefix to the `rank` data member of existing warriors:
|
This appends a `"super"` prefix to the `rank` data member of existing warriors:
|
||||||
|
|
||||||
@@ -499,6 +569,11 @@ objects. `local_iterator<T>`s can be explicitly converted to
|
|||||||
to a segment for `T`, it can then be explictly converted to a
|
to a segment for `T`, it can then be explictly converted to a
|
||||||
`local_iterator<T>` (otherwise the conversion is undefined behavior).
|
`local_iterator<T>` (otherwise the conversion is undefined behavior).
|
||||||
|
|
||||||
|
The fact that `local_iterator<T>` refers directly to a `T` object is more
|
||||||
|
apparent when we are using `boost::variant_collection`:
|
||||||
|
|
||||||
|
[segmented_structure_10]
|
||||||
|
|
||||||
The figure shows the action scopes of all the iterators associated to
|
The figure shows the action scopes of all the iterators associated to
|
||||||
a polymorphic collection (`const_` versions not included):
|
a polymorphic collection (`const_` versions not included):
|
||||||
|
|
||||||
@@ -510,7 +585,7 @@ of a particular segment, `segment_traversal()` returns an object for ranging ove
|
|||||||
/segments/, so that the whole collection can be processed with a nested
|
/segments/, so that the whole collection can be processed with a nested
|
||||||
segment-element `for` loop like the following:
|
segment-element `for` loop like the following:
|
||||||
|
|
||||||
[segmented_structure_9]
|
[segmented_structure_11]
|
||||||
|
|
||||||
Segment decomposition of traversal loops forms the basis of
|
Segment decomposition of traversal loops forms the basis of
|
||||||
[link poly_collection.tutorial.algorithms improved-performance algorithms].
|
[link poly_collection.tutorial.algorithms improved-performance algorithms].
|
||||||
@@ -522,7 +597,7 @@ Segment decomposition of traversal loops forms the basis of
|
|||||||
Much like `std::vector`, segments can be made to reserve memory in
|
Much like `std::vector`, segments can be made to reserve memory in
|
||||||
advance to minimize reallocations:
|
advance to minimize reallocations:
|
||||||
|
|
||||||
[segmented_structure_10]
|
[segmented_structure_12]
|
||||||
|
|
||||||
If there is no segment for the indicated type (here, `goblin`), one is
|
If there is no segment for the indicated type (here, `goblin`), one is
|
||||||
automatically created. This is in contrast with the rest of segment-specific
|
automatically created. This is in contrast with the rest of segment-specific
|
||||||
@@ -532,7 +607,7 @@ member functions, which throw
|
|||||||
|
|
||||||
`reserve` can deal with all segments at once. The following
|
`reserve` can deal with all segments at once. The following
|
||||||
|
|
||||||
[segmented_structure_11]
|
[segmented_structure_13]
|
||||||
|
|
||||||
instructs every /existing/ segment to reserve 1,000 elements. If a
|
instructs every /existing/ segment to reserve 1,000 elements. If a
|
||||||
segment is created later (through element insertion or with
|
segment is created later (through element insertion or with
|
||||||
@@ -710,7 +785,7 @@ signature, etc.].
|
|||||||
|
|
||||||
[import ../example/algorithms.cpp]
|
[import ../example/algorithms.cpp]
|
||||||
(Code samples from [@boost:/libs/poly_collection/example/algorithms.cpp `algorithms.cpp`].
|
(Code samples from [@boost:/libs/poly_collection/example/algorithms.cpp `algorithms.cpp`].
|
||||||
C++14 generic lambda expressions are used.)
|
C++14 generic lambda expressions are used. C++17 used for the `overloaded` utility.)
|
||||||
|
|
||||||
The ultimate purpose of Boost.PolyCollection is to speed up the processing of
|
The ultimate purpose of Boost.PolyCollection is to speed up the processing of
|
||||||
large quantities of polymorphic entities, in particular for those operations
|
large quantities of polymorphic entities, in particular for those operations
|
||||||
@@ -725,6 +800,7 @@ Boost.PolyCollection:
|
|||||||
* `std::vector<base*>` (or similar) → `boost::base_collection<base>`
|
* `std::vector<base*>` (or similar) → `boost::base_collection<base>`
|
||||||
* `std::vector<std::function<signature>>` → `boost::function_collection<signature>`
|
* `std::vector<std::function<signature>>` → `boost::function_collection<signature>`
|
||||||
* `std::vector<boost::type_erasure::any<concept_>>` → `boost::any_collection<concept_>`
|
* `std::vector<boost::type_erasure::any<concept_>>` → `boost::any_collection<concept_>`
|
||||||
|
* `std::vector<std::variant<Ts...>>` → `boost::any_collection<boost::mp11::mp_list<Ts...>>`
|
||||||
|
|
||||||
is expected to increase performance due to better caching and branch prediction
|
is expected to increase performance due to better caching and branch prediction
|
||||||
behavior. But there is still room for improvement.
|
behavior. But there is still room for improvement.
|
||||||
@@ -853,6 +929,15 @@ capabilities /may/ be able to figure out that the type restitution scenario
|
|||||||
is actually casting the element to its true type, in which case, again, virtual
|
is actually casting the element to its true type, in which case, again, virtual
|
||||||
calls are not needed.
|
calls are not needed.
|
||||||
|
|
||||||
|
When using `boost::variant_collection`, the convenience marker `all_types`
|
||||||
|
requests that all types be restituted without having to explicitly
|
||||||
|
write them down. This is of course feasible because these types are, again,
|
||||||
|
known at compile time. Note that, since elements are accessed directly according
|
||||||
|
to their type, no `visit` call is made in the example
|
||||||
|
[footnote Visitation avoidance is in fact the equivalent thing to devirtualization
|
||||||
|
in the realm of closed polymorphism.].
|
||||||
|
[algorithms_9]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
@@ -861,10 +946,9 @@ calls are not needed.
|
|||||||
|
|
||||||
[section Performance]
|
[section Performance]
|
||||||
|
|
||||||
[def _vs2015_x86_ Visual Studio 2015 x86]
|
[def _vs2022_x64_ Visual Studio 2022 x64]
|
||||||
[def _vs2015_x64_ Visual Studio 2015 x64]
|
[def _gcc132_x64_ GCC 13.2 x64]
|
||||||
[def _gcc63_x64_ GCC 6.3 x64]
|
[def _clang130_x64_ Clang 13.0 x64]
|
||||||
[def _clang40_x64_ Clang 4.0 x64]
|
|
||||||
|
|
||||||
[template perf_fig[name environment file]
|
[template perf_fig[name environment file]
|
||||||
[section [environment]]
|
[section [environment]]
|
||||||
@@ -891,13 +975,13 @@ Boost.PolyCollection in two scenarios:
|
|||||||
[link poly_collection.tutorial.algorithms.type_restitution type restitution]).
|
[link poly_collection.tutorial.algorithms.type_restitution type restitution]).
|
||||||
|
|
||||||
As a comparison baseline we used containers and facilities from the
|
As a comparison baseline we used containers and facilities from the
|
||||||
standard library and Boost (details below). Tests were run in the
|
standard library and Boost (details below). Tests were run on a Windows 10 machine
|
||||||
following environments:
|
with 8GB RAM and an Intel Core i5-8265U CPU @1.60GHz (base frequency)
|
||||||
|
for the following environments:
|
||||||
|
|
||||||
* *_vs2015_x86_*: Visual C++ 2015 in 32-bit (x86) release mode, Windows 7 64-bit, Intel Core i5-2520M @2.5GHz
|
* *_vs2022_x64_*: Visual Studio 2022 in 64-bit (x64), release mode
|
||||||
* *_vs2015_x64_*: Visual C++ 2015 in 64-bit (x64) release mode, same machine
|
* *_gcc132_x64_*: GCC 13.2.0 for MinGW, `-O3 -DNDEBUG`
|
||||||
* *_gcc63_x64_*: GCC 6.3 release mode, Xubuntu 17.04 x64, Intel Core i7-5820 @3.3GHz
|
* *_clang130_x64_*: Clang 13.0.1 for Visual Studio (clang-cl) in 64-bit (x64), release mode
|
||||||
* *_clang40_x64_*: Clang 4.0 release mode, same machine
|
|
||||||
|
|
||||||
[section Container definitions]
|
[section Container definitions]
|
||||||
|
|
||||||
@@ -931,39 +1015,48 @@ following environments:
|
|||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
[section `boost::variant_collection`]
|
||||||
|
|
||||||
|
* Baseline container: `variant_vector` = `std::vector<std::variant<int,double,char>>`
|
||||||
|
* Polymorphic collection: `variant_collection` = `boost::variant_collection<boost::mp11::mp_list<int,double,char>>`
|
||||||
|
* Element types: `T1` = `int`, `T2` = `double`, `T3` = `char`
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Insertion tests]
|
[section Insertion tests]
|
||||||
|
|
||||||
Tests measure the time taken to insert /n/ elements (/n/ between
|
Tests measure the time taken to insert /n/ elements (/n/ between
|
||||||
10'''<superscript>2</superscript>''' and 10'''<superscript>7</superscript>''')
|
10'''<superscript>2</superscript>''' and 10'''<superscript>7</superscript>''')
|
||||||
from a source of values with types following the cyclic sequence
|
from a source of values with types randomly selected from `T1`, `T2` and `T3` with equal probability.
|
||||||
|
|
||||||
`T1` `T1` `T2` `T2` `T3` `T1` `T1` `T2` `T2` `T3` ···
|
|
||||||
|
|
||||||
No `reserve` operation is done before insertion.
|
No `reserve` operation is done before insertion.
|
||||||
The figures show resulting times in nanoseconds/element.
|
The figures show resulting times in nanoseconds/element.
|
||||||
The horizontal axis is logarithmic.
|
The horizontal axis is logarithmic.
|
||||||
|
|
||||||
[section Results for `boost::base_collection`]
|
[section Results for `boost::base_collection`]
|
||||||
[perf_fig Insertion.._vs2015_x86_..insert_base_vs2015_x86]
|
[perf_fig Insertion.._vs2022_x64_..insert_base_vs2022_x64]
|
||||||
[perf_fig Insertion.._vs2015_x64_..insert_base_vs2015_x64]
|
[perf_fig Insertion.._gcc132_x64_..insert_base_gcc132_x64]
|
||||||
[perf_fig Insertion.._gcc63_x64_..insert_base_gcc63_x64]
|
[perf_fig Insertion.._clang130_x64_..insert_base_clang130_x64]
|
||||||
[perf_fig Insertion.._clang40_x64_..insert_base_clang40_x64]
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Results for `boost::function_collection`]
|
[section Results for `boost::function_collection`]
|
||||||
[perf_fig Insertion.._vs2015_x86_..insert_function_vs2015_x86]
|
[perf_fig Insertion.._vs2022_x64_..insert_function_vs2022_x64]
|
||||||
[perf_fig Insertion.._vs2015_x64_..insert_function_vs2015_x64]
|
[perf_fig Insertion.._gcc132_x64_..insert_function_gcc132_x64]
|
||||||
[perf_fig Insertion.._gcc63_x64_..insert_function_gcc63_x64]
|
[perf_fig Insertion.._clang130_x64_..insert_function_clang130_x64]
|
||||||
[perf_fig Insertion.._clang40_x64_..insert_function_clang40_x64]
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Results for `boost::any_collection`]
|
[section Results for `boost::any_collection`]
|
||||||
[perf_fig Insertion.._vs2015_x86_..insert_any_vs2015_x86]
|
[perf_fig Insertion.._vs2022_x64_..insert_any_vs2022_x64]
|
||||||
[perf_fig Insertion.._vs2015_x64_..insert_any_vs2015_x64]
|
[perf_fig Insertion.._gcc132_x64_..insert_any_gcc132_x64]
|
||||||
[perf_fig Insertion.._gcc63_x64_..insert_any_gcc63_x64]
|
[perf_fig Insertion.._clang130_x64_..insert_any_clang130_x64]
|
||||||
[perf_fig Insertion.._clang40_x64_..insert_any_clang40_x64]
|
[endsect]
|
||||||
|
|
||||||
|
[section Results for `boost::variant_collection`]
|
||||||
|
[perf_fig Insertion.._vs2022_x64_..insert_variant_vs2022_x64]
|
||||||
|
[perf_fig Insertion.._gcc132_x64_..insert_variant_gcc132_x64]
|
||||||
|
[perf_fig Insertion.._clang130_x64_..insert_variant_clang130_x64]
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
@@ -983,21 +1076,25 @@ whereas for `boost::any_collection` we use
|
|||||||
|
|
||||||
[perf_for_each_incrementable]
|
[perf_for_each_incrementable]
|
||||||
|
|
||||||
|
and for `boost::variant_collection` we have
|
||||||
|
|
||||||
|
[perf_for_each_alternative]
|
||||||
|
|
||||||
The baseline container is tested with three different setups:
|
The baseline container is tested with three different setups:
|
||||||
|
|
||||||
* Directly as initialized by the process described for the
|
* Directly as initialized by the process described for the
|
||||||
[link poly_collection.performance.insertion_tests insertion tests].
|
[link poly_collection.performance.insertion_tests insertion tests].
|
||||||
The sequence of types is complex enough that CPU's branch prediction mechanisms
|
As elements are ordered according to their
|
||||||
are not able to fully anticipate it
|
|
||||||
[footnote This has been verified empirically: simpler cycles did indeed
|
|
||||||
yield better execution times.]. As elements are ordered according to their
|
|
||||||
construction time, certain degree of memory contiguity is expected.
|
construction time, certain degree of memory contiguity is expected.
|
||||||
* With an extra post-insertion stage by which elements are sorted
|
* With an extra post-insertion stage by which elements are sorted
|
||||||
according to their `typeid()`. This increases branch prediction
|
according to their type. This increases branch prediction
|
||||||
efficiency at the expense of having worse cache friendliness.
|
efficiency at the expense of having worse cache friendliness.
|
||||||
* With an extra post-insertion stage that randomly
|
* With an extra post-insertion stage that randomly
|
||||||
shuffles all the elements in the container. This is the worst possible
|
shuffles all the elements in the container. This is the worst possible
|
||||||
scenario both in terms of caching and branch prediction.
|
scenario both in terms of caching and branch prediction.
|
||||||
|
We don't exercise this setup for `variant_vector` as it is
|
||||||
|
at equivalent to the direct case (`std::variant` does not allocate
|
||||||
|
dynamic memory).
|
||||||
|
|
||||||
As for the polymorphic collection, three variations are measured:
|
As for the polymorphic collection, three variations are measured:
|
||||||
|
|
||||||
@@ -1011,24 +1108,27 @@ The figures show resulting times in nanoseconds/element.
|
|||||||
The horizontal axis is logarithmic.
|
The horizontal axis is logarithmic.
|
||||||
|
|
||||||
[section Results for `boost::base_collection`]
|
[section Results for `boost::base_collection`]
|
||||||
[perf_fig Processing.._vs2015_x86_..for_each_base_vs2015_x86]
|
[perf_fig Processing.._vs2022_x64_..for_each_base_vs2022_x64]
|
||||||
[perf_fig Processing.._vs2015_x64_..for_each_base_vs2015_x64]
|
[perf_fig Processing.._gcc132_x64_..for_each_base_gcc132_x64]
|
||||||
[perf_fig Processing.._gcc63_x64_..for_each_base_gcc63_x64]
|
[perf_fig Processing.._clang130_x64_..for_each_base_clang130_x64]
|
||||||
[perf_fig Processing.._clang40_x64_..for_each_base_clang40_x64]
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Results for `boost::function_collection`]
|
[section Results for `boost::function_collection`]
|
||||||
[perf_fig Processing.._vs2015_x86_..for_each_function_vs2015_x86]
|
[perf_fig Processing.._vs2022_x64_..for_each_function_vs2022_x64]
|
||||||
[perf_fig Processing.._vs2015_x64_..for_each_function_vs2015_x64]
|
[perf_fig Processing.._gcc132_x64_..for_each_function_gcc132_x64]
|
||||||
[perf_fig Processing.._gcc63_x64_..for_each_function_gcc63_x64]
|
[perf_fig Processing.._clang130_x64_..for_each_function_clang130_x64]
|
||||||
[perf_fig Processing.._clang40_x64_..for_each_function_clang40_x64]
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Results for `boost::any_collection`]
|
[section Results for `boost::any_collection`]
|
||||||
[perf_fig Processing.._vs2015_x86_..for_each_any_vs2015_x86]
|
[perf_fig Processing.._vs2022_x64_..for_each_any_vs2022_x64]
|
||||||
[perf_fig Processing.._vs2015_x64_..for_each_any_vs2015_x64]
|
[perf_fig Processing.._gcc132_x64_..for_each_any_gcc132_x64]
|
||||||
[perf_fig Processing.._gcc63_x64_..for_each_any_gcc63_x64]
|
[perf_fig Processing.._clang130_x64_..for_each_any_clang130_x64]
|
||||||
[perf_fig Processing.._clang40_x64_..for_each_any_clang40_x64]
|
[endsect]
|
||||||
|
|
||||||
|
[section Results for `boost::variant_collection`]
|
||||||
|
[perf_fig Processing.._vs2022_x64_..for_each_variant_vs2022_x64]
|
||||||
|
[perf_fig Processing.._gcc132_x64_..for_each_variant_gcc132_x64]
|
||||||
|
[perf_fig Processing.._clang130_x64_..for_each_variant_clang130_x64]
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
@@ -1089,24 +1189,6 @@ parallel processing.
|
|||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section `variant_collection`]
|
|
||||||
|
|
||||||
/Closed polymorphism/ is a kind of dynamic polymorphism where the set of implementation
|
|
||||||
types is fixed at definition time: the prime example of this paradigm in C++ is
|
|
||||||
[@http://en.cppreference.com/w/cpp/utility/variant `std::variant`]. Although
|
|
||||||
`boost::any_collection<boost::mpl::vector<>>` can act as a sort of replacement for
|
|
||||||
`std::vector<std::variant<T1,...,TN>>`, this is in fact more similar to a
|
|
||||||
`std::vector<`[@http://en.cppreference.com/w/cpp/utility/any `std::any`]`>`,
|
|
||||||
and a collection class `boost::variant_collection<T1,...,TN>` could be designed to
|
|
||||||
better model closed polymorphism and take further advantage of the fact that
|
|
||||||
implementation types are fixed (for instance, internal virtual calls can be
|
|
||||||
completely eliminated). From a conceptual point of view, this would require introducing
|
|
||||||
a new [* `ClosedPolymorphicCollection`] notion and renaming the current
|
|
||||||
[link poly_collection.reference.polymorphic_containers.polymorphic_collections [* `PolymorphicCollection`]]
|
|
||||||
model to [* `OpenPolymorphicCollection`].
|
|
||||||
|
|
||||||
[endsect]
|
|
||||||
|
|
||||||
[section Ordered polymorphic collections]
|
[section Ordered polymorphic collections]
|
||||||
|
|
||||||
Users have expressed interest in polymorphic collections where elements are kept
|
Users have expressed interest in polymorphic collections where elements are kept
|
||||||
@@ -1122,6 +1204,13 @@ to allow for the definition of container-level `operator<` and related operators
|
|||||||
|
|
||||||
[section Release notes]
|
[section Release notes]
|
||||||
|
|
||||||
|
[section Boost 1.88]
|
||||||
|
|
||||||
|
* Added `boost::variant_collection`, a closed polymorphic collection
|
||||||
|
similar in behavior to `std::vector<std::variant<...>>`.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
[section Boost 1.76]
|
[section Boost 1.76]
|
||||||
|
|
||||||
* Worked around [@https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95888 GCC bug] affecting
|
* Worked around [@https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95888 GCC bug] affecting
|
||||||
@@ -1203,7 +1292,7 @@ Boost.PolyCollection:
|
|||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Acknowledgments]
|
[section Acknowledgements]
|
||||||
|
|
||||||
The library uses [@http://www.pdimov.com/ Peter Dimov]'s
|
The library uses [@http://www.pdimov.com/ Peter Dimov]'s
|
||||||
[@http://www.pdimov.com/cpp2/simple_cxx11_metaprogramming.html implementation
|
[@http://www.pdimov.com/cpp2/simple_cxx11_metaprogramming.html implementation
|
||||||
@@ -1223,7 +1312,7 @@ Adam Wulkiewicz. Many thanks to all of them. Steven Watanabe gave crucial help i
|
|||||||
solving some hard problems related to the usage of _Boost.TypeErasure_.
|
solving some hard problems related to the usage of _Boost.TypeErasure_.
|
||||||
|
|
||||||
Boost.PolyCollection was designed and written between rainy
|
Boost.PolyCollection was designed and written between rainy
|
||||||
[@https://es.wikipedia.org/wiki/Viav%C3%A9lez Viavélez], noisy Madrid and beautiful
|
[@https://es.wikipedia.org/wiki/Viav%C3%A9lez_(Valdepares) Viavélez], noisy Madrid and beautiful
|
||||||
[@https://en.wikipedia.org/wiki/C%C3%A1ceres,_Spain Cáceres], August-November, 2016.
|
[@https://en.wikipedia.org/wiki/C%C3%A1ceres,_Spain Cáceres], August-November, 2016.
|
||||||
Most of the after-review work in preparation for the official Boost release was done
|
Most of the after-review work in preparation for the official Boost release was done
|
||||||
in the quiet town of [@https://es.wikipedia.org/wiki/Oropesa_(Toledo) Oropesa] during
|
in the quiet town of [@https://es.wikipedia.org/wiki/Oropesa_(Toledo) Oropesa] during
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
[/
|
[/
|
||||||
Copyright 2016-2017 Joaquin M Lopez Munoz.
|
Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
Distributed under the Boost Software License, Version 1.0.
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
(See accompanying file LICENSE_1_0.txt or copy at
|
(See accompanying file LICENSE_1_0.txt or copy at
|
||||||
http://www.boost.org/LICENSE_1_0.txt)
|
http://www.boost.org/LICENSE_1_0.txt)
|
||||||
]
|
]
|
||||||
|
|
||||||
[template poly_collection_synopsis[class_name template_header value_type]
|
[template poly_collection_synopsis[class_name template_header value_type type_index]
|
||||||
``[template_header]``
|
``[template_header]``
|
||||||
class ``[class_name]``
|
class ``[class_name]``
|
||||||
{
|
{
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
using const_reference=const value_type&;
|
using const_reference=const value_type&;
|
||||||
using pointer=typename std::allocator_traits<Allocator>::pointer;
|
using pointer=typename std::allocator_traits<Allocator>::pointer;
|
||||||
using const_pointer=typename std::allocator_traits<Allocator>::const_pointer;
|
using const_pointer=typename std::allocator_traits<Allocator>::const_pointer;
|
||||||
|
using _type_index_=``[type_index]``;
|
||||||
using iterator=``/implementation-defined/``;
|
using iterator=``/implementation-defined/``;
|
||||||
using const_iterator=``/implementation-defined/``;
|
using const_iterator=``/implementation-defined/``;
|
||||||
using _local_base_iterator_=``/implementation-defined/``;
|
using _local_base_iterator_=``/implementation-defined/``;
|
||||||
@@ -58,7 +59,7 @@
|
|||||||
template<typename... T>
|
template<typename... T>
|
||||||
void _register_types_();
|
void _register_types_();
|
||||||
|
|
||||||
bool _is_registered_(const std::type_info& info)const;
|
bool _is_registered_(const type_index& info)const;
|
||||||
template<typename T> bool _is_registered_()const;
|
template<typename T> bool _is_registered_()const;
|
||||||
|
|
||||||
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.iterators ['// iterators:]]``
|
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.iterators ['// iterators:]]``
|
||||||
@@ -70,12 +71,12 @@
|
|||||||
const_iterator _cbegin_()const noexcept;
|
const_iterator _cbegin_()const noexcept;
|
||||||
const_iterator _cend_()const noexcept;
|
const_iterator _cend_()const noexcept;
|
||||||
|
|
||||||
local_base_iterator _begin_(const std::type_info& info);
|
local_base_iterator _begin_(const type_index& info);
|
||||||
local_base_iterator _end_(const std::type_info& info);
|
local_base_iterator _end_(const type_index& info);
|
||||||
const_local_base_iterator _begin_(const std::type_info& info)const;
|
const_local_base_iterator _begin_(const type_index& info)const;
|
||||||
const_local_base_iterator _end_(const std::type_info& info)const;
|
const_local_base_iterator _end_(const type_index& info)const;
|
||||||
const_local_base_iterator _cbegin_(const std::type_info& info)const;
|
const_local_base_iterator _cbegin_(const type_index& info)const;
|
||||||
const_local_base_iterator _cend_(const std::type_info& info)const;
|
const_local_base_iterator _cend_(const type_index& info)const;
|
||||||
|
|
||||||
template<typename T> local_iterator<T> _begin_();
|
template<typename T> local_iterator<T> _begin_();
|
||||||
template<typename T> local_iterator<T> _end_();
|
template<typename T> local_iterator<T> _end_();
|
||||||
@@ -84,8 +85,8 @@
|
|||||||
template<typename T> const_local_iterator<T> _cbegin_()const;
|
template<typename T> const_local_iterator<T> _cbegin_()const;
|
||||||
template<typename T> const_local_iterator<T> _cend_()const;
|
template<typename T> const_local_iterator<T> _cend_()const;
|
||||||
|
|
||||||
base_segment_info _segment_(const std::type_info& info);
|
base_segment_info _segment_(const type_index& info);
|
||||||
const_base_segment_info _segment_(const std::type_info& info)const;
|
const_base_segment_info _segment_(const type_index& info)const;
|
||||||
template<typename T> segment_info<T> _segment_();
|
template<typename T> segment_info<T> _segment_();
|
||||||
template<typename T> const_segment_info<T> _segment_()const;
|
template<typename T> const_segment_info<T> _segment_()const;
|
||||||
|
|
||||||
@@ -95,25 +96,25 @@
|
|||||||
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.capacity ['// capacity:]]``
|
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.capacity ['// capacity:]]``
|
||||||
|
|
||||||
bool empty()const noexcept;
|
bool empty()const noexcept;
|
||||||
bool _empty_(const std::type_info& info)const;
|
bool _empty_(const type_index& info)const;
|
||||||
template<typename T> bool _empty_()const;
|
template<typename T> bool _empty_()const;
|
||||||
|
|
||||||
size_type size()const noexcept;
|
size_type size()const noexcept;
|
||||||
size_type _size_(const std::type_info& info)const;
|
size_type _size_(const type_index& info)const;
|
||||||
template<typename T> size_type _size_()const;
|
template<typename T> size_type _size_()const;
|
||||||
|
|
||||||
size_type _max_size_(const std::type_info& info)const;
|
size_type _max_size_(const type_index& info)const;
|
||||||
template<typename T> size_type _max_size_()const;
|
template<typename T> size_type _max_size_()const;
|
||||||
|
|
||||||
size_type _capacity_(const std::type_info& info)const;
|
size_type _capacity_(const type_index& info)const;
|
||||||
template<typename T> size_type _capacity_()const;
|
template<typename T> size_type _capacity_()const;
|
||||||
|
|
||||||
void _reserve_(size_type n);
|
void _reserve_(size_type n);
|
||||||
void _reserve_(const std::type_info& info,size_type n);
|
void _reserve_(const type_index& info,size_type n);
|
||||||
template<typename T>void _reserve_(size_type n);
|
template<typename T>void _reserve_(size_type n);
|
||||||
|
|
||||||
void _shrink_to_fit_();
|
void _shrink_to_fit_();
|
||||||
void _shrink_to_fit_(const std::type_info& info);
|
void _shrink_to_fit_(const type_index& info);
|
||||||
template<typename T> void _shrink_to_fit_();
|
template<typename T> void _shrink_to_fit_();
|
||||||
|
|
||||||
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.modifiers ['// modifiers:]]``
|
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.modifiers ['// modifiers:]]``
|
||||||
@@ -146,7 +147,7 @@
|
|||||||
auto _erase_(CollectionIterator first,CollectionIterator last);
|
auto _erase_(CollectionIterator first,CollectionIterator last);
|
||||||
|
|
||||||
void _clear_()noexcept;
|
void _clear_()noexcept;
|
||||||
void _clear_(const std::type_info& info);
|
void _clear_(const type_index& info);
|
||||||
template<typename T> void _clear_();
|
template<typename T> void _clear_();
|
||||||
|
|
||||||
void swap(``[class_name]``& x);
|
void swap(``[class_name]``& x);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[/
|
[/
|
||||||
Copyright 2016-2017 Joaquin M Lopez Munoz.
|
Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
Distributed under the Boost Software License, Version 1.0.
|
Distributed under the Boost Software License, Version 1.0.
|
||||||
(See accompanying file LICENSE_1_0.txt or copy at
|
(See accompanying file LICENSE_1_0.txt or copy at
|
||||||
http://www.boost.org/LICENSE_1_0.txt)
|
http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -46,6 +46,11 @@ Static polymorphism is the trivial case where *subobject*(`x`) = `x` for all
|
|||||||
* *Implementation*(`Base`) = { `Derived` : `std::is_base_of_v<Base,Derived>` }.
|
* *Implementation*(`Base`) = { `Derived` : `std::is_base_of_v<Base,Derived>` }.
|
||||||
* *subobject*(`x`) = `static_cast<Derived&>(x)` with `typeid(x)==typeid(Derived)`.
|
* *subobject*(`x`) = `static_cast<Derived&>(x)` with `typeid(x)==typeid(Derived)`.
|
||||||
|
|
||||||
|
A polymorphism model is called /closed/ if, for any `I` \u2208 *Interface*,
|
||||||
|
*suboject* ranges over a finite subset ot types of *Implementation*(`I`),
|
||||||
|
that is, there is only a finite number of types subojects can belong in.
|
||||||
|
A non-closed model is called /open/.
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Polymorphic containers]
|
[section Polymorphic containers]
|
||||||
@@ -91,9 +96,11 @@ where a type `U` is said to be acceptable if
|
|||||||
[@http://en.cppreference.com/w/cpp/types/is_move_constructible
|
[@http://en.cppreference.com/w/cpp/types/is_move_constructible
|
||||||
`std::is_nothrow_move_constructible<U>::value`] is `true`.
|
`std::is_nothrow_move_constructible<U>::value`] is `true`.
|
||||||
|
|
||||||
|
The collection is /open/ (resp. /closed/) if its associated polymorphism model
|
||||||
|
is open (resp. closed).
|
||||||
Polymorphic collections conform
|
Polymorphic collections conform
|
||||||
to the requirements of _PolymorphicContainer_ with the following
|
to the requirements of _PolymorphicContainer_ with the following
|
||||||
modfications and extra guarantees:
|
modifications and extra guarantees:
|
||||||
|
|
||||||
* The complexity of `empty()` and `size()` is linear on the number of
|
* The complexity of `empty()` and `size()` is linear on the number of
|
||||||
segments of the collection.
|
segments of the collection.
|
||||||
@@ -107,7 +114,8 @@ _CopyAssignable_, _MoveConstructible_ or _MoveAssignable_.
|
|||||||
A type `U` is said to be /registered/ into the collection if a
|
A type `U` is said to be /registered/ into the collection if a
|
||||||
(possibly empty) segment for `U` has been created. Registered types
|
(possibly empty) segment for `U` has been created. Registered types
|
||||||
continue to stay so for the duration of the container except if it is
|
continue to stay so for the duration of the container except if it is
|
||||||
moved from, assigned to, or swapped.
|
moved from, assigned to, or swapped. For closed collections, all
|
||||||
|
acceptable types are automatically registered upon construction.
|
||||||
|
|
||||||
Each segment has an associated capacity indicating the maximum size
|
Each segment has an associated capacity indicating the maximum size
|
||||||
that it can attain without reallocation. When the limit
|
that it can attain without reallocation. When the limit
|
||||||
@@ -115,8 +123,10 @@ is exceeded (or explicitly through `reserve`) new storage space is
|
|||||||
allocated with greater capacity and elements are moved.
|
allocated with greater capacity and elements are moved.
|
||||||
|
|
||||||
Collection traversal goes through the elements of the first segment,
|
Collection traversal goes through the elements of the first segment,
|
||||||
then the second, etc. The order in which segments are visited is
|
then the second, etc. For open collections, the order in which segments
|
||||||
unspecified but remains stable until a new segment is created.
|
are visited is unspecified but remains stable until a new segment is created.
|
||||||
|
For closed collections, segment order is fixed and determined by
|
||||||
|
the specification of the collection type.
|
||||||
|
|
||||||
Besides `iterator` and `const_iterator`, there are iterator types
|
Besides `iterator` and `const_iterator`, there are iterator types
|
||||||
`local_base_iterator` and `local_iterator<U>` (and their `const_`
|
`local_base_iterator` and `local_iterator<U>` (and their `const_`
|
||||||
@@ -144,7 +154,7 @@ we use the following notation:
|
|||||||
* `C` is a polymorphic collection type,
|
* `C` is a polymorphic collection type,
|
||||||
* `c` is an object of type `C`, `cc` is a possibly `const` object of type `C`,
|
* `c` is an object of type `C`, `cc` is a possibly `const` object of type `C`,
|
||||||
* `al` is a value of type `C::allocator_type`,
|
* `al` is a value of type `C::allocator_type`,
|
||||||
* `info` is a `const std::type_info&`,
|
* `info` is a value of type `const C::index_type&`,
|
||||||
* `U` is an acceptable type, `Us...` is a template parameter pack of
|
* `U` is an acceptable type, `Us...` is a template parameter pack of
|
||||||
acceptable types,
|
acceptable types,
|
||||||
* `n` is a value of `size_type`,
|
* `n` is a value of `size_type`,
|
||||||
@@ -169,6 +179,18 @@ local) of `c` such that \[`xit1`, `xit2`) is a valid range.
|
|||||||
|
|
||||||
[section Types]
|
[section Types]
|
||||||
|
|
||||||
|
[#poly_collection.reference.polymorphic_containers.polymorphic_collections.types.type_index]
|
||||||
|
[def _type_index_ [link poly_collection.reference.polymorphic_containers.polymorphic_collections.types.type_index `type_index`]]
|
||||||
|
|
||||||
|
`C::type_index`
|
||||||
|
|
||||||
|
Can be either `std::type_info` or `std::size_t`. We define `index<U>` as follows:
|
||||||
|
|
||||||
|
* if `type_index` is `std::type_info`: `typeid(U)`,
|
||||||
|
* if `type_index` is `std::size_t`: the index number `i` such that `U` is the `i`-th
|
||||||
|
element in `Us...`, where `Us...` is the list of acceptable types as specified in the
|
||||||
|
associated polymorphism model.
|
||||||
|
|
||||||
[#poly_collection.reference.polymorphic_containers.polymorphic_collections.types.local_base_iterator]
|
[#poly_collection.reference.polymorphic_containers.polymorphic_collections.types.local_base_iterator]
|
||||||
[def _local_base_iterator_ [link poly_collection.reference.polymorphic_containers.polymorphic_collections.types.local_base_iterator `local_base_iterator`]]
|
[def _local_base_iterator_ [link poly_collection.reference.polymorphic_containers.polymorphic_collections.types.local_base_iterator `local_base_iterator`]]
|
||||||
|
|
||||||
@@ -219,15 +241,15 @@ _CopyConstructible_ and _CopyAssignable_ type with information about a given
|
|||||||
segment of a collection. If `ci` is a possibly `const` object of type
|
segment of a collection. If `ci` is a possibly `const` object of type
|
||||||
`C::const_base_segment_info` associated to the segment of `c` for `U`, then
|
`C::const_base_segment_info` associated to the segment of `c` for `U`, then
|
||||||
|
|
||||||
* `ci.begin()==c.cbegin(typeid(U))`
|
* `ci.begin()==c.cbegin(index<U>)`
|
||||||
* `ci.cbegin()==c.cbegin(typeid(U))`
|
* `ci.cbegin()==c.cbegin(index<U>)`
|
||||||
* `ci.begin<U>()==c.cbegin<U>()`
|
* `ci.begin<U>()==c.cbegin<U>()`
|
||||||
* `ci.cbegin<U>()==c.cbegin<U>()`
|
* `ci.cbegin<U>()==c.cbegin<U>()`
|
||||||
* `ci.end()==c.cend(typeid(U))`
|
* `ci.end()==c.cend(index<U>)`
|
||||||
* `ci.cend()==c.cend(typeid(U))`
|
* `ci.cend()==c.cend(index<U>)`
|
||||||
* `ci.end<U>()==c.cend<U>()`
|
* `ci.end<U>()==c.cend<U>()`
|
||||||
* `ci.cend<U>()==c.cend<U>()`
|
* `ci.cend<U>()==c.cend<U>()`
|
||||||
* `ci.type_info()==typeid(U)`
|
* `ci.type_info()==index<U>`
|
||||||
|
|
||||||
[#poly_collection.reference.polymorphic_containers.polymorphic_collections.types.base_segment_info]
|
[#poly_collection.reference.polymorphic_containers.polymorphic_collections.types.base_segment_info]
|
||||||
[def _base_segment_info_ [link poly_collection.reference.polymorphic_containers.polymorphic_collections.types.base_segment_info `base_segment_info`]]
|
[def _base_segment_info_ [link poly_collection.reference.polymorphic_containers.polymorphic_collections.types.base_segment_info `base_segment_info`]]
|
||||||
@@ -239,9 +261,9 @@ _CopyConstructible_ and _CopyAssignable_ type publicly derived from
|
|||||||
if `i` is an object of type `C::base_segment_info` associated to the
|
if `i` is an object of type `C::base_segment_info` associated to the
|
||||||
segment of `c` for `U`, then
|
segment of `c` for `U`, then
|
||||||
|
|
||||||
* `i.begin()==c.begin(typeid(U))`
|
* `i.begin()==c.begin(index<U>)`
|
||||||
* `i.begin<U>()==c.begin<U>()`
|
* `i.begin<U>()==c.begin<U>()`
|
||||||
* `i.end()==c.end(typeid(U))`
|
* `i.end()==c.end(index<U>)`
|
||||||
* `i.end<U>()==c.end<U>()`
|
* `i.end<U>()==c.end<U>()`
|
||||||
|
|
||||||
[#poly_collection.reference.polymorphic_containers.polymorphic_collections.types.const_segment_info]
|
[#poly_collection.reference.polymorphic_containers.polymorphic_collections.types.const_segment_info]
|
||||||
@@ -330,7 +352,7 @@ Internally calls `this->insert(j1,j2)` on construction.
|
|||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[section Type registration]
|
[section:type_registration Type registration (open collections only)]
|
||||||
|
|
||||||
[#poly_collection.reference.polymorphic_containers.polymorphic_collections.type_registration.register_types]
|
[#poly_collection.reference.polymorphic_containers.polymorphic_collections.type_registration.register_types]
|
||||||
[def _register_types_ [link poly_collection.reference.polymorphic_containers.polymorphic_collections.type_registration.register_types `register_types`]]
|
[def _register_types_ [link poly_collection.reference.polymorphic_containers.polymorphic_collections.type_registration.register_types `register_types`]]
|
||||||
@@ -646,6 +668,7 @@ from the last one to the end of its segment.
|
|||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[import poly_collection_synopsis.qbk] [/ template poly_collection_synopsis]
|
[import poly_collection_synopsis.qbk] [/ template poly_collection_synopsis]
|
||||||
|
[import closed_poly_collection_synopsis.qbk] [/ template closed_poly_collection_synopsis]
|
||||||
|
|
||||||
[section Header `"boost/poly_collection/exception.hpp"` synopsis]
|
[section Header `"boost/poly_collection/exception.hpp"` synopsis]
|
||||||
|
|
||||||
@@ -794,14 +817,14 @@ namespace.
|
|||||||
|
|
||||||
[section Class template `base_collection`]
|
[section Class template `base_collection`]
|
||||||
|
|
||||||
`base_collection<Base,Allocator>` is a _PolymorphicCollection_ associated to
|
`base_collection<Base,Allocator>` is an open _PolymorphicCollection_ associated to
|
||||||
the classic base/derived _polymorphism_model_:
|
the classic base/derived _polymorphism_model_:
|
||||||
|
|
||||||
* *Interface* = { `Base` : `std::is_polymorphic_v<Base>` }.
|
* *Interface* = { `Base` : `std::is_polymorphic_v<Base>` }.
|
||||||
* *Implementation*(`Base`) = { `Derived` : `std::is_base_of_v<Base,Derived>` }.
|
* *Implementation*(`Base`) = { `Derived` : `std::is_base_of_v<Base,Derived>` }.
|
||||||
* *subobject*(`x`) = `static_cast<Derived&>(x)` with `typeid(x)==typeid(Derived)`.
|
* *subobject*(`x`) = `static_cast<Derived&>(x)` with `typeid(x)==typeid(Derived)`.
|
||||||
|
|
||||||
[poly_collection_synopsis `base_collection`..`template<typename Base,typename Allocator>`..`Base`]
|
[poly_collection_synopsis `base_collection`..`template<typename Base,typename Allocator>`..`Base`..`std::type_info`]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
@@ -974,19 +997,16 @@ wrapped callable object.
|
|||||||
|
|
||||||
[section Class template `function_collection`]
|
[section Class template `function_collection`]
|
||||||
|
|
||||||
`function_collection<Signature,Allocator>` is a _PolymorphicCollection_ associated to
|
`function_collection<Signature,Allocator>` is an open _PolymorphicCollection_ associated to
|
||||||
a dynamic _polymorphism_model_ based on call signature compatibility:
|
a dynamic _polymorphism_model_ based on call signature compatibility:
|
||||||
|
|
||||||
[itemized_list
|
* *Interface* = { `Signature` : `Signature` = `R(Args...)` }.
|
||||||
[*Interface* = { `Signature` : `Signature` = `R(Args...)` }.]
|
* *Implementation*(`Signature`) = { `Callable` : `std::is_invocable_r_v<R,Callable,Args...>` }.
|
||||||
[*Implementation*(`Signature`) = { `Callable` : `std::is_invocable_r_v<R,Callable,Args...>` }.]
|
* *subobject*(`x`) =
|
||||||
[*subobject*(`x`) =[br]
|
* `x.target<T>()` with `typeid(T)==x.target_type()`, if `x` is an instantiation of _function_collection_value_type_,
|
||||||
`x.target<T>()` with `typeid(T)==x.target_type()`, if `x` is an instantiation of _function_collection_value_type_,[br]
|
* `x`, otherwise.
|
||||||
`x`, otherwise.
|
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
[poly_collection_synopsis `function_collection`..`template<typename Signature,typename Allocator>`..`_function_collection_value_type_<Signature>`]
|
[poly_collection_synopsis `function_collection`..`template<typename Signature,typename Allocator>`..`_function_collection_value_type_<Signature>`..`std::type_info`]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
@@ -1093,26 +1113,405 @@ The exact definition of `Concept2` is implementation defined.
|
|||||||
|
|
||||||
[section Class template `any_collection`]
|
[section Class template `any_collection`]
|
||||||
|
|
||||||
`any_collection<Concept,Allocator>` is a _PolymorphicCollection_ associated to
|
`any_collection<Concept,Allocator>` is an open _PolymorphicCollection_ associated to
|
||||||
a dynamic _polymorphism_model_ based on _duck_typing_ as implemented by
|
a dynamic _polymorphism_model_ based on _duck_typing_ as implemented by
|
||||||
_Boost.TypeErasure_:
|
_Boost.TypeErasure_:
|
||||||
|
|
||||||
[itemized_list
|
* *Interface* = { `Concept` :
|
||||||
[*Interface* = { `Concept` :
|
|
||||||
as [@boost:/doc/html/boost_typeerasure/conceptdef.html specified] by _Boost.TypeErasure_,
|
as [@boost:/doc/html/boost_typeerasure/conceptdef.html specified] by _Boost.TypeErasure_,
|
||||||
using the [@boost:/doc/html/boost/type_erasure/_self.html `_self`]
|
using the [@boost:/doc/html/boost/type_erasure/_self.html `_self`]
|
||||||
[@boost:/doc/html/boost/type_erasure/placeholder.html placeholder] }.]
|
[@boost:/doc/html/boost/type_erasure/placeholder.html placeholder] }.
|
||||||
[*Implementation*(`Concept`) = { `Concrete` : `Concrete` satisfies `Concept` }.]
|
* *Implementation*(`Concept`) = { `Concrete` : `Concrete` satisfies `Concept` }.
|
||||||
[*subobject*(`x`) =[br]
|
* *subobject*(`x`) =
|
||||||
`boost::type_erasure::`[@boost:/doc/html/boost/type_erasure/any_cast.html `any_cast`]`<T&>(x)`
|
* `boost::type_erasure::`[@boost:/doc/html/boost/type_erasure/any_cast.html `any_cast`]`<T&>(x)`
|
||||||
with `typeid(T)==boost::type_erasure::`[@boost:/doc/html/boost/type_erasure/typeid_of.html `typeid_of`]`(x)`,
|
with `typeid(T)==boost::type_erasure::`[@boost:/doc/html/boost/type_erasure/typeid_of.html `typeid_of`]`(x)`,
|
||||||
if `x` is an instantiation of `boost::type_erasure::`[@boost:/doc/html/boost/type_erasure/any.html `any`]
|
if `x` is an instantiation of `boost::type_erasure::`[@boost:/doc/html/boost/type_erasure/any.html `any`]
|
||||||
including [@boost:/doc/html/boost/type_erasure/typeid_.html `typeid_`]`<>`,[br]
|
including [@boost:/doc/html/boost/type_erasure/typeid_.html `typeid_`]`<>`,
|
||||||
`x`, otherwise.
|
* `x`, otherwise.
|
||||||
]
|
|
||||||
]
|
|
||||||
|
|
||||||
[poly_collection_synopsis `any_collection`..`template<typename Concept,typename Allocator>`..`_any_collection_value_type_<Concept>`]
|
[poly_collection_synopsis `any_collection`..`template<typename Concept,typename Allocator>`..`_any_collection_value_type_<Concept>`..`std::type_info`]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section Header `"boost/poly_collection/variant_collection_fwd.hpp"` synopsis]
|
||||||
|
|
||||||
|
[def _variant_collection_ [link poly_collection.reference.header_boost_poly_collection_va0.class_template_variant_collectio `variant_collection`]]
|
||||||
|
[def _variant_collection_value_type_ [link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio `variant_collection_value_type`]]
|
||||||
|
|
||||||
|
#include <boost/mp11/list.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace boost{
|
||||||
|
|
||||||
|
namespace poly_collection{
|
||||||
|
|
||||||
|
template<typename TypeList>
|
||||||
|
using _variant_collection_value_type_=``/implementation-defined/``;
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename TypeList,
|
||||||
|
typename Allocator=std::allocator<variant_collection_value_type<TypeList>>
|
||||||
|
>
|
||||||
|
class _variant_collection_;
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
using variant_collection_of=variant_collection<mp11::mp_list<Ts...>>;
|
||||||
|
|
||||||
|
template<typename TypeList,typename Allocator>
|
||||||
|
bool operator==(
|
||||||
|
const variant_collection<TypeList,Allocator>& x,
|
||||||
|
const variant_collection<TypeList,Allocator>& y);
|
||||||
|
|
||||||
|
template<typename TypeList,typename Allocator>
|
||||||
|
bool operator!=(
|
||||||
|
const variant_collection<TypeList,Allocator>& x,
|
||||||
|
const variant_collection<TypeList,Allocator>& y);
|
||||||
|
|
||||||
|
template<typename TypeList,typename Allocator>
|
||||||
|
void swap(
|
||||||
|
variant_collection<TypeList,Allocator>& x,variant_collection<TypeList,Allocator>& y);
|
||||||
|
|
||||||
|
} /* namespace poly_collection */
|
||||||
|
|
||||||
|
using poly_collection::variant_collection;
|
||||||
|
using poly_collection::variant_collection_of;
|
||||||
|
|
||||||
|
} /* namespace boost */
|
||||||
|
|
||||||
|
Defines the alias template _variant_collection_value_type_ (the actual type
|
||||||
|
it refers to, though, is merely forward declared).
|
||||||
|
Forward declares the class template _variant_collection_
|
||||||
|
and specifies its default template arguments.
|
||||||
|
Defines the alias template `variant_collection_of`. Forward declares associated
|
||||||
|
free functions and brings `boost::poly_collection::variant_collection`
|
||||||
|
and `poly_collection::variant_collection_of` to the `boost` namespace.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section Header `"boost/poly_collection/variant_collection.hpp"` synopsis]
|
||||||
|
|
||||||
|
#include <boost/poly_collection/variant_collection_fwd.hpp>
|
||||||
|
|
||||||
|
namespace boost{
|
||||||
|
|
||||||
|
namespace poly_collection{
|
||||||
|
|
||||||
|
// defines the type ``_variant_collection_value_type_`` refers to
|
||||||
|
|
||||||
|
template<typename TypeList,typename Allocator>
|
||||||
|
class _variant_collection_;
|
||||||
|
|
||||||
|
template<typename TypeList,typename Allocator>
|
||||||
|
bool operator==(
|
||||||
|
const variant_collection<TypeList,Allocator>& x,
|
||||||
|
const variant_collection<TypeList,Allocator>& y);
|
||||||
|
|
||||||
|
template<typename TypeList,typename Allocator>
|
||||||
|
bool operator!=(
|
||||||
|
const variant_collection<TypeList,Allocator>& x,
|
||||||
|
const variant_collection<TypeList,Allocator>& y);
|
||||||
|
|
||||||
|
template<typename TypeList,typename Allocator>
|
||||||
|
void swap(
|
||||||
|
variant_collection<TypeList,Allocator>& x,variant_collection<TypeList,Allocator>& y);
|
||||||
|
|
||||||
|
} /* namespace poly_collection */
|
||||||
|
|
||||||
|
} /* namespace boost */
|
||||||
|
|
||||||
|
[section Alias template `variant_collection_value_type`]
|
||||||
|
|
||||||
|
`variant_collection_value_type<TypeList>` is the `value_type` of
|
||||||
|
`boost::variant_collection<TypeList,Allocator>`, where `TypeList`
|
||||||
|
is a [@boost:/libs/mp11/doc/html/mp11.html#definitions Boost.Mp11 list]
|
||||||
|
of different types `Ts...`.
|
||||||
|
`variant_collection_value_type<TypeList>` behaves similarly to
|
||||||
|
_std::variant_`<Ts...>`, with some intentional limitations such as the impossibility
|
||||||
|
of changing the type of the underlying alternative.
|
||||||
|
|
||||||
|
In what follows, the name [' `variant_collection_value_type_impl`] is used
|
||||||
|
just for explanatory purposes in place of the actual class template name,
|
||||||
|
which is implementation defined.
|
||||||
|
|
||||||
|
template<typename TypeList>
|
||||||
|
using variant_collection_value_type=
|
||||||
|
mp11::mp_rename<TypeList,``/variant_collection_value_type_impl/``>;
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
class ``/variant_collection_value_type_impl/``
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::size_t ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.index index]``()const noexcept;
|
||||||
|
bool ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.valueless_by_exception valueless_by_exception]``()const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bad_variant_access:std::exception
|
||||||
|
{
|
||||||
|
bad_variant_access()noexcept{}
|
||||||
|
const char* what()const noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename V> struct variant_size; // not defined
|
||||||
|
template<typename... Ts>
|
||||||
|
struct ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.variant_size variant_size]``<``/variant_collection_value_type_impl/``<Ts...>>;
|
||||||
|
template<typename V> struct ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.variant_size variant_size]``<const V>;
|
||||||
|
|
||||||
|
template<typename V>
|
||||||
|
constexpr std::size_t variant_size_v=variant_size<V>::value;
|
||||||
|
|
||||||
|
template<std::size_t I,typename T> struct variant_alternative; // not defined
|
||||||
|
template<std::size_t I,typename... Ts>
|
||||||
|
struct ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.variant_alternative variant_alternative]``<I,``/variant_collection_value_type_impl/``<Ts...>>;
|
||||||
|
template<std::size_t I,typename V> struct ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.variant_alternative variant_alternative]``<I,const T>;
|
||||||
|
template<std::size_t I,typename V> struct ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.variant_alternative variant_alternative]``<I,V&>;
|
||||||
|
template<std::size_t I,typename V> struct ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.variant_alternative variant_alternative]``<I,const V&>;
|
||||||
|
template<std::size_t I,typename V> struct ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.variant_alternative variant_alternative]``<I,V&&>;
|
||||||
|
template<std::size_t I,typename V> struct ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.variant_alternative variant_alternative]``<I,const V&&>;
|
||||||
|
|
||||||
|
template<std::size_t I,typename V>
|
||||||
|
using variant_alternative_t=typename variant_alternative<I,V>::type;
|
||||||
|
|
||||||
|
template<typename T,typename... Ts>
|
||||||
|
bool ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.holds_alternative holds_alternative]``(const ``/variant_collection_value_type_impl/``<Ts...>& x)noexcept;
|
||||||
|
|
||||||
|
template<std::size_t I,typename V>
|
||||||
|
variant_alternative_t<I,V&&> ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.get_by_index get]``(V&& x);
|
||||||
|
|
||||||
|
template<typename T,typename V>
|
||||||
|
variant_alternative_t<mp11::mp_find<std::decay_t<V>,T>::value,V&&> ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.get_by_type get]``(V&& x);
|
||||||
|
|
||||||
|
template<std::size_t I,typename... Ts>
|
||||||
|
variant_alternative_t<I,``/variant_collection_value_type_impl/``<Ts...>>*
|
||||||
|
``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.get_if_by_index get_if]``(``/variant_collection_value_type_impl/``<Ts...>* px)noexcept;
|
||||||
|
template<std::size_t I,typename... Ts>
|
||||||
|
const variant_alternative_t<I,``/variant_collection_value_type_impl/``<Ts...>>*
|
||||||
|
``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.get_if_by_index get_if]``(const ``/variant_collection_value_type_impl/``<Ts...>* px)noexcept;
|
||||||
|
|
||||||
|
template<typename T,typename... Ts>
|
||||||
|
T* ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.get_if_by_type get_if]``(``/variant_collection_value_type_impl/``<Ts...>* px)noexcept;
|
||||||
|
template<typename T,typename... Ts>
|
||||||
|
const T* ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.get_if_by_type get_if]``(const ``/variant_collection_value_type_impl/``<Ts...>* px)noexcept;
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
bool ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_eq operator==]``(
|
||||||
|
const ``/variant_collection_value_type_impl/``<Ts...>& x,
|
||||||
|
const ``/variant_collection_value_type_impl/``<Ts...>& y);
|
||||||
|
template<typename... Ts>
|
||||||
|
bool ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_ne operator!=]``(
|
||||||
|
const ``/variant_collection_value_type_impl/``<Ts...>& x,
|
||||||
|
const ``/variant_collection_value_type_impl/``<Ts...>& y);
|
||||||
|
template<typename... Ts>
|
||||||
|
bool ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_lt operator<]``(
|
||||||
|
const ``/variant_collection_value_type_impl/``<Ts...>& x,
|
||||||
|
const ``/variant_collection_value_type_impl/``<Ts...>& y);
|
||||||
|
template<typename... Ts>
|
||||||
|
bool ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_gt operator>]``(
|
||||||
|
const ``/variant_collection_value_type_impl/``<Ts...>& x,
|
||||||
|
const ``/variant_collection_value_type_impl/``<Ts...>& y);
|
||||||
|
template<typename... Ts>
|
||||||
|
bool ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_le operator=<]``(
|
||||||
|
const ``/variant_collection_value_type_impl/``<Ts...>& x,
|
||||||
|
const ``/variant_collection_value_type_impl/``<Ts...>& y);
|
||||||
|
template<typename... Ts>
|
||||||
|
bool ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_ge operator>=]``(
|
||||||
|
const ``/variant_collection_value_type_impl/``<Ts...>& x,
|
||||||
|
const ``/variant_collection_value_type_impl/``<Ts...>& y);
|
||||||
|
|
||||||
|
template<typename R=``/see-below/``,typename F,typename... Vs>
|
||||||
|
``/see-below/`` ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.visit visit]``(F&& f,Vs&&... xs);
|
||||||
|
|
||||||
|
template<typename R=``/see-below/``,typename V,typename... Fs>
|
||||||
|
``/see-below/`` ``[link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.visit_by_index visit_by_index]``(V&& x,Fs&&... fs);
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.index]
|
||||||
|
|
||||||
|
`std::size_t index()const noexcept;`
|
||||||
|
|
||||||
|
[*Returns:] The index number into `Ts...` of the type of the alternative
|
||||||
|
contained in the variant.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.valueless_by_exception]
|
||||||
|
|
||||||
|
`bool valueless_by_exception()const noexcept;`
|
||||||
|
|
||||||
|
[*Returns:] `false`.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.variant_size]
|
||||||
|
|
||||||
|
`template<typename... Ts>`[br]
|
||||||
|
`struct variant_size<`[^ /variant_collection_value_type_impl/]`<Ts...>>;`[br]
|
||||||
|
`template<typename V> struct variant_size<const V>;`
|
||||||
|
|
||||||
|
`variant_size<...>::value` is a `constexpr std::size_t` value with
|
||||||
|
the number of alternative types specified for the variant.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.variant_alternative]
|
||||||
|
|
||||||
|
`template<std::size_t I,typename... Ts>`[br]
|
||||||
|
`struct variant_alternative<I,`[^ /variant_collection_value_type_impl/]`<Ts...>>;`[br]
|
||||||
|
`template<std::size_t I,typename V> struct variant_alternative<I,const T>;`[br]
|
||||||
|
`template<std::size_t I,typename V> struct variant_alternative<I,V&>;`[br]
|
||||||
|
`template<std::size_t I,typename V> struct variant_alternative<I,const V&>;`[br]
|
||||||
|
`template<std::size_t I,typename V> struct variant_alternative<I,V&&>;`[br]
|
||||||
|
`template<std::size_t I,typename V> struct variant_alternative<I,const V&&>;`
|
||||||
|
|
||||||
|
`variant_alternative<I,V>::type` is the `I`-th alternative type in the variant
|
||||||
|
with the same `const` and reference qualification as `V`.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.holds_alternative]
|
||||||
|
|
||||||
|
`template<typename T,typename... Ts>`[br]
|
||||||
|
`bool holds_alternative(const `[^ /variant_collection_value_type_impl/]`<Ts...>& x)noexcept;`
|
||||||
|
|
||||||
|
[*Returns:] `true` iff the type of the alternative contained in the variant is `T`.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.get_by_index]
|
||||||
|
|
||||||
|
`template<std::size_t I,typename V>`[br]
|
||||||
|
`variant_alternative_t<I,V&&> get(V&& x);`
|
||||||
|
|
||||||
|
[*Effects:] Throws `bad_variant_access` if `x.index()!=I`.[br]
|
||||||
|
[*Returns:] A reference to the contained value
|
||||||
|
with the same `const` and reference qualification as `x`.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.get_by_type]
|
||||||
|
|
||||||
|
`template<typename T,typename V>`[br]
|
||||||
|
`variant_alternative_t<mp11::mp_find<std::decay_t<V>,T>::value,V&&> get(V&& x);`
|
||||||
|
|
||||||
|
[*Effects:] Throws `bad_variant_access` if `!holds_alternative<T>(x)`.[br]
|
||||||
|
[*Returns:] A reference to the contained value
|
||||||
|
with the same `const` and reference qualification as `x`.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.get_if_by_index]
|
||||||
|
|
||||||
|
`template<std::size_t I,typename... Ts>`[br]
|
||||||
|
`variant_alternative_t<I,`[^ /variant_collection_value_type_impl/]`<Ts...>>*`[br]
|
||||||
|
`get_if(`[^ /variant_collection_value_type_impl/]`<Ts...>* px)noexcept;`[br]
|
||||||
|
`template<std::size_t I,typename... Ts>`[br]
|
||||||
|
`const variant_alternative_t<I,`[^ /variant_collection_value_type_impl/]`<Ts...>>*`[br]
|
||||||
|
`get_if(const `[^ /variant_collection_value_type_impl/]`<Ts...>* px)noexcept;`
|
||||||
|
|
||||||
|
[*Returns:] `nullptr` if `px` is null or `px->index()!=I`,
|
||||||
|
a pointer to the contained value otherwise.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.get_if_by_type]
|
||||||
|
|
||||||
|
`template<typename T,typename... Ts>`[br]
|
||||||
|
`T* get_if(`[^ /variant_collection_value_type_impl/]`<Ts...>* px)noexcept;`[br]
|
||||||
|
`template<typename T,typename... Ts>`[br]
|
||||||
|
`const T* get_if(const `[^ /variant_collection_value_type_impl/]`<Ts...>* px)noexcept;`
|
||||||
|
|
||||||
|
[*Returns:] `nullptr` if `px` is null or `!holds_alternative<T>(*px)`,
|
||||||
|
a pointer to the contained value otherwise.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_eq]
|
||||||
|
|
||||||
|
`template<typename... Ts>`[br]
|
||||||
|
`bool operator==(`[br]
|
||||||
|
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br]
|
||||||
|
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);`
|
||||||
|
|
||||||
|
[*Returns:] `x.index()==y.index()&&get<I>(x)==get<I>(y)` with `I==x.index()`.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_ne]
|
||||||
|
|
||||||
|
`template<typename... Ts>`[br]
|
||||||
|
`bool operator!=(`[br]
|
||||||
|
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br]
|
||||||
|
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);`
|
||||||
|
|
||||||
|
[*Returns:] `x.index()!=y.index()||get<I>(x)!=get<I>(y)` with `I==x.index()`.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_lt]
|
||||||
|
|
||||||
|
`template<typename... Ts>`[br]
|
||||||
|
`bool operator<(`[br]
|
||||||
|
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br]
|
||||||
|
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);`
|
||||||
|
|
||||||
|
[*Returns:] `x.index()<y.index()||x.index()==y.index()&&get<I>(x)<get<I>(y)` with `I==x.index()`.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_gt]
|
||||||
|
|
||||||
|
`template<typename... Ts>`[br]
|
||||||
|
`bool operator>(`[br]
|
||||||
|
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br]
|
||||||
|
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);`
|
||||||
|
|
||||||
|
[*Returns:] `x.index()>y.index()||x.index()==y.index()&&get<I>(x)>get<I>(y)` with `I==x.index()`.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_le]
|
||||||
|
|
||||||
|
`template<typename... Ts>`[br]
|
||||||
|
`bool operator<=(`[br]
|
||||||
|
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br]
|
||||||
|
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);`
|
||||||
|
|
||||||
|
[*Returns:] `x.index()<y.index()||x.index()==y.index()&&get<I>(x)<=get<I>(y)` with `I==x.index()`.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.operator_ge]
|
||||||
|
|
||||||
|
`template<typename... Ts>`[br]
|
||||||
|
`bool operator>=(`[br]
|
||||||
|
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& x,`[br]
|
||||||
|
[^ \u00a0\u00a0]`const `[^ /variant_collection_value_type_impl/]`<Ts...>& y);`
|
||||||
|
|
||||||
|
[*Returns:] `x.index()>y.index()||x.index()==y.index()&&get<I>(x)>=get<I>(y)` with `I==x.index()`.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.visit]
|
||||||
|
|
||||||
|
`template<typename R=`[^ /see-below/]`,typename F,typename... Vs>`[br]
|
||||||
|
[^ /see-below/]` visit(F&& f,Vs&&... xs);`
|
||||||
|
|
||||||
|
[*Effects:] Calls the expression `e(Is...)`, defined as
|
||||||
|
`std::forward<F>(f)(get<Is>(std::forward<Vs>(xs)...)`, with `Is...` equal to `xs.index()...`.[br]
|
||||||
|
[*Returns:]
|
||||||
|
|
||||||
|
* If `R` is specified as `void`: nothing.
|
||||||
|
* If `R` is specified as a type different from `void`: the value `e(Is...)` implicitly
|
||||||
|
converted to `R`.
|
||||||
|
* If `R` is not specified, `e(Is...)`. In this and the previous case,
|
||||||
|
`e(Js...)` must have the same type for all valid index packs `Js...`.
|
||||||
|
|
||||||
|
[#poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio.visit_by_index]
|
||||||
|
|
||||||
|
`template<typename R=`[^ /see-below/]`,typename V,typename... Fs>`[br]
|
||||||
|
[^ /see-below/]` visit_by_index(V&& x,Fs&&... fs);`
|
||||||
|
|
||||||
|
[*Requires:] `sizeof...(Fs)` is equal to the number of alternative types in the variant.[br]
|
||||||
|
[*Effects:] Calls the expression `e(i)`, defined as
|
||||||
|
`std::forward<Fi>(fi)(get<i>(std::forward<V>(x)))`, with `i==x.index()` and
|
||||||
|
`Fi` and `fi` denoting the `i`-th element of `Fs...` and `fs...`, respectively.[br]
|
||||||
|
[*Returns:]
|
||||||
|
|
||||||
|
* If `R` is specified as `void`: nothing.
|
||||||
|
* If `R` is specified as a type different from `void`: the value `e(i)` implicitly
|
||||||
|
converted to `R`.
|
||||||
|
* If `R` is not specified, `e(i)`. In this and the previous case,
|
||||||
|
`e(j)` must have the same type for all `j` in \[0, `sizeof...(Fs)`).
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section Class template `variant_collection`]
|
||||||
|
|
||||||
|
`variant_collection<TypeList,Allocator>` is a closed _PolymorphicCollection_ associated to
|
||||||
|
a dynamic _polymorphism_model_ based on the interface of _std::variant_:
|
||||||
|
|
||||||
|
* *Interface* = { `TypeList` = `L<Ts...>` : `L` is an arbitrary class template, `Ts...` is not empty, and
|
||||||
|
each `Ti` in `Ts...` is different, _MoveConstructible_, and _MoveAssignable_ or such that
|
||||||
|
[@http://en.cppreference.com/w/cpp/types/is_move_constructible `std::is_nothrow_move_constructible<Ti>::value`] is `true` }.
|
||||||
|
* *Implementation*(`L<Ts...>`) = { `Ts...` } \u222a
|
||||||
|
{ [link poly_collection.reference.header_boost_poly_collection_va0.alias_template_variant_collectio `variant_collection_value_type`]`<Us...>` : `Us...` \u2286 `Ts...` } \u222a
|
||||||
|
{ _std::variant_`<Us...>` : `Us...` \u2286 `Ts...` } \u222a
|
||||||
|
{ [@boost:libs/variant2/doc/html/variant2.html#ref_variant `boost::variant2::variant`]`<Us...>` : `Us...` \u2286 `Ts...` }.
|
||||||
|
* *subobject*(`x`) =
|
||||||
|
* `get<I>(x)` with `I==x.index()`, if the type of `x` is not in `Ts...`,
|
||||||
|
* `x`, otherwise.
|
||||||
|
|
||||||
|
[closed_poly_collection_synopsis `variant_collection`..`template<typename TypeList,typename Allocator>`..`_variant_collection_value_type_<TypeList>`..`std::size_t`]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
@@ -1124,6 +1523,10 @@ _Boost.TypeErasure_:
|
|||||||
|
|
||||||
namespace poly_collection{
|
namespace poly_collection{
|
||||||
|
|
||||||
|
``['`// total restitution for closed collections:`]``
|
||||||
|
|
||||||
|
struct all_types;
|
||||||
|
|
||||||
``['`// non-modifying sequence operations:`]``
|
``['`// non-modifying sequence operations:`]``
|
||||||
|
|
||||||
template<typename... Ts,typename PolyCollectionIterator,typename Predicate>
|
template<typename... Ts,typename PolyCollectionIterator,typename Predicate>
|
||||||
@@ -1468,12 +1871,15 @@ these algorithms for /type restitution/.
|
|||||||
For the description of the algorithms we use the following notation:
|
For the description of the algorithms we use the following notation:
|
||||||
|
|
||||||
* [' `alg`] is the (unqualified) name of any of the algorithms in
|
* [' `alg`] is the (unqualified) name of any of the algorithms in
|
||||||
`"boost/poly_collection/algorithm.hpp"` except `copy_n` and `rotate_copy`.
|
`"boost/poly_collection/algorithm.hpp"` except `for_each_n`, `copy_n` and `rotate_copy`.
|
||||||
* `first`, `middle` and `last` are (same-typed) possibly const global iterators
|
* `first`, `middle` and `last` are (same-typed) possibly const global iterators
|
||||||
of a collection of Boost.PolyCollection such that \[`first`, `middle`) and
|
of a collection of Boost.PolyCollection such that \[`first`, `middle`) and
|
||||||
\[`middle`, `last`) are valid ranges.
|
\[`middle`, `last`) are valid ranges.
|
||||||
* `args...` is a function parameter pack of types `Args&&...`,
|
* `args...` is a function parameter pack of types `Args&&...`,
|
||||||
* `Ts...` is a template parameter pack of arbitrary types.
|
* `Ts...` is a template parameter pack of arbitrary types.
|
||||||
|
* Open collections: `Us...` is defined as `Ts...`.
|
||||||
|
* Closed collections: `Us...` is defined as the set of all acceptable types
|
||||||
|
in the collection if `all_types` is in `Ts...`, or as `Ts...` otherwise.
|
||||||
|
|
||||||
(1) [' `alg`]`(first,last,args...)`[br]
|
(1) [' `alg`]`(first,last,args...)`[br]
|
||||||
(2) `for_each_n(first,args...)`[br]
|
(2) `for_each_n(first,args...)`[br]
|
||||||
@@ -1503,14 +1909,18 @@ as:[br]
|
|||||||
(4) `std::rotate_copy(rfirst,rmiddle,rlast,args...)`,[br]
|
(4) `std::rotate_copy(rfirst,rmiddle,rlast,args...)`,[br]
|
||||||
and `rfirst`, `rmiddle` and `rlast` are iterator-like objects behaving like
|
and `rfirst`, `rmiddle` and `rlast` are iterator-like objects behaving like
|
||||||
their `first`, `middle` and `last` counterparts except that they
|
their `first`, `middle` and `last` counterparts except that they
|
||||||
dereference to the corresponding subobject (`const`) `T&` if pointing to a
|
dereference to the corresponding subobject (`const`) `U&` if pointing to a
|
||||||
segment for `T` and `T` is in `Ts...`
|
segment for `U` and `U` is in `Us...`
|
||||||
[footnote Strictly speaking a proper _ForwardIterator_ cannot behave
|
[footnote Strictly speaking a proper _ForwardIterator_ cannot behave
|
||||||
like this as dereferencing must yield /exactly/ a (`const`) `value_type&`
|
like this as dereferencing must yield /exactly/ a (`const`) `value_type&`
|
||||||
value, which disallows this type of polymorphism.].[br]
|
value, which disallows this type of polymorphism.].[br]
|
||||||
[*Effects:] Equivalent to `expr`.[br]
|
[*Effects:] Equivalent to `expr`.[br]
|
||||||
[*Returns:] `expr`.[br]
|
[*Returns:] `expr`.[br]
|
||||||
[*Complexity:] That of `expr`.
|
[*Complexity:] That of `expr`.[br]
|
||||||
|
[*Note:] In the case of closed collections, if `Us...` contains all the
|
||||||
|
acceptable types of the collection (/total restitution/), then
|
||||||
|
the dereference operation of `rfirst`, `rmiddle` and `rlast` to the
|
||||||
|
collection's `value_type` is not ever instantiated.
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright 2016-2017 Joaquín M López Muñoz.
|
# Copyright 2016-2024 Joaquín M López Muñoz.
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
# http://www.boost.org/LICENSE_1_0.txt)
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -13,7 +13,7 @@ project
|
|||||||
|
|
||||||
exe algorithms
|
exe algorithms
|
||||||
: algorithms.cpp
|
: algorithms.cpp
|
||||||
: <cxxstd>14
|
: <cxxstd>17
|
||||||
;
|
;
|
||||||
|
|
||||||
exe basic_any
|
exe basic_any
|
||||||
@@ -29,6 +29,11 @@ exe basic_function
|
|||||||
: <cxxstd>14
|
: <cxxstd>14
|
||||||
;
|
;
|
||||||
|
|
||||||
|
exe basic_variant
|
||||||
|
: basic_variant.cpp
|
||||||
|
: <cxxstd>17
|
||||||
|
;
|
||||||
|
|
||||||
exe exceptions
|
exe exceptions
|
||||||
: exceptions.cpp
|
: exceptions.cpp
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2017 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <boost/poly_collection/algorithm.hpp>
|
#include <boost/poly_collection/algorithm.hpp>
|
||||||
#include <boost/poly_collection/any_collection.hpp>
|
#include <boost/poly_collection/any_collection.hpp>
|
||||||
#include <boost/poly_collection/base_collection.hpp>
|
#include <boost/poly_collection/base_collection.hpp>
|
||||||
|
#include <boost/poly_collection/variant_collection.hpp>
|
||||||
#include <boost/type_erasure/any.hpp>
|
#include <boost/type_erasure/any.hpp>
|
||||||
#include <boost/type_erasure/any_cast.hpp>
|
#include <boost/type_erasure/any_cast.hpp>
|
||||||
#include <boost/type_erasure/builtin.hpp>
|
#include <boost/type_erasure/builtin.hpp>
|
||||||
@@ -32,6 +33,11 @@ std::ostream& operator<<(std::ostream& os,const window& w)
|
|||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
struct overloaded:Ts...{using Ts::operator()...;};
|
||||||
|
template<class... Ts>
|
||||||
|
overloaded(Ts...)->overloaded<Ts...>;
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
boost::base_collection<sprite> c;
|
boost::base_collection<sprite> c;
|
||||||
@@ -168,4 +174,33 @@ int main()
|
|||||||
});
|
});
|
||||||
std::cout<<"\n";
|
std::cout<<"\n";
|
||||||
//]
|
//]
|
||||||
|
|
||||||
|
{
|
||||||
|
//[algorithms_9
|
||||||
|
boost::variant_collection<
|
||||||
|
boost::mp11::mp_list<warrior,juggernaut,goblin,elf,std::string,window>
|
||||||
|
> c;
|
||||||
|
//= ...
|
||||||
|
//<-
|
||||||
|
c.insert(warrior(0));
|
||||||
|
c.insert(std::string("play again"));
|
||||||
|
c.insert(window("player one"));
|
||||||
|
//->
|
||||||
|
|
||||||
|
auto print_sprite=[](const sprite& s) { s.render(std::cout); };
|
||||||
|
auto print_string=[](const std::string& str){ std::cout<<str; };
|
||||||
|
auto print_window=[](const window& w) { w.display(std::cout); };
|
||||||
|
auto print=overloaded{print_sprite,print_string,print_window};
|
||||||
|
|
||||||
|
const char* comma="";
|
||||||
|
boost::poly_collection::for_each<boost::poly_collection::all_types>(
|
||||||
|
c.begin(),c.end(),[&](const auto& r){
|
||||||
|
std::cout<<comma;
|
||||||
|
print(r);
|
||||||
|
comma=",";
|
||||||
|
});
|
||||||
|
std::cout<<"\n";
|
||||||
|
|
||||||
|
//]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* basic usage of boost::variant_collection */
|
||||||
|
|
||||||
|
#include <boost/poly_collection/variant_collection.hpp>
|
||||||
|
#include <random>
|
||||||
|
#include "rolegame.hpp"
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
struct overloaded:Ts...{using Ts::operator()...;};
|
||||||
|
template<class... Ts>
|
||||||
|
overloaded(Ts...)->overloaded<Ts...>;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
//[basic_variant_1
|
||||||
|
//= #include <boost/poly_collection/variant_collection.hpp>
|
||||||
|
//= ...
|
||||||
|
//=
|
||||||
|
boost::variant_collection<
|
||||||
|
boost::mp11::mp_list<warrior,juggernaut,goblin,elf,std::string,window>
|
||||||
|
> c;
|
||||||
|
//]
|
||||||
|
|
||||||
|
{
|
||||||
|
//[basic_variant_2
|
||||||
|
boost::variant_collection_of<
|
||||||
|
warrior,juggernaut,goblin,elf,std::string,window
|
||||||
|
> c;
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
|
||||||
|
// populate with sprites
|
||||||
|
std::mt19937 gen{92754}; // some arbitrary random seed
|
||||||
|
std::discrete_distribution<> rnd{{1,1,1,1}};
|
||||||
|
for(int i=0;i<5;++i){ // assign each type with 1/4 probability
|
||||||
|
switch(rnd(gen)){
|
||||||
|
case 0: c.insert(warrior{i});break;
|
||||||
|
case 1: c.insert(juggernaut{i});break;
|
||||||
|
case 2: c.insert(goblin{i});break;
|
||||||
|
case 3: c.insert(elf{i});break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// populate with messages
|
||||||
|
c.insert(std::string{"\"stamina: 10,000\""});
|
||||||
|
c.insert(std::string{"\"game over\""});
|
||||||
|
|
||||||
|
// populate with windows
|
||||||
|
c.insert(window{"pop-up 1"});
|
||||||
|
c.insert(window{"pop-up 2"});
|
||||||
|
|
||||||
|
{
|
||||||
|
//[basic_variant_3
|
||||||
|
//= // usual utility to construct a visitor
|
||||||
|
//= template<typename... Ts>
|
||||||
|
//= struct overloaded:Ts...{using Ts::operator()...;};
|
||||||
|
//= template<class... Ts>
|
||||||
|
//= overloaded(Ts...)->overloaded<Ts...>;
|
||||||
|
|
||||||
|
const char* comma="";
|
||||||
|
for(const auto& r:c){
|
||||||
|
std::cout<<comma;
|
||||||
|
visit(overloaded{
|
||||||
|
[](const sprite& s) { s.render(std::cout); },
|
||||||
|
[](const std::string& str){ std::cout<<str; },
|
||||||
|
[](const window& w) { w.display(std::cout); }
|
||||||
|
},r);
|
||||||
|
comma=",";
|
||||||
|
}
|
||||||
|
std::cout<<"\n";
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
//[basic_variant_4
|
||||||
|
auto print_sprite=[](const sprite& s) { s.render(std::cout); };
|
||||||
|
auto print_string=[](const std::string& str){ std::cout<<str; };
|
||||||
|
auto print_window=[](const window& w) { w.display(std::cout); };
|
||||||
|
|
||||||
|
const char* comma="";
|
||||||
|
for(const auto& r:c){
|
||||||
|
std::cout<<comma;
|
||||||
|
visit_by_index(
|
||||||
|
r,
|
||||||
|
print_sprite, // type #0: warrior
|
||||||
|
print_sprite, // type #1: juggernaut
|
||||||
|
print_sprite, // type #2: goblin
|
||||||
|
print_sprite, // type #3: elf
|
||||||
|
print_string, // type #4
|
||||||
|
print_window); // type #5
|
||||||
|
comma=",";
|
||||||
|
}
|
||||||
|
std::cout<<"\n";
|
||||||
|
//]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2017 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -64,10 +64,13 @@ void resume_timing()
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <boost/mp11/list.hpp>
|
||||||
|
#include <boost/variant2/variant.hpp>
|
||||||
#include <boost/poly_collection/algorithm.hpp>
|
#include <boost/poly_collection/algorithm.hpp>
|
||||||
#include <boost/poly_collection/any_collection.hpp>
|
#include <boost/poly_collection/any_collection.hpp>
|
||||||
#include <boost/poly_collection/base_collection.hpp>
|
#include <boost/poly_collection/base_collection.hpp>
|
||||||
#include <boost/poly_collection/function_collection.hpp>
|
#include <boost/poly_collection/function_collection.hpp>
|
||||||
|
#include <boost/poly_collection/variant_collection.hpp>
|
||||||
#include <boost/ptr_container/ptr_container.hpp>
|
#include <boost/ptr_container/ptr_container.hpp>
|
||||||
#include <boost/type_erasure/any.hpp>
|
#include <boost/type_erasure/any.hpp>
|
||||||
#include <boost/type_erasure/callable.hpp>
|
#include <boost/type_erasure/callable.hpp>
|
||||||
@@ -143,13 +146,13 @@ struct ptr_vector:boost::ptr_vector<Base>
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void insert(const T& x)
|
BOOST_FORCEINLINE void insert(const T& x)
|
||||||
{
|
{
|
||||||
this->push_back(new T{x});
|
this->push_back(new T{x});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void for_each(F f)
|
BOOST_FORCEINLINE void for_each(F f)
|
||||||
{
|
{
|
||||||
std::for_each(this->begin(),this->end(),f);
|
std::for_each(this->begin(),this->end(),f);
|
||||||
}
|
}
|
||||||
@@ -182,7 +185,7 @@ template<typename Base>
|
|||||||
struct base_collection:boost::base_collection<Base>
|
struct base_collection:boost::base_collection<Base>
|
||||||
{
|
{
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void for_each(F f)
|
BOOST_FORCEINLINE void for_each(F f)
|
||||||
{
|
{
|
||||||
std::for_each(this->begin(),this->end(),f);
|
std::for_each(this->begin(),this->end(),f);
|
||||||
}
|
}
|
||||||
@@ -194,7 +197,7 @@ template<typename Base,typename... T>
|
|||||||
struct poly_for_each_base_collection:base_collection<Base>
|
struct poly_for_each_base_collection:base_collection<Base>
|
||||||
{
|
{
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void for_each(F f)
|
BOOST_FORCEINLINE void for_each(F f)
|
||||||
{
|
{
|
||||||
boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
|
boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
|
||||||
}
|
}
|
||||||
@@ -203,13 +206,13 @@ struct poly_for_each_base_collection:base_collection<Base>
|
|||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
struct func_vector:std::vector<std::function<Signature>>
|
struct func_vector:std::vector<std::function<Signature>>
|
||||||
{
|
{
|
||||||
template<typename T> void insert(const T& x)
|
template<typename T> BOOST_FORCEINLINE void insert(const T& x)
|
||||||
{
|
{
|
||||||
this->push_back(x);
|
this->push_back(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void for_each(F f)
|
BOOST_FORCEINLINE void for_each(F f)
|
||||||
{
|
{
|
||||||
std::for_each(this->begin(),this->end(),f);
|
std::for_each(this->begin(),this->end(),f);
|
||||||
}
|
}
|
||||||
@@ -243,7 +246,7 @@ template<typename Signature>
|
|||||||
struct func_collection:boost::function_collection<Signature>
|
struct func_collection:boost::function_collection<Signature>
|
||||||
{
|
{
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void for_each(F f)
|
BOOST_FORCEINLINE void for_each(F f)
|
||||||
{
|
{
|
||||||
std::for_each(this->begin(),this->end(),f);
|
std::for_each(this->begin(),this->end(),f);
|
||||||
}
|
}
|
||||||
@@ -255,7 +258,7 @@ template<typename Signature,typename... T>
|
|||||||
struct poly_for_each_func_collection:func_collection<Signature>
|
struct poly_for_each_func_collection:func_collection<Signature>
|
||||||
{
|
{
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void for_each(F f)
|
BOOST_FORCEINLINE void for_each(F f)
|
||||||
{
|
{
|
||||||
boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
|
boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
|
||||||
}
|
}
|
||||||
@@ -270,7 +273,7 @@ struct any_vector:std::vector<boost::type_erasure::any<Concept>>
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void for_each(F f)
|
BOOST_FORCEINLINE void for_each(F f)
|
||||||
{
|
{
|
||||||
std::for_each(this->begin(),this->end(),f);
|
std::for_each(this->begin(),this->end(),f);
|
||||||
}
|
}
|
||||||
@@ -304,7 +307,7 @@ template<typename Concept>
|
|||||||
struct any_collection:boost::any_collection<Concept>
|
struct any_collection:boost::any_collection<Concept>
|
||||||
{
|
{
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void for_each(F f)
|
BOOST_FORCEINLINE void for_each(F f)
|
||||||
{
|
{
|
||||||
std::for_each(this->begin(),this->end(),f);
|
std::for_each(this->begin(),this->end(),f);
|
||||||
}
|
}
|
||||||
@@ -316,7 +319,69 @@ template<typename Concept,typename... T>
|
|||||||
struct poly_for_each_any_collection:any_collection<Concept>
|
struct poly_for_each_any_collection:any_collection<Concept>
|
||||||
{
|
{
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void for_each(F f)
|
BOOST_FORCEINLINE void for_each(F f)
|
||||||
|
{
|
||||||
|
boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename L>
|
||||||
|
struct variant_vector:
|
||||||
|
std::vector<boost::mp11::mp_rename<L,boost::variant2::variant>>
|
||||||
|
{
|
||||||
|
template<typename T> void insert(const T& x)
|
||||||
|
{
|
||||||
|
this->push_back(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
BOOST_FORCEINLINE void for_each(F f)
|
||||||
|
{
|
||||||
|
std::for_each(this->begin(),this->end(),f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare_for_for_each(){}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename L>
|
||||||
|
struct sorted_variant_vector:variant_vector<L>
|
||||||
|
{
|
||||||
|
void prepare_for_for_each()
|
||||||
|
{
|
||||||
|
using value_type=typename sorted_variant_vector::value_type;
|
||||||
|
std::sort(
|
||||||
|
this->begin(),this->end(),[](const value_type& x,const value_type& y){
|
||||||
|
return x.index()<y.index();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename L>
|
||||||
|
struct shuffled_variant_vector:variant_vector<L>
|
||||||
|
{
|
||||||
|
void prepare_for_for_each()
|
||||||
|
{
|
||||||
|
std::shuffle(this->begin(),this->end(),std::mt19937(1));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename L>
|
||||||
|
struct variant_collection:boost::variant_collection<L>
|
||||||
|
{
|
||||||
|
template<typename F>
|
||||||
|
BOOST_FORCEINLINE void for_each(F f)
|
||||||
|
{
|
||||||
|
std::for_each(this->begin(),this->end(),f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void prepare_for_for_each(){}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename L,typename... T>
|
||||||
|
struct poly_for_each_variant_collection:variant_collection<L>
|
||||||
|
{
|
||||||
|
template<typename F>
|
||||||
|
BOOST_FORCEINLINE void for_each(F f)
|
||||||
{
|
{
|
||||||
boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
|
boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
|
||||||
}
|
}
|
||||||
@@ -344,16 +409,38 @@ struct label
|
|||||||
template<typename... T>
|
template<typename... T>
|
||||||
struct element_sequence{};
|
struct element_sequence{};
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename ElementSequence,
|
||||||
|
typename Container
|
||||||
|
>
|
||||||
|
struct container_fill_helper
|
||||||
|
{
|
||||||
|
Container& c;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
template<typename J>
|
||||||
|
void operator()(J)const
|
||||||
|
{
|
||||||
|
using T=boost::mp11::mp_at_c<ElementSequence,J::value>;
|
||||||
|
c.insert(T(i));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename... Element,
|
typename... Element,
|
||||||
typename Container
|
typename Container
|
||||||
>
|
>
|
||||||
void container_fill(unsigned int n,element_sequence<Element...>,Container& c)
|
void container_fill(unsigned int n,element_sequence<Element...>,Container& c)
|
||||||
{
|
{
|
||||||
auto m=n/sizeof...(Element);
|
pause_timing();
|
||||||
for(unsigned int i=0;i!=m;++i){
|
std::mt19937 rng{1};
|
||||||
using seq=int[sizeof...(Element)];
|
std::uniform_int_distribution<> d(0,sizeof...(Element)-1);
|
||||||
(void)seq{(c.insert(Element(i)),0)...};
|
resume_timing();
|
||||||
|
|
||||||
|
for(unsigned int i=0;i!=n;++i){
|
||||||
|
boost::mp11::mp_with_index<sizeof...(Element)>(
|
||||||
|
d(rng),
|
||||||
|
container_fill_helper<element_sequence<Element...>,Container>{c,i});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,9 +491,7 @@ void insert_perf(
|
|||||||
for(unsigned int s=0,n=n0;
|
for(unsigned int s=0,n=n0;
|
||||||
(n=(unsigned int)std::round(n0*std::pow(10.0,s/1000.0)))<=n1;
|
(n=(unsigned int)std::round(n0*std::pow(10.0,s/1000.0)))<=n1;
|
||||||
s+=dsav){
|
s+=dsav){
|
||||||
unsigned int m=(unsigned int)std::round(n/sizeof...(Element)),
|
print(n,insert_perf(n,elements,labels)...);
|
||||||
nn=m*sizeof...(Element);
|
|
||||||
print(nn,insert_perf(nn,elements,labels)...);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,9 +535,7 @@ void for_each_perf(
|
|||||||
for(unsigned int s=0,n=n0;
|
for(unsigned int s=0,n=n0;
|
||||||
(n=(unsigned int)std::round(n0*std::pow(10.0,s/1000.0)))<=n1;
|
(n=(unsigned int)std::round(n0*std::pow(10.0,s/1000.0)))<=n1;
|
||||||
s+=dsav){
|
s+=dsav){
|
||||||
unsigned int m=(unsigned int)std::round(n/sizeof...(Element)),
|
print(n,for_each_perf(n,elements,f,labels)...);
|
||||||
nn=m*sizeof...(Element);
|
|
||||||
print(nn,for_each_perf(nn,elements,f,labels)...);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,7 +568,27 @@ struct for_each_incrementable
|
|||||||
};
|
};
|
||||||
//]
|
//]
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
//[perf_for_each_alternative
|
||||||
|
struct for_each_alternative
|
||||||
|
{
|
||||||
|
for_each_alternative():res{0}{}
|
||||||
|
|
||||||
|
template<template<typename...> class V,typename... Ts>
|
||||||
|
void operator()(V<Ts...>& x){
|
||||||
|
visit(*this,x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void operator()(T& x){
|
||||||
|
++x;
|
||||||
|
++res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res;
|
||||||
|
};
|
||||||
|
//]
|
||||||
|
|
||||||
|
int main(int argc,char *argv[])
|
||||||
{
|
{
|
||||||
using test=std::pair<std::string,bool&>;
|
using test=std::pair<std::string,bool&>;
|
||||||
|
|
||||||
@@ -495,15 +598,19 @@ int main(int argc, char *argv[])
|
|||||||
insert_function=false,
|
insert_function=false,
|
||||||
for_each_function=false,
|
for_each_function=false,
|
||||||
insert_any=false,
|
insert_any=false,
|
||||||
for_each_any=false;
|
for_each_any=false,
|
||||||
std::array<test,7> tests={{
|
insert_variant=false,
|
||||||
|
for_each_variant=false;
|
||||||
|
std::array<test,9> tests={{
|
||||||
{"all",all},
|
{"all",all},
|
||||||
{"insert_base",insert_base},
|
{"insert_base",insert_base},
|
||||||
{"for_each_base",for_each_base},
|
{"for_each_base",for_each_base},
|
||||||
{"insert_function",insert_function},
|
{"insert_function",insert_function},
|
||||||
{"for_each_function",for_each_function},
|
{"for_each_function",for_each_function},
|
||||||
{"insert_any",insert_any},
|
{"insert_any",insert_any},
|
||||||
{"for_each_any",for_each_any}
|
{"for_each_any",for_each_any},
|
||||||
|
{"insert_variant",insert_variant},
|
||||||
|
{"for_each_variant",for_each_variant}
|
||||||
}};
|
}};
|
||||||
|
|
||||||
if(argc<2){
|
if(argc<2){
|
||||||
@@ -526,8 +633,7 @@ int main(int argc, char *argv[])
|
|||||||
unsigned int n0=100,n1=10000000,dsav=50; /* sav for savart */
|
unsigned int n0=100,n1=10000000,dsav=50; /* sav for savart */
|
||||||
|
|
||||||
{
|
{
|
||||||
auto seq= element_sequence<
|
auto seq= element_sequence<derived1,derived2,derived3>{};
|
||||||
derived1,derived1,derived2,derived2,derived3>{};
|
|
||||||
auto f= for_each_callable{};
|
auto f= for_each_callable{};
|
||||||
auto pv= label<ptr_vector<base>>
|
auto pv= label<ptr_vector<base>>
|
||||||
{"ptr_vector"};
|
{"ptr_vector"};
|
||||||
@@ -540,7 +646,7 @@ int main(int argc, char *argv[])
|
|||||||
auto fbc= label<poly_for_each_base_collection<base>>
|
auto fbc= label<poly_for_each_base_collection<base>>
|
||||||
{"base_collection (poly::for_each)"};
|
{"base_collection (poly::for_each)"};
|
||||||
auto rfbc= label<
|
auto rfbc= label<
|
||||||
poly_for_each_base_collection<base,derived1,derived2,derived2>
|
poly_for_each_base_collection<base,derived1,derived2,derived3>
|
||||||
>
|
>
|
||||||
{"base_collection (restituted poly::for_each)"};
|
{"base_collection (restituted poly::for_each)"};
|
||||||
|
|
||||||
@@ -551,8 +657,7 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
using signature=int(int);
|
using signature=int(int);
|
||||||
|
|
||||||
auto seq= element_sequence<
|
auto seq= element_sequence<concrete1,concrete2,concrete3>{};
|
||||||
concrete1,concrete1,concrete2,concrete2,concrete3>{};
|
|
||||||
auto f = for_each_callable{};
|
auto f = for_each_callable{};
|
||||||
auto fv= label<func_vector<signature>>
|
auto fv= label<func_vector<signature>>
|
||||||
{"func_vector"};
|
{"func_vector"};
|
||||||
@@ -582,7 +687,7 @@ int main(int argc, char *argv[])
|
|||||||
>;
|
>;
|
||||||
//]
|
//]
|
||||||
|
|
||||||
auto seq= element_sequence<int,int,double,double,char>{};
|
auto seq= element_sequence<int,double,char>{};
|
||||||
auto f= for_each_incrementable{};
|
auto f= for_each_incrementable{};
|
||||||
auto av= label<any_vector<concept_>>
|
auto av= label<any_vector<concept_>>
|
||||||
{"any_vector"};
|
{"any_vector"};
|
||||||
@@ -601,4 +706,30 @@ int main(int argc, char *argv[])
|
|||||||
if(all||for_each_any)for_each_perf(
|
if(all||for_each_any)for_each_perf(
|
||||||
n0,n1,dsav,seq,f,av,sav,shav,ac,fac,rfac);
|
n0,n1,dsav,seq,f,av,sav,shav,ac,fac,rfac);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
//[perf_variant_types
|
||||||
|
using type_list=boost::mp11::mp_list<int,double,char>;
|
||||||
|
//]
|
||||||
|
|
||||||
|
auto seq= element_sequence<int,double,char>{};
|
||||||
|
auto f= for_each_alternative{};
|
||||||
|
auto vv= label<variant_vector<type_list>>
|
||||||
|
{"variant_vector"};
|
||||||
|
auto svv= label<sorted_variant_vector<type_list>>
|
||||||
|
{"sorted variant_vector"};
|
||||||
|
auto shvv= label<shuffled_variant_vector<type_list>>
|
||||||
|
{"shuffled variant_vector"};
|
||||||
|
auto vc= label<variant_collection<type_list>>
|
||||||
|
{"variant_collection"};
|
||||||
|
auto fvc= label<poly_for_each_variant_collection<type_list>>
|
||||||
|
{"variant_collection (poly::for_each)"};
|
||||||
|
auto rfvc= label<
|
||||||
|
poly_for_each_variant_collection<
|
||||||
|
type_list,boost::poly_collection::all_types>>
|
||||||
|
{"variant_collection (restituted poly::for_each)"};
|
||||||
|
|
||||||
|
if(all||insert_variant)insert_perf(n0,n1,dsav,seq,vv,vc);
|
||||||
|
if(all||for_each_variant)for_each_perf(
|
||||||
|
n0,n1,dsav,seq,f,vv,svv,shvv,vc,fvc,rfvc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2017 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <boost/poly_collection/any_collection.hpp>
|
#include <boost/poly_collection/any_collection.hpp>
|
||||||
#include <boost/poly_collection/base_collection.hpp>
|
#include <boost/poly_collection/base_collection.hpp>
|
||||||
|
#include <boost/poly_collection/variant_collection.hpp>
|
||||||
#include <boost/type_erasure/operators.hpp>
|
#include <boost/type_erasure/operators.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <random>
|
#include <random>
|
||||||
@@ -104,6 +105,22 @@ int main()
|
|||||||
//]
|
//]
|
||||||
|
|
||||||
//[segmented_structure_6
|
//[segmented_structure_6
|
||||||
|
boost::variant_collection<
|
||||||
|
boost::mp11::mp_list<warrior,juggernaut,goblin,elf,std::string,window>
|
||||||
|
> c3;
|
||||||
|
//= ... // populate c3 some entities
|
||||||
|
//=
|
||||||
|
//<-
|
||||||
|
c3.insert(warrior{0});
|
||||||
|
c3.insert(warrior{1});
|
||||||
|
c3.insert(std::string("game over"));
|
||||||
|
c3.insert(window{"pop-up"});
|
||||||
|
//->
|
||||||
|
std::cout<<c3.size<warrior>()<<"\n"; // same as with other collections
|
||||||
|
std::cout<<c3.size(0)<<"\n"; // list number of warriors (type #0 in the list of types)
|
||||||
|
//]
|
||||||
|
|
||||||
|
//[segmented_structure_7
|
||||||
const char* comma="";
|
const char* comma="";
|
||||||
for(auto first=c.begin(typeid(warrior)),last=c.end(typeid(warrior));
|
for(auto first=c.begin(typeid(warrior)),last=c.end(typeid(warrior));
|
||||||
first!=last;++first){
|
first!=last;++first){
|
||||||
@@ -114,7 +131,7 @@ int main()
|
|||||||
std::cout<<"\n";
|
std::cout<<"\n";
|
||||||
//]
|
//]
|
||||||
|
|
||||||
//[segmented_structure_7
|
//[segmented_structure_8
|
||||||
/*=const char**/ comma="";
|
/*=const char**/ comma="";
|
||||||
for(const auto& x:c.segment(typeid(warrior))){
|
for(const auto& x:c.segment(typeid(warrior))){
|
||||||
std::cout<<comma;
|
std::cout<<comma;
|
||||||
@@ -124,7 +141,7 @@ int main()
|
|||||||
std::cout<<"\n";
|
std::cout<<"\n";
|
||||||
//]
|
//]
|
||||||
|
|
||||||
//[segmented_structure_8
|
//[segmented_structure_9
|
||||||
/*=const char**/ comma="";
|
/*=const char**/ comma="";
|
||||||
for(auto first=c.begin<warrior>(),last=c.end<warrior>();
|
for(auto first=c.begin<warrior>(),last=c.end<warrior>();
|
||||||
first!=last;++first){
|
first!=last;++first){
|
||||||
@@ -150,10 +167,22 @@ int main()
|
|||||||
}
|
}
|
||||||
std::cout<<"\n";
|
std::cout<<"\n";
|
||||||
|
|
||||||
|
//]
|
||||||
|
|
||||||
|
//[segmented_structure_10
|
||||||
|
// traverse all windows in our variant_collection
|
||||||
|
|
||||||
|
for(auto& x:c3.segment<window>()){
|
||||||
|
// visitation not required: we're accessing window directly
|
||||||
|
x.display(std::cout);
|
||||||
|
}
|
||||||
|
//<-
|
||||||
|
std::cout<<"\n";
|
||||||
|
//->
|
||||||
//]
|
//]
|
||||||
|
|
||||||
auto render=[&](){
|
auto render=[&](){
|
||||||
//[segmented_structure_9
|
//[segmented_structure_11
|
||||||
const char* comma="";
|
const char* comma="";
|
||||||
for(auto seg:c.segment_traversal()){
|
for(auto seg:c.segment_traversal()){
|
||||||
for(sprite& s:seg){
|
for(sprite& s:seg){
|
||||||
@@ -167,12 +196,12 @@ int main()
|
|||||||
};
|
};
|
||||||
render();
|
render();
|
||||||
|
|
||||||
//[segmented_structure_10
|
//[segmented_structure_12
|
||||||
c.reserve<goblin>(100); // no reallocation till we exceed 100 goblins
|
c.reserve<goblin>(100); // no reallocation till we exceed 100 goblins
|
||||||
std::cout<<c.capacity<goblin>()<<"\n"; // prints 100
|
std::cout<<c.capacity<goblin>()<<"\n"; // prints 100
|
||||||
//]
|
//]
|
||||||
|
|
||||||
//[segmented_structure_11
|
//[segmented_structure_13
|
||||||
c.reserve(1000); // reserve(1000) for each segment
|
c.reserve(1000); // reserve(1000) for each segment
|
||||||
std::cout<<c.capacity<warrior>()<<", "
|
std::cout<<c.capacity<warrior>()<<", "
|
||||||
<<c.capacity<juggernaut>()<<", "
|
<<c.capacity<juggernaut>()<<", "
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2020 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -14,7 +14,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <boost/config.hpp>
|
||||||
#include <boost/poly_collection/detail/auto_iterator.hpp>
|
#include <boost/poly_collection/detail/auto_iterator.hpp>
|
||||||
|
#include <boost/poly_collection/detail/copyable.hpp>
|
||||||
#include <boost/poly_collection/detail/functional.hpp>
|
#include <boost/poly_collection/detail/functional.hpp>
|
||||||
#include <boost/poly_collection/detail/iterator_traits.hpp>
|
#include <boost/poly_collection/detail/iterator_traits.hpp>
|
||||||
#include <boost/poly_collection/detail/segment_split.hpp>
|
#include <boost/poly_collection/detail/segment_split.hpp>
|
||||||
@@ -37,6 +39,11 @@
|
|||||||
* being a particular example).
|
* being a particular example).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if defined(BOOST_MSVC)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4714) /* marked as __forceinline not inlined */
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace boost{
|
namespace boost{
|
||||||
|
|
||||||
namespace poly_collection{
|
namespace poly_collection{
|
||||||
@@ -56,9 +63,12 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename Predicate,
|
typename... Ts,typename Iterator,typename Predicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
|
BOOST_FORCEINLINE
|
||||||
bool all_of(const Iterator& first,const Iterator& last,Predicate pred)
|
bool all_of(const Iterator& first,const Iterator& last,Predicate pred)
|
||||||
{
|
{
|
||||||
auto alg=restitute_range<Ts...>(std_all_of{},pred);
|
using model_type=typename iterator_traits<Iterator>::model_type;
|
||||||
|
|
||||||
|
auto alg=restitute_range<model_type,Ts...>(std_all_of{},pred);
|
||||||
for(auto i:detail::segment_split(first,last))if(!alg(i))return false;
|
for(auto i:detail::segment_split(first,last))if(!alg(i))return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -69,9 +79,12 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename Predicate,
|
typename... Ts,typename Iterator,typename Predicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
bool any_of(const Iterator& first,const Iterator& last,Predicate pred)
|
BOOST_FORCEINLINE bool any_of(
|
||||||
|
const Iterator& first,const Iterator& last,Predicate pred)
|
||||||
{
|
{
|
||||||
auto alg=restitute_range<Ts...>(std_any_of{},pred);
|
using model_type=typename iterator_traits<Iterator>::model_type;
|
||||||
|
|
||||||
|
auto alg=restitute_range<model_type,Ts...>(std_any_of{},pred);
|
||||||
for(auto i:detail::segment_split(first,last))if(alg(i))return true;
|
for(auto i:detail::segment_split(first,last))if(alg(i))return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -82,9 +95,12 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename Predicate,
|
typename... Ts,typename Iterator,typename Predicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
bool none_of(const Iterator& first,const Iterator& last,Predicate pred)
|
BOOST_FORCEINLINE bool none_of(
|
||||||
|
const Iterator& first,const Iterator& last,Predicate pred)
|
||||||
{
|
{
|
||||||
auto alg=restitute_range<Ts...>(std_none_of{},pred);
|
using model_type=typename iterator_traits<Iterator>::model_type;
|
||||||
|
|
||||||
|
auto alg=restitute_range<model_type,Ts...>(std_none_of{},pred);
|
||||||
for(auto i:detail::segment_split(first,last))if(!alg(i))return false;
|
for(auto i:detail::segment_split(first,last))if(!alg(i))return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -99,13 +115,16 @@ struct for_each_alg
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<
|
template<typename... Ts,typename Iterator,typename Function,
|
||||||
typename... Ts,typename Iterator,typename Function,
|
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Function for_each(const Iterator& first,const Iterator& last,Function f)
|
BOOST_FORCEINLINE Function for_each(
|
||||||
|
const Iterator& first,const Iterator& last,Function f)
|
||||||
{
|
{
|
||||||
for_each_segment(first,last,restitute_range<Ts...>(for_each_alg{},f));
|
using model_type=typename iterator_traits<Iterator>::model_type;
|
||||||
|
|
||||||
|
for_each_segment(
|
||||||
|
first,last,restitute_range<model_type,Ts...>(for_each_alg{},f));
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,19 +145,20 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename Size,typename Function,
|
typename... Ts,typename Iterator,typename Size,typename Function,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator for_each_n(const Iterator& first,Size n,Function f)
|
BOOST_FORCEINLINE Iterator for_each_n(const Iterator& first,Size n,Function f)
|
||||||
{
|
{
|
||||||
using traits=iterator_traits<Iterator>;
|
using traits=iterator_traits<Iterator>;
|
||||||
|
using model_type=typename traits::model_type;
|
||||||
using local_base_iterator=typename traits::local_base_iterator;
|
using local_base_iterator=typename traits::local_base_iterator;
|
||||||
|
|
||||||
if(n<=0)return first;
|
if(n<=0)return first;
|
||||||
|
|
||||||
auto alg=restitute_iterator<Ts...>(
|
auto alg=restitute_iterator<model_type,Ts...>(
|
||||||
cast_return<local_base_iterator>(for_each_n_alg{}));
|
cast_return<local_base_iterator>(for_each_n_alg{}));
|
||||||
auto lbit=traits::local_base_iterator_from(first);
|
auto lbit=traits::local_base_iterator_from(first);
|
||||||
auto sit=traits::base_segment_info_iterator_from(first);
|
auto sit=traits::base_segment_info_iterator_from(first);
|
||||||
for(;;){
|
for(;;){
|
||||||
auto m=sit->end()-lbit;
|
Size m=static_cast<Size>(sit->end()-lbit);
|
||||||
if(n<=m){
|
if(n<=m){
|
||||||
auto it=alg(sit->type_info(),lbit,n,f);
|
auto it=alg(sit->type_info(),lbit,n,f);
|
||||||
return traits::iterator_from(
|
return traits::iterator_from(
|
||||||
@@ -158,13 +178,14 @@ template<
|
|||||||
typename Iterator,typename... Args,
|
typename Iterator,typename... Args,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator generic_find(
|
BOOST_FORCEINLINE Iterator generic_find(
|
||||||
const Iterator& first,const Iterator& last,Args&&... args)
|
const Iterator& first,const Iterator& last,Args&&... args)
|
||||||
{
|
{
|
||||||
using traits=iterator_traits<Iterator>;
|
using traits=iterator_traits<Iterator>;
|
||||||
|
using model_type=typename traits::model_type;
|
||||||
using local_base_iterator=typename traits::local_base_iterator;
|
using local_base_iterator=typename traits::local_base_iterator;
|
||||||
|
|
||||||
auto alg=restitute_range<Ts...>(
|
auto alg=restitute_range<model_type,Ts...>(
|
||||||
cast_return<local_base_iterator>(Algorithm{}),
|
cast_return<local_base_iterator>(Algorithm{}),
|
||||||
std::forward<Args>(args)...);
|
std::forward<Args>(args)...);
|
||||||
for(auto i:detail::segment_split(first,last)){
|
for(auto i:detail::segment_split(first,last)){
|
||||||
@@ -182,7 +203,8 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename T,
|
typename... Ts,typename Iterator,typename T,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator find(const Iterator& first,const Iterator& last,const T& x)
|
BOOST_FORCEINLINE Iterator find(
|
||||||
|
const Iterator& first,const Iterator& last,const T& x)
|
||||||
{
|
{
|
||||||
return generic_find<std_find,Ts...>(first,last,x);
|
return generic_find<std_find,Ts...>(first,last,x);
|
||||||
}
|
}
|
||||||
@@ -193,7 +215,8 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename Predicate,
|
typename... Ts,typename Iterator,typename Predicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator find_if(const Iterator& first,const Iterator& last,Predicate pred)
|
BOOST_FORCEINLINE Iterator find_if(
|
||||||
|
const Iterator& first,const Iterator& last,Predicate pred)
|
||||||
{
|
{
|
||||||
return generic_find<std_find_if,Ts...>(first,last,pred);
|
return generic_find<std_find_if,Ts...>(first,last,pred);
|
||||||
}
|
}
|
||||||
@@ -204,7 +227,8 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename Predicate,
|
typename... Ts,typename Iterator,typename Predicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator find_if_not(const Iterator& first,const Iterator& last,Predicate pred)
|
BOOST_FORCEINLINE Iterator find_if_not(
|
||||||
|
const Iterator& first,const Iterator& last,Predicate pred)
|
||||||
{
|
{
|
||||||
return generic_find<std_find_if_not,Ts...>(first,last,pred);
|
return generic_find<std_find_if_not,Ts...>(first,last,pred);
|
||||||
}
|
}
|
||||||
@@ -217,7 +241,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename ForwardIterator,
|
typename... Ts,typename Iterator,typename ForwardIterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator find_first_of(
|
BOOST_FORCEINLINE Iterator find_first_of(
|
||||||
const Iterator& first1,const Iterator& last1,
|
const Iterator& first1,const Iterator& last1,
|
||||||
ForwardIterator first2,ForwardIterator last2)
|
ForwardIterator first2,ForwardIterator last2)
|
||||||
{
|
{
|
||||||
@@ -229,7 +253,7 @@ template<
|
|||||||
typename ForwardIterator,typename BinaryPredicate,
|
typename ForwardIterator,typename BinaryPredicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator find_first_of(
|
BOOST_FORCEINLINE Iterator find_first_of(
|
||||||
const Iterator& first1,const Iterator& last1,
|
const Iterator& first1,const Iterator& last1,
|
||||||
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
||||||
{
|
{
|
||||||
@@ -240,23 +264,27 @@ template<typename... Ts>
|
|||||||
struct adjacent_find_alg
|
struct adjacent_find_alg
|
||||||
{
|
{
|
||||||
template<
|
template<
|
||||||
typename LocalIterator,typename BinaryPredicate,typename LocalBaseIterator
|
typename LocalIterator,typename BinaryPredicate,
|
||||||
|
typename TypeIndex,typename LocalBaseIterator
|
||||||
>
|
>
|
||||||
LocalBaseIterator operator()(
|
LocalBaseIterator operator()(
|
||||||
LocalIterator first,LocalIterator last,BinaryPredicate pred,
|
LocalIterator first,LocalIterator last,BinaryPredicate pred,
|
||||||
bool& carry,const std::type_info* prev_info, /* note the &s */
|
bool& carry,TypeIndex& prev_info, /* note the &s */
|
||||||
LocalBaseIterator& prev)const
|
LocalBaseIterator& prev)const
|
||||||
{
|
{
|
||||||
|
using traits=iterator_traits<LocalIterator>;
|
||||||
|
using model_type=typename traits::model_type;
|
||||||
|
|
||||||
if(first==last)return LocalBaseIterator{last};
|
if(first==last)return LocalBaseIterator{last};
|
||||||
if(carry){
|
if(carry){
|
||||||
auto p=restitute_iterator<Ts...>(deref_to(pred));
|
auto p=restitute_iterator<model_type,Ts...>(deref_to(pred));
|
||||||
if(p(*prev_info,prev,first))return prev;
|
if(p(prev_info,prev,first))return prev;
|
||||||
}
|
}
|
||||||
auto res=std::adjacent_find(first,last,pred);
|
auto res=std::adjacent_find(first,last,pred);
|
||||||
if(res==last){
|
if(res==last){
|
||||||
carry=true;
|
carry=true;
|
||||||
prev_info=&typeid(
|
prev_info=traits::template index<
|
||||||
typename std::iterator_traits<LocalIterator>::value_type);
|
typename std::iterator_traits<LocalIterator>::value_type>();
|
||||||
prev=LocalBaseIterator{last-1};
|
prev=LocalBaseIterator{last-1};
|
||||||
}
|
}
|
||||||
else carry=false;
|
else carry=false;
|
||||||
@@ -268,14 +296,15 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename BinaryPredicate,
|
typename... Ts,typename Iterator,typename BinaryPredicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator adjacent_find(
|
BOOST_FORCEINLINE Iterator adjacent_find(
|
||||||
const Iterator& first,const Iterator& last,BinaryPredicate pred)
|
const Iterator& first,const Iterator& last,BinaryPredicate pred)
|
||||||
{
|
{
|
||||||
using traits=iterator_traits<Iterator>;
|
using traits=iterator_traits<Iterator>;
|
||||||
using local_base_iterator=typename traits::local_base_iterator;
|
using local_base_iterator=typename traits::local_base_iterator;
|
||||||
|
|
||||||
bool carry=false;
|
bool carry=false;
|
||||||
const std::type_info* prev_info{&typeid(void)};
|
auto prev_info=
|
||||||
|
make_copyable(traits::template index<void>());
|
||||||
local_base_iterator prev;
|
local_base_iterator prev;
|
||||||
return generic_find<adjacent_find_alg<Ts...>,Ts...>(
|
return generic_find<adjacent_find_alg<Ts...>,Ts...>(
|
||||||
first,last,pred,carry,prev_info,prev);
|
first,last,pred,carry,prev_info,prev);
|
||||||
@@ -285,7 +314,8 @@ template<
|
|||||||
typename... Ts,typename Iterator,
|
typename... Ts,typename Iterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator adjacent_find(const Iterator& first,const Iterator& last)
|
BOOST_FORCEINLINE Iterator adjacent_find(
|
||||||
|
const Iterator& first,const Iterator& last)
|
||||||
{
|
{
|
||||||
return algorithm::adjacent_find<Ts...>(first,last,transparent_equal_to{});
|
return algorithm::adjacent_find<Ts...>(first,last,transparent_equal_to{});
|
||||||
}
|
}
|
||||||
@@ -295,10 +325,13 @@ template<
|
|||||||
typename Iterator,typename... Args,
|
typename Iterator,typename... Args,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
std::ptrdiff_t generic_count(
|
BOOST_FORCEINLINE std::ptrdiff_t generic_count(
|
||||||
const Iterator& first,const Iterator& last,Args&&... args)
|
const Iterator& first,const Iterator& last,Args&&... args)
|
||||||
{
|
{
|
||||||
auto alg=restitute_range<Ts...>(Algorithm{},std::forward<Args>(args)...);
|
using model_type=typename iterator_traits<Iterator>::model_type;
|
||||||
|
|
||||||
|
auto alg=restitute_range<model_type,Ts...>(
|
||||||
|
Algorithm{},std::forward<Args>(args)...);
|
||||||
std::ptrdiff_t res=0;
|
std::ptrdiff_t res=0;
|
||||||
for(auto i:detail::segment_split(first,last))res+=alg(i);
|
for(auto i:detail::segment_split(first,last))res+=alg(i);
|
||||||
return res;
|
return res;
|
||||||
@@ -310,7 +343,8 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename T,
|
typename... Ts,typename Iterator,typename T,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
std::ptrdiff_t count(const Iterator& first,const Iterator& last,const T& x)
|
BOOST_FORCEINLINE std::ptrdiff_t count(
|
||||||
|
const Iterator& first,const Iterator& last,const T& x)
|
||||||
{
|
{
|
||||||
return generic_count<std_count,Ts...>(first,last,x);
|
return generic_count<std_count,Ts...>(first,last,x);
|
||||||
}
|
}
|
||||||
@@ -321,7 +355,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename Predicate,
|
typename... Ts,typename Iterator,typename Predicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
std::ptrdiff_t count_if(
|
BOOST_FORCEINLINE std::ptrdiff_t count_if(
|
||||||
const Iterator& first,const Iterator& last,Predicate pred)
|
const Iterator& first,const Iterator& last,Predicate pred)
|
||||||
{
|
{
|
||||||
return generic_count<std_count_if,Ts...>(first,last,pred);
|
return generic_count<std_count_if,Ts...>(first,last,pred);
|
||||||
@@ -366,7 +400,7 @@ template<
|
|||||||
typename InputIterator,typename BinaryPredicate,
|
typename InputIterator,typename BinaryPredicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
std::pair<Iterator,InputIterator> mismatch(
|
BOOST_FORCEINLINE std::pair<Iterator,InputIterator> mismatch(
|
||||||
const Iterator& first1,const Iterator& last1,
|
const Iterator& first1,const Iterator& last1,
|
||||||
InputIterator first2,BinaryPredicate pred)
|
InputIterator first2,BinaryPredicate pred)
|
||||||
{
|
{
|
||||||
@@ -378,7 +412,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename InputIterator,
|
typename... Ts,typename Iterator,typename InputIterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
std::pair<Iterator,InputIterator> mismatch(
|
BOOST_FORCEINLINE std::pair<Iterator,InputIterator> mismatch(
|
||||||
const Iterator& first1,const Iterator& last1,InputIterator first2)
|
const Iterator& first1,const Iterator& last1,InputIterator first2)
|
||||||
{
|
{
|
||||||
return algorithm::mismatch<Ts...>(
|
return algorithm::mismatch<Ts...>(
|
||||||
@@ -390,7 +424,7 @@ template<
|
|||||||
typename InputIterator,typename BinaryPredicate,
|
typename InputIterator,typename BinaryPredicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
std::pair<Iterator,InputIterator> mismatch(
|
BOOST_FORCEINLINE std::pair<Iterator,InputIterator> mismatch(
|
||||||
const Iterator& first1,const Iterator& last1,
|
const Iterator& first1,const Iterator& last1,
|
||||||
InputIterator first2,InputIterator last2,BinaryPredicate pred)
|
InputIterator first2,InputIterator last2,BinaryPredicate pred)
|
||||||
{
|
{
|
||||||
@@ -402,7 +436,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename InputIterator,
|
typename... Ts,typename Iterator,typename InputIterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
std::pair<Iterator,InputIterator> mismatch(
|
BOOST_FORCEINLINE std::pair<Iterator,InputIterator> mismatch(
|
||||||
const Iterator& first1,const Iterator& last1,
|
const Iterator& first1,const Iterator& last1,
|
||||||
InputIterator first2,InputIterator last2)
|
InputIterator first2,InputIterator last2)
|
||||||
{
|
{
|
||||||
@@ -447,11 +481,13 @@ template<
|
|||||||
typename InputIterator,typename BinaryPredicate,
|
typename InputIterator,typename BinaryPredicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
bool equal(
|
BOOST_FORCEINLINE bool equal(
|
||||||
const Iterator& first1,const Iterator& last1,
|
const Iterator& first1,const Iterator& last1,
|
||||||
InputIterator first2,BinaryPredicate pred)
|
InputIterator first2,BinaryPredicate pred)
|
||||||
{
|
{
|
||||||
auto alg=restitute_range<Ts...>(equal_alg{},first2,pred);
|
using model_type=typename iterator_traits<Iterator>::model_type;
|
||||||
|
|
||||||
|
auto alg=restitute_range<model_type,Ts...>(equal_alg{},first2,pred);
|
||||||
for(auto i:detail::segment_split(first1,last1))if(!alg(i))return false;
|
for(auto i:detail::segment_split(first1,last1))if(!alg(i))return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -460,7 +496,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename InputIterator,
|
typename... Ts,typename Iterator,typename InputIterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
bool equal(
|
BOOST_FORCEINLINE bool equal(
|
||||||
const Iterator& first1,const Iterator& last1,InputIterator first2)
|
const Iterator& first1,const Iterator& last1,InputIterator first2)
|
||||||
{
|
{
|
||||||
return algorithm::equal<Ts...>(first1,last1,first2,transparent_equal_to{});
|
return algorithm::equal<Ts...>(first1,last1,first2,transparent_equal_to{});
|
||||||
@@ -471,11 +507,13 @@ template<
|
|||||||
typename InputIterator,typename BinaryPredicate,
|
typename InputIterator,typename BinaryPredicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
bool equal(
|
BOOST_FORCEINLINE bool equal(
|
||||||
const Iterator& first1,const Iterator& last1,
|
const Iterator& first1,const Iterator& last1,
|
||||||
InputIterator first2,InputIterator last2,BinaryPredicate pred)
|
InputIterator first2,InputIterator last2,BinaryPredicate pred)
|
||||||
{
|
{
|
||||||
auto alg=restitute_range<Ts...>(equal_alg{},first2,last2,pred);
|
using model_type=typename iterator_traits<Iterator>::model_type;
|
||||||
|
|
||||||
|
auto alg=restitute_range<model_type,Ts...>(equal_alg{},first2,last2,pred);
|
||||||
for(auto i:detail::segment_split(first1,last1))if(!alg(i))return false;
|
for(auto i:detail::segment_split(first1,last1))if(!alg(i))return false;
|
||||||
return first2==last2;
|
return first2==last2;
|
||||||
}
|
}
|
||||||
@@ -484,7 +522,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename InputIterator,
|
typename... Ts,typename Iterator,typename InputIterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
bool equal(
|
BOOST_FORCEINLINE bool equal(
|
||||||
const Iterator& first1,const Iterator& last1,
|
const Iterator& first1,const Iterator& last1,
|
||||||
InputIterator first2,InputIterator last2)
|
InputIterator first2,InputIterator last2)
|
||||||
{
|
{
|
||||||
@@ -496,7 +534,8 @@ template<
|
|||||||
typename Iterator,
|
typename Iterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
std::ptrdiff_t fast_distance(const Iterator& first,const Iterator& last)
|
BOOST_FORCEINLINE std::ptrdiff_t fast_distance(
|
||||||
|
const Iterator& first,const Iterator& last)
|
||||||
{
|
{
|
||||||
using traits=iterator_traits<Iterator>;
|
using traits=iterator_traits<Iterator>;
|
||||||
|
|
||||||
@@ -526,18 +565,19 @@ template<
|
|||||||
typename ForwardIterator,typename BinaryPredicate,
|
typename ForwardIterator,typename BinaryPredicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
bool is_permutation_suffix(
|
BOOST_FORCEINLINE bool is_permutation_suffix(
|
||||||
const Iterator& first1,const Iterator& last1,
|
const Iterator& first1,const Iterator& last1,
|
||||||
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
||||||
{
|
{
|
||||||
using traits=iterator_traits<Iterator>;
|
using traits=iterator_traits<Iterator>;
|
||||||
|
using model_type=typename traits::model_type;
|
||||||
|
|
||||||
auto send=traits::end_base_segment_info_iterator_from(last1);
|
auto send=traits::end_base_segment_info_iterator_from(last1);
|
||||||
for(auto i:detail::segment_split(first1,last1)){
|
for(auto i:detail::segment_split(first1,last1)){
|
||||||
for(auto lbscan=i.begin();lbscan!=i.end();++lbscan){
|
for(auto lbscan=i.begin();lbscan!=i.end();++lbscan){
|
||||||
auto& info=i.type_info();
|
auto& info=i.type_info();
|
||||||
auto p=head_closure(
|
auto p=head_closure(
|
||||||
restitute_iterator<Ts...>(deref_1st_to(pred)),info,lbscan);
|
restitute_iterator<model_type,Ts...>(deref_1st_to(pred)),info,lbscan);
|
||||||
auto scan=traits::iterator_from(lbscan,send);
|
auto scan=traits::iterator_from(lbscan,send);
|
||||||
if(algorithm::find_if<Ts...>(first1,scan,p)!=scan)continue;
|
if(algorithm::find_if<Ts...>(first1,scan,p)!=scan)continue;
|
||||||
std::ptrdiff_t matches=std::count_if(first2,last2,p);
|
std::ptrdiff_t matches=std::count_if(first2,last2,p);
|
||||||
@@ -553,7 +593,7 @@ template<
|
|||||||
typename ForwardIterator,typename BinaryPredicate,
|
typename ForwardIterator,typename BinaryPredicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
bool is_permutation(
|
BOOST_FORCEINLINE bool is_permutation(
|
||||||
Iterator first1,Iterator last1,ForwardIterator first2,BinaryPredicate pred)
|
Iterator first1,Iterator last1,ForwardIterator first2,BinaryPredicate pred)
|
||||||
{
|
{
|
||||||
std::tie(first1,first2)=algorithm::mismatch<Ts...>(first1,last1,first2,pred);
|
std::tie(first1,first2)=algorithm::mismatch<Ts...>(first1,last1,first2,pred);
|
||||||
@@ -565,7 +605,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename ForwardIterator,
|
typename... Ts,typename Iterator,typename ForwardIterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
bool is_permutation(
|
BOOST_FORCEINLINE bool is_permutation(
|
||||||
const Iterator& first1,const Iterator& last1,ForwardIterator first2)
|
const Iterator& first1,const Iterator& last1,ForwardIterator first2)
|
||||||
{
|
{
|
||||||
return algorithm::is_permutation<Ts...>(
|
return algorithm::is_permutation<Ts...>(
|
||||||
@@ -577,7 +617,7 @@ template<
|
|||||||
typename ForwardIterator,typename BinaryPredicate,
|
typename ForwardIterator,typename BinaryPredicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
bool is_permutation(
|
BOOST_FORCEINLINE bool is_permutation(
|
||||||
Iterator first1,Iterator last1,
|
Iterator first1,Iterator last1,
|
||||||
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
||||||
{
|
{
|
||||||
@@ -592,7 +632,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename ForwardIterator,
|
typename... Ts,typename Iterator,typename ForwardIterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
bool is_permutation(
|
BOOST_FORCEINLINE bool is_permutation(
|
||||||
const Iterator& first1,const Iterator& last1,
|
const Iterator& first1,const Iterator& last1,
|
||||||
ForwardIterator first2,ForwardIterator last2)
|
ForwardIterator first2,ForwardIterator last2)
|
||||||
{
|
{
|
||||||
@@ -605,7 +645,7 @@ template<
|
|||||||
typename ForwardIterator,typename BinaryPredicate,
|
typename ForwardIterator,typename BinaryPredicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator search(
|
BOOST_FORCEINLINE Iterator search(
|
||||||
const Iterator& first1,const Iterator& last1,
|
const Iterator& first1,const Iterator& last1,
|
||||||
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
||||||
{
|
{
|
||||||
@@ -626,7 +666,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename ForwardIterator,
|
typename... Ts,typename Iterator,typename ForwardIterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator search(
|
BOOST_FORCEINLINE Iterator search(
|
||||||
const Iterator& first1,const Iterator& last1,
|
const Iterator& first1,const Iterator& last1,
|
||||||
ForwardIterator first2,ForwardIterator last2)
|
ForwardIterator first2,ForwardIterator last2)
|
||||||
{
|
{
|
||||||
@@ -639,7 +679,7 @@ template<
|
|||||||
typename ForwardIterator,typename BinaryPredicate,
|
typename ForwardIterator,typename BinaryPredicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator find_end(
|
BOOST_FORCEINLINE Iterator find_end(
|
||||||
Iterator first1,Iterator last1,
|
Iterator first1,Iterator last1,
|
||||||
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
||||||
{
|
{
|
||||||
@@ -659,7 +699,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename ForwardIterator,
|
typename... Ts,typename Iterator,typename ForwardIterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator find_end(
|
BOOST_FORCEINLINE Iterator find_end(
|
||||||
const Iterator& first1,const Iterator& last1,
|
const Iterator& first1,const Iterator& last1,
|
||||||
ForwardIterator first2,ForwardIterator last2)
|
ForwardIterator first2,ForwardIterator last2)
|
||||||
{
|
{
|
||||||
@@ -695,18 +735,19 @@ template<
|
|||||||
typename Size,typename T,typename BinaryPredicate,
|
typename Size,typename T,typename BinaryPredicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator search_n(
|
BOOST_FORCEINLINE Iterator search_n(
|
||||||
const Iterator& first,const Iterator& last,
|
const Iterator& first,const Iterator& last,
|
||||||
Size count,const T& x,BinaryPredicate pred)
|
Size count,const T& x,BinaryPredicate pred)
|
||||||
{
|
{
|
||||||
using traits=iterator_traits<Iterator>;
|
using traits=iterator_traits<Iterator>;
|
||||||
|
using model_type=typename traits::model_type;
|
||||||
using local_base_iterator=typename traits::local_base_iterator;
|
using local_base_iterator=typename traits::local_base_iterator;
|
||||||
|
|
||||||
if(count<=0)return first;
|
if(count<=0)return first;
|
||||||
|
|
||||||
bool carry=false;
|
bool carry=false;
|
||||||
auto remain=count;
|
auto remain=count;
|
||||||
auto alg=restitute_range<Ts...>(
|
auto alg=restitute_range<model_type,Ts...>(
|
||||||
cast_return<local_base_iterator>(search_n_alg{}),
|
cast_return<local_base_iterator>(search_n_alg{}),
|
||||||
count,carry,remain,x,pred);
|
count,carry,remain,x,pred);
|
||||||
local_base_iterator prev;
|
local_base_iterator prev;
|
||||||
@@ -728,7 +769,7 @@ template<
|
|||||||
typename Size,typename T,
|
typename Size,typename T,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator search_n(
|
BOOST_FORCEINLINE Iterator search_n(
|
||||||
const Iterator& first,const Iterator& last,Size count,const T& x)
|
const Iterator& first,const Iterator& last,Size count,const T& x)
|
||||||
{
|
{
|
||||||
return algorithm::search_n<Ts...>(
|
return algorithm::search_n<Ts...>(
|
||||||
@@ -740,11 +781,13 @@ template<
|
|||||||
typename Iterator,typename OutputIterator,typename... Args,
|
typename Iterator,typename OutputIterator,typename... Args,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator generic_copy(
|
BOOST_FORCEINLINE OutputIterator generic_copy(
|
||||||
const Iterator& first,const Iterator& last,OutputIterator res,Args&&... args)
|
const Iterator& first,const Iterator& last,OutputIterator res,Args&&... args)
|
||||||
{
|
{
|
||||||
|
using model_type=typename iterator_traits<Iterator>::model_type;
|
||||||
|
|
||||||
for(auto i:detail::segment_split(first,last)){
|
for(auto i:detail::segment_split(first,last)){
|
||||||
auto alg=restitute_range<Ts...>(
|
auto alg=restitute_range<model_type,Ts...>(
|
||||||
Algorithm{},res,std::forward<Args>(args)...);
|
Algorithm{},res,std::forward<Args>(args)...);
|
||||||
res=alg(i);
|
res=alg(i);
|
||||||
}
|
}
|
||||||
@@ -757,7 +800,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename OutputIterator,
|
typename... Ts,typename Iterator,typename OutputIterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator copy(
|
BOOST_FORCEINLINE OutputIterator copy(
|
||||||
const Iterator& first,const Iterator& last,OutputIterator res)
|
const Iterator& first,const Iterator& last,OutputIterator res)
|
||||||
{
|
{
|
||||||
return generic_copy<std_copy,Ts...>(first,last,res);
|
return generic_copy<std_copy,Ts...>(first,last,res);
|
||||||
@@ -769,17 +812,19 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename Size,typename OutputIterator,
|
typename... Ts,typename Iterator,typename Size,typename OutputIterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator copy_n(const Iterator& first,Size count,OutputIterator res)
|
BOOST_FORCEINLINE OutputIterator copy_n(
|
||||||
|
const Iterator& first,Size count,OutputIterator res)
|
||||||
{
|
{
|
||||||
using traits=iterator_traits<Iterator>;
|
using traits=iterator_traits<Iterator>;
|
||||||
|
using model_type=typename traits::model_type;
|
||||||
|
|
||||||
if(count<=0)return res;
|
if(count<=0)return res;
|
||||||
|
|
||||||
auto lbit=traits::local_base_iterator_from(first);
|
auto lbit=traits::local_base_iterator_from(first);
|
||||||
auto sit=traits::base_segment_info_iterator_from(first);
|
auto sit=traits::base_segment_info_iterator_from(first);
|
||||||
for(;;){
|
for(;;){
|
||||||
auto n=(std::min)(count,sit->end()-lbit);
|
auto n=(std::min)(count,static_cast<Size>(sit->end()-lbit));
|
||||||
auto alg=restitute_iterator<Ts...>(std_copy_n{},n,res);
|
auto alg=restitute_iterator<model_type,Ts...>(std_copy_n{},n,res);
|
||||||
res=alg(sit->type_info(),lbit);
|
res=alg(sit->type_info(),lbit);
|
||||||
if((count-=n)==0)break;
|
if((count-=n)==0)break;
|
||||||
++sit;
|
++sit;
|
||||||
@@ -794,7 +839,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename OutputIterator,typename Predicate,
|
typename... Ts,typename Iterator,typename OutputIterator,typename Predicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator copy_if(
|
BOOST_FORCEINLINE OutputIterator copy_if(
|
||||||
const Iterator& first,const Iterator& last,OutputIterator res,Predicate pred)
|
const Iterator& first,const Iterator& last,OutputIterator res,Predicate pred)
|
||||||
{
|
{
|
||||||
return generic_copy<std_copy_if,Ts...>(first,last,res,pred);
|
return generic_copy<std_copy_if,Ts...>(first,last,res,pred);
|
||||||
@@ -806,7 +851,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename OutputIterator,
|
typename... Ts,typename Iterator,typename OutputIterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator move(
|
BOOST_FORCEINLINE OutputIterator move(
|
||||||
const Iterator& first,const Iterator& last,OutputIterator res)
|
const Iterator& first,const Iterator& last,OutputIterator res)
|
||||||
{
|
{
|
||||||
return generic_copy<std_move,Ts...>(first,last,res);
|
return generic_copy<std_move,Ts...>(first,last,res);
|
||||||
@@ -819,7 +864,7 @@ template<
|
|||||||
typename OutputIterator,typename UnaryOperation,
|
typename OutputIterator,typename UnaryOperation,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator transform(
|
BOOST_FORCEINLINE OutputIterator transform(
|
||||||
const Iterator& first,const Iterator& last,
|
const Iterator& first,const Iterator& last,
|
||||||
OutputIterator res,UnaryOperation op)
|
OutputIterator res,UnaryOperation op)
|
||||||
{
|
{
|
||||||
@@ -847,7 +892,7 @@ template<
|
|||||||
typename OutputIterator,typename BinaryOperation,
|
typename OutputIterator,typename BinaryOperation,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator transform(
|
BOOST_FORCEINLINE OutputIterator transform(
|
||||||
const Iterator& first1,const Iterator& last1,InputIterator first2,
|
const Iterator& first1,const Iterator& last1,InputIterator first2,
|
||||||
OutputIterator res,BinaryOperation op)
|
OutputIterator res,BinaryOperation op)
|
||||||
{
|
{
|
||||||
@@ -878,7 +923,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename OutputIterator,typename T,
|
typename... Ts,typename Iterator,typename OutputIterator,typename T,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator replace_copy(
|
BOOST_FORCEINLINE OutputIterator replace_copy(
|
||||||
const Iterator& first,const Iterator& last,OutputIterator res,
|
const Iterator& first,const Iterator& last,OutputIterator res,
|
||||||
const T& old_x,const T& new_x)
|
const T& old_x,const T& new_x)
|
||||||
{
|
{
|
||||||
@@ -913,7 +958,7 @@ template<
|
|||||||
typename Predicate,typename T,
|
typename Predicate,typename T,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator replace_copy_if(
|
BOOST_FORCEINLINE OutputIterator replace_copy_if(
|
||||||
const Iterator& first,const Iterator& last,OutputIterator res,
|
const Iterator& first,const Iterator& last,OutputIterator res,
|
||||||
Predicate pred,const T& new_x)
|
Predicate pred,const T& new_x)
|
||||||
{
|
{
|
||||||
@@ -926,7 +971,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename OutputIterator,typename T,
|
typename... Ts,typename Iterator,typename OutputIterator,typename T,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator remove_copy(
|
BOOST_FORCEINLINE OutputIterator remove_copy(
|
||||||
const Iterator& first,const Iterator& last,OutputIterator res,const T& x)
|
const Iterator& first,const Iterator& last,OutputIterator res,const T& x)
|
||||||
{
|
{
|
||||||
return generic_copy<std_remove_copy,Ts...>(first,last,res,x);
|
return generic_copy<std_remove_copy,Ts...>(first,last,res,x);
|
||||||
@@ -939,7 +984,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename OutputIterator,typename Predicate,
|
typename... Ts,typename Iterator,typename OutputIterator,typename Predicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator remove_copy_if(
|
BOOST_FORCEINLINE OutputIterator remove_copy_if(
|
||||||
const Iterator& first,const Iterator& last,OutputIterator res,Predicate pred)
|
const Iterator& first,const Iterator& last,OutputIterator res,Predicate pred)
|
||||||
{
|
{
|
||||||
return generic_copy<std_remove_copy_if,Ts...>(first,last,res,pred);
|
return generic_copy<std_remove_copy_if,Ts...>(first,last,res,pred);
|
||||||
@@ -950,23 +995,26 @@ struct unique_copy_alg
|
|||||||
{
|
{
|
||||||
template<
|
template<
|
||||||
typename LocalIterator,typename OutputIterator,
|
typename LocalIterator,typename OutputIterator,
|
||||||
typename BinaryPredicate,typename LocalBaseIterator
|
typename BinaryPredicate,typename TypeIndex,typename LocalBaseIterator
|
||||||
>
|
>
|
||||||
OutputIterator operator()(
|
OutputIterator operator()(
|
||||||
LocalIterator first,LocalIterator last,
|
LocalIterator first,LocalIterator last,
|
||||||
OutputIterator res, BinaryPredicate pred,
|
OutputIterator res, BinaryPredicate pred,
|
||||||
bool& carry,const std::type_info* prev_info, /* note the &s */
|
bool& carry,TypeIndex& prev_info, /* note the &s */
|
||||||
LocalBaseIterator& prev)const
|
LocalBaseIterator& prev)const
|
||||||
{
|
{
|
||||||
|
using traits=iterator_traits<LocalIterator>;
|
||||||
|
using model_type=typename traits::model_type;
|
||||||
|
|
||||||
if(carry){
|
if(carry){
|
||||||
auto p=restitute_iterator<Ts...>(deref_to(pred));
|
auto p=restitute_iterator<model_type,Ts...>(deref_to(pred));
|
||||||
for(;first!=last;++first)if(!p(*prev_info,prev,first))break;
|
for(;first!=last;++first)if(!p(prev_info,prev,first))break;
|
||||||
}
|
}
|
||||||
if(first==last)return res;
|
if(first==last)return res;
|
||||||
res=std::unique_copy(first,last,res,pred);
|
res=std::unique_copy(first,last,res,pred);
|
||||||
carry=true;
|
carry=true;
|
||||||
prev_info=&typeid(
|
prev_info=traits::template index<
|
||||||
typename std::iterator_traits<LocalIterator>::value_type);
|
typename std::iterator_traits<LocalIterator>::value_type>();
|
||||||
prev=LocalBaseIterator{last-1};
|
prev=LocalBaseIterator{last-1};
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -977,7 +1025,7 @@ template<
|
|||||||
typename OutputIterator,typename BinaryPredicate,
|
typename OutputIterator,typename BinaryPredicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator unique_copy(
|
BOOST_FORCEINLINE OutputIterator unique_copy(
|
||||||
const Iterator& first,const Iterator& last,
|
const Iterator& first,const Iterator& last,
|
||||||
OutputIterator res,BinaryPredicate pred)
|
OutputIterator res,BinaryPredicate pred)
|
||||||
{
|
{
|
||||||
@@ -985,7 +1033,8 @@ OutputIterator unique_copy(
|
|||||||
using local_base_iterator=typename traits::local_base_iterator;
|
using local_base_iterator=typename traits::local_base_iterator;
|
||||||
|
|
||||||
bool carry=false;
|
bool carry=false;
|
||||||
const std::type_info* prev_info{&typeid(void)};
|
auto prev_info=
|
||||||
|
make_copyable(traits::template index<void>());
|
||||||
local_base_iterator prev;
|
local_base_iterator prev;
|
||||||
return generic_copy<unique_copy_alg<Ts...>,Ts...>(
|
return generic_copy<unique_copy_alg<Ts...>,Ts...>(
|
||||||
first,last,res,pred,carry,prev_info,prev);
|
first,last,res,pred,carry,prev_info,prev);
|
||||||
@@ -995,7 +1044,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename OutputIterator,
|
typename... Ts,typename Iterator,typename OutputIterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator unique_copy(
|
BOOST_FORCEINLINE OutputIterator unique_copy(
|
||||||
const Iterator& first,const Iterator& last,OutputIterator res)
|
const Iterator& first,const Iterator& last,OutputIterator res)
|
||||||
{
|
{
|
||||||
return algorithm::unique_copy<Ts...>(first,last,res,transparent_equal_to{});
|
return algorithm::unique_copy<Ts...>(first,last,res,transparent_equal_to{});
|
||||||
@@ -1005,7 +1054,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename OutputIterator,
|
typename... Ts,typename Iterator,typename OutputIterator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator rotate_copy(
|
BOOST_FORCEINLINE OutputIterator rotate_copy(
|
||||||
const Iterator& first,const Iterator& middle,const Iterator& last,
|
const Iterator& first,const Iterator& middle,const Iterator& last,
|
||||||
OutputIterator res)
|
OutputIterator res)
|
||||||
{
|
{
|
||||||
@@ -1040,15 +1089,17 @@ template<
|
|||||||
typename Distance,typename UniformRandomBitGenerator,
|
typename Distance,typename UniformRandomBitGenerator,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
OutputIterator sample(
|
BOOST_FORCEINLINE OutputIterator sample(
|
||||||
const Iterator& first,const Iterator& last,
|
const Iterator& first,const Iterator& last,
|
||||||
OutputIterator res,Distance n,UniformRandomBitGenerator&& g)
|
OutputIterator res,Distance n,UniformRandomBitGenerator&& g)
|
||||||
{
|
{
|
||||||
Distance m=algorithm::fast_distance(first,last);
|
using model_type=typename iterator_traits<Iterator>::model_type;
|
||||||
|
|
||||||
|
Distance m=static_cast<Distance>(algorithm::fast_distance(first,last));
|
||||||
n=(std::min)(n,m);
|
n=(std::min)(n,m);
|
||||||
|
|
||||||
for(auto i:detail::segment_split(first,last)){
|
for(auto i:detail::segment_split(first,last)){
|
||||||
auto alg=restitute_range<Ts...>(sample_alg{},res,n,m,g);
|
auto alg=restitute_range<model_type,Ts...>(sample_alg{},res,n,m,g);
|
||||||
res=alg(i);
|
res=alg(i);
|
||||||
if(n==0)return res;
|
if(n==0)return res;
|
||||||
}
|
}
|
||||||
@@ -1059,7 +1110,8 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename Predicate,
|
typename... Ts,typename Iterator,typename Predicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
bool is_partitioned(const Iterator& first,const Iterator& last,Predicate pred)
|
BOOST_FORCEINLINE bool is_partitioned(
|
||||||
|
const Iterator& first,const Iterator& last,Predicate pred)
|
||||||
{
|
{
|
||||||
auto it=algorithm::find_if_not<Ts...>(first,last,pred);
|
auto it=algorithm::find_if_not<Ts...>(first,last,pred);
|
||||||
if(it==last)return true;
|
if(it==last)return true;
|
||||||
@@ -1074,12 +1126,15 @@ template<
|
|||||||
typename OutputIterator1,typename OutputIterator2,typename Predicate,
|
typename OutputIterator1,typename OutputIterator2,typename Predicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
std::pair<OutputIterator1,OutputIterator2> partition_copy(
|
BOOST_FORCEINLINE std::pair<OutputIterator1,OutputIterator2> partition_copy(
|
||||||
const Iterator& first,const Iterator& last,
|
const Iterator& first,const Iterator& last,
|
||||||
OutputIterator1 rest,OutputIterator2 resf,Predicate pred)
|
OutputIterator1 rest,OutputIterator2 resf,Predicate pred)
|
||||||
{
|
{
|
||||||
|
using model_type=typename iterator_traits<Iterator>::model_type;
|
||||||
|
|
||||||
for(auto i:detail::segment_split(first,last)){
|
for(auto i:detail::segment_split(first,last)){
|
||||||
auto alg=restitute_range<Ts...>(std_partition_copy{},rest,resf,pred);
|
auto alg=restitute_range<model_type,Ts...>(
|
||||||
|
std_partition_copy{},rest,resf,pred);
|
||||||
std::tie(rest,resf)=alg(i);
|
std::tie(rest,resf)=alg(i);
|
||||||
}
|
}
|
||||||
return {rest,resf};
|
return {rest,resf};
|
||||||
@@ -1094,7 +1149,9 @@ struct partition_point_pred
|
|||||||
bool operator()(const Iterator& it)const
|
bool operator()(const Iterator& it)const
|
||||||
{
|
{
|
||||||
using traits=iterator_traits<Iterator>;
|
using traits=iterator_traits<Iterator>;
|
||||||
auto p=restitute_iterator<Ts...>(deref_to(pred));
|
using model_type=typename traits::model_type;
|
||||||
|
|
||||||
|
auto p=restitute_iterator<model_type,Ts...>(deref_to(pred));
|
||||||
return p(
|
return p(
|
||||||
traits::base_segment_info_iterator_from(it)->type_info(),
|
traits::base_segment_info_iterator_from(it)->type_info(),
|
||||||
traits::local_base_iterator_from(it));
|
traits::local_base_iterator_from(it));
|
||||||
@@ -1107,7 +1164,7 @@ template<
|
|||||||
typename... Ts,typename Iterator,typename Predicate,
|
typename... Ts,typename Iterator,typename Predicate,
|
||||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||||
>
|
>
|
||||||
Iterator partition_point(
|
BOOST_FORCEINLINE Iterator partition_point(
|
||||||
const Iterator& first,const Iterator& last,Predicate pred)
|
const Iterator& first,const Iterator& last,Predicate pred)
|
||||||
{
|
{
|
||||||
auto_iterator<Iterator> afirst{first},alast{last};
|
auto_iterator<Iterator> afirst{first},alast{last};
|
||||||
@@ -1183,4 +1240,8 @@ using detail::algorithm::partition_point;
|
|||||||
|
|
||||||
} /* namespace boost */
|
} /* namespace boost */
|
||||||
|
|
||||||
|
#if defined(BOOST_MSVC)
|
||||||
|
#pragma warning(pop) /* C4714 */
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2018 Joaquin M Lopez Munoz.
|
/* Copyright 2018-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -36,13 +36,13 @@ namespace detail{
|
|||||||
* prevents intermediate entities from calling Allocator::[construct|destroy].
|
* prevents intermediate entities from calling Allocator::[construct|destroy].
|
||||||
* allocator_adaptor<Allocator> does this by taking advantage of the fact that
|
* allocator_adaptor<Allocator> does this by taking advantage of the fact that
|
||||||
* elements are ultimately held within a value_holder:
|
* elements are ultimately held within a value_holder:
|
||||||
* - construct(value_holder<T>*,...) uses placement new construction and
|
* - construct(value_holder<T,U>*,...) uses placement new construction and
|
||||||
* passes the wrapped Allocator object for value_holder<T> to use for
|
* passes the wrapped Allocator object for value_holder<T> to use for
|
||||||
* its inner construction of T.
|
* its inner construction of T.
|
||||||
* - For the rest of types, construct uses placement new construction and
|
* - For the rest of types, construct uses placement new construction and
|
||||||
* passes down the adaptor object itself as an argument following an
|
* passes down the adaptor object itself as an argument following an
|
||||||
* approach analogous to that of std::scoped_allocator_adaptor.
|
* approach analogous to that of std::scoped_allocator_adaptor.
|
||||||
* - destroy(value_holder<T>) resorts to Allocator::destroy to destroy the
|
* - destroy(value_holder<T,U>) resorts to Allocator::destroy to destroy the
|
||||||
* contained T element.
|
* contained T element.
|
||||||
* - For the rest of types, destroy(T) calls ~T directly.
|
* - For the rest of types, destroy(T) calls ~T directly.
|
||||||
*
|
*
|
||||||
@@ -53,7 +53,7 @@ namespace detail{
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
class value_holder_base;
|
class value_holder_base;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T,typename U>
|
||||||
class value_holder;
|
class value_holder;
|
||||||
|
|
||||||
template<typename T,typename Allocator,typename... Args>
|
template<typename T,typename Allocator,typename... Args>
|
||||||
@@ -144,10 +144,11 @@ struct allocator_adaptor:Allocator
|
|||||||
p,std::forward<Args>(args)...);
|
p,std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T,typename... Args>
|
template<typename T,typename U,typename... Args>
|
||||||
void construct(value_holder<T>* p,Args&&... args)
|
void construct(value_holder<T,U>* p,Args&&... args)
|
||||||
{
|
{
|
||||||
::new ((void*)p) value_holder<T>(allocator(),std::forward<Args>(args)...);
|
::new ((void*)p) value_holder<T,U>(
|
||||||
|
allocator(),std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T1,typename T2,typename... Args1,typename... Args2>
|
template<typename T1,typename T2,typename... Args1,typename... Args2>
|
||||||
@@ -206,8 +207,8 @@ struct allocator_adaptor:Allocator
|
|||||||
p->~T();
|
p->~T();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T,typename U>
|
||||||
void destroy(value_holder<T>* p)
|
void destroy(value_holder<T,U>* p)
|
||||||
{
|
{
|
||||||
traits::destroy(
|
traits::destroy(
|
||||||
allocator(),
|
allocator(),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2020 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -100,6 +100,8 @@ struct any_model
|
|||||||
type_erasure::_self&
|
type_erasure::_self&
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
using type_index=std::type_info;
|
||||||
|
|
||||||
template<typename Concrete>
|
template<typename Concrete>
|
||||||
using is_implementation=std::true_type; /* can't compile-time check concept
|
using is_implementation=std::true_type; /* can't compile-time check concept
|
||||||
* compliance */
|
* compliance */
|
||||||
@@ -107,13 +109,16 @@ struct any_model
|
|||||||
using is_terminal=any_model_is_terminal<T>;
|
using is_terminal=any_model_is_terminal<T>;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static const std::type_info& subtypeid(const T&){return typeid(T);}
|
static const std::type_info& index(){return typeid(T);}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static const std::type_info& subindex(const T&){return typeid(T);}
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename Concept2,typename T,
|
typename Concept2,typename T,
|
||||||
any_model_enable_if_has_typeid_<Concept2,T> =nullptr
|
any_model_enable_if_has_typeid_<Concept2,T> =nullptr
|
||||||
>
|
>
|
||||||
static const std::type_info& subtypeid(
|
static const std::type_info& subindex(
|
||||||
const type_erasure::any<Concept2,T>& a)
|
const type_erasure::any<Concept2,T>& a)
|
||||||
{
|
{
|
||||||
return type_erasure::typeid_of(a);
|
return type_erasure::typeid_of(a);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2018 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -34,6 +34,7 @@ template<typename Base>
|
|||||||
struct base_model
|
struct base_model
|
||||||
{
|
{
|
||||||
using value_type=Base;
|
using value_type=Base;
|
||||||
|
using type_index=std::type_info;
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
using is_implementation=std::is_base_of<Base,Derived>;
|
using is_implementation=std::is_base_of<Base,Derived>;
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -48,11 +49,14 @@ private:
|
|||||||
typename std::enable_if<is_terminal<T>::value>::type*;
|
typename std::enable_if<is_terminal<T>::value>::type*;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
template<typename T>
|
||||||
|
static const std::type_info& index(){return typeid(T);}
|
||||||
|
|
||||||
template<typename T,enable_if_not_terminal<T> =nullptr>
|
template<typename T,enable_if_not_terminal<T> =nullptr>
|
||||||
static const std::type_info& subtypeid(const T& x){return typeid(x);}
|
static const std::type_info& subindex(const T& x){return typeid(x);}
|
||||||
|
|
||||||
template<typename T,enable_if_terminal<T> =nullptr>
|
template<typename T,enable_if_terminal<T> =nullptr>
|
||||||
static const std::type_info& subtypeid(const T&){return typeid(T);}
|
static const std::type_info& subindex(const T&){return typeid(T);}
|
||||||
|
|
||||||
template<typename T,enable_if_not_terminal<T> =nullptr>
|
template<typename T,enable_if_not_terminal<T> =nullptr>
|
||||||
static void* subaddress(T& x)
|
static void* subaddress(T& x)
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if BOOST_WORKAROUND(BOOST_GCC_VERSION,>=40900)||\
|
||||||
|
BOOST_WORKAROUND(BOOST_CLANG,>=1)&&\
|
||||||
|
(__clang_major__>3 || __clang_major__==3 && __clang_minor__ >= 8)
|
||||||
|
/* https://github.com/boostorg/poly_collection/issues/15 */
|
||||||
|
|
||||||
|
#define BOOST_POLY_COLLECTION_INSIDE_NO_SANITIZE
|
||||||
|
#define BOOST_POLY_COLLECTION_NO_SANITIZE \
|
||||||
|
__attribute__((no_sanitize("undefined")))
|
||||||
|
|
||||||
|
/* UBSan seems not to be supported in some environments */
|
||||||
|
#if defined(BOOST_GCC_VERSION)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wattributes"
|
||||||
|
#elif defined(BOOST_CLANG)
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wattributes"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define BOOST_POLY_COLLECTION_NO_SANITIZE
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_POLY_COLLECTION_DETAIL_COPYABLE_HPP
|
||||||
|
#define BOOST_POLY_COLLECTION_DETAIL_COPYABLE_HPP
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace boost{
|
||||||
|
|
||||||
|
namespace poly_collection{
|
||||||
|
|
||||||
|
namespace detail{
|
||||||
|
|
||||||
|
/* wraps T if it is not copyable */
|
||||||
|
|
||||||
|
template<typename T,typename=void>
|
||||||
|
struct copyable_impl{using type=T;};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct reference_wrapper
|
||||||
|
{
|
||||||
|
reference_wrapper(T& x):p{&x}{}
|
||||||
|
|
||||||
|
operator T&()const noexcept{return *p;}
|
||||||
|
|
||||||
|
T* p;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct copyable_impl<
|
||||||
|
T,
|
||||||
|
typename std::enable_if<!std::is_copy_constructible<T>::value>::type
|
||||||
|
>
|
||||||
|
{using type=reference_wrapper<const T>;};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using copyable=typename copyable_impl<T>::type;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
copyable<T> make_copyable(const T& x){return x;}
|
||||||
|
|
||||||
|
} /* namespace poly_collection::detail */
|
||||||
|
|
||||||
|
} /* namespace poly_collection */
|
||||||
|
|
||||||
|
} /* namespace boost */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(BOOST_POLY_COLLECTION_INSIDE_NO_SANITIZE)
|
||||||
|
#if defined(BOOST_GCC_VERSION)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#elif defined(BOOST_CLANG)
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef BOOST_POLY_COLLECTION_NO_SANITIZE
|
||||||
|
#undef BOOST_POLY_COLLECTION_INSIDE_NO_SANITIZE
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,602 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_POLY_COLLECTION_DETAIL_FIXED_VARIANT_HPP
|
||||||
|
#define BOOST_POLY_COLLECTION_DETAIL_FIXED_VARIANT_HPP
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <boost/core/addressof.hpp>
|
||||||
|
#include <boost/mp11/algorithm.hpp>
|
||||||
|
#include <boost/mp11/function.hpp>
|
||||||
|
#include <boost/mp11/list.hpp>
|
||||||
|
#include <boost/mp11/set.hpp>
|
||||||
|
#include <boost/mp11/tuple.hpp>
|
||||||
|
#include <boost/poly_collection/detail/is_equality_comparable.hpp>
|
||||||
|
#include <boost/poly_collection/detail/is_nothrow_eq_comparable.hpp>
|
||||||
|
#include <boost/type_traits/is_constructible.hpp>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace boost{
|
||||||
|
|
||||||
|
namespace poly_collection{
|
||||||
|
|
||||||
|
namespace fixed_variant_impl{
|
||||||
|
|
||||||
|
/* fixed_variant behaves as a variant without the possibility to change the
|
||||||
|
* initial alternative. The referenced value does not belong in fixed_variant
|
||||||
|
* but assumed to be right before it, which layout is implemented by
|
||||||
|
* fixed_variant_closure<T,fixed_variant<...>>. This approach allows us to pack
|
||||||
|
* same-alternative fixed_variants optimally, without reserving space for
|
||||||
|
* the largest alternative type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
class fixed_variant
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
mp11::mp_is_set<fixed_variant>::value,
|
||||||
|
"all types in the variant must be distinct");
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<
|
||||||
|
typename T,
|
||||||
|
std::size_t I=mp11::mp_find<fixed_variant,T>::value,
|
||||||
|
typename std::enable_if<
|
||||||
|
(I<mp11::mp_size<fixed_variant>::value)>::type* =nullptr
|
||||||
|
>
|
||||||
|
explicit fixed_variant(const T&):index_{I}{}
|
||||||
|
|
||||||
|
std::size_t index()const noexcept{return index_;}
|
||||||
|
bool valueless_by_exception()const noexcept{return false;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t index_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct fixed_variant_store
|
||||||
|
{
|
||||||
|
template<typename... Args>
|
||||||
|
fixed_variant_store(Args&&... args):value{std::forward<Args>(args)...}{}
|
||||||
|
|
||||||
|
T value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T,typename Base>
|
||||||
|
class fixed_variant_closure:public fixed_variant_store<T>,public Base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<
|
||||||
|
typename... Args,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_constructible<T,Args&&...>::value
|
||||||
|
>::type* =nullptr
|
||||||
|
>
|
||||||
|
fixed_variant_closure(Args&&... args)
|
||||||
|
noexcept(std::is_nothrow_constructible<T,Args&&...>::value):
|
||||||
|
fixed_variant_store<T>{std::forward<Args>(args)...},
|
||||||
|
Base{this->value}
|
||||||
|
{}
|
||||||
|
|
||||||
|
fixed_variant_closure(const fixed_variant_closure&)=default;
|
||||||
|
fixed_variant_closure(fixed_variant_closure&&)=default;
|
||||||
|
fixed_variant_closure& operator=(fixed_variant_closure&&)=default;
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename Q=T,
|
||||||
|
typename std::enable_if<
|
||||||
|
detail::is_equality_comparable<Q>::value,bool>::type* =nullptr
|
||||||
|
>
|
||||||
|
bool operator==(const fixed_variant_closure& x)const
|
||||||
|
noexcept(detail::is_nothrow_equality_comparable<T>::value)
|
||||||
|
{
|
||||||
|
return this->value==x.value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bad_variant_access:std::exception
|
||||||
|
{
|
||||||
|
bad_variant_access()noexcept{}
|
||||||
|
const char* what()const noexcept{return "bad variant access";}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> struct variant_size;
|
||||||
|
template<typename... Ts>
|
||||||
|
struct variant_size<fixed_variant<Ts...>>:
|
||||||
|
std::integral_constant<std::size_t, sizeof...(Ts)>{};
|
||||||
|
template<typename T> struct variant_size<const T>:variant_size<T>{};
|
||||||
|
|
||||||
|
#ifndef BOOST_NO_CXX14_VARIABLE_TEMPLATES
|
||||||
|
template<typename T>
|
||||||
|
constexpr std::size_t variant_size_v=variant_size<T>::value;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<std::size_t I,typename T,typename=void> struct variant_alternative;
|
||||||
|
|
||||||
|
template<typename T> struct is_fixed_variant:std::false_type{};
|
||||||
|
template<typename... Ts>
|
||||||
|
struct is_fixed_variant<fixed_variant<Ts...>>:std::true_type{};
|
||||||
|
|
||||||
|
template<typename T,typename Q>
|
||||||
|
struct transfer_cref{using type=Q;};
|
||||||
|
template<typename T,typename Q>
|
||||||
|
struct transfer_cref<const T,Q>{using type=const Q;};
|
||||||
|
template<typename T,typename Q>
|
||||||
|
struct transfer_cref<T&,Q>
|
||||||
|
{using type=typename transfer_cref<T,Q>::type&;};
|
||||||
|
template<typename T,typename Q>
|
||||||
|
struct transfer_cref<T&&,Q>
|
||||||
|
{using type=typename transfer_cref<T,Q>::type&&;};
|
||||||
|
|
||||||
|
template<std::size_t I,typename V>
|
||||||
|
struct variant_alternative<
|
||||||
|
I,V,
|
||||||
|
typename std::enable_if<
|
||||||
|
is_fixed_variant<typename std::decay<V>::type>::value
|
||||||
|
>::type
|
||||||
|
>
|
||||||
|
{
|
||||||
|
using type=typename transfer_cref<
|
||||||
|
V,mp11::mp_at_c<typename std::decay<V>::type,I>>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<std::size_t I,typename V>
|
||||||
|
using variant_alternative_t=typename variant_alternative<I,V>::type;
|
||||||
|
|
||||||
|
template<typename T,typename... Ts>
|
||||||
|
bool holds_alternative(const fixed_variant<Ts...>& x)noexcept
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
mp11::mp_contains<fixed_variant<Ts...>,T>::value,
|
||||||
|
"type must be one of the variant alternatives");
|
||||||
|
return x.index()==mp11::mp_find<fixed_variant<Ts...>,T>::value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T,typename... Ts>
|
||||||
|
const T& unsafe_get(const fixed_variant<Ts...>& x)
|
||||||
|
{
|
||||||
|
return static_cast<const fixed_variant_closure<T,fixed_variant<Ts...>>&>
|
||||||
|
(x).value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T,typename... Ts>
|
||||||
|
T& unsafe_get(fixed_variant<Ts...>& x)
|
||||||
|
{
|
||||||
|
return const_cast<T&>(
|
||||||
|
unsafe_get<T>(const_cast<const fixed_variant<Ts...>&>(x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T,typename... Ts>
|
||||||
|
const T&& unsafe_get(const fixed_variant<Ts...>&& x)
|
||||||
|
{
|
||||||
|
return std::move(unsafe_get<T>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T,typename... Ts>
|
||||||
|
T&& unsafe_get(fixed_variant<Ts...>&& x)
|
||||||
|
{
|
||||||
|
return std::move(unsafe_get<T>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I,typename V>
|
||||||
|
variant_alternative_t<I,V&&> unsafe_get(V&& x)
|
||||||
|
{
|
||||||
|
using raw_variant=typename std::decay<V>::type;
|
||||||
|
|
||||||
|
return unsafe_get<mp11::mp_at_c<raw_variant,I>>(std::forward<V>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I,typename V>
|
||||||
|
variant_alternative_t<I,V&&> get(V&& x)
|
||||||
|
{
|
||||||
|
using raw_variant=typename std::decay<V>::type;
|
||||||
|
static_assert(
|
||||||
|
I<mp11::mp_size<raw_variant>::value,
|
||||||
|
"index must be less than the number of alternatives");
|
||||||
|
|
||||||
|
if(x.index()!=I)throw bad_variant_access{};
|
||||||
|
else return unsafe_get<I>(std::forward<V>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T,typename V>
|
||||||
|
auto get(V&& x)->decltype(unsafe_get<T>(std::forward<V>(x)))
|
||||||
|
{
|
||||||
|
using raw_variant=typename std::decay<V>::type;
|
||||||
|
static_assert(
|
||||||
|
mp11::mp_contains<raw_variant,T>::value,
|
||||||
|
"type must be one of the variant alternatives");
|
||||||
|
|
||||||
|
if(!holds_alternative<T>(x))throw bad_variant_access{};
|
||||||
|
else return unsafe_get<T>(std::forward<V>(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I,typename... Ts>
|
||||||
|
variant_alternative_t<I,fixed_variant<Ts...>>*
|
||||||
|
get_if(fixed_variant<Ts...>* px)noexcept
|
||||||
|
{
|
||||||
|
if(!px||px->index()!=I)return nullptr;
|
||||||
|
else return std::addressof(unsafe_get<I>(*px));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t I,typename... Ts>
|
||||||
|
const variant_alternative_t<I,fixed_variant<Ts...>>*
|
||||||
|
get_if(const fixed_variant<Ts...>* px)noexcept
|
||||||
|
{
|
||||||
|
return get_if<I>(const_cast<fixed_variant<Ts...>*>(px));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T,typename... Ts>
|
||||||
|
T* get_if(fixed_variant<Ts...>* px)noexcept
|
||||||
|
{
|
||||||
|
if(!px||!holds_alternative<T>(*px))return nullptr;
|
||||||
|
else return std::addressof(unsafe_get<T>(*px));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T,typename... Ts>
|
||||||
|
const T* get_if(const fixed_variant<Ts...>* px)noexcept
|
||||||
|
{
|
||||||
|
return get_if<T>(const_cast<fixed_variant<Ts...>*>(px));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct deduced;
|
||||||
|
|
||||||
|
template<typename R,typename F,typename... Vs>
|
||||||
|
struct return_type_impl
|
||||||
|
{
|
||||||
|
using type=R;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename F,typename... Vs>
|
||||||
|
struct return_type_impl<deduced,F,Vs...>
|
||||||
|
{
|
||||||
|
using type=decltype(std::declval<F>()(get<0>(std::declval<Vs>())...));
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename R,typename F,typename... Vs>
|
||||||
|
using return_type=typename return_type_impl<R,F,Vs...>::type;
|
||||||
|
|
||||||
|
template<typename R,typename F,typename... Vs>
|
||||||
|
struct visit_helper;
|
||||||
|
|
||||||
|
template<typename R,typename F>
|
||||||
|
struct visit_helper<R,F>
|
||||||
|
{
|
||||||
|
F&& f;
|
||||||
|
|
||||||
|
R operator()(){return std::forward<F>(f)();}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
struct visit_helper<void,F>
|
||||||
|
{
|
||||||
|
F&& f;
|
||||||
|
|
||||||
|
void operator()(){(void)std::forward<F>(f)();}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename R=deduced,typename F,
|
||||||
|
typename ReturnType=return_type<R,F&&>
|
||||||
|
>
|
||||||
|
ReturnType visit(F&& f)
|
||||||
|
{
|
||||||
|
return visit_helper<ReturnType,F>{std::forward<F>(f)}();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename R,typename F,typename V>
|
||||||
|
struct visit_helper<R,F,V>
|
||||||
|
{
|
||||||
|
F&& f;
|
||||||
|
V&& x;
|
||||||
|
|
||||||
|
template<typename I>
|
||||||
|
R operator()(I)
|
||||||
|
{
|
||||||
|
return std::forward<F>(f)(unsafe_get<I::value>(std::forward<V>(x)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename F,typename V>
|
||||||
|
struct visit_helper<void,F,V>
|
||||||
|
{
|
||||||
|
F&& f;
|
||||||
|
V&& x;
|
||||||
|
|
||||||
|
template<typename I>
|
||||||
|
void operator()(I)
|
||||||
|
{
|
||||||
|
(void)std::forward<F>(f)(unsafe_get<I::value>(std::forward<V>(x)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename R=deduced,typename F,typename V,
|
||||||
|
typename ReturnType=return_type<R,F&&,V&&>
|
||||||
|
>
|
||||||
|
ReturnType visit(F&& f,V&& x)
|
||||||
|
{
|
||||||
|
using raw_variant=typename std::decay<V>::type;
|
||||||
|
|
||||||
|
return mp11::mp_with_index<mp11::mp_size<raw_variant>::value>(
|
||||||
|
x.index(),
|
||||||
|
visit_helper<ReturnType,F,V>{std::forward<F>(f),std::forward<V>(x)});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename R,typename F,typename V,typename I>
|
||||||
|
struct bound_f
|
||||||
|
{
|
||||||
|
F&& f;
|
||||||
|
V&& x;
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
R operator()(Args&&... xs)
|
||||||
|
{
|
||||||
|
return std::forward<F>(f)(
|
||||||
|
unsafe_get<I::value>(std::forward<V>(x)),std::forward<Args>(xs)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename F,typename V,typename I>
|
||||||
|
struct bound_f<void,F,V,I>
|
||||||
|
{
|
||||||
|
F&& f;
|
||||||
|
V&& x;
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void operator()(Args&&... xs)
|
||||||
|
{
|
||||||
|
(void)std::forward<F>(f)(
|
||||||
|
unsafe_get<I::value>(std::forward<V>(x)),std::forward<Args>(xs)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename R,typename F>
|
||||||
|
struct bound_visit;
|
||||||
|
|
||||||
|
template<typename R,typename F,typename V,typename... Vs>
|
||||||
|
struct visit_helper<R,F,V,Vs...>
|
||||||
|
{
|
||||||
|
F&& f;
|
||||||
|
V&& x;
|
||||||
|
std::tuple<Vs&&...> xs;
|
||||||
|
|
||||||
|
template<typename I>
|
||||||
|
R operator()(I)
|
||||||
|
{
|
||||||
|
return mp11::tuple_apply(
|
||||||
|
bound_visit<R,bound_f<R,F,V,I>>{{std::forward<F>(f),std::forward<V>(x)}},
|
||||||
|
std::move(xs));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename R=deduced,typename F,typename V1,typename V2,typename... Vs,
|
||||||
|
typename ReturnType=return_type<R,F&&,V1&&,V2&&,Vs&&...>
|
||||||
|
>
|
||||||
|
ReturnType visit(F&& f,V1&& x1,V2&& x2,Vs&&... xs)
|
||||||
|
{
|
||||||
|
using raw_variant=typename std::decay<V1>::type;
|
||||||
|
|
||||||
|
return mp11::mp_with_index<mp11::mp_size<raw_variant>::value>(
|
||||||
|
x1.index(),
|
||||||
|
visit_helper<ReturnType,F,V1,V2,Vs...>{
|
||||||
|
std::forward<F>(f),std::forward<V1>(x1),
|
||||||
|
std::forward_as_tuple(std::forward<V2>(x2),std::forward<Vs>(xs)...)});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename R,typename F>
|
||||||
|
struct bound_visit
|
||||||
|
{
|
||||||
|
F&& f;
|
||||||
|
|
||||||
|
template<typename... Vs>
|
||||||
|
R operator()(Vs&&... xs)
|
||||||
|
{
|
||||||
|
return visit<R>(std::forward<F>(f),std::forward<Vs>(xs)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename R,typename V,typename... Fs>
|
||||||
|
struct return_type_by_index_impl
|
||||||
|
{
|
||||||
|
using type=R;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename V,typename F,typename... Fs>
|
||||||
|
struct return_type_by_index_impl<deduced,V,F,Fs...>
|
||||||
|
{
|
||||||
|
using type=decltype(std::declval<F>()(get<0>(std::declval<V>())));
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename R,typename V,typename... Fs>
|
||||||
|
using return_type_by_index=typename return_type_by_index_impl<R,V,Fs...>::type;
|
||||||
|
|
||||||
|
template<typename R,typename V,typename... Fs>
|
||||||
|
struct visit_by_index_helper
|
||||||
|
{
|
||||||
|
V&& x;
|
||||||
|
std::tuple<Fs&&...> fs;
|
||||||
|
|
||||||
|
template<typename I>
|
||||||
|
R operator()(I)
|
||||||
|
{
|
||||||
|
return std::get<I::value>(std::move(fs))(
|
||||||
|
unsafe_get<I::value>(std::forward<V>(x)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename V,typename... Fs>
|
||||||
|
struct visit_by_index_helper<void,V,Fs...>
|
||||||
|
{
|
||||||
|
V&& x;
|
||||||
|
std::tuple<Fs&&...> fs;
|
||||||
|
|
||||||
|
template<typename I>
|
||||||
|
void operator()(I)
|
||||||
|
{
|
||||||
|
(void)std::get<I::value>(std::move(fs))(
|
||||||
|
unsafe_get<I::value>(std::forward<V>(x)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename R=deduced,typename V,typename... Fs,
|
||||||
|
typename ReturnType=return_type_by_index<R,V&&,Fs&&...>
|
||||||
|
>
|
||||||
|
ReturnType visit_by_index(V&& x,Fs&&... fs)
|
||||||
|
{
|
||||||
|
using raw_variant=typename std::decay<V>::type;
|
||||||
|
static_assert(
|
||||||
|
mp11::mp_size<raw_variant>::value==sizeof...(Fs),
|
||||||
|
"the number of function objects must be the same as that of the "
|
||||||
|
"alternative types in the variant");
|
||||||
|
|
||||||
|
return mp11::mp_with_index<mp11::mp_size<raw_variant>::value>(
|
||||||
|
x.index(),
|
||||||
|
visit_by_index_helper<ReturnType,V,Fs...>{
|
||||||
|
std::forward<V>(x),
|
||||||
|
std::forward_as_tuple(std::forward<Fs>(fs)...)});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename RelOp,typename ... Ts>
|
||||||
|
struct relop_helper
|
||||||
|
{
|
||||||
|
const fixed_variant<Ts...> &x,&y;
|
||||||
|
|
||||||
|
template<typename I> bool operator()(I)const
|
||||||
|
{
|
||||||
|
return RelOp{}(unsafe_get<I::value>(x),unsafe_get<I::value>(y));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct eq_
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
bool operator()(const T& x,const T& y)const{return x==y;}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
bool operator==(
|
||||||
|
const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
x.index()==y.index()&&
|
||||||
|
mp11::mp_with_index<sizeof...(Ts)>(x.index(),relop_helper<eq_,Ts...>{x,y});
|
||||||
|
}
|
||||||
|
|
||||||
|
struct neq_
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
bool operator()(const T& x,const T& y)const{return x!=y;}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
bool operator!=(
|
||||||
|
const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
x.index()!=y.index()||
|
||||||
|
mp11::mp_with_index<sizeof...(Ts)>(
|
||||||
|
x.index(),relop_helper<neq_,Ts...>{x,y});
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lt_
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
bool operator()(const T& x,const T& y)const{return x<y;}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
bool operator<(
|
||||||
|
const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
x.index()<y.index()||
|
||||||
|
(x.index()==y.index()&&mp11::mp_with_index<sizeof...(Ts)>(
|
||||||
|
x.index(),relop_helper<lt_,Ts...>{x,y}));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lte_
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
bool operator()(const T& x,const T& y)const{return x<=y;}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
bool operator<=(
|
||||||
|
const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
x.index()<y.index()||
|
||||||
|
(x.index()==y.index()&&mp11::mp_with_index<sizeof...(Ts)>(
|
||||||
|
x.index(),relop_helper<lte_,Ts...>{x,y}));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct gt_
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
bool operator()(const T& x,const T& y)const{return x>y;}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
bool operator>(
|
||||||
|
const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
x.index()>y.index()||
|
||||||
|
(x.index()==y.index()&&mp11::mp_with_index<sizeof...(Ts)>(
|
||||||
|
x.index(),relop_helper<gt_,Ts...>{x,y}));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct gte_
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
bool operator()(const T& x,const T& y)const{return x>=y;}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
bool operator>=(
|
||||||
|
const fixed_variant<Ts...>& x,const fixed_variant<Ts...>& y)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
x.index()>y.index()||
|
||||||
|
(x.index()==y.index()&&mp11::mp_with_index<sizeof...(Ts)>(
|
||||||
|
x.index(),relop_helper<gte_,Ts...>{x,y}));
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace poly_collection::fixed_variant_impl */
|
||||||
|
|
||||||
|
using boost::poly_collection::fixed_variant_impl::variant_size;
|
||||||
|
|
||||||
|
#ifndef BOOST_NO_CXX14_VARIABLE_TEMPLATES
|
||||||
|
using boost::poly_collection::fixed_variant_impl::variant_size_v;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using boost::poly_collection::fixed_variant_impl::bad_variant_access;
|
||||||
|
using boost::poly_collection::fixed_variant_impl::variant_alternative;
|
||||||
|
using boost::poly_collection::fixed_variant_impl::variant_alternative_t;
|
||||||
|
using boost::poly_collection::fixed_variant_impl::visit;
|
||||||
|
using boost::poly_collection::fixed_variant_impl::visit_by_index;
|
||||||
|
using boost::poly_collection::fixed_variant_impl::holds_alternative;
|
||||||
|
using boost::poly_collection::fixed_variant_impl::get;
|
||||||
|
using boost::poly_collection::fixed_variant_impl::unsafe_get;
|
||||||
|
using boost::poly_collection::fixed_variant_impl::get_if;
|
||||||
|
|
||||||
|
} /* namespace poly_collection */
|
||||||
|
|
||||||
|
} /* namespace boost */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_POLY_COLLECTION_DETAIL_FIXED_VARIANT_ITERATOR_HPP
|
||||||
|
#define BOOST_POLY_COLLECTION_DETAIL_FIXED_VARIANT_ITERATOR_HPP
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <boost/detail/workaround.hpp>
|
||||||
|
#include <boost/iterator/iterator_facade.hpp>
|
||||||
|
#include <boost/poly_collection/detail/fixed_variant.hpp>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace boost{
|
||||||
|
|
||||||
|
namespace poly_collection{
|
||||||
|
|
||||||
|
namespace detail{
|
||||||
|
|
||||||
|
/* Iterator over the sequence of T subojects within a range of
|
||||||
|
* fixed_variant_closure<T,fixed_variant<...>>s.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename Variant,typename T>
|
||||||
|
class fixed_variant_alternative_iterator:
|
||||||
|
public boost::iterator_facade<
|
||||||
|
fixed_variant_alternative_iterator<Variant,T>,
|
||||||
|
T,
|
||||||
|
boost::random_access_traversal_tag
|
||||||
|
>
|
||||||
|
{
|
||||||
|
static constexpr std::size_t Stride=sizeof(
|
||||||
|
fixed_variant_impl::fixed_variant_closure<
|
||||||
|
typename std::remove_const<T>::type,Variant>);
|
||||||
|
|
||||||
|
public:
|
||||||
|
fixed_variant_alternative_iterator()=default;
|
||||||
|
fixed_variant_alternative_iterator(T* p)noexcept:p{p}{}
|
||||||
|
fixed_variant_alternative_iterator(
|
||||||
|
const fixed_variant_alternative_iterator&)=default;
|
||||||
|
fixed_variant_alternative_iterator& operator=(
|
||||||
|
const fixed_variant_alternative_iterator&)=default;
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename NonConstT,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_same<T,const NonConstT>::value>::type* =nullptr
|
||||||
|
>
|
||||||
|
fixed_variant_alternative_iterator(
|
||||||
|
const fixed_variant_alternative_iterator<Variant,NonConstT>& x)noexcept:
|
||||||
|
p{x.p}{}
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename NonConstT,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_same<T,const NonConstT>::value>::type* =nullptr
|
||||||
|
>
|
||||||
|
fixed_variant_alternative_iterator& operator=(
|
||||||
|
const fixed_variant_alternative_iterator<Variant,NonConstT>& x)noexcept
|
||||||
|
{
|
||||||
|
p=x.p;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* interoperability with T* */
|
||||||
|
|
||||||
|
fixed_variant_alternative_iterator& operator=(T* p_)noexcept
|
||||||
|
{p=p_;return *this;}
|
||||||
|
operator T*()const noexcept{return p;}
|
||||||
|
|
||||||
|
std::size_t stride()const noexcept{return Stride;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename,typename>
|
||||||
|
friend class fixed_variant_alternative_iterator;
|
||||||
|
|
||||||
|
using char_pointer=typename std::conditional<
|
||||||
|
std::is_const<T>::value,
|
||||||
|
const char*,
|
||||||
|
char*
|
||||||
|
>::type;
|
||||||
|
|
||||||
|
static char_pointer char_ptr(T* p)noexcept
|
||||||
|
{return reinterpret_cast<char_pointer>(p);}
|
||||||
|
static T* value_ptr(char_pointer p)noexcept
|
||||||
|
{return reinterpret_cast<T*>(p);}
|
||||||
|
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
|
||||||
|
T& dereference()const noexcept{return *p;}
|
||||||
|
bool equal(const fixed_variant_alternative_iterator& x)const noexcept
|
||||||
|
{return p==x.p;}
|
||||||
|
void increment()noexcept{p=value_ptr(char_ptr(p)+Stride);}
|
||||||
|
void decrement()noexcept{p=value_ptr(char_ptr(p)-Stride);}
|
||||||
|
template<typename Integral>
|
||||||
|
void advance(Integral n)noexcept
|
||||||
|
{p=value_ptr(char_ptr(p)+n*(std::ptrdiff_t)Stride);}
|
||||||
|
std::ptrdiff_t distance_to(
|
||||||
|
const fixed_variant_alternative_iterator& x)const noexcept
|
||||||
|
{return (char_ptr(x.p)-char_ptr(p))/(std::ptrdiff_t)Stride;}
|
||||||
|
|
||||||
|
T* p;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Iterator over the sequence of fixed_variant base objects within a range of
|
||||||
|
* fixed_variant_closure<T,fixed_variant<...>>s. As T is not part of the
|
||||||
|
* iterator definition, the stride between values is a run-time value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename Variant>
|
||||||
|
class fixed_variant_iterator:
|
||||||
|
public boost::iterator_facade<
|
||||||
|
fixed_variant_iterator<Variant>,
|
||||||
|
Variant,
|
||||||
|
boost::random_access_traversal_tag
|
||||||
|
>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
fixed_variant_iterator()=default;
|
||||||
|
fixed_variant_iterator(Variant* p,std::size_t stride)noexcept:
|
||||||
|
p{p},stride_{stride}{}
|
||||||
|
fixed_variant_iterator(const fixed_variant_iterator&)=default;
|
||||||
|
fixed_variant_iterator& operator=(const fixed_variant_iterator&)=default;
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename NonConstVariant,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_same<Variant,const NonConstVariant>::value>::type* =nullptr
|
||||||
|
>
|
||||||
|
fixed_variant_iterator(
|
||||||
|
const fixed_variant_iterator<NonConstVariant>& x)noexcept:
|
||||||
|
p{x.p},stride_{x.stride_}{}
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename NonConstVariant,
|
||||||
|
typename std::enable_if<
|
||||||
|
std::is_same<Variant,const NonConstVariant>::value>::type* =nullptr
|
||||||
|
>
|
||||||
|
fixed_variant_iterator& operator=(
|
||||||
|
const fixed_variant_iterator<NonConstVariant>& x)noexcept
|
||||||
|
{
|
||||||
|
p=x.p;stride_=x.stride_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* interoperability with Variant* */
|
||||||
|
|
||||||
|
fixed_variant_iterator& operator=(Variant* p_)noexcept{p=p_;return *this;}
|
||||||
|
operator Variant*()const noexcept{return p;}
|
||||||
|
|
||||||
|
/* interoperability with fixed_variant_alternative_iterator<Variant,T> */
|
||||||
|
|
||||||
|
#include <boost/poly_collection/detail/begin_no_sanitize.hpp>
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename T,
|
||||||
|
typename NonConstT=typename std::remove_const<T>::type,
|
||||||
|
typename NonConstVariant=typename std::remove_const<Variant>::type,
|
||||||
|
typename std::enable_if<
|
||||||
|
mp11::mp_contains<NonConstVariant,NonConstT>::value&&
|
||||||
|
(!std::is_const<Variant>::value||std::is_const<T>::value)
|
||||||
|
>::type* =nullptr
|
||||||
|
>
|
||||||
|
BOOST_POLY_COLLECTION_NO_SANITIZE explicit operator
|
||||||
|
fixed_variant_alternative_iterator<NonConstVariant,T>()const noexcept
|
||||||
|
{
|
||||||
|
return p?std::addressof(unsafe_get<NonConstT>(*p)):nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <boost/poly_collection/detail/end_no_sanitize.hpp>
|
||||||
|
|
||||||
|
std::size_t stride()const noexcept{return stride_;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename>
|
||||||
|
friend class fixed_variant_iterator;
|
||||||
|
|
||||||
|
using char_pointer=typename std::conditional<
|
||||||
|
std::is_const<Variant>::value,
|
||||||
|
const char*,
|
||||||
|
char*
|
||||||
|
>::type;
|
||||||
|
|
||||||
|
static char_pointer char_ptr(Variant* p)noexcept
|
||||||
|
{return reinterpret_cast<char_pointer>(p);}
|
||||||
|
static Variant* value_ptr(char_pointer p)noexcept
|
||||||
|
{return reinterpret_cast<Variant*>(p);}
|
||||||
|
|
||||||
|
friend class boost::iterator_core_access;
|
||||||
|
|
||||||
|
Variant& dereference()const noexcept{return *p;}
|
||||||
|
bool equal(const fixed_variant_iterator& x)const noexcept{return p==x.p;}
|
||||||
|
void increment()noexcept{p=value_ptr(char_ptr(p)+stride_);}
|
||||||
|
void decrement()noexcept{p=value_ptr(char_ptr(p)-stride_);}
|
||||||
|
template<typename Integral>
|
||||||
|
void advance(Integral n)noexcept
|
||||||
|
{p=value_ptr(char_ptr(p)+n*(std::ptrdiff_t)stride_);}
|
||||||
|
std::ptrdiff_t distance_to(const fixed_variant_iterator& x)const noexcept
|
||||||
|
{return (char_ptr(x.p)-char_ptr(p))/(std::ptrdiff_t)stride_;}
|
||||||
|
|
||||||
|
Variant* p;
|
||||||
|
std::size_t stride_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace poly_collection::detail */
|
||||||
|
|
||||||
|
} /* namespace poly_collection */
|
||||||
|
|
||||||
|
} /* namespace boost */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2018 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -49,6 +49,8 @@ struct function_model<R(Args...)>
|
|||||||
{
|
{
|
||||||
using value_type=callable_wrapper<R(Args...)>;
|
using value_type=callable_wrapper<R(Args...)>;
|
||||||
|
|
||||||
|
using type_index=std::type_info;
|
||||||
|
|
||||||
template<typename Callable>
|
template<typename Callable>
|
||||||
using is_implementation=is_invocable_r<R,Callable&,Args...>;
|
using is_implementation=is_invocable_r<R,Callable&,Args...>;
|
||||||
|
|
||||||
@@ -56,10 +58,13 @@ struct function_model<R(Args...)>
|
|||||||
using is_terminal=function_model_is_terminal<T>;
|
using is_terminal=function_model_is_terminal<T>;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static const std::type_info& subtypeid(const T&){return typeid(T);}
|
static const std::type_info& index(){return typeid(T);}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static const std::type_info& subindex(const T&){return typeid(T);}
|
||||||
|
|
||||||
template<typename Signature>
|
template<typename Signature>
|
||||||
static const std::type_info& subtypeid(
|
static const std::type_info& subindex(
|
||||||
const callable_wrapper<Signature>& f)
|
const callable_wrapper<Signature>& f)
|
||||||
{
|
{
|
||||||
return f.target_type();
|
return f.target_type();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2018 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
* C++14 generic lambdas.
|
* C++14 generic lambdas.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if BOOST_WORKAROUND(BOOST_MSVC,>=1910)
|
#if BOOST_WORKAROUND(BOOST_MSVC,>=1910)&&BOOST_WORKAROUND(BOOST_MSVC,<1920)
|
||||||
/* https://lists.boost.org/Archives/boost/2017/06/235687.php */
|
/* https://lists.boost.org/Archives/boost/2017/06/235687.php */
|
||||||
|
|
||||||
#define BOOST_POLY_COLLECTION_DEFINE_OVERLOAD_SET(name,f) \
|
#define BOOST_POLY_COLLECTION_DEFINE_OVERLOAD_SET(name,f) \
|
||||||
@@ -66,7 +66,7 @@ struct tail_closure_class
|
|||||||
template<typename... Args,std::size_t... I>
|
template<typename... Args,std::size_t... I>
|
||||||
return_type<Args&&...> call(mp11::index_sequence<I...>,Args&&... args)
|
return_type<Args&&...> call(mp11::index_sequence<I...>,Args&&... args)
|
||||||
{
|
{
|
||||||
return f(std::forward<Args>(args)...,std::get<I>(t)...);
|
return f(std::forward<Args>(args)...,std::get<I>(std::move(t))...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
@@ -99,7 +99,7 @@ struct head_closure_class
|
|||||||
template<typename... Args,std::size_t... I>
|
template<typename... Args,std::size_t... I>
|
||||||
return_type<Args&&...> call(mp11::index_sequence<I...>,Args&&... args)
|
return_type<Args&&...> call(mp11::index_sequence<I...>,Args&&... args)
|
||||||
{
|
{
|
||||||
return f(std::get<I>(t)...,std::forward<Args>(args)...);
|
return f(std::get<I>(std::move(t))...,std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2017 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -13,6 +13,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <boost/mp11/algorithm.hpp>
|
||||||
|
#include <boost/poly_collection/detail/is_closed_collection.hpp>
|
||||||
|
#include <boost/poly_collection/detail/is_moveable.hpp>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace boost{
|
namespace boost{
|
||||||
@@ -21,20 +24,28 @@ namespace poly_collection{
|
|||||||
|
|
||||||
namespace detail{
|
namespace detail{
|
||||||
|
|
||||||
/* This can be further specialized by Model when the std type trait classes
|
/* is_acceptable can be further specialized by (open collection) Model when
|
||||||
* fail to give the right info (as it can happen with class templates whose
|
* the std type_traits classes fail to give the right info (as it can happen
|
||||||
* nominally existing operators do not compile for certain instantiations).
|
* with class templates whose nominally existing operators do not compile for
|
||||||
|
* certain instantiations).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename T,typename Model,typename=void>
|
template<typename T,typename Model,typename=void>
|
||||||
struct is_acceptable:std::integral_constant<
|
struct is_acceptable:std::integral_constant<
|
||||||
bool,
|
bool,
|
||||||
Model::template is_implementation<T>::value&&
|
Model::template is_implementation<T>::value&&is_moveable<T>::value
|
||||||
std::is_move_constructible<typename std::decay<T>::type>::value&&
|
|
||||||
(std::is_move_assignable<typename std::decay<T>::type>::value||
|
|
||||||
std::is_nothrow_move_constructible<typename std::decay<T>::type>::value)
|
|
||||||
>{};
|
>{};
|
||||||
|
|
||||||
|
/* Closed collections are defined by having a compile-time fixed list of
|
||||||
|
* acceptable types.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename T,typename Model>
|
||||||
|
struct is_acceptable<
|
||||||
|
T,Model,
|
||||||
|
typename std::enable_if<is_closed_collection<Model>::value>::type
|
||||||
|
>:mp11::mp_contains<typename Model::acceptable_type_list,T>{};
|
||||||
|
|
||||||
} /* namespace poly_collection::detail */
|
} /* namespace poly_collection::detail */
|
||||||
|
|
||||||
} /* namespace poly_collection */
|
} /* namespace poly_collection */
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_POLY_COLLECTION_DETAIL_IS_CLOSED_COLLECTION_HPP
|
||||||
|
#define BOOST_POLY_COLLECTION_DETAIL_IS_CLOSED_COLLECTION_HPP
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/mp11/algorithm.hpp>
|
||||||
|
#include <boost/mp11/set.hpp>
|
||||||
|
#include <boost/poly_collection/detail/is_moveable.hpp>
|
||||||
|
#include <boost/type_traits/make_void.hpp>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace boost{
|
||||||
|
|
||||||
|
namespace poly_collection{
|
||||||
|
|
||||||
|
namespace detail{
|
||||||
|
|
||||||
|
template<typename Model,typename=void>
|
||||||
|
struct is_closed_collection:std::false_type{};
|
||||||
|
|
||||||
|
template<typename Model>
|
||||||
|
struct is_closed_collection<
|
||||||
|
Model,void_t<typename Model::acceptable_type_list>
|
||||||
|
>:std::true_type
|
||||||
|
{
|
||||||
|
using type_list=typename Model::acceptable_type_list;
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
mp11::mp_is_set<type_list>::value,
|
||||||
|
"all types in a closed collection must be distinct");
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
mp11::mp_all_of<type_list,is_moveable>::value,
|
||||||
|
"all types of a closed collection must be nothrow move constructible "
|
||||||
|
"or else move constructible and move assignable");
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace poly_collection::detail */
|
||||||
|
|
||||||
|
} /* namespace poly_collection */
|
||||||
|
|
||||||
|
} /* namespace boost */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2017-2018 Joaquin M Lopez Munoz.
|
/* Copyright 2017-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -25,7 +25,7 @@ namespace detail{
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
using is_equality_comparable=std::integral_constant<
|
using is_equality_comparable=std::integral_constant<
|
||||||
bool,
|
bool,
|
||||||
has_equal_to<T,T,bool>::value
|
has_equal_to<const T&,const T&,bool>::value
|
||||||
>;
|
>;
|
||||||
|
|
||||||
} /* namespace poly_collection::detail */
|
} /* namespace poly_collection::detail */
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_POLY_COLLECTION_DETAIL_IS_MOVEABLE_HPP
|
||||||
|
#define BOOST_POLY_COLLECTION_DETAIL_IS_MOVEABLE_HPP
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace boost{
|
||||||
|
|
||||||
|
namespace poly_collection{
|
||||||
|
|
||||||
|
namespace detail{
|
||||||
|
|
||||||
|
template<typename T> struct is_moveable:std::integral_constant<
|
||||||
|
bool,
|
||||||
|
std::is_move_constructible<typename std::decay<T>::type>::value&&
|
||||||
|
(std::is_move_assignable<typename std::decay<T>::type>::value||
|
||||||
|
std::is_nothrow_move_constructible<typename std::decay<T>::type>::value)
|
||||||
|
>{};
|
||||||
|
|
||||||
|
} /* namespace poly_collection::detail */
|
||||||
|
|
||||||
|
} /* namespace poly_collection */
|
||||||
|
|
||||||
|
} /* namespace boost */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2017 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -34,7 +34,7 @@ struct is_nothrow_equality_comparable<
|
|||||||
>::type
|
>::type
|
||||||
>:std::integral_constant<
|
>:std::integral_constant<
|
||||||
bool,
|
bool,
|
||||||
noexcept(std::declval<T>()==std::declval<T>())
|
noexcept(std::declval<const T&>()==std::declval<const T&>())
|
||||||
>{};
|
>{};
|
||||||
|
|
||||||
} /* namespace poly_collection::detail */
|
} /* namespace poly_collection::detail */
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2021 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -226,12 +226,25 @@ private:
|
|||||||
return BaseIterator{bit+(it-static_cast<BaseIterator2>(bit))};
|
return BaseIterator{bit+(it-static_cast<BaseIterator2>(bit))};
|
||||||
}
|
}
|
||||||
|
|
||||||
base_iterator base()const noexcept
|
base_iterator base()const noexcept
|
||||||
{return local_iterator_impl::iterator_adaptor_::base();}
|
{
|
||||||
const std::type_info& type_info()const{return *mapit->first;}
|
return local_iterator_impl::iterator_adaptor_::base();
|
||||||
segment_type& segment()noexcept
|
}
|
||||||
{return const_cast<segment_type&>(mapit->second);}
|
|
||||||
const segment_type& segment()const noexcept{return mapit->second;}
|
const typename PolyCollection::type_index& type_info()const
|
||||||
|
{
|
||||||
|
return mapit->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
segment_type& segment()noexcept
|
||||||
|
{
|
||||||
|
return const_cast<segment_type&>(mapit->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
const segment_type& segment()const noexcept
|
||||||
|
{
|
||||||
|
return mapit->second;
|
||||||
|
}
|
||||||
|
|
||||||
const_segment_map_iterator mapit;
|
const_segment_map_iterator mapit;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2017 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -31,7 +31,8 @@ namespace detail{
|
|||||||
|
|
||||||
/* (Internal) bunch of traits-grouped functions for const-preserving
|
/* (Internal) bunch of traits-grouped functions for const-preserving
|
||||||
* interoperatibility between iterators and local iterators of a
|
* interoperatibility between iterators and local iterators of a
|
||||||
* poly_collection.
|
* poly_collection, plus access to associated model's index from
|
||||||
|
* an iterator type.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename Iterator>
|
template<typename Iterator>
|
||||||
@@ -53,6 +54,8 @@ template<typename Iterator>
|
|||||||
struct iterator_traits
|
struct iterator_traits
|
||||||
{
|
{
|
||||||
using container_type=typename poly_collection_of<Iterator>::type;
|
using container_type=typename poly_collection_of<Iterator>::type;
|
||||||
|
using model_type=typename model_of<container_type>::type;
|
||||||
|
using type_index=typename container_type::type_index;
|
||||||
using is_const_iterator=typename std::is_const<
|
using is_const_iterator=typename std::is_const<
|
||||||
typename std::remove_reference<
|
typename std::remove_reference<
|
||||||
typename std::iterator_traits<Iterator>::reference
|
typename std::iterator_traits<Iterator>::reference
|
||||||
@@ -93,10 +96,7 @@ struct iterator_traits
|
|||||||
static local_base_iterator
|
static local_base_iterator
|
||||||
local_base_iterator_from(iterator it)noexcept
|
local_base_iterator_from(iterator it)noexcept
|
||||||
{
|
{
|
||||||
return {
|
return {it.mapit,model_type::nonconst_iterator(it.segpos)};
|
||||||
it.mapit,
|
|
||||||
model_of<container_type>::type::nonconst_iterator(it.segpos)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static iterator
|
static iterator
|
||||||
@@ -105,6 +105,12 @@ struct iterator_traits
|
|||||||
{
|
{
|
||||||
return {lbit.mapit,mapend.base(),lbit.base()};
|
return {lbit.mapit,mapend.base(),lbit.base()};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static decltype(model_type::template index<T>()) index()
|
||||||
|
{
|
||||||
|
return model_type::template index<T>();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace poly_collection::detail */
|
} /* namespace poly_collection::detail */
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2020 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -35,13 +35,23 @@ namespace detail{
|
|||||||
* {value_type*,sizeof(store_value_type)}.
|
* {value_type*,sizeof(store_value_type)}.
|
||||||
* - Model provides a function value_ptr for
|
* - Model provides a function value_ptr for
|
||||||
* const Concrete* -> const value_type* conversion.
|
* const Concrete* -> const value_type* conversion.
|
||||||
|
* - If Model provides a final_type<Concrete> template alias, it is this
|
||||||
|
* type that is stored in the segment rather than Concrete. In this case,
|
||||||
|
* final_type<Concrete> must be constructible from Concrete and
|
||||||
|
* Concrete* must be reinterpret_castable to final_type<Concrete>* and vice
|
||||||
|
* versa.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename Model,typename Concrete,typename Allocator>
|
template<typename Model,typename Concrete,typename Allocator>
|
||||||
class packed_segment:public segment_backend<Model,Allocator>
|
class packed_segment:public segment_backend<Model,Allocator>
|
||||||
{
|
{
|
||||||
|
template<typename M>
|
||||||
|
static typename M::template final_type<Concrete> final_type_helper(M);
|
||||||
|
static Concrete final_type_helper(...);
|
||||||
|
|
||||||
using value_type=typename Model::value_type;
|
using value_type=typename Model::value_type;
|
||||||
using store_value_type=value_holder<Concrete>;
|
using final_type=decltype(final_type_helper(std::declval<Model>()));
|
||||||
|
using store_value_type=value_holder<final_type,Concrete>;
|
||||||
using store=std::vector<
|
using store=std::vector<
|
||||||
store_value_type,
|
store_value_type,
|
||||||
typename std::allocator_traits<Allocator>::
|
typename std::allocator_traits<Allocator>::
|
||||||
@@ -266,7 +276,7 @@ private:
|
|||||||
static Concrete* concrete_ptr(store_value_type* p)noexcept
|
static Concrete* concrete_ptr(store_value_type* p)noexcept
|
||||||
{
|
{
|
||||||
return reinterpret_cast<Concrete*>(
|
return reinterpret_cast<Concrete*>(
|
||||||
static_cast<value_holder_base<Concrete>*>(p));
|
static_cast<value_holder_base<final_type>*>(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Concrete* const_concrete_ptr(const store_value_type* p)noexcept
|
static const Concrete* const_concrete_ptr(const store_value_type* p)noexcept
|
||||||
@@ -282,8 +292,8 @@ private:
|
|||||||
static const store_value_type* const_store_value_type_ptr(
|
static const store_value_type* const_store_value_type_ptr(
|
||||||
const Concrete* p)noexcept
|
const Concrete* p)noexcept
|
||||||
{
|
{
|
||||||
return static_cast<const value_holder<Concrete>*>(
|
return static_cast<const store_value_type*>(
|
||||||
reinterpret_cast<const value_holder_base<Concrete>*>(p));
|
reinterpret_cast<const value_holder_base<final_type>*>(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* It would have sufficed if iterator_from returned const_store_iterator
|
/* It would have sufficed if iterator_from returned const_store_iterator
|
||||||
|
|||||||
@@ -16,17 +16,20 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
#include <boost/iterator/iterator_adaptor.hpp>
|
#include <boost/iterator/iterator_adaptor.hpp>
|
||||||
|
#include <boost/mp11/algorithm.hpp>
|
||||||
|
#include <boost/mp11/list.hpp>
|
||||||
|
#include <boost/mp11/utility.hpp>
|
||||||
#include <boost/poly_collection/detail/allocator_adaptor.hpp>
|
#include <boost/poly_collection/detail/allocator_adaptor.hpp>
|
||||||
#include <boost/poly_collection/detail/iterator_impl.hpp>
|
#include <boost/poly_collection/detail/iterator_impl.hpp>
|
||||||
#include <boost/poly_collection/detail/is_acceptable.hpp>
|
#include <boost/poly_collection/detail/is_acceptable.hpp>
|
||||||
|
#include <boost/poly_collection/detail/is_closed_collection.hpp>
|
||||||
#include <boost/poly_collection/detail/is_constructible.hpp>
|
#include <boost/poly_collection/detail/is_constructible.hpp>
|
||||||
#include <boost/poly_collection/detail/is_final.hpp>
|
#include <boost/poly_collection/detail/is_final.hpp>
|
||||||
#include <boost/poly_collection/detail/segment.hpp>
|
#include <boost/poly_collection/detail/segment.hpp>
|
||||||
#include <boost/poly_collection/detail/type_info_map.hpp>
|
#include <boost/poly_collection/detail/segment_map.hpp>
|
||||||
#include <boost/poly_collection/exception.hpp>
|
#include <boost/poly_collection/exception.hpp>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <typeinfo>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace boost{
|
namespace boost{
|
||||||
@@ -42,13 +45,18 @@ using namespace detail;
|
|||||||
template<typename Model,typename Allocator>
|
template<typename Model,typename Allocator>
|
||||||
class poly_collection
|
class poly_collection
|
||||||
{
|
{
|
||||||
template<typename T>
|
/* used only to early force closed collection acceptability checks */
|
||||||
static const std::type_info& subtypeid(const T& x)
|
static constexpr bool is_closed_collection=
|
||||||
{return Model::subtypeid(x);}
|
detail::is_closed_collection<Model>::value;
|
||||||
|
|
||||||
template<typename...>
|
template<typename...>
|
||||||
struct for_all_types{using type=void*;};
|
struct for_all_types{using type=void*;};
|
||||||
template<typename... T>
|
template<typename... T>
|
||||||
using for_all=typename for_all_types<T...>::type;
|
using for_all=typename for_all_types<T...>::type;
|
||||||
|
template<typename Model_>
|
||||||
|
using enable_if_open_collection=typename std::enable_if<
|
||||||
|
!detail::is_closed_collection<Model_>::value
|
||||||
|
>::type*;
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct is_implementation: /* using makes VS2015 choke, hence we derive */
|
struct is_implementation: /* using makes VS2015 choke, hence we derive */
|
||||||
Model::template is_implementation<typename std::decay<T>::type>{};
|
Model::template is_implementation<typename std::decay<T>::type>{};
|
||||||
@@ -116,14 +124,6 @@ class poly_collection
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
using const_segment_iterator=
|
using const_segment_iterator=
|
||||||
typename segment_type::template const_iterator<T>;
|
typename segment_type::template const_iterator<T>;
|
||||||
using segment_map=type_info_map<
|
|
||||||
segment_type,
|
|
||||||
typename std::allocator_traits<segment_allocator_type>::template
|
|
||||||
rebind_alloc<segment_type>
|
|
||||||
>;
|
|
||||||
using segment_map_allocator_type=typename segment_map::allocator_type;
|
|
||||||
using segment_map_iterator=typename segment_map::iterator;
|
|
||||||
using const_segment_map_iterator=typename segment_map::const_iterator;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* types */
|
/* types */
|
||||||
@@ -136,8 +136,24 @@ public:
|
|||||||
using const_reference=const value_type&;
|
using const_reference=const value_type&;
|
||||||
using pointer=typename std::allocator_traits<Allocator>::pointer;
|
using pointer=typename std::allocator_traits<Allocator>::pointer;
|
||||||
using const_pointer=typename std::allocator_traits<Allocator>::const_pointer;
|
using const_pointer=typename std::allocator_traits<Allocator>::const_pointer;
|
||||||
|
using type_index=typename Model::type_index;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using segment_map=typename detail::segment_map<
|
||||||
|
type_index,
|
||||||
|
segment_type,
|
||||||
|
typename std::allocator_traits<segment_allocator_type>::template
|
||||||
|
rebind_alloc<segment_type>
|
||||||
|
>;
|
||||||
|
using segment_map_allocator_type=typename segment_map::allocator_type;
|
||||||
|
using segment_map_iterator=typename segment_map::iterator;
|
||||||
|
using const_segment_map_iterator=typename segment_map::const_iterator;
|
||||||
|
template<typename T>
|
||||||
|
static auto index()->decltype(Model::template index<T>())
|
||||||
|
{return Model::template index<T>();}
|
||||||
|
template<typename T>
|
||||||
|
static auto subindex(const T& x)->decltype(Model::subindex(x))
|
||||||
|
{return Model::subindex(x);}
|
||||||
template<typename,bool>
|
template<typename,bool>
|
||||||
friend class detail::iterator_impl;
|
friend class detail::iterator_impl;
|
||||||
template<typename,typename>
|
template<typename,typename>
|
||||||
@@ -183,7 +199,7 @@ public:
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
const_local_iterator<T> cend()const noexcept{return end<T>();}
|
const_local_iterator<T> cend()const noexcept{return end<T>();}
|
||||||
|
|
||||||
const std::type_info& type_info()const{return *it->first;}
|
const type_index& type_info()const{return it->first;}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class poly_collection;
|
friend class poly_collection;
|
||||||
@@ -377,21 +393,38 @@ public:
|
|||||||
|
|
||||||
/* construct/destroy/copy */
|
/* construct/destroy/copy */
|
||||||
|
|
||||||
poly_collection()=default;
|
poly_collection(){initialize_map();};
|
||||||
|
|
||||||
poly_collection(const poly_collection&)=default;
|
poly_collection(const poly_collection&)=default;
|
||||||
poly_collection(poly_collection&&)=default;
|
|
||||||
|
poly_collection(poly_collection&& x):poly_collection{x.get_allocator()}
|
||||||
|
{
|
||||||
|
map.swap(x.map);
|
||||||
|
}
|
||||||
|
|
||||||
explicit poly_collection(const allocator_type& al):
|
explicit poly_collection(const allocator_type& al):
|
||||||
map{segment_map_allocator_type{al}}{}
|
map{segment_map_allocator_type{al}}
|
||||||
|
{
|
||||||
|
initialize_map();
|
||||||
|
}
|
||||||
|
|
||||||
poly_collection(const poly_collection& x,const allocator_type& al):
|
poly_collection(const poly_collection& x,const allocator_type& al):
|
||||||
map{x.map,segment_map_allocator_type{al}}{}
|
map{x.map,segment_map_allocator_type{al}}{}
|
||||||
poly_collection(poly_collection&& x,const allocator_type& al):
|
|
||||||
map{std::move(x.map),segment_map_allocator_type{al}}{}
|
poly_collection(poly_collection&& x,const allocator_type& al):map{al}
|
||||||
|
{
|
||||||
|
segment_map m2{x.get_allocator()};
|
||||||
|
initialize_map(m2);
|
||||||
|
m2.swap(x.map);
|
||||||
|
segment_map m3{std::move(m2),al};
|
||||||
|
map.swap(m3);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename InputIterator>
|
template<typename InputIterator>
|
||||||
poly_collection(
|
poly_collection(
|
||||||
InputIterator first,InputIterator last,
|
InputIterator first,InputIterator last,
|
||||||
const allocator_type& al=allocator_type{}):
|
const allocator_type& al=allocator_type{}):
|
||||||
map{segment_map_allocator_type{al}}
|
poly_collection{segment_map_allocator_type{al}}
|
||||||
{
|
{
|
||||||
this->insert(first,last);
|
this->insert(first,last);
|
||||||
}
|
}
|
||||||
@@ -399,37 +432,53 @@ public:
|
|||||||
// TODO: what to do with initializer_list?
|
// TODO: what to do with initializer_list?
|
||||||
|
|
||||||
poly_collection& operator=(const poly_collection&)=default;
|
poly_collection& operator=(const poly_collection&)=default;
|
||||||
poly_collection& operator=(poly_collection&&)=default;
|
|
||||||
|
poly_collection& operator=(poly_collection&& x)
|
||||||
|
{
|
||||||
|
if(this!=std::addressof(x)){
|
||||||
|
segment_map m2{x.get_allocator()};
|
||||||
|
initialize_map(m2);
|
||||||
|
m2.swap(x.map);
|
||||||
|
map=std::move(m2);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
allocator_type get_allocator()const noexcept{return map.get_allocator();}
|
allocator_type get_allocator()const noexcept{return map.get_allocator();}
|
||||||
|
|
||||||
/* type registration */
|
/* type registration (open collections only) */
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename... T,
|
typename... T,
|
||||||
for_all<enable_if_acceptable<T>...> =nullptr
|
for_all<enable_if_acceptable<T>...> =nullptr,
|
||||||
|
typename M=Model,
|
||||||
|
enable_if_open_collection<M> =nullptr
|
||||||
>
|
>
|
||||||
void register_types()
|
void register_types()
|
||||||
{
|
{
|
||||||
/* http://twitter.com/SeanParent/status/558765089294020609 */
|
mp11::mp_for_each<
|
||||||
|
mp11::mp_transform<mp11::mp_identity,mp11::mp_list<T...>>
|
||||||
using seq=int[1+sizeof...(T)];
|
>(create_segment{map});
|
||||||
(void)seq{
|
|
||||||
0,
|
|
||||||
(map.insert(
|
|
||||||
typeid(T),segment_type::template make<T>(get_allocator())),0)...
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_registered(const std::type_info& info)const
|
template<
|
||||||
|
typename M=Model,
|
||||||
|
enable_if_open_collection<M> =nullptr
|
||||||
|
>
|
||||||
|
bool is_registered(const type_index& info)const
|
||||||
{
|
{
|
||||||
return map.find(info)!=map.end();
|
return map.find(info)!=map.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
template<
|
||||||
|
typename T,
|
||||||
|
enable_if_acceptable<T> =nullptr,
|
||||||
|
typename M=Model,
|
||||||
|
enable_if_open_collection<M> =nullptr
|
||||||
|
>
|
||||||
bool is_registered()const
|
bool is_registered()const
|
||||||
{
|
{
|
||||||
return is_registered(typeid(T));
|
return is_registered(index<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* iterators */
|
/* iterators */
|
||||||
@@ -441,60 +490,60 @@ public:
|
|||||||
const_iterator cbegin()const noexcept{return begin();}
|
const_iterator cbegin()const noexcept{return begin();}
|
||||||
const_iterator cend()const noexcept{return end();}
|
const_iterator cend()const noexcept{return end();}
|
||||||
|
|
||||||
local_base_iterator begin(const std::type_info& info)
|
local_base_iterator begin(const type_index& info)
|
||||||
{
|
{
|
||||||
auto it=get_map_iterator_for(info);
|
auto it=get_map_iterator_for(info);
|
||||||
return {it,segment(it).begin()};
|
return {it,segment(it).begin()};
|
||||||
}
|
}
|
||||||
|
|
||||||
local_base_iterator end(const std::type_info& info)
|
local_base_iterator end(const type_index& info)
|
||||||
{
|
{
|
||||||
auto it=get_map_iterator_for(info);
|
auto it=get_map_iterator_for(info);
|
||||||
return {it,segment(it).end()};
|
return {it,segment(it).end()};
|
||||||
}
|
}
|
||||||
|
|
||||||
const_local_base_iterator begin(const std::type_info& info)const
|
const_local_base_iterator begin(const type_index& info)const
|
||||||
{
|
{
|
||||||
auto it=get_map_iterator_for(info);
|
auto it=get_map_iterator_for(info);
|
||||||
return {it,segment(it).begin()};
|
return {it,segment(it).begin()};
|
||||||
}
|
}
|
||||||
|
|
||||||
const_local_base_iterator end(const std::type_info& info)const
|
const_local_base_iterator end(const type_index& info)const
|
||||||
{
|
{
|
||||||
auto it=get_map_iterator_for(info);
|
auto it=get_map_iterator_for(info);
|
||||||
return {it,segment(it).end()};
|
return {it,segment(it).end()};
|
||||||
}
|
}
|
||||||
|
|
||||||
const_local_base_iterator cbegin(const std::type_info& info)const
|
const_local_base_iterator cbegin(const type_index& info)const
|
||||||
{return begin(info);}
|
{return begin(info);}
|
||||||
const_local_base_iterator cend(const std::type_info& info)const
|
const_local_base_iterator cend(const type_index& info)const
|
||||||
{return end(info);}
|
{return end(info);}
|
||||||
|
|
||||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||||
local_iterator<T> begin()
|
local_iterator<T> begin()
|
||||||
{
|
{
|
||||||
auto it=get_map_iterator_for(typeid(T));
|
auto it=get_map_iterator_for(index<T>());
|
||||||
return {it,segment(it).template begin<T>()};
|
return {it,segment(it).template begin<T>()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||||
local_iterator<T> end()
|
local_iterator<T> end()
|
||||||
{
|
{
|
||||||
auto it=get_map_iterator_for(typeid(T));
|
auto it=get_map_iterator_for(index<T>());
|
||||||
return {it,segment(it).template end<T>()};
|
return {it,segment(it).template end<T>()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||||
const_local_iterator<T> begin()const
|
const_local_iterator<T> begin()const
|
||||||
{
|
{
|
||||||
auto it=get_map_iterator_for(typeid(T));
|
auto it=get_map_iterator_for(index<T>());
|
||||||
return {it,segment(it).template begin<T>()};
|
return {it,segment(it).template begin<T>()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||||
const_local_iterator<T> end()const
|
const_local_iterator<T> end()const
|
||||||
{
|
{
|
||||||
auto it=get_map_iterator_for(typeid(T));
|
auto it=get_map_iterator_for(index<T>());
|
||||||
return {it,segment(it).template end<T>()};
|
return {it,segment(it).template end<T>()};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,21 +553,22 @@ public:
|
|||||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||||
const_local_iterator<T> cend()const{return end<T>();}
|
const_local_iterator<T> cend()const{return end<T>();}
|
||||||
|
|
||||||
base_segment_info segment(const std::type_info& info)
|
base_segment_info segment(const type_index& info)
|
||||||
{
|
{
|
||||||
return get_map_iterator_for(info);
|
return get_map_iterator_for(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
const_base_segment_info segment(const std::type_info& info)const
|
const_base_segment_info segment(const type_index& info)const
|
||||||
{
|
{
|
||||||
return get_map_iterator_for(info);
|
return get_map_iterator_for(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||||
segment_info<T> segment(){return get_map_iterator_for(typeid(T));}
|
segment_info<T> segment(){return get_map_iterator_for(index<T>());}
|
||||||
|
|
||||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||||
const_segment_info<T> segment()const{return get_map_iterator_for(typeid(T));}
|
const_segment_info<T> segment()const
|
||||||
|
{return get_map_iterator_for(index<T>());}
|
||||||
|
|
||||||
segment_traversal_info segment_traversal()noexcept{return map;}
|
segment_traversal_info segment_traversal()noexcept{return map;}
|
||||||
const_segment_traversal_info segment_traversal()const noexcept{return map;}
|
const_segment_traversal_info segment_traversal()const noexcept{return map;}
|
||||||
@@ -531,7 +581,7 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty(const std::type_info& info)const
|
bool empty(const type_index& info)const
|
||||||
{
|
{
|
||||||
return segment(get_map_iterator_for(info)).empty();
|
return segment(get_map_iterator_for(info)).empty();
|
||||||
}
|
}
|
||||||
@@ -539,7 +589,7 @@ public:
|
|||||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||||
bool empty()const
|
bool empty()const
|
||||||
{
|
{
|
||||||
return segment(get_map_iterator_for(typeid(T))).template empty<T>();
|
return segment(get_map_iterator_for(index<T>())).template empty<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type size()const noexcept
|
size_type size()const noexcept
|
||||||
@@ -549,7 +599,7 @@ public:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type size(const std::type_info& info)const
|
size_type size(const type_index& info)const
|
||||||
{
|
{
|
||||||
return segment(get_map_iterator_for(info)).size();
|
return segment(get_map_iterator_for(info)).size();
|
||||||
}
|
}
|
||||||
@@ -557,10 +607,10 @@ public:
|
|||||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||||
size_type size()const
|
size_type size()const
|
||||||
{
|
{
|
||||||
return segment(get_map_iterator_for(typeid(T))).template size<T>();
|
return segment(get_map_iterator_for(index<T>())).template size<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type max_size(const std::type_info& info)const
|
size_type max_size(const type_index& info)const
|
||||||
{
|
{
|
||||||
return segment(get_map_iterator_for(info)).max_size();
|
return segment(get_map_iterator_for(info)).max_size();
|
||||||
}
|
}
|
||||||
@@ -568,10 +618,10 @@ public:
|
|||||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||||
size_type max_size()const
|
size_type max_size()const
|
||||||
{
|
{
|
||||||
return segment(get_map_iterator_for(typeid(T))).template max_size<T>();
|
return segment(get_map_iterator_for(index<T>())).template max_size<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_type capacity(const std::type_info& info)const
|
size_type capacity(const type_index& info)const
|
||||||
{
|
{
|
||||||
return segment(get_map_iterator_for(info)).capacity();
|
return segment(get_map_iterator_for(info)).capacity();
|
||||||
}
|
}
|
||||||
@@ -579,7 +629,7 @@ public:
|
|||||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||||
size_type capacity()const
|
size_type capacity()const
|
||||||
{
|
{
|
||||||
return segment(get_map_iterator_for(typeid(T))).template capacity<T>();
|
return segment(get_map_iterator_for(index<T>())).template capacity<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reserve(size_type n)
|
void reserve(size_type n)
|
||||||
@@ -587,7 +637,7 @@ public:
|
|||||||
for(auto& x:map)x.second.reserve(n);
|
for(auto& x:map)x.second.reserve(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void reserve(const std::type_info& info,size_type n)
|
void reserve(const type_index& info,size_type n)
|
||||||
{
|
{
|
||||||
segment(get_map_iterator_for(info)).reserve(n);
|
segment(get_map_iterator_for(info)).reserve(n);
|
||||||
}
|
}
|
||||||
@@ -605,7 +655,7 @@ public:
|
|||||||
for(auto& x:map)x.second.shrink_to_fit();
|
for(auto& x:map)x.second.shrink_to_fit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void shrink_to_fit(const std::type_info& info)
|
void shrink_to_fit(const type_index& info)
|
||||||
{
|
{
|
||||||
segment(get_map_iterator_for(info)).shrink_to_fit();
|
segment(get_map_iterator_for(info)).shrink_to_fit();
|
||||||
}
|
}
|
||||||
@@ -613,7 +663,7 @@ public:
|
|||||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||||
void shrink_to_fit()
|
void shrink_to_fit()
|
||||||
{
|
{
|
||||||
segment(get_map_iterator_for(typeid(T))).template shrink_to_fit<T>();
|
segment(get_map_iterator_for(index<T>())).template shrink_to_fit<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* modifiers */
|
/* modifiers */
|
||||||
@@ -653,7 +703,7 @@ public:
|
|||||||
local_base_iterator
|
local_base_iterator
|
||||||
emplace_pos(const_local_base_iterator pos,Args&&... args)
|
emplace_pos(const_local_base_iterator pos,Args&&... args)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(pos.type_info()==typeid(T));
|
BOOST_ASSERT(pos.type_info()==index<T>());
|
||||||
return {
|
return {
|
||||||
pos.mapit,
|
pos.mapit,
|
||||||
pos.segment().template emplace<T>(pos.base(),std::forward<Args>(args)...)
|
pos.segment().template emplace<T>(pos.base(),std::forward<Args>(args)...)
|
||||||
@@ -709,7 +759,7 @@ public:
|
|||||||
nonconst_version<local_iterator_impl<BaseIterator>>
|
nonconst_version<local_iterator_impl<BaseIterator>>
|
||||||
insert(local_iterator_impl<BaseIterator> pos,T&& x)
|
insert(local_iterator_impl<BaseIterator> pos,T&& x)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(pos.type_info()==subtypeid(x));
|
BOOST_ASSERT(pos.type_info()==subindex(x));
|
||||||
return {
|
return {
|
||||||
pos.mapit,
|
pos.mapit,
|
||||||
pos.segment().insert(pos.base(),std::forward<T>(x))
|
pos.segment().insert(pos.base(),std::forward<T>(x))
|
||||||
@@ -846,7 +896,7 @@ public:
|
|||||||
size_type n=0;
|
size_type n=0;
|
||||||
|
|
||||||
for(;first!=last;++first){
|
for(;first!=last;++first){
|
||||||
BOOST_ASSERT(pos.type_info()==subtypeid(*first));
|
BOOST_ASSERT(pos.type_info()==subindex(*first));
|
||||||
it=std::next(seg.insert(it,*first));
|
it=std::next(seg.insert(it,*first));
|
||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
@@ -940,7 +990,7 @@ public:
|
|||||||
for(auto& x:map)x.second.clear();
|
for(auto& x:map)x.second.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear(const std::type_info& info)
|
void clear(const type_index& info)
|
||||||
{
|
{
|
||||||
segment(get_map_iterator_for(info)).clear();
|
segment(get_map_iterator_for(info)).clear();
|
||||||
}
|
}
|
||||||
@@ -948,7 +998,7 @@ public:
|
|||||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
segment(get_map_iterator_for(typeid(T))).template clear<T>();
|
segment(get_map_iterator_for(index<T>())).template clear<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap(poly_collection& x){map.swap(x.map);}
|
void swap(poly_collection& x){map.swap(x.map);}
|
||||||
@@ -958,6 +1008,71 @@ private:
|
|||||||
friend bool operator==(
|
friend bool operator==(
|
||||||
const poly_collection<M,A>&,const poly_collection<M,A>&);
|
const poly_collection<M,A>&,const poly_collection<M,A>&);
|
||||||
|
|
||||||
|
struct create_segment
|
||||||
|
{
|
||||||
|
segment_map& map;
|
||||||
|
|
||||||
|
template<typename TI>
|
||||||
|
void operator()(TI)
|
||||||
|
{
|
||||||
|
using T=typename TI::type;
|
||||||
|
map.insert(
|
||||||
|
index<T>(),segment_type::template make<T>(map.get_allocator()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void initialize_map(){initialize_map(map);}
|
||||||
|
|
||||||
|
void initialize_map(segment_map& m)
|
||||||
|
{
|
||||||
|
initialize_map(
|
||||||
|
m,
|
||||||
|
std::integral_constant<
|
||||||
|
bool,detail::is_closed_collection<Model>::value>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialize_map(segment_map&,std::false_type /* open collection */){}
|
||||||
|
|
||||||
|
void initialize_map(segment_map& m,std::true_type /* closed collection */)
|
||||||
|
{
|
||||||
|
mp11::mp_for_each<
|
||||||
|
mp11::mp_transform<
|
||||||
|
mp11::mp_identity,typename Model::acceptable_type_list
|
||||||
|
>
|
||||||
|
>(create_segment{m});
|
||||||
|
}
|
||||||
|
|
||||||
|
static const std::type_info& type_info(const std::type_info& info)
|
||||||
|
{
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TypeIndex>
|
||||||
|
static const std::type_info& type_info(const TypeIndex& info)
|
||||||
|
{
|
||||||
|
return typeid(void); /* no way to recover the type from its index */
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static const std::type_info& subtype_info(const T& x)
|
||||||
|
{
|
||||||
|
return subtype_info(x,std::is_same<type_index,std::type_info>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static const std::type_info& subtype_info(
|
||||||
|
const T& x,std::true_type /* type_index is std::type_info*/)
|
||||||
|
{
|
||||||
|
return subindex(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static const std::type_info& subtype_info(
|
||||||
|
const T& x,std::false_type /* type_index is not std::type_info*/)
|
||||||
|
{
|
||||||
|
return Model::subtype_info(x);
|
||||||
|
}
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename T,
|
typename T,
|
||||||
enable_if_acceptable<T> =nullptr,
|
enable_if_acceptable<T> =nullptr,
|
||||||
@@ -965,12 +1080,12 @@ private:
|
|||||||
>
|
>
|
||||||
const_segment_map_iterator get_map_iterator_for(const T& x)
|
const_segment_map_iterator get_map_iterator_for(const T& x)
|
||||||
{
|
{
|
||||||
const auto& id=subtypeid(x);
|
const auto& id=subindex(x);
|
||||||
auto it=map.find(id);
|
auto it=map.find(id);
|
||||||
if(it!=map.end())return it;
|
if(it!=map.end())return it;
|
||||||
else if(id!=typeid(T))throw unregistered_type{id};
|
else if(id!=index<T>())throw unregistered_type{subtype_info(x)};
|
||||||
else return map.insert(
|
else return map.insert(
|
||||||
typeid(T),segment_type::template make<T>(get_allocator())).first;
|
index<T>(),segment_type::template make<T>(get_allocator())).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<
|
template<
|
||||||
@@ -980,10 +1095,10 @@ private:
|
|||||||
>
|
>
|
||||||
const_segment_map_iterator get_map_iterator_for(const T&)
|
const_segment_map_iterator get_map_iterator_for(const T&)
|
||||||
{
|
{
|
||||||
auto it=map.find(typeid(T));
|
auto it=map.find(index<T>());
|
||||||
if(it!=map.end())return it;
|
if(it!=map.end())return it;
|
||||||
else return map.insert(
|
else return map.insert(
|
||||||
typeid(T),segment_type::template make<T>(get_allocator())).first;
|
index<T>(),segment_type::template make<T>(get_allocator())).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<
|
template<
|
||||||
@@ -993,9 +1108,9 @@ private:
|
|||||||
>
|
>
|
||||||
const_segment_map_iterator get_map_iterator_for(const T& x)const
|
const_segment_map_iterator get_map_iterator_for(const T& x)const
|
||||||
{
|
{
|
||||||
const auto& id=subtypeid(x);
|
const auto& id=subindex(x);
|
||||||
auto it=map.find(id);
|
auto it=map.find(id);
|
||||||
if(it==map.end())throw unregistered_type{id};
|
if(it==map.end())throw unregistered_type{subtype_info(x)};
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1016,7 +1131,7 @@ private:
|
|||||||
const_segment_map_iterator get_map_iterator_for(
|
const_segment_map_iterator get_map_iterator_for(
|
||||||
const T& x,const segment_type& seg)
|
const T& x,const segment_type& seg)
|
||||||
{
|
{
|
||||||
const auto& id=subtypeid(x);
|
const auto& id=subindex(x);
|
||||||
auto it=map.find(id);
|
auto it=map.find(id);
|
||||||
if(it!=map.end())return it;
|
if(it!=map.end())return it;
|
||||||
else return map.insert(
|
else return map.insert(
|
||||||
@@ -1026,23 +1141,22 @@ private:
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
const_segment_map_iterator get_map_iterator_for()
|
const_segment_map_iterator get_map_iterator_for()
|
||||||
{
|
{
|
||||||
auto it=map.find(typeid(T));
|
auto it=map.find(index<T>());
|
||||||
if(it!=map.end())return it;
|
if(it!=map.end())return it;
|
||||||
else return map.insert(
|
else return map.insert(
|
||||||
typeid(T),segment_type::template make<T>(get_allocator())).first;
|
index<T>(),segment_type::template make<T>(get_allocator())).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
const_segment_map_iterator get_map_iterator_for(const std::type_info& info)
|
const_segment_map_iterator get_map_iterator_for(const type_index& info)
|
||||||
{
|
{
|
||||||
return const_cast<const poly_collection*>(this)->
|
return const_cast<const poly_collection*>(this)->
|
||||||
get_map_iterator_for(info);
|
get_map_iterator_for(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
const_segment_map_iterator get_map_iterator_for(
|
const_segment_map_iterator get_map_iterator_for(const type_index& info)const
|
||||||
const std::type_info& info)const
|
|
||||||
{
|
{
|
||||||
auto it=map.find(info);
|
auto it=map.find(info);
|
||||||
if(it==map.end())throw unregistered_type{info};
|
if(it==map.end())throw unregistered_type{type_info(info)};
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1067,7 +1181,7 @@ private:
|
|||||||
>
|
>
|
||||||
segment_base_iterator push_back(segment_type& seg,T&& x)
|
segment_base_iterator push_back(segment_type& seg,T&& x)
|
||||||
{
|
{
|
||||||
return subtypeid(x)==typeid(T)?
|
return subindex(x)==index<T>()?
|
||||||
seg.push_back_terminal(std::forward<T>(x)):
|
seg.push_back_terminal(std::forward<T>(x)):
|
||||||
seg.push_back(std::forward<T>(x));
|
seg.push_back(std::forward<T>(x));
|
||||||
}
|
}
|
||||||
@@ -1090,7 +1204,7 @@ private:
|
|||||||
static segment_base_iterator local_insert(
|
static segment_base_iterator local_insert(
|
||||||
segment_type& seg,BaseIterator pos,U&& x)
|
segment_type& seg,BaseIterator pos,U&& x)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(subtypeid(x)==typeid(T));
|
BOOST_ASSERT(subindex(x)==index<T>());
|
||||||
return seg.insert(pos,std::forward<U>(x));
|
return seg.insert(pos,std::forward<U>(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1102,7 +1216,7 @@ private:
|
|||||||
static segment_base_iterator local_insert(
|
static segment_base_iterator local_insert(
|
||||||
segment_type& seg,BaseIterator pos,U&& x)
|
segment_type& seg,BaseIterator pos,U&& x)
|
||||||
{
|
{
|
||||||
if(subtypeid(x)==typeid(T))return seg.insert(pos,std::forward<U>(x));
|
if(subindex(x)==index<T>())return seg.insert(pos,std::forward<U>(x));
|
||||||
else return seg.template emplace<T>(pos,std::forward<U>(x));
|
else return seg.template emplace<T>(pos,std::forward<U>(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1143,7 +1257,7 @@ bool operator==(
|
|||||||
const auto &mapx=x.map,&mapy=y.map;
|
const auto &mapx=x.map,&mapy=y.map;
|
||||||
for(const auto& p:mapx){
|
for(const auto& p:mapx){
|
||||||
auto ss=p.second.size();
|
auto ss=p.second.size();
|
||||||
auto it=mapy.find(*p.first);
|
auto it=mapy.find(p.first);
|
||||||
if(it==mapy.end()?ss!=0:p.second!=it->second)return false;
|
if(it==mapy.end()?ss!=0:p.second!=it->second)return false;
|
||||||
s+=ss;
|
s+=ss;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2018 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -175,6 +175,12 @@ public:
|
|||||||
impl<U>().nv_insert(it,*static_cast<const U*>(subaddress(x))));
|
impl<U>().nv_insert(it,*static_cast<const U*>(subaddress(x))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename U,typename T>
|
||||||
|
base_iterator insert(iterator<U> it,const T& x)
|
||||||
|
{
|
||||||
|
return insert(const_iterator<U>{it},x);
|
||||||
|
}
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename T,
|
typename T,
|
||||||
typename std::enable_if<
|
typename std::enable_if<
|
||||||
@@ -198,6 +204,17 @@ public:
|
|||||||
impl<U>().nv_insert(it,std::move(*static_cast<U*>(subaddress(x)))));
|
impl<U>().nv_insert(it,std::move(*static_cast<U*>(subaddress(x)))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename U,typename T,
|
||||||
|
typename std::enable_if<
|
||||||
|
!std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
|
||||||
|
>::type* =nullptr
|
||||||
|
>
|
||||||
|
base_iterator insert(iterator<U> it,T&& x)
|
||||||
|
{
|
||||||
|
return insert(const_iterator<U>{it},std::move(x));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename InputIterator>
|
template<typename InputIterator>
|
||||||
base_iterator insert(InputIterator first,InputIterator last)
|
base_iterator insert(InputIterator first,InputIterator last)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_POLY_COLLECTION_DETAIL_SEGMENT_MAP_HPP
|
||||||
|
#define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_MAP_HPP
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/poly_collection/detail/size_t_map.hpp>
|
||||||
|
#include <boost/poly_collection/detail/type_info_map.hpp>
|
||||||
|
|
||||||
|
namespace boost{
|
||||||
|
|
||||||
|
namespace poly_collection{
|
||||||
|
|
||||||
|
namespace detail{
|
||||||
|
|
||||||
|
template<typename Key> struct segment_map_helper;
|
||||||
|
|
||||||
|
template<> struct segment_map_helper<std::type_info>
|
||||||
|
{
|
||||||
|
template<typename... Args> using fn=type_info_map<Args...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> struct segment_map_helper<std::size_t>
|
||||||
|
{
|
||||||
|
template<typename... Args> using fn=size_t_map<Args...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Key,typename... Args>
|
||||||
|
using segment_map=typename segment_map_helper<Key>::template fn<Args...>;
|
||||||
|
|
||||||
|
} /* namespace poly_collection::detail */
|
||||||
|
|
||||||
|
} /* namespace poly_collection */
|
||||||
|
|
||||||
|
} /* namespace boost */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2017 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -13,11 +13,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
#include <boost/iterator/iterator_facade.hpp>
|
#include <boost/iterator/iterator_facade.hpp>
|
||||||
#include <boost/poly_collection/detail/iterator_traits.hpp>
|
#include <boost/poly_collection/detail/iterator_traits.hpp>
|
||||||
#include <typeinfo>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#if defined(BOOST_MSVC)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4714) /* marked as __forceinline not inlined */
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace boost{
|
namespace boost{
|
||||||
|
|
||||||
namespace poly_collection{
|
namespace poly_collection{
|
||||||
@@ -32,16 +37,17 @@ class segment_splitter
|
|||||||
using traits=iterator_traits<PolyCollectionIterator>;
|
using traits=iterator_traits<PolyCollectionIterator>;
|
||||||
using local_base_iterator=typename traits::local_base_iterator;
|
using local_base_iterator=typename traits::local_base_iterator;
|
||||||
using base_segment_info_iterator=typename traits::base_segment_info_iterator;
|
using base_segment_info_iterator=typename traits::base_segment_info_iterator;
|
||||||
|
using type_index=typename traits::type_index;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct info
|
struct info
|
||||||
{
|
{
|
||||||
const std::type_info& type_info()const noexcept{return *pinfo_;}
|
const type_index& type_info()const noexcept{return info_;}
|
||||||
local_base_iterator begin()const noexcept{return begin_;}
|
local_base_iterator begin()const noexcept{return begin_;}
|
||||||
local_base_iterator end()const noexcept{return end_;}
|
local_base_iterator end()const noexcept{return end_;}
|
||||||
|
|
||||||
const std::type_info* pinfo_;
|
const type_index& info_;
|
||||||
local_base_iterator begin_,end_;
|
local_base_iterator begin_,end_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iterator:iterator_facade<iterator,info,std::input_iterator_tag,info>
|
struct iterator:iterator_facade<iterator,info,std::input_iterator_tag,info>
|
||||||
@@ -65,7 +71,7 @@ public:
|
|||||||
info dereference()const noexcept
|
info dereference()const noexcept
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
&it->type_info(),
|
it->type_info(),
|
||||||
it==traits::base_segment_info_iterator_from(*pfirst)?
|
it==traits::base_segment_info_iterator_from(*pfirst)?
|
||||||
traits::local_base_iterator_from(*pfirst):it->begin(),
|
traits::local_base_iterator_from(*pfirst):it->begin(),
|
||||||
it==traits::base_segment_info_iterator_from(*plast)?
|
it==traits::base_segment_info_iterator_from(*plast)?
|
||||||
@@ -111,7 +117,7 @@ segment_split(
|
|||||||
/* equivalent to for(auto i:segment_split(first,last))f(i) */
|
/* equivalent to for(auto i:segment_split(first,last))f(i) */
|
||||||
|
|
||||||
template<typename PolyCollectionIterator,typename F>
|
template<typename PolyCollectionIterator,typename F>
|
||||||
void for_each_segment(
|
BOOST_FORCEINLINE void for_each_segment(
|
||||||
const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
|
const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
|
||||||
{
|
{
|
||||||
using traits=iterator_traits<PolyCollectionIterator>;
|
using traits=iterator_traits<PolyCollectionIterator>;
|
||||||
@@ -125,20 +131,20 @@ void for_each_segment(
|
|||||||
|
|
||||||
if(sfirst!=slast){
|
if(sfirst!=slast){
|
||||||
for(;;){
|
for(;;){
|
||||||
f(info{&sfirst->type_info(),lbfirst,sfirst->end()});
|
f(info{sfirst->type_info(),lbfirst,sfirst->end()});
|
||||||
++sfirst;
|
++sfirst;
|
||||||
if(sfirst==slast)break;
|
if(sfirst==slast)break;
|
||||||
lbfirst=sfirst->begin();
|
lbfirst=sfirst->begin();
|
||||||
}
|
}
|
||||||
if(sfirst!=send)f(info{&sfirst->type_info(),sfirst->begin(),lblast});
|
if(sfirst!=send)f(info{sfirst->type_info(),sfirst->begin(),lblast});
|
||||||
}
|
}
|
||||||
else if(sfirst!=send){
|
else if(sfirst!=send){
|
||||||
f(info{&sfirst->type_info(),lbfirst,lblast});
|
f(info{sfirst->type_info(),lbfirst,lblast});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
template<typename PolyCollectionIterator,typename F>
|
template<typename PolyCollectionIterator,typename F>
|
||||||
void for_each_segment(
|
BOOST_FORCEINLINE void for_each_segment(
|
||||||
const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
|
const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
|
||||||
{
|
{
|
||||||
for(auto i:segment_split(first,last))f(i);
|
for(auto i:segment_split(first,last))f(i);
|
||||||
@@ -151,4 +157,8 @@ void for_each_segment(
|
|||||||
|
|
||||||
} /* namespace boost */
|
} /* namespace boost */
|
||||||
|
|
||||||
|
#if defined(BOOST_MSVC)
|
||||||
|
#pragma warning(pop) /* C4714 */
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_POLY_COLLECTION_DETAIL_SIZE_T_MAP_HPP
|
||||||
|
#define BOOST_POLY_COLLECTION_DETAIL_SIZE_T_MAP_HPP
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace boost{
|
||||||
|
|
||||||
|
namespace poly_collection{
|
||||||
|
|
||||||
|
namespace detail{
|
||||||
|
|
||||||
|
/* Map-like wrapper over a vector of std::pair<std::size_t,T>. It is required
|
||||||
|
* that the first member of the i-th element be i, which implies that
|
||||||
|
* insert(i,x) must executed in increasing order of i.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename T,typename Allocator>
|
||||||
|
class size_t_map
|
||||||
|
{
|
||||||
|
using vector_type=std::vector<
|
||||||
|
std::pair<std::size_t,T>,
|
||||||
|
typename std::allocator_traits<Allocator>::template
|
||||||
|
rebind_alloc<std::pair<std::size_t,T>>
|
||||||
|
>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using key_type=std::size_t;
|
||||||
|
using mapped_type=T;
|
||||||
|
using value_type=typename vector_type::value_type;
|
||||||
|
using allocator_type=typename vector_type::allocator_type;
|
||||||
|
using iterator=typename vector_type::iterator;
|
||||||
|
using const_iterator=typename vector_type::const_iterator;
|
||||||
|
|
||||||
|
size_t_map()=default;
|
||||||
|
size_t_map(const size_t_map& x)=default;
|
||||||
|
size_t_map(size_t_map&& x)=default;
|
||||||
|
size_t_map(const allocator_type& al):v{al}{}
|
||||||
|
size_t_map(const size_t_map& x,const allocator_type& al):v{x.v,al}{}
|
||||||
|
size_t_map(size_t_map&& x,const allocator_type& al):v{std::move(x.v),al}{}
|
||||||
|
size_t_map& operator=(const size_t_map& x)=default;
|
||||||
|
size_t_map& operator=(size_t_map&& x)=default;
|
||||||
|
|
||||||
|
allocator_type get_allocator()const noexcept{return v.get_allocator();}
|
||||||
|
|
||||||
|
iterator begin()noexcept{return v.begin();}
|
||||||
|
iterator end()noexcept{return v.end();}
|
||||||
|
const_iterator begin()const noexcept{return v.begin();}
|
||||||
|
const_iterator end()const noexcept{return v.end();}
|
||||||
|
const_iterator cbegin()const noexcept{return v.cbegin();}
|
||||||
|
const_iterator cend()const noexcept{return v.cend();}
|
||||||
|
|
||||||
|
const_iterator find(const key_type& key)const
|
||||||
|
{
|
||||||
|
if(key<v.size())return v.begin()+key;
|
||||||
|
else return v.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename P>
|
||||||
|
std::pair<iterator,bool> insert(const key_type& key,P&& x)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(key==v.size());
|
||||||
|
v.emplace_back(key,std::forward<P>(x));
|
||||||
|
return {v.end()-1,true};
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(size_t_map& x){v.swap(x.v);}
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector_type v;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T,typename Allocator>
|
||||||
|
void swap(size_t_map<T,Allocator>& x,size_t_map<T,Allocator>& y)
|
||||||
|
{
|
||||||
|
x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace poly_collection::detail */
|
||||||
|
|
||||||
|
} /* namespace poly_collection */
|
||||||
|
|
||||||
|
} /* namespace boost */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
#include <boost/detail/workaround.hpp>
|
#include <boost/detail/workaround.hpp>
|
||||||
#include <boost/iterator/iterator_facade.hpp>
|
#include <boost/iterator/iterator_facade.hpp>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
@@ -63,32 +64,7 @@ public:
|
|||||||
stride_iterator& operator=(Value* p_)noexcept{p=p_;return *this;}
|
stride_iterator& operator=(Value* p_)noexcept{p=p_;return *this;}
|
||||||
operator Value*()const noexcept{return p;}
|
operator Value*()const noexcept{return p;}
|
||||||
|
|
||||||
template<
|
#include <boost/poly_collection/detail/begin_no_sanitize.hpp>
|
||||||
typename DerivedValue,
|
|
||||||
typename std::enable_if<
|
|
||||||
std::is_base_of<Value,DerivedValue>::value&&
|
|
||||||
(std::is_const<Value>::value||!std::is_const<DerivedValue>::value)
|
|
||||||
>::type* =nullptr
|
|
||||||
>
|
|
||||||
explicit stride_iterator(DerivedValue* x)noexcept:
|
|
||||||
p{x},stride_{sizeof(DerivedValue)}{}
|
|
||||||
|
|
||||||
#if BOOST_WORKAROUND(BOOST_GCC_VERSION,>=40900)||\
|
|
||||||
BOOST_WORKAROUND(BOOST_CLANG,>=1)&&\
|
|
||||||
(__clang_major__>3 || __clang_major__==3 && __clang_minor__ >= 8)
|
|
||||||
/* https://github.com/boostorg/poly_collection/issues/15 */
|
|
||||||
|
|
||||||
#define BOOST_POLY_COLLECTION_NO_SANITIZE
|
|
||||||
|
|
||||||
/* UBSan seems not to be supported in some environments */
|
|
||||||
#if defined(BOOST_GCC_VERSION)
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wattributes"
|
|
||||||
#elif defined(BOOST_CLANG)
|
|
||||||
#pragma clang diagnostic push
|
|
||||||
#pragma clang diagnostic ignored "-Wattributes"
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template<
|
template<
|
||||||
typename DerivedValue,
|
typename DerivedValue,
|
||||||
@@ -97,21 +73,11 @@ public:
|
|||||||
(!std::is_const<Value>::value||std::is_const<DerivedValue>::value)
|
(!std::is_const<Value>::value||std::is_const<DerivedValue>::value)
|
||||||
>::type* =nullptr
|
>::type* =nullptr
|
||||||
>
|
>
|
||||||
#if defined(BOOST_POLY_COLLECTION_NO_SANITIZE)
|
BOOST_POLY_COLLECTION_NO_SANITIZE
|
||||||
__attribute__((no_sanitize("undefined")))
|
|
||||||
#endif
|
|
||||||
explicit operator DerivedValue*()const noexcept
|
explicit operator DerivedValue*()const noexcept
|
||||||
{return static_cast<DerivedValue*>(p);}
|
{return static_cast<DerivedValue*>(p);}
|
||||||
|
|
||||||
#if defined(BOOST_POLY_COLLECTION_NO_SANITIZE)
|
#include <boost/poly_collection/detail/end_no_sanitize.hpp>
|
||||||
#if defined(BOOST_GCC_VERSION)
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#elif defined(BOOST_CLANG)
|
|
||||||
#pragma clang diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef BOOST_POLY_COLLECTION_NO_SANITIZE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::size_t stride()const noexcept{return stride_;}
|
std::size_t stride()const noexcept{return stride_;}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2020 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -32,33 +32,34 @@ namespace detail{
|
|||||||
* std::type_info instances to describe the same type, which implies that
|
* std::type_info instances to describe the same type, which implies that
|
||||||
* std::type_info::operator== and std::type_info::hash_code are costly
|
* std::type_info::operator== and std::type_info::hash_code are costly
|
||||||
* operations typically relying on the stored type name.
|
* operations typically relying on the stored type name.
|
||||||
* type_info_ptr_hash<T> behaves roughly as a
|
* type_info_map<T> behaves roughly as a
|
||||||
* std::unordered_map<std::type_index,T> but maintains an internal cache of
|
* std::unordered_map<std::type_index,T> but maintains an internal cache of
|
||||||
* passed std::type_info instances so that lookup is performed (when there's a
|
* passed std::type_info instances so that lookup is performed (when there's a
|
||||||
* cache hit) without invoking std::type_info equality and hashing ops.
|
* cache hit) without invoking std::type_info equality and hashing ops.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct type_info_ptr_hash
|
struct type_info_hash
|
||||||
{
|
{
|
||||||
std::size_t operator()(const std::type_info* p)const noexcept
|
std::size_t operator()(const std::type_info& i)const noexcept
|
||||||
{return p->hash_code();}
|
{return i.hash_code();}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct type_info_ptr_equal_to
|
struct type_info_equal_to
|
||||||
{
|
{
|
||||||
bool operator()(
|
bool operator()(
|
||||||
const std::type_info* p,const std::type_info* q)const noexcept
|
const std::type_info& i,const std::type_info& j)const noexcept
|
||||||
{return *p==*q;}
|
{return i==j;}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T,typename Allocator>
|
template<typename T,typename Allocator>
|
||||||
class type_info_map
|
class type_info_map
|
||||||
{
|
{
|
||||||
using map_type=std::unordered_map<
|
using map_type=std::unordered_map<
|
||||||
const std::type_info*,T,
|
std::reference_wrapper<const std::type_info>,T,
|
||||||
type_info_ptr_hash,type_info_ptr_equal_to,
|
type_info_hash,type_info_equal_to,
|
||||||
typename std::allocator_traits<Allocator>::template
|
typename std::allocator_traits<Allocator>::template
|
||||||
rebind_alloc<std::pair<const std::type_info* const,T>>
|
rebind_alloc<
|
||||||
|
std::pair<const std::reference_wrapper<const std::type_info>,T>>
|
||||||
>;
|
>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -147,7 +148,7 @@ public:
|
|||||||
{
|
{
|
||||||
auto cit=cache.find(&key);
|
auto cit=cache.find(&key);
|
||||||
if(cit!=cache.end())return cit->second;
|
if(cit!=cache.end())return cit->second;
|
||||||
auto mit=map.find(&key);
|
auto mit=map.find(key);
|
||||||
if(mit!=map.end())cache.insert({&key,mit});
|
if(mit!=map.end())cache.insert({&key,mit});
|
||||||
return mit;
|
return mit;
|
||||||
}
|
}
|
||||||
@@ -156,14 +157,14 @@ public:
|
|||||||
{
|
{
|
||||||
auto cit=cache.find(&key);
|
auto cit=cache.find(&key);
|
||||||
if(cit!=cache.end())return cit->second;
|
if(cit!=cache.end())return cit->second;
|
||||||
return map.find(&key);
|
return map.find(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename P>
|
template<typename P>
|
||||||
std::pair<iterator,bool> insert(const key_type& key,P&& x)
|
std::pair<iterator,bool> insert(const key_type& key,P&& x)
|
||||||
{
|
{
|
||||||
auto c=map.bucket_count();
|
auto c=map.bucket_count();
|
||||||
auto p=map.emplace(&key,std::forward<P>(x));
|
auto p=map.emplace(key,std::forward<P>(x));
|
||||||
if(map.bucket_count()!=c)rebuild_cache();
|
if(map.bucket_count()!=c)rebuild_cache();
|
||||||
cache.insert({&key,p.first});
|
cache.insert({&key,p.first});
|
||||||
return p;
|
return p;
|
||||||
@@ -231,12 +232,12 @@ private:
|
|||||||
|
|
||||||
void build_cache(const cache_type& x)
|
void build_cache(const cache_type& x)
|
||||||
{
|
{
|
||||||
for(const auto& p:x)cache.insert({p.first,map.find(p.first)});
|
for(const auto& p:x)cache.insert({p.first,map.find(*p.first)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void rebuild_cache()
|
void rebuild_cache()
|
||||||
{
|
{
|
||||||
for(auto& p:cache)p.second=map.find(p.first);
|
for(auto& p:cache)p.second=map.find(*p.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
map_type map;
|
map_type map;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2017 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -13,45 +13,145 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <boost/detail/workaround.hpp>
|
||||||
|
#include <boost/mp11/algorithm.hpp>
|
||||||
|
#include <boost/mp11/bind.hpp>
|
||||||
|
#include <boost/mp11/function.hpp>
|
||||||
|
#include <boost/mp11/list.hpp>
|
||||||
|
#include <boost/poly_collection/detail/is_closed_collection.hpp>
|
||||||
#include <boost/poly_collection/detail/functional.hpp>
|
#include <boost/poly_collection/detail/functional.hpp>
|
||||||
#include <boost/poly_collection/detail/iterator_traits.hpp>
|
#include <boost/poly_collection/detail/iterator_traits.hpp>
|
||||||
#include <typeinfo>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#if defined(BOOST_MSVC)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4714) /* marked as __forceinline not inlined */
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace boost{
|
namespace boost{
|
||||||
|
|
||||||
namespace poly_collection{
|
namespace poly_collection{
|
||||||
|
|
||||||
|
struct all_types;
|
||||||
|
|
||||||
namespace detail{
|
namespace detail{
|
||||||
|
|
||||||
/* Given types Ts..., a const std::type_info& info and a local_base_iterator
|
/* If a list of restituted types contain all_types, replaces it with the
|
||||||
* it, we denote by restitute<Ts...>(info,it):
|
* list of all acceptable types of the associated closed collection.
|
||||||
* - a local_iterator<Ti> from it, if info==typeid(Ti) for some Ti in Ts...
|
|
||||||
* - it otherwise.
|
|
||||||
*
|
|
||||||
* Using this notation, restitute_range<Ts...>(f,args...)(s) resolves to
|
|
||||||
* f(restitute<Ts...>(info,begin),restitute<Ts...>(info,end),args...) where
|
|
||||||
* info=s.type_info(), begin=s.begin(), end=s.end().
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename F,typename... Ts>
|
template<typename Model,typename L,typename=void>
|
||||||
|
struct restitution_list_impl
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
!mp11::mp_contains<L,all_types>::value,
|
||||||
|
"all_types can't be used with open collections");
|
||||||
|
|
||||||
|
using type=L;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Model,typename L>
|
||||||
|
struct restitution_list_impl<
|
||||||
|
Model,L,
|
||||||
|
typename std::enable_if<is_closed_collection<Model>::value>::type
|
||||||
|
>
|
||||||
|
{
|
||||||
|
using type=typename std::conditional<
|
||||||
|
mp11::mp_contains<L,all_types>::value,
|
||||||
|
typename Model::acceptable_type_list,
|
||||||
|
L
|
||||||
|
>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Model,typename... Ts>
|
||||||
|
using restitution_list=
|
||||||
|
typename restitution_list_impl<Model,mp11::mp_list<Ts...>>::type;
|
||||||
|
|
||||||
|
/* Calculates if the given types cover the entire set of acceptable types for
|
||||||
|
* the associated closed collection.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace is_total_restitution_impl
|
||||||
|
{
|
||||||
|
template<typename Model,typename L,typename=void>
|
||||||
|
struct helper:std::false_type{};
|
||||||
|
|
||||||
|
#if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
|
||||||
|
template<typename L1,typename L2>
|
||||||
|
struct is_contained;
|
||||||
|
|
||||||
|
template<template <typename...> class L1,typename L2>
|
||||||
|
struct is_contained<L1<>,L2>:std::true_type{};
|
||||||
|
|
||||||
|
template<template <typename...> class L1,typename T,typename... Ts,typename L2>
|
||||||
|
struct is_contained<L1<T,Ts...>,L2>:is_contained<L1<Ts...>,L2>
|
||||||
|
{
|
||||||
|
using super=is_contained<L1<Ts...>,L2>;
|
||||||
|
static constexpr bool value=super::value&&mp11::mp_contains<L2,T>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Model,typename L>
|
||||||
|
struct helper<
|
||||||
|
Model,L,
|
||||||
|
typename std::enable_if<
|
||||||
|
is_closed_collection<Model>::value&&
|
||||||
|
is_contained<typename Model::acceptable_type_list,L>::value
|
||||||
|
>::type
|
||||||
|
>:std::true_type{};
|
||||||
|
#else
|
||||||
|
template<typename Model,typename L>
|
||||||
|
struct helper<
|
||||||
|
Model,L,
|
||||||
|
typename std::enable_if<
|
||||||
|
is_closed_collection<Model>::value&&
|
||||||
|
mp11::mp_all_of_q<
|
||||||
|
typename Model::acceptable_type_list,
|
||||||
|
mp11::mp_bind_front<mp11::mp_contains,L>
|
||||||
|
>::value
|
||||||
|
>::type
|
||||||
|
>:std::true_type{};
|
||||||
|
#endif
|
||||||
|
} /* namespace is_total_restitution_impl */
|
||||||
|
|
||||||
|
template<typename Model,typename L>
|
||||||
|
using is_total_restitution=
|
||||||
|
mp11::mp_bool<is_total_restitution_impl::helper<Model,L>::value>;
|
||||||
|
|
||||||
|
/* Given types Ts..., a const type_index& info and a local_base_iterator
|
||||||
|
* it, we denote by restitute<Ts...>(info,it):
|
||||||
|
* - a local_iterator<Ti> from it, if info==index<Ti>() for some Ti in
|
||||||
|
* Ts...
|
||||||
|
* - it otherwise,
|
||||||
|
* where type_index and index are the type indexing facilities of the
|
||||||
|
* underlying polymorphic model.
|
||||||
|
*
|
||||||
|
* Using this notation, restitute_range<IsTotal,Ts...>(f,args...)(s) resolves
|
||||||
|
* to f(restitute<Ts...>(info,begin),restitute<Ts...>(info,end),args...) where
|
||||||
|
* info=s.type_info(), begin=s.begin(), end=s.end(). If the restitution is
|
||||||
|
* total, f(begin,end,args...) (the base, unrestituted case) is not only
|
||||||
|
* not called ever, but also not instantiated.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename IsTotal,typename F,typename... Ts>
|
||||||
struct restitute_range_class;
|
struct restitute_range_class;
|
||||||
|
|
||||||
template<typename F,typename T,typename... Ts>
|
template<typename IsTotal,typename F,typename T,typename... Ts>
|
||||||
struct restitute_range_class<F,T,Ts...>:
|
struct restitute_range_class<IsTotal,F,T,Ts...>:
|
||||||
restitute_range_class<F,Ts...>
|
restitute_range_class<IsTotal,F,Ts...>
|
||||||
{
|
{
|
||||||
using super=restitute_range_class<F,Ts...>;
|
using super=restitute_range_class<IsTotal,F,Ts...>;
|
||||||
using super::super;
|
using super::super;
|
||||||
|
|
||||||
template<typename SegmentInfo>
|
template<typename SegmentInfo>
|
||||||
auto operator()(SegmentInfo&& s)
|
BOOST_FORCEINLINE auto operator()(SegmentInfo&& s)
|
||||||
->decltype(std::declval<F>()(s.begin(),s.end()))
|
->decltype(std::declval<F>()(s.begin(),s.end()))
|
||||||
{
|
{
|
||||||
using traits=iterator_traits<decltype(s.begin())>;
|
using traits=iterator_traits<decltype(s.begin())>;
|
||||||
using local_iterator=typename traits::template local_iterator<T>;
|
using local_iterator=typename traits::template local_iterator<T>;
|
||||||
|
|
||||||
if(s.type_info()==typeid(T))
|
if(s.type_info()==traits::template index<T>())
|
||||||
return (this->f)(
|
return (this->f)(
|
||||||
local_iterator{s.begin()},local_iterator{s.end()});
|
local_iterator{s.begin()},local_iterator{s.end()});
|
||||||
else
|
else
|
||||||
@@ -59,13 +159,31 @@ struct restitute_range_class<F,T,Ts...>:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename F>
|
template<typename F,typename T>
|
||||||
struct restitute_range_class<F>
|
struct restitute_range_class<std::true_type /* total */,F,T>
|
||||||
{
|
{
|
||||||
restitute_range_class(const F& f):f(f){}
|
restitute_range_class(const F& f):f(f){}
|
||||||
|
|
||||||
template<typename SegmentInfo>
|
template<typename SegmentInfo>
|
||||||
auto operator()(SegmentInfo&& s)
|
BOOST_FORCEINLINE auto operator()(SegmentInfo&& s)
|
||||||
|
->decltype(std::declval<F>()(s.begin(),s.end()))
|
||||||
|
{
|
||||||
|
using traits=iterator_traits<decltype(s.begin())>;
|
||||||
|
using local_iterator=typename traits::template local_iterator<T>;
|
||||||
|
|
||||||
|
return f(local_iterator{s.begin()},local_iterator{s.end()});
|
||||||
|
}
|
||||||
|
|
||||||
|
F f;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
struct restitute_range_class<std::false_type /* non total */,F>
|
||||||
|
{
|
||||||
|
restitute_range_class(const F& f):f(f){}
|
||||||
|
|
||||||
|
template<typename SegmentInfo>
|
||||||
|
BOOST_FORCEINLINE auto operator()(SegmentInfo&& s)
|
||||||
->decltype(std::declval<F>()(s.begin(),s.end()))
|
->decltype(std::declval<F>()(s.begin(),s.end()))
|
||||||
{
|
{
|
||||||
return f(s.begin(),s.end());
|
return f(s.begin(),s.end());
|
||||||
@@ -74,57 +192,88 @@ struct restitute_range_class<F>
|
|||||||
F f;
|
F f;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts,typename F,typename... Args>
|
template<
|
||||||
auto restitute_range(const F& f,Args&&... args)
|
typename Model,typename... Ts,typename F,typename... Args,
|
||||||
->restitute_range_class<
|
typename RestitutionList=restitution_list<Model,Ts...>
|
||||||
decltype(tail_closure(f,std::forward<Args>(args)...)),
|
>
|
||||||
Ts...
|
auto restitute_range(const F& f,Args&&... args)->mp11::mp_apply<
|
||||||
|
restitute_range_class,
|
||||||
|
mp11::mp_append<
|
||||||
|
mp11::mp_list<
|
||||||
|
is_total_restitution<Model,RestitutionList>,
|
||||||
|
decltype(tail_closure(f,std::forward<Args>(args)...))
|
||||||
|
>,
|
||||||
|
RestitutionList
|
||||||
>
|
>
|
||||||
|
>
|
||||||
{
|
{
|
||||||
return tail_closure(f,std::forward<Args>(args)...);
|
return tail_closure(f,std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* restitute_iterator<Ts...>(f,args2...)(index,it,args1...) resolves to
|
/* restitute_iterator<IsTotal,Ts...>(f,args2...)(info,it,args1...) resolves to
|
||||||
* f(restitute<Ts...>(index,it),args1...,args2...).
|
* f(restitute<Ts...>(info,it),args1...,args2...).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename F,typename... Ts>
|
template<typename IsTotal,typename F,typename... Ts>
|
||||||
struct restitute_iterator_class;
|
struct restitute_iterator_class;
|
||||||
|
|
||||||
template<typename F,typename T,typename... Ts>
|
template<typename IsTotal,typename F,typename T,typename... Ts>
|
||||||
struct restitute_iterator_class<F,T,Ts...>:
|
struct restitute_iterator_class<IsTotal,F,T,Ts...>:
|
||||||
restitute_iterator_class<F,Ts...>
|
restitute_iterator_class<IsTotal,F,Ts...>
|
||||||
{
|
{
|
||||||
using super=restitute_iterator_class<F,Ts...>;
|
using super=restitute_iterator_class<IsTotal,F,Ts...>;
|
||||||
using super::super;
|
using super::super;
|
||||||
|
|
||||||
template<typename Iterator,typename... Args>
|
template<
|
||||||
auto operator()(
|
typename TypeIndex,typename Iterator,typename... Args,
|
||||||
const std::type_info& info,Iterator&& it,Args&&... args)
|
typename Traits=iterator_traits<typename std::decay<Iterator>::type>,
|
||||||
|
typename LocalIterator=typename Traits::template local_iterator<T>
|
||||||
|
>
|
||||||
|
BOOST_FORCEINLINE auto operator()(
|
||||||
|
const TypeIndex& info,Iterator&& it,Args&&... args)
|
||||||
->decltype(
|
->decltype(
|
||||||
std::declval<F>()
|
std::declval<F>()(LocalIterator{it},std::forward<Args>(args)...))
|
||||||
(std::forward<Iterator>(it),std::forward<Args>(args)...))
|
|
||||||
{
|
{
|
||||||
using traits=iterator_traits<typename std::decay<Iterator>::type>;
|
if(static_cast<const typename Traits::type_index&>(info)==
|
||||||
using local_iterator=typename traits::template local_iterator<T>;
|
Traits::template index<T>()){
|
||||||
|
return (this->f)(LocalIterator{it},std::forward<Args>(args)...);
|
||||||
if(info==typeid(T))
|
}
|
||||||
return (this->f)(
|
else{
|
||||||
local_iterator{it},std::forward<Args>(args)...);
|
|
||||||
else
|
|
||||||
return super::operator()(
|
return super::operator()(
|
||||||
info,std::forward<Iterator>(it),std::forward<Args>(args)...);
|
info,std::forward<Iterator>(it),std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename F>
|
template<typename F,typename T>
|
||||||
struct restitute_iterator_class<F>
|
struct restitute_iterator_class<std::true_type /* total */,F,T>
|
||||||
{
|
{
|
||||||
restitute_iterator_class(const F& f):f(f){}
|
restitute_iterator_class(const F& f):f(f){}
|
||||||
|
|
||||||
template<typename Iterator,typename... Args>
|
template<
|
||||||
auto operator()(
|
typename TypeIndex,typename Iterator,typename... Args,
|
||||||
const std::type_info&,Iterator&& it,Args&&... args)
|
typename Traits=iterator_traits<typename std::decay<Iterator>::type>,
|
||||||
|
typename LocalIterator=typename Traits::template local_iterator<T>
|
||||||
|
>
|
||||||
|
BOOST_FORCEINLINE auto operator()(
|
||||||
|
const TypeIndex& info,Iterator&& it,Args&&... args)
|
||||||
|
->decltype(
|
||||||
|
std::declval<F>()(LocalIterator{it},std::forward<Args>(args)...))
|
||||||
|
{
|
||||||
|
return f(LocalIterator{it},std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
F f;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
struct restitute_iterator_class<std::false_type /* non total */,F>
|
||||||
|
{
|
||||||
|
restitute_iterator_class(const F& f):f(f){}
|
||||||
|
|
||||||
|
template<typename TypeIndex,typename Iterator,typename... Args>
|
||||||
|
BOOST_FORCEINLINE auto operator()(
|
||||||
|
const TypeIndex&,Iterator&& it,Args&&... args)
|
||||||
->decltype(
|
->decltype(
|
||||||
std::declval<F>()
|
std::declval<F>()
|
||||||
(std::forward<Iterator>(it),std::forward<Args>(args)...))
|
(std::forward<Iterator>(it),std::forward<Args>(args)...))
|
||||||
@@ -135,57 +284,20 @@ struct restitute_iterator_class<F>
|
|||||||
F f;
|
F f;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts,typename F,typename... Args>
|
template<
|
||||||
auto restitute_iterator(const F& f,Args&&... args)
|
typename Model,typename... Ts,typename F,typename... Args,
|
||||||
->restitute_iterator_class<
|
typename RestitutionList=restitution_list<Model,Ts...>
|
||||||
decltype(tail_closure(f,std::forward<Args>(args)...)),
|
>
|
||||||
Ts...
|
auto restitute_iterator(const F& f,Args&&... args)->mp11::mp_apply<
|
||||||
>
|
restitute_iterator_class,
|
||||||
{
|
mp11::mp_append<
|
||||||
return tail_closure(f,std::forward<Args>(args)...);
|
mp11::mp_list<
|
||||||
}
|
is_total_restitution<Model,RestitutionList>,
|
||||||
|
decltype(tail_closure(f,std::forward<Args>(args)...))
|
||||||
/* binary_restitute_iterator<Ts...>(f,args...)(index1,it1,index2,it2) resolves
|
>,
|
||||||
* to f(restitute<Ts...>(index1,it1),restitute<Ts...>(index2,it2),args...).
|
RestitutionList
|
||||||
*/
|
|
||||||
|
|
||||||
template<typename F,typename... Ts>
|
|
||||||
struct binary_restitute_iterator_class
|
|
||||||
{
|
|
||||||
binary_restitute_iterator_class(const F& f):f(f){}
|
|
||||||
|
|
||||||
template<typename Iterator1,typename Iterator2>
|
|
||||||
auto operator()(
|
|
||||||
const std::type_info& info1,Iterator1&& it1,
|
|
||||||
const std::type_info& info2,Iterator2&& it2)
|
|
||||||
->decltype(
|
|
||||||
std::declval<F>()
|
|
||||||
(std::forward<Iterator1>(it1),std::forward<Iterator2>(it2)))
|
|
||||||
{
|
|
||||||
return restitute_iterator<Ts...>(*this)(
|
|
||||||
info2,std::forward<Iterator2>(it2),info1,std::forward<Iterator1>(it1));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Iterator2,typename Iterator1>
|
|
||||||
auto operator()(
|
|
||||||
Iterator2&& it2,const std::type_info& info1,Iterator1&& it1)
|
|
||||||
->decltype(
|
|
||||||
std::declval<F>()
|
|
||||||
(std::forward<Iterator1>(it1),std::forward<Iterator2>(it2)))
|
|
||||||
{
|
|
||||||
return restitute_iterator<Ts...>(f)(
|
|
||||||
info1,std::forward<Iterator1>(it1),std::forward<Iterator2>(it2));
|
|
||||||
}
|
|
||||||
|
|
||||||
F f;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... Ts,typename F,typename... Args>
|
|
||||||
auto binary_restitute_iterator(const F& f,Args&&... args)
|
|
||||||
->binary_restitute_iterator_class<
|
|
||||||
decltype(tail_closure(f,std::forward<Args>(args)...)),
|
|
||||||
Ts...
|
|
||||||
>
|
>
|
||||||
|
>
|
||||||
{
|
{
|
||||||
return tail_closure(f,std::forward<Args>(args)...);
|
return tail_closure(f,std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
@@ -196,4 +308,8 @@ auto binary_restitute_iterator(const F& f,Args&&... args)
|
|||||||
|
|
||||||
} /* namespace boost */
|
} /* namespace boost */
|
||||||
|
|
||||||
|
#if defined(BOOST_MSVC)
|
||||||
|
#pragma warning(pop) /* C4714 */
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2022 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/core/addressof.hpp>
|
|
||||||
#include <boost/poly_collection/detail/is_constructible.hpp>
|
#include <boost/poly_collection/detail/is_constructible.hpp>
|
||||||
#include <boost/poly_collection/detail/is_equality_comparable.hpp>
|
#include <boost/poly_collection/detail/is_equality_comparable.hpp>
|
||||||
#include <boost/poly_collection/detail/is_nothrow_eq_comparable.hpp>
|
#include <boost/poly_collection/detail/is_nothrow_eq_comparable.hpp>
|
||||||
@@ -48,6 +47,13 @@ namespace detail{
|
|||||||
* Emplacing is explicitly signalled with value_holder_emplacing_ctor to
|
* Emplacing is explicitly signalled with value_holder_emplacing_ctor to
|
||||||
* protect us from greedy T's constructible from anything (like
|
* protect us from greedy T's constructible from anything (like
|
||||||
* boost::type_erasure::any).
|
* boost::type_erasure::any).
|
||||||
|
*
|
||||||
|
* If specified, the second arg in value_holder<T,U> is a type
|
||||||
|
* from where T will be copy/move constructed, rather than T itself.
|
||||||
|
* T must be (nothrow) copy/move constructible iff it is (nothrow)
|
||||||
|
* constructible from const U&/U&&. This serves the use case where a segment
|
||||||
|
* for U does not store Us but objects of some other type (=T) constructed
|
||||||
|
* from them.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct value_holder_emplacing_ctor_t{};
|
struct value_holder_emplacing_ctor_t{};
|
||||||
@@ -61,24 +67,23 @@ protected:
|
|||||||
alignas(T) unsigned char s[sizeof(T)];
|
alignas(T) unsigned char s[sizeof(T)];
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T,typename U=T>
|
||||||
class value_holder:public value_holder_base<T>
|
class value_holder:public value_holder_base<T>
|
||||||
{
|
{
|
||||||
template<typename U>
|
template<typename Q>
|
||||||
using enable_if_not_emplacing_ctor_t=typename std::enable_if<
|
using enable_if_not_emplacing_ctor_t=typename std::enable_if<
|
||||||
!std::is_same<
|
!std::is_same<
|
||||||
typename std::decay<U>::type,value_holder_emplacing_ctor_t
|
typename std::decay<Q>::type,value_holder_emplacing_ctor_t
|
||||||
>::value
|
>::value
|
||||||
>::type*;
|
>::type*;
|
||||||
|
|
||||||
using is_nothrow_move_constructible=std::is_nothrow_move_constructible<T>;
|
using is_nothrow_move_constructible=std::is_nothrow_move_constructible<U>;
|
||||||
using is_copy_constructible=std::is_copy_constructible<T>;
|
using is_copy_constructible=std::is_copy_constructible<U>;
|
||||||
using is_nothrow_copy_constructible=std::is_nothrow_copy_constructible<T>;
|
using is_nothrow_copy_constructible=std::is_nothrow_copy_constructible<U>;
|
||||||
using is_move_assignable=std::is_move_assignable<T>;
|
using is_move_assignable=std::is_move_assignable<U>;
|
||||||
using is_nothrow_move_assignable=std::is_nothrow_move_assignable<T>;
|
using is_nothrow_move_assignable=std::is_nothrow_move_assignable<U>;
|
||||||
using is_equality_comparable=detail::is_equality_comparable<T>;
|
using is_equality_comparable=detail::is_equality_comparable<U>;
|
||||||
using is_nothrow_equality_comparable=
|
using is_nothrow_equality_comparable=detail::is_nothrow_equality_comparable<U>;
|
||||||
detail::is_nothrow_equality_comparable<T>;
|
|
||||||
|
|
||||||
T* data()noexcept{return reinterpret_cast<T*>(&this->s);}
|
T* data()noexcept{return reinterpret_cast<T*>(&this->s);}
|
||||||
const T* data()const noexcept
|
const T* data()const noexcept
|
||||||
@@ -92,14 +97,14 @@ public:
|
|||||||
typename Allocator,
|
typename Allocator,
|
||||||
enable_if_not_emplacing_ctor_t<Allocator> =nullptr
|
enable_if_not_emplacing_ctor_t<Allocator> =nullptr
|
||||||
>
|
>
|
||||||
value_holder(Allocator& al,const T& x)
|
value_holder(Allocator& al,const U& x)
|
||||||
noexcept(is_nothrow_copy_constructible::value)
|
noexcept(is_nothrow_copy_constructible::value)
|
||||||
{copy(al,x);}
|
{allocator_copy(al,x);}
|
||||||
template<
|
template<
|
||||||
typename Allocator,
|
typename Allocator,
|
||||||
enable_if_not_emplacing_ctor_t<Allocator> =nullptr
|
enable_if_not_emplacing_ctor_t<Allocator> =nullptr
|
||||||
>
|
>
|
||||||
value_holder(Allocator& al,T&& x)
|
value_holder(Allocator& al,U&& x)
|
||||||
noexcept(is_nothrow_move_constructible::value)
|
noexcept(is_nothrow_move_constructible::value)
|
||||||
{std::allocator_traits<Allocator>::construct(al,data(),std::move(x));}
|
{std::allocator_traits<Allocator>::construct(al,data(),std::move(x));}
|
||||||
template<
|
template<
|
||||||
@@ -115,7 +120,7 @@ public:
|
|||||||
>
|
>
|
||||||
value_holder(Allocator& al,const value_holder& x)
|
value_holder(Allocator& al,const value_holder& x)
|
||||||
noexcept(is_nothrow_copy_constructible::value)
|
noexcept(is_nothrow_copy_constructible::value)
|
||||||
{copy(al,x.value());}
|
{allocator_copy(al,x.value());}
|
||||||
template<
|
template<
|
||||||
typename Allocator,
|
typename Allocator,
|
||||||
enable_if_not_emplacing_ctor_t<Allocator> =nullptr
|
enable_if_not_emplacing_ctor_t<Allocator> =nullptr
|
||||||
@@ -130,10 +135,10 @@ public:
|
|||||||
* following to make their life easier.
|
* following to make their life easier.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
value_holder(const T& x)
|
value_holder(const U& x)
|
||||||
noexcept(is_nothrow_copy_constructible::value)
|
noexcept(is_nothrow_copy_constructible::value)
|
||||||
{copy(x);}
|
{copy(x);}
|
||||||
value_holder(T&& x)
|
value_holder(U&& x)
|
||||||
noexcept(is_nothrow_move_constructible::value)
|
noexcept(is_nothrow_move_constructible::value)
|
||||||
{::new ((void*)data()) T(std::move(x));}
|
{::new ((void*)data()) T(std::move(x));}
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
@@ -164,31 +169,37 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename Allocator>
|
template<typename Allocator,typename Q>
|
||||||
void copy(Allocator& al,const T& x){copy(al,x,is_copy_constructible{});}
|
void allocator_copy(Allocator& al,const Q& x)
|
||||||
|
{
|
||||||
|
allocator_copy(al,x,is_copy_constructible{});
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Allocator>
|
template<typename Allocator,typename Q>
|
||||||
void copy(Allocator& al,const T& x,std::true_type)
|
void allocator_copy(Allocator& al,const Q& x,std::true_type)
|
||||||
{
|
{
|
||||||
std::allocator_traits<Allocator>::construct(al,data(),x);
|
std::allocator_traits<Allocator>::construct(al,data(),x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Allocator>
|
template<typename Allocator,typename Q>
|
||||||
void copy(Allocator&,const T&,std::false_type)
|
void allocator_copy(Allocator&,const Q&,std::false_type)
|
||||||
{
|
{
|
||||||
throw not_copy_constructible{typeid(T)};
|
throw not_copy_constructible{typeid(U)};
|
||||||
}
|
}
|
||||||
|
|
||||||
void copy(const T& x){copy(x,is_copy_constructible{});}
|
template<typename Q>
|
||||||
|
void copy(const Q& x){copy(x,is_copy_constructible{});}
|
||||||
|
|
||||||
void copy(const T& x,std::true_type)
|
template<typename Q>
|
||||||
|
void copy(const Q& x,std::true_type)
|
||||||
{
|
{
|
||||||
::new (data()) T(x);
|
::new (data()) T(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void copy(const T&,std::false_type)
|
template<typename Q>
|
||||||
|
void copy(const Q&,std::false_type)
|
||||||
{
|
{
|
||||||
throw not_copy_constructible{typeid(T)};
|
throw not_copy_constructible{typeid(U)};
|
||||||
}
|
}
|
||||||
|
|
||||||
void move_assign(T&& x){move_assign(std::move(x),is_move_assignable{});}
|
void move_assign(T&& x){move_assign(std::move(x),is_move_assignable{});}
|
||||||
@@ -205,7 +216,7 @@ private:
|
|||||||
static_assert(is_nothrow_move_constructible::value,
|
static_assert(is_nothrow_move_constructible::value,
|
||||||
"type should be move assignable or nothrow move constructible");
|
"type should be move assignable or nothrow move constructible");
|
||||||
|
|
||||||
if(data()!=boost::addressof(x)){
|
if(data()!=std::addressof(x)){
|
||||||
value().~T();
|
value().~T();
|
||||||
::new (data()) T(std::move(x));
|
::new (data()) T(std::move(x));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,275 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_POLY_COLLECTION_DETAIL_VARIANT_MODEL_HPP
|
||||||
|
#define BOOST_POLY_COLLECTION_DETAIL_VARIANT_MODEL_HPP
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <boost/core/addressof.hpp>
|
||||||
|
#include <boost/mp11/algorithm.hpp>
|
||||||
|
#include <boost/mp11/list.hpp>
|
||||||
|
#include <boost/mp11/set.hpp>
|
||||||
|
#include <boost/poly_collection/detail/is_acceptable.hpp>
|
||||||
|
#include <boost/poly_collection/detail/fixed_variant.hpp>
|
||||||
|
#include <boost/poly_collection/detail/fixed_variant_iterator.hpp>
|
||||||
|
#include <boost/poly_collection/detail/packed_segment.hpp>
|
||||||
|
#include <boost/poly_collection/detail/segment_backend.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <typeinfo>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_CXX17_HDR_VARIANT)
|
||||||
|
#include <variant>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost{namespace variant2{
|
||||||
|
|
||||||
|
template<class... T> class variant;
|
||||||
|
|
||||||
|
}} /* namespace boost::variant2 */
|
||||||
|
|
||||||
|
namespace boost_poly_collection_invoke_visit_variant2{
|
||||||
|
|
||||||
|
/* defined here to avoid ADL ambiguities with visit */
|
||||||
|
|
||||||
|
template<typename F,typename... Ts>
|
||||||
|
auto invoke_visit(F&& f,const boost::variant2::variant<Ts...>&x)->
|
||||||
|
decltype(visit(std::forward<F>(f),x))
|
||||||
|
{
|
||||||
|
return visit(std::forward<F>(f),x);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace boost_poly_collection_invoke_visit_variant2 */
|
||||||
|
|
||||||
|
namespace boost{
|
||||||
|
|
||||||
|
namespace poly_collection{
|
||||||
|
|
||||||
|
namespace detail{
|
||||||
|
|
||||||
|
/* model for variant_collection */
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
struct variant_model;
|
||||||
|
|
||||||
|
template<typename V,typename...Ts>
|
||||||
|
struct variant_model_is_subvariant:std::false_type{};
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename TL1,typename TL2,
|
||||||
|
typename TS1=mp11::mp_set_union<mp11::mp_list<>,TL1>,
|
||||||
|
typename TS2=mp11::mp_set_union<mp11::mp_list<>,TL2>
|
||||||
|
>
|
||||||
|
struct variant_model_is_subset:std::integral_constant<
|
||||||
|
bool,
|
||||||
|
mp11::mp_size<mp11::mp_set_union<TS1,TS2>>::value==
|
||||||
|
mp11::mp_size<TS2>::value
|
||||||
|
>{};
|
||||||
|
|
||||||
|
template<typename... Us,typename... Ts>
|
||||||
|
struct variant_model_is_subvariant<
|
||||||
|
fixed_variant_impl::fixed_variant<Us...>,
|
||||||
|
Ts...
|
||||||
|
>:variant_model_is_subset<mp11::mp_list<Us...>,mp11::mp_list<Ts...>>{};
|
||||||
|
|
||||||
|
template<typename... Us,typename... Ts>
|
||||||
|
struct variant_model_is_subvariant<
|
||||||
|
variant2::variant<Us...>,
|
||||||
|
Ts...
|
||||||
|
>:variant_model_is_subset<mp11::mp_list<Us...>,mp11::mp_list<Ts...>>{};
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_CXX17_HDR_VARIANT)
|
||||||
|
template<typename... Us,typename... Ts>
|
||||||
|
struct variant_model_is_subvariant<
|
||||||
|
std::variant<Us...>,
|
||||||
|
Ts...
|
||||||
|
>:variant_model_is_subset<mp11::mp_list<Us...>,mp11::mp_list<Ts...>>{};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename F,typename... Ts>
|
||||||
|
auto invoke_visit(F&& f,const fixed_variant_impl::fixed_variant<Ts...>&x)->
|
||||||
|
decltype(boost::poly_collection::visit(std::forward<F>(f),x))
|
||||||
|
{
|
||||||
|
return boost::poly_collection::visit(std::forward<F>(f),x);
|
||||||
|
}
|
||||||
|
|
||||||
|
using boost_poly_collection_invoke_visit_variant2::invoke_visit;
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_CXX17_HDR_VARIANT)
|
||||||
|
template<typename F,typename... Ts>
|
||||||
|
auto invoke_visit(F&& f,const std::variant<Ts...>&x)->
|
||||||
|
decltype(std::visit(std::forward<F>(f),x))
|
||||||
|
{
|
||||||
|
return std::visit(std::forward<F>(f),x);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
struct variant_model
|
||||||
|
{
|
||||||
|
using value_type=fixed_variant_impl::fixed_variant<Ts...>;
|
||||||
|
using type_index=std::size_t;
|
||||||
|
using acceptable_type_list=mp11::mp_list<Ts...>;
|
||||||
|
template<typename T>
|
||||||
|
struct is_terminal: /* using makes VS2015 choke, hence we derive */
|
||||||
|
mp11::mp_contains<acceptable_type_list,T>{};
|
||||||
|
template<typename T>
|
||||||
|
struct is_implementation:std::integral_constant< /* idem */
|
||||||
|
bool,
|
||||||
|
is_terminal<T>::value||
|
||||||
|
variant_model_is_subvariant<T,Ts...>::value
|
||||||
|
>{};
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename T>
|
||||||
|
using enable_if_terminal=
|
||||||
|
typename std::enable_if<is_terminal<T>::value>::type*;
|
||||||
|
template<typename T>
|
||||||
|
using enable_if_not_terminal=
|
||||||
|
typename std::enable_if<!is_terminal<T>::value>::type*;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename T> static type_index index()
|
||||||
|
{
|
||||||
|
return mp11::mp_find<acceptable_type_list,T>::value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T,enable_if_terminal<T> =nullptr>
|
||||||
|
static type_index subindex(const T&){return index<T>();}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename... Qs>
|
||||||
|
struct subindex_lambda
|
||||||
|
{
|
||||||
|
template<typename I>
|
||||||
|
std::size_t operator()(I)const
|
||||||
|
{
|
||||||
|
return mp11::mp_find<
|
||||||
|
acceptable_type_list,mp11::mp_at<mp11::mp_list<Qs...>,I>>::value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<
|
||||||
|
template<typename...> class V,typename... Qs,
|
||||||
|
enable_if_not_terminal<V<Qs...>> =nullptr>
|
||||||
|
static type_index subindex(const V<Qs...>& x)
|
||||||
|
{
|
||||||
|
static constexpr auto not_found=mp11::mp_size<acceptable_type_list>::value;
|
||||||
|
auto i=x.index();
|
||||||
|
if(i>=sizeof...(Qs))return not_found;
|
||||||
|
else return mp11::mp_with_index<sizeof...(Qs)>(
|
||||||
|
i,subindex_lambda<Qs...>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T,enable_if_terminal<T> =nullptr>
|
||||||
|
static void* subaddress(T& x){return boost::addressof(x);}
|
||||||
|
|
||||||
|
template<typename T,enable_if_terminal<T> =nullptr>
|
||||||
|
static const void* subaddress(const T& x){return boost::addressof(x);}
|
||||||
|
|
||||||
|
template<typename T,enable_if_not_terminal<T> =nullptr>
|
||||||
|
static void* subaddress(T& x)
|
||||||
|
{
|
||||||
|
return const_cast<void*>(subaddress(const_cast<const T&>(x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct subaddress_visitor
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
const void* operator()(const T& x)const
|
||||||
|
{
|
||||||
|
return static_cast<const void*>(boost::addressof(x));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename T,enable_if_not_terminal<T> =nullptr>
|
||||||
|
static const void* subaddress(const T& x)
|
||||||
|
{
|
||||||
|
return invoke_visit(subaddress_visitor{},x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T,enable_if_terminal<T> =nullptr>
|
||||||
|
static const std::type_info& subtype_info(const T& x)
|
||||||
|
{
|
||||||
|
return typeid(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct subtype_info_visitor
|
||||||
|
{
|
||||||
|
template<typename T>
|
||||||
|
const std::type_info& operator()(const T&)const{return typeid(T);}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename T,enable_if_not_terminal<T> =nullptr>
|
||||||
|
static const std::type_info& subtype_info(const T& x)
|
||||||
|
{
|
||||||
|
return invoke_visit(subtype_info_visitor{},x);
|
||||||
|
}
|
||||||
|
|
||||||
|
using base_iterator=fixed_variant_iterator<value_type>;
|
||||||
|
using const_base_iterator=fixed_variant_iterator<const value_type>;
|
||||||
|
using base_sentinel=value_type*;
|
||||||
|
using const_base_sentinel=const value_type*;
|
||||||
|
template<typename T>
|
||||||
|
using iterator=fixed_variant_alternative_iterator<value_type,T>;
|
||||||
|
template<typename T>
|
||||||
|
using const_iterator=fixed_variant_alternative_iterator<value_type,const T>;
|
||||||
|
template<typename Allocator>
|
||||||
|
using segment_backend=detail::segment_backend<variant_model,Allocator>;
|
||||||
|
template<typename T,typename Allocator>
|
||||||
|
using segment_backend_implementation=
|
||||||
|
packed_segment<variant_model,T,Allocator>;
|
||||||
|
|
||||||
|
static base_iterator nonconst_iterator(const_base_iterator it)
|
||||||
|
{
|
||||||
|
return base_iterator{
|
||||||
|
const_cast<value_type*>(static_cast<const value_type*>(it)),it.stride()};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static iterator<T> nonconst_iterator(const_iterator<T> it)
|
||||||
|
{
|
||||||
|
return {const_cast<T*>(static_cast<const T*>(it))};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename,typename,typename>
|
||||||
|
friend class packed_segment;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using final_type=fixed_variant_impl::fixed_variant_closure<
|
||||||
|
T,fixed_variant_impl::fixed_variant<Ts...>>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static const value_type* value_ptr(const T* p)noexcept
|
||||||
|
{
|
||||||
|
return reinterpret_cast<const final_type<T>*>(p);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace poly_collection::detail */
|
||||||
|
|
||||||
|
} /* namespace poly_collection */
|
||||||
|
|
||||||
|
} /* namespace boost */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_POLY_COLLECTION_VARIANT_COLLECTION_HPP
|
||||||
|
#define BOOST_POLY_COLLECTION_VARIANT_COLLECTION_HPP
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/poly_collection/variant_collection_fwd.hpp>
|
||||||
|
#include <boost/mp11/list.hpp>
|
||||||
|
#include <boost/poly_collection/detail/variant_model.hpp>
|
||||||
|
#include <boost/poly_collection/detail/poly_collection.hpp>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace boost{
|
||||||
|
|
||||||
|
namespace poly_collection{
|
||||||
|
|
||||||
|
template<typename TypeList,typename Allocator>
|
||||||
|
class variant_collection:
|
||||||
|
public common_impl::poly_collection<
|
||||||
|
mp11::mp_rename<TypeList,detail::variant_model>,Allocator>
|
||||||
|
{
|
||||||
|
using base_type=common_impl::poly_collection<
|
||||||
|
mp11::mp_rename<TypeList,detail::variant_model>,Allocator>;
|
||||||
|
|
||||||
|
base_type& base()noexcept{return *this;}
|
||||||
|
const base_type& base()const noexcept{return *this;}
|
||||||
|
|
||||||
|
public:
|
||||||
|
using base_type::base_type;
|
||||||
|
|
||||||
|
variant_collection()=default;
|
||||||
|
variant_collection(const variant_collection& x)=default;
|
||||||
|
variant_collection(variant_collection&& x)=default;
|
||||||
|
variant_collection& operator=(const variant_collection& x)=default;
|
||||||
|
variant_collection& operator=(variant_collection&& x)=default;
|
||||||
|
|
||||||
|
template<typename TL,typename A>
|
||||||
|
friend bool operator==(
|
||||||
|
const variant_collection<TL,A>&,const variant_collection<TL,A>&);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename TypeList,typename Allocator>
|
||||||
|
bool operator==(
|
||||||
|
const variant_collection<TypeList,Allocator>& x,
|
||||||
|
const variant_collection<TypeList,Allocator>& y)
|
||||||
|
{
|
||||||
|
return x.base()==y.base();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TypeList,typename Allocator>
|
||||||
|
bool operator!=(
|
||||||
|
const variant_collection<TypeList,Allocator>& x,
|
||||||
|
const variant_collection<TypeList,Allocator>& y)
|
||||||
|
{
|
||||||
|
return !(x==y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: other rel operators?
|
||||||
|
|
||||||
|
template<typename TypeList,typename Allocator>
|
||||||
|
void swap(
|
||||||
|
variant_collection<TypeList,Allocator>& x,
|
||||||
|
variant_collection<TypeList,Allocator>& y)
|
||||||
|
{
|
||||||
|
x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace */
|
||||||
|
|
||||||
|
using poly_collection::variant_collection;
|
||||||
|
|
||||||
|
} /* namespace boost */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_POLY_COLLECTION_VARIANT_COLLECTION_FWD_HPP
|
||||||
|
#define BOOST_POLY_COLLECTION_VARIANT_COLLECTION_FWD_HPP
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/mp11/list.hpp>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace boost{
|
||||||
|
|
||||||
|
namespace poly_collection{
|
||||||
|
|
||||||
|
namespace detail{
|
||||||
|
template<typename... Ts> struct variant_model;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TypeList>
|
||||||
|
using variant_collection_value_type=
|
||||||
|
typename mp11::mp_rename<TypeList,detail::variant_model>::value_type;
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename TypeList,
|
||||||
|
typename Allocator=std::allocator<variant_collection_value_type<TypeList>>
|
||||||
|
>
|
||||||
|
class variant_collection;
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
using variant_collection_of=variant_collection<mp11::mp_list<Ts...>>;
|
||||||
|
|
||||||
|
template<typename TypeList,typename Allocator>
|
||||||
|
bool operator==(
|
||||||
|
const variant_collection<TypeList,Allocator>& x,
|
||||||
|
const variant_collection<TypeList,Allocator>& y);
|
||||||
|
|
||||||
|
template<typename TypeList,typename Allocator>
|
||||||
|
bool operator!=(
|
||||||
|
const variant_collection<TypeList,Allocator>& x,
|
||||||
|
const variant_collection<TypeList,Allocator>& y);
|
||||||
|
|
||||||
|
template<typename TypeList,typename Allocator>
|
||||||
|
void swap(
|
||||||
|
variant_collection<TypeList,Allocator>& x,
|
||||||
|
variant_collection<TypeList,Allocator>& y);
|
||||||
|
|
||||||
|
} /* namespace poly_collection */
|
||||||
|
|
||||||
|
using poly_collection::variant_collection;
|
||||||
|
using poly_collection::variant_collection_of;
|
||||||
|
|
||||||
|
} /* namespace boost */
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -16,46 +16,24 @@ project
|
|||||||
<library>/boost/poly_collection//boost_poly_collection
|
<library>/boost/poly_collection//boost_poly_collection
|
||||||
[ requires cxx11_noexcept ] # used as a proxy for C++11 support
|
[ requires cxx11_noexcept ] # used as a proxy for C++11 support
|
||||||
<toolset>msvc:<cxxflags>-D_SCL_SECURE_NO_WARNINGS
|
<toolset>msvc:<cxxflags>-D_SCL_SECURE_NO_WARNINGS
|
||||||
|
<toolset>msvc:<cxxflags>/bigobj
|
||||||
|
<toolset>gcc:<inlining>on
|
||||||
|
<toolset>gcc:<optimization>space
|
||||||
|
<toolset>clang:<inlining>on
|
||||||
|
<toolset>clang:<optimization>space
|
||||||
;
|
;
|
||||||
|
|
||||||
test-suite "poly_collection" :
|
test-suite "poly_collection" :
|
||||||
[ run test_algorithm.cpp test_algorithm1.cpp
|
[ run test_algorithm.cpp test_algorithm1.cpp
|
||||||
test_algorithm2.cpp test_algorithm3.cpp
|
test_algorithm2.cpp test_algorithm3.cpp
|
||||||
test_algorithm_main.cpp
|
test_algorithm4.cpp test_algorithm_main.cpp ]
|
||||||
:
|
[ run test_capacity.cpp test_capacity_main.cpp ]
|
||||||
:
|
[ run test_comparison.cpp test_comparison_main.cpp ]
|
||||||
: <toolset>msvc:<cxxflags>/bigobj
|
[ run test_construction.cpp test_construction_main.cpp ]
|
||||||
<toolset>gcc:<inlining>on
|
[ run test_emplacement.cpp test_emplacement_main.cpp ]
|
||||||
<toolset>gcc:<optimization>space
|
[ run test_erasure.cpp test_erasure_main.cpp ]
|
||||||
<toolset>clang:<inlining>on
|
[ run test_fixed_variant.cpp test_fixed_variant_main.cpp ]
|
||||||
<toolset>clang:<optimization>space ]
|
[ run test_insertion.cpp test_insertion_main.cpp ]
|
||||||
[ run test_capacity.cpp test_capacity_main.cpp ]
|
[ run test_iterators.cpp test_iterators_main.cpp ]
|
||||||
[ run test_comparison.cpp test_comparison_main.cpp ]
|
[ run test_registration.cpp test_registration_main.cpp ]
|
||||||
[ run test_construction.cpp test_construction_main.cpp
|
|
||||||
:
|
|
||||||
:
|
|
||||||
: <toolset>msvc:<cxxflags>/bigobj
|
|
||||||
<toolset>gcc:<inlining>on
|
|
||||||
<toolset>gcc:<optimization>space
|
|
||||||
<toolset>clang:<inlining>on
|
|
||||||
<toolset>clang:<optimization>space ]
|
|
||||||
[ run test_emplacement.cpp test_emplacement_main.cpp ]
|
|
||||||
[ run test_erasure.cpp test_erasure_main.cpp ]
|
|
||||||
[ run test_insertion.cpp test_insertion_main.cpp
|
|
||||||
:
|
|
||||||
:
|
|
||||||
: <toolset>msvc:<cxxflags>/bigobj
|
|
||||||
<toolset>gcc:<inlining>on
|
|
||||||
<toolset>gcc:<optimization>space
|
|
||||||
<toolset>clang:<inlining>on
|
|
||||||
<toolset>clang:<optimization>space ]
|
|
||||||
[ run test_iterators.cpp test_iterators_main.cpp
|
|
||||||
:
|
|
||||||
:
|
|
||||||
: <toolset>msvc:<cxxflags>/bigobj
|
|
||||||
<toolset>gcc:<inlining>on
|
|
||||||
<toolset>gcc:<optimization>space
|
|
||||||
<toolset>clang:<inlining>on
|
|
||||||
<toolset>clang:<optimization>space ]
|
|
||||||
[ run test_registration.cpp test_registration_main.cpp ]
|
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "test_algorithm1.hpp"
|
#include "test_algorithm1.hpp"
|
||||||
#include "test_algorithm2.hpp"
|
#include "test_algorithm2.hpp"
|
||||||
#include "test_algorithm3.hpp"
|
#include "test_algorithm3.hpp"
|
||||||
|
#include "test_algorithm4.hpp"
|
||||||
|
|
||||||
/* test split in chunks to avoid problems with compilation object sizes */
|
/* test split in chunks to avoid problems with compilation object sizes */
|
||||||
|
|
||||||
@@ -18,4 +19,5 @@ void test_algorithm()
|
|||||||
test_algorithm1();
|
test_algorithm1();
|
||||||
test_algorithm2();
|
test_algorithm2();
|
||||||
test_algorithm3();
|
test_algorithm3();
|
||||||
|
test_algorithm4();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test_algorithm4.hpp"
|
||||||
|
|
||||||
|
#include <boost/detail/workaround.hpp>
|
||||||
|
#include <boost/iterator/function_output_iterator.hpp>
|
||||||
|
#include <iterator>
|
||||||
|
#include <random>
|
||||||
|
#include <type_traits>
|
||||||
|
#include "variant_types.hpp"
|
||||||
|
#include "test_algorithm_impl.hpp"
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct pierced_pred
|
||||||
|
{
|
||||||
|
template<
|
||||||
|
typename Q,
|
||||||
|
typename std::enable_if<!std::is_same<T,Q>::value>::type* =nullptr
|
||||||
|
>
|
||||||
|
bool operator()(const Q&)const{return true;}
|
||||||
|
|
||||||
|
template<
|
||||||
|
typename Q,typename R,
|
||||||
|
typename std::enable_if<
|
||||||
|
!std::is_same<T,Q>::value&&!std::is_same<T,R>::value>::type* =nullptr
|
||||||
|
>
|
||||||
|
bool operator()(const Q&,const R&)const{return true;}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename PolyCollection,typename T>
|
||||||
|
void test_total_restitution_algorithm()
|
||||||
|
{
|
||||||
|
using namespace boost::poly_collection;
|
||||||
|
using value_type=typename PolyCollection::value_type;
|
||||||
|
|
||||||
|
PolyCollection p;
|
||||||
|
pierced_pred<value_type> pred;
|
||||||
|
int seq[1];
|
||||||
|
auto out=boost::make_function_output_iterator(pred);
|
||||||
|
|
||||||
|
#if BOOST_WORKAROUND(BOOST_MSVC,>=1910)&&BOOST_WORKAROUND(BOOST_MSVC,<1920)
|
||||||
|
/* Internal fix for https://lists.boost.org/Archives/boost/2017/06/235687.php
|
||||||
|
* causes instantiation of std alg for value_type.
|
||||||
|
*/
|
||||||
|
#else
|
||||||
|
(void)all_of<all_types>(p.begin(),p.end(),pred);
|
||||||
|
(void)any_of<all_types>(p.begin(),p.end(),pred);
|
||||||
|
(void)none_of<all_types>(p.begin(),p.end(),pred);
|
||||||
|
(void)count_if<all_types>(p.begin(),p.end(),pred);
|
||||||
|
(void)is_permutation<all_types>(
|
||||||
|
p.begin(),p.end(),std::begin(seq),pred);
|
||||||
|
(void)copy<all_types>(p.begin(),p.end(),out);
|
||||||
|
(void)copy_if<all_types>(p.begin(),p.end(),out,pred);
|
||||||
|
(void)rotate_copy<all_types>(p.begin(),p.begin(),p.end(),out);
|
||||||
|
(void)move<all_types>(p.begin(),p.end(),out);
|
||||||
|
(void)transform<all_types>(p.begin(),p.end(),out,pred);
|
||||||
|
(void)remove_copy<all_types>(p.begin(),p.end(),out,T{0});
|
||||||
|
(void)remove_copy_if<all_types>(p.begin(),p.end(),out,pred);
|
||||||
|
(void)is_partitioned<all_types>(p.begin(),p.begin(),pred);
|
||||||
|
(void)partition_copy<all_types>(p.begin(),p.begin(),out,out,pred);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
(void)for_each<all_types>(p.begin(),p.end(),pred);
|
||||||
|
(void)for_each_n<all_types>(p.begin(),0,pred);
|
||||||
|
/* find: no easy way to check value_type is not compared against */
|
||||||
|
(void)find_if<all_types>(p.begin(),p.end(),pred);
|
||||||
|
(void)find_if_not<all_types>(p.begin(),p.end(),pred);
|
||||||
|
(void)find_end<all_types>
|
||||||
|
(p.begin(),p.end(),std::begin(seq),std::end(seq),pred);
|
||||||
|
(void)find_first_of<all_types>
|
||||||
|
(p.begin(),p.end(),std::begin(seq),std::end(seq),pred);
|
||||||
|
(void)adjacent_find<all_types>(p.begin(),p.end(),pred);
|
||||||
|
/* count, no easy way to check value_type is not compared against */
|
||||||
|
(void)mismatch<all_types>(p.begin(),p.end(),std::begin(seq),pred);
|
||||||
|
(void)equal<all_types>(p.begin(),p.end(),std::begin(seq),pred);
|
||||||
|
(void)search<all_types>(
|
||||||
|
p.begin(),p.end(),std::begin(seq),std::end(seq),pred);
|
||||||
|
(void)search_n<all_types>(p.begin(),p.end(),1,T{0},pred);
|
||||||
|
(void)copy_n<all_types>(p.begin(),0,out);
|
||||||
|
(void)replace_copy<all_types>(p.begin(),p.end(),out,T{0},T{0});
|
||||||
|
(void)replace_copy_if<all_types>(p.begin(),p.end(),out,pred,T{0});
|
||||||
|
(void)unique_copy<all_types>(p.begin(),p.end(),out,pred);
|
||||||
|
(void)sample<all_types>(p.begin(),p.begin(),out,0,std::mt19937{});
|
||||||
|
(void)partition_point<all_types>(p.begin(),p.begin(),pred);
|
||||||
|
};
|
||||||
|
|
||||||
|
void test_algorithm4()
|
||||||
|
{
|
||||||
|
test_algorithm<
|
||||||
|
variant_types::collection,jammed_auto_increment,variant_types::to_int,
|
||||||
|
variant_types::t1,variant_types::t2,variant_types::t3,
|
||||||
|
variant_types::t4,variant_types::t5>();
|
||||||
|
test_total_restitution_algorithm<
|
||||||
|
variant_types::collection,variant_types::t1>();
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
*
|
||||||
|
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void test_algorithm4();
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2020 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
using namespace test_utilities;
|
using namespace test_utilities;
|
||||||
|
|
||||||
#if BOOST_WORKAROUND(BOOST_MSVC,>=1910)
|
#if BOOST_WORKAROUND(BOOST_MSVC,>=1910)&&BOOST_WORKAROUND(BOOST_MSVC,<1920)
|
||||||
/* https://lists.boost.org/Archives/boost/2017/06/235687.php */
|
/* https://lists.boost.org/Archives/boost/2017/06/235687.php */
|
||||||
|
|
||||||
#define DEFINE_ALGORITHM(name,f) \
|
#define DEFINE_ALGORITHM(name,f) \
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "test_construction.hpp"
|
#include "test_construction.hpp"
|
||||||
#include "test_emplacement.hpp"
|
#include "test_emplacement.hpp"
|
||||||
#include "test_erasure.hpp"
|
#include "test_erasure.hpp"
|
||||||
|
#include "test_fixed_variant.hpp"
|
||||||
#include "test_insertion.hpp"
|
#include "test_insertion.hpp"
|
||||||
#include "test_iterators.hpp"
|
#include "test_iterators.hpp"
|
||||||
#include "test_registration.hpp"
|
#include "test_registration.hpp"
|
||||||
@@ -25,6 +26,7 @@ int main()
|
|||||||
test_construction();
|
test_construction();
|
||||||
test_emplacement();
|
test_emplacement();
|
||||||
test_erasure();
|
test_erasure();
|
||||||
|
test_fixed_variant();
|
||||||
test_insertion();
|
test_insertion();
|
||||||
test_iterators();
|
test_iterators();
|
||||||
test_registration();
|
test_registration();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2017 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "any_types.hpp"
|
#include "any_types.hpp"
|
||||||
#include "base_types.hpp"
|
#include "base_types.hpp"
|
||||||
#include "function_types.hpp"
|
#include "function_types.hpp"
|
||||||
|
#include "variant_types.hpp"
|
||||||
#include "test_utilities.hpp"
|
#include "test_utilities.hpp"
|
||||||
|
|
||||||
using namespace test_utilities;
|
using namespace test_utilities;
|
||||||
@@ -27,29 +28,30 @@ void test_capacity()
|
|||||||
BOOST_TEST(cp.empty());
|
BOOST_TEST(cp.empty());
|
||||||
BOOST_TEST(cp.size()==0);
|
BOOST_TEST(cp.size()==0);
|
||||||
|
|
||||||
p.template register_types<Types...>();
|
register_types<Types...>(p);
|
||||||
BOOST_TEST(cp.empty());
|
BOOST_TEST(cp.empty());
|
||||||
do_((BOOST_TEST(cp.empty(typeid(Types))),0)...);
|
do_((BOOST_TEST(cp.empty(typeid_<Types>(cp))),0)...);
|
||||||
do_((BOOST_TEST(cp.template empty<Types>()),0)...);
|
do_((BOOST_TEST(cp.template empty<Types>()),0)...);
|
||||||
BOOST_TEST(cp.size()==0);
|
BOOST_TEST(cp.size()==0);
|
||||||
do_((BOOST_TEST(cp.size(typeid(Types))==0),0)...);
|
do_((BOOST_TEST(cp.size(typeid_<Types>(cp))==0),0)...);
|
||||||
do_((BOOST_TEST(cp.template size<Types>()==0),0)...);
|
do_((BOOST_TEST(cp.template size<Types>()==0),0)...);
|
||||||
|
|
||||||
p.reserve(10);
|
p.reserve(10);
|
||||||
do_((BOOST_TEST(cp.capacity(typeid(Types))>=10),0)...);
|
do_((BOOST_TEST(cp.capacity(typeid_<Types>(cp))>=10),0)...);
|
||||||
do_((BOOST_TEST(
|
do_((BOOST_TEST(
|
||||||
cp.template capacity<Types>()==cp.capacity(typeid(Types))),0)...);
|
cp.template capacity<Types>()==cp.capacity(typeid_<Types>(cp))),0)...);
|
||||||
|
|
||||||
do_((p.reserve(typeid(Types),20),0)...);
|
do_((p.reserve(typeid_<Types>(p),20),0)...);
|
||||||
do_((BOOST_TEST(cp.capacity(typeid(Types))>=20),0)...);
|
do_((BOOST_TEST(cp.capacity(typeid_<Types>(cp))>=20),0)...);
|
||||||
|
|
||||||
do_((p.template reserve<Types>(30),0)...);
|
do_((p.template reserve<Types>(30),0)...);
|
||||||
do_((BOOST_TEST(cp.template capacity<Types>()>=30),0)...);
|
do_((BOOST_TEST(cp.template capacity<Types>()>=30),0)...);
|
||||||
|
|
||||||
fill<constraints<>,Types...>(p,v,30);
|
fill<constraints<>,Types...>(p,v,30);
|
||||||
BOOST_TEST(cp.size()==30*sizeof...(Types));
|
BOOST_TEST(cp.size()==30*sizeof...(Types));
|
||||||
do_((BOOST_TEST(cp.size(typeid(Types))==30),0)...);
|
do_((BOOST_TEST(cp.size(typeid_<Types>(cp))==30),0)...);
|
||||||
do_((BOOST_TEST(cp.template size<Types>()==cp.size(typeid(Types))),0)...);
|
do_((BOOST_TEST(
|
||||||
|
cp.template size<Types>()==cp.size(typeid_<Types>(cp))),0)...);
|
||||||
|
|
||||||
auto min_capacity=[&]{
|
auto min_capacity=[&]{
|
||||||
return (std::min)({cp.template capacity<Types>()...});
|
return (std::min)({cp.template capacity<Types>()...});
|
||||||
@@ -66,7 +68,7 @@ void test_capacity()
|
|||||||
do_((p.erase(cp.template begin<Types>()),0)...);
|
do_((p.erase(cp.template begin<Types>()),0)...);
|
||||||
BOOST_TEST(c==min_capacity());
|
BOOST_TEST(c==min_capacity());
|
||||||
|
|
||||||
do_((p.shrink_to_fit(typeid(Types)),0)...);
|
do_((p.shrink_to_fit(typeid_<Types>(p)),0)...);
|
||||||
BOOST_TEST(c>=min_capacity());
|
BOOST_TEST(c>=min_capacity());
|
||||||
c=min_capacity();
|
c=min_capacity();
|
||||||
|
|
||||||
@@ -89,4 +91,8 @@ void test_capacity()
|
|||||||
function_types::collection,auto_increment,
|
function_types::collection,auto_increment,
|
||||||
function_types::t1,function_types::t2,function_types::t3,
|
function_types::t1,function_types::t2,function_types::t3,
|
||||||
function_types::t4,function_types::t5>();
|
function_types::t4,function_types::t5>();
|
||||||
|
test_capacity<
|
||||||
|
variant_types::collection,auto_increment,
|
||||||
|
variant_types::t1,variant_types::t2,variant_types::t3,
|
||||||
|
variant_types::t4,variant_types::t5>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2018 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "any_types.hpp"
|
#include "any_types.hpp"
|
||||||
#include "base_types.hpp"
|
#include "base_types.hpp"
|
||||||
#include "function_types.hpp"
|
#include "function_types.hpp"
|
||||||
|
#include "variant_types.hpp"
|
||||||
#include "test_utilities.hpp"
|
#include "test_utilities.hpp"
|
||||||
|
|
||||||
using namespace test_utilities;
|
using namespace test_utilities;
|
||||||
@@ -49,7 +50,7 @@ void test_comparison()
|
|||||||
const PolyCollection& cp2=p2;
|
const PolyCollection& cp2=p2;
|
||||||
ValueFactory v;
|
ValueFactory v;
|
||||||
|
|
||||||
p1.template register_types<Types...>();
|
register_types<Types...>(p1);
|
||||||
fill<
|
fill<
|
||||||
constraints<is_not_equality_comparable>,
|
constraints<is_not_equality_comparable>,
|
||||||
Types...
|
Types...
|
||||||
@@ -123,7 +124,7 @@ void test_comparison()
|
|||||||
const PolyCollection& cp2=p2;
|
const PolyCollection& cp2=p2;
|
||||||
ValueFactory v;
|
ValueFactory v;
|
||||||
|
|
||||||
p1.template register_types<Types...>();
|
register_types<Types...>(p1);
|
||||||
fill<
|
fill<
|
||||||
constraints<is_equality_comparable,is_copy_constructible>,
|
constraints<is_equality_comparable,is_copy_constructible>,
|
||||||
Types...
|
Types...
|
||||||
@@ -157,7 +158,7 @@ void test_stateless_lambda_comparability_check()
|
|||||||
|
|
||||||
void test_comparison()
|
void test_comparison()
|
||||||
{
|
{
|
||||||
test_comparison<
|
/* test_comparison<
|
||||||
any_types::collection,auto_increment,
|
any_types::collection,auto_increment,
|
||||||
any_types::t1,any_types::t2,any_types::t3,
|
any_types::t1,any_types::t2,any_types::t3,
|
||||||
any_types::t4,any_types::t5>();
|
any_types::t4,any_types::t5>();
|
||||||
@@ -168,6 +169,10 @@ void test_comparison()
|
|||||||
test_comparison<
|
test_comparison<
|
||||||
function_types::collection,auto_increment,
|
function_types::collection,auto_increment,
|
||||||
function_types::t1,function_types::t2,function_types::t3,
|
function_types::t1,function_types::t2,function_types::t3,
|
||||||
function_types::t4,function_types::t5>();
|
function_types::t4,function_types::t5>();*/
|
||||||
|
test_comparison<
|
||||||
|
variant_types::collection,auto_increment,
|
||||||
|
variant_types::t1,variant_types::t2,variant_types::t3,
|
||||||
|
variant_types::t4,variant_types::t5>();
|
||||||
test_stateless_lambda_comparability_check();
|
test_stateless_lambda_comparability_check();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016-2020 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "any_types.hpp"
|
#include "any_types.hpp"
|
||||||
#include "base_types.hpp"
|
#include "base_types.hpp"
|
||||||
#include "function_types.hpp"
|
#include "function_types.hpp"
|
||||||
|
#include "variant_types.hpp"
|
||||||
#include "test_utilities.hpp"
|
#include "test_utilities.hpp"
|
||||||
|
|
||||||
using namespace test_utilities;
|
using namespace test_utilities;
|
||||||
@@ -58,7 +59,7 @@ void test_allocator_aware_construction()
|
|||||||
BOOST_TEST(p3==p);
|
BOOST_TEST(p3==p);
|
||||||
BOOST_TEST(d2==d3);
|
BOOST_TEST(d2==d3);
|
||||||
BOOST_TEST(p2.empty());
|
BOOST_TEST(p2.empty());
|
||||||
do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
|
do_((BOOST_TEST(!is_open_and_registered<Types>(p2)),0)...);
|
||||||
BOOST_TEST(p2.get_allocator().comes_from(root1));
|
BOOST_TEST(p2.get_allocator().comes_from(root1));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -91,7 +92,7 @@ void test_allocator_aware_construction()
|
|||||||
if(AlwaysEqual)BOOST_TEST(d2==d3);
|
if(AlwaysEqual)BOOST_TEST(d2==d3);
|
||||||
|
|
||||||
BOOST_TEST(p2.empty());
|
BOOST_TEST(p2.empty());
|
||||||
do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
|
do_((BOOST_TEST(!is_open_and_registered<Types>(p2)),0)...);
|
||||||
|
|
||||||
#if !defined(BOOST_MSVC)&&\
|
#if !defined(BOOST_MSVC)&&\
|
||||||
BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
|
BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
|
||||||
@@ -146,7 +147,7 @@ void test_allocator_aware_construction()
|
|||||||
if(Propagate||AlwaysEqual){
|
if(Propagate||AlwaysEqual){
|
||||||
BOOST_TEST(d2==d3);
|
BOOST_TEST(d2==d3);
|
||||||
BOOST_TEST(p2.empty());
|
BOOST_TEST(p2.empty());
|
||||||
do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
|
do_((BOOST_TEST(!is_open_and_registered<Types>(p2)),0)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
|
#if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<40900)
|
||||||
@@ -187,7 +188,7 @@ void test_allocator_aware_construction()
|
|||||||
e3=get_layout_data<Types...>(p3);
|
e3=get_layout_data<Types...>(p3);
|
||||||
BOOST_TEST(d2==e3);
|
BOOST_TEST(d2==e3);
|
||||||
BOOST_TEST(d3==e2);
|
BOOST_TEST(d3==e2);
|
||||||
do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
|
do_((BOOST_TEST(!is_open_and_registered<Types>(p2)),0)...);
|
||||||
if(!use_same_allocator
|
if(!use_same_allocator
|
||||||
#if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
|
#if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
|
||||||
/* std::unordered_map::swap does not swap equal allocators */
|
/* std::unordered_map::swap does not swap equal allocators */
|
||||||
@@ -218,7 +219,7 @@ void test_allocator_aware_construction()
|
|||||||
f3=get_layout_data<Types...>(p3);
|
f3=get_layout_data<Types...>(p3);
|
||||||
BOOST_TEST(e2==f3);
|
BOOST_TEST(e2==f3);
|
||||||
BOOST_TEST(e3==f2);
|
BOOST_TEST(e3==f2);
|
||||||
do_((BOOST_TEST(!p3.template is_registered<Types>()),0)...);
|
do_((BOOST_TEST(!is_open_and_registered<Types>(p3)),0)...);
|
||||||
if(!use_same_allocator){
|
if(!use_same_allocator){
|
||||||
BOOST_TEST(p2.get_allocator().comes_from(root1));
|
BOOST_TEST(p2.get_allocator().comes_from(root1));
|
||||||
BOOST_TEST(p3.get_allocator().comes_from(root2));
|
BOOST_TEST(p3.get_allocator().comes_from(root2));
|
||||||
@@ -306,12 +307,12 @@ void test_construction()
|
|||||||
PolyCollection p2{std::move(p)};
|
PolyCollection p2{std::move(p)};
|
||||||
BOOST_TEST(!p2.empty());
|
BOOST_TEST(!p2.empty());
|
||||||
BOOST_TEST(p.empty());
|
BOOST_TEST(p.empty());
|
||||||
do_((BOOST_TEST(!p.template is_registered<Types>()),0)...);
|
do_((BOOST_TEST(!is_open_and_registered<Types>(p)),0)...);
|
||||||
|
|
||||||
p={std::move(p2)};
|
p={std::move(p2)};
|
||||||
BOOST_TEST(!p.empty());
|
BOOST_TEST(!p.empty());
|
||||||
BOOST_TEST(p2.empty());
|
BOOST_TEST(p2.empty());
|
||||||
do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
|
do_((BOOST_TEST(!is_open_and_registered<Types>(p2)),0)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -371,5 +372,9 @@ void test_construction()
|
|||||||
function_types::collection,auto_increment,
|
function_types::collection,auto_increment,
|
||||||
function_types::t1,function_types::t2,function_types::t3,
|
function_types::t1,function_types::t2,function_types::t3,
|
||||||
function_types::t4,function_types::t5>();
|
function_types::t4,function_types::t5>();
|
||||||
|
test_construction<
|
||||||
|
variant_types::collection,auto_increment,
|
||||||
|
variant_types::t1,variant_types::t2,variant_types::t3,
|
||||||
|
variant_types::t4,variant_types::t5>();
|
||||||
test_scoped_allocator();
|
test_scoped_allocator();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2016 Joaquin M Lopez Munoz.
|
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "any_types.hpp"
|
#include "any_types.hpp"
|
||||||
#include "base_types.hpp"
|
#include "base_types.hpp"
|
||||||
#include "function_types.hpp"
|
#include "function_types.hpp"
|
||||||
|
#include "variant_types.hpp"
|
||||||
#include "test_utilities.hpp"
|
#include "test_utilities.hpp"
|
||||||
|
|
||||||
using namespace test_utilities;
|
using namespace test_utilities;
|
||||||
@@ -37,25 +38,25 @@ void test_emplacement()
|
|||||||
|
|
||||||
iterator it=p.template emplace<type>(4);
|
iterator it=p.template emplace<type>(4);
|
||||||
BOOST_TEST(*p.template begin<type>()==type{4});
|
BOOST_TEST(*p.template begin<type>()==type{4});
|
||||||
BOOST_TEST(&*it==&*p.begin(typeid(type)));
|
BOOST_TEST(&*it==&*p.begin(typeid_<type>(p)));
|
||||||
|
|
||||||
iterator it2=p.template emplace_hint<type>(it,3);
|
iterator it2=p.template emplace_hint<type>(it,3);
|
||||||
BOOST_TEST(*p.template begin<type>()==type{3});
|
BOOST_TEST(*p.template begin<type>()==type{3});
|
||||||
BOOST_TEST(&*it2==&*p.begin(typeid(type)));
|
BOOST_TEST(&*it2==&*p.begin(typeid_<type>(p)));
|
||||||
|
|
||||||
iterator it3=p.template emplace_hint<type>(p.cend(),5);
|
iterator it3=p.template emplace_hint<type>(p.cend(),5);
|
||||||
BOOST_TEST(*(p.template end<type>()-1)==type{5});
|
BOOST_TEST(*(p.template end<type>()-1)==type{5});
|
||||||
BOOST_TEST(&*it3==&*(p.end(typeid(type))-1));
|
BOOST_TEST(&*it3==&*(p.end(typeid_<type>(p))-1));
|
||||||
|
|
||||||
local_base_iterator lbit=
|
local_base_iterator lbit=
|
||||||
p.template emplace_pos<type>(p.begin(typeid(type)),2);
|
p.template emplace_pos<type>(p.begin(typeid_<type>(p)),2);
|
||||||
BOOST_TEST(*static_cast<local_iterator>(lbit)==type{2});
|
BOOST_TEST(*static_cast<local_iterator>(lbit)==type{2});
|
||||||
BOOST_TEST(lbit==p.begin(typeid(type)));
|
BOOST_TEST(lbit==p.begin(typeid_<type>(p)));
|
||||||
|
|
||||||
local_base_iterator lbit2=
|
local_base_iterator lbit2=
|
||||||
p.template emplace_pos<type>(p.cend(typeid(type)),6);
|
p.template emplace_pos<type>(p.cend(typeid_<type>(p)),6);
|
||||||
BOOST_TEST(*static_cast<local_iterator>(lbit2)==type{6});
|
BOOST_TEST(*static_cast<local_iterator>(lbit2)==type{6});
|
||||||
BOOST_TEST(lbit2==p.end(typeid(type))-1);
|
BOOST_TEST(lbit2==p.end(typeid_<type>(p))-1);
|
||||||
|
|
||||||
local_iterator lit=p.emplace_pos(p.template begin<type>(),1);
|
local_iterator lit=p.emplace_pos(p.template begin<type>(),1);
|
||||||
BOOST_TEST(*lit==type{1});
|
BOOST_TEST(*lit==type{1});
|
||||||
@@ -76,8 +77,8 @@ void test_emplacement()
|
|||||||
p.template emplace<type>();
|
p.template emplace<type>();
|
||||||
p.template emplace_hint<type>(p.begin());
|
p.template emplace_hint<type>(p.begin());
|
||||||
p.template emplace_hint<type>(p.cend());
|
p.template emplace_hint<type>(p.cend());
|
||||||
p.template emplace_pos<type>(p.begin(typeid(type)));
|
p.template emplace_pos<type>(p.begin(typeid_<type>(p)));
|
||||||
p.template emplace_pos<type>(p.cend(typeid(type)));
|
p.template emplace_pos<type>(p.cend(typeid_<type>(p)));
|
||||||
p.emplace_pos(p.template begin<type>());
|
p.emplace_pos(p.template begin<type>());
|
||||||
p.emplace_pos(p.template cend<type>());
|
p.emplace_pos(p.template cend<type>());
|
||||||
BOOST_TEST(p.size()==7);
|
BOOST_TEST(p.size()==7);
|
||||||
@@ -95,9 +96,9 @@ void test_emplacement()
|
|||||||
p.template emplace_hint<type>(p.begin(),v.template make<type>());
|
p.template emplace_hint<type>(p.begin(),v.template make<type>());
|
||||||
p.template emplace_hint<type>(p.cend(),v.template make<type>());
|
p.template emplace_hint<type>(p.cend(),v.template make<type>());
|
||||||
p.template emplace_pos<type>(
|
p.template emplace_pos<type>(
|
||||||
p.begin(typeid(type)),v.template make<type>());
|
p.begin(typeid_<type>(p)),v.template make<type>());
|
||||||
p.template emplace_pos<type>(
|
p.template emplace_pos<type>(
|
||||||
p.cend(typeid(type)),v.template make<type>());
|
p.cend(typeid_<type>(p)),v.template make<type>());
|
||||||
p.emplace_pos(p.template begin<type>(),v.template make<type>());
|
p.emplace_pos(p.template begin<type>(),v.template make<type>());
|
||||||
p.emplace_pos(p.template cend<type>(),v.template make<type>());
|
p.emplace_pos(p.template cend<type>(),v.template make<type>());
|
||||||
BOOST_TEST(p.size()==7);
|
BOOST_TEST(p.size()==7);
|
||||||
@@ -118,4 +119,8 @@ void test_emplacement()
|
|||||||
function_types::collection,auto_increment,
|
function_types::collection,auto_increment,
|
||||||
function_types::t1,function_types::t2,function_types::t3,
|
function_types::t1,function_types::t2,function_types::t3,
|
||||||
function_types::t4,function_types::t5>();
|
function_types::t4,function_types::t5>();
|
||||||
|
test_emplacement<
|
||||||
|
variant_types::collection,auto_increment,
|
||||||
|
variant_types::t1,variant_types::t2,variant_types::t3,
|
||||||
|
variant_types::t4,variant_types::t5>();
|
||||||
}
|
}
|
||||||
|
|||||||