// // immer: immutable data structures for C++ // Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente // // This software is distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt // #pragma once #include #if defined(__GNUC__) && __GNUC__ == 7 && __GNUC_MINOR__ == 1 #define IMMER_BROKEN_STANDARD_LAYOUT_DETECTION 1 #define immer_offsetof(st, m) ((std::size_t) & (((st*) 0)->m)) #else #define IMMER_BROKEN_STANDARD_LAYOUT_DETECTION 0 #define immer_offsetof offsetof #endif namespace immer { namespace detail { // // Metafunction that returns a standard layout struct that combines // all the standard layout types in `Ts...`, while making sure that // empty base optimizations are used. // // To query a part of the type do `get(x)`; // // This is useful when putting together a type that merges various // types coming from different policies. Some of them might be empty, // so we shall enable empty base optimizations. But if we just // inherit from all of them, we would break the "standard layout" // rules, preventing us from using `offseof(...)`. So metafunction // will generate the type by sometimes inheriting, sometimes adding as // member. // // Note that the types are added to the combined type from right to // left! // template struct combine_standard_layout; template using combine_standard_layout_t = typename combine_standard_layout::type; namespace csl { template struct type_t {}; template U& get(T& x); template const U& get(const T& x); template struct inherit { struct type : T , Next { using Next::get_; template friend decltype(auto) get(type& x) { return x.get_(type_t{}); } template friend decltype(auto) get(const type& x) { return x.get_(type_t{}); } T& get_(type_t) { return *this; } const T& get_(type_t) const { return *this; } }; }; template struct inherit { struct type : T { template friend decltype(auto) get(type& x) { return x.get_(type_t{}); } template friend decltype(auto) get(const type& x) { return x.get_(type_t{}); } T& get_(type_t) { return *this; } const T& get_(type_t) const { return *this; } }; }; template struct member { struct type : Next { T d; using Next::get_; template friend decltype(auto) get(type& x) { return x.get_(type_t{}); } template friend decltype(auto) get(const type& x) { return x.get_(type_t{}); } T& get_(type_t) { return d; } const T& get_(type_t) const { return d; } }; }; template struct member { struct type { T d; template friend decltype(auto) get(type& x) { return x.get_(type_t{}); } template friend decltype(auto) get(const type& x) { return x.get_(type_t{}); } T& get_(type_t) { return d; } const T& get_(type_t) const { return d; } }; }; template struct member_two { struct type { Next n; T d; template friend decltype(auto) get(type& x) { return x.get_(type_t{}); } template friend decltype(auto) get(const type& x) { return x.get_(type_t{}); } T& get_(type_t) { return d; } const T& get_(type_t) const { return d; } template auto get_(type_t t) -> decltype(auto) { return n.get_(t); } template auto get_(type_t t) const -> decltype(auto) { return n.get_(t); } }; }; template struct combine_standard_layout_aux; template struct combine_standard_layout_aux { static_assert(std::is_standard_layout::value, ""); using type = typename std::conditional_t::value, csl::inherit, csl::member>::type; }; template struct combine_standard_layout_aux { static_assert(std::is_standard_layout::value, ""); using this_t = T; using next_t = typename combine_standard_layout_aux::type; static constexpr auto empty_this = std::is_empty::value; static constexpr auto empty_next = std::is_empty::value; using type = typename std::conditional_t< empty_this, inherit, std::conditional_t, member_two>>::type; }; } // namespace csl using csl::get; template struct combine_standard_layout { using type = typename csl::combine_standard_layout_aux::type; #if !IMMER_BROKEN_STANDARD_LAYOUT_DETECTION static_assert(std::is_standard_layout::value, ""); #endif }; } // namespace detail } // namespace immer