initial commit
@@ -0,0 +1,47 @@
|
||||
# Copyright 2016 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)
|
||||
#
|
||||
# See http://www.boost.org/libs/poly_collection for library home page.
|
||||
|
||||
import os ;
|
||||
using quickbook ;
|
||||
using boostbook ;
|
||||
|
||||
# code for copying images to HTML folder ripped from
|
||||
# http://boost.org/libs/accumulators/doc/Jamfile.v2
|
||||
|
||||
if [ os.name ] = NT
|
||||
{
|
||||
CP = copy /y ;
|
||||
MKDIR = mkdir ;
|
||||
FROM = .\\img\\*.* ;
|
||||
TOHTML = .\\html\\img\\ ;
|
||||
}
|
||||
else
|
||||
{
|
||||
CP = cp ;
|
||||
MKDIR = mkdir -p ;
|
||||
FROM = ./img/*.* ;
|
||||
TOHTML = ./html/img/ ;
|
||||
}
|
||||
|
||||
actions copy_img
|
||||
{
|
||||
$(MKDIR) $(TOHTML)
|
||||
$(CP) $(FROM) $(TOHTML)
|
||||
}
|
||||
|
||||
make img_copied : poly_collection.qbk : @copy_img ;
|
||||
|
||||
xml poly_collection : poly_collection.qbk : <dependency>img_copied ;
|
||||
|
||||
boostbook standalone
|
||||
: poly_collection
|
||||
:
|
||||
<xsl:param>boost.defaults=Boost
|
||||
<xsl:param>boost.image.src=img/proposed_for_boost.png
|
||||
<xsl:param>boost.root=http://www.boost.org/doc/libs/release
|
||||
#<xsl:param>boost.root=../../../..
|
||||
;
|
||||
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
@@ -0,0 +1,149 @@
|
||||
[/
|
||||
Copyright 2016 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_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 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_segment_info_;
|
||||
class _segment_info_;
|
||||
using _segment_info_iterator_=``/implementation-defined/``;
|
||||
using _const_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.type_registration ['// type registration:]]``
|
||||
|
||||
template<typename... T>
|
||||
void _register_types_();
|
||||
|
||||
bool _is_registered_(const std::type_index& index)const;
|
||||
template<typename T> bool _is_registered_()const;
|
||||
|
||||
``[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 std::type_index& index);
|
||||
local_base_iterator _end_(const std::type_index& index);
|
||||
const_local_base_iterator _begin_(const std::type_index& index)const;
|
||||
const_local_base_iterator _end_(const std::type_index& index)const;
|
||||
const_local_base_iterator _cbegin_(const std::type_index& index)const;
|
||||
const_local_base_iterator _cend_(const std::type_index& index)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;
|
||||
|
||||
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 std::type_index& index)const;
|
||||
template<typename T> bool _empty_()const;
|
||||
|
||||
size_type size()const noexcept;
|
||||
size_type _size_(const std::type_index& index)const;
|
||||
template<typename T> size_type _size_()const;
|
||||
|
||||
size_type _max_size_()const noexcept;
|
||||
size_type _max_size_(const std::type_index& index)const;
|
||||
template<typename T> size_type _max_size_()const;
|
||||
|
||||
size_type _capacity_()const noexcept;
|
||||
size_type _capacity_(const std::type_index& index)const;
|
||||
template<typename T> size_type _capacity_()const;
|
||||
|
||||
void _reserve_(size_type n);
|
||||
void _reserve_(const std::type_index& index,size_type n);
|
||||
template<typename T>void _reserve_(size_type n);
|
||||
|
||||
void _shrink_to_fit_();
|
||||
void _shrink_to_fit_(const std::type_index& index);
|
||||
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 std::type_index& index);
|
||||
template<typename T> void _clear_();
|
||||
|
||||
void swap(``[class_name]``& x);
|
||||
};
|
||||
]
|
||||
@@ -0,0 +1,47 @@
|
||||
# Copyright 2016 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)
|
||||
#
|
||||
# See http://www.boost.org/libs/poly_collection for library home page.
|
||||
|
||||
exe algorithms
|
||||
: algorithms.cpp
|
||||
: <include>$(BOOST_ROOT)
|
||||
;
|
||||
|
||||
exe basic_any
|
||||
: basic_any.cpp
|
||||
: <include>$(BOOST_ROOT)
|
||||
;
|
||||
|
||||
exe basic_base
|
||||
: basic_base.cpp
|
||||
: <include>$(BOOST_ROOT)
|
||||
;
|
||||
|
||||
exe basic_function
|
||||
: basic_function.cpp
|
||||
: <include>$(BOOST_ROOT)
|
||||
;
|
||||
|
||||
exe exceptions
|
||||
: exceptions.cpp
|
||||
: <include>$(BOOST_ROOT)
|
||||
;
|
||||
|
||||
exe insertion_emplacement
|
||||
: insertion_emplacement.cpp
|
||||
: <include>$(BOOST_ROOT)
|
||||
;
|
||||
|
||||
exe perf
|
||||
: perf.cpp
|
||||
: <include>$(BOOST_ROOT)
|
||||
: release
|
||||
;
|
||||
|
||||
exe segmented_structure
|
||||
: segmented_structure.cpp
|
||||
: <include>$(BOOST_ROOT)
|
||||
;
|
||||
@@ -0,0 +1,170 @@
|
||||
/* Copyright 2016 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.
|
||||
*/
|
||||
|
||||
/* Boost.PolyCollection algorithms */
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/poly_collection/algorithm.hpp>
|
||||
#include <boost/poly_collection/any_collection.hpp>
|
||||
#include <boost/poly_collection/base_collection.hpp>
|
||||
#include <boost/type_erasure/any.hpp>
|
||||
#include <boost/type_erasure/any_cast.hpp>
|
||||
#include <boost/type_erasure/builtin.hpp>
|
||||
#include <boost/type_erasure/operators.hpp>
|
||||
#include <boost/type_erasure/typeid_of.hpp>
|
||||
#include <random>
|
||||
#include "rolegame.hpp"
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,const sprite& s)
|
||||
{
|
||||
s.render(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,const window& w)
|
||||
{
|
||||
w.display(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::base_collection<sprite> c;
|
||||
|
||||
// populate c
|
||||
|
||||
std::mt19937 gen{92748}; // some arbitrary random seed
|
||||
std::uniform_real_distribution<> rnd;
|
||||
for(int i=0;i<8;++i){ // assign each type with 1/3 probability
|
||||
auto r=rnd(gen);
|
||||
if(r<1.0/3)c.insert(warrior{i});
|
||||
else if(r<2.0/3)c.insert(juggernaut{i});
|
||||
else c.insert(goblin{i});
|
||||
}
|
||||
|
||||
auto render1=[](const boost::base_collection<sprite>& c){
|
||||
//[algorithms_1
|
||||
const char* comma="";
|
||||
std::for_each(c.begin(),c.end(),[&](const sprite& s){
|
||||
std::cout<<comma;
|
||||
s.render(std::cout);
|
||||
comma=",";
|
||||
});
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
};
|
||||
render1(c);
|
||||
|
||||
auto render2=[](const boost::base_collection<sprite>& c){
|
||||
//[algorithms_2
|
||||
const char* comma="";
|
||||
for(auto seg_info:c.segment_traversal()){
|
||||
for(const sprite& s:seg_info){
|
||||
std::cout<<comma;
|
||||
s.render(std::cout);
|
||||
comma=",";
|
||||
}
|
||||
};
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
};
|
||||
render2(c);
|
||||
|
||||
auto render3=[](const boost::base_collection<sprite>& c){
|
||||
//[algorithms_3
|
||||
//= #include <boost/poly_collection/algorithm.hpp>
|
||||
//= ...
|
||||
//=
|
||||
const char* comma="";
|
||||
boost::poly_collection::for_each(c.begin(),c.end(),[&](const sprite& s){
|
||||
std::cout<<comma;
|
||||
s.render(std::cout);
|
||||
comma=",";
|
||||
});
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
};
|
||||
render3(c);
|
||||
|
||||
//[algorithms_4
|
||||
auto n=boost::poly_collection::count_if(
|
||||
c.begin(),c.end(),[](const sprite& s){return s.id%2==0;});
|
||||
std::cout<<n<<" sprites with even id\n";
|
||||
//]
|
||||
|
||||
using renderable=boost::type_erasure::ostreamable<>;
|
||||
using standalone_renderable=boost::mpl::vector<
|
||||
renderable,
|
||||
boost::type_erasure::copy_constructible<>,
|
||||
boost::type_erasure::typeid_<>
|
||||
>;
|
||||
|
||||
{
|
||||
//[algorithms_5
|
||||
sprite* ps=new warrior{5};
|
||||
// sprite -> warrior
|
||||
warrior* pw=static_cast<warrior*>(ps);
|
||||
//<-
|
||||
(void)pw;
|
||||
delete ps;
|
||||
//->
|
||||
|
||||
//<-
|
||||
boost::type_erasure::any<standalone_renderable> r=std::string{"hello"};
|
||||
//->
|
||||
//= boost::type_erasure::any<renderable> r=std::string{"hello"};
|
||||
// renderable -> std::string
|
||||
std::string& str=boost::type_erasure::any_cast<std::string&>(r);
|
||||
//]
|
||||
|
||||
//[algorithms_6
|
||||
// render r with std::string restitution
|
||||
if(boost::type_erasure::typeid_of(r)==typeid(std::string)){
|
||||
std::string& str=boost::type_erasure::any_cast<std::string&>(r);
|
||||
std::cout<<str<<"\n";
|
||||
}
|
||||
else{
|
||||
std::cout<<r<<"\n";
|
||||
}
|
||||
//]
|
||||
}
|
||||
|
||||
auto& bc=c;
|
||||
{
|
||||
boost::any_collection<renderable> c;
|
||||
c.insert(bc.begin<warrior>(),bc.end<warrior>());
|
||||
c.insert(bc.begin<juggernaut>(),bc.end<juggernaut>());
|
||||
c.insert(bc.begin<goblin>(),bc.end<goblin>());
|
||||
c.insert(std::string{"\"stamina: 10,000\""});
|
||||
c.insert(std::string{"\"game over\""});
|
||||
c.insert(window{"pop-up 1"});
|
||||
c.insert(window{"pop-up 2"});
|
||||
|
||||
//[algorithms_7
|
||||
const char* comma="";
|
||||
boost::poly_collection::for_each
|
||||
<warrior,juggernaut,goblin,std::string,window>( //restituted types
|
||||
c.begin(),c.end(),[&](const auto& x){
|
||||
std::cout<<comma<<x;
|
||||
comma=",";
|
||||
});
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
}
|
||||
|
||||
//[algorithms_8
|
||||
const char* comma="";
|
||||
boost::poly_collection::for_each<warrior,juggernaut,goblin>(
|
||||
c.begin(),c.end(),[&](const auto& s){
|
||||
std::cout<<comma;
|
||||
s.render(std::cout);
|
||||
comma=",";
|
||||
});
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/* Copyright 2016 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::any_collection */
|
||||
|
||||
#include <boost/poly_collection/any_collection.hpp>
|
||||
#include <boost/type_erasure/operators.hpp>
|
||||
#include <random>
|
||||
#include "rolegame.hpp"
|
||||
|
||||
//[basic_any_1
|
||||
std::ostream& operator<<(std::ostream& os,const sprite& s)
|
||||
{
|
||||
s.render(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
// std::string already has a suitable operator<<
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,const window& w)
|
||||
{
|
||||
w.display(os);
|
||||
return os;
|
||||
}
|
||||
//]
|
||||
|
||||
int main()
|
||||
{
|
||||
//[basic_any_2
|
||||
//= #include <boost/poly_collection/any_collection.hpp>
|
||||
//= #include <boost/type_erasure/operators.hpp>
|
||||
//= ...
|
||||
//=
|
||||
using renderable=boost::type_erasure::ostreamable<>;
|
||||
boost::any_collection<renderable> c;
|
||||
//]
|
||||
|
||||
//[basic_any_3
|
||||
// populate with sprites
|
||||
std::mt19937 gen{92748}; // some arbitrary random seed
|
||||
std::uniform_real_distribution<> rnd;
|
||||
for(int i=0;i<4;++i){ // assign each type with 1/3 probability
|
||||
auto r=rnd(gen);
|
||||
if(r<1.0/3)c.insert(warrior{i});
|
||||
else if(r<2.0/3)c.insert(juggernaut{i});
|
||||
else c.insert(goblin{i});
|
||||
}
|
||||
|
||||
// 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_any_4
|
||||
const char* comma="";
|
||||
for(const auto& r:c){
|
||||
std::cout<<comma<<r;
|
||||
comma=",";
|
||||
}
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/* Copyright 2016 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::base_collection */
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/poly_collection/base_collection.hpp>
|
||||
#include <random>
|
||||
#include "rolegame.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
//[basic_base_1
|
||||
//= #include <boost/poly_collection/base_collection.hpp>
|
||||
//= ...
|
||||
//=
|
||||
boost::base_collection<sprite> c;
|
||||
|
||||
std::mt19937 gen{92748}; // some arbitrary random seed
|
||||
std::uniform_real_distribution<> rnd;
|
||||
for(int i=0;i<8;++i){ // assign each type with 1/3 probability
|
||||
auto r=rnd(gen);
|
||||
if(r<1.0/3)c.insert(warrior{i});
|
||||
else if(r<2.0/3)c.insert(juggernaut{i});
|
||||
else c.insert(goblin{i});
|
||||
}
|
||||
//]
|
||||
|
||||
auto render=[&](){
|
||||
//[basic_base_2
|
||||
const char* comma="";
|
||||
for(const sprite& s:c){
|
||||
std::cout<<comma;
|
||||
s.render(std::cout);
|
||||
comma=",";
|
||||
}
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
};
|
||||
render();
|
||||
|
||||
//[basic_base_3
|
||||
c.insert(goblin{8});
|
||||
//]
|
||||
render();
|
||||
|
||||
//[basic_base_4
|
||||
// find element with id==7 and remove it
|
||||
auto it=std::find_if(c.begin(),c.end(),[](const sprite& s){return s.id==7;});
|
||||
c.erase(it);
|
||||
//]
|
||||
render();
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/* Copyright 2016 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::function_collection */
|
||||
|
||||
#include <boost/poly_collection/function_collection.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
#include "rolegame.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
//[basic_function_1
|
||||
std::vector<std::unique_ptr<sprite>> sprs;
|
||||
std::vector<std::string> msgs;
|
||||
std::vector<window> wnds;
|
||||
//]
|
||||
|
||||
// populate sprs
|
||||
std::mt19937 gen{92748}; // some arbitrary random seed
|
||||
std::uniform_real_distribution<> rnd;
|
||||
for(int i=0;i<4;++i){ // assign each type with 1/3 probability
|
||||
auto r=rnd(gen);
|
||||
if(r<1.0/3)sprs.push_back(std::make_unique<warrior>(i));
|
||||
else if(r<2.0/3)sprs.push_back(std::make_unique<juggernaut>(i));
|
||||
else sprs.push_back(std::make_unique<goblin>(i));
|
||||
}
|
||||
|
||||
// populate msgs
|
||||
msgs.push_back("\"stamina: 10,000\"");
|
||||
msgs.push_back("\"game over\"");
|
||||
|
||||
// populate wnds
|
||||
wnds.emplace_back("pop-up 1");
|
||||
wnds.emplace_back("pop-up 2");
|
||||
|
||||
//[basic_function_2
|
||||
//= #include <boost/poly_collection/function_collection.hpp>
|
||||
//= ...
|
||||
//=
|
||||
// function signature accepting std::ostream& and returning nothing
|
||||
using render_callback=void(std::ostream&);
|
||||
boost::function_collection<render_callback> c;
|
||||
//]
|
||||
|
||||
//[basic_function_3
|
||||
auto render_sprite=[](const sprite& s){
|
||||
return [&](std::ostream& os){s.render(os);};
|
||||
};
|
||||
for(const auto& ps:sprs)c.insert(render_sprite(*ps));
|
||||
|
||||
auto render_message=[](const std::string& m){
|
||||
return [&](std::ostream& os){os<<m;};
|
||||
};
|
||||
for(const auto& m:msgs)c.insert(render_message(m));
|
||||
|
||||
auto render_window=[](const window& w){
|
||||
return [&](std::ostream& os){w.display(os);};
|
||||
};
|
||||
for(const auto& w:wnds)c.insert(render_window(w));
|
||||
//]
|
||||
|
||||
//[basic_function_4
|
||||
const char* comma="";
|
||||
for(const auto& cbk:c){
|
||||
std::cout<<comma;
|
||||
cbk(std::cout);
|
||||
comma=",";
|
||||
}
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
|
||||
//[basic_function_5
|
||||
auto cbk=*c.begin();
|
||||
cbk(std::cout); // renders first element to std::cout
|
||||
std::function<render_callback> f=cbk;
|
||||
f(std::cout); // exactly the same
|
||||
//]
|
||||
|
||||
//[basic_function_6
|
||||
//= *c.begin()=render_message("last minute message"); // compile-time error
|
||||
//]
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/* Copyright 2016 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.
|
||||
*/
|
||||
|
||||
/* Boost.PolyCollection exceptions */
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <boost/poly_collection/base_collection.hpp>
|
||||
#include <random>
|
||||
#include "rolegame.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::base_collection<sprite> c,c2;
|
||||
|
||||
// populate c
|
||||
|
||||
std::mt19937 gen{92748}; // some arbitrary random seed
|
||||
std::uniform_real_distribution<> rnd;
|
||||
for(int i=0;i<8;++i){ // assign each type with 1/3 probability
|
||||
auto r=rnd(gen);
|
||||
if(r<1.0/3)c.insert(warrior{i});
|
||||
else if(r<2.0/3)c.insert(juggernaut{i});
|
||||
else c.insert(goblin{i});
|
||||
}
|
||||
|
||||
auto render=[](const boost::base_collection<sprite>& c){
|
||||
const char* comma="";
|
||||
for(const sprite& s:c){
|
||||
std::cout<<comma;
|
||||
s.render(std::cout);
|
||||
comma=",";
|
||||
}
|
||||
std::cout<<"\n";
|
||||
};
|
||||
render(c);
|
||||
|
||||
try{
|
||||
//[exceptions_1
|
||||
c.insert(elf{0}); // no problem
|
||||
//= ...
|
||||
//=
|
||||
c2=c; // throws boost::poly_collection::not_copy_constructible
|
||||
//]
|
||||
}catch(boost::poly_collection::not_copy_constructible&){}
|
||||
|
||||
try{
|
||||
//[exceptions_2
|
||||
c.clear<elf>(); // get rid of non-copyable elfs
|
||||
c2=c; // now it works
|
||||
// check that the two are indeed equal
|
||||
std::cout<<(c==c2)<<"\n";
|
||||
// throws boost::poly_collection::not_equality_comparable
|
||||
//]
|
||||
}catch(boost::poly_collection::not_equality_comparable&){}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/* Copyright 2016 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.
|
||||
*/
|
||||
|
||||
/* examples of insertion and emplacement */
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <boost/poly_collection/base_collection.hpp>
|
||||
#include <random>
|
||||
#include "rolegame.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::base_collection<sprite> c;
|
||||
|
||||
// populate c
|
||||
|
||||
std::mt19937 gen{92748}; // some arbitrary random seed
|
||||
std::uniform_real_distribution<> rnd;
|
||||
for(int i=0;i<8;++i){ // assign each type with 1/3 probability
|
||||
auto r=rnd(gen);
|
||||
if(r<1.0/3)c.insert(warrior{i});
|
||||
else if(r<2.0/3)c.insert(juggernaut{i});
|
||||
else c.insert(goblin{i});
|
||||
}
|
||||
|
||||
auto render=[](const boost::base_collection<sprite>& c){
|
||||
const char* comma="";
|
||||
for(const sprite& s:c){
|
||||
std::cout<<comma;
|
||||
s.render(std::cout);
|
||||
comma=",";
|
||||
}
|
||||
std::cout<<"\n";
|
||||
};
|
||||
render(c);
|
||||
|
||||
//[insertion_emplacement_1]
|
||||
c.insert(c.begin(),juggernaut{8});
|
||||
//]
|
||||
render(c);
|
||||
|
||||
//[insertion_emplacement_2]
|
||||
c.insert(c.begin(),goblin{9});
|
||||
//]
|
||||
render(c);
|
||||
|
||||
//[insertion_emplacement_3]
|
||||
c.insert(c.begin<juggernaut>()+2,juggernaut{10});
|
||||
// ^^ remember local iterators are random access
|
||||
//]
|
||||
render(c);
|
||||
|
||||
//[insertion_emplacement_4]
|
||||
//= c.insert(c.begin(typeid(warrior)),juggernaut{11}); // undefined behavior!!
|
||||
//]
|
||||
|
||||
//[insertion_emplacement_5]
|
||||
boost::base_collection<sprite> c2;
|
||||
|
||||
c2.insert(c.begin(),c.end()); // read below
|
||||
//<-
|
||||
render(c2);
|
||||
//->
|
||||
|
||||
// add some more warriors
|
||||
std::array<warrior,3> aw={{11,12,13}};
|
||||
c2.insert(aw.begin(),aw.end());
|
||||
//<-
|
||||
render(c2);
|
||||
//->
|
||||
|
||||
// add some goblins at the beginning of their segment
|
||||
std::array<goblin,3> ag={{14,15,16}};
|
||||
c2.insert(c2.begin<goblin>(),ag.begin(),ag.end());
|
||||
//<-
|
||||
render(c2);
|
||||
//->
|
||||
//]
|
||||
|
||||
//[insertion_emplacement_6]
|
||||
//<-
|
||||
// same as line at beginning of of revious snippet
|
||||
//->
|
||||
c2.insert(c.begin(),c.end());
|
||||
//]
|
||||
|
||||
//[insertion_emplacement_7]
|
||||
//= c.emplace(11); // does not compile
|
||||
//]
|
||||
|
||||
//[insertion_emplacement_8]
|
||||
c.emplace<goblin>(11); // now it works
|
||||
//]
|
||||
render(c);
|
||||
|
||||
//[insertion_emplacement_9]
|
||||
c.emplace_hint<juggernaut>(c.begin(),12); // at the beginning if possible
|
||||
c.emplace_pos<goblin>(c.begin<goblin>()+2,13); // amidst the goblins
|
||||
c.emplace_pos<warrior>(c.begin(typeid(warrior)),14); // local_base_iterator
|
||||
//]
|
||||
render(c);
|
||||
}
|
||||
@@ -0,0 +1,600 @@
|
||||
/* Copyright 2016 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.
|
||||
*/
|
||||
|
||||
/* Boost.PolyCollection performance tests */
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <numeric>
|
||||
|
||||
std::chrono::high_resolution_clock::time_point measure_start,measure_pause;
|
||||
|
||||
template<typename F>
|
||||
double measure(F f)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
|
||||
static const int num_trials=10;
|
||||
static const milliseconds min_time_per_trial(200);
|
||||
std::array<double,num_trials> trials;
|
||||
volatile decltype(f()) res; /* to avoid optimizing f() away */
|
||||
|
||||
for(int i=0;i<num_trials;++i){
|
||||
int runs=0;
|
||||
high_resolution_clock::time_point t2;
|
||||
|
||||
measure_start=high_resolution_clock::now();
|
||||
do{
|
||||
res=f();
|
||||
++runs;
|
||||
t2=high_resolution_clock::now();
|
||||
}while(t2-measure_start<min_time_per_trial);
|
||||
trials[i]=duration_cast<duration<double>>(t2-measure_start).count()/runs;
|
||||
}
|
||||
(void)res; /* var not used warn */
|
||||
|
||||
std::sort(trials.begin(),trials.end());
|
||||
return std::accumulate(
|
||||
trials.begin()+2,trials.end()-2,0.0)/(trials.size()-4);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
double measure(unsigned int n,F f)
|
||||
{
|
||||
double t=measure(f);
|
||||
return (t/n)*10E9;
|
||||
}
|
||||
|
||||
void pause_timing()
|
||||
{
|
||||
measure_pause=std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
void resume_timing()
|
||||
{
|
||||
measure_start+=std::chrono::high_resolution_clock::now()-measure_pause;
|
||||
}
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#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/ptr_container/ptr_container.hpp>
|
||||
#include <boost/type_erasure/any.hpp>
|
||||
#include <boost/type_erasure/callable.hpp>
|
||||
#include <boost/type_erasure/builtin.hpp>
|
||||
#include <boost/type_erasure/operators.hpp>
|
||||
#include <boost/type_erasure/typeid_of.hpp>
|
||||
#include <functional>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
//[perf_base_types
|
||||
struct base
|
||||
{
|
||||
virtual ~base()=default;
|
||||
virtual int operator()(int)const=0;
|
||||
};
|
||||
|
||||
struct derived1 final:base
|
||||
{
|
||||
derived1(int n):n{n}{}
|
||||
virtual int operator()(int)const{return n;}
|
||||
|
||||
int n;
|
||||
};
|
||||
|
||||
struct derived2 final:base
|
||||
{
|
||||
derived2(int n):n{n}{}
|
||||
virtual int operator()(int x)const{return x*n;}
|
||||
|
||||
int unused,n;
|
||||
};
|
||||
|
||||
struct derived3 final:base
|
||||
{
|
||||
derived3(int n):n{n}{}
|
||||
virtual int operator()(int x)const{return x*x*n;}
|
||||
|
||||
int unused,n;
|
||||
};
|
||||
//]
|
||||
|
||||
//[perf_function_types
|
||||
struct concrete1
|
||||
{
|
||||
concrete1(int n):n{n}{}
|
||||
int operator()(int)const{return n;}
|
||||
|
||||
int n;
|
||||
};
|
||||
|
||||
struct concrete2
|
||||
{
|
||||
concrete2(int n):n{n}{}
|
||||
int operator()(int x)const{return x*n;}
|
||||
|
||||
int unused,n;
|
||||
};
|
||||
|
||||
struct concrete3
|
||||
{
|
||||
concrete3(int n):n{n}{}
|
||||
int operator()(int x)const{return x*x*n;}
|
||||
|
||||
int unused,n;
|
||||
};
|
||||
//]
|
||||
|
||||
template<typename Base>
|
||||
struct ptr_vector:boost::ptr_vector<Base>
|
||||
{
|
||||
public:
|
||||
template<typename T>
|
||||
void insert(const T& x)
|
||||
{
|
||||
this->push_back(new T{x});
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
{
|
||||
std::for_each(this->begin(),this->end(),f);
|
||||
}
|
||||
|
||||
void prepare_for_for_each(){}
|
||||
};
|
||||
|
||||
template<typename Base>
|
||||
struct sorted_ptr_vector:ptr_vector<Base>
|
||||
{
|
||||
void prepare_for_for_each()
|
||||
{
|
||||
std::sort(
|
||||
this->c_array(),this->c_array()+this->size(),
|
||||
[](Base* x,Base* y){return typeid(*x).before(typeid(*y));});
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Base>
|
||||
struct shuffled_ptr_vector:ptr_vector<Base>
|
||||
{
|
||||
void prepare_for_for_each()
|
||||
{
|
||||
std::shuffle(
|
||||
this->c_array(),this->c_array()+this->size(),std::mt19937(1));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Base>
|
||||
struct base_collection:boost::base_collection<Base>
|
||||
{
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
{
|
||||
std::for_each(this->begin(),this->end(),f);
|
||||
}
|
||||
|
||||
void prepare_for_for_each(){}
|
||||
};
|
||||
|
||||
template<typename Base,typename... T>
|
||||
struct poly_for_each_base_collection:base_collection<Base>
|
||||
{
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
{
|
||||
boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
struct func_vector:std::vector<std::function<Signature>>
|
||||
{
|
||||
template<typename T> void insert(const T& x)
|
||||
{
|
||||
this->push_back(x);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
{
|
||||
std::for_each(this->begin(),this->end(),f);
|
||||
}
|
||||
|
||||
void prepare_for_for_each(){}
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
struct sorted_func_vector:func_vector<Signature>
|
||||
{
|
||||
void prepare_for_for_each()
|
||||
{
|
||||
using value_type=typename sorted_func_vector::value_type;
|
||||
std::sort(
|
||||
this->begin(),this->end(),[](const value_type& x,const value_type& y){
|
||||
return x.target_type().before(y.target_type());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
struct shuffled_func_vector:func_vector<Signature>
|
||||
{
|
||||
void prepare_for_for_each()
|
||||
{
|
||||
std::shuffle(this->begin(),this->end(),std::mt19937(1));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
struct func_collection:boost::function_collection<Signature>
|
||||
{
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
{
|
||||
std::for_each(this->begin(),this->end(),f);
|
||||
}
|
||||
|
||||
void prepare_for_for_each(){}
|
||||
};
|
||||
|
||||
template<typename Signature,typename... T>
|
||||
struct poly_for_each_func_collection:func_collection<Signature>
|
||||
{
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
{
|
||||
boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Concept>
|
||||
struct any_vector:std::vector<boost::type_erasure::any<Concept>>
|
||||
{
|
||||
template<typename T> void insert(const T& x)
|
||||
{
|
||||
this->push_back(x);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
{
|
||||
std::for_each(this->begin(),this->end(),f);
|
||||
}
|
||||
|
||||
void prepare_for_for_each(){}
|
||||
};
|
||||
|
||||
template<typename Concept>
|
||||
struct sorted_any_vector:any_vector<Concept>
|
||||
{
|
||||
void prepare_for_for_each()
|
||||
{
|
||||
using value_type=typename sorted_any_vector::value_type;
|
||||
std::sort(
|
||||
this->begin(),this->end(),[](const value_type& x,const value_type& y){
|
||||
return typeid_of(x).before(typeid_of(y));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Concept>
|
||||
struct shuffled_any_vector:any_vector<Concept>
|
||||
{
|
||||
void prepare_for_for_each()
|
||||
{
|
||||
std::shuffle(this->begin(),this->end(),std::mt19937(1));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Concept>
|
||||
struct any_collection:boost::any_collection<Concept>
|
||||
{
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
{
|
||||
std::for_each(this->begin(),this->end(),f);
|
||||
}
|
||||
|
||||
void prepare_for_for_each(){}
|
||||
};
|
||||
|
||||
template<typename Concept,typename... T>
|
||||
struct poly_for_each_any_collection:any_collection<Concept>
|
||||
{
|
||||
template<typename F>
|
||||
void for_each(F f)
|
||||
{
|
||||
boost::poly_collection::for_each<T...>(this->begin(),this->end(),f);
|
||||
}
|
||||
};
|
||||
|
||||
#include <iostream>
|
||||
|
||||
template<typename... Printables>
|
||||
void print(Printables... ps)
|
||||
{
|
||||
const char* delim="";
|
||||
using seq=int[1+sizeof...(ps)];
|
||||
(void)seq{0,(std::cout<<delim<<ps,delim=";",0)...};
|
||||
std::cout<<"\n";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct label
|
||||
{
|
||||
label(const char* str):str{str}{}
|
||||
operator const char*()const{return str;}
|
||||
const char* str;
|
||||
};
|
||||
|
||||
template<typename... T>
|
||||
struct element_sequence{};
|
||||
|
||||
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)...};
|
||||
}
|
||||
}
|
||||
|
||||
struct insert_perf_functor
|
||||
{
|
||||
template<
|
||||
typename... Element,
|
||||
typename Container
|
||||
>
|
||||
std::size_t operator()(
|
||||
unsigned int n,element_sequence<Element...> elements,label<Container>)const
|
||||
{
|
||||
pause_timing();
|
||||
std::size_t res=0;
|
||||
{
|
||||
Container c;
|
||||
resume_timing();
|
||||
container_fill(n,elements,c);
|
||||
pause_timing();
|
||||
res=c.size();
|
||||
}
|
||||
resume_timing();
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
template<
|
||||
typename... Element,
|
||||
typename Container
|
||||
>
|
||||
double insert_perf(
|
||||
unsigned int n,element_sequence<Element...> elements,label<Container> label)
|
||||
{
|
||||
return measure(n,std::bind(insert_perf_functor{},n,elements,label));
|
||||
}
|
||||
|
||||
template<
|
||||
typename... Element,
|
||||
typename... Container
|
||||
>
|
||||
void insert_perf(
|
||||
unsigned int n0,unsigned int n1,unsigned int dn,
|
||||
element_sequence<Element...> elements,label<Container>... labels)
|
||||
{
|
||||
double fdn=1.1;
|
||||
|
||||
std::cout<<"insert:\n";
|
||||
print("n",labels...);
|
||||
|
||||
for(unsigned int n=n0;n<=n1;n+=dn,dn=(unsigned int)(dn*fdn)){
|
||||
unsigned int m=n/sizeof...(Element),nn=m*sizeof...(Element);
|
||||
print(nn,insert_perf(nn,elements,labels)...);
|
||||
}
|
||||
}
|
||||
|
||||
struct for_each_perf_functor
|
||||
{
|
||||
template<typename F,typename Container>
|
||||
auto operator()(F f,Container& c)const->decltype(f.res)
|
||||
{
|
||||
c.for_each(std::ref(f));
|
||||
return f.res;
|
||||
}
|
||||
};
|
||||
|
||||
template<
|
||||
typename... Element,
|
||||
typename F,
|
||||
typename Container
|
||||
>
|
||||
double for_each_perf(
|
||||
unsigned int n,
|
||||
element_sequence<Element...> elements,F f,label<Container>)
|
||||
{
|
||||
Container c;
|
||||
container_fill(n,elements,c);
|
||||
c.prepare_for_for_each();
|
||||
return measure(n,std::bind(for_each_perf_functor{},f,std::ref(c)));
|
||||
}
|
||||
|
||||
template<
|
||||
typename... Element,
|
||||
typename F,
|
||||
typename... Container
|
||||
>
|
||||
void for_each_perf(
|
||||
unsigned int n0,unsigned int n1,unsigned int dn,
|
||||
element_sequence<Element...> elements,F f,label<Container>... labels)
|
||||
{
|
||||
double fdn=1.1;
|
||||
|
||||
std::cout<<"for_each:\n";
|
||||
print("n",labels...);
|
||||
|
||||
for(unsigned int n=n0;n<=n1;n+=dn,dn=(unsigned int)(dn*fdn)){
|
||||
unsigned int m=n/sizeof...(Element),nn=m*sizeof...(Element);
|
||||
print(nn,for_each_perf(nn,elements,f,labels)...);
|
||||
}
|
||||
}
|
||||
|
||||
//[perf_for_each_callable
|
||||
struct for_each_callable
|
||||
{
|
||||
for_each_callable():res{0}{}
|
||||
|
||||
template<typename T>
|
||||
void operator()(T& x){
|
||||
res+=x(2);
|
||||
}
|
||||
|
||||
int res;
|
||||
};
|
||||
//]
|
||||
|
||||
//[pef_for_each_incrementable
|
||||
struct for_each_incrementable
|
||||
{
|
||||
for_each_incrementable():res{0}{}
|
||||
|
||||
template<typename T>
|
||||
void operator()(T& x){
|
||||
++x;
|
||||
++res;
|
||||
}
|
||||
|
||||
int res;
|
||||
};
|
||||
//]
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
using test=std::pair<std::string,bool&>;
|
||||
|
||||
bool all=false,
|
||||
insert_base=false,
|
||||
for_each_base=false,
|
||||
insert_function=false,
|
||||
for_each_function=false,
|
||||
insert_any=false,
|
||||
for_each_any=false;
|
||||
std::array<test,7> 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}
|
||||
}};
|
||||
|
||||
if(argc<2){
|
||||
std::cout<<"specify one or more tests to execute:\n";
|
||||
for(const auto& p:tests)std::cout<<" "<<p.first<<"\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
for(int arg=1;arg<argc;++arg){
|
||||
auto it=std::find_if(tests.begin(),tests.end(),[&](test& t){
|
||||
return t.first==argv[arg];
|
||||
});
|
||||
if(it==tests.end()){
|
||||
std::cout<<"invalid test name\n";
|
||||
return 1;
|
||||
}
|
||||
it->second=true;
|
||||
}
|
||||
|
||||
unsigned int n0=1000,n1=11000000,dn=1000;
|
||||
|
||||
{
|
||||
auto seq= element_sequence<
|
||||
derived1,derived1,derived2,derived2,derived3>{};
|
||||
auto f= for_each_callable{};
|
||||
auto pv= label<ptr_vector<base>>
|
||||
{"ptr_vector"};
|
||||
auto spv= label<sorted_ptr_vector<base>>
|
||||
{"sorted ptr_vector"};
|
||||
auto shpv= label<shuffled_ptr_vector<base>>
|
||||
{"shuffled ptr_vector"};
|
||||
auto bc= label<base_collection<base>>
|
||||
{"base_collection"};
|
||||
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>
|
||||
>
|
||||
{"base_collection (restituted poly::for_each)"};
|
||||
|
||||
if(all||insert_base)insert_perf(n0,n1,dn,seq,pv,bc);
|
||||
if(all||for_each_base)for_each_perf(
|
||||
n0,n1,dn,seq,f,pv,spv,shpv,bc,fbc,rfbc);
|
||||
}
|
||||
{
|
||||
using signature=int(int);
|
||||
|
||||
auto seq= element_sequence<
|
||||
concrete1,concrete1,concrete2,concrete2,concrete3>{};
|
||||
auto f = for_each_callable{};
|
||||
auto fv= label<func_vector<signature>>
|
||||
{"func_vector"};
|
||||
auto sfv= label<sorted_func_vector<signature>>
|
||||
{"sorted func_vector"};
|
||||
auto shfv= label<shuffled_func_vector<signature>>
|
||||
{"shuffled func_vector"};
|
||||
auto fc= label<func_collection<signature>>
|
||||
{"function_collection"};
|
||||
auto ffc= label<poly_for_each_func_collection<signature>>
|
||||
{"function_collection (poly::for_each)"};
|
||||
auto rffc= label<poly_for_each_func_collection<
|
||||
signature,concrete1,concrete2,concrete3>>
|
||||
{"function_collection (restituted poly::for_each)"};
|
||||
|
||||
if(all||insert_function)insert_perf(n0,n1,dn,seq,fv,fc);
|
||||
if(all||for_each_function)for_each_perf(
|
||||
n0,n1,dn,seq,f,fv,sfv,shfv,fc,ffc,rffc);
|
||||
}
|
||||
{
|
||||
//[perf_any_types
|
||||
using concept=boost::mpl::vector<
|
||||
boost::type_erasure::copy_constructible<>,
|
||||
boost::type_erasure::relaxed,
|
||||
boost::type_erasure::typeid_<>,
|
||||
boost::type_erasure::incrementable<>
|
||||
>;
|
||||
//]
|
||||
|
||||
auto seq= element_sequence<int,int,double,double,char>{};
|
||||
auto f= for_each_incrementable{};
|
||||
auto av= label<any_vector<concept>>
|
||||
{"any_vector"};
|
||||
auto sav= label<sorted_any_vector<concept>>
|
||||
{"sorted any_vector"};
|
||||
auto shav= label<shuffled_any_vector<concept>>
|
||||
{"shuffled any_vector"};
|
||||
auto ac= label<any_collection<concept>>
|
||||
{"any_collection"};
|
||||
auto fac= label<poly_for_each_any_collection<concept>>
|
||||
{"any_collection (poly::for_each)"};
|
||||
auto rfac= label<poly_for_each_any_collection<concept,int,double,char>>
|
||||
{"any_collection (restituted poly::for_each)"};
|
||||
|
||||
if(all||insert_any)insert_perf(n0,n1,dn,seq,av,ac);
|
||||
if(all||for_each_any)for_each_perf(n0,n1,dn,seq,f,av,sav,shav,ac,fac,rfac);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/* Copyright 2016 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_EXAMPLE_ROLEGAME_HPP
|
||||
#define BOOST_POLY_COLLECTION_EXAMPLE_ROLEGAME_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
/* entities of a purported role game used in the examples */
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
//[rolegame_1
|
||||
struct sprite
|
||||
{
|
||||
sprite(int id):id(id){}
|
||||
virtual ~sprite()=default;
|
||||
virtual void render(std::ostream& os)const=0;
|
||||
|
||||
int id;
|
||||
};
|
||||
//]
|
||||
|
||||
//[rolegame_2
|
||||
struct warrior:sprite
|
||||
{
|
||||
using sprite::sprite;
|
||||
warrior(std::string rank,int id):sprite{id},rank{std::move(rank)}{}
|
||||
|
||||
virtual void render(std::ostream& os)const{os<<rank<<" "<<id;};
|
||||
|
||||
std::string rank="warrior";
|
||||
};
|
||||
|
||||
struct juggernaut:warrior
|
||||
{
|
||||
juggernaut(int id):warrior{"juggernaut",id}{}
|
||||
};
|
||||
|
||||
struct goblin:sprite
|
||||
{
|
||||
using sprite::sprite;
|
||||
virtual void render(std::ostream& os)const{os<<"goblin "<<id;};
|
||||
};
|
||||
//]
|
||||
|
||||
//[rolegame_3
|
||||
struct window
|
||||
{
|
||||
window(std::string caption):caption{std::move(caption)}{}
|
||||
|
||||
void display(std::ostream& os)const{os<<"["<<caption<<"]";}
|
||||
|
||||
std::string caption;
|
||||
};
|
||||
//]
|
||||
|
||||
//[rolegame_4
|
||||
struct elf:sprite
|
||||
{
|
||||
using sprite::sprite;
|
||||
elf(const elf&)=delete; // not copyable
|
||||
elf(elf&&)=default; // but moveable
|
||||
virtual void render(std::ostream& os)const{os<<"elf "<<id;};
|
||||
};
|
||||
//]
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,161 @@
|
||||
/* Copyright 2016 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.
|
||||
*/
|
||||
|
||||
/* segment-specific operations */
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/poly_collection/any_collection.hpp>
|
||||
#include <boost/poly_collection/base_collection.hpp>
|
||||
#include <boost/type_erasure/operators.hpp>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include "rolegame.hpp"
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,const sprite& s)
|
||||
{
|
||||
s.render(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,const window& w)
|
||||
{
|
||||
w.display(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::base_collection<sprite> c;
|
||||
|
||||
//[segmented_structure_1
|
||||
//= std::unique_ptr<sprite> make_sprite()
|
||||
//= {
|
||||
//<-
|
||||
auto make_sprite=[]()->std::unique_ptr<sprite>{
|
||||
//->
|
||||
static std::mt19937 gen{92748};
|
||||
static std::uniform_real_distribution<> rnd;
|
||||
static int id=0;
|
||||
|
||||
auto r=rnd(gen);
|
||||
if(r<1.0/3)return std::make_unique<warrior>(id++);
|
||||
else if(r<2.0/3)return std::make_unique<juggernaut>(id++);
|
||||
else return std::make_unique<goblin>(id++);
|
||||
//<-
|
||||
};
|
||||
//->
|
||||
//= }
|
||||
//= ...
|
||||
//=
|
||||
//<-
|
||||
try{
|
||||
//->
|
||||
for(int i=0;i<8;++i)c.insert(*make_sprite());
|
||||
// throws boost::poly_collection::unregistered_type
|
||||
//<-
|
||||
}catch(boost::poly_collection::unregistered_type&){}
|
||||
//->
|
||||
//]
|
||||
|
||||
//[segmented_structure_2
|
||||
std::cout<<c.is_registered<warrior>()<<"\n"; // prints 0
|
||||
std::cout<<c.is_registered(typeid(warrior))<<"\n"; // alternate syntax
|
||||
//]
|
||||
|
||||
//[segmented_structure_3
|
||||
c.register_types<warrior,juggernaut,goblin>();
|
||||
// everything works fine now
|
||||
for(int i=0;i<8;++i)c.insert(*make_sprite());
|
||||
//]
|
||||
|
||||
using renderable=boost::type_erasure::ostreamable<>;
|
||||
//[segmented_structure_4
|
||||
boost::any_collection<renderable> c1,c2;
|
||||
//= ... // populate c2
|
||||
//=
|
||||
//<-
|
||||
c2.insert(window{"pop-up"});
|
||||
try{
|
||||
//->
|
||||
c1.insert(*c2.begin()); // throws: actual type of *c2.begin() not known by c1
|
||||
//<-
|
||||
}catch(boost::poly_collection::unregistered_type&){}
|
||||
//->
|
||||
//]
|
||||
|
||||
//[segmented_structure_5
|
||||
//= ... // populate c with 8 assorted entities
|
||||
//=
|
||||
std::cout<<c.size()<<"\n"; // 8 sprites
|
||||
std::cout<<c.size<juggernaut>()<<"\n"; // 2 juggernauts
|
||||
std::cout<<c.size(typeid(juggernaut))<<"\n"; // alternate syntax
|
||||
c.clear<juggernaut>(); // remove juggenauts only
|
||||
std::cout<<c.empty<juggernaut>()<<"\n"; // 1 (no juggernauts left)
|
||||
std::cout<<c.size()<<"\n"; // 6 sprites remaining
|
||||
//]
|
||||
|
||||
//[segmented_structure_6
|
||||
const char* comma="";
|
||||
for(auto first=c.begin(typeid(warrior)),last=c.end(typeid(warrior));
|
||||
first!=last;++first){
|
||||
std::cout<<comma;
|
||||
first->render(std::cout);
|
||||
comma=",";
|
||||
}
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
|
||||
//[segmented_structure_7
|
||||
/*=const char**/ comma="";
|
||||
for(auto first=c.begin<warrior>(),last=c.end<warrior>();
|
||||
first!=last;++first){
|
||||
first->rank.insert(0,"super");
|
||||
std::cout<<comma;
|
||||
first->render(std::cout);
|
||||
comma=",";
|
||||
}
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
|
||||
auto render=[&](){
|
||||
//[segmented_structure_8
|
||||
const char* comma="";
|
||||
for(auto seg_info:c.segment_traversal()){
|
||||
for(sprite& s:seg_info){
|
||||
std::cout<<comma;
|
||||
s.render(std::cout);
|
||||
comma=",";
|
||||
}
|
||||
}
|
||||
std::cout<<"\n";
|
||||
//]
|
||||
};
|
||||
render();
|
||||
|
||||
//[segmented_structure_9
|
||||
c.reserve<goblin>(100); // no reallocation till we exceed 100 goblins
|
||||
std::cout<<c.capacity<goblin>()<<"\n"; // prints 100
|
||||
//]
|
||||
|
||||
//[segmented_structure_10
|
||||
c.reserve(1000); // reserve(1000) for each segment
|
||||
std::cout<<c.capacity()<<"\n"; // prints 1000
|
||||
//]
|
||||
|
||||
{
|
||||
//[segmented_structure_11
|
||||
boost::base_collection<sprite> c; // newly created collection
|
||||
std::cout<<c.capacity()<<"\n"; // prints 18446744073709551615!!
|
||||
//]
|
||||
|
||||
//[segmented_structure_12
|
||||
c.register_types<warrior,juggernaut,goblin>();
|
||||
std::cout<<c.capacity()<<"\n"; // prints 0
|
||||
//]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/* Copyright 2016 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/any_collection for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_POLY_COLLECTION_ANY_COLLECTION_HPP
|
||||
#define BOOST_POLY_COLLECTION_ANY_COLLECTION_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/poly_collection/any_collection_fwd.hpp>
|
||||
#include <boost/poly_collection/detail/any_model.hpp>
|
||||
#include <boost/poly_collection/detail/poly_collection.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
template<typename Concept,typename Allocator>
|
||||
class any_collection:
|
||||
public detail::poly_collection<detail::any_model<Concept>,Allocator>
|
||||
{
|
||||
using base_type=
|
||||
detail::poly_collection<detail::any_model<Concept>,Allocator>;
|
||||
|
||||
base_type& base()noexcept{return *this;}
|
||||
const base_type& base()const noexcept{return *this;}
|
||||
|
||||
public:
|
||||
using base_type::base_type;
|
||||
|
||||
any_collection()=default;
|
||||
any_collection(const any_collection& x)=default;
|
||||
any_collection(any_collection&& x)=default;
|
||||
any_collection& operator=(const any_collection& x)=default;
|
||||
any_collection& operator=(any_collection&& x)=default;
|
||||
|
||||
friend bool operator==(
|
||||
const any_collection<Concept,Allocator>& x,
|
||||
const any_collection<Concept,Allocator>& y)
|
||||
{
|
||||
return x.base()==y.base();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Concept,typename Allocator>
|
||||
bool operator!=(
|
||||
const any_collection<Concept,Allocator>& x,
|
||||
const any_collection<Concept,Allocator>& y)
|
||||
{
|
||||
return !(x==y);
|
||||
}
|
||||
|
||||
template<typename Concept,typename Allocator>
|
||||
void swap(
|
||||
any_collection<Concept,Allocator>& x,any_collection<Concept,Allocator>& y)
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
using poly_collection::any_collection;
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
/* Copyright 2016 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/any_collection for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_POLY_COLLECTION_ANY_COLLECTION_FWD_HPP
|
||||
#define BOOST_POLY_COLLECTION_ANY_COLLECTION_FWD_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
template<typename Concept> struct any_model;
|
||||
}
|
||||
|
||||
template<typename Concept>
|
||||
using any_collection_value_type=
|
||||
typename detail::any_model<Concept>::value_type;
|
||||
|
||||
template<
|
||||
typename Concept,
|
||||
typename Allocator=std::allocator<any_collection_value_type<Concept>>
|
||||
>
|
||||
class any_collection;
|
||||
|
||||
template<typename Concept,typename Allocator>
|
||||
bool operator==(
|
||||
const any_collection<Concept,Allocator>& x,
|
||||
const any_collection<Concept,Allocator>& y);
|
||||
|
||||
template<typename Concept,typename Allocator>
|
||||
bool operator!=(
|
||||
const any_collection<Concept,Allocator>& x,
|
||||
const any_collection<Concept,Allocator>& y);
|
||||
|
||||
template<typename Concept,typename Allocator>
|
||||
void swap(
|
||||
any_collection<Concept,Allocator>& x,any_collection<Concept,Allocator>& y);
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
using poly_collection::any_collection;
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
/* Copyright 2016 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/base_collection for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_POLY_COLLECTION_BASE_COLLECTION_HPP
|
||||
#define BOOST_POLY_COLLECTION_BASE_COLLECTION_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/poly_collection/base_collection_fwd.hpp>
|
||||
#include <boost/poly_collection/detail/base_model.hpp>
|
||||
#include <boost/poly_collection/detail/poly_collection.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
template<typename Base,typename Allocator>
|
||||
class base_collection:
|
||||
public detail::poly_collection<detail::base_model<Base>,Allocator>
|
||||
{
|
||||
using base_type=
|
||||
detail::poly_collection<detail::base_model<Base>,Allocator>;
|
||||
|
||||
base_type& base()noexcept{return *this;}
|
||||
const base_type& base()const noexcept{return *this;}
|
||||
|
||||
public:
|
||||
using base_type::base_type;
|
||||
|
||||
base_collection()=default;
|
||||
base_collection(const base_collection& x)=default;
|
||||
base_collection(base_collection&& x)=default;
|
||||
base_collection& operator=(const base_collection& x)=default;
|
||||
base_collection& operator=(base_collection&& x)=default;
|
||||
|
||||
friend bool operator==(
|
||||
const base_collection<Base,Allocator>& x,
|
||||
const base_collection<Base,Allocator>& y)
|
||||
{
|
||||
return x.base()==y.base();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Base,typename Allocator>
|
||||
bool operator!=(
|
||||
const base_collection<Base,Allocator>& x,
|
||||
const base_collection<Base,Allocator>& y)
|
||||
{
|
||||
return !(x==y);
|
||||
}
|
||||
|
||||
template<typename Base,typename Allocator>
|
||||
void swap(
|
||||
base_collection<Base,Allocator>& x,base_collection<Base,Allocator>& y)
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
using poly_collection::base_collection;
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
/* Copyright 2016 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/base_collection for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_POLY_COLLECTION_BASE_COLLECTION_FWD_HPP
|
||||
#define BOOST_POLY_COLLECTION_BASE_COLLECTION_FWD_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
template<typename Base,typename Allocator=std::allocator<Base>>
|
||||
class base_collection;
|
||||
|
||||
template<typename Base,typename Allocator>
|
||||
bool operator==(
|
||||
const base_collection<Base,Allocator>& x,
|
||||
const base_collection<Base,Allocator>& y);
|
||||
|
||||
template<typename Base,typename Allocator>
|
||||
bool operator!=(
|
||||
const base_collection<Base,Allocator>& x,
|
||||
const base_collection<Base,Allocator>& y);
|
||||
|
||||
template<typename Base,typename Allocator>
|
||||
void swap(
|
||||
base_collection<Base,Allocator>& x,base_collection<Base,Allocator>& y);
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
using poly_collection::base_collection;
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,92 @@
|
||||
/* Copyright 2016 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_ANY_ITERATOR_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_ANY_ITERATOR_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/iterator/iterator_adaptor.hpp>
|
||||
#include <boost/type_erasure/any_cast.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* type_erasure::any<Concept>* adaptor convertible to pointer to wrapped
|
||||
* entity.
|
||||
*/
|
||||
|
||||
template<typename Any>
|
||||
class any_iterator:public boost::iterator_adaptor<any_iterator<Any>,Any*>
|
||||
{
|
||||
public:
|
||||
any_iterator()=default;
|
||||
explicit any_iterator(Any* p)noexcept:any_iterator::iterator_adaptor_{p}{}
|
||||
any_iterator(const any_iterator&)=default;
|
||||
any_iterator& operator=(const any_iterator&)=default;
|
||||
|
||||
template<
|
||||
typename NonConstAny,
|
||||
typename std::enable_if<
|
||||
std::is_same<Any,const NonConstAny>::value>::type* =nullptr
|
||||
>
|
||||
any_iterator(const any_iterator<NonConstAny>& x)noexcept:
|
||||
any_iterator::iterator_adaptor_{x.base()}{}
|
||||
|
||||
template<
|
||||
typename NonConstAny,
|
||||
typename std::enable_if<
|
||||
std::is_same<Any,const NonConstAny>::value>::type* =nullptr
|
||||
>
|
||||
any_iterator& operator=(const any_iterator<NonConstAny>& x)noexcept
|
||||
{
|
||||
this->base_reference()=x.base();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* interoperability with Any* */
|
||||
|
||||
any_iterator& operator=(Any* p)noexcept
|
||||
{this->base_reference()=p;return *this;}
|
||||
operator Any*()const noexcept{return this->base();}
|
||||
|
||||
/* interoperability with Concrete* */
|
||||
|
||||
template<
|
||||
typename Concrete,
|
||||
typename std::enable_if<
|
||||
/* can't compile-time check concept compliance */
|
||||
!std::is_const<Any>::value||std::is_const<Concrete>::value
|
||||
>::type* =nullptr
|
||||
>
|
||||
explicit operator Concrete*()const noexcept
|
||||
{
|
||||
return const_cast<Concrete*>(
|
||||
static_cast<typename std::remove_const<Concrete>::type*>(
|
||||
type_erasure::any_cast<void*>(this->base())));
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename>
|
||||
friend class any_iterator;
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,171 @@
|
||||
/* Copyright 2016 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_ANY_MODEL_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_ANY_MODEL_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/core/addressof.hpp>
|
||||
#include <boost/mpl/vector/vector10.hpp>
|
||||
#include <boost/poly_collection/detail/any_iterator.hpp>
|
||||
#include <boost/poly_collection/detail/is_acceptable.hpp>
|
||||
#include <boost/poly_collection/detail/segment_backend.hpp>
|
||||
#include <boost/poly_collection/detail/split_segment.hpp>
|
||||
#include <boost/type_erasure/any.hpp>
|
||||
#include <boost/type_erasure/any_cast.hpp>
|
||||
#include <boost/type_erasure/builtin.hpp>
|
||||
#include <boost/type_erasure/is_subconcept.hpp>
|
||||
#include <boost/type_erasure/relaxed.hpp>
|
||||
#include <boost/type_erasure/typeid_of.hpp>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* model for any_collection */
|
||||
|
||||
template<typename Concept>
|
||||
struct any_model;
|
||||
|
||||
/* Refine is_acceptable to cover type_erasure::any classes whose assignment
|
||||
* operator won't compile.
|
||||
*/
|
||||
|
||||
template<typename Concept,typename Concept2,typename T>
|
||||
struct is_acceptable<
|
||||
type_erasure::any<Concept2,T>,any_model<Concept>,
|
||||
typename std::enable_if<
|
||||
!type_erasure::is_relaxed<Concept2>::value&&
|
||||
!type_erasure::is_subconcept<type_erasure::assignable<>,Concept2>::value
|
||||
>::type
|
||||
>:std::false_type{};
|
||||
|
||||
/* is_terminal defined out-class to allow for partial specialization */
|
||||
|
||||
template<typename T,typename=void>
|
||||
struct any_model_is_terminal:std::true_type{};
|
||||
|
||||
template<typename Concept,typename T>
|
||||
struct any_model_is_terminal<
|
||||
type_erasure::any<Concept,T>,
|
||||
typename std::enable_if<
|
||||
type_erasure::is_subconcept<type_erasure::typeid_<>,Concept>::value
|
||||
>::type
|
||||
>:std::false_type{};
|
||||
|
||||
template<typename Concept>
|
||||
struct any_model
|
||||
{
|
||||
using value_type=type_erasure::any<
|
||||
typename std::conditional<
|
||||
type_erasure::is_subconcept<type_erasure::typeid_<>,Concept>::value,
|
||||
Concept,
|
||||
mpl::vector2<Concept,type_erasure::typeid_<>>
|
||||
>::type,
|
||||
type_erasure::_self&
|
||||
>;
|
||||
|
||||
template<typename Concrete>
|
||||
using is_subtype=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& subtypeid(const T&){return typeid(T);}
|
||||
|
||||
template<
|
||||
typename Concept2,typename T,
|
||||
typename std::enable_if<
|
||||
type_erasure::is_subconcept<type_erasure::typeid_<>,Concept2>::value
|
||||
>::type* = nullptr
|
||||
>
|
||||
static const std::type_info& subtypeid(
|
||||
const type_erasure::any<Concept2,T>& a)
|
||||
{
|
||||
return type_erasure::typeid_of(a);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void* subaddress(T& x){return boost::addressof(x);}
|
||||
|
||||
template<typename T>
|
||||
static const void* subaddress(const T& x){return boost::addressof(x);}
|
||||
|
||||
template<
|
||||
typename Concept2,typename T,
|
||||
typename std::enable_if<
|
||||
type_erasure::is_subconcept<type_erasure::typeid_<>,Concept2>::value
|
||||
>::type* =nullptr
|
||||
>
|
||||
static void* subaddress(type_erasure::any<Concept2,T>& a)
|
||||
{
|
||||
return type_erasure::any_cast<void*>(&a);
|
||||
}
|
||||
|
||||
template<
|
||||
typename Concept2,typename T,
|
||||
typename std::enable_if<
|
||||
type_erasure::is_subconcept<type_erasure::typeid_<>,Concept2>::value
|
||||
>::type* =nullptr
|
||||
>
|
||||
static const void* subaddress(const type_erasure::any<Concept2,T>& a)
|
||||
{
|
||||
return type_erasure::any_cast<void*>(&a);
|
||||
}
|
||||
|
||||
using base_iterator=any_iterator<value_type>;
|
||||
using const_base_iterator=any_iterator<const value_type>;
|
||||
using base_sentinel=value_type*;
|
||||
using const_base_sentinel=const value_type*;
|
||||
template<typename Concrete>
|
||||
using iterator=Concrete*;
|
||||
template<typename Concrete>
|
||||
using const_iterator=const Concrete*;
|
||||
using segment_backend=detail::segment_backend<any_model>;
|
||||
|
||||
static base_iterator nonconst_iterator(const_base_iterator it)
|
||||
{
|
||||
return base_iterator{
|
||||
const_cast<value_type*>(static_cast<const value_type*>(it))};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static iterator<T> nonconst_iterator(const_iterator<T> it)
|
||||
{
|
||||
return const_cast<iterator<T>>(it);
|
||||
}
|
||||
|
||||
template<typename Concrete,typename Allocator>
|
||||
static segment_backend* make(const Allocator& al)
|
||||
{
|
||||
return new split_segment<
|
||||
any_model,
|
||||
Concrete,
|
||||
typename std::allocator_traits<Allocator>::
|
||||
template rebind_alloc<Concrete>
|
||||
>{al};
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
/* Copyright 2016 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_AUTO_ITERATOR_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_AUTO_ITERATOR_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/iterator/iterator_adaptor.hpp>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* auto_iterator<Iterator> (for want of a better name) behaves like Iterator
|
||||
* save for the fact that it derefs to Iterator& rather than
|
||||
* Iterator::reference. This is useful to "lift" std algorithms so that
|
||||
* user-defined predicates are passed iterators that can then be dereferenced
|
||||
* internally.
|
||||
*/
|
||||
|
||||
template<typename Iterator>
|
||||
class auto_iterator:
|
||||
public boost::iterator_adaptor<auto_iterator<Iterator>,Iterator,Iterator>
|
||||
{
|
||||
public:
|
||||
auto_iterator()=default;
|
||||
auto_iterator(const Iterator& it):auto_iterator::iterator_adaptor_{it}{}
|
||||
auto_iterator(const auto_iterator&)=default;
|
||||
auto_iterator& operator=(const auto_iterator&)=default;
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
Iterator& dereference()const noexcept
|
||||
{
|
||||
return const_cast<auto_iterator*>(this)->base_reference();
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,112 @@
|
||||
/* Copyright 2016 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_BASE_MODEL_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_BASE_MODEL_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/core/addressof.hpp>
|
||||
#include <boost/poly_collection/detail/is_final.hpp>
|
||||
#include <boost/poly_collection/detail/packed_segment.hpp>
|
||||
#include <boost/poly_collection/detail/stride_iterator.hpp>
|
||||
#include <boost/poly_collection/detail/value_holder.hpp>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* model for base_collection */
|
||||
|
||||
template<typename Base>
|
||||
struct base_model
|
||||
{
|
||||
using value_type=Base;
|
||||
template<typename Derived>
|
||||
using is_subtype=std::is_base_of<Base,Derived>;
|
||||
template<typename T>
|
||||
using is_terminal=is_final<T>; //TODO: should we say !is_polymorhpic||is_final?
|
||||
template<typename T>
|
||||
static const std::type_info& subtypeid(const T& x){return typeid(x);}
|
||||
template<typename T>
|
||||
static void* subaddress(T& x){return boost::addressof(x);}
|
||||
template<typename T>
|
||||
static const void* subaddress(const T& x){return boost::addressof(x);}
|
||||
|
||||
using base_iterator=stride_iterator<Base>;
|
||||
using const_base_iterator=stride_iterator<const Base>;
|
||||
using base_sentinel=Base*;
|
||||
using const_base_sentinel=const Base*;
|
||||
template<typename Derived>
|
||||
using iterator=Derived*;
|
||||
template<typename Derived>
|
||||
using const_iterator=const Derived*;
|
||||
using segment_backend=detail::segment_backend<base_model>;
|
||||
|
||||
static base_iterator nonconst_iterator(const_base_iterator it)
|
||||
{
|
||||
return {
|
||||
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<iterator<T>>(it);
|
||||
}
|
||||
|
||||
template<typename Derived,typename Allocator>
|
||||
static segment_backend* make(const Allocator& al)
|
||||
{
|
||||
return new packed_segment<
|
||||
base_model,
|
||||
Derived,
|
||||
typename std::allocator_traits<Allocator>::
|
||||
template rebind_alloc<Derived>
|
||||
>{al};
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename,typename,typename>
|
||||
friend class packed_segment;
|
||||
|
||||
template<typename Derived>
|
||||
using element_type=value_holder<Derived>;
|
||||
|
||||
template<typename Derived>
|
||||
static const Base* value_ptr(const value_holder<Derived>* p)noexcept
|
||||
{
|
||||
return reinterpret_cast<const Derived*>(
|
||||
static_cast<const value_holder_base<Derived>*>(p));
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
static const value_holder<Derived>* element_ptr(const Derived* p)noexcept
|
||||
{
|
||||
return static_cast<const value_holder<Derived>*>(
|
||||
reinterpret_cast<const value_holder_base<Derived>*>(p));
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,104 @@
|
||||
/* Copyright 2016 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_CALLABLE_WRAPPER_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_CALLABLE_WRAPPER_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/poly_collection/detail/is_callable.hpp>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* lightweight std::function look-alike over non-owned callable entities */
|
||||
|
||||
template<typename Signature>
|
||||
class callable_wrapper;
|
||||
|
||||
template<typename R,typename... Args>
|
||||
class callable_wrapper<R(Args...)>
|
||||
{
|
||||
public:
|
||||
// TODO: we should prevent assignment by user code
|
||||
template<
|
||||
typename Callable,
|
||||
typename std::enable_if<
|
||||
!std::is_same<Callable,callable_wrapper>::value&&
|
||||
is_callable<Callable(Args...),R>::value
|
||||
>::type* =nullptr
|
||||
>
|
||||
explicit callable_wrapper(Callable& x)noexcept:pt{info(x)},px{&x}{}
|
||||
callable_wrapper(const callable_wrapper&)=default;
|
||||
callable_wrapper& operator=(const callable_wrapper&)=default;
|
||||
|
||||
explicit operator bool()const noexcept{return true;}
|
||||
|
||||
R operator()(Args... args)const
|
||||
{return pt->call(px,std::forward<Args>(args)...);}
|
||||
|
||||
const std::type_info& target_type()const noexcept{return pt->info;}
|
||||
|
||||
template<typename T>
|
||||
T* target()noexcept
|
||||
{return typeid(T)==pt->info?static_cast<T*>(px):nullptr;}
|
||||
template<typename T>
|
||||
const T* target()const noexcept
|
||||
{return typeid(T)==pt->info?static_cast<const T*>(px):nullptr;}
|
||||
|
||||
/* not in std::function interface */
|
||||
|
||||
operator std::function<R(Args...)>()const noexcept{return pt->convert(px);}
|
||||
|
||||
void* data()noexcept{return px;}
|
||||
const void* data()const noexcept{return px;}
|
||||
|
||||
private:
|
||||
struct table
|
||||
{
|
||||
R(*call)(void*,Args...);
|
||||
const std::type_info& info;
|
||||
std::function<R(Args...)> (*convert)(void*);
|
||||
};
|
||||
|
||||
template<typename Callable>
|
||||
static table* info(Callable&)noexcept
|
||||
{
|
||||
static table t={
|
||||
[](void* p,Args... args)->R{
|
||||
auto r=std::ref(*static_cast<Callable*>(p));
|
||||
return r(std::forward<Args>(args)...);
|
||||
},
|
||||
typeid(Callable),
|
||||
[](void* p){
|
||||
auto r=std::ref(*static_cast<Callable*>(p));
|
||||
return std::function<R(Args...)>{r};
|
||||
}
|
||||
};
|
||||
return &t;
|
||||
}
|
||||
|
||||
table* pt;
|
||||
void* px;
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,95 @@
|
||||
/* Copyright 2016 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_CALLABLE_WRAPPER_ITERATOR_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_CALLABLE_WRAPPER_ITERATOR_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/iterator/iterator_adaptor.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* callable_wrapper<Sig>* adaptor convertible to pointer to wrapped entity */
|
||||
|
||||
template<typename CWrapper>
|
||||
class callable_wrapper_iterator:public boost::iterator_adaptor<
|
||||
callable_wrapper_iterator<CWrapper>,CWrapper*
|
||||
>
|
||||
{
|
||||
public:
|
||||
callable_wrapper_iterator()=default;
|
||||
explicit callable_wrapper_iterator(CWrapper* p)noexcept:
|
||||
callable_wrapper_iterator::iterator_adaptor_{p}{}
|
||||
callable_wrapper_iterator(const callable_wrapper_iterator&)=default;
|
||||
callable_wrapper_iterator& operator=(
|
||||
const callable_wrapper_iterator&)=default;
|
||||
|
||||
template<
|
||||
typename NonConstCWrapper,
|
||||
typename std::enable_if<
|
||||
std::is_same<CWrapper,const NonConstCWrapper>::value>::type* =nullptr
|
||||
>
|
||||
callable_wrapper_iterator(
|
||||
const callable_wrapper_iterator<NonConstCWrapper>& x)noexcept:
|
||||
callable_wrapper_iterator::iterator_adaptor_{x.base()}{}
|
||||
|
||||
template<
|
||||
typename NonConstCWrapper,
|
||||
typename std::enable_if<
|
||||
std::is_same<CWrapper,const NonConstCWrapper>::value>::type* =nullptr
|
||||
>
|
||||
callable_wrapper_iterator& operator=(
|
||||
const callable_wrapper_iterator<NonConstCWrapper>& x)noexcept
|
||||
{
|
||||
this->base_reference()=x.base();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* interoperability with CWrapper* */
|
||||
|
||||
callable_wrapper_iterator& operator=(CWrapper* p)noexcept
|
||||
{this->base_reference()=p;return *this;}
|
||||
operator CWrapper*()const noexcept{return this->base();}
|
||||
|
||||
/* interoperability with Callable* */
|
||||
|
||||
template<
|
||||
typename Callable,
|
||||
typename std::enable_if<
|
||||
std::is_constructible<CWrapper,Callable&>::value&&
|
||||
(!std::is_const<CWrapper>::value||std::is_const<Callable>::value)
|
||||
>::type* =nullptr
|
||||
>
|
||||
explicit operator Callable*()const noexcept
|
||||
{
|
||||
return const_cast<Callable*>(
|
||||
static_cast<const Callable*>(
|
||||
const_cast<const void*>(
|
||||
this->base()->data())));
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename>
|
||||
friend class callable_wrapper_iterator;
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,126 @@
|
||||
/* Copyright 2016 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_FUNCTION_MODEL_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_FUNCTION_MODEL_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/core/addressof.hpp>
|
||||
#include <boost/poly_collection/detail/callable_wrapper.hpp>
|
||||
#include <boost/poly_collection/detail/callable_wrapper_iterator.hpp>
|
||||
#include <boost/poly_collection/detail/is_callable.hpp>
|
||||
#include <boost/poly_collection/detail/segment_backend.hpp>
|
||||
#include <boost/poly_collection/detail/split_segment.hpp>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* model for function_collection */
|
||||
|
||||
template<typename Signature>
|
||||
struct function_model;
|
||||
|
||||
/* is_terminal defined out-class to allow for partial specialization */
|
||||
|
||||
template<typename T>
|
||||
struct function_model_is_terminal:std::true_type{};
|
||||
|
||||
template<typename Signature>
|
||||
struct function_model_is_terminal<callable_wrapper<Signature>>:
|
||||
std::false_type{};
|
||||
|
||||
template<typename R,typename... Args>
|
||||
struct function_model<R(Args...)>
|
||||
{
|
||||
using value_type=callable_wrapper<R(Args...)>;
|
||||
|
||||
template<typename Callable>
|
||||
using is_subtype=is_callable<Callable&(Args...),R>;
|
||||
|
||||
template<typename T>
|
||||
using is_terminal=function_model_is_terminal<T>;
|
||||
|
||||
template<typename T>
|
||||
static const std::type_info& subtypeid(const T&){return typeid(T);}
|
||||
|
||||
template<typename Signature>
|
||||
static const std::type_info& subtypeid(
|
||||
const callable_wrapper<Signature>& f)
|
||||
{
|
||||
return f.target_type();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void* subaddress(T& x){return boost::addressof(x);}
|
||||
|
||||
template<typename T>
|
||||
static const void* subaddress(const T& x){return boost::addressof(x);}
|
||||
|
||||
template<typename Signature>
|
||||
static void* subaddress(callable_wrapper<Signature>& f)
|
||||
{
|
||||
return f.data();
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
static const void* subaddress(const callable_wrapper<Signature>& f)
|
||||
{
|
||||
return f.data();
|
||||
}
|
||||
|
||||
using base_iterator=callable_wrapper_iterator<value_type>;
|
||||
using const_base_iterator=callable_wrapper_iterator<const value_type>;
|
||||
using base_sentinel=value_type*;
|
||||
using const_base_sentinel=const value_type*;
|
||||
template<typename Callable>
|
||||
using iterator=Callable*;
|
||||
template<typename Callable>
|
||||
using const_iterator=const Callable*;
|
||||
using segment_backend=detail::segment_backend<function_model>;
|
||||
|
||||
static base_iterator nonconst_iterator(const_base_iterator it)
|
||||
{
|
||||
return base_iterator{
|
||||
const_cast<value_type*>(static_cast<const value_type*>(it))};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static iterator<T> nonconst_iterator(const_iterator<T> it)
|
||||
{
|
||||
return const_cast<iterator<T>>(it);
|
||||
}
|
||||
|
||||
template<typename Callable,typename Allocator>
|
||||
static segment_backend* make(const Allocator& al)
|
||||
{
|
||||
return new split_segment<
|
||||
function_model,
|
||||
Callable,
|
||||
typename std::allocator_traits<Allocator>::
|
||||
template rebind_alloc<Callable>
|
||||
>{al};
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,180 @@
|
||||
/* Copyright 2016 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_FUNCTIONAL_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_FUNCTIONAL_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/poly_collection/detail/integer_sequence.hpp>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
/* Assorted functional utilities. Much of this would be almost trivial with
|
||||
* C++14 generic lambdas.
|
||||
*/
|
||||
|
||||
#define BOOST_POLY_COLLECTION_DEFINE_OVERLOAD_SET(name,f) \
|
||||
struct name \
|
||||
{ \
|
||||
template<typename... Args> \
|
||||
auto operator()(Args&&... args)const-> \
|
||||
decltype(f(std::forward<Args>(args)...)) \
|
||||
{ \
|
||||
return f(std::forward<Args>(args)...); \
|
||||
} \
|
||||
};
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
template<typename F,typename Tuple>
|
||||
struct tail_closure_class
|
||||
{
|
||||
template<typename... Args,std::size_t... I>
|
||||
auto call(index_sequence<I...>,Args&&... args)
|
||||
->decltype(std::declval<F>()(
|
||||
std::forward<Args>(args)...,
|
||||
std::get<I>(std::declval<Tuple>())...))
|
||||
{
|
||||
return f(std::forward<Args>(args)...,std::get<I>(t)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto operator()(Args&&... args)
|
||||
->decltype(this->call(
|
||||
make_index_sequence<std::tuple_size<Tuple>::value>{},
|
||||
std::forward<Args>(args)...))
|
||||
{
|
||||
return call(
|
||||
make_index_sequence<std::tuple_size<Tuple>::value>{},
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
F f;
|
||||
Tuple t;
|
||||
};
|
||||
|
||||
template<typename F,typename... Args>
|
||||
auto tail_closure(const F& f,Args&&... args)
|
||||
->tail_closure_class<F,std::tuple<Args&&...>>
|
||||
{
|
||||
return {f,std::forward_as_tuple(std::forward<Args>(args)...)};
|
||||
}
|
||||
|
||||
template<typename F,typename Tuple>
|
||||
struct head_closure_class
|
||||
{
|
||||
template<typename... Args,std::size_t... I>
|
||||
auto call(index_sequence<I...>,Args&&... args)
|
||||
->decltype(std::declval<F>()(
|
||||
std::get<I>(std::declval<Tuple>())...,std::forward<Args>(args)...))
|
||||
{
|
||||
return f(std::get<I>(t)...,std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto operator()(Args&&... args)
|
||||
->decltype(this->call(
|
||||
make_index_sequence<std::tuple_size<Tuple>::value>{},
|
||||
std::forward<Args>(args)...))
|
||||
{
|
||||
return call(
|
||||
make_index_sequence<std::tuple_size<Tuple>::value>{},
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
F f;
|
||||
Tuple t;
|
||||
};
|
||||
|
||||
template<typename F,typename... Args>
|
||||
auto head_closure(const F& f,Args&&... args)
|
||||
->head_closure_class<F,std::tuple<Args&&...>>
|
||||
{
|
||||
return {f,std::forward_as_tuple(std::forward<Args>(args)...)};
|
||||
}
|
||||
|
||||
template<typename ReturnType,typename F>
|
||||
struct cast_return_class
|
||||
{
|
||||
template<typename... Args>
|
||||
ReturnType operator()(Args&&... args)const
|
||||
{
|
||||
return static_cast<ReturnType>(f(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
F f;
|
||||
};
|
||||
|
||||
template<typename ReturnType,typename F>
|
||||
cast_return_class<ReturnType,F> cast_return(const F& f)
|
||||
{
|
||||
return {f};
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
struct deref_to_class
|
||||
{
|
||||
template<typename... Args>
|
||||
auto operator()(Args&&... args)->decltype(std::declval<F>()(*args...))
|
||||
{
|
||||
return f(*args...);
|
||||
}
|
||||
|
||||
F f;
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
deref_to_class<F> deref_to(const F& f)
|
||||
{
|
||||
return {f};
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
struct deref_1st_to_class
|
||||
{
|
||||
template<typename Arg,typename... Args>
|
||||
auto operator()(Arg&& arg,Args&&... args)
|
||||
->decltype(std::declval<F>()(*arg,std::forward<Args>(args)...))
|
||||
{
|
||||
return f(*arg,std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
F f;
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
deref_1st_to_class<F> deref_1st_to(const F& f)
|
||||
{
|
||||
return {f};
|
||||
}
|
||||
|
||||
struct transparent_equal_to
|
||||
{
|
||||
template<typename T,typename U>
|
||||
auto operator()(T&& x,U&& y)const
|
||||
noexcept(noexcept(std::forward<T>(x)==std::forward<U>(y)))
|
||||
->decltype(std::forward<T>(x)==std::forward<U>(y))
|
||||
{
|
||||
return std::forward<T>(x)==std::forward<U>(y);
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
/* Copyright 2016 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_INTEGER_SEQUENCE_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_INTEGER_SEQUENCE_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* ripped from http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html */
|
||||
|
||||
template<typename T,T... Ints> struct integer_sequence{};
|
||||
|
||||
template<typename S> struct next_integer_sequence;
|
||||
|
||||
template<typename T,T... Ints>
|
||||
struct next_integer_sequence<integer_sequence<T,Ints...>>
|
||||
{
|
||||
using type=integer_sequence<T,Ints...,sizeof...(Ints)>;
|
||||
};
|
||||
|
||||
template<typename T,T I,T N> struct make_int_seq_impl;
|
||||
|
||||
template<typename T,T N>
|
||||
using make_integer_sequence=typename make_int_seq_impl<T,0,N>::type;
|
||||
|
||||
template<typename T,T I,T N> struct make_int_seq_impl
|
||||
{
|
||||
using type=typename next_integer_sequence<
|
||||
typename make_int_seq_impl<T,I+1,N>::type>::type;
|
||||
};
|
||||
|
||||
template<typename T,T N> struct make_int_seq_impl<T,N,N>
|
||||
{
|
||||
using type=integer_sequence<T>;
|
||||
};
|
||||
|
||||
template<std::size_t... Ints>
|
||||
using index_sequence=integer_sequence<std::size_t,Ints...>;
|
||||
|
||||
template<std::size_t N>
|
||||
using make_index_sequence=make_integer_sequence<std::size_t,N>;
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
/* Copyright 2016 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_ACCEPTABLE_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_IS_ACCEPTABLE_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost{
|
||||
|
||||
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).
|
||||
*/
|
||||
|
||||
template<typename T,typename Model,typename=void>
|
||||
struct is_acceptable:std::integral_constant<
|
||||
bool,
|
||||
Model::template is_subtype<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)
|
||||
>{};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
/* Copyright 2016 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_CALLABLE_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_IS_CALLABLE_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
/* technique explained at
|
||||
* http://bannalia.blogspot.com/2016/09/compile-time-checking-existence-of.html
|
||||
*/
|
||||
|
||||
namespace boost{
|
||||
namespace poly_collection{
|
||||
namespace detail{
|
||||
namespace is_callable_fallback{
|
||||
|
||||
template <typename,typename> struct is_callable;
|
||||
template <typename F,typename... Args,typename R>
|
||||
struct is_callable<F(Args...), R>:
|
||||
std::is_constructible<
|
||||
std::function<R(Args...)>,
|
||||
std::reference_wrapper<typename std::remove_reference<F>::type>
|
||||
>
|
||||
{};
|
||||
|
||||
struct hook{};
|
||||
|
||||
}}}}
|
||||
|
||||
namespace std{
|
||||
|
||||
template<>
|
||||
struct is_void<::boost::poly_collection::detail::is_callable_fallback::hook>:
|
||||
std::false_type
|
||||
{
|
||||
template<typename T,typename R>
|
||||
static constexpr bool is_callable_f()
|
||||
{
|
||||
using namespace ::boost::poly_collection::detail::is_callable_fallback;
|
||||
return is_callable<T,R>::value;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace std */
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
template<typename T,typename R=void>
|
||||
struct is_callable:std::integral_constant<
|
||||
bool,
|
||||
std::is_void<is_callable_fallback::hook>::template is_callable_f<T,R>()
|
||||
>{};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,61 @@
|
||||
/* Copyright 2016 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_CONSTRUCIBLE_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_IS_CONSTRUCIBLE_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1900))
|
||||
/* https://connect.microsoft.com/VisualStudio/Feedback/Details/2118677 */
|
||||
|
||||
#include <boost/type_traits/is_constructible.hpp>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
template<typename T,typename U>
|
||||
struct is_constructible:std::integral_constant<
|
||||
bool,
|
||||
boost::is_constructible<T,U>::value
|
||||
>{};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#else
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
template<typename T,typename U>
|
||||
using is_constructible=std::is_constructible<T,U>;
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
/* Copyright 2016 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_FINAL_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_IS_FINAL_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/type_traits/is_final.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
/* technique explained at
|
||||
* http://bannalia.blogspot.com/2016/09/compile-time-checking-existence-of.html
|
||||
*/
|
||||
|
||||
namespace boost{
|
||||
namespace poly_collection{
|
||||
namespace detail{
|
||||
namespace is_final_fallback{
|
||||
|
||||
template<typename T> using is_final=boost::is_final<T>;
|
||||
|
||||
struct hook{};
|
||||
|
||||
}}}}
|
||||
|
||||
namespace std{
|
||||
|
||||
template<>
|
||||
struct is_void<::boost::poly_collection::detail::is_final_fallback::hook>:
|
||||
std::false_type
|
||||
{
|
||||
template<typename T>
|
||||
static constexpr bool is_final_f()
|
||||
{
|
||||
using namespace ::boost::poly_collection::detail::is_final_fallback;
|
||||
return is_final<T>::value;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace std */
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
template<typename T>
|
||||
struct is_final:std::integral_constant<
|
||||
bool,
|
||||
std::is_void<is_final_fallback::hook>::template is_final_f<T>()
|
||||
>{};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
/* Copyright 2016 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_NOTHROW_EQ_COMPARABLE_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_IS_NOTHROW_EQ_COMPARABLE_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/type_traits/has_equal_to.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
template<typename T,typename=void>
|
||||
struct is_nothrow_equality_comparable:std::false_type{};
|
||||
|
||||
template<typename T>
|
||||
struct is_nothrow_equality_comparable<
|
||||
T,
|
||||
typename std::enable_if<
|
||||
boost::has_equal_to<T,T>::value
|
||||
>::type
|
||||
>:std::integral_constant<
|
||||
bool,
|
||||
noexcept(std::declval<T>()==std::declval<T>())
|
||||
>{};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,242 @@
|
||||
/* Copyright 2016 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_ITERATOR_IMPL_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_ITERATOR_IMPL_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/iterator/iterator_adaptor.hpp>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <boost/poly_collection/detail/is_constructible.hpp>
|
||||
#include <boost/poly_collection/detail/iterator_traits.hpp>
|
||||
#include <type_traits>
|
||||
#include <typeindex>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* Implementations of poly_collection::[const_][local_[base_]]iterator moved
|
||||
* out of class to allow for use in deduced contexts.
|
||||
*/
|
||||
|
||||
template<typename PolyCollection,bool Const>
|
||||
using iterator_impl_value_type=typename std::conditional<
|
||||
Const,
|
||||
const typename PolyCollection::value_type,
|
||||
typename PolyCollection::value_type
|
||||
>::type;
|
||||
|
||||
template<typename PolyCollection,bool Const>
|
||||
class iterator_impl:
|
||||
public boost::iterator_facade<
|
||||
iterator_impl<PolyCollection,Const>,
|
||||
iterator_impl_value_type<PolyCollection,Const>,
|
||||
boost::forward_traversal_tag
|
||||
>
|
||||
{
|
||||
using segment_type=typename PolyCollection::segment_type;
|
||||
using const_segment_base_iterator=
|
||||
typename PolyCollection::const_segment_base_iterator;
|
||||
using const_segment_base_sentinel=
|
||||
typename PolyCollection::const_segment_base_sentinel;
|
||||
using const_segment_map_iterator=
|
||||
typename PolyCollection::const_segment_map_iterator;
|
||||
|
||||
public:
|
||||
using value_type=iterator_impl_value_type<PolyCollection,Const>;
|
||||
|
||||
private:
|
||||
iterator_impl(
|
||||
const_segment_map_iterator mapit,
|
||||
const_segment_map_iterator mapend)noexcept:
|
||||
mapit{mapit},mapend{mapend}
|
||||
{
|
||||
next_segment_position();
|
||||
}
|
||||
|
||||
iterator_impl(
|
||||
const_segment_map_iterator mapit_,const_segment_map_iterator mapend_,
|
||||
const_segment_base_iterator segpos_)noexcept:
|
||||
mapit{mapit_},mapend{mapend_},segpos{segpos_}
|
||||
{
|
||||
if(mapit!=mapend&&segpos==sentinel()){
|
||||
++mapit;
|
||||
next_segment_position();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
iterator_impl()=default;
|
||||
iterator_impl(const iterator_impl&)=default;
|
||||
iterator_impl& operator=(const iterator_impl&)=default;
|
||||
|
||||
template<bool Const2,typename std::enable_if<!Const2>::type* =nullptr>
|
||||
iterator_impl(const iterator_impl<PolyCollection,Const2>& x):
|
||||
mapit{x.mapit},mapend{x.mapend},segpos{x.segpos}{}
|
||||
|
||||
private:
|
||||
template<typename,bool>
|
||||
friend class iterator_impl;
|
||||
friend PolyCollection;
|
||||
friend class boost::iterator_core_access;
|
||||
template<typename>
|
||||
friend struct iterator_traits;
|
||||
|
||||
value_type& dereference()const noexcept
|
||||
{return const_cast<value_type&>(*segpos);}
|
||||
bool equal(const iterator_impl& x)const noexcept{return segpos==x.segpos;}
|
||||
|
||||
void increment()noexcept
|
||||
{
|
||||
if(++segpos==sentinel()){
|
||||
++mapit;
|
||||
next_segment_position();
|
||||
}
|
||||
}
|
||||
|
||||
void next_segment_position()noexcept
|
||||
{
|
||||
for(;mapit!=mapend;++mapit){
|
||||
segpos=segment().begin();
|
||||
if(segpos!=sentinel())return;
|
||||
}
|
||||
segpos=nullptr;
|
||||
}
|
||||
|
||||
segment_type& segment()noexcept
|
||||
{return const_cast<segment_type&>(mapit->second);}
|
||||
const segment_type& segment()const noexcept{return mapit->second;}
|
||||
|
||||
const_segment_base_sentinel sentinel()const noexcept
|
||||
{return segment().sentinel();}
|
||||
|
||||
const_segment_map_iterator mapit,mapend;
|
||||
const_segment_base_iterator segpos;
|
||||
};
|
||||
|
||||
template<typename PolyCollection,bool Const>
|
||||
struct poly_collection_of<iterator_impl<PolyCollection,Const>>
|
||||
{
|
||||
using type=PolyCollection;
|
||||
};
|
||||
|
||||
template<typename PolyCollection,typename BaseIterator>
|
||||
class local_iterator_impl:
|
||||
public boost::iterator_adaptor<
|
||||
local_iterator_impl<PolyCollection,BaseIterator>,
|
||||
BaseIterator
|
||||
>
|
||||
{
|
||||
using segment_type=typename PolyCollection::segment_type;
|
||||
using segment_base_iterator=typename PolyCollection::segment_base_iterator;
|
||||
using const_segment_map_iterator=
|
||||
typename PolyCollection::const_segment_map_iterator;
|
||||
|
||||
template<typename Iterator>
|
||||
local_iterator_impl(
|
||||
const_segment_map_iterator mapit,
|
||||
Iterator it):
|
||||
local_iterator_impl::iterator_adaptor_{BaseIterator(it)},
|
||||
mapit{mapit}
|
||||
{}
|
||||
|
||||
public:
|
||||
using base_iterator=BaseIterator;
|
||||
|
||||
local_iterator_impl()=default;
|
||||
local_iterator_impl(const local_iterator_impl&)=default;
|
||||
local_iterator_impl& operator=(const local_iterator_impl&)=default;
|
||||
|
||||
template<
|
||||
typename BaseIterator2,
|
||||
typename std::enable_if<
|
||||
std::is_convertible<BaseIterator2,BaseIterator>::value
|
||||
>::type* =nullptr
|
||||
>
|
||||
local_iterator_impl(
|
||||
const local_iterator_impl<PolyCollection,BaseIterator2>& x):
|
||||
local_iterator_impl::iterator_adaptor_{x.base()},
|
||||
mapit{x.mapit}{}
|
||||
|
||||
template<
|
||||
typename BaseIterator2,
|
||||
typename std::enable_if<
|
||||
!std::is_convertible<BaseIterator2,BaseIterator>::value&&
|
||||
is_constructible<BaseIterator,BaseIterator2>::value
|
||||
>::type* =nullptr
|
||||
>
|
||||
explicit local_iterator_impl(
|
||||
const local_iterator_impl<PolyCollection,BaseIterator2>& x):
|
||||
local_iterator_impl::iterator_adaptor_{BaseIterator(x.base())},
|
||||
mapit{x.mapit}{}
|
||||
|
||||
template<
|
||||
typename BaseIterator2,
|
||||
typename std::enable_if<
|
||||
!is_constructible<BaseIterator,BaseIterator2>::value&&
|
||||
is_constructible<BaseIterator,segment_base_iterator>::value&&
|
||||
is_constructible<BaseIterator2,segment_base_iterator>::value
|
||||
>::type* =nullptr
|
||||
>
|
||||
explicit local_iterator_impl(
|
||||
const local_iterator_impl<PolyCollection,BaseIterator2>& x):
|
||||
local_iterator_impl::iterator_adaptor_{
|
||||
base_iterator_from(x.segment(),x.base())},
|
||||
mapit{x.mapit}{}
|
||||
|
||||
/* define [] to avoid Boost.Iterator operator_brackets_proxy mess */
|
||||
|
||||
template<typename DifferenceType>
|
||||
typename std::iterator_traits<BaseIterator>::reference
|
||||
operator[](DifferenceType n)const{return *(*this+n);}
|
||||
|
||||
private:
|
||||
template<typename,typename>
|
||||
friend class local_iterator_impl;
|
||||
friend PolyCollection;
|
||||
template<typename>
|
||||
friend struct iterator_traits;
|
||||
|
||||
template<typename BaseIterator2>
|
||||
static BaseIterator base_iterator_from(
|
||||
const segment_type& s,BaseIterator2 it)
|
||||
{
|
||||
segment_base_iterator bit=s.begin();
|
||||
return BaseIterator{bit+(it-static_cast<BaseIterator2>(bit))};
|
||||
}
|
||||
|
||||
base_iterator base()const noexcept
|
||||
{return local_iterator_impl::iterator_adaptor_::base();}
|
||||
std::type_index type_index()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;
|
||||
};
|
||||
|
||||
template<typename PolyCollection,typename BaseIterator>
|
||||
struct poly_collection_of<local_iterator_impl<PolyCollection,BaseIterator>>
|
||||
{
|
||||
using type=PolyCollection;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
/* Copyright 2016 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_ITERATOR_TRAITS_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_ITERATOR_TRAITS_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* (Internal) bunch of traits-grouped functions for const-preserving
|
||||
* interoperatibility between iterators and local iterators of a
|
||||
* poly_collection.
|
||||
*/
|
||||
|
||||
template<typename Iterator>
|
||||
struct poly_collection_of /* to be specialized for iterator impls */
|
||||
{
|
||||
using type=void;
|
||||
};
|
||||
|
||||
template<typename Model,typename Allocator>
|
||||
class poly_collection;
|
||||
|
||||
template<typename PolyCollection>
|
||||
struct model_of;
|
||||
|
||||
template<typename Model,typename Allocator>
|
||||
struct model_of<poly_collection<Model,Allocator>>
|
||||
{
|
||||
using type=Model;
|
||||
};
|
||||
|
||||
template<typename Iterator>
|
||||
struct iterator_traits
|
||||
{
|
||||
using container_type=typename poly_collection_of<Iterator>::type;
|
||||
using is_const_iterator=typename std::is_const<
|
||||
typename std::remove_reference<
|
||||
typename std::iterator_traits<Iterator>::reference
|
||||
>::type
|
||||
>::type;
|
||||
using iterator=typename std::conditional<
|
||||
is_const_iterator::value,
|
||||
typename container_type::const_iterator,
|
||||
typename container_type::iterator
|
||||
>::type;
|
||||
using segment_info_iterator=typename std::conditional<
|
||||
is_const_iterator::value,
|
||||
typename container_type::const_segment_info_iterator,
|
||||
typename container_type::segment_info_iterator
|
||||
>::type;
|
||||
using local_base_iterator=typename std::conditional<
|
||||
is_const_iterator::value,
|
||||
typename container_type::const_local_base_iterator,
|
||||
typename container_type::local_base_iterator
|
||||
>::type;
|
||||
template<typename T>
|
||||
using local_iterator=typename std::conditional<
|
||||
is_const_iterator::value,
|
||||
typename container_type::template const_local_iterator<T>,
|
||||
typename container_type::template local_iterator<T>
|
||||
>::type;
|
||||
|
||||
static segment_info_iterator
|
||||
segment_info_iterator_from(iterator it)noexcept{return it.mapit;}
|
||||
|
||||
static segment_info_iterator
|
||||
segment_info_iterator_from(local_base_iterator it)noexcept{return it.mapit;}
|
||||
|
||||
static segment_info_iterator
|
||||
end_segment_info_iterator_from(iterator it)noexcept{return it.mapend;}
|
||||
|
||||
static local_base_iterator
|
||||
local_base_iterator_from(iterator it)noexcept
|
||||
{
|
||||
return {
|
||||
it.mapit,
|
||||
model_of<container_type>::type::nonconst_iterator(it.segpos)
|
||||
};
|
||||
}
|
||||
|
||||
static iterator
|
||||
iterator_from(
|
||||
local_base_iterator lbit,segment_info_iterator mapend)noexcept
|
||||
{
|
||||
return {lbit.mapit,mapend.base(),lbit.base()};
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,260 @@
|
||||
/* Copyright 2016 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_PACKED_SEGMENT_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_PACKED_SEGMENT_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/poly_collection/detail/segment_backend.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* segment_backend implementation where value_type& and Concrete& actually refer
|
||||
* to the same stored entity of type Model::element_type<Concrete>.
|
||||
*
|
||||
* Requires:
|
||||
* - [const_]base_iterator is a stride iterator constructible from
|
||||
* {value_type*,sizeof(element_type<Concrete>)}.
|
||||
* - element_type<Concrete> is copy constructible from a Concrete&, copy
|
||||
* constructible, move assignable, equality comparable and type-erased
|
||||
* emplaceable (see segment_backend.hpp).
|
||||
* - Model provides functions value_ptr for
|
||||
* element_type<Concrete>* -> value_type* conversion and element_ptr for
|
||||
* Concrete* -> element_type<Concrete>* conversion.
|
||||
*/
|
||||
|
||||
template<typename Model,typename Concrete,typename Allocator>
|
||||
class packed_segment:public segment_backend<Model>
|
||||
{
|
||||
using value_type=typename Model::value_type;
|
||||
using store_value_type=typename Model::template element_type<Concrete>;
|
||||
template<typename Concrete2>
|
||||
using const_iterator=typename Model::template const_iterator<Concrete2>;
|
||||
using store=std::vector<
|
||||
store_value_type,
|
||||
typename std::allocator_traits<Allocator>::
|
||||
template rebind_alloc<store_value_type>
|
||||
>;
|
||||
using const_store_iterator=typename store::const_iterator;
|
||||
using segment_backend=detail::segment_backend<Model>;
|
||||
using typename segment_backend::value_pointer;
|
||||
using typename segment_backend::const_value_pointer;
|
||||
using typename segment_backend::base_iterator;
|
||||
using typename segment_backend::const_base_iterator;
|
||||
using typename segment_backend::base_sentinel;
|
||||
using typename segment_backend::position_pointer;
|
||||
using typename segment_backend::range;
|
||||
|
||||
public:
|
||||
virtual ~packed_segment()=default;
|
||||
|
||||
virtual segment_backend* copy()const{return new packed_segment{store{s}};}
|
||||
virtual segment_backend* empty_copy()const
|
||||
{return new packed_segment{s.get_allocator()};}
|
||||
|
||||
virtual bool equal(const segment_backend* p)const
|
||||
{
|
||||
return s==static_cast<const packed_segment*>(p)->s;
|
||||
}
|
||||
|
||||
virtual base_iterator begin()const noexcept
|
||||
{
|
||||
return {value_ptr(s.data()),sizeof(store_value_type)};
|
||||
}
|
||||
|
||||
virtual base_iterator end()const noexcept
|
||||
{
|
||||
return {value_ptr(s.data()+s.size()),sizeof(store_value_type)};
|
||||
}
|
||||
|
||||
virtual bool empty()const noexcept{return s.empty();}
|
||||
virtual std::size_t size()const noexcept{return s.size();}
|
||||
virtual std::size_t max_size()const noexcept{return s.max_size();}
|
||||
virtual std::size_t capacity()const noexcept{return s.capacity();}
|
||||
virtual base_sentinel reserve(std::size_t n){s.reserve(n);return sentinel();}
|
||||
virtual base_sentinel shrink_to_fit(){s.shrink_to_fit();return sentinel();}
|
||||
|
||||
virtual range emplace(
|
||||
const_base_iterator p,void (*emplf)(void*,void*),void* arg)
|
||||
{
|
||||
return range_from(s.emplace(iterator_from(p),emplf,arg));
|
||||
}
|
||||
|
||||
virtual range emplace(
|
||||
position_pointer p,void (*emplf)(void*,void*),void* arg)
|
||||
{
|
||||
return range_from(s.emplace(iterator_from(p),emplf,arg));
|
||||
}
|
||||
|
||||
virtual range emplace_back(void (*emplf)(void*,void*),void* arg)
|
||||
{
|
||||
s.emplace_back(emplf,arg);
|
||||
return range_from(s.size()-1);
|
||||
}
|
||||
|
||||
virtual range push_back(const_value_pointer x)
|
||||
{
|
||||
s.push_back(const_concrete_ref(x));
|
||||
return range_from(s.size()-1);
|
||||
}
|
||||
|
||||
virtual range push_back_move(value_pointer x)
|
||||
{
|
||||
s.push_back(std::move(concrete_ref(x)));
|
||||
return range_from(s.size()-1);
|
||||
}
|
||||
|
||||
virtual range insert(const_base_iterator p,const_value_pointer x)
|
||||
{
|
||||
return range_from(s.insert(iterator_from(p),const_concrete_ref(x)));
|
||||
}
|
||||
|
||||
virtual range insert(position_pointer p,const_value_pointer x)
|
||||
{
|
||||
return range_from(s.insert(iterator_from(p),const_concrete_ref(x)));
|
||||
}
|
||||
|
||||
virtual range insert_move(const_base_iterator p,value_pointer x)
|
||||
{
|
||||
return range_from(s.insert(iterator_from(p),std::move(concrete_ref(x))));
|
||||
}
|
||||
|
||||
virtual range insert_move(position_pointer p,value_pointer x)
|
||||
{
|
||||
return range_from(s.insert(iterator_from(p),std::move(concrete_ref(x))));
|
||||
}
|
||||
|
||||
virtual range erase(const_base_iterator p)
|
||||
{
|
||||
return range_from(s.erase(iterator_from(p)));
|
||||
}
|
||||
|
||||
virtual range erase(position_pointer p)
|
||||
{
|
||||
return range_from(s.erase(iterator_from(p)));
|
||||
}
|
||||
|
||||
virtual range erase(const_base_iterator first,const_base_iterator last)
|
||||
{
|
||||
return range_from(s.erase(iterator_from(first),iterator_from(last)));
|
||||
}
|
||||
|
||||
virtual range erase(position_pointer first,position_pointer last)
|
||||
{
|
||||
return range_from(s.erase(iterator_from(first),iterator_from(last)));
|
||||
}
|
||||
|
||||
virtual range erase_till_end(const_base_iterator first)
|
||||
{
|
||||
return range_from(s.erase(iterator_from(first),s.end()));
|
||||
}
|
||||
|
||||
virtual range erase_till_end(position_pointer first)
|
||||
{
|
||||
return range_from(s.erase(iterator_from(first),s.end()));
|
||||
}
|
||||
|
||||
virtual range erase_from_begin(const_base_iterator last)
|
||||
{
|
||||
return range_from(s.erase(s.begin(),iterator_from(last)));
|
||||
}
|
||||
|
||||
virtual range erase_from_begin(position_pointer last)
|
||||
{
|
||||
return range_from(s.erase(s.begin(),iterator_from(last)));
|
||||
}
|
||||
|
||||
virtual base_sentinel clear()noexcept{s.clear();return sentinel();}
|
||||
|
||||
private:
|
||||
friend Model;
|
||||
|
||||
packed_segment(const Allocator& al):s{al}{}
|
||||
packed_segment(store&& s):s{std::move(s)}{}
|
||||
|
||||
static Concrete& concrete_ref(value_pointer p)noexcept
|
||||
{
|
||||
return *static_cast<Concrete*>(p);
|
||||
}
|
||||
|
||||
static const Concrete& const_concrete_ref(const_value_pointer p)noexcept
|
||||
{
|
||||
return *static_cast<const Concrete*>(p);
|
||||
}
|
||||
|
||||
static const Concrete* const_concrete_ptr(position_pointer p)noexcept
|
||||
{
|
||||
return static_cast<const Concrete*>(p);
|
||||
}
|
||||
|
||||
static value_type* value_ptr(const store_value_type* p)noexcept
|
||||
{
|
||||
return const_cast<value_type*>(Model::value_ptr(p));
|
||||
}
|
||||
|
||||
static const store_value_type* const_store_value_type_ptr(
|
||||
position_pointer p)noexcept
|
||||
{
|
||||
return Model::element_ptr(const_concrete_ptr(p));
|
||||
}
|
||||
|
||||
const_store_iterator iterator_from(const_base_iterator p)const
|
||||
{
|
||||
return iterator_from(
|
||||
static_cast<const Concrete*>(
|
||||
static_cast<const_iterator<Concrete>>(p)));
|
||||
}
|
||||
|
||||
const_store_iterator iterator_from(position_pointer p)const
|
||||
{
|
||||
return s.begin()+(const_store_value_type_ptr(p)-s.data());
|
||||
}
|
||||
|
||||
base_sentinel sentinel()const noexcept
|
||||
{
|
||||
return base_iterator{
|
||||
value_ptr(s.data()+s.size()),
|
||||
sizeof(store_value_type)
|
||||
};
|
||||
}
|
||||
|
||||
range range_from(const_store_iterator it)const
|
||||
{
|
||||
return {
|
||||
{value_ptr(s.data()+(it-s.begin())),sizeof(store_value_type)},
|
||||
sentinel()
|
||||
};
|
||||
}
|
||||
|
||||
range range_from(std::size_t n)const
|
||||
{
|
||||
return {
|
||||
{value_ptr(s.data()+n),sizeof(store_value_type)},
|
||||
sentinel()
|
||||
};
|
||||
}
|
||||
|
||||
store s;
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,169 @@
|
||||
/* Copyright 2016 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_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* segment<Model,Allocator> encapsulates implementations of
|
||||
* Model::segment_backend virtual interface under a value-semantics type for
|
||||
* use by poly_collection. The techique is described by Sean Parent at slides
|
||||
* 157-205 of
|
||||
* https://github.com/sean-parent/sean-parent.github.com/wiki/
|
||||
* presentations/2013-09-11-cpp-seasoning/cpp-seasoning.pdf
|
||||
*/
|
||||
|
||||
template<typename Model,typename Allocator>
|
||||
class segment
|
||||
{
|
||||
public:
|
||||
using value_type=typename Model::value_type;
|
||||
using base_iterator=typename Model::base_iterator;
|
||||
using const_base_iterator=typename Model::const_base_iterator;
|
||||
using base_sentinel=typename Model::base_sentinel;
|
||||
using const_base_sentinel=typename Model::const_base_sentinel;
|
||||
template<typename T>
|
||||
using iterator=typename Model::template iterator<T>;
|
||||
template<typename T>
|
||||
using const_iterator=typename Model::template const_iterator<T>;
|
||||
|
||||
template<typename T>
|
||||
static segment make(const Allocator& al)
|
||||
{
|
||||
return std::unique_ptr<segment_backend>{Model::template make<T>(al)};
|
||||
}
|
||||
|
||||
/* clones the implementation of x with no elements */
|
||||
|
||||
static segment make_from_prototype(const segment& x)
|
||||
{
|
||||
return {from_prototype{},x};
|
||||
}
|
||||
|
||||
segment(const segment& x):pimpl{x.pimpl->copy()}{set_sentinel();}
|
||||
segment(segment&& x)=default;
|
||||
segment& operator=(segment x) // TODO: Why do we need this?
|
||||
{
|
||||
pimpl=std::move(x.pimpl);
|
||||
snt=x.snt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend bool operator==(const segment& x,const segment& y)
|
||||
{
|
||||
if(typeid(*(x.pimpl))!=typeid(*(y.pimpl)))return false;
|
||||
else return x.pimpl->equal(y.pimpl.get());
|
||||
}
|
||||
|
||||
friend bool operator!=(const segment& x,const segment& y){return !(x==y);}
|
||||
|
||||
base_iterator begin()const noexcept{return pimpl->begin();}
|
||||
base_iterator end()const noexcept{return pimpl->end();}
|
||||
base_sentinel sentinel()const noexcept{return snt;}
|
||||
bool empty()const noexcept{return pimpl->empty();}
|
||||
std::size_t size()const noexcept{return pimpl->size();}
|
||||
std::size_t max_size()const noexcept{return pimpl->max_size();}
|
||||
void reserve(std::size_t n){filter(pimpl->reserve(n));}
|
||||
std::size_t capacity()const noexcept{return pimpl->capacity();}
|
||||
void shrink_to_fit(){filter(pimpl->shrink_to_fit());}
|
||||
template<typename Iterator>
|
||||
base_iterator emplace(Iterator it,void (*emplf)(void*,void*),void* arg)
|
||||
{return filter(pimpl->emplace(decay(it),emplf,arg));}
|
||||
base_iterator emplace_back(void (*emplf)(void*,void*),void* arg)
|
||||
{return filter(pimpl->emplace_back(emplf,arg));}
|
||||
template<typename T>
|
||||
base_iterator push_back(const T& x)
|
||||
{return filter(pimpl->push_back(subaddress(x)));}
|
||||
template<
|
||||
typename T,
|
||||
typename std::enable_if<
|
||||
!std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
|
||||
>::type* =nullptr
|
||||
>
|
||||
base_iterator push_back(T&& x)
|
||||
{return filter(pimpl->push_back_move(subaddress(x)));}
|
||||
template<typename Iterator,typename T>
|
||||
base_iterator insert(Iterator it,const T& x)
|
||||
{return filter(pimpl->insert(decay(it),subaddress(x)));}
|
||||
template<
|
||||
typename Iterator,typename T,
|
||||
typename std::enable_if<
|
||||
!std::is_lvalue_reference<T>::value&&!std::is_const<T>::value
|
||||
>::type* =nullptr
|
||||
>
|
||||
base_iterator insert(Iterator it,T&& x)
|
||||
{return filter(
|
||||
pimpl->insert_move(decay(it),subaddress(x)));}
|
||||
template<typename Iterator>
|
||||
base_iterator erase(Iterator it){return filter(pimpl->erase(decay(it)));}
|
||||
template<typename Iterator>
|
||||
base_iterator erase(Iterator f,Iterator l)
|
||||
{return filter(pimpl->erase(decay(f),decay(l)));}
|
||||
template<typename Iterator>
|
||||
base_iterator erase_till_end(Iterator f)
|
||||
{return filter(pimpl->erase_till_end(decay(f)));}
|
||||
template<typename Iterator>
|
||||
base_iterator erase_from_begin(Iterator l)
|
||||
{return filter(pimpl->erase_from_begin(decay(l)));}
|
||||
void clear()noexcept{filter(pimpl->clear());}
|
||||
|
||||
private:
|
||||
using segment_backend=typename Model::segment_backend;
|
||||
using position_pointer=typename segment_backend::position_pointer;
|
||||
using range=typename segment_backend::range;
|
||||
|
||||
struct from_prototype{};
|
||||
|
||||
segment(std::unique_ptr<segment_backend>&& pimpl):
|
||||
pimpl{std::move(pimpl)}{set_sentinel();}
|
||||
segment(from_prototype,const segment& x):
|
||||
pimpl{x.pimpl->empty_copy()}{set_sentinel();}
|
||||
|
||||
template<typename T>
|
||||
static void* subaddress(T& x){return Model::subaddress(x);}
|
||||
template<typename T>
|
||||
static const void* subaddress(const T& x)
|
||||
{return Model::subaddress(x);}
|
||||
|
||||
static const_base_iterator decay(base_iterator it){return it;}
|
||||
static const_base_iterator decay(const_base_iterator it){return it;}
|
||||
template<typename T>
|
||||
static position_pointer decay(iterator<T> it)
|
||||
{return static_cast<T*>(it);}
|
||||
template<typename T>
|
||||
static position_pointer decay(const_iterator<T> it)
|
||||
{return static_cast<const T*>(it);}
|
||||
|
||||
void set_sentinel(){filter(pimpl->end());}
|
||||
void filter(base_sentinel x){snt=x;}
|
||||
base_iterator filter(const range& x){snt=x.second;return x.first;}
|
||||
|
||||
std::unique_ptr<segment_backend> pimpl;
|
||||
base_sentinel snt;
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,96 @@
|
||||
/* Copyright 2016 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_BACKEND_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_BACKEND_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* Internal virtual interface of segment<Model,Allocator>. Member functions
|
||||
* have been defined to minimize virtual function calls according to usage
|
||||
* patterns by poly_collection. For instance, ranges are returned rather than
|
||||
* iterators to allow for caching of and end sentinel at a higher level.
|
||||
* Information associated to concrete types handled by the segment, such as
|
||||
* inserted elements and local_iterator's, are type-erased. Similarly, emplace
|
||||
* is implemented through type-independent callback functions with signature
|
||||
*
|
||||
* void emplace(void* p,void* arg)
|
||||
*
|
||||
* where p is the address of the object to be constructed and arg is a
|
||||
* type-erased pointer to the constructor arguments.
|
||||
*/
|
||||
|
||||
template<typename Model>
|
||||
struct segment_backend
|
||||
{
|
||||
using value_pointer=void*;
|
||||
using const_value_pointer=const void*;
|
||||
using base_iterator=typename Model::base_iterator;
|
||||
using const_base_iterator=typename Model::const_base_iterator;
|
||||
using base_sentinel=typename Model::base_sentinel;
|
||||
using const_base_sentinel=typename Model::const_base_sentinel;
|
||||
using position_pointer=const void*;
|
||||
using range=std::pair<base_iterator,base_sentinel>;
|
||||
|
||||
segment_backend()=default;
|
||||
segment_backend(const segment_backend&)=delete;
|
||||
segment_backend& operator=(const segment_backend&)=delete;
|
||||
|
||||
virtual ~segment_backend()=default;
|
||||
virtual segment_backend* copy()const=0;
|
||||
virtual segment_backend* empty_copy()const=0;
|
||||
virtual bool equal(const segment_backend*)const=0;
|
||||
|
||||
virtual base_iterator begin()const noexcept=0;
|
||||
virtual base_iterator end()const noexcept=0;
|
||||
virtual bool empty()const noexcept=0;
|
||||
virtual std::size_t size()const noexcept=0;
|
||||
virtual std::size_t max_size()const noexcept=0;
|
||||
virtual std::size_t capacity()const noexcept=0;
|
||||
virtual base_sentinel reserve(std::size_t)=0;
|
||||
virtual base_sentinel shrink_to_fit()=0;
|
||||
virtual range emplace(
|
||||
const_base_iterator,void (*)(void*,void*),void*)=0;
|
||||
virtual range emplace(
|
||||
position_pointer,void (*)(void*,void*),void*)=0;
|
||||
virtual range emplace_back(void (*)(void*,void*),void*)=0;
|
||||
virtual range push_back(const_value_pointer)=0;
|
||||
virtual range push_back_move(value_pointer)=0;
|
||||
virtual range insert(const_base_iterator,const_value_pointer)=0;
|
||||
virtual range insert(position_pointer,const_value_pointer)=0;
|
||||
virtual range insert_move(const_base_iterator,value_pointer)=0;
|
||||
virtual range insert_move(position_pointer,value_pointer)=0;
|
||||
virtual range erase(const_base_iterator)=0;
|
||||
virtual range erase(position_pointer)=0;
|
||||
virtual range erase(const_base_iterator,const_base_iterator)=0;
|
||||
virtual range erase(position_pointer,position_pointer)=0;
|
||||
virtual range erase_till_end(const_base_iterator)=0;
|
||||
virtual range erase_till_end(position_pointer)=0;
|
||||
virtual range erase_from_begin(const_base_iterator)=0;
|
||||
virtual range erase_from_begin(position_pointer)=0;
|
||||
virtual base_sentinel clear()noexcept=0;
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,152 @@
|
||||
/* Copyright 2016 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_SPLIT_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_SEGMENT_SPLIT_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <boost/poly_collection/detail/iterator_traits.hpp>
|
||||
#include <typeindex>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* breakdown of an iterator range into local_base_iterator segments */
|
||||
|
||||
template<typename PolyCollectionIterator>
|
||||
class segment_splitter
|
||||
{
|
||||
using traits=iterator_traits<PolyCollectionIterator>;
|
||||
using local_base_iterator=typename traits::local_base_iterator;
|
||||
using segment_info_iterator=typename traits::segment_info_iterator;
|
||||
|
||||
public:
|
||||
struct info
|
||||
{
|
||||
std::type_index type_index()const noexcept{return index_;}
|
||||
local_base_iterator begin()const noexcept{return begin_;}
|
||||
local_base_iterator end()const noexcept{return end_;}
|
||||
|
||||
std::type_index index_;
|
||||
local_base_iterator begin_,end_;
|
||||
};
|
||||
|
||||
struct iterator:iterator_facade<iterator,info,std::input_iterator_tag,info>
|
||||
{
|
||||
iterator()=default;
|
||||
|
||||
private:
|
||||
friend class segment_splitter;
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
iterator(
|
||||
segment_info_iterator it,
|
||||
const PolyCollectionIterator& first,const PolyCollectionIterator& last):
|
||||
it{it},first{&first},last{&last}{}
|
||||
iterator(
|
||||
const PolyCollectionIterator& first,const PolyCollectionIterator& last):
|
||||
it{traits::segment_info_iterator_from(first)},first{&first},last{&last}{}
|
||||
|
||||
info dereference()const noexcept
|
||||
{
|
||||
return {
|
||||
it->type_index(),
|
||||
it==traits::segment_info_iterator_from(*first)?
|
||||
traits::local_base_iterator_from(*first):it->begin(),
|
||||
it==traits::segment_info_iterator_from(*last)?
|
||||
traits::local_base_iterator_from(*last):it->end()
|
||||
};
|
||||
}
|
||||
|
||||
bool equal(const iterator& x)const noexcept{return it==x.it;}
|
||||
void increment()noexcept{++it;}
|
||||
|
||||
segment_info_iterator it;
|
||||
const PolyCollectionIterator* first;
|
||||
const PolyCollectionIterator* last;
|
||||
};
|
||||
|
||||
segment_splitter(
|
||||
const PolyCollectionIterator& first,const PolyCollectionIterator& last):
|
||||
first{first},last{last}{}
|
||||
|
||||
iterator begin()const noexcept{return {first,last};}
|
||||
|
||||
iterator end()const noexcept
|
||||
{
|
||||
auto slast=traits::segment_info_iterator_from(last);
|
||||
if(slast!=traits::end_segment_info_iterator_from(last))++slast;
|
||||
return {slast,last,last};
|
||||
}
|
||||
|
||||
private:
|
||||
const PolyCollectionIterator& first;
|
||||
const PolyCollectionIterator& last;
|
||||
};
|
||||
|
||||
template<typename PolyCollectionIterator>
|
||||
segment_splitter<PolyCollectionIterator>
|
||||
segment_split(
|
||||
const PolyCollectionIterator& first,const PolyCollectionIterator& last)
|
||||
{
|
||||
return {first,last};
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* equivalent to for(auto i:segment_split(first,last))f(i) */
|
||||
|
||||
template<typename PolyCollectionIterator,typename F>
|
||||
void for_each_segment(
|
||||
const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
|
||||
{
|
||||
using traits=iterator_traits<PolyCollectionIterator>;
|
||||
using info=typename segment_splitter<PolyCollectionIterator>::info;
|
||||
|
||||
auto sfirst=traits::segment_info_iterator_from(first),
|
||||
slast=traits::segment_info_iterator_from(last),
|
||||
send=traits::end_segment_info_iterator_from(last);
|
||||
auto lbfirst=traits::local_base_iterator_from(first),
|
||||
lblast=traits::local_base_iterator_from(last);
|
||||
|
||||
if(sfirst!=slast){
|
||||
for(;;){
|
||||
f(info{sfirst->type_index(),lbfirst,sfirst->end()});
|
||||
++sfirst;
|
||||
if(sfirst==slast)break;
|
||||
lbfirst=sfirst->begin();
|
||||
}
|
||||
if(sfirst!=send)f(info{sfirst->type_index(),sfirst->begin(),lblast});
|
||||
}
|
||||
else if(sfirst!=send){
|
||||
f(info{sfirst->type_index(),lbfirst,lblast});
|
||||
}
|
||||
}
|
||||
#else
|
||||
template<typename PolyCollectionIterator,typename F>
|
||||
void for_each_segment(
|
||||
const PolyCollectionIterator& first,const PolyCollectionIterator& last,F&& f)
|
||||
{
|
||||
for(auto i:segment_split(first,last))f(i);
|
||||
}
|
||||
#endif
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,394 @@
|
||||
/* Copyright 2016 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_SPLIT_SEGMENT_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_SPLIT_SEGMENT_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/poly_collection/detail/segment_backend.hpp>
|
||||
#include <boost/poly_collection/detail/value_holder.hpp>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* segment_backend implementation that maintains two internal vectors, one for
|
||||
* value_type's (the index) and another for the concrete elements those refer
|
||||
* to (the store).
|
||||
*
|
||||
* Requires:
|
||||
* - [const_]base_iterator is constructible from value_type*.
|
||||
* - value_type is constructible from a reference to the concrete type and
|
||||
* copy constructible.
|
||||
*
|
||||
* Conversion from base_iterator to local_iterator<Concrete> requires accesing
|
||||
* value_type internal info, so the end() base_iterator has to be made to point
|
||||
* to a valid element of index, which implies size(index)=size(store)+1. This
|
||||
* slightly complicates the memory management.
|
||||
*/
|
||||
|
||||
template<typename Model,typename Concrete,typename Allocator>
|
||||
class split_segment:public segment_backend<Model>
|
||||
{
|
||||
using value_type=typename Model::value_type;
|
||||
using store=std::vector<
|
||||
value_holder<Concrete>,
|
||||
typename std::allocator_traits<Allocator>::
|
||||
template rebind_alloc<value_holder<Concrete>>
|
||||
>;
|
||||
using store_value_type=typename store::value_type;
|
||||
using const_store_iterator=typename store::const_iterator;
|
||||
using index=std::vector<
|
||||
value_type,
|
||||
typename std::allocator_traits<Allocator>::
|
||||
template rebind_alloc<value_type>
|
||||
>;
|
||||
using const_index_iterator=typename index::const_iterator;
|
||||
using segment_backend=detail::segment_backend<Model>;
|
||||
using typename segment_backend::value_pointer;
|
||||
using typename segment_backend::const_value_pointer;
|
||||
using typename segment_backend::base_iterator;
|
||||
using typename segment_backend::const_base_iterator;
|
||||
using typename segment_backend::base_sentinel;
|
||||
using typename segment_backend::position_pointer;
|
||||
using typename segment_backend::range;
|
||||
|
||||
public:
|
||||
virtual ~split_segment()=default;
|
||||
|
||||
virtual segment_backend* copy()const{return new split_segment{store{s}};}
|
||||
virtual segment_backend* empty_copy()const
|
||||
{return new split_segment{s.get_allocator()};}
|
||||
|
||||
virtual bool equal(const segment_backend* p)const
|
||||
{
|
||||
return s==static_cast<const split_segment*>(p)->s;
|
||||
}
|
||||
|
||||
virtual base_iterator begin()const noexcept
|
||||
{return base_iterator{value_ptr(i.data())};}
|
||||
virtual base_iterator end()const noexcept
|
||||
{return base_iterator{value_ptr(i.data()+s.size())};}
|
||||
virtual bool empty()const noexcept{return s.empty();}
|
||||
virtual std::size_t size()const noexcept{return s.size();}
|
||||
virtual std::size_t max_size()const noexcept{return s.max_size()-1;}
|
||||
virtual std::size_t capacity()const noexcept{return s.capacity();}
|
||||
|
||||
virtual base_sentinel reserve(std::size_t n)
|
||||
{
|
||||
bool rebuild=n>s.capacity();
|
||||
i.reserve(n+1);
|
||||
s.reserve(n);
|
||||
if(rebuild)rebuild_index();
|
||||
return sentinel();
|
||||
};
|
||||
|
||||
virtual base_sentinel shrink_to_fit()
|
||||
{
|
||||
auto p=s.data();
|
||||
s.shrink_to_fit();
|
||||
if(p!=s.data())try{
|
||||
index ii{{},i.get_allocator()};
|
||||
ii.reserve(s.capacity()+1);
|
||||
i=std::move(ii);
|
||||
build_index();
|
||||
}
|
||||
catch(...){
|
||||
rebuild_index();
|
||||
throw;
|
||||
}
|
||||
return sentinel();
|
||||
}
|
||||
|
||||
virtual range emplace(
|
||||
const_base_iterator p,void (*emplf)(void*,void*),void* arg)
|
||||
{
|
||||
p=prereserve(p);
|
||||
auto it=s.emplace(iterator_from(p),emplf,arg);
|
||||
push_index_entry();
|
||||
return range_from(it);
|
||||
}
|
||||
|
||||
virtual range emplace(
|
||||
position_pointer p,void (*emplf)(void*,void*),void* arg)
|
||||
{
|
||||
p=prereserve(p);
|
||||
auto it=s.emplace(iterator_from(p),emplf,arg);
|
||||
push_index_entry();
|
||||
return range_from(it);
|
||||
}
|
||||
|
||||
virtual range emplace_back(void (*emplf)(void*,void*),void* arg)
|
||||
{
|
||||
prereserve();
|
||||
s.emplace_back(emplf,arg);
|
||||
push_index_entry();
|
||||
return range_from(s.size()-1);
|
||||
}
|
||||
|
||||
virtual range push_back(const_value_pointer x)
|
||||
{
|
||||
prereserve();
|
||||
s.push_back(const_concrete_ref(x));
|
||||
push_index_entry();
|
||||
return range_from(s.size()-1);
|
||||
}
|
||||
|
||||
virtual range push_back_move(value_pointer x)
|
||||
{
|
||||
prereserve();
|
||||
s.push_back(std::move(concrete_ref(x)));
|
||||
push_index_entry();
|
||||
return range_from(s.size()-1);
|
||||
}
|
||||
|
||||
virtual range insert(const_base_iterator p,const_value_pointer x)
|
||||
{
|
||||
p=prereserve(p);
|
||||
auto it=s.insert(iterator_from(p),const_concrete_ref(x));
|
||||
push_index_entry();
|
||||
return range_from(it);
|
||||
}
|
||||
|
||||
virtual range insert(position_pointer p,const_value_pointer x)
|
||||
{
|
||||
p=prereserve(p);
|
||||
auto it=s.insert(iterator_from(p),const_concrete_ref(x));
|
||||
push_index_entry();
|
||||
return range_from(it);
|
||||
}
|
||||
|
||||
virtual range insert_move(const_base_iterator p,value_pointer x)
|
||||
{
|
||||
p=prereserve(p);
|
||||
auto it=s.insert(iterator_from(p),std::move(concrete_ref(x)));
|
||||
push_index_entry();
|
||||
return range_from(it);
|
||||
}
|
||||
|
||||
virtual range insert_move(position_pointer p,value_pointer x)
|
||||
{
|
||||
p=prereserve(p);
|
||||
auto it=s.insert(iterator_from(p),std::move(concrete_ref(x)));
|
||||
push_index_entry();
|
||||
return range_from(it);
|
||||
}
|
||||
|
||||
virtual range erase(const_base_iterator p)
|
||||
{
|
||||
pop_index_entry();
|
||||
return range_from(s.erase(iterator_from(p)));
|
||||
}
|
||||
|
||||
virtual range erase(position_pointer p)
|
||||
{
|
||||
pop_index_entry();
|
||||
return range_from(s.erase(iterator_from(p)));
|
||||
}
|
||||
|
||||
virtual range erase(const_base_iterator first,const_base_iterator last)
|
||||
{
|
||||
std::size_t n=s.size();
|
||||
auto it=s.erase(iterator_from(first),iterator_from(last));
|
||||
pop_index_entry(n-s.size());
|
||||
return range_from(it);
|
||||
}
|
||||
|
||||
virtual range erase(position_pointer first,position_pointer last)
|
||||
{
|
||||
std::size_t n=s.size();
|
||||
auto it=s.erase(iterator_from(first),iterator_from(last));
|
||||
pop_index_entry(n-s.size());
|
||||
return range_from(it);
|
||||
}
|
||||
|
||||
virtual range erase_till_end(const_base_iterator first)
|
||||
{
|
||||
std::size_t n=s.size();
|
||||
auto it=s.erase(iterator_from(first),s.end());
|
||||
pop_index_entry(n-s.size());
|
||||
return range_from(it);
|
||||
}
|
||||
|
||||
virtual range erase_till_end(position_pointer first)
|
||||
{
|
||||
std::size_t n=s.size();
|
||||
auto it=s.erase(iterator_from(first),s.end());
|
||||
pop_index_entry(n-s.size());
|
||||
return range_from(it);
|
||||
}
|
||||
|
||||
virtual range erase_from_begin(const_base_iterator last)
|
||||
{
|
||||
std::size_t n=s.size();
|
||||
auto it=s.erase(s.begin(),iterator_from(last));
|
||||
pop_index_entry(n-s.size());
|
||||
return range_from(it);
|
||||
}
|
||||
|
||||
virtual range erase_from_begin(position_pointer last)
|
||||
{
|
||||
std::size_t n=s.size();
|
||||
auto it=s.erase(s.begin(),iterator_from(last));
|
||||
pop_index_entry(n-s.size());
|
||||
return range_from(it);
|
||||
}
|
||||
|
||||
virtual base_sentinel clear()noexcept
|
||||
{
|
||||
s.clear();
|
||||
for(std::size_t n=i.size()-1;n--;)i.pop_back();
|
||||
return sentinel();
|
||||
}
|
||||
|
||||
private:
|
||||
friend Model;
|
||||
|
||||
split_segment(const Allocator& al):s{al},i{{},al}{build_index();}
|
||||
split_segment(store&& s_):
|
||||
s{std::move(s_)},i{{},s.get_allocator()}{build_index();}
|
||||
|
||||
void prereserve()
|
||||
{
|
||||
if(s.size()==s.capacity())expand();
|
||||
}
|
||||
|
||||
const_base_iterator prereserve(const_base_iterator p)
|
||||
{
|
||||
if(s.size()==s.capacity()){
|
||||
auto n=p-i.data();
|
||||
expand();
|
||||
return const_base_iterator{i.data()+n};
|
||||
}
|
||||
else return p;
|
||||
}
|
||||
|
||||
position_pointer prereserve(position_pointer p)
|
||||
{
|
||||
if(s.size()==s.capacity()){
|
||||
auto n=const_concrete_ptr(p)-const_concrete_ptr(s.data());
|
||||
expand();
|
||||
return const_concrete_ptr(s.data())+n;
|
||||
}
|
||||
else return p;
|
||||
}
|
||||
|
||||
void expand()
|
||||
{
|
||||
std::size_t c=
|
||||
s.size()<=1||(s.max_size()-1-s.size())/2<s.size()?
|
||||
s.size()+1:
|
||||
s.size()+s.size()/2;
|
||||
i.reserve(c+1);
|
||||
s.reserve(c);
|
||||
rebuild_index();
|
||||
}
|
||||
|
||||
void build_index(std::size_t start=0)
|
||||
{
|
||||
for(std::size_t n=start,m=s.size();n<=m;++n){
|
||||
i.push_back(value_type{concrete_ref(s.data()[n])});
|
||||
};
|
||||
}
|
||||
|
||||
void rebuild_index()
|
||||
{
|
||||
i.clear();
|
||||
build_index();
|
||||
}
|
||||
|
||||
void push_index_entry()
|
||||
{
|
||||
build_index(s.size());
|
||||
}
|
||||
|
||||
void pop_index_entry(std::size_t n=1)
|
||||
{
|
||||
while(n--)i.pop_back();
|
||||
}
|
||||
|
||||
static Concrete& concrete_ref(value_pointer p)noexcept
|
||||
{
|
||||
return *static_cast<Concrete*>(p);
|
||||
}
|
||||
|
||||
static Concrete& concrete_ref(store_value_type& r)noexcept
|
||||
{
|
||||
return *concrete_ptr(&r);
|
||||
}
|
||||
|
||||
static const Concrete& const_concrete_ref(const_value_pointer p)noexcept
|
||||
{
|
||||
return *static_cast<const Concrete*>(p);
|
||||
}
|
||||
|
||||
static Concrete* concrete_ptr(store_value_type* p)noexcept
|
||||
{
|
||||
return reinterpret_cast<Concrete*>(
|
||||
static_cast<value_holder_base<Concrete>*>(p));
|
||||
}
|
||||
|
||||
static const Concrete* const_concrete_ptr(position_pointer p)noexcept
|
||||
{
|
||||
return static_cast<const Concrete*>(p);
|
||||
}
|
||||
|
||||
static const Concrete* const_concrete_ptr(const store_value_type* p)noexcept
|
||||
{
|
||||
return concrete_ptr(const_cast<store_value_type*>(p));
|
||||
}
|
||||
|
||||
static value_type* value_ptr(const value_type* p)noexcept
|
||||
{
|
||||
return const_cast<value_type*>(p);
|
||||
}
|
||||
|
||||
const_store_iterator iterator_from(const_base_iterator p)const
|
||||
{
|
||||
return s.begin()+(p-i.data());
|
||||
}
|
||||
|
||||
const_store_iterator iterator_from(position_pointer p)const
|
||||
{
|
||||
return s.begin()+(const_concrete_ptr(p)-const_concrete_ptr(s.data()));
|
||||
}
|
||||
|
||||
base_sentinel sentinel()const noexcept
|
||||
{
|
||||
return base_iterator{value_ptr(i.data()+s.size())};
|
||||
}
|
||||
|
||||
range range_from(const_store_iterator it)const
|
||||
{
|
||||
return {base_iterator{value_ptr(i.data()+(it-s.begin()))},sentinel()};
|
||||
}
|
||||
|
||||
range range_from(std::size_t n)const
|
||||
{
|
||||
return {base_iterator{value_ptr(i.data()+n)},sentinel()};
|
||||
}
|
||||
|
||||
store s;
|
||||
index i;
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,123 @@
|
||||
/* Copyright 2016 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_STRIDE_ITERATOR_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_STRIDE_ITERATOR_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* random-access iterator to Value elements laid out stride *chars* apart */
|
||||
|
||||
template<typename Value>
|
||||
class stride_iterator:
|
||||
public boost::iterator_facade<
|
||||
stride_iterator<Value>,
|
||||
Value,
|
||||
boost::random_access_traversal_tag
|
||||
>
|
||||
{
|
||||
public:
|
||||
stride_iterator()=default;
|
||||
stride_iterator(Value* p,std::size_t stride)noexcept:p{p},stride_{stride}{}
|
||||
stride_iterator(const stride_iterator&)=default;
|
||||
stride_iterator& operator=(const stride_iterator&)=default;
|
||||
|
||||
template<
|
||||
typename NonConstValue,
|
||||
typename std::enable_if<
|
||||
std::is_same<Value,const NonConstValue>::value>::type* =nullptr
|
||||
>
|
||||
stride_iterator(const stride_iterator<NonConstValue>& x)noexcept:
|
||||
p{x.p},stride_{x.stride_}{}
|
||||
|
||||
template<
|
||||
typename NonConstValue,
|
||||
typename std::enable_if<
|
||||
std::is_same<Value,const NonConstValue>::value>::type* =nullptr
|
||||
>
|
||||
stride_iterator& operator=(const stride_iterator<NonConstValue>& x)noexcept
|
||||
{
|
||||
p=x.p;stride_=x.stride_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* interoperability with [Derived]Value* */
|
||||
|
||||
stride_iterator& operator=(Value* p)noexcept{this->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)}{}
|
||||
|
||||
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 operator DerivedValue*()const noexcept
|
||||
{return static_cast<DerivedValue*>(p);}
|
||||
|
||||
std::size_t stride()const noexcept{return stride_;}
|
||||
|
||||
private:
|
||||
template<typename>
|
||||
friend class stride_iterator;
|
||||
|
||||
using char_pointer=typename std::conditional<
|
||||
std::is_const<Value>::value,
|
||||
const char*,
|
||||
char*
|
||||
>::type;
|
||||
|
||||
static char_pointer char_ptr(Value* p)noexcept
|
||||
{return reinterpret_cast<char_pointer>(p);}
|
||||
static Value* value_ptr(char_pointer p)noexcept
|
||||
{return reinterpret_cast<Value*>(p);}
|
||||
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
Value& dereference()const noexcept{return *p;}
|
||||
bool equal(const stride_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*stride_);}
|
||||
std::ptrdiff_t distance_to(const stride_iterator& x)const noexcept
|
||||
{return (char_ptr(x.p)-char_ptr(p))/stride_;}
|
||||
|
||||
Value* p;
|
||||
std::size_t stride_;
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,199 @@
|
||||
/* Copyright 2016 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_TYPE_RESTITUTION_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_TYPE_RESTITUTION_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/poly_collection/detail/functional.hpp>
|
||||
#include <boost/poly_collection/detail/iterator_traits.hpp>
|
||||
#include <typeindex>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* Given types Ts..., a std::type_index index and a local_base_iterator it,
|
||||
* we denote by restitute<Ts...>(index,it):
|
||||
* - a local_iterator<Ti> from it, if index==typeid(Ti) for some Ti in Ts...
|
||||
* - it otherwise.
|
||||
*
|
||||
* Using this notation, restitute_range<Ts...>(f,args...)(s) resolves to
|
||||
* f(restitute<Ts...>(index,begin),restitute<Ts...>(index,end),args...) where
|
||||
* index=s.type_index(), begin=s.begin(), end=s.end().
|
||||
*/
|
||||
|
||||
template<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...>
|
||||
{
|
||||
using super=restitute_range_class<F,Ts...>;
|
||||
using super::super;
|
||||
|
||||
template<typename SegmentInfo>
|
||||
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_index()==typeid(T))
|
||||
return (this->f)(
|
||||
local_iterator{s.begin()},local_iterator{s.end()});
|
||||
else
|
||||
return super::operator()(std::forward<SegmentInfo>(s));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
struct restitute_range_class<F>
|
||||
{
|
||||
restitute_range_class(const F& f):f{f}{}
|
||||
|
||||
template<typename SegmentInfo>
|
||||
auto operator()(SegmentInfo&& s)
|
||||
->decltype(std::declval<F>()(s.begin(),s.end()))
|
||||
{
|
||||
return f(s.begin(),s.end());
|
||||
}
|
||||
|
||||
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...
|
||||
>
|
||||
{
|
||||
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...).
|
||||
*/
|
||||
|
||||
template<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...>
|
||||
{
|
||||
using super=restitute_iterator_class<F,Ts...>;
|
||||
using super::super;
|
||||
|
||||
template<typename Iterator,typename... Args>
|
||||
auto operator()(
|
||||
const std::type_index& index,Iterator&& it,Args&&... args)
|
||||
->decltype(
|
||||
std::declval<F>()
|
||||
(std::forward<Iterator>(it),std::forward<Args>(args)...))
|
||||
{
|
||||
using traits=iterator_traits<typename std::decay<Iterator>::type>;
|
||||
using local_iterator=typename traits::template local_iterator<T>;
|
||||
|
||||
if(index==typeid(T))
|
||||
return (this->f)(
|
||||
local_iterator{it},std::forward<Args>(args)...);
|
||||
else
|
||||
return super::operator()(
|
||||
index,std::forward<Iterator>(it),std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
struct restitute_iterator_class<F>
|
||||
{
|
||||
restitute_iterator_class(const F& f):f{f}{}
|
||||
|
||||
template<typename Iterator,typename... Args>
|
||||
auto operator()(
|
||||
const std::type_index&,Iterator&& it,Args&&... args)
|
||||
->decltype(
|
||||
std::declval<F>()
|
||||
(std::forward<Iterator>(it),std::forward<Args>(args)...))
|
||||
{
|
||||
return f(std::forward<Iterator>(it),std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
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_index& index1,Iterator1&& it1,
|
||||
const std::type_index& index2,Iterator2&& it2)
|
||||
->decltype(
|
||||
std::declval<F>()
|
||||
(std::forward<Iterator1>(it1),std::forward<Iterator2>(it2)))
|
||||
{
|
||||
return restitute_iterator<Ts...>(*this)(
|
||||
index2,std::forward<Iterator2>(it2),index1,std::forward<Iterator1>(it1));
|
||||
}
|
||||
|
||||
template<typename Iterator2,typename Iterator1>
|
||||
auto operator()(
|
||||
Iterator2&& it2,const std::type_index& index1,Iterator1&& it1)
|
||||
->decltype(
|
||||
std::declval<F>()
|
||||
(std::forward<Iterator1>(it1),std::forward<Iterator2>(it2)))
|
||||
{
|
||||
return restitute_iterator<Ts...>(f)(
|
||||
index1,std::forward<Iterator1>(it1),std::forward<Iterator2>(it2));
|
||||
}
|
||||
|
||||
F f;
|
||||
};
|
||||
|
||||
template<typename... Ts,typename F,typename... Args>
|
||||
auto binary_restitute_iterator(const F& f,Args&&... args)
|
||||
->binary_restitute_iterator_class<
|
||||
decltype(tail_closure(f,std::forward<Args>(args)...)),
|
||||
Ts...
|
||||
>
|
||||
{
|
||||
return tail_closure(f,std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,161 @@
|
||||
/* Copyright 2016 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_VALUE_HOLDER_HPP
|
||||
#define BOOST_POLY_COLLECTION_DETAIL_VALUE_HOLDER_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/core/addressof.hpp>
|
||||
#include <boost/type_traits/has_equal_to.hpp>
|
||||
#include <boost/poly_collection/detail/is_nothrow_eq_comparable.hpp>
|
||||
#include <boost/poly_collection/exception.hpp>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* Segments of a poly_collection maintain vectors of value_holder<T>
|
||||
* rather than directly T. This serves several purposes:
|
||||
* - value_holder<T> is copy constructible and equality comparable even if T
|
||||
* is not: executing the corresponding op results in a reporting exception
|
||||
* being thrown. This allows the segment to offer its full virtual
|
||||
* interface regardless of the properties of the concrete class contained.
|
||||
* - value_holder<T> emulates move assignment when T is not move assignable
|
||||
* (nothrow move constructibility required); this happens most notably with
|
||||
* lambda functions, whose assignment operator is deleted by standard
|
||||
* mandate [expr.prim.lambda]/20 even if the compiler generated one would
|
||||
* work (capture by value).
|
||||
* - value_holder<T> supports the type-erased emplace mechanism required
|
||||
* by segment_backend.
|
||||
*
|
||||
* A pointer to value_holder_base<T> can be reinterpret_cast'ed to T*.
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
class value_holder_base
|
||||
{
|
||||
protected:
|
||||
typename std::aligned_storage<sizeof(T),alignof(T)>::type s;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class value_holder:public value_holder_base<T>
|
||||
{
|
||||
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=std::integral_constant<
|
||||
bool,
|
||||
boost::has_equal_to<T,T>::value
|
||||
>;
|
||||
using is_nothrow_equality_comparable=
|
||||
detail::is_nothrow_equality_comparable<T>;
|
||||
|
||||
void* data()noexcept{return reinterpret_cast<void*>(&this->s);}
|
||||
const void* data()const noexcept
|
||||
{return reinterpret_cast<const void*>(&this->s);}
|
||||
|
||||
T& value()noexcept{return *static_cast<T*>(data());}
|
||||
const T& value()const noexcept{return *static_cast<const T*>(data());}
|
||||
|
||||
public:
|
||||
value_holder(const T& x)
|
||||
noexcept(is_nothrow_copy_constructible::value)
|
||||
{copy(x);}
|
||||
value_holder(T&& x)
|
||||
noexcept(is_nothrow_move_constructible::value)
|
||||
{::new (data()) T(std::move(x));}
|
||||
value_holder(void (* emplace)(void*,void*),void* arg)
|
||||
{emplace(data(),arg);}
|
||||
value_holder(const value_holder& x)
|
||||
noexcept(is_nothrow_copy_constructible::value)
|
||||
{copy(x.value());}
|
||||
value_holder(value_holder&& x)
|
||||
noexcept(is_nothrow_move_constructible::value)
|
||||
{::new (data()) T(std::move(x.value()));}
|
||||
|
||||
value_holder& operator=(const value_holder& x)=delete;
|
||||
value_holder& operator=(value_holder&& x)
|
||||
noexcept(is_nothrow_move_assignable::value||!is_move_assignable::value)
|
||||
/* if 2nd clause: nothrow move constructibility required */
|
||||
{
|
||||
move_assign(std::move(x.value()));
|
||||
return *this;
|
||||
}
|
||||
|
||||
~value_holder()noexcept{value().~T();}
|
||||
|
||||
friend bool operator==(const value_holder& x,const value_holder& y)
|
||||
noexcept(is_nothrow_equality_comparable::value)
|
||||
{
|
||||
return x.equal(y.value());
|
||||
}
|
||||
|
||||
private:
|
||||
void copy(const T& x){copy(x,is_copy_constructible{});}
|
||||
|
||||
void copy(const T& x,std::true_type)
|
||||
{
|
||||
::new (data()) T(x);
|
||||
}
|
||||
|
||||
void copy(const T&,std::false_type)
|
||||
{
|
||||
throw not_copy_constructible{typeid(T)};
|
||||
}
|
||||
|
||||
void move_assign(T&& x){move_assign(std::move(x),is_move_assignable{});}
|
||||
|
||||
void move_assign(T&& x,std::true_type)
|
||||
{
|
||||
value()=std::move(x);
|
||||
}
|
||||
|
||||
void move_assign(T&& x,std::false_type)
|
||||
{
|
||||
/* emulated assignment */
|
||||
|
||||
static_assert(is_nothrow_move_constructible::value,
|
||||
"type should be move assignable or nothrow move constructible");
|
||||
|
||||
if(data()!=boost::addressof(x)){
|
||||
value().~T();
|
||||
::new (data()) T(std::move(x));
|
||||
}
|
||||
}
|
||||
|
||||
bool equal(const T& x)const{return equal(x,is_equality_comparable{});}
|
||||
|
||||
bool equal(const T& x,std::true_type)const
|
||||
{
|
||||
return value()==x;
|
||||
}
|
||||
|
||||
bool equal(const T&,std::false_type)const
|
||||
{
|
||||
throw not_equality_comparable{typeid(T)};
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace poly_collection::detail */
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
/* Copyright 2016 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_EXCEPTION_HPP
|
||||
#define BOOST_POLY_COLLECTION_EXCEPTION_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <stdexcept>
|
||||
#include <typeindex>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
struct unregistered_type:std::logic_error
|
||||
{
|
||||
unregistered_type(const std::type_index& info):
|
||||
std::logic_error{"type not registered"},
|
||||
info{info}
|
||||
{}
|
||||
|
||||
std::type_index info;
|
||||
};
|
||||
|
||||
struct not_copy_constructible:std::logic_error
|
||||
{
|
||||
not_copy_constructible(const std::type_index& info):
|
||||
std::logic_error{"type is not copy constructible"},
|
||||
info{info}
|
||||
{}
|
||||
|
||||
std::type_index info;
|
||||
};
|
||||
|
||||
struct not_equality_comparable:std::logic_error
|
||||
{
|
||||
not_equality_comparable(const std::type_index& info):
|
||||
std::logic_error{"type does not support equality comparison"},
|
||||
info{info}
|
||||
{}
|
||||
|
||||
std::type_index info;
|
||||
};
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
/* Copyright 2016 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/function_collection for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_POLY_COLLECTION_FUNCTION_COLLECTION_HPP
|
||||
#define BOOST_POLY_COLLECTION_FUNCTION_COLLECTION_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/poly_collection/function_collection_fwd.hpp>
|
||||
#include <boost/poly_collection/detail/function_model.hpp>
|
||||
#include <boost/poly_collection/detail/poly_collection.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
template<typename Signature,typename Allocator>
|
||||
class function_collection:
|
||||
public detail::poly_collection<detail::function_model<Signature>,Allocator>
|
||||
{
|
||||
using base_type=
|
||||
detail::poly_collection<detail::function_model<Signature>,Allocator>;
|
||||
|
||||
base_type& base()noexcept{return *this;}
|
||||
const base_type& base()const noexcept{return *this;}
|
||||
|
||||
public:
|
||||
using base_type::base_type;
|
||||
|
||||
function_collection()=default;
|
||||
function_collection(const function_collection& x)=default;
|
||||
function_collection(function_collection&& x)=default;
|
||||
function_collection& operator=(const function_collection& x)=default;
|
||||
function_collection& operator=(function_collection&& x)=default;
|
||||
|
||||
friend bool operator==(
|
||||
const function_collection<Signature,Allocator>& x,
|
||||
const function_collection<Signature,Allocator>& y)
|
||||
{
|
||||
return x.base()==y.base();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature,typename Allocator>
|
||||
bool operator!=(
|
||||
const function_collection<Signature,Allocator>& x,
|
||||
const function_collection<Signature,Allocator>& y)
|
||||
{
|
||||
return !(x==y);
|
||||
}
|
||||
|
||||
template<typename Signature,typename Allocator>
|
||||
void swap(
|
||||
function_collection<Signature,Allocator>& x,
|
||||
function_collection<Signature,Allocator>& y)
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
using poly_collection::function_collection;
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
/* Copyright 2016 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/function_collection for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_POLY_COLLECTION_FUNCTION_COLLECTION_FWD_HPP
|
||||
#define BOOST_POLY_COLLECTION_FUNCTION_COLLECTION_FWD_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace poly_collection{
|
||||
|
||||
namespace detail{
|
||||
template<typename Signature> struct function_model;
|
||||
}
|
||||
|
||||
template<typename Signature>
|
||||
using function_collection_value_type=
|
||||
typename detail::function_model<Signature>::value_type;
|
||||
|
||||
template<
|
||||
typename Signature,
|
||||
typename Allocator=std::allocator<function_collection_value_type<Signature>>
|
||||
>
|
||||
class function_collection;
|
||||
|
||||
template<typename Signature,typename Allocator>
|
||||
bool operator==(
|
||||
const function_collection<Signature,Allocator>& x,
|
||||
const function_collection<Signature,Allocator>& y);
|
||||
|
||||
template<typename Signature,typename Allocator>
|
||||
bool operator!=(
|
||||
const function_collection<Signature,Allocator>& x,
|
||||
const function_collection<Signature,Allocator>& y);
|
||||
|
||||
template<typename Signature,typename Allocator>
|
||||
void swap(
|
||||
function_collection<Signature,Allocator>& x,
|
||||
function_collection<Signature,Allocator>& y);
|
||||
|
||||
} /* namespace poly_collection */
|
||||
|
||||
using poly_collection::function_collection;
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0.1 Transitional//EN">
|
||||
<!--
|
||||
Copyright 2016 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)
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<meta http-equiv="refresh" content="0; URL=doc/html/index.html">
|
||||
<title>Boost.PolyCollection Documentation</title>
|
||||
<link rel="stylesheet" href="doc/style.css" type="text/css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Automatic redirection failed, please go to
|
||||
<a href="doc/html/index.html">doc/html/index.html</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"key": "poly_collection",
|
||||
"name": "PolyCollection",
|
||||
"authors": [
|
||||
"Joaqu\u00edn M L\u00f3pez Mu\u00f1oz"
|
||||
],
|
||||
"description": "Fast containers of polymorphic objects.",
|
||||
"category": [
|
||||
"Containers"
|
||||
],
|
||||
"maintainers": [
|
||||
"Joaquin M Lopez Munoz <joaquin.lopezmunoz -at- gmail.com>"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
# Copyright 2016 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)
|
||||
#
|
||||
# See http://www.boost.org/libs/poly_collection for library home page.
|
||||
|
||||
test-suite "poly_collection" :
|
||||
[ run test_algorithm.cpp test_algorithm1.cpp
|
||||
test_algorithm2.cpp test_algorithm3.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_insertion.cpp test_insertion_main.cpp ]
|
||||
[ run test_iterators.cpp test_iterators_main.cpp ]
|
||||
[ run test_registration.cpp test_registration_main.cpp ]
|
||||
;
|
||||
@@ -0,0 +1,75 @@
|
||||
/* Copyright 2016 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_TEST_ANY_TYPES_HPP
|
||||
#define BOOST_POLY_COLLECTION_TEST_ANY_TYPES_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/poly_collection/any_collection.hpp>
|
||||
#include <boost/type_erasure/any_cast.hpp>
|
||||
#include <boost/type_erasure/operators.hpp>
|
||||
|
||||
namespace any_types{
|
||||
|
||||
struct incrementable1
|
||||
{
|
||||
incrementable1(int n):n{n}{}
|
||||
incrementable1(incrementable1&&)=default;
|
||||
incrementable1(const incrementable1&)=delete;
|
||||
incrementable1& operator=(incrementable1&&)=default;
|
||||
incrementable1& operator=(const incrementable1&)=delete;
|
||||
bool operator==(const incrementable1& x)const{return n==x.n;}
|
||||
incrementable1& operator++(){++n;return *this;}
|
||||
int n;
|
||||
};
|
||||
|
||||
struct incrementable3
|
||||
{
|
||||
incrementable3():n{-1}{}
|
||||
incrementable3(int n):n{(double)n}{}
|
||||
incrementable3& operator++(){++n;return *this;}
|
||||
double n;
|
||||
};
|
||||
|
||||
using concept=boost::type_erasure::incrementable<>;
|
||||
using collection=boost::any_collection<concept>;
|
||||
|
||||
using t1=incrementable1;
|
||||
using t2=double;
|
||||
using t3=incrementable3;
|
||||
using t4=int;
|
||||
using t5=char;
|
||||
|
||||
struct to_int
|
||||
{
|
||||
template<typename Concept,typename Tag>
|
||||
int operator()(const boost::type_erasure::any<Concept,Tag>& x)const
|
||||
{
|
||||
using boost::type_erasure::any_cast;
|
||||
|
||||
if(auto p=any_cast<t1*>(&x))return (*this)(*p);
|
||||
if(auto p=any_cast<t2*>(&x))return (*this)(*p);
|
||||
if(auto p=any_cast<t3*>(&x))return (*this)(*p);
|
||||
if(auto p=any_cast<t4*>(&x))return (*this)(*p);
|
||||
if(auto p=any_cast<t5*>(&x))return (*this)(*p);
|
||||
else return 0;
|
||||
}
|
||||
|
||||
int operator()(const t1& x)const{return x.n;}
|
||||
int operator()(const t2& x)const{return static_cast<int>(x);};
|
||||
int operator()(const t3& x)const{return static_cast<int>(x.n);}
|
||||
int operator()(const t4& x)const{return x;}
|
||||
int operator()(const t5& x)const{return static_cast<int>(x);};
|
||||
};
|
||||
|
||||
} /* namespace any_types*/
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,86 @@
|
||||
/* Copyright 2016 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_TEST_BASE_TYPES_HPP
|
||||
#define BOOST_POLY_COLLECTION_TEST_BASE_TYPES_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/poly_collection/base_collection.hpp>
|
||||
|
||||
namespace base_types{
|
||||
|
||||
struct base
|
||||
{
|
||||
virtual ~base()=default;
|
||||
virtual int operator()(int)const=0;
|
||||
};
|
||||
|
||||
struct derived1 final:base
|
||||
{
|
||||
derived1(int n):n{n}{}
|
||||
derived1(derived1&&)=default;
|
||||
derived1(const derived1&)=delete;
|
||||
derived1& operator=(derived1&&)=default;
|
||||
derived1& operator=(const derived1&)=delete;
|
||||
virtual int operator()(int)const{return n;}
|
||||
bool operator==(const derived1& x)const{return n==x.n;}
|
||||
int n;
|
||||
};
|
||||
|
||||
struct derived2:base
|
||||
{
|
||||
derived2(int n):n{n}{}
|
||||
derived2(derived2&&)=default;
|
||||
derived2& operator=(derived2&&)=delete;
|
||||
virtual int operator()(int x)const{return x*n;}
|
||||
bool operator==(const derived2& x)const{return n==x.n;}
|
||||
int n;
|
||||
};
|
||||
|
||||
struct derived3:base
|
||||
{
|
||||
derived3():n{-1}{}
|
||||
derived3(int n):n{n}{}
|
||||
virtual int operator()(int x)const{return x*x*n;}
|
||||
int n;
|
||||
};
|
||||
|
||||
struct derived4:derived3
|
||||
{
|
||||
using derived3::derived3;
|
||||
virtual int operator()(int x)const{return -(this->derived3::operator()(x));}
|
||||
bool operator==(const derived4& x)const{return n==x.n;}
|
||||
};
|
||||
|
||||
struct derived5:base
|
||||
{
|
||||
derived5(int n):n{n}{}
|
||||
virtual int operator()(int x)const{return x*x*x*n;}
|
||||
int n;
|
||||
};
|
||||
|
||||
using collection=boost::base_collection<base>;
|
||||
|
||||
using t1=derived1;
|
||||
using t2=derived2;
|
||||
using t3=derived3;
|
||||
using t4=derived4;
|
||||
using t5=derived5;
|
||||
|
||||
struct to_int
|
||||
{
|
||||
template<typename F>
|
||||
int operator()(const F& f)const{return f(1);}
|
||||
};
|
||||
|
||||
} /* namespace base_types*/
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,143 @@
|
||||
/* Copyright 2016 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_TEST_FUNCTION_TYPES_HPP
|
||||
#define BOOST_POLY_COLLECTION_TEST_FUNCTION_TYPES_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/poly_collection/function_collection.hpp>
|
||||
#include <typeindex>
|
||||
|
||||
namespace function_types{
|
||||
|
||||
struct function1 final
|
||||
{
|
||||
function1(int n):n{n}{}
|
||||
function1(function1&&)=default;
|
||||
function1(const function1&)=delete;
|
||||
function1& operator=(function1&&)=default;
|
||||
function1& operator=(const function1&)=delete;
|
||||
int operator()(int)const{return n;}
|
||||
friend bool operator==(
|
||||
const function1& x,const function1& y){return x.n==y.n;}
|
||||
int n;
|
||||
};
|
||||
|
||||
struct function2
|
||||
{
|
||||
function2(int n):n{n}{}
|
||||
int operator()(int x)const{return x*n;}
|
||||
bool operator==(const function2& x)const{return n==x.n;}
|
||||
int n;
|
||||
};
|
||||
|
||||
struct function3
|
||||
{
|
||||
function3():n{-1}{}
|
||||
function3(int n):n{n}{}
|
||||
int operator()(int x)const{return x*x*n;}
|
||||
int n;
|
||||
};
|
||||
|
||||
struct function4:function3
|
||||
{
|
||||
using function3::function3;
|
||||
int operator()(int x)const{return -(this->function3::operator()(x));}
|
||||
bool operator==(const function4& x)const{return n==x.n;}
|
||||
};
|
||||
|
||||
struct function5
|
||||
{
|
||||
function5(int n):n{n}{}
|
||||
int operator()(int x)const{return x*x*x*n;}
|
||||
int n;
|
||||
};
|
||||
|
||||
struct int_alias /* brings this namespace into ADL for operator== below */
|
||||
{
|
||||
int_alias(int n):n{n}{}
|
||||
operator int()const{return n;}
|
||||
int n;
|
||||
};
|
||||
|
||||
using signature=int_alias(int);
|
||||
using collection=boost::function_collection<signature>;
|
||||
|
||||
using t1=function1;
|
||||
using t2=function2;
|
||||
using t3=function3;
|
||||
using t4=function4;
|
||||
using t5=function5;
|
||||
|
||||
inline bool operator==(
|
||||
const collection::value_type& x,const collection::value_type& y)
|
||||
{
|
||||
std::type_index xt=x.target_type(),yt=y.target_type();
|
||||
if(xt==yt){
|
||||
if(xt==typeid(t1))return (*x.target<t1>())==(*y.target<t1>());
|
||||
if(xt==typeid(t2))return (*x.target<t2>()).operator==(*y.target<t2>());
|
||||
if(xt==typeid(t4))return (*x.target<t4>()).operator==(*y.target<t4>());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool operator==(const collection::value_type& x,const t1& y)
|
||||
{
|
||||
std::type_index xt=x.target_type();
|
||||
if(xt==typeid(t1))return (*x.target<t1>())==y;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool operator==(const t1& x,const collection::value_type& y)
|
||||
{
|
||||
return y==x;
|
||||
}
|
||||
|
||||
inline bool operator==(const collection::value_type& x,const t2& y)
|
||||
{
|
||||
std::type_index xt=x.target_type();
|
||||
if(xt==typeid(t2))return (*x.target<t2>())==y;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool operator==(const t2& x,const collection::value_type& y)
|
||||
{
|
||||
return y==x;
|
||||
}
|
||||
|
||||
inline bool operator==(const collection::value_type& x,const t4& y)
|
||||
{
|
||||
std::type_index xt=x.target_type();
|
||||
if(xt==typeid(t4))return (*x.target<t4>())==y;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool operator==(const t4& x,const collection::value_type& y)
|
||||
{
|
||||
return y==x;
|
||||
}
|
||||
|
||||
inline bool operator==(const t1&,const t2&){return false;}
|
||||
inline bool operator==(const t1&,const t4&){return false;}
|
||||
inline bool operator==(const t2&,const t1&){return false;}
|
||||
inline bool operator==(const t2&,const t4&){return false;}
|
||||
inline bool operator==(const t4&,const t1&){return false;}
|
||||
inline bool operator==(const t4&,const t2&){return false;}
|
||||
|
||||
struct to_int
|
||||
{
|
||||
template<typename F>
|
||||
int operator()(const F& f)const{return f(1);}
|
||||
};
|
||||
|
||||
} /* namespace function_types*/
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
/* Copyright 2016 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_algorithm.hpp"
|
||||
#include "test_algorithm1.hpp"
|
||||
#include "test_algorithm2.hpp"
|
||||
#include "test_algorithm3.hpp"
|
||||
|
||||
/* test split in chunks to avoid problems with compilation object sizes */
|
||||
|
||||
void test_algorithm()
|
||||
{
|
||||
test_algorithm1();
|
||||
test_algorithm2();
|
||||
test_algorithm3();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/* Copyright 2016 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_algorithm();
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Copyright 2016 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_algorithm1.hpp"
|
||||
|
||||
#include "any_types.hpp"
|
||||
#include "test_algorithm_impl.hpp"
|
||||
|
||||
void test_algorithm1()
|
||||
{
|
||||
test_algorithm<
|
||||
any_types::collection,jammed_auto_increment,any_types::to_int,
|
||||
any_types::t1,any_types::t2,any_types::t3,
|
||||
any_types::t4,any_types::t5>();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/* Copyright 2016 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_algorithm1();
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Copyright 2016 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_algorithm2.hpp"
|
||||
|
||||
#include "base_types.hpp"
|
||||
#include "test_algorithm_impl.hpp"
|
||||
|
||||
void test_algorithm2()
|
||||
{
|
||||
test_algorithm<
|
||||
base_types::collection,jammed_auto_increment,base_types::to_int,
|
||||
base_types::t1,base_types::t2,base_types::t3,
|
||||
base_types::t4,base_types::t5>();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/* Copyright 2016 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_algorithm2();
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Copyright 2016 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_algorithm3.hpp"
|
||||
|
||||
#include "function_types.hpp"
|
||||
#include "test_algorithm_impl.hpp"
|
||||
|
||||
void test_algorithm3()
|
||||
{
|
||||
test_algorithm<
|
||||
function_types::collection,jammed_auto_increment,function_types::to_int,
|
||||
function_types::t1,function_types::t2,function_types::t3,
|
||||
function_types::t4,function_types::t5>();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/* Copyright 2016 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_algorithm3();
|
||||
@@ -0,0 +1,928 @@
|
||||
/* Copyright 2016 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_TEST_TEST_ALGORITHM_IMPL_HPP
|
||||
#define BOOST_POLY_COLLECTION_TEST_TEST_ALGORITHM_IMPL_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/function_output_iterator.hpp>
|
||||
#include <boost/poly_collection/algorithm.hpp>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <random>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "test_utilities.hpp"
|
||||
|
||||
using namespace test_utilities;
|
||||
|
||||
#define DEFINE_ALGORITHM(name,f) \
|
||||
template<typename... Ts> \
|
||||
struct name \
|
||||
{ \
|
||||
template<typename... Args> \
|
||||
auto operator()(Args&&... args)const-> \
|
||||
decltype(f<Ts...>(std::forward<Args>(args)...)) \
|
||||
{ \
|
||||
return f<Ts...>(std::forward<Args>(args)...); \
|
||||
} \
|
||||
};
|
||||
|
||||
DEFINE_ALGORITHM(std_all_of,std::all_of)
|
||||
DEFINE_ALGORITHM(poly_all_of,boost::poly_collection::all_of)
|
||||
DEFINE_ALGORITHM(std_any_of,std::any_of)
|
||||
DEFINE_ALGORITHM(poly_any_of,boost::poly_collection::any_of)
|
||||
DEFINE_ALGORITHM(std_none_of,std::none_of)
|
||||
DEFINE_ALGORITHM(poly_none_of,boost::poly_collection::none_of)
|
||||
DEFINE_ALGORITHM(std_for_each,std::for_each)
|
||||
DEFINE_ALGORITHM(poly_for_each,boost::poly_collection::for_each)
|
||||
DEFINE_ALGORITHM(std_find,std::find)
|
||||
DEFINE_ALGORITHM(poly_find,boost::poly_collection::find)
|
||||
DEFINE_ALGORITHM(std_find_if,std::find_if)
|
||||
DEFINE_ALGORITHM(poly_find_if,boost::poly_collection::find_if)
|
||||
DEFINE_ALGORITHM(std_find_if_not,std::find_if_not)
|
||||
DEFINE_ALGORITHM(poly_find_if_not,boost::poly_collection::find_if_not)
|
||||
DEFINE_ALGORITHM(std_find_end,std::find_end)
|
||||
DEFINE_ALGORITHM(poly_find_end,boost::poly_collection::find_end)
|
||||
DEFINE_ALGORITHM(std_find_first_of,std::find_first_of)
|
||||
DEFINE_ALGORITHM(poly_find_first_of,boost::poly_collection::find_first_of)
|
||||
DEFINE_ALGORITHM(std_adjacent_find,std::adjacent_find)
|
||||
DEFINE_ALGORITHM(poly_adjacent_find,boost::poly_collection::adjacent_find)
|
||||
DEFINE_ALGORITHM(std_count,std::count)
|
||||
DEFINE_ALGORITHM(poly_count,boost::poly_collection::count)
|
||||
DEFINE_ALGORITHM(std_count_if,std::count_if)
|
||||
DEFINE_ALGORITHM(poly_count_if,boost::poly_collection::count_if)
|
||||
DEFINE_ALGORITHM(std_cpp11_mismatch,std::mismatch) /* note std_cpp11 prefix */
|
||||
DEFINE_ALGORITHM(poly_mismatch,boost::poly_collection::mismatch)
|
||||
DEFINE_ALGORITHM(std_cpp11_equal,std::equal) /* note std_cpp11 prefix */
|
||||
DEFINE_ALGORITHM(poly_equal,boost::poly_collection::equal)
|
||||
DEFINE_ALGORITHM(std_cpp11_is_permutation,std::is_permutation) /* std_cpp11 */
|
||||
DEFINE_ALGORITHM(poly_is_permutation,boost::poly_collection::is_permutation)
|
||||
DEFINE_ALGORITHM(std_search,std::search)
|
||||
DEFINE_ALGORITHM(poly_search,boost::poly_collection::search)
|
||||
DEFINE_ALGORITHM(std_search_n,std::search_n)
|
||||
DEFINE_ALGORITHM(poly_search_n,boost::poly_collection::search_n)
|
||||
DEFINE_ALGORITHM(std_copy,std::copy)
|
||||
DEFINE_ALGORITHM(poly_copy,boost::poly_collection::copy)
|
||||
DEFINE_ALGORITHM(std_copy_n,std::copy_n)
|
||||
DEFINE_ALGORITHM(poly_copy_n,boost::poly_collection::copy_n)
|
||||
DEFINE_ALGORITHM(std_copy_if,std::copy_if)
|
||||
DEFINE_ALGORITHM(poly_copy_if,boost::poly_collection::copy_if)
|
||||
DEFINE_ALGORITHM(std_move,std::move)
|
||||
DEFINE_ALGORITHM(poly_move,boost::poly_collection::move)
|
||||
DEFINE_ALGORITHM(std_transform,std::transform)
|
||||
DEFINE_ALGORITHM(poly_transform,boost::poly_collection::transform)
|
||||
DEFINE_ALGORITHM(std_replace_copy,std::replace_copy)
|
||||
DEFINE_ALGORITHM(poly_replace_copy,boost::poly_collection::replace_copy)
|
||||
DEFINE_ALGORITHM(std_replace_copy_if,std::replace_copy_if)
|
||||
DEFINE_ALGORITHM(poly_replace_copy_if,boost::poly_collection::replace_copy_if)
|
||||
DEFINE_ALGORITHM(std_remove_copy,std::remove_copy)
|
||||
DEFINE_ALGORITHM(poly_remove_copy,boost::poly_collection::remove_copy)
|
||||
DEFINE_ALGORITHM(std_remove_copy_if,std::remove_copy_if)
|
||||
DEFINE_ALGORITHM(poly_remove_copy_if,boost::poly_collection::remove_copy_if)
|
||||
DEFINE_ALGORITHM(std_unique_copy,std::unique_copy)
|
||||
DEFINE_ALGORITHM(poly_unique_copy,boost::poly_collection::unique_copy)
|
||||
DEFINE_ALGORITHM(std_rotate_copy,std::rotate_copy)
|
||||
DEFINE_ALGORITHM(poly_rotate_copy,boost::poly_collection::rotate_copy)
|
||||
DEFINE_ALGORITHM(std_is_partitioned,std::is_partitioned)
|
||||
DEFINE_ALGORITHM(poly_is_partitioned,boost::poly_collection::is_partitioned)
|
||||
DEFINE_ALGORITHM(std_partition_copy,std::partition_copy)
|
||||
DEFINE_ALGORITHM(poly_partition_copy,boost::poly_collection::partition_copy)
|
||||
DEFINE_ALGORITHM(std_partition_point,std::partition_point)
|
||||
DEFINE_ALGORITHM(poly_partition_point,boost::poly_collection::partition_point)
|
||||
|
||||
template<typename... Ts>
|
||||
struct std_mismatch:std_cpp11_mismatch<Ts...>
|
||||
{
|
||||
using std_cpp11_mismatch<Ts...>::operator();
|
||||
|
||||
/* C++14 variants */
|
||||
|
||||
template<typename InputIterator1,typename InputIterator2>
|
||||
std::pair<InputIterator1,InputIterator2> operator()(
|
||||
InputIterator1 first1,InputIterator1 last1,
|
||||
InputIterator2 first2,InputIterator2 last2)const
|
||||
{
|
||||
while(first1!=last1&&first2!=last2&&*first1==*first2){
|
||||
++first1;
|
||||
++first2;
|
||||
}
|
||||
return {first1,first2};
|
||||
}
|
||||
|
||||
template<typename InputIterator1,typename InputIterator2,typename Predicate>
|
||||
std::pair<InputIterator1,InputIterator2> operator()(
|
||||
InputIterator1 first1,InputIterator1 last1,
|
||||
InputIterator2 first2,InputIterator2 last2,Predicate pred)const
|
||||
{
|
||||
while(first1!=last1&&first2!=last2&&pred(*first1,*first2)){
|
||||
++first1;
|
||||
++first2;
|
||||
}
|
||||
return {first1,first2};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Ts>
|
||||
struct std_equal:std_cpp11_equal<Ts...>
|
||||
{
|
||||
using std_cpp11_equal<Ts...>::operator();
|
||||
|
||||
/* C++14 variants */
|
||||
|
||||
template<typename InputIterator1,typename InputIterator2>
|
||||
bool operator()(
|
||||
InputIterator1 first1,InputIterator1 last1,
|
||||
InputIterator2 first2,InputIterator2 last2)const
|
||||
{
|
||||
for(;first1!=last1&&first2!=last2;++first1,++first2){
|
||||
if(!(*first1==*first2))return false;
|
||||
}
|
||||
return first1==last1&&first2==last2;
|
||||
}
|
||||
|
||||
template<typename InputIterator1,typename InputIterator2,typename Predicate>
|
||||
bool operator()(
|
||||
InputIterator1 first1,InputIterator1 last1,
|
||||
InputIterator2 first2,InputIterator2 last2,Predicate pred)const
|
||||
{
|
||||
for(;first1!=last1&&first2!=last2;++first1,++first2){
|
||||
if(!pred(*first1,*first2))return false;
|
||||
}
|
||||
return first1==last1&&first2==last2;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Ts>
|
||||
struct std_is_permutation:std_cpp11_is_permutation<Ts...>
|
||||
{
|
||||
using std_cpp11_is_permutation<Ts...>::operator();
|
||||
|
||||
/* C++14 variants */
|
||||
|
||||
template<typename ForwardIterator1,typename ForwardIterator2>
|
||||
bool operator()(
|
||||
ForwardIterator1 first1,ForwardIterator1 last1,
|
||||
ForwardIterator2 first2,ForwardIterator2 last2)const
|
||||
{
|
||||
if(std::distance(first1,last1)!=std::distance(first2,last2))return false;
|
||||
return std::is_permutation(first1,last1,first2);
|
||||
}
|
||||
|
||||
template<
|
||||
typename ForwardIterator1,typename ForwardIterator2,typename Predicate
|
||||
>
|
||||
bool operator()(
|
||||
ForwardIterator1 first1,ForwardIterator1 last1,
|
||||
ForwardIterator2 first2,ForwardIterator2 last2,Predicate pred)const
|
||||
{
|
||||
if(std::distance(first1,last1)!=std::distance(first2,last2))return false;
|
||||
return std::is_permutation(first1,last1,first2,pred);
|
||||
}
|
||||
};
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename Algorithm,
|
||||
typename PolyCollection,typename... Args
|
||||
>
|
||||
void test_algorithm(PolyCollection& p,Args&&... args)
|
||||
{
|
||||
Algorithm alg;
|
||||
ControlAlgorithm control;
|
||||
for(auto first=p.begin(),end=p.end();;++first){
|
||||
for(auto last=first;last!=end;++last){
|
||||
BOOST_TEST(
|
||||
alg(first,last,std::forward<Args>(args)...)==
|
||||
control(first,last,std::forward<Args>(args)...));
|
||||
}
|
||||
if(first==end)break;
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename... Algorithms,
|
||||
typename PolyCollection,typename... Args
|
||||
>
|
||||
void test_algorithms(PolyCollection& p,Args&&... args)
|
||||
{
|
||||
do_((test_algorithm<ControlAlgorithm,Algorithms>(
|
||||
p,std::forward<Args>(args)...),0)...);
|
||||
do_((test_algorithm<ControlAlgorithm,Algorithms>(
|
||||
const_cast<const PolyCollection&>(p),std::forward<Args>(args)...),0)...);
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename... Algorithms,
|
||||
typename PolyCollection,typename... Args
|
||||
>
|
||||
void test_algorithms_with_equality_impl(
|
||||
std::true_type,PolyCollection& p,Args&&... args)
|
||||
{
|
||||
test_algorithms<ControlAlgorithm,Algorithms...>(
|
||||
p,std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename... Algorithm,
|
||||
typename PolyCollection,typename... Args
|
||||
>
|
||||
void test_algorithms_with_equality_impl(
|
||||
std::false_type,PolyCollection&,Args&&...)
|
||||
{
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename... Algorithms,
|
||||
typename PolyCollection,typename... Args
|
||||
>
|
||||
void test_algorithms_with_equality(PolyCollection& p,Args&&... args)
|
||||
{
|
||||
test_algorithms_with_equality_impl<ControlAlgorithm,Algorithms...>(
|
||||
is_equality_comparable<typename PolyCollection::value_type>{},
|
||||
p,std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename Algorithm,
|
||||
typename ToInt,typename PolyCollection,typename... Args
|
||||
>
|
||||
void test_copy_algorithm(ToInt to_int,PolyCollection& p,Args&&... args)
|
||||
{
|
||||
Algorithm alg;
|
||||
ControlAlgorithm control;
|
||||
for(auto first=p.begin(),end=p.end();;++first){
|
||||
for(auto last=first;last!=end;++last){
|
||||
using vector=std::vector<int>;
|
||||
|
||||
vector v1,v2;
|
||||
auto insert1=compose(to_int,[&](int x){v1.push_back(x);});
|
||||
auto insert2=compose(to_int,[&](int x){v2.push_back(x);});
|
||||
auto out1=boost::make_function_output_iterator(std::ref(insert1));
|
||||
auto out2=boost::make_function_output_iterator(std::ref(insert2));
|
||||
|
||||
out1=alg(first,last,out1,std::forward<Args>(args)...);
|
||||
out2=control(first,last,out2,std::forward<Args>(args)...);
|
||||
BOOST_TEST(v1==v2);
|
||||
}
|
||||
if(first==end)break;
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename... Algorithms,
|
||||
typename ToInt,typename PolyCollection,typename... Args
|
||||
>
|
||||
void test_copy_algorithms(ToInt to_int,PolyCollection& p,Args&&... args)
|
||||
{
|
||||
do_((test_copy_algorithm<ControlAlgorithm,Algorithms>(
|
||||
to_int,p,std::forward<Args>(args)...),0)...);
|
||||
do_((test_copy_algorithm<ControlAlgorithm,Algorithms>(
|
||||
to_int,const_cast<const PolyCollection&>(p),
|
||||
std::forward<Args>(args)...),0)...);
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename... Algorithms,
|
||||
typename ToInt,typename PolyCollection,typename... Args
|
||||
>
|
||||
void test_copy_algorithms_with_equality_impl(
|
||||
std::true_type,ToInt to_int,PolyCollection& p,Args&&... args)
|
||||
{
|
||||
test_copy_algorithms<ControlAlgorithm,Algorithms...>(
|
||||
to_int,p,std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename... Algorithm,
|
||||
typename ToInt,typename PolyCollection,typename... Args
|
||||
>
|
||||
void test_copy_algorithms_with_equality_impl(
|
||||
std::false_type,ToInt,PolyCollection&,Args&&...)
|
||||
{
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename... Algorithms,
|
||||
typename ToInt,typename PolyCollection,typename... Args
|
||||
>
|
||||
void test_copy_algorithms_with_equality(
|
||||
ToInt to_int,PolyCollection& p,Args&&... args)
|
||||
{
|
||||
test_copy_algorithms_with_equality_impl<ControlAlgorithm,Algorithms...>(
|
||||
is_equality_comparable<typename PolyCollection::value_type>{},
|
||||
to_int,p,std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename Algorithm,
|
||||
typename ToInt,typename PolyCollection,typename... Args
|
||||
>
|
||||
void test_copy_n_algorithm(ToInt to_int,PolyCollection& p,Args&&... args)
|
||||
{
|
||||
Algorithm alg;
|
||||
ControlAlgorithm control;
|
||||
for(auto first=p.begin(),end=p.end();;++first){
|
||||
for(std::ptrdiff_t n=0,m=std::distance(first,end);n<=m;++n){
|
||||
using vector=std::vector<int>;
|
||||
|
||||
vector v1,v2;
|
||||
auto insert1=compose(to_int,[&](int x){v1.push_back(x);});
|
||||
auto insert2=compose(to_int,[&](int x){v2.push_back(x);});
|
||||
auto out1=boost::make_function_output_iterator(std::ref(insert1));
|
||||
auto out2=boost::make_function_output_iterator(std::ref(insert2));
|
||||
|
||||
alg(first,n,out1,std::forward<Args>(args)...);
|
||||
control(first,n,out2,std::forward<Args>(args)...);
|
||||
BOOST_TEST(v1==v2);
|
||||
}
|
||||
if(first==end)break;
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename... Algorithms,
|
||||
typename ToInt,typename PolyCollection,typename... Args
|
||||
>
|
||||
void test_copy_n_algorithms(ToInt to_int,PolyCollection& p,Args&&... args)
|
||||
{
|
||||
do_((test_copy_n_algorithm<ControlAlgorithm,Algorithms>(
|
||||
to_int,p,std::forward<Args>(args)...),0)...);
|
||||
do_((test_copy_n_algorithm<ControlAlgorithm,Algorithms>(
|
||||
to_int,const_cast<const PolyCollection&>(p),
|
||||
std::forward<Args>(args)...),0)...);
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename Algorithm,
|
||||
typename ToInt,typename PolyCollection
|
||||
>
|
||||
void test_transform2_algorithm(ToInt to_int,PolyCollection& p)
|
||||
{
|
||||
Algorithm alg;
|
||||
ControlAlgorithm control;
|
||||
for(auto first=p.begin(),end=p.end();;++first){
|
||||
for(auto last=first;last!=end;++last){
|
||||
using vector=std::vector<int>;
|
||||
|
||||
auto op=compose_all(to_int,[](int x,int y){return x+y;});
|
||||
vector v1,v2;
|
||||
auto insert1=[&](int x){v1.push_back(x);};
|
||||
auto insert2=[&](int x){v2.push_back(x);};
|
||||
auto out1=boost::make_function_output_iterator(std::ref(insert1));
|
||||
auto out2=boost::make_function_output_iterator(std::ref(insert2));
|
||||
|
||||
out1=alg(first,last,p.begin(),out1,op);
|
||||
out2=control(first,last,p.begin(),out2,op);
|
||||
BOOST_TEST(v1==v2);
|
||||
}
|
||||
if(first==end)break;
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename... Algorithms,
|
||||
typename ToInt,typename PolyCollection
|
||||
>
|
||||
void test_transform2_algorithms(ToInt to_int,PolyCollection& p)
|
||||
{
|
||||
do_((test_transform2_algorithm<ControlAlgorithm,Algorithms>(
|
||||
to_int,p),0)...);
|
||||
do_((test_transform2_algorithm<ControlAlgorithm,Algorithms>(
|
||||
to_int,const_cast<const PolyCollection&>(p)),0)...);
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename Algorithm,
|
||||
typename ToInt,typename PolyCollection
|
||||
>
|
||||
void test_rotate_copy_algorithm(ToInt to_int,PolyCollection& p)
|
||||
{
|
||||
Algorithm alg;
|
||||
ControlAlgorithm control;
|
||||
for(auto first=p.begin(),end=p.end();;++first){
|
||||
for(auto last=first;last!=end;++last){
|
||||
for(auto middle=first;;++middle){
|
||||
using vector=std::vector<int>;
|
||||
|
||||
vector v1,v2;
|
||||
auto insert1=compose(to_int,[&](int x){v1.push_back(x);});
|
||||
auto insert2=compose(to_int,[&](int x){v2.push_back(x);});
|
||||
auto out1=boost::make_function_output_iterator(std::ref(insert1));
|
||||
auto out2=boost::make_function_output_iterator(std::ref(insert2));
|
||||
|
||||
out1=alg(first,middle,last,out1);
|
||||
out2=control(first,middle,last,out2);
|
||||
BOOST_TEST(v1==v2);
|
||||
|
||||
if(middle==last)break;
|
||||
}
|
||||
}
|
||||
if(first==end)break;
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename... Algorithms,
|
||||
typename ToInt,typename PolyCollection
|
||||
>
|
||||
void test_rotate_copy_algorithms(ToInt to_int,PolyCollection& p)
|
||||
{
|
||||
do_((test_rotate_copy_algorithm<ControlAlgorithm,Algorithms>(
|
||||
to_int,p),0)...);
|
||||
do_((test_rotate_copy_algorithm<ControlAlgorithm,Algorithms>(
|
||||
to_int,const_cast<const PolyCollection&>(p)),0)...);
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename Algorithm,
|
||||
typename ToInt,typename PolyCollection,typename Predicate
|
||||
>
|
||||
void test_partition_copy_algorithm(
|
||||
ToInt to_int,PolyCollection& p,Predicate pred)
|
||||
{
|
||||
Algorithm alg;
|
||||
ControlAlgorithm control;
|
||||
for(auto first=p.begin(),end=p.end();;++first){
|
||||
for(auto last=first;last!=end;++last){
|
||||
using vector=std::vector<int>;
|
||||
|
||||
vector v11,v12,v21,v22;
|
||||
auto insert11=compose(to_int,[&](int x){v11.push_back(x);});
|
||||
auto insert12=compose(to_int,[&](int x){v12.push_back(x);});
|
||||
auto insert21=compose(to_int,[&](int x){v21.push_back(x);});
|
||||
auto insert22=compose(to_int,[&](int x){v22.push_back(x);});
|
||||
auto out11=boost::make_function_output_iterator(std::ref(insert11));
|
||||
auto out12=boost::make_function_output_iterator(std::ref(insert12));
|
||||
auto out21=boost::make_function_output_iterator(std::ref(insert21));
|
||||
auto out22=boost::make_function_output_iterator(std::ref(insert22));
|
||||
|
||||
std::tie(out11,out12)=alg(first,last,out11,out12,pred);
|
||||
std::tie(out21,out22)=control(first,last,out21,out22,pred);
|
||||
BOOST_TEST(v11==v21);
|
||||
BOOST_TEST(v12==v22);
|
||||
}
|
||||
if(first==end)break;
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename ControlAlgorithm,typename... Algorithms,
|
||||
typename ToInt,typename PolyCollection,typename Predicate
|
||||
>
|
||||
void test_partition_copy_algorithms(
|
||||
ToInt to_int,PolyCollection& p,Predicate pred)
|
||||
{
|
||||
do_((test_partition_copy_algorithm<ControlAlgorithm,Algorithms>(
|
||||
to_int,p,pred),0)...);
|
||||
do_((test_partition_copy_algorithm<ControlAlgorithm,Algorithms>(
|
||||
to_int,const_cast<const PolyCollection&>(p),pred),0)...);
|
||||
}
|
||||
|
||||
template<
|
||||
typename PolyCollection,typename ValueFactory,typename ToInt,
|
||||
typename... Types
|
||||
>
|
||||
void test_algorithm()
|
||||
{
|
||||
PolyCollection p;
|
||||
ValueFactory v;
|
||||
ToInt to_int;
|
||||
|
||||
fill<constraints<>,Types...>(p,v,2);
|
||||
|
||||
{
|
||||
auto always_true=compose(to_int,[](int){return true;});
|
||||
auto always_false=compose(to_int,[](int){return false;});
|
||||
auto pred=compose(to_int,[](int x){return x%2==0;});
|
||||
|
||||
test_algorithms<std_all_of<>,poly_all_of<>,poly_all_of<Types...>>(
|
||||
p,always_true);
|
||||
test_algorithms<std_all_of<>,poly_all_of<>,poly_all_of<Types...>>(
|
||||
p,always_false);
|
||||
test_algorithms<std_all_of<>,poly_all_of<>,poly_all_of<Types...>>(
|
||||
p,pred);
|
||||
|
||||
test_algorithms<std_any_of<>,poly_any_of<>,poly_any_of<Types...>>(
|
||||
p,always_true);
|
||||
test_algorithms<std_any_of<>,poly_any_of<>,poly_any_of<Types...>>(
|
||||
p,always_false);
|
||||
test_algorithms<std_any_of<>,poly_any_of<>,poly_any_of<Types...>>(
|
||||
p,pred);
|
||||
|
||||
test_algorithms<std_none_of<>,poly_none_of<>,poly_none_of<Types...>>(
|
||||
p,always_true);
|
||||
test_algorithms<std_none_of<>,poly_none_of<>,poly_none_of<Types...>>(
|
||||
p,always_false);
|
||||
test_algorithms<std_none_of<>,poly_none_of<>,poly_none_of<Types...>>(
|
||||
p,pred);
|
||||
}
|
||||
{
|
||||
struct acc_t
|
||||
{
|
||||
acc_t():res{0}{}
|
||||
void operator()(int x){res+=x;}
|
||||
int res;
|
||||
} acc;
|
||||
using poly_acc_base=decltype(compose(to_int,acc));
|
||||
struct poly_acc_t:poly_acc_base
|
||||
{
|
||||
poly_acc_t(const poly_acc_base& x):poly_acc_base{x}{};
|
||||
bool operator==(const poly_acc_t& x)const{return this->f2.res==x.f2.res;}
|
||||
} poly_acc{compose(to_int,acc)};
|
||||
|
||||
test_algorithms<std_for_each<>,poly_for_each<>,poly_for_each<Types...>>(
|
||||
p,poly_acc);
|
||||
}
|
||||
{
|
||||
for(const auto& x:p){
|
||||
test_algorithms_with_equality<
|
||||
std_find<>,poly_find<>,only_eq_comparable<poly_find,Types...>
|
||||
>(p,x);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto it=p.begin();
|
||||
std::advance(it,p.size()/2);
|
||||
int n=to_int(*it);
|
||||
auto pred=compose(to_int,[=](int x){return x==n;});
|
||||
|
||||
test_algorithms<std_find_if<>,poly_find_if<>,poly_find_if<Types...>>(
|
||||
p,pred);
|
||||
|
||||
test_algorithms<
|
||||
std_find_if_not<>,poly_find_if_not<>,poly_find_if_not<Types...>
|
||||
>(p,pred);
|
||||
}
|
||||
{
|
||||
auto first=p.begin(),end=first;
|
||||
std::advance(end,+p.size()/2);
|
||||
for(;first!=end;++first){
|
||||
test_algorithms_with_equality<
|
||||
std_find_end<>,poly_find_end<>,
|
||||
only_eq_comparable<poly_find_end,Types...>
|
||||
>(p,first,end);
|
||||
|
||||
test_algorithms_with_equality<
|
||||
std_search<>,poly_search<>,
|
||||
only_eq_comparable<poly_search,Types...>
|
||||
>(p,first,end);
|
||||
}
|
||||
}
|
||||
{
|
||||
std::vector<int> v;
|
||||
for(const auto& x:p)v.push_back(to_int(x));
|
||||
v.erase(v.begin()+v.size()/2,v.end());
|
||||
|
||||
for(auto first=v.begin(),end=v.begin()+v.size()/2;first!=end;++first){
|
||||
for(int i=1;i<4;++i){
|
||||
auto pred=compose(to_int,[&](int x,int y){return x%i==y%i;});
|
||||
|
||||
test_algorithms<
|
||||
std_find_end<>,poly_find_end<>,poly_find_end<Types...>
|
||||
>(p,first,end,pred);
|
||||
|
||||
test_algorithms<std_search<>,poly_search<>,poly_search<Types...>>(
|
||||
p,first,end,pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
using value_type=typename PolyCollection::value_type;
|
||||
using vector=std::vector<std::reference_wrapper<const value_type>>;
|
||||
|
||||
vector v;
|
||||
for(const auto& x:p){
|
||||
switch(v.size()%3){
|
||||
case 0:v.push_back(x);break;
|
||||
case 1:v.push_back(*p.begin());break;
|
||||
default:{}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto first=v.begin(),end=v.end();first!=end;++first){
|
||||
for(auto last=first;last!=end;++last){
|
||||
test_algorithms_with_equality<
|
||||
std_find_first_of<>,poly_find_first_of<>,
|
||||
only_eq_comparable<poly_find_first_of,Types...>
|
||||
>(p,first,last);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
std::vector<int> v;
|
||||
for(const auto& x:p){
|
||||
switch(v.size()%3){
|
||||
case 0:v.push_back(to_int(x));break;
|
||||
case 1:v.push_back(-1);break;
|
||||
default:{}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto first=v.begin(),end=v.end();first!=end;++first){
|
||||
for(auto last=first;last!=end;++last){
|
||||
test_algorithms<
|
||||
std_find_first_of<>,poly_find_first_of<>,poly_find_first_of<Types...>
|
||||
>(p,first,last,compose(to_int,std::equal_to<int>{}));
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
test_algorithms_with_equality<
|
||||
std_adjacent_find<>,poly_adjacent_find<>,
|
||||
only_eq_comparable<poly_adjacent_find,Types...>
|
||||
>(p);
|
||||
}
|
||||
{
|
||||
std::vector<int> v;
|
||||
for(const auto& x:p)v.push_back(to_int(x));
|
||||
v.push_back(-1);
|
||||
|
||||
for(auto first=v.begin(),end=v.end()-1;first!=end;++first){
|
||||
int n1=*first,n2=*(first+1);
|
||||
test_algorithms<
|
||||
std_adjacent_find<>,poly_adjacent_find<>,poly_adjacent_find<Types...>
|
||||
>(p,compose_all(to_int,[=](int x,int y){return x==n1&&y==n2;}));
|
||||
}
|
||||
}
|
||||
{
|
||||
for(const auto& x:p){
|
||||
test_algorithms_with_equality<
|
||||
std_count<>,poly_count<>,only_eq_comparable<poly_count,Types...>
|
||||
>(p,x);
|
||||
}
|
||||
}
|
||||
{
|
||||
for(int i=1;i<4;++i){
|
||||
test_algorithms<std_count_if<>,poly_count_if<>,poly_count_if<Types...>>(
|
||||
p,compose(to_int,[&](int x){return x%i==0;}));
|
||||
}
|
||||
}
|
||||
{
|
||||
using value_type=typename PolyCollection::value_type;
|
||||
using vector=std::vector<std::reference_wrapper<const value_type>>;
|
||||
|
||||
vector v;
|
||||
for(const auto& x:p)v.push_back(x);
|
||||
v.back()=v.front();
|
||||
auto w=v;
|
||||
v.insert(v.end(),w.begin(),w.end());
|
||||
|
||||
for(auto first=v.begin(),end=v.begin()+v.size()/2;first!=end;++first){
|
||||
test_algorithms_with_equality<
|
||||
std_mismatch<>,poly_mismatch<>,
|
||||
only_eq_comparable<poly_mismatch,Types...>
|
||||
>(p,first);
|
||||
|
||||
test_algorithms_with_equality<
|
||||
std_mismatch<>,poly_mismatch<>,
|
||||
only_eq_comparable<poly_mismatch,Types...>
|
||||
>(p,first,end);
|
||||
|
||||
test_algorithms_with_equality<
|
||||
std_equal<>,poly_equal<>,only_eq_comparable<poly_equal,Types...>
|
||||
>(p,first);
|
||||
|
||||
test_algorithms_with_equality<
|
||||
std_equal<>,poly_equal<>,only_eq_comparable<poly_equal,Types...>
|
||||
>(p,first,end);
|
||||
}
|
||||
|
||||
test_algorithms_with_equality<
|
||||
std_mismatch<>,poly_mismatch<>,only_eq_comparable<poly_mismatch,Types...>
|
||||
>(p,v.end(),v.end());
|
||||
|
||||
test_algorithms_with_equality<
|
||||
std_equal<>,poly_equal<>,only_eq_comparable<poly_equal,Types...>
|
||||
>(p,v.end(),v.end());
|
||||
}
|
||||
{
|
||||
std::vector<int> v;
|
||||
for(const auto& x:p)v.push_back(to_int(x));
|
||||
v.back()=-1;
|
||||
auto w=v;
|
||||
v.insert(v.end(),w.begin(),w.end());
|
||||
auto pred=compose(to_int,std::equal_to<int>{});
|
||||
|
||||
for(auto first=v.begin(),end=v.begin()+v.size()/2;first!=end;++first){
|
||||
test_algorithms<std_mismatch<>,poly_mismatch<>,poly_mismatch<Types...>>(
|
||||
p,first,pred);
|
||||
|
||||
test_algorithms<std_mismatch<>,poly_mismatch<>,poly_mismatch<Types...>>(
|
||||
p,first,end,pred);
|
||||
|
||||
test_algorithms<std_equal<>,poly_equal<>,poly_equal<Types...>>(
|
||||
p,first,pred);
|
||||
|
||||
test_algorithms<std_equal<>,poly_equal<>,poly_equal<Types...>>(
|
||||
p,first,end,pred);
|
||||
}
|
||||
|
||||
test_algorithms<std_mismatch<>,poly_mismatch<>,poly_mismatch<Types...>>(
|
||||
p,v.end(),v.end(),pred);
|
||||
|
||||
test_algorithms<std_equal<>,poly_equal<>,poly_equal<Types...>>(
|
||||
p,v.end(),v.end(),pred);
|
||||
}
|
||||
{
|
||||
using value_type=typename PolyCollection::value_type;
|
||||
using vector=std::vector<std::reference_wrapper<const value_type>>;
|
||||
|
||||
vector v;
|
||||
for(const auto& x:p)v.push_back(x);
|
||||
auto w=v;
|
||||
std::mt19937 gen{73642};
|
||||
std::shuffle(w.begin(),w.end(),gen);
|
||||
v.insert(v.end(),w.begin(),w.end());
|
||||
auto pred=compose_all(to_int,std::equal_to<int>{});
|
||||
|
||||
for(auto first=unwrap_iterator(v.begin()),
|
||||
end=unwrap_iterator(v.begin()+v.size()/2);first!=end;++first){
|
||||
test_algorithms_with_equality<
|
||||
std_is_permutation<>,
|
||||
poly_is_permutation<>,
|
||||
only_eq_comparable<poly_is_permutation,Types...>
|
||||
>(p,first);
|
||||
|
||||
test_algorithms<
|
||||
std_is_permutation<>,
|
||||
poly_is_permutation<>,poly_is_permutation<Types...>
|
||||
>(p,first,pred);
|
||||
|
||||
test_algorithms_with_equality<
|
||||
std_is_permutation<>,
|
||||
poly_is_permutation<>,
|
||||
only_eq_comparable<poly_is_permutation,Types...>
|
||||
>(p,first,end);
|
||||
|
||||
test_algorithms<
|
||||
std_is_permutation<>,
|
||||
poly_is_permutation<>,poly_is_permutation<Types...>
|
||||
>(p,first,end,pred);
|
||||
}
|
||||
|
||||
test_algorithms_with_equality<
|
||||
std_is_permutation<>,
|
||||
poly_is_permutation<>,
|
||||
only_eq_comparable<poly_is_permutation,Types...>
|
||||
>(p,unwrap_iterator(v.end()),unwrap_iterator(v.end()));
|
||||
|
||||
test_algorithms<
|
||||
std_is_permutation<>,
|
||||
poly_is_permutation<>,poly_is_permutation<Types...>
|
||||
>(p,unwrap_iterator(v.end()),unwrap_iterator(v.end()),pred);
|
||||
}
|
||||
{
|
||||
/* search tested above */
|
||||
}
|
||||
{
|
||||
for(const auto&x: p){
|
||||
for(int n=0;n<3;++n){
|
||||
test_algorithms_with_equality<
|
||||
std_search_n<>,poly_search_n<>,
|
||||
only_eq_comparable<poly_search_n,Types...>
|
||||
>(p,n,x);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
for(int n=0;n<6;++n){
|
||||
test_algorithms<std_search_n<>,poly_search_n<>,poly_search_n<Types...>>(
|
||||
p,n,0,compose(to_int,[&](int x,int y){return x%(6-n)==y%(6-n);}));
|
||||
}
|
||||
}
|
||||
{
|
||||
test_copy_algorithms<std_copy<>,poly_copy<>,poly_copy<Types...>>(
|
||||
to_int,p);
|
||||
}
|
||||
{
|
||||
test_copy_n_algorithms<std_copy_n<>,poly_copy_n<>,poly_copy_n<Types...>>(
|
||||
to_int,p);
|
||||
}
|
||||
{
|
||||
auto always_true=compose(to_int,[](int){return true;});
|
||||
auto always_false=compose(to_int,[](int){return false;});
|
||||
auto pred=compose(to_int,[](int x){return x%2==0;});
|
||||
|
||||
test_copy_algorithms<std_copy_if<>,poly_copy_if<>,poly_copy_if<Types...>>(
|
||||
to_int,p,always_true);
|
||||
test_copy_algorithms<std_copy_if<>,poly_copy_if<>,poly_copy_if<Types...>>(
|
||||
to_int,p,always_false);
|
||||
test_copy_algorithms<std_copy_if<>,poly_copy_if<>,poly_copy_if<Types...>>(
|
||||
to_int,p,pred);
|
||||
}
|
||||
{
|
||||
test_copy_algorithms<std_move<>,poly_move<>,poly_move<Types...>>(
|
||||
to_int,p); /* we're not checking std::move is properly used internally */
|
||||
}
|
||||
{
|
||||
auto f=compose(to_int,[](int x){return -x;});
|
||||
auto int_id=[](int x){return x;};
|
||||
|
||||
test_copy_algorithms<
|
||||
std_transform<>,poly_transform<>,poly_transform<Types...>
|
||||
>(int_id,p,f);
|
||||
}
|
||||
{
|
||||
test_transform2_algorithms<
|
||||
std_transform<>,poly_transform<>,poly_transform<Types...>
|
||||
>(to_int,p);
|
||||
}
|
||||
{
|
||||
const auto& y=*p.begin();
|
||||
for(const auto& x:p){
|
||||
test_copy_algorithms_with_equality<
|
||||
std_replace_copy<>,poly_replace_copy<>,
|
||||
only_eq_comparable<poly_replace_copy,Types...>
|
||||
>(to_int,p,x,y);
|
||||
|
||||
test_copy_algorithms_with_equality<
|
||||
std_remove_copy<>,poly_remove_copy<>,
|
||||
only_eq_comparable<poly_remove_copy,Types...>
|
||||
>(to_int,p,x);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto always_true=compose(to_int,[](int){return true;});
|
||||
auto always_false=compose(to_int,[](int){return false;});
|
||||
auto pred=compose(to_int,[](int x){return x%2==0;});
|
||||
auto& x=*p.begin();
|
||||
|
||||
test_copy_algorithms<
|
||||
std_replace_copy_if<>,
|
||||
poly_replace_copy_if<>,poly_replace_copy_if<Types...>
|
||||
>(to_int,p,always_true,x);
|
||||
test_copy_algorithms<
|
||||
std_replace_copy_if<>,
|
||||
poly_replace_copy_if<>,poly_replace_copy_if<Types...>
|
||||
>(to_int,p,always_false,x);
|
||||
test_copy_algorithms<
|
||||
std_replace_copy_if<>,
|
||||
poly_replace_copy_if<>,poly_replace_copy_if<Types...>
|
||||
>(to_int,p,pred,x);
|
||||
|
||||
test_copy_algorithms<
|
||||
std_remove_copy_if<>,
|
||||
poly_remove_copy_if<>,poly_remove_copy_if<Types...>
|
||||
>(to_int,p,always_true);
|
||||
test_copy_algorithms<
|
||||
std_remove_copy_if<>,
|
||||
poly_remove_copy_if<>,poly_remove_copy_if<Types...>
|
||||
>(to_int,p,always_false);
|
||||
test_copy_algorithms<
|
||||
std_remove_copy_if<>,
|
||||
poly_remove_copy_if<>,poly_remove_copy_if<Types...>
|
||||
>(to_int,p,pred);
|
||||
}
|
||||
{
|
||||
test_copy_algorithms_with_equality<
|
||||
std_unique_copy<>,poly_unique_copy<>,
|
||||
only_eq_comparable<poly_unique_copy,Types...>
|
||||
>(to_int,p);
|
||||
}
|
||||
{
|
||||
for(int n=0;n<6;++n){
|
||||
test_copy_algorithms<
|
||||
std_unique_copy<>,poly_unique_copy<>,poly_unique_copy<Types...>
|
||||
>(to_int,p,
|
||||
compose_all(to_int,[&](int x,int y){return x%(6-n)==y%(6-n);}));
|
||||
}
|
||||
}
|
||||
{
|
||||
test_rotate_copy_algorithms<
|
||||
std_rotate_copy<>,poly_rotate_copy<>,poly_rotate_copy<Types...>
|
||||
>(to_int,p);
|
||||
}
|
||||
{
|
||||
for(int n=0;n<6;++n){
|
||||
auto pred=compose(to_int,[&](int x){return x%(6-n)<=(6-n)/2;});
|
||||
|
||||
test_algorithms<
|
||||
std_is_partitioned<>,
|
||||
poly_is_partitioned<>,poly_is_partitioned<Types...>
|
||||
>(p,pred);
|
||||
|
||||
test_partition_copy_algorithms<
|
||||
std_partition_copy<>,
|
||||
poly_partition_copy<>,poly_partition_copy<Types...>
|
||||
>(to_int,p,pred);
|
||||
|
||||
test_algorithms<
|
||||
std_partition_point<>,
|
||||
poly_partition_point<>,poly_partition_point<Types...>
|
||||
>(p,pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
/* Copyright 2016 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 <boost/core/lightweight_test.hpp>
|
||||
#include "test_algorithm.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
test_algorithm();
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Copyright 2016 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 <boost/core/lightweight_test.hpp>
|
||||
#include "test_algorithm.hpp"
|
||||
#include "test_capacity.hpp"
|
||||
#include "test_comparison.hpp"
|
||||
#include "test_construction.hpp"
|
||||
#include "test_emplacement.hpp"
|
||||
#include "test_erasure.hpp"
|
||||
#include "test_insertion.hpp"
|
||||
#include "test_iterators.hpp"
|
||||
#include "test_registration.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
test_algorithm();
|
||||
test_capacity();
|
||||
test_comparison();
|
||||
test_construction();
|
||||
test_emplacement();
|
||||
test_erasure();
|
||||
test_insertion();
|
||||
test_iterators();
|
||||
test_registration();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/* Copyright 2016 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_capacity.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <limits>
|
||||
#include "any_types.hpp"
|
||||
#include "base_types.hpp"
|
||||
#include "function_types.hpp"
|
||||
#include "test_utilities.hpp"
|
||||
|
||||
using namespace test_utilities;
|
||||
|
||||
template<typename PolyCollection,typename ValueFactory,typename... Types>
|
||||
void test_capacity()
|
||||
{
|
||||
using size_type=typename PolyCollection::size_type;
|
||||
|
||||
PolyCollection p;
|
||||
const PolyCollection& cp=p;
|
||||
ValueFactory v;
|
||||
|
||||
BOOST_TEST(cp.empty());
|
||||
BOOST_TEST(cp.size()==0);
|
||||
BOOST_TEST(cp.max_size()==(std::numeric_limits<size_type>::max)());
|
||||
BOOST_TEST(cp.capacity()==(std::numeric_limits<size_type>::max)());
|
||||
|
||||
p.template register_types<Types...>();
|
||||
BOOST_TEST(cp.empty());
|
||||
do_((BOOST_TEST(cp.empty(typeid(Types))),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.template size<Types>()==0),0)...);
|
||||
BOOST_TEST(cp.max_size()==(std::min)({cp.max_size(typeid(Types))...}));
|
||||
BOOST_TEST(cp.max_size()==(std::min)({cp.template max_size<Types>()...}));
|
||||
BOOST_TEST(cp.capacity()==(std::min)({cp.capacity(typeid(Types))...}));
|
||||
BOOST_TEST(cp.capacity()==(std::min)({cp.template capacity<Types>()...}));
|
||||
|
||||
p.reserve(10);
|
||||
do_((BOOST_TEST(cp.capacity(typeid(Types))>=10),0)...);
|
||||
do_((BOOST_TEST(
|
||||
cp.template capacity<Types>()==cp.capacity(typeid(Types))),0)...);
|
||||
BOOST_TEST(cp.capacity()==(std::min)({cp.capacity(typeid(Types))...}));
|
||||
|
||||
do_((p.reserve(typeid(Types),20),0)...);
|
||||
do_((BOOST_TEST(cp.capacity(typeid(Types))>=20),0)...);
|
||||
|
||||
do_((p.template reserve<Types>(30),0)...);
|
||||
do_((BOOST_TEST(cp.template capacity<Types>()>=30),0)...);
|
||||
|
||||
auto c=cp.capacity();
|
||||
BOOST_TEST(c==(std::min)({cp.capacity(typeid(Types))...}));
|
||||
|
||||
fill<constraints<>,Types...>(p,v,30);
|
||||
BOOST_TEST(c==cp.capacity());
|
||||
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)...);
|
||||
|
||||
p.reserve(cp.capacity()+1);
|
||||
BOOST_TEST(cp.size()==30*sizeof...(Types));
|
||||
c=cp.capacity();
|
||||
|
||||
p.shrink_to_fit();
|
||||
BOOST_TEST(c>=cp.capacity());
|
||||
c=cp.capacity();
|
||||
|
||||
do_((p.erase(cp.template begin<Types>()),0)...);
|
||||
BOOST_TEST(c==cp.capacity());
|
||||
|
||||
do_((p.shrink_to_fit(typeid(Types)),0)...);
|
||||
BOOST_TEST(c>=cp.capacity());
|
||||
c=cp.capacity();
|
||||
|
||||
p.clear();
|
||||
do_((p.template shrink_to_fit<Types>(),0)...);
|
||||
BOOST_TEST(c>=cp.capacity());
|
||||
}
|
||||
|
||||
void test_capacity()
|
||||
{
|
||||
test_capacity<
|
||||
any_types::collection,auto_increment,
|
||||
any_types::t1,any_types::t2,any_types::t3,
|
||||
any_types::t4,any_types::t5>();
|
||||
test_capacity<
|
||||
base_types::collection,auto_increment,
|
||||
base_types::t1,base_types::t2,base_types::t3,
|
||||
base_types::t4,base_types::t5>();
|
||||
test_capacity<
|
||||
function_types::collection,auto_increment,
|
||||
function_types::t1,function_types::t2,function_types::t3,
|
||||
function_types::t4,function_types::t5>();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/* Copyright 2016 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_capacity();
|
||||
@@ -0,0 +1,16 @@
|
||||
/* Copyright 2016 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 <boost/core/lightweight_test.hpp>
|
||||
#include "test_capacity.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
test_capacity();
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/* Copyright 2016 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_comparison.hpp"
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include "any_types.hpp"
|
||||
#include "base_types.hpp"
|
||||
#include "function_types.hpp"
|
||||
#include "test_utilities.hpp"
|
||||
|
||||
using namespace test_utilities;
|
||||
|
||||
template<typename PolyCollection,typename ValueFactory,typename... Types>
|
||||
void test_comparison()
|
||||
{
|
||||
{
|
||||
PolyCollection p1,p2;
|
||||
const PolyCollection& cp1=p1;
|
||||
const PolyCollection& cp2=p2;
|
||||
|
||||
BOOST_TEST(cp1==cp1);
|
||||
BOOST_TEST(!(cp1!=cp1));
|
||||
BOOST_TEST(cp1==cp2);
|
||||
BOOST_TEST(!(cp1!=cp2));
|
||||
}
|
||||
{
|
||||
PolyCollection p1,p2;
|
||||
const PolyCollection& cp1=p1;
|
||||
const PolyCollection& cp2=p2;
|
||||
ValueFactory v;
|
||||
|
||||
fill<
|
||||
constraints<is_not_equality_comparable>,
|
||||
Types...
|
||||
>(p1,v,2);
|
||||
|
||||
BOOST_TEST(!(cp1==cp2));
|
||||
BOOST_TEST(cp1!=cp2);
|
||||
}
|
||||
{
|
||||
PolyCollection p1,p2;
|
||||
const PolyCollection& cp1=p1;
|
||||
const PolyCollection& cp2=p2;
|
||||
ValueFactory v;
|
||||
|
||||
p1.template register_types<Types...>();
|
||||
fill<
|
||||
constraints<is_not_equality_comparable>,
|
||||
Types...
|
||||
>(p1,v,2);
|
||||
|
||||
BOOST_TEST(!(cp1==cp2));
|
||||
BOOST_TEST(cp1!=cp2);
|
||||
}
|
||||
{
|
||||
PolyCollection p1,p2;
|
||||
const PolyCollection& cp1=p1;
|
||||
const PolyCollection& cp2=p2;
|
||||
ValueFactory v;
|
||||
|
||||
fill<
|
||||
constraints<is_not_equality_comparable>,
|
||||
Types...
|
||||
>(p1,v,1);
|
||||
fill<
|
||||
constraints<is_not_equality_comparable>,
|
||||
Types...
|
||||
>(p2,v,2);
|
||||
|
||||
BOOST_TEST(!(cp1==cp2));
|
||||
BOOST_TEST(cp1!=cp2);
|
||||
}
|
||||
{
|
||||
using not_equality_comparable=
|
||||
boost::poly_collection::not_equality_comparable;
|
||||
|
||||
PolyCollection p1,p2;
|
||||
const PolyCollection& cp1=p1;
|
||||
const PolyCollection& cp2=p2;
|
||||
ValueFactory v;
|
||||
|
||||
fill<
|
||||
constraints<is_not_equality_comparable>,
|
||||
Types...
|
||||
>(p1,v,2);
|
||||
fill<
|
||||
constraints<is_not_equality_comparable>,
|
||||
Types...
|
||||
>(p2,v,2);
|
||||
|
||||
check_throw<not_equality_comparable>(
|
||||
[&]{(void)(cp1==cp2);},
|
||||
[&]{(void)(cp1!=cp2);});
|
||||
}
|
||||
{
|
||||
PolyCollection p1,p2;
|
||||
const PolyCollection& cp1=p1;
|
||||
const PolyCollection& cp2=p2;
|
||||
ValueFactory v;
|
||||
|
||||
fill<
|
||||
constraints<is_not_equality_comparable>,
|
||||
Types...
|
||||
>(p1,v,2);
|
||||
fill<
|
||||
constraints<is_equality_comparable,is_copy_constructible>,
|
||||
Types...
|
||||
>(p2,v,2);
|
||||
p1.insert(p2.begin(),p2.end());
|
||||
|
||||
BOOST_TEST(!(cp1==cp2));
|
||||
BOOST_TEST(cp1!=cp2);
|
||||
}
|
||||
{
|
||||
PolyCollection p1,p2;
|
||||
const PolyCollection& cp1=p1;
|
||||
const PolyCollection& cp2=p2;
|
||||
ValueFactory v;
|
||||
|
||||
p1.template register_types<Types...>();
|
||||
fill<
|
||||
constraints<is_equality_comparable,is_copy_constructible>,
|
||||
Types...
|
||||
>(p2,v,2);
|
||||
p1.insert(p2.begin(),p2.end());
|
||||
|
||||
BOOST_TEST(cp1==cp2);
|
||||
BOOST_TEST(!(cp1!=cp2));
|
||||
|
||||
p1.erase(p1.begin());
|
||||
BOOST_TEST(!(cp1==cp2));
|
||||
BOOST_TEST(cp1!=cp2);
|
||||
}
|
||||
}
|
||||
|
||||
void test_comparison()
|
||||
{
|
||||
test_comparison<
|
||||
any_types::collection,auto_increment,
|
||||
any_types::t1,any_types::t2,any_types::t3,
|
||||
any_types::t4,any_types::t5>();
|
||||
test_comparison<
|
||||
base_types::collection,auto_increment,
|
||||
base_types::t1,base_types::t2,base_types::t3,
|
||||
base_types::t4,base_types::t5>();
|
||||
test_comparison<
|
||||
function_types::collection,auto_increment,
|
||||
function_types::t1,function_types::t2,function_types::t3,
|
||||
function_types::t4,function_types::t5>();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/* Copyright 2016 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_comparison();
|
||||
@@ -0,0 +1,16 @@
|
||||
/* Copyright 2016 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 <boost/core/lightweight_test.hpp>
|
||||
#include "test_comparison.hpp"
|
||||
|
||||
int main()
|
||||
{
|
||||
test_comparison();
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/* Copyright 2016 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_construction.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <utility>
|
||||
#include "any_types.hpp"
|
||||
#include "base_types.hpp"
|
||||
#include "function_types.hpp"
|
||||
#include "test_utilities.hpp"
|
||||
|
||||
using namespace test_utilities;
|
||||
|
||||
template<typename PolyCollection,typename ValueFactory,typename... Types>
|
||||
void test_construction()
|
||||
{
|
||||
{
|
||||
PolyCollection p;
|
||||
const PolyCollection& cp=p;
|
||||
ValueFactory v;
|
||||
|
||||
fill<
|
||||
constraints<is_equality_comparable,is_copy_constructible>,
|
||||
Types...
|
||||
>(p,v,2);
|
||||
|
||||
{
|
||||
PolyCollection p2{cp};
|
||||
BOOST_TEST(p2==p);
|
||||
}
|
||||
{
|
||||
PolyCollection p2;
|
||||
p2=cp;
|
||||
BOOST_TEST(p2==p);
|
||||
}
|
||||
{
|
||||
PolyCollection p2{cp};
|
||||
auto d2=get_layout_data<Types...>(p2);
|
||||
PolyCollection p3{std::move(p2)};
|
||||
auto d3=get_layout_data<Types...>(p3);
|
||||
BOOST_TEST(d2==d3);
|
||||
BOOST_TEST(p2.empty());
|
||||
do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
|
||||
}
|
||||
{
|
||||
PolyCollection p2{cp};
|
||||
auto d2=get_layout_data<Types...>(p2);
|
||||
PolyCollection p3;
|
||||
p3={std::move(p2)};
|
||||
auto d3=get_layout_data<Types...>(p3);
|
||||
BOOST_TEST(d2==d3);
|
||||
BOOST_TEST(p2.empty());
|
||||
do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
|
||||
}
|
||||
{
|
||||
PolyCollection p2{cp.begin(),cp.end()};
|
||||
BOOST_TEST(p2==p);
|
||||
}
|
||||
{
|
||||
using type=first_of<
|
||||
constraints<is_equality_comparable,is_copy_constructible>,
|
||||
Types...>;
|
||||
|
||||
PolyCollection p2{cp.template begin<type>(),cp.template end<type>()};
|
||||
BOOST_TEST(
|
||||
p2.size()==cp.template size<type>()&&
|
||||
std::equal(
|
||||
p2.template begin<type>(),p2.template end<type>(),
|
||||
cp.template begin<type>()));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
using rooted_poly_collection=
|
||||
realloc_poly_collection<PolyCollection,rooted_allocator>;
|
||||
using allocator_type=typename rooted_poly_collection::allocator_type;
|
||||
|
||||
allocator_type root1{0},root2{0};
|
||||
rooted_poly_collection p{root1};
|
||||
const rooted_poly_collection& cp=p;
|
||||
ValueFactory v;
|
||||
|
||||
fill<
|
||||
constraints<is_equality_comparable,is_copy_constructible>,
|
||||
Types...
|
||||
>(p,v,2);
|
||||
|
||||
{
|
||||
rooted_poly_collection p2{cp,root2};
|
||||
BOOST_TEST(p2==p);
|
||||
BOOST_TEST(p2.get_allocator()==root2);
|
||||
}
|
||||
{
|
||||
rooted_poly_collection p2{root2};
|
||||
p2=cp;
|
||||
BOOST_TEST(p2==p);
|
||||
BOOST_TEST(p2.get_allocator().root==&root2);
|
||||
}
|
||||
{
|
||||
rooted_poly_collection p2{cp};
|
||||
auto d2=get_layout_data<Types...>(p2);
|
||||
rooted_poly_collection p3{std::move(p2),root2};
|
||||
auto d3=get_layout_data<Types...>(p3);
|
||||
BOOST_TEST(d2==d3);
|
||||
BOOST_TEST(p2.empty());
|
||||
do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
|
||||
BOOST_TEST(p3.get_allocator().root==&root2);
|
||||
}
|
||||
{
|
||||
rooted_poly_collection p2{cp};
|
||||
auto d2=get_layout_data<Types...>(p2);
|
||||
rooted_poly_collection p3{root2};
|
||||
p3=std::move(p2);
|
||||
auto d3=get_layout_data<Types...>(p3);
|
||||
BOOST_TEST(d2==d3);
|
||||
BOOST_TEST(p2.empty());
|
||||
do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
|
||||
BOOST_TEST(p3.get_allocator().root==&root2);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
using not_copy_constructible=
|
||||
boost::poly_collection::not_copy_constructible;
|
||||
|
||||
PolyCollection p;
|
||||
const PolyCollection& cp=p;
|
||||
ValueFactory v;
|
||||
|
||||
fill<
|
||||
constraints<is_equality_comparable,is_not_copy_constructible>,
|
||||
Types...
|
||||
>(p,v,2);
|
||||
|
||||
check_throw<not_copy_constructible>([&]{
|
||||
PolyCollection p2{cp};
|
||||
(void)p2;
|
||||
});
|
||||
check_throw<not_copy_constructible>([&]{
|
||||
PolyCollection p2;
|
||||
p2=cp;
|
||||
});
|
||||
{
|
||||
PolyCollection p2{std::move(p)};
|
||||
BOOST_TEST(!p2.empty());
|
||||
BOOST_TEST(p.empty());
|
||||
do_((BOOST_TEST(!p.template is_registered<Types>()),0)...);
|
||||
|
||||
p={std::move(p2)};
|
||||
BOOST_TEST(!p.empty());
|
||||
BOOST_TEST(p2.empty());
|
||||
do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
PolyCollection p1,p2;
|
||||
ValueFactory v;
|
||||
|
||||
fill<constraints<>,Types...>(p1,v,2);
|
||||
auto d1=get_layout_data<Types...>(p1),
|
||||
d2=get_layout_data<Types...>(p2);
|
||||
|
||||
p1.swap(p2);
|
||||
auto e1=get_layout_data<Types...>(p1),
|
||||
e2=get_layout_data<Types...>(p2);
|
||||
BOOST_TEST(d1==e2);
|
||||
BOOST_TEST(d2==e1);
|
||||
do_((BOOST_TEST(!p1.template is_registered<Types>()),0)...);
|
||||
|
||||
using std::swap;
|
||||
swap(p1,p2);
|
||||
auto f1=get_layout_data<Types...>(p1),
|
||||
f2=get_layout_data<Types...>(p2);
|
||||
BOOST_TEST(e1==f2);
|
||||
BOOST_TEST(e2==f1);
|
||||
do_((BOOST_TEST(!p2.template is_registered<Types>()),0)...);
|
||||
}
|
||||
}
|
||||
|
||||
void test_construction()
|
||||
{
|
||||
test_construction<
|
||||
any_types::collection,auto_increment,
|
||||
any_types::t1,any_types::t2,any_types::t3,
|
||||
any_types::t4,any_types::t5>();
|
||||
test_construction<
|
||||
base_types::collection,auto_increment,
|
||||
base_types::t1,base_types::t2,base_types::t3,
|
||||
base_types::t4,base_types::t5>();
|
||||
test_construction<
|
||||
function_types::collection,auto_increment,
|
||||
function_types::t1,function_types::t2,function_types::t3,
|
||||
function_types::t4,function_types::t5>();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
/* Copyright 2016 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_construction();
|
||||