Line data Source code
1 : // 2 : // immer: immutable data structures for C++ 3 : // Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente 4 : // 5 : // This software is distributed under the Boost Software License, Version 1.0. 6 : // See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt 7 : // 8 : 9 : #pragma once 10 : 11 : #include <cstddef> 12 : #include <type_traits> 13 : 14 : #if defined(__GNUC__) && __GNUC__ == 7 && __GNUC_MINOR__ == 1 15 : #define IMMER_BROKEN_STANDARD_LAYOUT_DETECTION 1 16 : #define immer_offsetof(st, m) ((std::size_t) & (((st*) 0)->m)) 17 : #else 18 : #define IMMER_BROKEN_STANDARD_LAYOUT_DETECTION 0 19 : #define immer_offsetof offsetof 20 : #endif 21 : 22 : namespace immer { 23 : namespace detail { 24 : 25 : // 26 : // Metafunction that returns a standard layout struct that combines 27 : // all the standard layout types in `Ts...`, while making sure that 28 : // empty base optimizations are used. 29 : // 30 : // To query a part of the type do `get<my_part>(x)`; 31 : // 32 : // This is useful when putting together a type that merges various 33 : // types coming from different policies. Some of them might be empty, 34 : // so we shall enable empty base optimizations. But if we just 35 : // inherit from all of them, we would break the "standard layout" 36 : // rules, preventing us from using `offseof(...)`. So metafunction 37 : // will generate the type by sometimes inheriting, sometimes adding as 38 : // member. 39 : // 40 : // Note that the types are added to the combined type from right to 41 : // left! 42 : // 43 : template <typename... Ts> 44 : struct combine_standard_layout; 45 : 46 : template <typename... Ts> 47 : using combine_standard_layout_t = typename combine_standard_layout<Ts...>::type; 48 : 49 : namespace csl { 50 : 51 : template <typename T> 52 : struct type_t 53 : {}; 54 : 55 : template <typename U, typename T> 56 : U& get(T& x); 57 : 58 : template <typename U, typename T> 59 : const U& get(const T& x); 60 : 61 : template <typename T, typename Next = void> 62 : struct inherit 63 : { 64 : struct type 65 : : T 66 : , Next 67 : { 68 : using Next::get_; 69 : 70 : template <typename U> 71 : friend decltype(auto) get(type& x) 72 : { 73 : return x.get_(type_t<U>{}); 74 : } 75 : template <typename U> 76 : friend decltype(auto) get(const type& x) 77 : { 78 : return x.get_(type_t<U>{}); 79 : } 80 : 81 : T& get_(type_t<T>) { return *this; } 82 : const T& get_(type_t<T>) const { return *this; } 83 : }; 84 : }; 85 : 86 : template <typename T> 87 : struct inherit<T, void> 88 : { 89 : struct type : T 90 : { 91 : template <typename U> 92 : friend decltype(auto) get(type& x) 93 : { 94 : return x.get_(type_t<U>{}); 95 : } 96 : template <typename U> 97 : friend decltype(auto) get(const type& x) 98 : { 99 : return x.get_(type_t<U>{}); 100 : } 101 : 102 : T& get_(type_t<T>) { return *this; } 103 : const T& get_(type_t<T>) const { return *this; } 104 : }; 105 : }; 106 : 107 : template <typename T, typename Next = void> 108 : struct member 109 : { 110 : struct type : Next 111 : { 112 : T d; 113 : 114 : using Next::get_; 115 : 116 : template <typename U> 117 : friend decltype(auto) get(type& x) 118 : { 119 : return x.get_(type_t<U>{}); 120 : } 121 : template <typename U> 122 : friend decltype(auto) get(const type& x) 123 : { 124 : return x.get_(type_t<U>{}); 125 : } 126 : 127 : T& get_(type_t<T>) { return d; } 128 : const T& get_(type_t<T>) const { return d; } 129 : }; 130 : }; 131 : 132 : template <typename T> 133 : struct member<T, void> 134 : { 135 66954 : struct type 136 : { 137 : T d; 138 : 139 : template <typename U> 140 : friend decltype(auto) get(type& x) 141 : { 142 : return x.get_(type_t<U>{}); 143 : } 144 : template <typename U> 145 : friend decltype(auto) get(const type& x) 146 : { 147 : return x.get_(type_t<U>{}); 148 : } 149 : 150 : T& get_(type_t<T>) { return d; } 151 4378456 : const T& get_(type_t<T>) const { return d; } 152 : }; 153 : }; 154 : 155 : template <typename T, typename Next> 156 : struct member_two 157 : { 158 30239 : struct type 159 : { 160 : Next n; 161 : T d; 162 : 163 : template <typename U> 164 : friend decltype(auto) get(type& x) 165 : { 166 : return x.get_(type_t<U>{}); 167 : } 168 : template <typename U> 169 4378456 : friend decltype(auto) get(const type& x) 170 : { 171 4378456 : return x.get_(type_t<U>{}); 172 : } 173 : 174 : T& get_(type_t<T>) { return d; } 175 : const T& get_(type_t<T>) const { return d; } 176 : 177 : template <typename U> 178 : auto get_(type_t<U> t) -> decltype(auto) 179 : { 180 : return n.get_(t); 181 : } 182 : template <typename U> 183 4378456 : auto get_(type_t<U> t) const -> decltype(auto) 184 : { 185 1623998 : return n.get_(t); 186 : } 187 : }; 188 : }; 189 : 190 : template <typename... Ts> 191 : struct combine_standard_layout_aux; 192 : 193 : template <typename T> 194 : struct combine_standard_layout_aux<T> 195 : { 196 : static_assert(std::is_standard_layout<T>::value, ""); 197 : 198 : using type = typename std::conditional_t<std::is_empty<T>::value, 199 : csl::inherit<T>, 200 : csl::member<T>>::type; 201 : }; 202 : 203 : template <typename T, typename... Ts> 204 : struct combine_standard_layout_aux<T, Ts...> 205 : { 206 : static_assert(std::is_standard_layout<T>::value, ""); 207 : 208 : using this_t = T; 209 : using next_t = typename combine_standard_layout_aux<Ts...>::type; 210 : 211 : static constexpr auto empty_this = std::is_empty<this_t>::value; 212 : static constexpr auto empty_next = std::is_empty<next_t>::value; 213 : 214 : using type = typename std::conditional_t< 215 : empty_this, 216 : inherit<this_t, next_t>, 217 : std::conditional_t<empty_next, 218 : member<this_t, next_t>, 219 : member_two<this_t, next_t>>>::type; 220 : }; 221 : 222 : } // namespace csl 223 : 224 : using csl::get; 225 : 226 : template <typename... Ts> 227 : struct combine_standard_layout 228 : { 229 : using type = typename csl::combine_standard_layout_aux<Ts...>::type; 230 : #if !IMMER_BROKEN_STANDARD_LAYOUT_DETECTION 231 : static_assert(std::is_standard_layout<type>::value, ""); 232 : #endif 233 : }; 234 : 235 : } // namespace detail 236 : } // namespace immer