Feature/variant_collection (#26)
* added variant_collection
* added variant_collection
* avoided &* on null pointers
* made (non-public) fixed_variant ctor explicit
* tested higher-arity visit
* implemented visit<void>
* fixed {boost::variant2|std}::variant insertion
* fixed lookup issues with invoke_visit
* removed unneeded constexpr qualifiers
* s/typeid_/index
* reverted c6bc62f6d2 as Clang 5.0 didnt seem to like it
* reinstated c6bc62f6d2
* dropped -std=c++1z for Clang 5.0
* updated docs and examples
* added boost::poly_collection::visit_by_index
* typo
* explicit cted tuple in make_iota_tuple
* changed function name to see if it helps with mangling-related Clang 3.8 ICE
* rewritten make_iota_tuple to try to make Clang 3.8 happier
* added boost::variant_collection_of
@@ -347,7 +347,7 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 5.0",
|
||||
"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",
|
||||
),
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ jobs:
|
||||
install: clang-4.0
|
||||
- toolset: clang
|
||||
compiler: clang++-5.0
|
||||
cxxstd: "11,14,1z"
|
||||
cxxstd: "11,14"
|
||||
os: ubuntu-latest
|
||||
container: ubuntu:18.04
|
||||
install: clang-5.0
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
[/
|
||||
Copyright 2024 Joaquin M Lopez Munoz.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[template closed_poly_collection_synopsis[class_name template_header value_type type_index]
|
||||
``[template_header]``
|
||||
class ``[class_name]``
|
||||
{
|
||||
public:
|
||||
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.types ['// types:]]``
|
||||
|
||||
using value_type=``[value_type]``;
|
||||
using allocator_type=Allocator;
|
||||
using size_type=std::size_t;
|
||||
using difference_type=std::ptrdiff_t;
|
||||
using reference=value_type&;
|
||||
using const_reference=const value_type&;
|
||||
using pointer=typename std::allocator_traits<Allocator>::pointer;
|
||||
using const_pointer=typename std::allocator_traits<Allocator>::const_pointer;
|
||||
using _type_index_=``[type_index]``;
|
||||
using iterator=``/implementation-defined/``;
|
||||
using const_iterator=``/implementation-defined/``;
|
||||
using _local_base_iterator_=``/implementation-defined/``;
|
||||
using _const_local_base_iterator_=``/implementation-defined/``;
|
||||
template<typename T> using _local_iterator_=``/implementation-defined/``;
|
||||
template<typename T> using _const_local_iterator_=``/implementation-defined/``;
|
||||
class _const_base_segment_info_;
|
||||
class _base_segment_info_;
|
||||
template<typename T> class _const_segment_info_;
|
||||
template<typename T> class _segment_info_;
|
||||
using _base_segment_info_iterator_=``/implementation-defined/``;
|
||||
using _const_base_segment_info_iterator_=``/implementation-defined/``;
|
||||
class _const_segment_traversal_info_;
|
||||
class _segment_traversal_info_;
|
||||
|
||||
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.construct_copy_destroy ['// construct/destroy/copy:]]``
|
||||
|
||||
``[class_name]``();
|
||||
``[class_name]``(const ``[class_name]``&);
|
||||
``[class_name]``(``[class_name]``&&);
|
||||
explicit ``[class_name]``(const allocator_type& al);
|
||||
``[class_name]``(const ``[class_name]``& x,const allocator_type& al);
|
||||
``[class_name]``(``[class_name]``&& x,const allocator_type& al);
|
||||
template<typename InputIterator>
|
||||
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.construct_copy_destroy.range_construction [class_name]]``(
|
||||
InputIterator first,InputIterator last,
|
||||
const allocator_type& al=allocator_type{});
|
||||
|
||||
``[class_name]``& operator=(const ``[class_name]``&);
|
||||
``[class_name]``& operator=(``[class_name]``&&);
|
||||
|
||||
allocator_type get_allocator()const noexcept;
|
||||
|
||||
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.iterators ['// iterators:]]``
|
||||
|
||||
iterator _begin_()noexcept;
|
||||
iterator _end_()noexcept;
|
||||
const_iterator _begin_()const noexcept;
|
||||
const_iterator _end_()const noexcept;
|
||||
const_iterator _cbegin_()const noexcept;
|
||||
const_iterator _cend_()const noexcept;
|
||||
|
||||
local_base_iterator _begin_(const type_index& info);
|
||||
local_base_iterator _end_(const type_index& info);
|
||||
const_local_base_iterator _begin_(const type_index& info)const;
|
||||
const_local_base_iterator _end_(const type_index& info)const;
|
||||
const_local_base_iterator _cbegin_(const type_index& info)const;
|
||||
const_local_base_iterator _cend_(const type_index& info)const;
|
||||
|
||||
template<typename T> local_iterator<T> _begin_();
|
||||
template<typename T> local_iterator<T> _end_();
|
||||
template<typename T> const_local_iterator<T> _begin_()const;
|
||||
template<typename T> const_local_iterator<T> _end_()const;
|
||||
template<typename T> const_local_iterator<T> _cbegin_()const;
|
||||
template<typename T> const_local_iterator<T> _cend_()const;
|
||||
|
||||
base_segment_info _segment_(const type_index& info);
|
||||
const_base_segment_info _segment_(const type_index& info)const;
|
||||
template<typename T> segment_info<T> _segment_();
|
||||
template<typename T> const_segment_info<T> _segment_()const;
|
||||
|
||||
segment_traversal_info _segment_traversal_()noexcept;
|
||||
const_segment_traversal_info _segment_traversal_()const noexcept;
|
||||
|
||||
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.capacity ['// capacity:]]``
|
||||
|
||||
bool empty()const noexcept;
|
||||
bool _empty_(const type_index& info)const;
|
||||
template<typename T> bool _empty_()const;
|
||||
|
||||
size_type size()const noexcept;
|
||||
size_type _size_(const type_index& info)const;
|
||||
template<typename T> size_type _size_()const;
|
||||
|
||||
size_type _max_size_(const type_index& info)const;
|
||||
template<typename T> size_type _max_size_()const;
|
||||
|
||||
size_type _capacity_(const type_index& info)const;
|
||||
template<typename T> size_type _capacity_()const;
|
||||
|
||||
void _reserve_(size_type n);
|
||||
void _reserve_(const type_index& info,size_type n);
|
||||
template<typename T>void _reserve_(size_type n);
|
||||
|
||||
void _shrink_to_fit_();
|
||||
void _shrink_to_fit_(const type_index& info);
|
||||
template<typename T> void _shrink_to_fit_();
|
||||
|
||||
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.modifiers ['// modifiers:]]``
|
||||
|
||||
template<typename T,typename... Args>
|
||||
iterator _emplace_(Args&&... args);
|
||||
|
||||
template<typename T,typename... Args>
|
||||
iterator _emplace_hint_(const_iterator hint,Args&&... args);
|
||||
|
||||
template<typename T,typename LocalIterator,typename... Args>
|
||||
auto _emplace_pos_(LocalIterator pos,Args&&... args);
|
||||
|
||||
template<typename T>
|
||||
iterator _insert_(T&& x);
|
||||
|
||||
template<typename CollectionIterator,typename T>
|
||||
auto _insert_hint_(CollectionIterator hint,T&& x);
|
||||
|
||||
template<typename InputIterator>
|
||||
void _insert_range_(InputIterator first,InputIterator last);
|
||||
|
||||
template<typename CollectionIterator,typename InputIterator>
|
||||
void _insert_hint_range_(CollectionIterator hint,InputIterator first,InputIterator last);
|
||||
|
||||
template<typename CollectionIterator>
|
||||
auto _erase_(CollectionIterator pos);
|
||||
|
||||
template<typename CollectionIterator>
|
||||
auto _erase_(CollectionIterator first,CollectionIterator last);
|
||||
|
||||
void _clear_()noexcept;
|
||||
void _clear_(const type_index& info);
|
||||
template<typename T> void _clear_();
|
||||
|
||||
void swap(``[class_name]``& x);
|
||||
};
|
||||
]
|
||||
|
After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 25 KiB |
@@ -1,7 +1,7 @@
|
||||
[library Boost.PolyCollection
|
||||
[quickbook 1.6]
|
||||
[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]
|
||||
[id poly_collection]
|
||||
[dirname poly_collection]
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
[def _Boost.TypeErasure_ [@boost:/libs/type_erasure Boost.TypeErasure]]
|
||||
[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 _duck_typing_ [@https://en.wikipedia.org/wiki/Duck_typing ['duck typing]]]
|
||||
[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 _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::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 _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,
|
||||
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:
|
||||
|
||||
* `boost::base_collection`
|
||||
* `boost::function_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++:
|
||||
|
||||
* Classic base/derived or OOP polymorphism.
|
||||
* Function wrapping in the spirit of _std::function_.
|
||||
* 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.
|
||||
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
|
||||
the same opportunities for efficient container data structures as we have
|
||||
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
|
||||
dealing with OOP, `std::function`-like polymorphism and duck typing as
|
||||
implemented by Boost.TypeErasure:
|
||||
Boost.PolyCollection provides four different container class templates
|
||||
dealing with OOP, `std::function`-like polymorphism, duck typing as
|
||||
implemented by Boost.TypeErasure, and closed polymorphism in the spirit of
|
||||
`std::variant`:
|
||||
|
||||
* `boost::base_collection`
|
||||
* `boost::function_collection`
|
||||
* `boost::any_collection`
|
||||
* `boost::variant_collection`
|
||||
|
||||
The interfaces of these containers are mostly the same and follow the usual
|
||||
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
|
||||
internally defined `Concept2` that extends `Concept`.].
|
||||
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.
|
||||
|
||||
[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]
|
||||
|
||||
[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]
|
||||
|
||||
[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]
|
||||
|
||||
[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
|
||||
[link poly_collection.tutorial.deeper_into_the_segmented_nature.reserve `reserve`])
|
||||
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]
|
||||
|
||||
@@ -456,7 +526,7 @@ registered. Segment-specific addressability also includes traversal:
|
||||
|
||||
The following runs only over the `warrior`s of the collection:
|
||||
|
||||
[segmented_structure_6]
|
||||
[segmented_structure_7]
|
||||
|
||||
Output:
|
||||
|
||||
@@ -475,11 +545,11 @@ whole-collection iterators only model _ForwardIterator_.
|
||||
A terser range-based `for` loop can be used with the convenience `segment`
|
||||
member function:
|
||||
|
||||
[segmented_structure_7]
|
||||
[segmented_structure_8]
|
||||
|
||||
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:
|
||||
|
||||
@@ -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
|
||||
`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
|
||||
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
|
||||
segment-element `for` loop like the following:
|
||||
|
||||
[segmented_structure_9]
|
||||
[segmented_structure_11]
|
||||
|
||||
Segment decomposition of traversal loops forms the basis of
|
||||
[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
|
||||
advance to minimize reallocations:
|
||||
|
||||
[segmented_structure_10]
|
||||
[segmented_structure_12]
|
||||
|
||||
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
|
||||
@@ -532,7 +607,7 @@ member functions, which throw
|
||||
|
||||
`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
|
||||
segment is created later (through element insertion or with
|
||||
@@ -710,7 +785,7 @@ signature, etc.].
|
||||
|
||||
[import ../example/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
|
||||
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<std::function<signature>>` → `boost::function_collection<signature>`
|
||||
* `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
|
||||
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
|
||||
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]
|
||||
@@ -861,10 +946,9 @@ calls are not needed.
|
||||
|
||||
[section Performance]
|
||||
|
||||
[def _vs2015_x86_ Visual Studio 2015 x86]
|
||||
[def _vs2015_x64_ Visual Studio 2015 x64]
|
||||
[def _gcc63_x64_ GCC 6.3 x64]
|
||||
[def _clang40_x64_ Clang 4.0 x64]
|
||||
[def _vs2022_x64_ Visual Studio 2022 x64]
|
||||
[def _gcc132_x64_ GCC 13.2 x64]
|
||||
[def _clang130_x64_ Clang 13.0 x64]
|
||||
|
||||
[template perf_fig[name environment file]
|
||||
[section [environment]]
|
||||
@@ -891,13 +975,13 @@ Boost.PolyCollection in two scenarios:
|
||||
[link poly_collection.tutorial.algorithms.type_restitution type restitution]).
|
||||
|
||||
As a comparison baseline we used containers and facilities from the
|
||||
standard library and Boost (details below). Tests were run in the
|
||||
following environments:
|
||||
standard library and Boost (details below). Tests were run on a Windows 10 machine
|
||||
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
|
||||
* *_vs2015_x64_*: Visual C++ 2015 in 64-bit (x64) release mode, same machine
|
||||
* *_gcc63_x64_*: GCC 6.3 release mode, Xubuntu 17.04 x64, Intel Core i7-5820 @3.3GHz
|
||||
* *_clang40_x64_*: Clang 4.0 release mode, same machine
|
||||
* *_vs2022_x64_*: Visual Studio 2022 in 64-bit (x64), release mode
|
||||
* *_gcc132_x64_*: GCC 13.2.0 for MinGW, `-O3 -DNDEBUG`
|
||||
* *_clang130_x64_*: Clang 13.0.1 for Visual Studio (clang-cl) in 64-bit (x64), release mode
|
||||
|
||||
[section Container definitions]
|
||||
|
||||
@@ -931,39 +1015,48 @@ following environments:
|
||||
|
||||
[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]
|
||||
|
||||
[section Insertion tests]
|
||||
|
||||
Tests measure the time taken to insert /n/ elements (/n/ between
|
||||
10'''<superscript>2</superscript>''' and 10'''<superscript>7</superscript>''')
|
||||
from a source of values with types following the cyclic sequence
|
||||
|
||||
`T1` `T1` `T2` `T2` `T3` `T1` `T1` `T2` `T2` `T3` ···
|
||||
from a source of values with types randomly selected from `T1`, `T2` and `T3` with equal probability.
|
||||
|
||||
No `reserve` operation is done before insertion.
|
||||
The figures show resulting times in nanoseconds/element.
|
||||
The horizontal axis is logarithmic.
|
||||
|
||||
[section Results for `boost::base_collection`]
|
||||
[perf_fig Insertion.._vs2015_x86_..insert_base_vs2015_x86]
|
||||
[perf_fig Insertion.._vs2015_x64_..insert_base_vs2015_x64]
|
||||
[perf_fig Insertion.._gcc63_x64_..insert_base_gcc63_x64]
|
||||
[perf_fig Insertion.._clang40_x64_..insert_base_clang40_x64]
|
||||
[perf_fig Insertion.._vs2022_x64_..insert_base_vs2022_x64]
|
||||
[perf_fig Insertion.._gcc132_x64_..insert_base_gcc132_x64]
|
||||
[perf_fig Insertion.._clang130_x64_..insert_base_clang130_x64]
|
||||
[endsect]
|
||||
|
||||
[section Results for `boost::function_collection`]
|
||||
[perf_fig Insertion.._vs2015_x86_..insert_function_vs2015_x86]
|
||||
[perf_fig Insertion.._vs2015_x64_..insert_function_vs2015_x64]
|
||||
[perf_fig Insertion.._gcc63_x64_..insert_function_gcc63_x64]
|
||||
[perf_fig Insertion.._clang40_x64_..insert_function_clang40_x64]
|
||||
[perf_fig Insertion.._vs2022_x64_..insert_function_vs2022_x64]
|
||||
[perf_fig Insertion.._gcc132_x64_..insert_function_gcc132_x64]
|
||||
[perf_fig Insertion.._clang130_x64_..insert_function_clang130_x64]
|
||||
[endsect]
|
||||
|
||||
[section Results for `boost::any_collection`]
|
||||
[perf_fig Insertion.._vs2015_x86_..insert_any_vs2015_x86]
|
||||
[perf_fig Insertion.._vs2015_x64_..insert_any_vs2015_x64]
|
||||
[perf_fig Insertion.._gcc63_x64_..insert_any_gcc63_x64]
|
||||
[perf_fig Insertion.._clang40_x64_..insert_any_clang40_x64]
|
||||
[perf_fig Insertion.._vs2022_x64_..insert_any_vs2022_x64]
|
||||
[perf_fig Insertion.._gcc132_x64_..insert_any_gcc132_x64]
|
||||
[perf_fig Insertion.._clang130_x64_..insert_any_clang130_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]
|
||||
@@ -983,21 +1076,25 @@ whereas for `boost::any_collection` we use
|
||||
|
||||
[perf_for_each_incrementable]
|
||||
|
||||
and for `boost::variant_collection` we have
|
||||
|
||||
[perf_for_each_alternative]
|
||||
|
||||
The baseline container is tested with three different setups:
|
||||
|
||||
* Directly as initialized by the process described for the
|
||||
[link poly_collection.performance.insertion_tests insertion tests].
|
||||
The sequence of types is complex enough that CPU's branch prediction mechanisms
|
||||
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
|
||||
As elements are ordered according to their
|
||||
construction time, certain degree of memory contiguity is expected.
|
||||
* 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.
|
||||
* With an extra post-insertion stage that randomly
|
||||
shuffles all the elements in the container. This is the worst possible
|
||||
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:
|
||||
|
||||
@@ -1011,24 +1108,27 @@ The figures show resulting times in nanoseconds/element.
|
||||
The horizontal axis is logarithmic.
|
||||
|
||||
[section Results for `boost::base_collection`]
|
||||
[perf_fig Processing.._vs2015_x86_..for_each_base_vs2015_x86]
|
||||
[perf_fig Processing.._vs2015_x64_..for_each_base_vs2015_x64]
|
||||
[perf_fig Processing.._gcc63_x64_..for_each_base_gcc63_x64]
|
||||
[perf_fig Processing.._clang40_x64_..for_each_base_clang40_x64]
|
||||
[perf_fig Processing.._vs2022_x64_..for_each_base_vs2022_x64]
|
||||
[perf_fig Processing.._gcc132_x64_..for_each_base_gcc132_x64]
|
||||
[perf_fig Processing.._clang130_x64_..for_each_base_clang130_x64]
|
||||
[endsect]
|
||||
|
||||
[section Results for `boost::function_collection`]
|
||||
[perf_fig Processing.._vs2015_x86_..for_each_function_vs2015_x86]
|
||||
[perf_fig Processing.._vs2015_x64_..for_each_function_vs2015_x64]
|
||||
[perf_fig Processing.._gcc63_x64_..for_each_function_gcc63_x64]
|
||||
[perf_fig Processing.._clang40_x64_..for_each_function_clang40_x64]
|
||||
[perf_fig Processing.._vs2022_x64_..for_each_function_vs2022_x64]
|
||||
[perf_fig Processing.._gcc132_x64_..for_each_function_gcc132_x64]
|
||||
[perf_fig Processing.._clang130_x64_..for_each_function_clang130_x64]
|
||||
[endsect]
|
||||
|
||||
[section Results for `boost::any_collection`]
|
||||
[perf_fig Processing.._vs2015_x86_..for_each_any_vs2015_x86]
|
||||
[perf_fig Processing.._vs2015_x64_..for_each_any_vs2015_x64]
|
||||
[perf_fig Processing.._gcc63_x64_..for_each_any_gcc63_x64]
|
||||
[perf_fig Processing.._clang40_x64_..for_each_any_clang40_x64]
|
||||
[perf_fig Processing.._vs2022_x64_..for_each_any_vs2022_x64]
|
||||
[perf_fig Processing.._gcc132_x64_..for_each_any_gcc132_x64]
|
||||
[perf_fig Processing.._clang130_x64_..for_each_any_clang130_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]
|
||||
@@ -1089,24 +1189,6 @@ parallel processing.
|
||||
|
||||
[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]
|
||||
|
||||
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 Boost 1.88]
|
||||
|
||||
* Added `boost::variant_collection`, a closed polymorphic collection
|
||||
similar in behavior to `std::vector<std::variant<...>>`.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Boost 1.76]
|
||||
|
||||
* Worked around [@https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95888 GCC bug] affecting
|
||||
@@ -1203,7 +1292,7 @@ Boost.PolyCollection:
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Acknowledgments]
|
||||
[section Acknowledgements]
|
||||
|
||||
The library uses [@http://www.pdimov.com/ Peter Dimov]'s
|
||||
[@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_.
|
||||
|
||||
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.
|
||||
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
|
||||
|
||||
@@ -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.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
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]``
|
||||
class ``[class_name]``
|
||||
{
|
||||
@@ -20,6 +20,7 @@
|
||||
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/``;
|
||||
@@ -58,7 +59,7 @@
|
||||
template<typename... T>
|
||||
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;
|
||||
|
||||
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.iterators ['// iterators:]]``
|
||||
@@ -70,12 +71,12 @@
|
||||
const_iterator _cbegin_()const noexcept;
|
||||
const_iterator _cend_()const noexcept;
|
||||
|
||||
local_base_iterator _begin_(const std::type_info& info);
|
||||
local_base_iterator _end_(const std::type_info& info);
|
||||
const_local_base_iterator _begin_(const std::type_info& info)const;
|
||||
const_local_base_iterator _end_(const std::type_info& info)const;
|
||||
const_local_base_iterator _cbegin_(const std::type_info& info)const;
|
||||
const_local_base_iterator _cend_(const std::type_info& info)const;
|
||||
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_();
|
||||
@@ -84,8 +85,8 @@
|
||||
template<typename T> const_local_iterator<T> _cbegin_()const;
|
||||
template<typename T> const_local_iterator<T> _cend_()const;
|
||||
|
||||
base_segment_info _segment_(const std::type_info& info);
|
||||
const_base_segment_info _segment_(const std::type_info& info)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;
|
||||
|
||||
@@ -95,25 +96,25 @@
|
||||
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.capacity ['// capacity:]]``
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
size_type _capacity_(const std::type_info& info)const;
|
||||
size_type _capacity_(const type_index& info)const;
|
||||
template<typename T> size_type _capacity_()const;
|
||||
|
||||
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);
|
||||
|
||||
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_();
|
||||
|
||||
``[link poly_collection.reference.polymorphic_containers.polymorphic_collections.modifiers ['// modifiers:]]``
|
||||
@@ -146,7 +147,7 @@
|
||||
auto _erase_(CollectionIterator first,CollectionIterator last);
|
||||
|
||||
void _clear_()noexcept;
|
||||
void _clear_(const std::type_info& info);
|
||||
void _clear_(const type_index& info);
|
||||
template<typename T> void _clear_();
|
||||
|
||||
void swap(``[class_name]``& x);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[/
|
||||
Copyright 2016-2017 Joaquin M Lopez Munoz.
|
||||
Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
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>` }.
|
||||
* *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]
|
||||
|
||||
[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
|
||||
`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
|
||||
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
|
||||
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
|
||||
(possibly empty) segment for `U` has been created. Registered types
|
||||
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
|
||||
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.
|
||||
|
||||
Collection traversal goes through the elements of the first segment,
|
||||
then the second, etc. The order in which segments are visited is
|
||||
unspecified but remains stable until a new segment is created.
|
||||
then the second, etc. For open collections, the order in which segments
|
||||
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
|
||||
`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 an object of type `C`, `cc` is a possibly `const` object of type `C`,
|
||||
* `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
|
||||
acceptable types,
|
||||
* `n` is a value of `size_type`,
|
||||
@@ -169,6 +179,18 @@ local) of `c` such that \[`xit1`, `xit2`) is a valid range.
|
||||
|
||||
[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]
|
||||
[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
|
||||
`C::const_base_segment_info` associated to the segment of `c` for `U`, then
|
||||
|
||||
* `ci.begin()==c.cbegin(typeid(U))`
|
||||
* `ci.cbegin()==c.cbegin(typeid(U))`
|
||||
* `ci.begin()==c.cbegin(index<U>)`
|
||||
* `ci.cbegin()==c.cbegin(index<U>)`
|
||||
* `ci.begin<U>()==c.cbegin<U>()`
|
||||
* `ci.cbegin<U>()==c.cbegin<U>()`
|
||||
* `ci.end()==c.cend(typeid(U))`
|
||||
* `ci.cend()==c.cend(typeid(U))`
|
||||
* `ci.end()==c.cend(index<U>)`
|
||||
* `ci.cend()==c.cend(index<U>)`
|
||||
* `ci.end<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]
|
||||
[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
|
||||
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.end()==c.end(typeid(U))`
|
||||
* `i.end()==c.end(index<U>)`
|
||||
* `i.end<U>()==c.end<U>()`
|
||||
|
||||
[#poly_collection.reference.polymorphic_containers.polymorphic_collections.types.const_segment_info]
|
||||
@@ -330,7 +352,7 @@ Internally calls `this->insert(j1,j2)` on construction.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Type registration]
|
||||
[section:type_registration Type registration (open collections only)]
|
||||
|
||||
[#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`]]
|
||||
@@ -646,6 +668,7 @@ from the last one to the end of its segment.
|
||||
[endsect]
|
||||
|
||||
[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]
|
||||
|
||||
@@ -794,14 +817,14 @@ namespace.
|
||||
|
||||
[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_:
|
||||
|
||||
* *Interface* = { `Base` : `std::is_polymorphic_v<Base>` }.
|
||||
* *Implementation*(`Base`) = { `Derived` : `std::is_base_of_v<Base,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]
|
||||
|
||||
@@ -974,19 +997,16 @@ wrapped callable object.
|
||||
|
||||
[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:
|
||||
|
||||
[itemized_list
|
||||
[*Interface* = { `Signature` : `Signature` = `R(Args...)` }.]
|
||||
[*Implementation*(`Signature`) = { `Callable` : `std::is_invocable_r_v<R,Callable,Args...>` }.]
|
||||
[*subobject*(`x`) =[br]
|
||||
`x.target<T>()` with `typeid(T)==x.target_type()`, if `x` is an instantiation of _function_collection_value_type_,[br]
|
||||
`x`, otherwise.
|
||||
]
|
||||
]
|
||||
* *Interface* = { `Signature` : `Signature` = `R(Args...)` }.
|
||||
* *Implementation*(`Signature`) = { `Callable` : `std::is_invocable_r_v<R,Callable,Args...>` }.
|
||||
* *subobject*(`x`) =
|
||||
* `x.target<T>()` with `typeid(T)==x.target_type()`, if `x` is an instantiation of _function_collection_value_type_,
|
||||
* `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]
|
||||
|
||||
@@ -1093,26 +1113,405 @@ The exact definition of `Concept2` is implementation defined.
|
||||
|
||||
[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
|
||||
_Boost.TypeErasure_:
|
||||
|
||||
[itemized_list
|
||||
[*Interface* = { `Concept` :
|
||||
* *Interface* = { `Concept` :
|
||||
as [@boost:/doc/html/boost_typeerasure/conceptdef.html specified] by _Boost.TypeErasure_,
|
||||
using the [@boost:/doc/html/boost/type_erasure/_self.html `_self`]
|
||||
[@boost:/doc/html/boost/type_erasure/placeholder.html placeholder] }.]
|
||||
[*Implementation*(`Concept`) = { `Concrete` : `Concrete` satisfies `Concept` }.]
|
||||
[*subobject*(`x`) =[br]
|
||||
`boost::type_erasure::`[@boost:/doc/html/boost/type_erasure/any_cast.html `any_cast`]`<T&>(x)`
|
||||
[@boost:/doc/html/boost/type_erasure/placeholder.html placeholder] }.
|
||||
* *Implementation*(`Concept`) = { `Concrete` : `Concrete` satisfies `Concept` }.
|
||||
* *subobject*(`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)`,
|
||||
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]
|
||||
`x`, otherwise.
|
||||
]
|
||||
]
|
||||
including [@boost:/doc/html/boost/type_erasure/typeid_.html `typeid_`]`<>`,
|
||||
* `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]
|
||||
|
||||
@@ -1124,6 +1523,10 @@ _Boost.TypeErasure_:
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
``['`// total restitution for closed collections:`]``
|
||||
|
||||
struct all_types;
|
||||
|
||||
``['`// non-modifying sequence operations:`]``
|
||||
|
||||
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:
|
||||
|
||||
* [' `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
|
||||
of a collection of Boost.PolyCollection such that \[`first`, `middle`) and
|
||||
\[`middle`, `last`) are valid ranges.
|
||||
* `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]
|
||||
(2) `for_each_n(first,args...)`[br]
|
||||
@@ -1503,14 +1909,18 @@ as:[br]
|
||||
(4) `std::rotate_copy(rfirst,rmiddle,rlast,args...)`,[br]
|
||||
and `rfirst`, `rmiddle` and `rlast` are iterator-like objects behaving like
|
||||
their `first`, `middle` and `last` counterparts except that they
|
||||
dereference to the corresponding subobject (`const`) `T&` if pointing to a
|
||||
segment for `T` and `T` is in `Ts...`
|
||||
dereference to the corresponding subobject (`const`) `U&` if pointing to a
|
||||
segment for `U` and `U` is in `Us...`
|
||||
[footnote Strictly speaking a proper _ForwardIterator_ cannot behave
|
||||
like this as dereferencing must yield /exactly/ a (`const`) `value_type&`
|
||||
value, which disallows this type of polymorphism.].[br]
|
||||
[*Effects:] Equivalent to `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]
|
||||
|
||||
|
||||
@@ -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.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -13,7 +13,7 @@ project
|
||||
|
||||
exe algorithms
|
||||
: algorithms.cpp
|
||||
: <cxxstd>14
|
||||
: <cxxstd>17
|
||||
;
|
||||
|
||||
exe basic_any
|
||||
@@ -29,6 +29,11 @@ exe basic_function
|
||||
: <cxxstd>14
|
||||
;
|
||||
|
||||
exe basic_variant
|
||||
: basic_variant.cpp
|
||||
: <cxxstd>17
|
||||
;
|
||||
|
||||
exe exceptions
|
||||
: exceptions.cpp
|
||||
;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2016-2017 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <boost/poly_collection/algorithm.hpp>
|
||||
#include <boost/poly_collection/any_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_cast.hpp>
|
||||
#include <boost/type_erasure/builtin.hpp>
|
||||
@@ -32,6 +33,11 @@ std::ostream& operator<<(std::ostream& os,const window& w)
|
||||
return os;
|
||||
}
|
||||
|
||||
template<typename... Ts>
|
||||
struct overloaded:Ts...{using Ts::operator()...;};
|
||||
template<class... Ts>
|
||||
overloaded(Ts...)->overloaded<Ts...>;
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::base_collection<sprite> c;
|
||||
@@ -168,4 +174,33 @@ int main()
|
||||
});
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
|
||||
{
|
||||
//[algorithms_9
|
||||
boost::variant_collection<
|
||||
boost::mp11::mp_list<warrior,juggernaut,goblin,elf,std::string,window>
|
||||
> c;
|
||||
//= ...
|
||||
//<-
|
||||
c.insert(warrior(0));
|
||||
c.insert(std::string("play again"));
|
||||
c.insert(window("player one"));
|
||||
//->
|
||||
|
||||
auto print_sprite=[](const sprite& s) { s.render(std::cout); };
|
||||
auto print_string=[](const std::string& str){ std::cout<<str; };
|
||||
auto print_window=[](const window& w) { w.display(std::cout); };
|
||||
auto print=overloaded{print_sprite,print_string,print_window};
|
||||
|
||||
const char* comma="";
|
||||
boost::poly_collection::for_each<boost::poly_collection::all_types>(
|
||||
c.begin(),c.end(),[&](const auto& r){
|
||||
std::cout<<comma;
|
||||
print(r);
|
||||
comma=",";
|
||||
});
|
||||
std::cout<<"\n";
|
||||
|
||||
//]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||
*/
|
||||
|
||||
/* basic usage of boost::variant_collection */
|
||||
|
||||
#include <boost/poly_collection/variant_collection.hpp>
|
||||
#include <random>
|
||||
#include "rolegame.hpp"
|
||||
|
||||
template<typename... Ts>
|
||||
struct overloaded:Ts...{using Ts::operator()...;};
|
||||
template<class... Ts>
|
||||
overloaded(Ts...)->overloaded<Ts...>;
|
||||
|
||||
int main()
|
||||
{
|
||||
//[basic_variant_1
|
||||
//= #include <boost/poly_collection/variant_collection.hpp>
|
||||
//= ...
|
||||
//=
|
||||
boost::variant_collection<
|
||||
boost::mp11::mp_list<warrior,juggernaut,goblin,elf,std::string,window>
|
||||
> c;
|
||||
//]
|
||||
|
||||
{
|
||||
//[basic_variant_2
|
||||
boost::variant_collection_of<
|
||||
warrior,juggernaut,goblin,elf,std::string,window
|
||||
> c;
|
||||
//]
|
||||
}
|
||||
|
||||
// populate with sprites
|
||||
std::mt19937 gen{92754}; // some arbitrary random seed
|
||||
std::discrete_distribution<> rnd{{1,1,1,1}};
|
||||
for(int i=0;i<5;++i){ // assign each type with 1/4 probability
|
||||
switch(rnd(gen)){
|
||||
case 0: c.insert(warrior{i});break;
|
||||
case 1: c.insert(juggernaut{i});break;
|
||||
case 2: c.insert(goblin{i});break;
|
||||
case 3: c.insert(elf{i});break;
|
||||
}
|
||||
}
|
||||
|
||||
// populate with messages
|
||||
c.insert(std::string{"\"stamina: 10,000\""});
|
||||
c.insert(std::string{"\"game over\""});
|
||||
|
||||
// populate with windows
|
||||
c.insert(window{"pop-up 1"});
|
||||
c.insert(window{"pop-up 2"});
|
||||
|
||||
{
|
||||
//[basic_variant_3
|
||||
//= // usual utility to construct a visitor
|
||||
//= template<typename... Ts>
|
||||
//= struct overloaded:Ts...{using Ts::operator()...;};
|
||||
//= template<class... Ts>
|
||||
//= overloaded(Ts...)->overloaded<Ts...>;
|
||||
|
||||
const char* comma="";
|
||||
for(const auto& r:c){
|
||||
std::cout<<comma;
|
||||
visit(overloaded{
|
||||
[](const sprite& s) { s.render(std::cout); },
|
||||
[](const std::string& str){ std::cout<<str; },
|
||||
[](const window& w) { w.display(std::cout); }
|
||||
},r);
|
||||
comma=",";
|
||||
}
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
}
|
||||
|
||||
{
|
||||
//[basic_variant_4
|
||||
auto print_sprite=[](const sprite& s) { s.render(std::cout); };
|
||||
auto print_string=[](const std::string& str){ std::cout<<str; };
|
||||
auto print_window=[](const window& w) { w.display(std::cout); };
|
||||
|
||||
const char* comma="";
|
||||
for(const auto& r:c){
|
||||
std::cout<<comma;
|
||||
visit_by_index(
|
||||
r,
|
||||
print_sprite, // type #0: warrior
|
||||
print_sprite, // type #1: juggernaut
|
||||
print_sprite, // type #2: goblin
|
||||
print_sprite, // type #3: elf
|
||||
print_string, // type #4
|
||||
print_window); // type #5
|
||||
comma=",";
|
||||
}
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2016-2017 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -64,10 +64,13 @@ void resume_timing()
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <boost/mp11/list.hpp>
|
||||
#include <boost/variant2/variant.hpp>
|
||||
#include <boost/poly_collection/algorithm.hpp>
|
||||
#include <boost/poly_collection/any_collection.hpp>
|
||||
#include <boost/poly_collection/base_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/type_erasure/any.hpp>
|
||||
#include <boost/type_erasure/callable.hpp>
|
||||
@@ -143,13 +146,13 @@ struct ptr_vector:boost::ptr_vector<Base>
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
void insert(const T& x)
|
||||
BOOST_FORCEINLINE void insert(const T& x)
|
||||
{
|
||||
this->push_back(new T{x});
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
BOOST_FORCEINLINE void for_each(F f)
|
||||
{
|
||||
std::for_each(this->begin(),this->end(),f);
|
||||
}
|
||||
@@ -182,7 +185,7 @@ template<typename Base>
|
||||
struct base_collection:boost::base_collection<Base>
|
||||
{
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
BOOST_FORCEINLINE void for_each(F 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>
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -203,13 +206,13 @@ struct poly_for_each_base_collection:base_collection<Base>
|
||||
template<typename 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);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
BOOST_FORCEINLINE void for_each(F f)
|
||||
{
|
||||
std::for_each(this->begin(),this->end(),f);
|
||||
}
|
||||
@@ -243,7 +246,7 @@ template<typename Signature>
|
||||
struct func_collection:boost::function_collection<Signature>
|
||||
{
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
BOOST_FORCEINLINE void for_each(F 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>
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -270,7 +273,7 @@ struct any_vector:std::vector<boost::type_erasure::any<Concept>>
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
BOOST_FORCEINLINE void for_each(F f)
|
||||
{
|
||||
std::for_each(this->begin(),this->end(),f);
|
||||
}
|
||||
@@ -304,7 +307,7 @@ template<typename Concept>
|
||||
struct any_collection:boost::any_collection<Concept>
|
||||
{
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
BOOST_FORCEINLINE void for_each(F 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>
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -344,16 +409,38 @@ struct label
|
||||
template<typename... T>
|
||||
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<
|
||||
typename... Element,
|
||||
typename Container
|
||||
>
|
||||
void container_fill(unsigned int n,element_sequence<Element...>,Container& c)
|
||||
{
|
||||
auto m=n/sizeof...(Element);
|
||||
for(unsigned int i=0;i!=m;++i){
|
||||
using seq=int[sizeof...(Element)];
|
||||
(void)seq{(c.insert(Element(i)),0)...};
|
||||
pause_timing();
|
||||
std::mt19937 rng{1};
|
||||
std::uniform_int_distribution<> d(0,sizeof...(Element)-1);
|
||||
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;
|
||||
(n=(unsigned int)std::round(n0*std::pow(10.0,s/1000.0)))<=n1;
|
||||
s+=dsav){
|
||||
unsigned int m=(unsigned int)std::round(n/sizeof...(Element)),
|
||||
nn=m*sizeof...(Element);
|
||||
print(nn,insert_perf(nn,elements,labels)...);
|
||||
print(n,insert_perf(n,elements,labels)...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,9 +535,7 @@ void for_each_perf(
|
||||
for(unsigned int s=0,n=n0;
|
||||
(n=(unsigned int)std::round(n0*std::pow(10.0,s/1000.0)))<=n1;
|
||||
s+=dsav){
|
||||
unsigned int m=(unsigned int)std::round(n/sizeof...(Element)),
|
||||
nn=m*sizeof...(Element);
|
||||
print(nn,for_each_perf(nn,elements,f,labels)...);
|
||||
print(n,for_each_perf(n,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&>;
|
||||
|
||||
@@ -495,15 +598,19 @@ int main(int argc, char *argv[])
|
||||
insert_function=false,
|
||||
for_each_function=false,
|
||||
insert_any=false,
|
||||
for_each_any=false;
|
||||
std::array<test,7> tests={{
|
||||
for_each_any=false,
|
||||
insert_variant=false,
|
||||
for_each_variant=false;
|
||||
std::array<test,9> tests={{
|
||||
{"all",all},
|
||||
{"insert_base",insert_base},
|
||||
{"for_each_base",for_each_base},
|
||||
{"insert_function",insert_function},
|
||||
{"for_each_function",for_each_function},
|
||||
{"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){
|
||||
@@ -526,8 +633,7 @@ int main(int argc, char *argv[])
|
||||
unsigned int n0=100,n1=10000000,dsav=50; /* sav for savart */
|
||||
|
||||
{
|
||||
auto seq= element_sequence<
|
||||
derived1,derived1,derived2,derived2,derived3>{};
|
||||
auto seq= element_sequence<derived1,derived2,derived3>{};
|
||||
auto f= for_each_callable{};
|
||||
auto pv= label<ptr_vector<base>>
|
||||
{"ptr_vector"};
|
||||
@@ -540,7 +646,7 @@ int main(int argc, char *argv[])
|
||||
auto fbc= label<poly_for_each_base_collection<base>>
|
||||
{"base_collection (poly::for_each)"};
|
||||
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)"};
|
||||
|
||||
@@ -551,8 +657,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
using signature=int(int);
|
||||
|
||||
auto seq= element_sequence<
|
||||
concrete1,concrete1,concrete2,concrete2,concrete3>{};
|
||||
auto seq= element_sequence<concrete1,concrete2,concrete3>{};
|
||||
auto f = for_each_callable{};
|
||||
auto fv= label<func_vector<signature>>
|
||||
{"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 av= label<any_vector<concept_>>
|
||||
{"any_vector"};
|
||||
@@ -601,4 +706,30 @@ int main(int argc, char *argv[])
|
||||
if(all||for_each_any)for_each_perf(
|
||||
n0,n1,dsav,seq,f,av,sav,shav,ac,fac,rfac);
|
||||
}
|
||||
{
|
||||
//[perf_variant_types
|
||||
using type_list=boost::mp11::mp_list<int,double,char>;
|
||||
//]
|
||||
|
||||
auto seq= element_sequence<int,double,char>{};
|
||||
auto f= for_each_alternative{};
|
||||
auto vv= label<variant_vector<type_list>>
|
||||
{"variant_vector"};
|
||||
auto svv= label<sorted_variant_vector<type_list>>
|
||||
{"sorted variant_vector"};
|
||||
auto shvv= label<shuffled_variant_vector<type_list>>
|
||||
{"shuffled variant_vector"};
|
||||
auto vc= label<variant_collection<type_list>>
|
||||
{"variant_collection"};
|
||||
auto fvc= label<poly_for_each_variant_collection<type_list>>
|
||||
{"variant_collection (poly::for_each)"};
|
||||
auto rfvc= label<
|
||||
poly_for_each_variant_collection<
|
||||
type_list,boost::poly_collection::all_types>>
|
||||
{"variant_collection (restituted poly::for_each)"};
|
||||
|
||||
if(all||insert_variant)insert_perf(n0,n1,dsav,seq,vv,vc);
|
||||
if(all||for_each_variant)for_each_perf(
|
||||
n0,n1,dsav,seq,f,vv,svv,shvv,vc,fvc,rfvc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2016-2017 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <algorithm>
|
||||
#include <boost/poly_collection/any_collection.hpp>
|
||||
#include <boost/poly_collection/base_collection.hpp>
|
||||
#include <boost/poly_collection/variant_collection.hpp>
|
||||
#include <boost/type_erasure/operators.hpp>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
@@ -104,6 +105,22 @@ int main()
|
||||
//]
|
||||
|
||||
//[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="";
|
||||
for(auto first=c.begin(typeid(warrior)),last=c.end(typeid(warrior));
|
||||
first!=last;++first){
|
||||
@@ -114,7 +131,7 @@ int main()
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
|
||||
//[segmented_structure_7
|
||||
//[segmented_structure_8
|
||||
/*=const char**/ comma="";
|
||||
for(const auto& x:c.segment(typeid(warrior))){
|
||||
std::cout<<comma;
|
||||
@@ -124,7 +141,7 @@ int main()
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
|
||||
//[segmented_structure_8
|
||||
//[segmented_structure_9
|
||||
/*=const char**/ comma="";
|
||||
for(auto first=c.begin<warrior>(),last=c.end<warrior>();
|
||||
first!=last;++first){
|
||||
@@ -150,10 +167,22 @@ int main()
|
||||
}
|
||||
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=[&](){
|
||||
//[segmented_structure_9
|
||||
//[segmented_structure_11
|
||||
const char* comma="";
|
||||
for(auto seg:c.segment_traversal()){
|
||||
for(sprite& s:seg){
|
||||
@@ -167,12 +196,12 @@ int main()
|
||||
};
|
||||
render();
|
||||
|
||||
//[segmented_structure_10
|
||||
//[segmented_structure_12
|
||||
c.reserve<goblin>(100); // no reallocation till we exceed 100 goblins
|
||||
std::cout<<c.capacity<goblin>()<<"\n"; // prints 100
|
||||
//]
|
||||
|
||||
//[segmented_structure_11
|
||||
//[segmented_structure_13
|
||||
c.reserve(1000); // reserve(1000) for each segment
|
||||
std::cout<<c.capacity<warrior>()<<", "
|
||||
<<c.capacity<juggernaut>()<<", "
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2016-2020 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -14,7 +14,9 @@
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/config.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/iterator_traits.hpp>
|
||||
#include <boost/poly_collection/detail/segment_split.hpp>
|
||||
@@ -37,6 +39,11 @@
|
||||
* being a particular example).
|
||||
*/
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4714) /* marked as __forceinline not inlined */
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
@@ -56,9 +63,12 @@ template<
|
||||
typename... Ts,typename Iterator,typename Predicate,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
BOOST_FORCEINLINE
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
@@ -69,9 +79,12 @@ template<
|
||||
typename... Ts,typename Iterator,typename Predicate,
|
||||
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;
|
||||
return false;
|
||||
}
|
||||
@@ -82,9 +95,12 @@ template<
|
||||
typename... Ts,typename Iterator,typename Predicate,
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
@@ -99,13 +115,16 @@ struct for_each_alg
|
||||
}
|
||||
};
|
||||
|
||||
template<
|
||||
typename... Ts,typename Iterator,typename Function,
|
||||
template<typename... Ts,typename Iterator,typename Function,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -126,19 +145,20 @@ template<
|
||||
typename... Ts,typename Iterator,typename Size,typename Function,
|
||||
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 model_type=typename traits::model_type;
|
||||
using local_base_iterator=typename traits::local_base_iterator;
|
||||
|
||||
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{}));
|
||||
auto lbit=traits::local_base_iterator_from(first);
|
||||
auto sit=traits::base_segment_info_iterator_from(first);
|
||||
for(;;){
|
||||
auto m=sit->end()-lbit;
|
||||
Size m=static_cast<Size>(sit->end()-lbit);
|
||||
if(n<=m){
|
||||
auto it=alg(sit->type_info(),lbit,n,f);
|
||||
return traits::iterator_from(
|
||||
@@ -158,13 +178,14 @@ template<
|
||||
typename Iterator,typename... Args,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
Iterator generic_find(
|
||||
BOOST_FORCEINLINE Iterator generic_find(
|
||||
const Iterator& first,const Iterator& last,Args&&... args)
|
||||
{
|
||||
using traits=iterator_traits<Iterator>;
|
||||
using model_type=typename traits::model_type;
|
||||
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{}),
|
||||
std::forward<Args>(args)...);
|
||||
for(auto i:detail::segment_split(first,last)){
|
||||
@@ -182,7 +203,8 @@ template<
|
||||
typename... Ts,typename Iterator,typename T,
|
||||
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);
|
||||
}
|
||||
@@ -193,7 +215,8 @@ template<
|
||||
typename... Ts,typename Iterator,typename Predicate,
|
||||
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);
|
||||
}
|
||||
@@ -204,7 +227,8 @@ template<
|
||||
typename... Ts,typename Iterator,typename Predicate,
|
||||
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);
|
||||
}
|
||||
@@ -217,7 +241,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename ForwardIterator,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
Iterator find_first_of(
|
||||
BOOST_FORCEINLINE Iterator find_first_of(
|
||||
const Iterator& first1,const Iterator& last1,
|
||||
ForwardIterator first2,ForwardIterator last2)
|
||||
{
|
||||
@@ -229,7 +253,7 @@ template<
|
||||
typename ForwardIterator,typename BinaryPredicate,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
Iterator find_first_of(
|
||||
BOOST_FORCEINLINE Iterator find_first_of(
|
||||
const Iterator& first1,const Iterator& last1,
|
||||
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
||||
{
|
||||
@@ -240,23 +264,27 @@ template<typename... Ts>
|
||||
struct adjacent_find_alg
|
||||
{
|
||||
template<
|
||||
typename LocalIterator,typename BinaryPredicate,typename LocalBaseIterator
|
||||
typename LocalIterator,typename BinaryPredicate,
|
||||
typename TypeIndex,typename LocalBaseIterator
|
||||
>
|
||||
LocalBaseIterator operator()(
|
||||
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
|
||||
{
|
||||
using traits=iterator_traits<LocalIterator>;
|
||||
using model_type=typename traits::model_type;
|
||||
|
||||
if(first==last)return LocalBaseIterator{last};
|
||||
if(carry){
|
||||
auto p=restitute_iterator<Ts...>(deref_to(pred));
|
||||
if(p(*prev_info,prev,first))return prev;
|
||||
auto p=restitute_iterator<model_type,Ts...>(deref_to(pred));
|
||||
if(p(prev_info,prev,first))return prev;
|
||||
}
|
||||
auto res=std::adjacent_find(first,last,pred);
|
||||
if(res==last){
|
||||
carry=true;
|
||||
prev_info=&typeid(
|
||||
typename std::iterator_traits<LocalIterator>::value_type);
|
||||
prev_info=traits::template index<
|
||||
typename std::iterator_traits<LocalIterator>::value_type>();
|
||||
prev=LocalBaseIterator{last-1};
|
||||
}
|
||||
else carry=false;
|
||||
@@ -268,14 +296,15 @@ template<
|
||||
typename... Ts,typename Iterator,typename BinaryPredicate,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
Iterator adjacent_find(
|
||||
BOOST_FORCEINLINE Iterator adjacent_find(
|
||||
const Iterator& first,const Iterator& last,BinaryPredicate pred)
|
||||
{
|
||||
using traits=iterator_traits<Iterator>;
|
||||
using local_base_iterator=typename traits::local_base_iterator;
|
||||
|
||||
bool carry=false;
|
||||
const std::type_info* prev_info{&typeid(void)};
|
||||
auto prev_info=
|
||||
make_copyable(traits::template index<void>());
|
||||
local_base_iterator prev;
|
||||
return generic_find<adjacent_find_alg<Ts...>,Ts...>(
|
||||
first,last,pred,carry,prev_info,prev);
|
||||
@@ -285,7 +314,8 @@ template<
|
||||
typename... Ts,typename Iterator,
|
||||
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{});
|
||||
}
|
||||
@@ -295,10 +325,13 @@ template<
|
||||
typename Iterator,typename... Args,
|
||||
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)
|
||||
{
|
||||
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;
|
||||
for(auto i:detail::segment_split(first,last))res+=alg(i);
|
||||
return res;
|
||||
@@ -310,7 +343,8 @@ template<
|
||||
typename... Ts,typename Iterator,typename T,
|
||||
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);
|
||||
}
|
||||
@@ -321,7 +355,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename Predicate,
|
||||
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)
|
||||
{
|
||||
return generic_count<std_count_if,Ts...>(first,last,pred);
|
||||
@@ -366,7 +400,7 @@ template<
|
||||
typename InputIterator,typename BinaryPredicate,
|
||||
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,BinaryPredicate pred)
|
||||
{
|
||||
@@ -378,7 +412,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename InputIterator,
|
||||
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)
|
||||
{
|
||||
return algorithm::mismatch<Ts...>(
|
||||
@@ -390,7 +424,7 @@ template<
|
||||
typename InputIterator,typename BinaryPredicate,
|
||||
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,InputIterator last2,BinaryPredicate pred)
|
||||
{
|
||||
@@ -402,7 +436,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename InputIterator,
|
||||
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,InputIterator last2)
|
||||
{
|
||||
@@ -447,11 +481,13 @@ template<
|
||||
typename InputIterator,typename BinaryPredicate,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
bool equal(
|
||||
BOOST_FORCEINLINE bool equal(
|
||||
const Iterator& first1,const Iterator& last1,
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
@@ -460,7 +496,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename InputIterator,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
bool equal(
|
||||
BOOST_FORCEINLINE bool equal(
|
||||
const Iterator& first1,const Iterator& last1,InputIterator first2)
|
||||
{
|
||||
return algorithm::equal<Ts...>(first1,last1,first2,transparent_equal_to{});
|
||||
@@ -471,11 +507,13 @@ template<
|
||||
typename InputIterator,typename BinaryPredicate,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
bool equal(
|
||||
BOOST_FORCEINLINE bool equal(
|
||||
const Iterator& first1,const Iterator& last1,
|
||||
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;
|
||||
return first2==last2;
|
||||
}
|
||||
@@ -484,7 +522,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename InputIterator,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
bool equal(
|
||||
BOOST_FORCEINLINE bool equal(
|
||||
const Iterator& first1,const Iterator& last1,
|
||||
InputIterator first2,InputIterator last2)
|
||||
{
|
||||
@@ -496,7 +534,8 @@ template<
|
||||
typename Iterator,
|
||||
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>;
|
||||
|
||||
@@ -526,18 +565,19 @@ template<
|
||||
typename ForwardIterator,typename BinaryPredicate,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
bool is_permutation_suffix(
|
||||
BOOST_FORCEINLINE bool is_permutation_suffix(
|
||||
const Iterator& first1,const Iterator& last1,
|
||||
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
||||
{
|
||||
using traits=iterator_traits<Iterator>;
|
||||
using model_type=typename traits::model_type;
|
||||
|
||||
auto send=traits::end_base_segment_info_iterator_from(last1);
|
||||
for(auto i:detail::segment_split(first1,last1)){
|
||||
for(auto lbscan=i.begin();lbscan!=i.end();++lbscan){
|
||||
auto& info=i.type_info();
|
||||
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);
|
||||
if(algorithm::find_if<Ts...>(first1,scan,p)!=scan)continue;
|
||||
std::ptrdiff_t matches=std::count_if(first2,last2,p);
|
||||
@@ -553,7 +593,7 @@ template<
|
||||
typename ForwardIterator,typename BinaryPredicate,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
bool is_permutation(
|
||||
BOOST_FORCEINLINE bool is_permutation(
|
||||
Iterator first1,Iterator last1,ForwardIterator first2,BinaryPredicate pred)
|
||||
{
|
||||
std::tie(first1,first2)=algorithm::mismatch<Ts...>(first1,last1,first2,pred);
|
||||
@@ -565,7 +605,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename ForwardIterator,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
bool is_permutation(
|
||||
BOOST_FORCEINLINE bool is_permutation(
|
||||
const Iterator& first1,const Iterator& last1,ForwardIterator first2)
|
||||
{
|
||||
return algorithm::is_permutation<Ts...>(
|
||||
@@ -577,7 +617,7 @@ template<
|
||||
typename ForwardIterator,typename BinaryPredicate,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
bool is_permutation(
|
||||
BOOST_FORCEINLINE bool is_permutation(
|
||||
Iterator first1,Iterator last1,
|
||||
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
||||
{
|
||||
@@ -592,7 +632,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename ForwardIterator,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
bool is_permutation(
|
||||
BOOST_FORCEINLINE bool is_permutation(
|
||||
const Iterator& first1,const Iterator& last1,
|
||||
ForwardIterator first2,ForwardIterator last2)
|
||||
{
|
||||
@@ -605,7 +645,7 @@ template<
|
||||
typename ForwardIterator,typename BinaryPredicate,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
Iterator search(
|
||||
BOOST_FORCEINLINE Iterator search(
|
||||
const Iterator& first1,const Iterator& last1,
|
||||
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
||||
{
|
||||
@@ -626,7 +666,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename ForwardIterator,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
Iterator search(
|
||||
BOOST_FORCEINLINE Iterator search(
|
||||
const Iterator& first1,const Iterator& last1,
|
||||
ForwardIterator first2,ForwardIterator last2)
|
||||
{
|
||||
@@ -639,7 +679,7 @@ template<
|
||||
typename ForwardIterator,typename BinaryPredicate,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
Iterator find_end(
|
||||
BOOST_FORCEINLINE Iterator find_end(
|
||||
Iterator first1,Iterator last1,
|
||||
ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred)
|
||||
{
|
||||
@@ -659,7 +699,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename ForwardIterator,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
Iterator find_end(
|
||||
BOOST_FORCEINLINE Iterator find_end(
|
||||
const Iterator& first1,const Iterator& last1,
|
||||
ForwardIterator first2,ForwardIterator last2)
|
||||
{
|
||||
@@ -695,18 +735,19 @@ template<
|
||||
typename Size,typename T,typename BinaryPredicate,
|
||||
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,BinaryPredicate pred)
|
||||
{
|
||||
using traits=iterator_traits<Iterator>;
|
||||
using model_type=typename traits::model_type;
|
||||
using local_base_iterator=typename traits::local_base_iterator;
|
||||
|
||||
if(count<=0)return first;
|
||||
|
||||
bool carry=false;
|
||||
auto remain=count;
|
||||
auto alg=restitute_range<Ts...>(
|
||||
auto alg=restitute_range<model_type,Ts...>(
|
||||
cast_return<local_base_iterator>(search_n_alg{}),
|
||||
count,carry,remain,x,pred);
|
||||
local_base_iterator prev;
|
||||
@@ -728,7 +769,7 @@ template<
|
||||
typename Size,typename T,
|
||||
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)
|
||||
{
|
||||
return algorithm::search_n<Ts...>(
|
||||
@@ -740,11 +781,13 @@ template<
|
||||
typename Iterator,typename OutputIterator,typename... Args,
|
||||
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)
|
||||
{
|
||||
using model_type=typename iterator_traits<Iterator>::model_type;
|
||||
|
||||
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)...);
|
||||
res=alg(i);
|
||||
}
|
||||
@@ -757,7 +800,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename OutputIterator,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
OutputIterator copy(
|
||||
BOOST_FORCEINLINE OutputIterator copy(
|
||||
const Iterator& first,const Iterator& last,OutputIterator res)
|
||||
{
|
||||
return generic_copy<std_copy,Ts...>(first,last,res);
|
||||
@@ -769,17 +812,19 @@ template<
|
||||
typename... Ts,typename Iterator,typename Size,typename OutputIterator,
|
||||
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 model_type=typename traits::model_type;
|
||||
|
||||
if(count<=0)return res;
|
||||
|
||||
auto lbit=traits::local_base_iterator_from(first);
|
||||
auto sit=traits::base_segment_info_iterator_from(first);
|
||||
for(;;){
|
||||
auto n=(std::min)(count,sit->end()-lbit);
|
||||
auto alg=restitute_iterator<Ts...>(std_copy_n{},n,res);
|
||||
auto n=(std::min)(count,static_cast<Size>(sit->end()-lbit));
|
||||
auto alg=restitute_iterator<model_type,Ts...>(std_copy_n{},n,res);
|
||||
res=alg(sit->type_info(),lbit);
|
||||
if((count-=n)==0)break;
|
||||
++sit;
|
||||
@@ -794,7 +839,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename OutputIterator,typename Predicate,
|
||||
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)
|
||||
{
|
||||
return generic_copy<std_copy_if,Ts...>(first,last,res,pred);
|
||||
@@ -806,7 +851,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename OutputIterator,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
OutputIterator move(
|
||||
BOOST_FORCEINLINE OutputIterator move(
|
||||
const Iterator& first,const Iterator& last,OutputIterator res)
|
||||
{
|
||||
return generic_copy<std_move,Ts...>(first,last,res);
|
||||
@@ -819,7 +864,7 @@ template<
|
||||
typename OutputIterator,typename UnaryOperation,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
OutputIterator transform(
|
||||
BOOST_FORCEINLINE OutputIterator transform(
|
||||
const Iterator& first,const Iterator& last,
|
||||
OutputIterator res,UnaryOperation op)
|
||||
{
|
||||
@@ -847,7 +892,7 @@ template<
|
||||
typename OutputIterator,typename BinaryOperation,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
OutputIterator transform(
|
||||
BOOST_FORCEINLINE OutputIterator transform(
|
||||
const Iterator& first1,const Iterator& last1,InputIterator first2,
|
||||
OutputIterator res,BinaryOperation op)
|
||||
{
|
||||
@@ -878,7 +923,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename OutputIterator,typename T,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
OutputIterator replace_copy(
|
||||
BOOST_FORCEINLINE OutputIterator replace_copy(
|
||||
const Iterator& first,const Iterator& last,OutputIterator res,
|
||||
const T& old_x,const T& new_x)
|
||||
{
|
||||
@@ -913,7 +958,7 @@ template<
|
||||
typename Predicate,typename T,
|
||||
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,
|
||||
Predicate pred,const T& new_x)
|
||||
{
|
||||
@@ -926,7 +971,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename OutputIterator,typename T,
|
||||
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)
|
||||
{
|
||||
return generic_copy<std_remove_copy,Ts...>(first,last,res,x);
|
||||
@@ -939,7 +984,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename OutputIterator,typename Predicate,
|
||||
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)
|
||||
{
|
||||
return generic_copy<std_remove_copy_if,Ts...>(first,last,res,pred);
|
||||
@@ -950,23 +995,26 @@ struct unique_copy_alg
|
||||
{
|
||||
template<
|
||||
typename LocalIterator,typename OutputIterator,
|
||||
typename BinaryPredicate,typename LocalBaseIterator
|
||||
typename BinaryPredicate,typename TypeIndex,typename LocalBaseIterator
|
||||
>
|
||||
OutputIterator operator()(
|
||||
LocalIterator first,LocalIterator last,
|
||||
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
|
||||
{
|
||||
using traits=iterator_traits<LocalIterator>;
|
||||
using model_type=typename traits::model_type;
|
||||
|
||||
if(carry){
|
||||
auto p=restitute_iterator<Ts...>(deref_to(pred));
|
||||
for(;first!=last;++first)if(!p(*prev_info,prev,first))break;
|
||||
auto p=restitute_iterator<model_type,Ts...>(deref_to(pred));
|
||||
for(;first!=last;++first)if(!p(prev_info,prev,first))break;
|
||||
}
|
||||
if(first==last)return res;
|
||||
res=std::unique_copy(first,last,res,pred);
|
||||
carry=true;
|
||||
prev_info=&typeid(
|
||||
typename std::iterator_traits<LocalIterator>::value_type);
|
||||
prev_info=traits::template index<
|
||||
typename std::iterator_traits<LocalIterator>::value_type>();
|
||||
prev=LocalBaseIterator{last-1};
|
||||
return res;
|
||||
}
|
||||
@@ -977,7 +1025,7 @@ template<
|
||||
typename OutputIterator,typename BinaryPredicate,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
OutputIterator unique_copy(
|
||||
BOOST_FORCEINLINE OutputIterator unique_copy(
|
||||
const Iterator& first,const Iterator& last,
|
||||
OutputIterator res,BinaryPredicate pred)
|
||||
{
|
||||
@@ -985,7 +1033,8 @@ OutputIterator unique_copy(
|
||||
using local_base_iterator=typename traits::local_base_iterator;
|
||||
|
||||
bool carry=false;
|
||||
const std::type_info* prev_info{&typeid(void)};
|
||||
auto prev_info=
|
||||
make_copyable(traits::template index<void>());
|
||||
local_base_iterator prev;
|
||||
return generic_copy<unique_copy_alg<Ts...>,Ts...>(
|
||||
first,last,res,pred,carry,prev_info,prev);
|
||||
@@ -995,7 +1044,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename OutputIterator,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
OutputIterator unique_copy(
|
||||
BOOST_FORCEINLINE OutputIterator unique_copy(
|
||||
const Iterator& first,const Iterator& last,OutputIterator res)
|
||||
{
|
||||
return algorithm::unique_copy<Ts...>(first,last,res,transparent_equal_to{});
|
||||
@@ -1005,7 +1054,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename OutputIterator,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
OutputIterator rotate_copy(
|
||||
BOOST_FORCEINLINE OutputIterator rotate_copy(
|
||||
const Iterator& first,const Iterator& middle,const Iterator& last,
|
||||
OutputIterator res)
|
||||
{
|
||||
@@ -1040,15 +1089,17 @@ template<
|
||||
typename Distance,typename UniformRandomBitGenerator,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
OutputIterator sample(
|
||||
BOOST_FORCEINLINE OutputIterator sample(
|
||||
const Iterator& first,const Iterator& last,
|
||||
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);
|
||||
|
||||
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);
|
||||
if(n==0)return res;
|
||||
}
|
||||
@@ -1059,7 +1110,8 @@ template<
|
||||
typename... Ts,typename Iterator,typename Predicate,
|
||||
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);
|
||||
if(it==last)return true;
|
||||
@@ -1074,12 +1126,15 @@ template<
|
||||
typename OutputIterator1,typename OutputIterator2,typename Predicate,
|
||||
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,
|
||||
OutputIterator1 rest,OutputIterator2 resf,Predicate pred)
|
||||
{
|
||||
using model_type=typename iterator_traits<Iterator>::model_type;
|
||||
|
||||
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);
|
||||
}
|
||||
return {rest,resf};
|
||||
@@ -1094,7 +1149,9 @@ struct partition_point_pred
|
||||
bool operator()(const Iterator& it)const
|
||||
{
|
||||
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(
|
||||
traits::base_segment_info_iterator_from(it)->type_info(),
|
||||
traits::local_base_iterator_from(it));
|
||||
@@ -1107,7 +1164,7 @@ template<
|
||||
typename... Ts,typename Iterator,typename Predicate,
|
||||
enable_if_poly_collection_iterator<Iterator> =nullptr
|
||||
>
|
||||
Iterator partition_point(
|
||||
BOOST_FORCEINLINE Iterator partition_point(
|
||||
const Iterator& first,const Iterator& last,Predicate pred)
|
||||
{
|
||||
auto_iterator<Iterator> afirst{first},alast{last};
|
||||
@@ -1183,4 +1240,8 @@ using detail::algorithm::partition_point;
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop) /* C4714 */
|
||||
#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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -36,13 +36,13 @@ namespace detail{
|
||||
* prevents intermediate entities from calling Allocator::[construct|destroy].
|
||||
* allocator_adaptor<Allocator> does this by taking advantage of the fact that
|
||||
* 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
|
||||
* its inner construction of T.
|
||||
* - For the rest of types, construct uses placement new construction and
|
||||
* passes down the adaptor object itself as an argument following an
|
||||
* 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.
|
||||
* - For the rest of types, destroy(T) calls ~T directly.
|
||||
*
|
||||
@@ -53,7 +53,7 @@ namespace detail{
|
||||
template<typename T>
|
||||
class value_holder_base;
|
||||
|
||||
template<typename T>
|
||||
template<typename T,typename U>
|
||||
class value_holder;
|
||||
|
||||
template<typename T,typename Allocator,typename... Args>
|
||||
@@ -144,10 +144,11 @@ struct allocator_adaptor:Allocator
|
||||
p,std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T,typename... Args>
|
||||
void construct(value_holder<T>* p,Args&&... args)
|
||||
template<typename T,typename U,typename... 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>
|
||||
@@ -206,8 +207,8 @@ struct allocator_adaptor:Allocator
|
||||
p->~T();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void destroy(value_holder<T>* p)
|
||||
template<typename T,typename U>
|
||||
void destroy(value_holder<T,U>* p)
|
||||
{
|
||||
traits::destroy(
|
||||
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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -100,20 +100,25 @@ struct any_model
|
||||
type_erasure::_self&
|
||||
>;
|
||||
|
||||
using type_index=std::type_info;
|
||||
|
||||
template<typename Concrete>
|
||||
using is_implementation=std::true_type; /* can't compile-time check concept
|
||||
* compliance */
|
||||
template<typename T>
|
||||
using is_terminal=any_model_is_terminal<T>;
|
||||
|
||||
template<typename T>
|
||||
static const std::type_info& index(){return typeid(T);}
|
||||
|
||||
template<typename T>
|
||||
static const std::type_info& subtypeid(const T&){return typeid(T);}
|
||||
static const std::type_info& subindex(const T&){return typeid(T);}
|
||||
|
||||
template<
|
||||
typename Concept2,typename T,
|
||||
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)
|
||||
{
|
||||
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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -34,6 +34,7 @@ template<typename Base>
|
||||
struct base_model
|
||||
{
|
||||
using value_type=Base;
|
||||
using type_index=std::type_info;
|
||||
template<typename Derived>
|
||||
using is_implementation=std::is_base_of<Base,Derived>;
|
||||
template<typename T>
|
||||
@@ -48,11 +49,14 @@ private:
|
||||
typename std::enable_if<is_terminal<T>::value>::type*;
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
static const std::type_info& index(){return typeid(T);}
|
||||
|
||||
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>
|
||||
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>
|
||||
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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -49,17 +49,22 @@ struct function_model<R(Args...)>
|
||||
{
|
||||
using value_type=callable_wrapper<R(Args...)>;
|
||||
|
||||
using type_index=std::type_info;
|
||||
|
||||
template<typename Callable>
|
||||
using is_implementation=is_invocable_r<R,Callable&,Args...>;
|
||||
|
||||
template<typename T>
|
||||
using is_terminal=function_model_is_terminal<T>;
|
||||
|
||||
template<typename T>
|
||||
static const std::type_info& index(){return typeid(T);}
|
||||
|
||||
template<typename T>
|
||||
static const std::type_info& subtypeid(const T&){return typeid(T);}
|
||||
static const std::type_info& subindex(const T&){return typeid(T);}
|
||||
|
||||
template<typename Signature>
|
||||
static const std::type_info& subtypeid(
|
||||
static const std::type_info& subindex(
|
||||
const callable_wrapper<Signature>& f)
|
||||
{
|
||||
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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -23,7 +23,7 @@
|
||||
* 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 */
|
||||
|
||||
#define BOOST_POLY_COLLECTION_DEFINE_OVERLOAD_SET(name,f) \
|
||||
@@ -66,7 +66,7 @@ struct tail_closure_class
|
||||
template<typename... Args,std::size_t... I>
|
||||
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>
|
||||
@@ -99,7 +99,7 @@ struct head_closure_class
|
||||
template<typename... Args,std::size_t... I>
|
||||
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>
|
||||
|
||||
@@ -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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -13,6 +13,9 @@
|
||||
#pragma once
|
||||
#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>
|
||||
|
||||
namespace boost{
|
||||
@@ -21,20 +24,28 @@ namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* This can be further specialized by Model when the std type trait classes
|
||||
* fail to give the right info (as it can happen with class templates whose
|
||||
* nominally existing operators do not compile for certain instantiations).
|
||||
/* is_acceptable can be further specialized by (open collection) Model when
|
||||
* the std type_traits classes fail to give the right info (as it can happen
|
||||
* with class templates whose nominally existing operators do not compile for
|
||||
* certain instantiations).
|
||||
*/
|
||||
|
||||
template<typename T,typename Model,typename=void>
|
||||
struct is_acceptable:std::integral_constant<
|
||||
bool,
|
||||
Model::template is_implementation<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)
|
||||
Model::template is_implementation<T>::value&&is_moveable<T>::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 */
|
||||
|
||||
@@ -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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -25,7 +25,7 @@ namespace detail{
|
||||
template<typename T>
|
||||
using is_equality_comparable=std::integral_constant<
|
||||
bool,
|
||||
has_equal_to<T,T,bool>::value
|
||||
has_equal_to<const T&,const T&,bool>::value
|
||||
>;
|
||||
|
||||
} /* 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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -34,7 +34,7 @@ struct is_nothrow_equality_comparable<
|
||||
>::type
|
||||
>:std::integral_constant<
|
||||
bool,
|
||||
noexcept(std::declval<T>()==std::declval<T>())
|
||||
noexcept(std::declval<const T&>()==std::declval<const T&>())
|
||||
>{};
|
||||
|
||||
} /* 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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -226,12 +226,25 @@ private:
|
||||
return BaseIterator{bit+(it-static_cast<BaseIterator2>(bit))};
|
||||
}
|
||||
|
||||
base_iterator base()const noexcept
|
||||
{return local_iterator_impl::iterator_adaptor_::base();}
|
||||
const std::type_info& 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;}
|
||||
base_iterator base()const noexcept
|
||||
{
|
||||
return local_iterator_impl::iterator_adaptor_::base();
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -31,7 +31,8 @@ namespace detail{
|
||||
|
||||
/* (Internal) bunch of traits-grouped functions for const-preserving
|
||||
* 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>
|
||||
@@ -53,6 +54,8 @@ template<typename Iterator>
|
||||
struct iterator_traits
|
||||
{
|
||||
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<
|
||||
typename std::remove_reference<
|
||||
typename std::iterator_traits<Iterator>::reference
|
||||
@@ -93,10 +96,7 @@ struct iterator_traits
|
||||
static local_base_iterator
|
||||
local_base_iterator_from(iterator it)noexcept
|
||||
{
|
||||
return {
|
||||
it.mapit,
|
||||
model_of<container_type>::type::nonconst_iterator(it.segpos)
|
||||
};
|
||||
return {it.mapit,model_type::nonconst_iterator(it.segpos)};
|
||||
}
|
||||
|
||||
static iterator
|
||||
@@ -105,6 +105,12 @@ struct iterator_traits
|
||||
{
|
||||
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 */
|
||||
|
||||
@@ -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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -35,13 +35,23 @@ namespace detail{
|
||||
* {value_type*,sizeof(store_value_type)}.
|
||||
* - Model provides a function value_ptr for
|
||||
* 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>
|
||||
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 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<
|
||||
store_value_type,
|
||||
typename std::allocator_traits<Allocator>::
|
||||
@@ -266,7 +276,7 @@ private:
|
||||
static Concrete* concrete_ptr(store_value_type* p)noexcept
|
||||
{
|
||||
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
|
||||
@@ -282,8 +292,8 @@ private:
|
||||
static const store_value_type* const_store_value_type_ptr(
|
||||
const Concrete* p)noexcept
|
||||
{
|
||||
return static_cast<const value_holder<Concrete>*>(
|
||||
reinterpret_cast<const value_holder_base<Concrete>*>(p));
|
||||
return static_cast<const store_value_type*>(
|
||||
reinterpret_cast<const value_holder_base<final_type>*>(p));
|
||||
}
|
||||
|
||||
/* It would have sufficed if iterator_from returned const_store_iterator
|
||||
|
||||
@@ -16,17 +16,20 @@
|
||||
#include <algorithm>
|
||||
#include <boost/assert.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/iterator_impl.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_final.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 <iterator>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
@@ -42,13 +45,18 @@ using namespace detail;
|
||||
template<typename Model,typename Allocator>
|
||||
class poly_collection
|
||||
{
|
||||
template<typename T>
|
||||
static const std::type_info& subtypeid(const T& x)
|
||||
{return Model::subtypeid(x);}
|
||||
/* used only to early force closed collection acceptability checks */
|
||||
static constexpr bool is_closed_collection=
|
||||
detail::is_closed_collection<Model>::value;
|
||||
|
||||
template<typename...>
|
||||
struct for_all_types{using type=void*;};
|
||||
template<typename... T>
|
||||
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>
|
||||
struct is_implementation: /* using makes VS2015 choke, hence we derive */
|
||||
Model::template is_implementation<typename std::decay<T>::type>{};
|
||||
@@ -116,14 +124,6 @@ class poly_collection
|
||||
template<typename T>
|
||||
using const_segment_iterator=
|
||||
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:
|
||||
/* types */
|
||||
@@ -136,8 +136,24 @@ public:
|
||||
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=typename Model::type_index;
|
||||
|
||||
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>
|
||||
friend class detail::iterator_impl;
|
||||
template<typename,typename>
|
||||
@@ -183,7 +199,7 @@ public:
|
||||
template<typename 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:
|
||||
friend class poly_collection;
|
||||
@@ -377,21 +393,38 @@ public:
|
||||
|
||||
/* construct/destroy/copy */
|
||||
|
||||
poly_collection()=default;
|
||||
poly_collection(){initialize_map();};
|
||||
|
||||
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):
|
||||
map{segment_map_allocator_type{al}}{}
|
||||
map{segment_map_allocator_type{al}}
|
||||
{
|
||||
initialize_map();
|
||||
}
|
||||
|
||||
poly_collection(const poly_collection& x,const 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>
|
||||
poly_collection(
|
||||
InputIterator first,InputIterator last,
|
||||
const allocator_type& al=allocator_type{}):
|
||||
map{segment_map_allocator_type{al}}
|
||||
poly_collection{segment_map_allocator_type{al}}
|
||||
{
|
||||
this->insert(first,last);
|
||||
}
|
||||
@@ -399,37 +432,53 @@ public:
|
||||
// TODO: what to do with initializer_list?
|
||||
|
||||
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();}
|
||||
|
||||
/* type registration */
|
||||
/* type registration (open collections only) */
|
||||
|
||||
template<
|
||||
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()
|
||||
{
|
||||
/* http://twitter.com/SeanParent/status/558765089294020609 */
|
||||
|
||||
using seq=int[1+sizeof...(T)];
|
||||
(void)seq{
|
||||
0,
|
||||
(map.insert(
|
||||
typeid(T),segment_type::template make<T>(get_allocator())),0)...
|
||||
};
|
||||
mp11::mp_for_each<
|
||||
mp11::mp_transform<mp11::mp_identity,mp11::mp_list<T...>>
|
||||
>(create_segment{map});
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return is_registered(typeid(T));
|
||||
return is_registered(index<T>());
|
||||
}
|
||||
|
||||
/* iterators */
|
||||
@@ -441,60 +490,60 @@ public:
|
||||
const_iterator cbegin()const noexcept{return begin();}
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);}
|
||||
const_local_base_iterator cend(const std::type_info& info)const
|
||||
const_local_base_iterator cend(const type_index& info)const
|
||||
{return end(info);}
|
||||
|
||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||
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>()};
|
||||
}
|
||||
|
||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||
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>()};
|
||||
}
|
||||
|
||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||
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>()};
|
||||
}
|
||||
|
||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||
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>()};
|
||||
}
|
||||
|
||||
@@ -504,21 +553,22 @@ public:
|
||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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>
|
||||
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;}
|
||||
const_segment_traversal_info segment_traversal()const noexcept{return map;}
|
||||
@@ -531,7 +581,7 @@ public:
|
||||
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();
|
||||
}
|
||||
@@ -539,7 +589,7 @@ public:
|
||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||
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
|
||||
@@ -549,7 +599,7 @@ public:
|
||||
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();
|
||||
}
|
||||
@@ -557,10 +607,10 @@ public:
|
||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||
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();
|
||||
}
|
||||
@@ -568,10 +618,10 @@ public:
|
||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||
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();
|
||||
}
|
||||
@@ -579,7 +629,7 @@ public:
|
||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||
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)
|
||||
@@ -587,7 +637,7 @@ public:
|
||||
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);
|
||||
}
|
||||
@@ -605,7 +655,7 @@ public:
|
||||
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();
|
||||
}
|
||||
@@ -613,7 +663,7 @@ public:
|
||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||
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 */
|
||||
@@ -653,7 +703,7 @@ public:
|
||||
local_base_iterator
|
||||
emplace_pos(const_local_base_iterator pos,Args&&... args)
|
||||
{
|
||||
BOOST_ASSERT(pos.type_info()==typeid(T));
|
||||
BOOST_ASSERT(pos.type_info()==index<T>());
|
||||
return {
|
||||
pos.mapit,
|
||||
pos.segment().template emplace<T>(pos.base(),std::forward<Args>(args)...)
|
||||
@@ -709,7 +759,7 @@ public:
|
||||
nonconst_version<local_iterator_impl<BaseIterator>>
|
||||
insert(local_iterator_impl<BaseIterator> pos,T&& x)
|
||||
{
|
||||
BOOST_ASSERT(pos.type_info()==subtypeid(x));
|
||||
BOOST_ASSERT(pos.type_info()==subindex(x));
|
||||
return {
|
||||
pos.mapit,
|
||||
pos.segment().insert(pos.base(),std::forward<T>(x))
|
||||
@@ -846,7 +896,7 @@ public:
|
||||
size_type n=0;
|
||||
|
||||
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));
|
||||
++n;
|
||||
}
|
||||
@@ -940,7 +990,7 @@ public:
|
||||
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();
|
||||
}
|
||||
@@ -948,7 +998,7 @@ public:
|
||||
template<typename T,enable_if_acceptable<T> =nullptr>
|
||||
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);}
|
||||
@@ -958,6 +1008,71 @@ private:
|
||||
friend bool operator==(
|
||||
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<
|
||||
typename T,
|
||||
enable_if_acceptable<T> =nullptr,
|
||||
@@ -965,12 +1080,12 @@ private:
|
||||
>
|
||||
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);
|
||||
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(
|
||||
typeid(T),segment_type::template make<T>(get_allocator())).first;
|
||||
index<T>(),segment_type::template make<T>(get_allocator())).first;
|
||||
}
|
||||
|
||||
template<
|
||||
@@ -980,10 +1095,10 @@ private:
|
||||
>
|
||||
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;
|
||||
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<
|
||||
@@ -993,9 +1108,9 @@ private:
|
||||
>
|
||||
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);
|
||||
if(it==map.end())throw unregistered_type{id};
|
||||
if(it==map.end())throw unregistered_type{subtype_info(x)};
|
||||
return it;
|
||||
}
|
||||
|
||||
@@ -1016,7 +1131,7 @@ private:
|
||||
const_segment_map_iterator get_map_iterator_for(
|
||||
const T& x,const segment_type& seg)
|
||||
{
|
||||
const auto& id=subtypeid(x);
|
||||
const auto& id=subindex(x);
|
||||
auto it=map.find(id);
|
||||
if(it!=map.end())return it;
|
||||
else return map.insert(
|
||||
@@ -1026,23 +1141,22 @@ private:
|
||||
template<typename T>
|
||||
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;
|
||||
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)->
|
||||
get_map_iterator_for(info);
|
||||
}
|
||||
|
||||
const_segment_map_iterator get_map_iterator_for(
|
||||
const std::type_info& info)const
|
||||
const_segment_map_iterator get_map_iterator_for(const type_index& info)const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1067,7 +1181,7 @@ private:
|
||||
>
|
||||
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(std::forward<T>(x));
|
||||
}
|
||||
@@ -1090,7 +1204,7 @@ private:
|
||||
static segment_base_iterator local_insert(
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -1102,7 +1216,7 @@ private:
|
||||
static segment_base_iterator local_insert(
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -1143,7 +1257,7 @@ bool operator==(
|
||||
const auto &mapx=x.map,&mapy=y.map;
|
||||
for(const auto& p:mapx){
|
||||
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;
|
||||
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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -175,6 +175,12 @@ public:
|
||||
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<
|
||||
typename T,
|
||||
typename std::enable_if<
|
||||
@@ -198,6 +204,17 @@ public:
|
||||
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>
|
||||
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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -13,11 +13,16 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <boost/poly_collection/detail/iterator_traits.hpp>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4714) /* marked as __forceinline not inlined */
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
@@ -32,16 +37,17 @@ class segment_splitter
|
||||
using traits=iterator_traits<PolyCollectionIterator>;
|
||||
using local_base_iterator=typename traits::local_base_iterator;
|
||||
using base_segment_info_iterator=typename traits::base_segment_info_iterator;
|
||||
using type_index=typename traits::type_index;
|
||||
|
||||
public:
|
||||
struct info
|
||||
{
|
||||
const std::type_info& type_info()const noexcept{return *pinfo_;}
|
||||
local_base_iterator begin()const noexcept{return begin_;}
|
||||
local_base_iterator end()const noexcept{return end_;}
|
||||
const type_index& type_info()const noexcept{return info_;}
|
||||
local_base_iterator begin()const noexcept{return begin_;}
|
||||
local_base_iterator end()const noexcept{return end_;}
|
||||
|
||||
const std::type_info* pinfo_;
|
||||
local_base_iterator begin_,end_;
|
||||
const type_index& info_;
|
||||
local_base_iterator begin_,end_;
|
||||
};
|
||||
|
||||
struct iterator:iterator_facade<iterator,info,std::input_iterator_tag,info>
|
||||
@@ -65,7 +71,7 @@ public:
|
||||
info dereference()const noexcept
|
||||
{
|
||||
return {
|
||||
&it->type_info(),
|
||||
it->type_info(),
|
||||
it==traits::base_segment_info_iterator_from(*pfirst)?
|
||||
traits::local_base_iterator_from(*pfirst):it->begin(),
|
||||
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) */
|
||||
|
||||
template<typename PolyCollectionIterator,typename F>
|
||||
void for_each_segment(
|
||||
BOOST_FORCEINLINE void for_each_segment(
|
||||
const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
|
||||
{
|
||||
using traits=iterator_traits<PolyCollectionIterator>;
|
||||
@@ -125,20 +131,20 @@ void for_each_segment(
|
||||
|
||||
if(sfirst!=slast){
|
||||
for(;;){
|
||||
f(info{&sfirst->type_info(),lbfirst,sfirst->end()});
|
||||
f(info{sfirst->type_info(),lbfirst,sfirst->end()});
|
||||
++sfirst;
|
||||
if(sfirst==slast)break;
|
||||
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){
|
||||
f(info{&sfirst->type_info(),lbfirst,lblast});
|
||||
f(info{sfirst->type_info(),lbfirst,lblast});
|
||||
}
|
||||
}
|
||||
#else
|
||||
template<typename PolyCollectionIterator,typename F>
|
||||
void for_each_segment(
|
||||
BOOST_FORCEINLINE void for_each_segment(
|
||||
const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
|
||||
{
|
||||
for(auto i:segment_split(first,last))f(i);
|
||||
@@ -151,4 +157,8 @@ void for_each_segment(
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop) /* C4714 */
|
||||
#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
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <type_traits>
|
||||
@@ -63,32 +64,7 @@ public:
|
||||
stride_iterator& operator=(Value* p_)noexcept{p=p_;return *this;}
|
||||
operator Value*()const noexcept{return p;}
|
||||
|
||||
template<
|
||||
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
|
||||
#include <boost/poly_collection/detail/begin_no_sanitize.hpp>
|
||||
|
||||
template<
|
||||
typename DerivedValue,
|
||||
@@ -97,21 +73,11 @@ public:
|
||||
(!std::is_const<Value>::value||std::is_const<DerivedValue>::value)
|
||||
>::type* =nullptr
|
||||
>
|
||||
#if defined(BOOST_POLY_COLLECTION_NO_SANITIZE)
|
||||
__attribute__((no_sanitize("undefined")))
|
||||
#endif
|
||||
BOOST_POLY_COLLECTION_NO_SANITIZE
|
||||
explicit operator DerivedValue*()const noexcept
|
||||
{return static_cast<DerivedValue*>(p);}
|
||||
|
||||
#if defined(BOOST_POLY_COLLECTION_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
|
||||
#endif
|
||||
#include <boost/poly_collection/detail/end_no_sanitize.hpp>
|
||||
|
||||
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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* 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::operator== and std::type_info::hash_code are costly
|
||||
* 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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
struct type_info_ptr_hash
|
||||
struct type_info_hash
|
||||
{
|
||||
std::size_t operator()(const std::type_info* p)const noexcept
|
||||
{return p->hash_code();}
|
||||
std::size_t operator()(const std::type_info& i)const noexcept
|
||||
{return i.hash_code();}
|
||||
};
|
||||
|
||||
struct type_info_ptr_equal_to
|
||||
struct type_info_equal_to
|
||||
{
|
||||
bool operator()(
|
||||
const std::type_info* p,const std::type_info* q)const noexcept
|
||||
{return *p==*q;}
|
||||
const std::type_info& i,const std::type_info& j)const noexcept
|
||||
{return i==j;}
|
||||
};
|
||||
|
||||
template<typename T,typename Allocator>
|
||||
class type_info_map
|
||||
{
|
||||
using map_type=std::unordered_map<
|
||||
const std::type_info*,T,
|
||||
type_info_ptr_hash,type_info_ptr_equal_to,
|
||||
std::reference_wrapper<const std::type_info>,T,
|
||||
type_info_hash,type_info_equal_to,
|
||||
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:
|
||||
@@ -147,7 +148,7 @@ public:
|
||||
{
|
||||
auto cit=cache.find(&key);
|
||||
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});
|
||||
return mit;
|
||||
}
|
||||
@@ -156,14 +157,14 @@ public:
|
||||
{
|
||||
auto cit=cache.find(&key);
|
||||
if(cit!=cache.end())return cit->second;
|
||||
return map.find(&key);
|
||||
return map.find(key);
|
||||
}
|
||||
|
||||
template<typename P>
|
||||
std::pair<iterator,bool> insert(const key_type& key,P&& x)
|
||||
{
|
||||
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();
|
||||
cache.insert({&key,p.first});
|
||||
return p;
|
||||
@@ -231,12 +232,12 @@ private:
|
||||
|
||||
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()
|
||||
{
|
||||
for(auto& p:cache)p.second=map.find(p.first);
|
||||
for(auto& p:cache)p.second=map.find(*p.first);
|
||||
}
|
||||
|
||||
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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -13,45 +13,145 @@
|
||||
#pragma once
|
||||
#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/iterator_traits.hpp>
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4714) /* marked as __forceinline not inlined */
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
struct all_types;
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* Given types Ts..., a const std::type_info& info and a local_base_iterator
|
||||
* it, we denote by restitute<Ts...>(info,it):
|
||||
* - 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().
|
||||
/* If a list of restituted types contain all_types, replaces it with the
|
||||
* list of all acceptable types of the associated closed collection.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
template<typename F,typename T,typename... Ts>
|
||||
struct restitute_range_class<F,T,Ts...>:
|
||||
restitute_range_class<F,Ts...>
|
||||
template<typename IsTotal,typename F,typename T,typename... Ts>
|
||||
struct restitute_range_class<IsTotal,F,T,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;
|
||||
|
||||
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>;
|
||||
|
||||
if(s.type_info()==typeid(T))
|
||||
if(s.type_info()==traits::template index<T>())
|
||||
return (this->f)(
|
||||
local_iterator{s.begin()},local_iterator{s.end()});
|
||||
else
|
||||
@@ -59,13 +159,31 @@ struct restitute_range_class<F,T,Ts...>:
|
||||
}
|
||||
};
|
||||
|
||||
template<typename F,typename T>
|
||||
struct restitute_range_class<std::true_type /* total */,F,T>
|
||||
{
|
||||
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()))
|
||||
{
|
||||
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<F>
|
||||
struct restitute_range_class<std::false_type /* non total */,F>
|
||||
{
|
||||
restitute_range_class(const F& f):f(f){}
|
||||
|
||||
template<typename SegmentInfo>
|
||||
auto operator()(SegmentInfo&& s)
|
||||
BOOST_FORCEINLINE auto operator()(SegmentInfo&& s)
|
||||
->decltype(std::declval<F>()(s.begin(),s.end()))
|
||||
{
|
||||
return f(s.begin(),s.end());
|
||||
@@ -74,57 +192,88 @@ struct restitute_range_class<F>
|
||||
F f;
|
||||
};
|
||||
|
||||
template<typename... Ts,typename F,typename... Args>
|
||||
auto restitute_range(const F& f,Args&&... args)
|
||||
->restitute_range_class<
|
||||
decltype(tail_closure(f,std::forward<Args>(args)...)),
|
||||
Ts...
|
||||
template<
|
||||
typename Model,typename... Ts,typename F,typename... Args,
|
||||
typename RestitutionList=restitution_list<Model,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)...);
|
||||
}
|
||||
|
||||
/* restitute_iterator<Ts...>(f,args2...)(index,it,args1...) resolves to
|
||||
* f(restitute<Ts...>(index,it),args1...,args2...).
|
||||
/* restitute_iterator<IsTotal,Ts...>(f,args2...)(info,it,args1...) resolves to
|
||||
* f(restitute<Ts...>(info,it),args1...,args2...).
|
||||
*/
|
||||
|
||||
template<typename F,typename... Ts>
|
||||
template<typename IsTotal,typename F,typename... Ts>
|
||||
struct restitute_iterator_class;
|
||||
|
||||
template<typename F,typename T,typename... Ts>
|
||||
struct restitute_iterator_class<F,T,Ts...>:
|
||||
restitute_iterator_class<F,Ts...>
|
||||
template<typename IsTotal,typename F,typename T,typename... Ts>
|
||||
struct restitute_iterator_class<IsTotal,F,T,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;
|
||||
|
||||
template<typename Iterator,typename... Args>
|
||||
auto operator()(
|
||||
const std::type_info& info,Iterator&& it,Args&&... args)
|
||||
template<
|
||||
typename TypeIndex,typename Iterator,typename... 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>()
|
||||
(std::forward<Iterator>(it),std::forward<Args>(args)...))
|
||||
std::declval<F>()(LocalIterator{it},std::forward<Args>(args)...))
|
||||
{
|
||||
using traits=iterator_traits<typename std::decay<Iterator>::type>;
|
||||
using local_iterator=typename traits::template local_iterator<T>;
|
||||
|
||||
if(info==typeid(T))
|
||||
return (this->f)(
|
||||
local_iterator{it},std::forward<Args>(args)...);
|
||||
else
|
||||
if(static_cast<const typename Traits::type_index&>(info)==
|
||||
Traits::template index<T>()){
|
||||
return (this->f)(LocalIterator{it},std::forward<Args>(args)...);
|
||||
}
|
||||
else{
|
||||
return super::operator()(
|
||||
info,std::forward<Iterator>(it),std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
struct restitute_iterator_class<F>
|
||||
template<typename F,typename T>
|
||||
struct restitute_iterator_class<std::true_type /* total */,F,T>
|
||||
{
|
||||
restitute_iterator_class(const F& f):f(f){}
|
||||
|
||||
template<typename Iterator,typename... Args>
|
||||
auto operator()(
|
||||
const std::type_info&,Iterator&& it,Args&&... args)
|
||||
template<
|
||||
typename TypeIndex,typename Iterator,typename... 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(
|
||||
std::declval<F>()
|
||||
(std::forward<Iterator>(it),std::forward<Args>(args)...))
|
||||
@@ -135,57 +284,20 @@ struct restitute_iterator_class<F>
|
||||
F f;
|
||||
};
|
||||
|
||||
template<typename... Ts,typename F,typename... Args>
|
||||
auto restitute_iterator(const F& f,Args&&... args)
|
||||
->restitute_iterator_class<
|
||||
decltype(tail_closure(f,std::forward<Args>(args)...)),
|
||||
Ts...
|
||||
>
|
||||
{
|
||||
return 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...).
|
||||
*/
|
||||
|
||||
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...
|
||||
template<
|
||||
typename Model,typename... Ts,typename F,typename... Args,
|
||||
typename RestitutionList=restitution_list<Model,Ts...>
|
||||
>
|
||||
auto restitute_iterator(const F& f,Args&&... args)->mp11::mp_apply<
|
||||
restitute_iterator_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)...);
|
||||
}
|
||||
@@ -196,4 +308,8 @@ auto binary_restitute_iterator(const F& f,Args&&... args)
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop) /* C4714 */
|
||||
#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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -13,7 +13,6 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/core/addressof.hpp>
|
||||
#include <boost/poly_collection/detail/is_constructible.hpp>
|
||||
#include <boost/poly_collection/detail/is_equality_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
|
||||
* protect us from greedy T's constructible from anything (like
|
||||
* 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{};
|
||||
@@ -61,24 +67,23 @@ protected:
|
||||
alignas(T) unsigned char s[sizeof(T)];
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
template<typename T,typename U=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<
|
||||
!std::is_same<
|
||||
typename std::decay<U>::type,value_holder_emplacing_ctor_t
|
||||
typename std::decay<Q>::type,value_holder_emplacing_ctor_t
|
||||
>::value
|
||||
>::type*;
|
||||
|
||||
using is_nothrow_move_constructible=std::is_nothrow_move_constructible<T>;
|
||||
using is_copy_constructible=std::is_copy_constructible<T>;
|
||||
using is_nothrow_copy_constructible=std::is_nothrow_copy_constructible<T>;
|
||||
using is_move_assignable=std::is_move_assignable<T>;
|
||||
using is_nothrow_move_assignable=std::is_nothrow_move_assignable<T>;
|
||||
using is_equality_comparable=detail::is_equality_comparable<T>;
|
||||
using is_nothrow_equality_comparable=
|
||||
detail::is_nothrow_equality_comparable<T>;
|
||||
using is_nothrow_move_constructible=std::is_nothrow_move_constructible<U>;
|
||||
using is_copy_constructible=std::is_copy_constructible<U>;
|
||||
using is_nothrow_copy_constructible=std::is_nothrow_copy_constructible<U>;
|
||||
using is_move_assignable=std::is_move_assignable<U>;
|
||||
using is_nothrow_move_assignable=std::is_nothrow_move_assignable<U>;
|
||||
using is_equality_comparable=detail::is_equality_comparable<U>;
|
||||
using is_nothrow_equality_comparable=detail::is_nothrow_equality_comparable<U>;
|
||||
|
||||
T* data()noexcept{return reinterpret_cast<T*>(&this->s);}
|
||||
const T* data()const noexcept
|
||||
@@ -92,14 +97,14 @@ public:
|
||||
typename Allocator,
|
||||
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)
|
||||
{copy(al,x);}
|
||||
{allocator_copy(al,x);}
|
||||
template<
|
||||
typename Allocator,
|
||||
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)
|
||||
{std::allocator_traits<Allocator>::construct(al,data(),std::move(x));}
|
||||
template<
|
||||
@@ -115,7 +120,7 @@ public:
|
||||
>
|
||||
value_holder(Allocator& al,const value_holder& x)
|
||||
noexcept(is_nothrow_copy_constructible::value)
|
||||
{copy(al,x.value());}
|
||||
{allocator_copy(al,x.value());}
|
||||
template<
|
||||
typename Allocator,
|
||||
enable_if_not_emplacing_ctor_t<Allocator> =nullptr
|
||||
@@ -130,10 +135,10 @@ public:
|
||||
* following to make their life easier.
|
||||
*/
|
||||
|
||||
value_holder(const T& x)
|
||||
value_holder(const U& x)
|
||||
noexcept(is_nothrow_copy_constructible::value)
|
||||
{copy(x);}
|
||||
value_holder(T&& x)
|
||||
value_holder(U&& x)
|
||||
noexcept(is_nothrow_move_constructible::value)
|
||||
{::new ((void*)data()) T(std::move(x));}
|
||||
template<typename... Args>
|
||||
@@ -164,31 +169,37 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename Allocator>
|
||||
void copy(Allocator& al,const T& x){copy(al,x,is_copy_constructible{});}
|
||||
template<typename Allocator,typename Q>
|
||||
void allocator_copy(Allocator& al,const Q& x)
|
||||
{
|
||||
allocator_copy(al,x,is_copy_constructible{});
|
||||
}
|
||||
|
||||
template<typename Allocator>
|
||||
void copy(Allocator& al,const T& x,std::true_type)
|
||||
template<typename Allocator,typename Q>
|
||||
void allocator_copy(Allocator& al,const Q& x,std::true_type)
|
||||
{
|
||||
std::allocator_traits<Allocator>::construct(al,data(),x);
|
||||
}
|
||||
|
||||
template<typename Allocator>
|
||||
void copy(Allocator&,const T&,std::false_type)
|
||||
template<typename Allocator,typename Q>
|
||||
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);
|
||||
}
|
||||
|
||||
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{});}
|
||||
@@ -205,7 +216,7 @@ private:
|
||||
static_assert(is_nothrow_move_constructible::value,
|
||||
"type should be move assignable or nothrow move constructible");
|
||||
|
||||
if(data()!=boost::addressof(x)){
|
||||
if(data()!=std::addressof(x)){
|
||||
value().~T();
|
||||
::new (data()) T(std::move(x));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_POLY_COLLECTION_DETAIL_VARIANT_MODEL_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_VARIANT_MODEL_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/core/addressof.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
#include <boost/mp11/set.hpp>
|
||||
#include <boost/poly_collection/detail/is_acceptable.hpp>
|
||||
#include <boost/poly_collection/detail/fixed_variant.hpp>
|
||||
#include <boost/poly_collection/detail/fixed_variant_iterator.hpp>
|
||||
#include <boost/poly_collection/detail/packed_segment.hpp>
|
||||
#include <boost/poly_collection/detail/segment_backend.hpp>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
#if !defined(BOOST_NO_CXX17_HDR_VARIANT)
|
||||
#include <variant>
|
||||
#endif
|
||||
|
||||
namespace boost{namespace variant2{
|
||||
|
||||
template<class... T> class variant;
|
||||
|
||||
}} /* namespace boost::variant2 */
|
||||
|
||||
namespace boost_poly_collection_invoke_visit_variant2{
|
||||
|
||||
/* defined here to avoid ADL ambiguities with visit */
|
||||
|
||||
template<typename F,typename... Ts>
|
||||
auto invoke_visit(F&& f,const boost::variant2::variant<Ts...>&x)->
|
||||
decltype(visit(std::forward<F>(f),x))
|
||||
{
|
||||
return visit(std::forward<F>(f),x);
|
||||
}
|
||||
|
||||
} /* namespace boost_poly_collection_invoke_visit_variant2 */
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* model for variant_collection */
|
||||
|
||||
template<typename... Ts>
|
||||
struct variant_model;
|
||||
|
||||
template<typename V,typename...Ts>
|
||||
struct variant_model_is_subvariant:std::false_type{};
|
||||
|
||||
template<
|
||||
typename TL1,typename TL2,
|
||||
typename TS1=mp11::mp_set_union<mp11::mp_list<>,TL1>,
|
||||
typename TS2=mp11::mp_set_union<mp11::mp_list<>,TL2>
|
||||
>
|
||||
struct variant_model_is_subset:std::integral_constant<
|
||||
bool,
|
||||
mp11::mp_size<mp11::mp_set_union<TS1,TS2>>::value==
|
||||
mp11::mp_size<TS2>::value
|
||||
>{};
|
||||
|
||||
template<typename... Us,typename... Ts>
|
||||
struct variant_model_is_subvariant<
|
||||
fixed_variant_impl::fixed_variant<Us...>,
|
||||
Ts...
|
||||
>:variant_model_is_subset<mp11::mp_list<Us...>,mp11::mp_list<Ts...>>{};
|
||||
|
||||
template<typename... Us,typename... Ts>
|
||||
struct variant_model_is_subvariant<
|
||||
variant2::variant<Us...>,
|
||||
Ts...
|
||||
>:variant_model_is_subset<mp11::mp_list<Us...>,mp11::mp_list<Ts...>>{};
|
||||
|
||||
#if !defined(BOOST_NO_CXX17_HDR_VARIANT)
|
||||
template<typename... Us,typename... Ts>
|
||||
struct variant_model_is_subvariant<
|
||||
std::variant<Us...>,
|
||||
Ts...
|
||||
>:variant_model_is_subset<mp11::mp_list<Us...>,mp11::mp_list<Ts...>>{};
|
||||
#endif
|
||||
|
||||
template<typename F,typename... Ts>
|
||||
auto invoke_visit(F&& f,const fixed_variant_impl::fixed_variant<Ts...>&x)->
|
||||
decltype(boost::poly_collection::visit(std::forward<F>(f),x))
|
||||
{
|
||||
return boost::poly_collection::visit(std::forward<F>(f),x);
|
||||
}
|
||||
|
||||
using boost_poly_collection_invoke_visit_variant2::invoke_visit;
|
||||
|
||||
#if !defined(BOOST_NO_CXX17_HDR_VARIANT)
|
||||
template<typename F,typename... Ts>
|
||||
auto invoke_visit(F&& f,const std::variant<Ts...>&x)->
|
||||
decltype(std::visit(std::forward<F>(f),x))
|
||||
{
|
||||
return std::visit(std::forward<F>(f),x);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename... Ts>
|
||||
struct variant_model
|
||||
{
|
||||
using value_type=fixed_variant_impl::fixed_variant<Ts...>;
|
||||
using type_index=std::size_t;
|
||||
using acceptable_type_list=mp11::mp_list<Ts...>;
|
||||
template<typename T>
|
||||
struct is_terminal: /* using makes VS2015 choke, hence we derive */
|
||||
mp11::mp_contains<acceptable_type_list,T>{};
|
||||
template<typename T>
|
||||
struct is_implementation:std::integral_constant< /* idem */
|
||||
bool,
|
||||
is_terminal<T>::value||
|
||||
variant_model_is_subvariant<T,Ts...>::value
|
||||
>{};
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
using enable_if_terminal=
|
||||
typename std::enable_if<is_terminal<T>::value>::type*;
|
||||
template<typename T>
|
||||
using enable_if_not_terminal=
|
||||
typename std::enable_if<!is_terminal<T>::value>::type*;
|
||||
|
||||
public:
|
||||
template<typename T> static type_index index()
|
||||
{
|
||||
return mp11::mp_find<acceptable_type_list,T>::value;
|
||||
}
|
||||
|
||||
template<typename T,enable_if_terminal<T> =nullptr>
|
||||
static type_index subindex(const T&){return index<T>();}
|
||||
|
||||
private:
|
||||
template<typename... Qs>
|
||||
struct subindex_lambda
|
||||
{
|
||||
template<typename I>
|
||||
std::size_t operator()(I)const
|
||||
{
|
||||
return mp11::mp_find<
|
||||
acceptable_type_list,mp11::mp_at<mp11::mp_list<Qs...>,I>>::value;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
template<
|
||||
template<typename...> class V,typename... Qs,
|
||||
enable_if_not_terminal<V<Qs...>> =nullptr>
|
||||
static type_index subindex(const V<Qs...>& x)
|
||||
{
|
||||
static constexpr auto not_found=mp11::mp_size<acceptable_type_list>::value;
|
||||
auto i=x.index();
|
||||
if(i>=sizeof...(Qs))return not_found;
|
||||
else return mp11::mp_with_index<sizeof...(Qs)>(
|
||||
i,subindex_lambda<Qs...>{});
|
||||
}
|
||||
|
||||
template<typename T,enable_if_terminal<T> =nullptr>
|
||||
static void* subaddress(T& x){return boost::addressof(x);}
|
||||
|
||||
template<typename T,enable_if_terminal<T> =nullptr>
|
||||
static const void* subaddress(const T& x){return boost::addressof(x);}
|
||||
|
||||
template<typename T,enable_if_not_terminal<T> =nullptr>
|
||||
static void* subaddress(T& x)
|
||||
{
|
||||
return const_cast<void*>(subaddress(const_cast<const T&>(x)));
|
||||
}
|
||||
|
||||
private:
|
||||
struct subaddress_visitor
|
||||
{
|
||||
template<typename T>
|
||||
const void* operator()(const T& x)const
|
||||
{
|
||||
return static_cast<const void*>(boost::addressof(x));
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
template<typename T,enable_if_not_terminal<T> =nullptr>
|
||||
static const void* subaddress(const T& x)
|
||||
{
|
||||
return invoke_visit(subaddress_visitor{},x);
|
||||
}
|
||||
|
||||
template<typename T,enable_if_terminal<T> =nullptr>
|
||||
static const std::type_info& subtype_info(const T& x)
|
||||
{
|
||||
return typeid(x);
|
||||
}
|
||||
|
||||
private:
|
||||
struct subtype_info_visitor
|
||||
{
|
||||
template<typename T>
|
||||
const std::type_info& operator()(const T&)const{return typeid(T);}
|
||||
};
|
||||
|
||||
public:
|
||||
template<typename T,enable_if_not_terminal<T> =nullptr>
|
||||
static const std::type_info& subtype_info(const T& x)
|
||||
{
|
||||
return invoke_visit(subtype_info_visitor{},x);
|
||||
}
|
||||
|
||||
using base_iterator=fixed_variant_iterator<value_type>;
|
||||
using const_base_iterator=fixed_variant_iterator<const value_type>;
|
||||
using base_sentinel=value_type*;
|
||||
using const_base_sentinel=const value_type*;
|
||||
template<typename T>
|
||||
using iterator=fixed_variant_alternative_iterator<value_type,T>;
|
||||
template<typename T>
|
||||
using const_iterator=fixed_variant_alternative_iterator<value_type,const T>;
|
||||
template<typename Allocator>
|
||||
using segment_backend=detail::segment_backend<variant_model,Allocator>;
|
||||
template<typename T,typename Allocator>
|
||||
using segment_backend_implementation=
|
||||
packed_segment<variant_model,T,Allocator>;
|
||||
|
||||
static base_iterator nonconst_iterator(const_base_iterator it)
|
||||
{
|
||||
return base_iterator{
|
||||
const_cast<value_type*>(static_cast<const value_type*>(it)),it.stride()};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static iterator<T> nonconst_iterator(const_iterator<T> it)
|
||||
{
|
||||
return {const_cast<T*>(static_cast<const T*>(it))};
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename,typename,typename>
|
||||
friend class packed_segment;
|
||||
|
||||
template<typename T>
|
||||
using final_type=fixed_variant_impl::fixed_variant_closure<
|
||||
T,fixed_variant_impl::fixed_variant<Ts...>>;
|
||||
|
||||
template<typename T>
|
||||
static const value_type* value_ptr(const T* p)noexcept
|
||||
{
|
||||
return reinterpret_cast<const final_type<T>*>(p);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,83 @@
|
||||
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_POLY_COLLECTION_VARIANT_COLLECTION_HPP
|
||||
#define BOOST_POLY_COLLECTION_VARIANT_COLLECTION_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/poly_collection/variant_collection_fwd.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
#include <boost/poly_collection/detail/variant_model.hpp>
|
||||
#include <boost/poly_collection/detail/poly_collection.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
template<typename TypeList,typename Allocator>
|
||||
class variant_collection:
|
||||
public common_impl::poly_collection<
|
||||
mp11::mp_rename<TypeList,detail::variant_model>,Allocator>
|
||||
{
|
||||
using base_type=common_impl::poly_collection<
|
||||
mp11::mp_rename<TypeList,detail::variant_model>,Allocator>;
|
||||
|
||||
base_type& base()noexcept{return *this;}
|
||||
const base_type& base()const noexcept{return *this;}
|
||||
|
||||
public:
|
||||
using base_type::base_type;
|
||||
|
||||
variant_collection()=default;
|
||||
variant_collection(const variant_collection& x)=default;
|
||||
variant_collection(variant_collection&& x)=default;
|
||||
variant_collection& operator=(const variant_collection& x)=default;
|
||||
variant_collection& operator=(variant_collection&& x)=default;
|
||||
|
||||
template<typename TL,typename A>
|
||||
friend bool operator==(
|
||||
const variant_collection<TL,A>&,const variant_collection<TL,A>&);
|
||||
};
|
||||
|
||||
template<typename TypeList,typename Allocator>
|
||||
bool operator==(
|
||||
const variant_collection<TypeList,Allocator>& x,
|
||||
const variant_collection<TypeList,Allocator>& y)
|
||||
{
|
||||
return x.base()==y.base();
|
||||
}
|
||||
|
||||
template<typename TypeList,typename Allocator>
|
||||
bool operator!=(
|
||||
const variant_collection<TypeList,Allocator>& x,
|
||||
const variant_collection<TypeList,Allocator>& y)
|
||||
{
|
||||
return !(x==y);
|
||||
}
|
||||
|
||||
// TODO: other rel operators?
|
||||
|
||||
template<typename TypeList,typename Allocator>
|
||||
void swap(
|
||||
variant_collection<TypeList,Allocator>& x,
|
||||
variant_collection<TypeList,Allocator>& y)
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
using poly_collection::variant_collection;
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,62 @@
|
||||
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_POLY_COLLECTION_VARIANT_COLLECTION_FWD_HPP
|
||||
#define BOOST_POLY_COLLECTION_VARIANT_COLLECTION_FWD_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/mp11/list.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
template<typename... Ts> struct variant_model;
|
||||
}
|
||||
|
||||
template<typename TypeList>
|
||||
using variant_collection_value_type=
|
||||
typename mp11::mp_rename<TypeList,detail::variant_model>::value_type;
|
||||
|
||||
template<
|
||||
typename TypeList,
|
||||
typename Allocator=std::allocator<variant_collection_value_type<TypeList>>
|
||||
>
|
||||
class variant_collection;
|
||||
|
||||
template<typename... Ts>
|
||||
using variant_collection_of=variant_collection<mp11::mp_list<Ts...>>;
|
||||
|
||||
template<typename TypeList,typename Allocator>
|
||||
bool operator==(
|
||||
const variant_collection<TypeList,Allocator>& x,
|
||||
const variant_collection<TypeList,Allocator>& y);
|
||||
|
||||
template<typename TypeList,typename Allocator>
|
||||
bool operator!=(
|
||||
const variant_collection<TypeList,Allocator>& x,
|
||||
const variant_collection<TypeList,Allocator>& y);
|
||||
|
||||
template<typename TypeList,typename Allocator>
|
||||
void swap(
|
||||
variant_collection<TypeList,Allocator>& x,
|
||||
variant_collection<TypeList,Allocator>& y);
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
using poly_collection::variant_collection;
|
||||
using poly_collection::variant_collection_of;
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -16,46 +16,24 @@ project
|
||||
<library>/boost/poly_collection//boost_poly_collection
|
||||
[ requires cxx11_noexcept ] # used as a proxy for C++11 support
|
||||
<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" :
|
||||
[ run test_algorithm.cpp test_algorithm1.cpp
|
||||
test_algorithm2.cpp test_algorithm3.cpp
|
||||
test_algorithm_main.cpp
|
||||
:
|
||||
:
|
||||
: <toolset>msvc:<cxxflags>/bigobj
|
||||
<toolset>gcc:<inlining>on
|
||||
<toolset>gcc:<optimization>space
|
||||
<toolset>clang:<inlining>on
|
||||
<toolset>clang:<optimization>space ]
|
||||
[ run test_capacity.cpp test_capacity_main.cpp ]
|
||||
[ run test_comparison.cpp test_comparison_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 ]
|
||||
[ run test_algorithm.cpp test_algorithm1.cpp
|
||||
test_algorithm2.cpp test_algorithm3.cpp
|
||||
test_algorithm4.cpp test_algorithm_main.cpp ]
|
||||
[ run test_capacity.cpp test_capacity_main.cpp ]
|
||||
[ run test_comparison.cpp test_comparison_main.cpp ]
|
||||
[ run test_construction.cpp test_construction_main.cpp ]
|
||||
[ run test_emplacement.cpp test_emplacement_main.cpp ]
|
||||
[ run test_erasure.cpp test_erasure_main.cpp ]
|
||||
[ run test_fixed_variant.cpp test_fixed_variant_main.cpp ]
|
||||
[ run test_insertion.cpp test_insertion_main.cpp ]
|
||||
[ run test_iterators.cpp test_iterators_main.cpp ]
|
||||
[ run test_registration.cpp test_registration_main.cpp ]
|
||||
;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2016 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "test_algorithm1.hpp"
|
||||
#include "test_algorithm2.hpp"
|
||||
#include "test_algorithm3.hpp"
|
||||
#include "test_algorithm4.hpp"
|
||||
|
||||
/* test split in chunks to avoid problems with compilation object sizes */
|
||||
|
||||
@@ -18,4 +19,5 @@ void test_algorithm()
|
||||
test_algorithm1();
|
||||
test_algorithm2();
|
||||
test_algorithm3();
|
||||
test_algorithm4();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||
*/
|
||||
|
||||
#include "test_algorithm4.hpp"
|
||||
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/iterator/function_output_iterator.hpp>
|
||||
#include <iterator>
|
||||
#include <random>
|
||||
#include <type_traits>
|
||||
#include "variant_types.hpp"
|
||||
#include "test_algorithm_impl.hpp"
|
||||
|
||||
template<typename T>
|
||||
struct pierced_pred
|
||||
{
|
||||
template<
|
||||
typename Q,
|
||||
typename std::enable_if<!std::is_same<T,Q>::value>::type* =nullptr
|
||||
>
|
||||
bool operator()(const Q&)const{return true;}
|
||||
|
||||
template<
|
||||
typename Q,typename R,
|
||||
typename std::enable_if<
|
||||
!std::is_same<T,Q>::value&&!std::is_same<T,R>::value>::type* =nullptr
|
||||
>
|
||||
bool operator()(const Q&,const R&)const{return true;}
|
||||
};
|
||||
|
||||
template<typename PolyCollection,typename T>
|
||||
void test_total_restitution_algorithm()
|
||||
{
|
||||
using namespace boost::poly_collection;
|
||||
using value_type=typename PolyCollection::value_type;
|
||||
|
||||
PolyCollection p;
|
||||
pierced_pred<value_type> pred;
|
||||
int seq[1];
|
||||
auto out=boost::make_function_output_iterator(pred);
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC,>=1910)&&BOOST_WORKAROUND(BOOST_MSVC,<1920)
|
||||
/* Internal fix for https://lists.boost.org/Archives/boost/2017/06/235687.php
|
||||
* causes instantiation of std alg for value_type.
|
||||
*/
|
||||
#else
|
||||
(void)all_of<all_types>(p.begin(),p.end(),pred);
|
||||
(void)any_of<all_types>(p.begin(),p.end(),pred);
|
||||
(void)none_of<all_types>(p.begin(),p.end(),pred);
|
||||
(void)count_if<all_types>(p.begin(),p.end(),pred);
|
||||
(void)is_permutation<all_types>(
|
||||
p.begin(),p.end(),std::begin(seq),pred);
|
||||
(void)copy<all_types>(p.begin(),p.end(),out);
|
||||
(void)copy_if<all_types>(p.begin(),p.end(),out,pred);
|
||||
(void)rotate_copy<all_types>(p.begin(),p.begin(),p.end(),out);
|
||||
(void)move<all_types>(p.begin(),p.end(),out);
|
||||
(void)transform<all_types>(p.begin(),p.end(),out,pred);
|
||||
(void)remove_copy<all_types>(p.begin(),p.end(),out,T{0});
|
||||
(void)remove_copy_if<all_types>(p.begin(),p.end(),out,pred);
|
||||
(void)is_partitioned<all_types>(p.begin(),p.begin(),pred);
|
||||
(void)partition_copy<all_types>(p.begin(),p.begin(),out,out,pred);
|
||||
#endif
|
||||
|
||||
(void)for_each<all_types>(p.begin(),p.end(),pred);
|
||||
(void)for_each_n<all_types>(p.begin(),0,pred);
|
||||
/* find: no easy way to check value_type is not compared against */
|
||||
(void)find_if<all_types>(p.begin(),p.end(),pred);
|
||||
(void)find_if_not<all_types>(p.begin(),p.end(),pred);
|
||||
(void)find_end<all_types>
|
||||
(p.begin(),p.end(),std::begin(seq),std::end(seq),pred);
|
||||
(void)find_first_of<all_types>
|
||||
(p.begin(),p.end(),std::begin(seq),std::end(seq),pred);
|
||||
(void)adjacent_find<all_types>(p.begin(),p.end(),pred);
|
||||
/* count, no easy way to check value_type is not compared against */
|
||||
(void)mismatch<all_types>(p.begin(),p.end(),std::begin(seq),pred);
|
||||
(void)equal<all_types>(p.begin(),p.end(),std::begin(seq),pred);
|
||||
(void)search<all_types>(
|
||||
p.begin(),p.end(),std::begin(seq),std::end(seq),pred);
|
||||
(void)search_n<all_types>(p.begin(),p.end(),1,T{0},pred);
|
||||
(void)copy_n<all_types>(p.begin(),0,out);
|
||||
(void)replace_copy<all_types>(p.begin(),p.end(),out,T{0},T{0});
|
||||
(void)replace_copy_if<all_types>(p.begin(),p.end(),out,pred,T{0});
|
||||
(void)unique_copy<all_types>(p.begin(),p.end(),out,pred);
|
||||
(void)sample<all_types>(p.begin(),p.begin(),out,0,std::mt19937{});
|
||||
(void)partition_point<all_types>(p.begin(),p.begin(),pred);
|
||||
};
|
||||
|
||||
void test_algorithm4()
|
||||
{
|
||||
test_algorithm<
|
||||
variant_types::collection,jammed_auto_increment,variant_types::to_int,
|
||||
variant_types::t1,variant_types::t2,variant_types::t3,
|
||||
variant_types::t4,variant_types::t5>();
|
||||
test_total_restitution_algorithm<
|
||||
variant_types::collection,variant_types::t1>();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/* Copyright 2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See http://www.boost.org/libs/poly_collection for library home page.
|
||||
*/
|
||||
|
||||
void test_algorithm4();
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2016-2020 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
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 */
|
||||
|
||||
#define DEFINE_ALGORITHM(name,f) \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2016 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "test_construction.hpp"
|
||||
#include "test_emplacement.hpp"
|
||||
#include "test_erasure.hpp"
|
||||
#include "test_fixed_variant.hpp"
|
||||
#include "test_insertion.hpp"
|
||||
#include "test_iterators.hpp"
|
||||
#include "test_registration.hpp"
|
||||
@@ -25,6 +26,7 @@ int main()
|
||||
test_construction();
|
||||
test_emplacement();
|
||||
test_erasure();
|
||||
test_fixed_variant();
|
||||
test_insertion();
|
||||
test_iterators();
|
||||
test_registration();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2016-2017 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "any_types.hpp"
|
||||
#include "base_types.hpp"
|
||||
#include "function_types.hpp"
|
||||
#include "variant_types.hpp"
|
||||
#include "test_utilities.hpp"
|
||||
|
||||
using namespace test_utilities;
|
||||
@@ -27,29 +28,30 @@ void test_capacity()
|
||||
BOOST_TEST(cp.empty());
|
||||
BOOST_TEST(cp.size()==0);
|
||||
|
||||
p.template register_types<Types...>();
|
||||
register_types<Types...>(p);
|
||||
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)...);
|
||||
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)...);
|
||||
|
||||
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(
|
||||
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_((BOOST_TEST(cp.capacity(typeid(Types))>=20),0)...);
|
||||
do_((p.reserve(typeid_<Types>(p),20),0)...);
|
||||
do_((BOOST_TEST(cp.capacity(typeid_<Types>(cp))>=20),0)...);
|
||||
|
||||
do_((p.template reserve<Types>(30),0)...);
|
||||
do_((BOOST_TEST(cp.template capacity<Types>()>=30),0)...);
|
||||
|
||||
fill<constraints<>,Types...>(p,v,30);
|
||||
BOOST_TEST(cp.size()==30*sizeof...(Types));
|
||||
do_((BOOST_TEST(cp.size(typeid(Types))==30),0)...);
|
||||
do_((BOOST_TEST(cp.template size<Types>()==cp.size(typeid(Types))),0)...);
|
||||
do_((BOOST_TEST(cp.size(typeid_<Types>(cp))==30),0)...);
|
||||
do_((BOOST_TEST(
|
||||
cp.template size<Types>()==cp.size(typeid_<Types>(cp))),0)...);
|
||||
|
||||
auto min_capacity=[&]{
|
||||
return (std::min)({cp.template capacity<Types>()...});
|
||||
@@ -66,7 +68,7 @@ void test_capacity()
|
||||
do_((p.erase(cp.template begin<Types>()),0)...);
|
||||
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());
|
||||
c=min_capacity();
|
||||
|
||||
@@ -89,4 +91,8 @@ void test_capacity()
|
||||
function_types::collection,auto_increment,
|
||||
function_types::t1,function_types::t2,function_types::t3,
|
||||
function_types::t4,function_types::t5>();
|
||||
test_capacity<
|
||||
variant_types::collection,auto_increment,
|
||||
variant_types::t1,variant_types::t2,variant_types::t3,
|
||||
variant_types::t4,variant_types::t5>();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2016-2018 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2016-2024 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "any_types.hpp"
|
||||
#include "base_types.hpp"
|
||||
#include "function_types.hpp"
|
||||
#include "variant_types.hpp"
|
||||
#include "test_utilities.hpp"
|
||||
|
||||
using namespace test_utilities;
|
||||
@@ -49,7 +50,7 @@ void test_comparison()
|
||||
const PolyCollection& cp2=p2;
|
||||
ValueFactory v;
|
||||
|
||||
p1.template register_types<Types...>();
|
||||
register_types<Types...>(p1);
|
||||
fill<
|
||||
constraints<is_not_equality_comparable>,
|
||||
Types...
|
||||
@@ -123,7 +124,7 @@ void test_comparison()
|
||||
const PolyCollection& cp2=p2;
|
||||
ValueFactory v;
|
||||
|
||||
p1.template register_types<Types...>();
|
||||
register_types<Types...>(p1);
|
||||
fill<
|
||||
constraints<is_equality_comparable,is_copy_constructible>,
|
||||
Types...
|
||||
@@ -157,7 +158,7 @@ void test_stateless_lambda_comparability_check()
|
||||
|
||||
void test_comparison()
|
||||
{
|
||||
test_comparison<
|
||||
/* test_comparison<
|
||||
any_types::collection,auto_increment,
|
||||
any_types::t1,any_types::t2,any_types::t3,
|
||||
any_types::t4,any_types::t5>();
|
||||
@@ -168,6 +169,10 @@ void test_comparison()
|
||||
test_comparison<
|
||||
function_types::collection,auto_increment,
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "any_types.hpp"
|
||||
#include "base_types.hpp"
|
||||
#include "function_types.hpp"
|
||||
#include "variant_types.hpp"
|
||||
#include "test_utilities.hpp"
|
||||
|
||||
using namespace test_utilities;
|
||||
@@ -58,7 +59,7 @@ void test_allocator_aware_construction()
|
||||
BOOST_TEST(p3==p);
|
||||
BOOST_TEST(d2==d3);
|
||||
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));
|
||||
}
|
||||
{
|
||||
@@ -91,7 +92,7 @@ void test_allocator_aware_construction()
|
||||
if(AlwaysEqual)BOOST_TEST(d2==d3);
|
||||
|
||||
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)&&\
|
||||
BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB,BOOST_TESTED_AT(804))
|
||||
@@ -146,7 +147,7 @@ void test_allocator_aware_construction()
|
||||
if(Propagate||AlwaysEqual){
|
||||
BOOST_TEST(d2==d3);
|
||||
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)
|
||||
@@ -187,7 +188,7 @@ void test_allocator_aware_construction()
|
||||
e3=get_layout_data<Types...>(p3);
|
||||
BOOST_TEST(d2==e3);
|
||||
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 BOOST_WORKAROUND(BOOST_MSVC,<=1900)
|
||||
/* std::unordered_map::swap does not swap equal allocators */
|
||||
@@ -218,7 +219,7 @@ void test_allocator_aware_construction()
|
||||
f3=get_layout_data<Types...>(p3);
|
||||
BOOST_TEST(e2==f3);
|
||||
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){
|
||||
BOOST_TEST(p2.get_allocator().comes_from(root1));
|
||||
BOOST_TEST(p3.get_allocator().comes_from(root2));
|
||||
@@ -306,12 +307,12 @@ void test_construction()
|
||||
PolyCollection p2{std::move(p)};
|
||||
BOOST_TEST(!p2.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)};
|
||||
BOOST_TEST(!p.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::t1,function_types::t2,function_types::t3,
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "any_types.hpp"
|
||||
#include "base_types.hpp"
|
||||
#include "function_types.hpp"
|
||||
#include "variant_types.hpp"
|
||||
#include "test_utilities.hpp"
|
||||
|
||||
using namespace test_utilities;
|
||||
@@ -37,25 +38,25 @@ void test_emplacement()
|
||||
|
||||
iterator it=p.template emplace<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);
|
||||
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);
|
||||
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=
|
||||
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(lbit==p.begin(typeid(type)));
|
||||
BOOST_TEST(lbit==p.begin(typeid_<type>(p)));
|
||||
|
||||
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(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);
|
||||
BOOST_TEST(*lit==type{1});
|
||||
@@ -76,8 +77,8 @@ void test_emplacement()
|
||||
p.template emplace<type>();
|
||||
p.template emplace_hint<type>(p.begin());
|
||||
p.template emplace_hint<type>(p.cend());
|
||||
p.template emplace_pos<type>(p.begin(typeid(type)));
|
||||
p.template emplace_pos<type>(p.cend(typeid(type)));
|
||||
p.template emplace_pos<type>(p.begin(typeid_<type>(p)));
|
||||
p.template emplace_pos<type>(p.cend(typeid_<type>(p)));
|
||||
p.emplace_pos(p.template begin<type>());
|
||||
p.emplace_pos(p.template cend<type>());
|
||||
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.cend(),v.template make<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.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 cend<type>(),v.template make<type>());
|
||||
BOOST_TEST(p.size()==7);
|
||||
@@ -118,4 +119,8 @@ void test_emplacement()
|
||||
function_types::collection,auto_increment,
|
||||
function_types::t1,function_types::t2,function_types::t3,
|
||||
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>();
|
||||
}
|
||||
|
||||