-
-
Save EricWF/b465fc475f55561ba972b6dd87e7e7ea to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//===----------------------------------------------------------------------===// | |
// | |
// The LLVM Compiler Infrastructure | |
// | |
// This file is dual licensed under the MIT and the University of Illinois Open | |
// Source Licenses. See LICENSE.TXT for details. | |
// | |
//===----------------------------------------------------------------------===// | |
#include <array> | |
#include <cassert> | |
#include <deque> | |
#include <forward_list> | |
#include <list> | |
#include <map> | |
#include <queue> | |
#include <set> | |
#include <stack> | |
#include <type_traits> | |
#include <unordered_map> | |
#include <unordered_set> | |
#include <vector> | |
#include "min_allocator.h" | |
// Holder<ns::T> is a do-nothing wrapper around a value of the given type. | |
// | |
// Since unqualified name lookup and operator overload lookup participate in | |
// ADL, the dependent type ns::T contributes to the overload set considered by | |
// ADL. In other words, ADL will consider all associated namespaces: this | |
// includes not only N, but also any inline friend functions declared by ns::T. | |
// | |
// The purpose of this test is to ensure that simply constructing or destroying | |
// a container does not invoke ADL which would be problematic for unknown types. | |
// By using the type 'Holder<ns::T> *' as a container value, we can avoid the | |
// obvious problems with unknown types: a pointer is trivial, and its size is | |
// known. However, any ADL which includes ns::T as an associated namesapce will | |
// fail. | |
// | |
// For example: | |
// | |
// namespace ns { | |
// class T { | |
// // 13.5.7 [over.inc]: | |
// friend std::list<T *>::const_iterator | |
// operator++(std::list<T *>::const_iterator it) { | |
// return /* ... */; | |
// } | |
// }; | |
// } | |
// | |
// The C++ standard stipulates that some functions, such as std::advance, use | |
// overloaded operators (in C++14: 24.4.4 [iterator.operations]). The | |
// implication is that calls to such a function are dependent on knowing the | |
// overload set of operators in all associated namespaces; under ADL, this | |
// includes the private friend function in the example above. | |
// | |
// However, for some operations, such as construction and destruction, no such | |
// ADL is required. This can be important, for example, when using the Pimpl | |
// pattern: | |
// | |
// // Defined in a header file: | |
// class InterfaceList { | |
// // Defined in a .cpp file: | |
// class Impl; | |
// vector<Impl*> impls; | |
// public: | |
// ~InterfaceList(); | |
// }; | |
// | |
template <class T> | |
class Holder { T value; }; | |
namespace ns { class Fwd; } | |
template <class T> | |
struct replace_alloc_arg { | |
using type = T; | |
}; | |
template <class T> | |
struct replace_alloc_arg<std::allocator<T> > { | |
using type = min_allocator<T>; | |
}; | |
template <class Container> | |
struct replace_alloc; | |
template <template <class ...> class Container, class ...Args> | |
struct replace_alloc<Container<Args...> > { | |
using type = Container<typename replace_alloc_arg<Args>::type...>; | |
}; | |
template <class Cont> | |
using ReplaceAlloc = typename replace_alloc<Cont>::type; | |
// TestImp ensures that a given container type can be | |
// default-constructed and destroyed with an incomplete value pointer type. | |
template <class Container> | |
void TestImp() { | |
{ | |
Container u; | |
assert(u.empty()); | |
} | |
{ | |
auto u = Container(); | |
assert(u.empty()); | |
} | |
} | |
template <class Container> | |
void TestContainer() { | |
TestImp<Container>(); | |
TestImp<ReplaceAlloc<Container>>(); | |
} | |
template <template <class...> class Container> | |
void TestSequencePtr() { | |
using T = Holder<ns::Fwd>*; | |
TestContainer<Container<T>>(); | |
} | |
template <template <class...> class Container> | |
void TestMappingPtr() { | |
using T = Holder<ns::Fwd>*; | |
TestContainer< Container<T, T> >(); | |
TestContainer< Container<int, T> >(); | |
TestContainer< Container<T, int> >(); | |
} | |
template <template <class, class> class Adaptor, | |
template <class...> class Container = std::deque> | |
void TestAdaptorPtr() { | |
using T = Holder<ns::Fwd>*; | |
using C = Container<T>; | |
TestImp< Adaptor<T, C> >(); | |
TestImp< Adaptor<T, ReplaceAlloc<C>> >(); | |
} | |
int main() | |
{ | |
// Sequence containers: | |
{ | |
using T = Holder<ns::Fwd>*; | |
using C = std::array<T, 1>; | |
C a; | |
((void)a); | |
} | |
TestSequencePtr<std::deque>(); | |
TestSequencePtr<std::forward_list>(); | |
TestSequencePtr<std::list>(); | |
TestSequencePtr<std::vector>(); | |
// Associative containers, non-mapping: | |
TestSequencePtr<std::set>(); | |
TestSequencePtr<std::multiset>(); | |
TestSequencePtr<std::unordered_set>(); | |
TestSequencePtr<std::unordered_multiset>(); | |
// Associative containers, mapping: | |
TestMappingPtr<std::map>(); | |
TestMappingPtr<std::multimap>(); | |
TestMappingPtr<std::unordered_map>(); | |
TestMappingPtr<std::unordered_multimap>(); | |
// Container adapters: | |
TestAdaptorPtr<std::queue>(); | |
TestAdaptorPtr<std::stack>(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment