Files
poly_collection/test/test_utilities.hpp
joaquintides fcd9cebc92 Feature/variant_collection (#26)
* added variant_collection

* added variant_collection

* avoided &* on null pointers

* made (non-public) fixed_variant ctor explicit

* tested higher-arity visit

* implemented visit<void>

* fixed {boost::variant2|std}::variant insertion

* fixed lookup issues with invoke_visit

* removed unneeded constexpr qualifiers

* s/typeid_/index

* reverted c6bc62f6d2 as Clang 5.0 didnt seem to like it

* reinstated c6bc62f6d2

* dropped -std=c++1z for Clang 5.0

* updated docs and examples

* added boost::poly_collection::visit_by_index

* typo

* explicit cted tuple in make_iota_tuple

* changed function name to see if it helps with mangling-related Clang 3.8 ICE

* rewritten make_iota_tuple to try to make Clang 3.8 happier

* added boost::variant_collection_of
2024-12-28 10:56:06 +01:00

508 lines
12 KiB
C++

/* Copyright 2016-2024 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/poly_collection for library home page.
*/
#ifndef BOOST_POLY_COLLECTION_TEST_TEST_UTILITIES_HPP
#define BOOST_POLY_COLLECTION_TEST_TEST_UTILITIES_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <array>
#include <boost/core/lightweight_test.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/poly_collection/variant_collection_fwd.hpp>
#include <boost/type_traits/has_equal_to.hpp>
#include <boost/type_traits/make_void.hpp>
#include <iterator>
#include <memory>
#include <type_traits>
#include <typeinfo>
#include <utility>
namespace test_utilities{
template<typename... Values>
void do_(Values...){}
template<typename Exception,typename F>
void check_throw_case(F f)
{
try{
(void)f();
BOOST_TEST(false);
}
catch(const Exception&){}
catch(...){BOOST_TEST(false);}
}
template<typename Exception,typename... Fs>
void check_throw(Fs... f)
{
do_((check_throw_case<Exception>(f),0)...);
}
template<typename F1,typename F2>
struct compose_class
{
F1 f1;
F2 f2;
compose_class(const F1& f1,const F2& f2):f1(f1),f2(f2){}
template<typename T,typename... Args>
auto operator()(T&& x,Args&&... args)
->decltype(std::declval<F2>()(std::declval<F1>()(
std::forward<T>(x)),std::forward<Args>(args)...))
{
return f2(f1(std::forward<T>(x)),std::forward<Args>(args)...);
}
};
template<typename F1,typename F2>
compose_class<F1,F2> compose(F1 f1,F2 f2)
{
return {f1,f2};
}
template<typename F1,typename F2>
struct compose_all_class
{
F1 f1;
F2 f2;
compose_all_class(const F1& f1,const F2& f2):f1(f1),f2(f2){}
template<typename... Args>
auto operator()(Args&&... args)
->decltype(std::declval<F2>()(std::declval<F1>()(
std::forward<Args>(args))...))
{
return f2(f1(std::forward<Args>(args))...);
}
};
template<typename F1,typename F2>
compose_all_class<F1,F2> compose_all(F1 f1,F2 f2)
{
return {f1,f2};
}
using std::is_default_constructible;
using std::is_copy_constructible;
template<typename T>
using is_not_copy_constructible=std::integral_constant<
bool,
!std::is_copy_constructible<T>::value
>;
template<typename T>
using is_constructible_from_int=std::is_constructible<T,int>;
using std::is_copy_assignable;
template<typename T>
using is_not_copy_assignable=std::integral_constant<
bool,
!std::is_copy_assignable<T>::value
>;
template<typename T>
using is_equality_comparable=std::integral_constant<
bool,
boost::has_equal_to<const T&,const T&,bool>::value
>;
template<typename T>
using is_not_equality_comparable=std::integral_constant<
bool,
!is_equality_comparable<T>::value
>;
template<
typename T,
typename std::enable_if<is_not_copy_constructible<T>::value>::type* =nullptr
>
typename std::remove_reference<T>::type&& constref_if_copy_constructible(T&& x)
{
return std::move(x);
}
template<
typename T,
typename std::enable_if<is_copy_constructible<T>::value>::type* =nullptr
>
const T& constref_if_copy_constructible(T&& x)
{
return x;
}
template<template<typename> class... Traits>
struct constraints;
template<>
struct constraints<>
{
template<typename T>
struct apply:std::true_type{};
};
template<
template <typename> class Trait,
template <typename> class... Traits
>
struct constraints<Trait,Traits...>
{
template<typename T>
struct apply:std::integral_constant<
bool,
Trait<T>::value&&constraints<Traits...>::template apply<T>::value
>{};
};
template<typename... Ts>struct type_list{};
template<
typename Constraints,template <typename...> class Template,
typename TypeList,
typename... Ts
>
struct instantiate_with_class;
template<
typename Constraints,template <typename...> class Template,
typename... Us
>
struct instantiate_with_class<Constraints,Template,type_list<Us...>>
{using type=Template<Us...>;};
template<
typename Constraints,template <typename...> class Template,
typename... Us,
typename T,typename... Ts
>
struct instantiate_with_class<
Constraints,Template,type_list<Us...>,T,Ts...
>:instantiate_with_class<
Constraints,Template,
typename std::conditional<
Constraints::template apply<T>::value,
type_list<Us...,T>,
type_list<Us...>
>::type,
Ts...
>{};
template<
typename Constraints,template <typename...> class Template,
typename... Ts
>
using instantiate_with=typename instantiate_with_class<
Constraints,Template,type_list<>,Ts...
>::type;
template<
template <typename...> class Template,typename... Ts
>
using only_eq_comparable=instantiate_with<
constraints<is_equality_comparable>,
Template, Ts...
>;
template<typename T> struct identity{using type=T;};
template<typename Constraints,typename... Ts>
struct first_of_class{};
template<typename Constraints,typename T,typename... Ts>
struct first_of_class<Constraints,T,Ts...>:std::conditional<
Constraints::template apply<T>::value,
identity<T>,
first_of_class<Constraints,Ts...>
>::type{};
template<typename Constraints,typename... Ts>
using first_of=typename first_of_class<Constraints,Ts...>::type;
template<
typename Constraints,typename... Ts,
typename PolyCollection,typename ValueFactory
>
void fill(PolyCollection& p,ValueFactory& v,int n)
{
for(int i=0;i<n;++i){
do_(
(Constraints::template apply<Ts>::value?
(p.insert(v.template make<Ts>()),0):0)...);
}
}
template<typename PolyCollection>
bool is_first(
const PolyCollection& p,typename PolyCollection::const_iterator it)
{
return it==p.begin();
}
template<typename PolyCollection,typename TypeIndex,typename Iterator>
bool is_first(const PolyCollection& p,const TypeIndex& info,Iterator it)
{
return &*it==&*p.begin(info);
}
template<typename PolyCollection,typename TypeIndex,typename Iterator>
bool is_last(const PolyCollection& p,const TypeIndex& info,Iterator it)
{
return &*it==&*(p.end(info)-1);
}
template<typename T,typename PolyCollection,typename Iterator>
bool is_first(const PolyCollection& p,Iterator it)
{
return &*it==&*p.template begin<T>();
}
template<typename T,typename PolyCollection,typename Iterator>
bool is_last(const PolyCollection& p,Iterator it)
{
return &*it==&*(p.template end<T>()-1);
}
template<typename Iterator>
struct external_iterator_class:
public boost::iterator_adaptor<external_iterator_class<Iterator>,Iterator>
{
external_iterator_class(const Iterator& it):
external_iterator_class::iterator_adaptor_{it}{}
};
template<typename Iterator>
external_iterator_class<Iterator> external_iterator(Iterator it)
{
return it;
}
template<typename Iterator>
struct unwrap_iterator_class:public boost::iterator_adaptor<
unwrap_iterator_class<Iterator>,
Iterator,
typename std::iterator_traits<Iterator>::value_type::type
>
{
unwrap_iterator_class(const Iterator& it):
unwrap_iterator_class::iterator_adaptor_{it}{}
};
template<typename Iterator>
unwrap_iterator_class<Iterator> unwrap_iterator(Iterator it)
{
return it;
}
struct auto_increment
{
template<typename T>
T make(){return T(n++);}
int n=0;
};
struct jammed_auto_increment
{
template<typename T>
T make(){return T(n++/7);}
int n=0;
};
template<
typename T,
typename Propagate=std::true_type,typename AlwaysEqual=std::true_type
>
struct rooted_allocator:std::allocator<T>
{
using propagate_on_container_copy_assignment=Propagate;
using propagate_on_container_move_assignment=Propagate;
using propagate_on_container_swap=Propagate;
using is_always_equal=AlwaysEqual; /* for C++17 forward compatibility */
template<typename U>
struct rebind{using other=rooted_allocator<U,Propagate,AlwaysEqual>;};
rooted_allocator():root{nullptr}{}
explicit rooted_allocator(int):root{this}{}
template<typename U>
rooted_allocator(const rooted_allocator<U,Propagate,AlwaysEqual>& x):
root{x.root}{}
template<typename U>
bool operator==(const rooted_allocator<U,Propagate,AlwaysEqual>& x)const
{return AlwaysEqual::value?true:root==x.root;}
template<typename U>
bool operator!=(const rooted_allocator<U,Propagate,AlwaysEqual>& x)const
{return AlwaysEqual::value?false:root!=x.root;}
template<typename U>
bool comes_from(const rooted_allocator<U,Propagate,AlwaysEqual>& x)const
{return root==&x;}
private:
template<typename,typename,typename> friend struct rooted_allocator;
const void* root;
};
template<
typename PolyCollection,
template<typename...> class Allocator,typename... Args
>
struct realloc_poly_collection_class;
template<
typename PolyCollection,
template<typename...> class Allocator,typename... Args
>
using realloc_poly_collection=typename realloc_poly_collection_class<
PolyCollection,Allocator,Args...>::type;
template<
template<typename,typename> class PolyCollection,
typename T,typename OriginalAllocator,
template<typename...> class Allocator,typename... Args
>
struct realloc_poly_collection_class<
PolyCollection<T,OriginalAllocator>,Allocator,Args...
>
{
using value_type=typename PolyCollection<T,OriginalAllocator>::value_type;
using type=PolyCollection<T,Allocator<value_type,Args...>>;
};
template<typename PolyCollection>
struct is_closed_collection
{
private:
template<typename PolyCollection2>
static decltype(
std::declval<PolyCollection2&>().template register_types<>(),
std::false_type{}
) check(int);
template<typename> static std::true_type check(...);
public:
static constexpr bool value=decltype(check<PolyCollection>(0))::value;
};
template<
typename... T,typename PolyCollection,
typename std::enable_if<
!is_closed_collection<PolyCollection>::value>::type* =nullptr
>
void register_types(PolyCollection& p)
{
p.template register_types<T...>();
}
template<
typename... T,typename PolyCollection,
typename std::enable_if<
is_closed_collection<PolyCollection>::value>::type* =nullptr
>
void register_types(PolyCollection&)
{
}
template<
typename T,typename PolyCollection,
typename std::enable_if<
!is_closed_collection<PolyCollection>::value>::type* =nullptr
>
bool is_open_and_registered(const PolyCollection& p)
{
return p.template is_registered<T>();
}
template<
typename T,typename PolyCollection,
typename std::enable_if<
is_closed_collection<PolyCollection>::value>::type* =nullptr
>
bool is_open_and_registered(const PolyCollection&)
{
return false;
}
template<
typename T,typename PolyCollection,
typename std::enable_if<
!is_closed_collection<PolyCollection>::value>::type* =nullptr
>
bool is_registered(const PolyCollection& p)
{
return p.template is_registered<T>();
}
template<
typename T,typename PolyCollection,
typename std::enable_if<
is_closed_collection<PolyCollection>::value>::type* =nullptr
>
bool is_registered(const PolyCollection&)
{
return true;
}
template<std::size_t N>
struct layout_data
{
std::array<const void*,N> datas;
std::array<std::size_t,N> sizes;
bool operator==(const layout_data& x)const
{
return datas==x.datas&&sizes==x.sizes;
}
};
template<typename... Types,typename PolyCollection>
layout_data<sizeof...(Types)> get_layout_data(const PolyCollection& p)
{
return{
{{(is_registered<Types>(p)&&!p.template empty<Types>()?
&*p.template begin<Types>():nullptr)...}},
{{(is_registered<Types>(p)?
p.template size<Types>():0)...}}
};
}
template<
typename T,typename PolyCollection,
typename std::enable_if<
std::is_same<typename PolyCollection::type_index,std::type_info>::value
>::type* =nullptr
>
const std::type_info& typeid_(const PolyCollection&){return typeid(T);}
template<
typename T,typename PolyCollection,
typename std::enable_if<
std::is_same<typename PolyCollection::type_index,std::size_t>::value
>::type* =nullptr
>
std::size_t typeid_(const PolyCollection&)
{
return boost::mp11::mp_find<typename PolyCollection::value_type,T>::value;
}
} /* namespace test_utilities */
#endif