initial commit

This commit is contained in:
joaquintides
2016-11-06 11:17:58 +01:00
commit 9e5f11d733
117 changed files with 13463 additions and 0 deletions
+47
View File
@@ -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=../../../..
;
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

File diff suppressed because it is too large Load Diff
+149
View File
@@ -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);
};
]
+1453
View File
File diff suppressed because it is too large Load Diff
+47
View File
@@ -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)
;
+170
View File
@@ -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";
//]
}
+72
View File
@@ -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";
//]
}
+58
View File
@@ -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();
}
+90
View File
@@ -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
//]
}
+61
View File
@@ -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&){}
}
+108
View File
@@ -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);
}
+600
View File
@@ -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);
}
}
+78
View File
@@ -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
+161
View File
@@ -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
//]
}
}
File diff suppressed because it is too large Load Diff
@@ -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
File diff suppressed because it is too large Load Diff
@@ -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
+20
View File
@@ -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>
+14
View File
@@ -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>"
]
}
+20
View File
@@ -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 ]
;
+75
View File
@@ -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
+86
View File
@@ -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
+143
View File
@@ -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
+21
View File
@@ -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();
}
+9
View File
@@ -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();
+20
View File
@@ -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>();
}
+9
View File
@@ -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();
+20
View File
@@ -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>();
}
+9
View File
@@ -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();
+20
View File
@@ -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>();
}
+9
View File
@@ -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();
+928
View File
@@ -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
+16
View File
@@ -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();
}
+33
View File
@@ -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();
}
+102
View File
@@ -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>();
}
+9
View File
@@ -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();
+16
View File
@@ -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();
}
+156
View File
@@ -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>();
}
+9
View File
@@ -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();
+16
View File
@@ -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();
}
+202
View File
@@ -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>();
}
+9
View File
@@ -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();

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