LCOV - code coverage report
Current view: top level - src/immer/detail - combine_standard_layout.hpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 7 7 100.0 %
Date: 2025-02-23 09:33:43 Functions: 0 0 -

          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

Generated by: LCOV version 1.14