411 lines
9.5 KiB
C++
411 lines
9.5 KiB
C++
/* Copyright 2016-2018 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/type_traits/has_equal_to.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<T,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 Iterator>
|
|
bool is_first(const PolyCollection& p,const std::type_info& info,Iterator it)
|
|
{
|
|
return &*it==&*p.begin(info);
|
|
}
|
|
|
|
template<typename PolyCollection,typename Iterator>
|
|
bool is_last(const PolyCollection& p,const std::type_info& 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<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{
|
|
{{(p.template is_registered<Types>()?
|
|
&*p.template begin<Types>():nullptr)...}},
|
|
{{(p.template is_registered<Types>()?
|
|
p.template size<Types>():0)...}}
|
|
};
|
|
}
|
|
|
|
} /* namespace test_utilities */
|
|
|
|
#endif
|