1// -*- C++ -*-
2//===----------------------------------------------------------------------===//
3//
4// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5// See https://llvm.org/LICENSE.txt for license information.
6// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef _LIBCPP_EXPERIMENTAL___MEMORY
11#define _LIBCPP_EXPERIMENTAL___MEMORY
12
13#include <__memory/allocator_arg_t.h>
14#include <__memory/uses_allocator.h>
15#include <__type_traits/conditional.h>
16#include <__type_traits/is_constructible.h>
17#include <__type_traits/is_convertible.h>
18#include <__type_traits/is_same.h>
19#include <experimental/__config>
20#include <experimental/utility> // for erased_type
21
22#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
23#  pragma GCC system_header
24#endif
25
26_LIBCPP_BEGIN_NAMESPACE_LFTS
27
28template <
29    class _Tp, class _Alloc
30  , bool = uses_allocator<_Tp, _Alloc>::value
31  , bool = __has_allocator_type<_Tp>::value
32  >
33struct __lfts_uses_allocator : public false_type {};
34
35template <class _Tp, class _Alloc>
36struct __lfts_uses_allocator<_Tp, _Alloc, false, false> : public false_type {};
37
38template <class _Tp, class _Alloc, bool HasAlloc>
39struct __lfts_uses_allocator<_Tp, _Alloc, true, HasAlloc> : public true_type {};
40
41template <class _Tp, class _Alloc>
42struct __lfts_uses_allocator<_Tp, _Alloc, false, true>
43  : public integral_constant<bool
44    , is_convertible<_Alloc, typename _Tp::allocator_type>::value
45      || is_same<erased_type, typename _Tp::allocator_type>::value
46    >
47{};
48
49template <bool _UsesAlloc, class _Tp, class _Alloc, class ..._Args>
50struct __lfts_uses_alloc_ctor_imp
51{
52    static const int value = 0;
53};
54
55template <class _Tp, class _Alloc, class ..._Args>
56struct __lfts_uses_alloc_ctor_imp<true, _Tp, _Alloc, _Args...>
57{
58    static const bool __ic_first
59        = is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>::value;
60
61    static const bool __ic_second =
62        __conditional_t<
63            __ic_first,
64            false_type,
65            is_constructible<_Tp, _Args..., _Alloc>
66        >::value;
67
68    static_assert(__ic_first || __ic_second,
69                  "Request for uses allocator construction is ill-formed");
70
71    static const int value = __ic_first ? 1 : 2;
72};
73
74template <class _Tp, class _Alloc, class ..._Args>
75struct __lfts_uses_alloc_ctor
76  : integral_constant<int,
77        __lfts_uses_alloc_ctor_imp<
78            __lfts_uses_allocator<_Tp, _Alloc>::value
79          , _Tp, _Alloc, _Args...
80        >::value
81    >
82{};
83
84template <class _Tp, class _Allocator, class... _Args>
85inline _LIBCPP_INLINE_VISIBILITY
86void __user_alloc_construct_impl (integral_constant<int, 0>, _Tp *__storage, const _Allocator &, _Args &&... __args )
87{
88    new (__storage) _Tp (_VSTD::forward<_Args>(__args)...);
89}
90
91// FIXME: This should have a version which takes a non-const alloc.
92template <class _Tp, class _Allocator, class... _Args>
93inline _LIBCPP_INLINE_VISIBILITY
94void __user_alloc_construct_impl (integral_constant<int, 1>, _Tp *__storage, const _Allocator &__a, _Args &&... __args )
95{
96    new (__storage) _Tp (allocator_arg_t(), __a, _VSTD::forward<_Args>(__args)...);
97}
98
99// FIXME: This should have a version which takes a non-const alloc.
100template <class _Tp, class _Allocator, class... _Args>
101inline _LIBCPP_INLINE_VISIBILITY
102void __user_alloc_construct_impl (integral_constant<int, 2>, _Tp *__storage, const _Allocator &__a, _Args &&... __args )
103{
104    new (__storage) _Tp (_VSTD::forward<_Args>(__args)..., __a);
105}
106
107template <class _Tp, class _Alloc, class ..._Args>
108inline _LIBCPP_INLINE_VISIBILITY
109void __lfts_user_alloc_construct(
110    _Tp * __store, const _Alloc & __a, _Args &&... __args)
111{
112    ::std::experimental::fundamentals_v1::__user_alloc_construct_impl(
113        typename __lfts_uses_alloc_ctor<_Tp, _Alloc, _Args...>::type()
114       , __store, __a, _VSTD::forward<_Args>(__args)...
115       );
116}
117
118_LIBCPP_END_NAMESPACE_LFTS
119
120#endif /* _LIBCPP_EXPERIMENTAL___MEMORY */
121