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
This commit is contained in:
joaquintides
2024-12-28 10:56:06 +01:00
committed by GitHub
parent 89cb3f4e29
commit fcd9cebc92
108 changed files with 4425 additions and 729 deletions
+1 -1
View File
@@ -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",
), ),
+1 -1
View File
@@ -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
+147
View File
@@ -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);
};
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

+166 -77
View File
@@ -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
+19 -18
View File
@@ -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);
+452 -42
View File
@@ -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]
+7 -2
View File
@@ -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
; ;
+36 -1
View File
@@ -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";
//]
}
} }
+103
View File
@@ -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";
//]
}
}
+163 -32
View File
@@ -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);
}
} }
+35 -6
View File
@@ -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>()<<", "
+150 -89
View File
@@ -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
+17 -39
View File
@@ -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 ]
; ;
+3 -1
View File
@@ -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();
} }
+101
View File
@@ -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>();
}
+9
View File
@@ -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();
+2 -2
View File
@@ -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) \
+3 -1
View File
@@ -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();
+17 -11
View File
@@ -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>();
} }
+10 -5
View File
@@ -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();
} }
+13 -8
View File
@@ -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();
} }
+17 -12
View File
@@ -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>();
} }

Some files were not shown because too many files have changed in this diff Show More