1 // Copyright 2019 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef LIB_STDCOMPAT_INTERNAL_CONSTRUCTORS_H_
6 #define LIB_STDCOMPAT_INTERNAL_CONSTRUCTORS_H_
7 
8 #include <cstddef>
9 #include <type_traits>
10 #include <utility>
11 
12 namespace cpp17 {
13 namespace internal {
14 
15 // Mixin that implicitly deletes the subclass default constructor when type T
16 // is not default constructible.
17 template <typename T, bool = std::is_default_constructible<T>::value>
18 struct modulate_default_constructor {};
19 template <typename T>
20 struct modulate_default_constructor<T, false> {
21   constexpr modulate_default_constructor() = delete;
22 };
23 
24 // Mixin that implicitly deletes the subclass copy constructor when type T is
25 // not copy constructible.
26 template <std::size_t Index, typename T, bool = std::is_copy_constructible<T>::value>
27 struct modulate_copy_constructor {};
28 template <std::size_t Index, typename T>
29 struct modulate_copy_constructor<Index, T, false> {
30   constexpr modulate_copy_constructor() = default;
31   constexpr modulate_copy_constructor(const modulate_copy_constructor&) = delete;
32   constexpr modulate_copy_constructor& operator=(const modulate_copy_constructor&) = default;
33   constexpr modulate_copy_constructor(modulate_copy_constructor&&) = default;
34   constexpr modulate_copy_constructor& operator=(modulate_copy_constructor&&) = default;
35 };
36 
37 // Mixin that implicitly deletes the subclass copy assignment operator when type
38 // T is not copy assignable.
39 template <std::size_t Index, typename T, bool = std::is_copy_assignable<T>::value>
40 struct modulate_copy_assignment {};
41 template <std::size_t Index, typename T>
42 struct modulate_copy_assignment<Index, T, false> {
43   constexpr modulate_copy_assignment() = default;
44   constexpr modulate_copy_assignment(const modulate_copy_assignment&) = default;
45   constexpr modulate_copy_assignment& operator=(const modulate_copy_assignment&) = delete;
46   constexpr modulate_copy_assignment(modulate_copy_assignment&&) = default;
47   constexpr modulate_copy_assignment& operator=(modulate_copy_assignment&&) = default;
48 };
49 
50 // Mixin that implicitly deletes the subclass move constructor when type T is
51 // not move constructible.
52 template <std::size_t Index, typename T, bool = std::is_move_constructible<T>::value>
53 struct modulate_move_constructor {};
54 template <std::size_t Index, typename T>
55 struct modulate_move_constructor<Index, T, false> {
56   constexpr modulate_move_constructor() = default;
57   constexpr modulate_move_constructor(const modulate_move_constructor&) = default;
58   constexpr modulate_move_constructor& operator=(const modulate_move_constructor&) = default;
59   constexpr modulate_move_constructor(modulate_move_constructor&&) = delete;
60   constexpr modulate_move_constructor& operator=(modulate_move_constructor&&) = default;
61 };
62 
63 // Mixin that implicitly deletes the subclass move assignment operator when type
64 // T is not move assignable.
65 template <std::size_t Index, typename T, bool = std::is_move_assignable<T>::value>
66 struct modulate_move_assignment {};
67 template <std::size_t Index, typename T>
68 struct modulate_move_assignment<Index, T, false> {
69   constexpr modulate_move_assignment() = default;
70   constexpr modulate_move_assignment(const modulate_move_assignment&) = default;
71   constexpr modulate_move_assignment& operator=(const modulate_move_assignment&) = default;
72   constexpr modulate_move_assignment(modulate_move_assignment&&) = default;
73   constexpr modulate_move_assignment& operator=(modulate_move_assignment&&) = delete;
74 };
75 
76 // Utility that takes an index sequence and an equally sized parameter pack and
77 // mixes in each of the above copy/move construction/assignment modulators for
78 // each type in Ts. The indices are used to avoid duplicate direct base errors
79 // by ensuring that each mixin type is unique, even when there are duplicate
80 // types within the parameter pack Ts.
81 template <typename IndexSequence, typename... Ts>
82 struct modulate_copy_and_move_index;
83 
84 template <std::size_t... Is, typename... Ts>
85 struct modulate_copy_and_move_index<std::index_sequence<Is...>, Ts...>
86     : modulate_copy_constructor<Is, Ts>...,
87       modulate_copy_assignment<Is, Ts>...,
88       modulate_move_constructor<Is, Ts>...,
89       modulate_move_assignment<Is, Ts>... {};
90 
91 // Mixin that modulates the subclass copy/move constructors and assignment
92 // operators based on the copy/move characteristics of each type in Ts.
93 template <typename... Ts>
94 struct modulate_copy_and_move
95     : modulate_copy_and_move_index<std::index_sequence_for<Ts...>, Ts...> {};
96 
97 }  // namespace internal
98 }  // namespace cpp17
99 
100 #endif  // LIB_STDCOMPAT_INTERNAL_CONSTRUCTORS_H_
101