Skip to content

Instantly share code, notes, and snippets.

@EricWF
Created September 13, 2017 00:10
Show Gist options
  • Save EricWF/b465fc475f55561ba972b6dd87e7e7ea to your computer and use it in GitHub Desktop.
Save EricWF/b465fc475f55561ba972b6dd87e7e7ea to your computer and use it in GitHub Desktop.
//===----------------------------------------------------------------------===//
//
// 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