bit::memory
ebo_storage.hpp
1 /*****************************************************************************
2  * \file
3  * \brief This header contains an internal-only implementation of an EBO
4  * helper to reduce class-sizes.
5  *
6  * \note This is an internal header file, included by other library headers.
7  * Do not attempt to use it directly.
8  */
9 /*
10  The MIT License (MIT)
11 
12  Copyright (c) 2018 Matthew Rodusek
13 
14  Permission is hereby granted, free of charge, to any person obtaining a copy
15  of this software and associated documentation files (the "Software"), to deal
16  in the Software without restriction, including without limitation the rights
17  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18  copies of the Software, and to permit persons to whom the Software is
19  furnished to do so, subject to the following conditions:
20 
21  The above copyright notice and this permission notice shall be included in
22  all copies or substantial portions of the Software.
23 
24  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  SOFTWARE.
31 */
32 #ifndef BIT_MEMORY_UTILITIES_DETAIL_EBO_STORAGE_HPP
33 #define BIT_MEMORY_UTILITIES_DETAIL_EBO_STORAGE_HPP
34 
35 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
36 # pragma once
37 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
38 
39 #include <cstddef> // std::size_t
40 #include <tuple> // std::tuple_size
41 #include <type_traits> // std::integral_constant, std::enable_if, etc...
42 #include <utility> // std::index_sequence, std::piecewise_construct_t
43 
44 namespace bit {
45  namespace memory {
46 
61  template<typename...Ts>
62  class ebo_storage;
63 
64  //-------------------------------------------------------------------------
65  // Utilities
66  //-------------------------------------------------------------------------
67 
77  template<std::size_t Idx,typename...Types>
78  std::tuple_element_t<Idx,std::tuple<Types...>>&
79  get( ebo_storage<Types...>& ebo );
80  template<std::size_t Idx,typename...Types>
81  std::tuple_element_t<Idx,const std::tuple<Types...>>&
82  get( const ebo_storage<Types...>& ebo );
84 
85  //=========================================================================
86  // Implementation
87  //=========================================================================
88 
89  namespace detail {
90 
91  template<typename T, typename...Ts>
92  struct is_duplicate;
93 
94  template<typename T, typename...Ts>
95  struct is_duplicate<T,T,Ts...> : std::true_type{};
96 
97  template<typename T, typename T0, typename...Ts>
98  struct is_duplicate<T,T0,Ts...> : is_duplicate<T,Ts...>{};
99 
100  template<typename T>
101  struct is_duplicate<T> : std::false_type{};
102 
103  template<typename T0, typename...Ts>
104  struct can_ebo
105  : std::integral_constant<bool,std::is_class<T0>::value &&
106  std::is_empty<T0>::value &&
107  !std::is_final<T0>::value &&
108  !is_duplicate<T0,Ts...>::value>{};
109 
110  //=======================================================================
111  // ebo_storage_impl
112  //=======================================================================
113 
114  template<std::size_t Idx, typename T0, bool CanEbo, typename...Ts>
115  class ebo_storage_impl;
116 
117  //-----------------------------------------------------------------------
118 
119  template<std::size_t Idx, typename T0, typename T1, typename...Ts>
120  class ebo_storage_impl<Idx,T0,true,T1,Ts...>
121  : private T0,
122  public ebo_storage_impl<Idx+1,T1,can_ebo<T1,Ts...>::value, Ts...>
123  {
124  using base_type = detail::ebo_storage_impl<Idx+1,T1,can_ebo<T1,Ts...>::value, Ts...>;
125 
126  //---------------------------------------------------------------------
127  // Constructors
128  //---------------------------------------------------------------------
129  protected:
130 
131  ebo_storage_impl() = default;
132  template<typename Tuple, typename...Tuples, typename = std::enable_if_t<!std::is_same<std::decay_t<Tuple>,ebo_storage_impl>::value>>
133  ebo_storage_impl( Tuple&& tuple, Tuples&&...tuples );
134  ebo_storage_impl( const ebo_storage_impl& other ) = default;
135  ebo_storage_impl( ebo_storage_impl&& other ) = default;
136 
137  //---------------------------------------------------------------------
138 
139  ebo_storage_impl& operator=( const ebo_storage_impl& other ) = default;
140  ebo_storage_impl& operator=( ebo_storage_impl&& other ) = default;
141 
142  //---------------------------------------------------------------------
143  // Observers
144  //---------------------------------------------------------------------
145  protected:
146 
147  using base_type::get;
148 
149  T0& get( std::integral_constant<std::size_t,Idx> ) &;
150  const T0& get( std::integral_constant<std::size_t,Idx> ) const &;
151 
152  //---------------------------------------------------------------------
153  // Private Constructors
154  //---------------------------------------------------------------------
155  private:
156 
157  template<typename Tuple, std::size_t...Idxs, typename...Tuples>
158  ebo_storage_impl( Tuple&& tuple, std::index_sequence<Idxs...>, Tuples&&...tuples );
159  };
160 
161  //-----------------------------------------------------------------------
162 
163  template<std::size_t Idx, typename T0>
164  class ebo_storage_impl<Idx,T0,true>
165  : private T0
166  {
167 
168  protected:
169 
170  ebo_storage_impl() = default;
171  template<typename Tuple, typename = std::enable_if_t<!std::is_same<std::decay_t<Tuple>,ebo_storage_impl>::value>>
172  ebo_storage_impl( Tuple&& tuple );
173  ebo_storage_impl( const ebo_storage_impl& other ) = default;
174  ebo_storage_impl( ebo_storage_impl&& other ) = default;
175 
176  ebo_storage_impl& operator=( const ebo_storage_impl& other ) = default;
177  ebo_storage_impl& operator=( ebo_storage_impl&& other ) = default;
178 
179  //---------------------------------------------------------------------
180  // Protected Members
181  //---------------------------------------------------------------------
182  protected:
183 
184  T0& get( std::integral_constant<std::size_t,Idx> ) &;
185  const T0& get( std::integral_constant<std::size_t,Idx> ) const &;
186 
187  //---------------------------------------------------------------------
188  // Private Constructors
189  //---------------------------------------------------------------------
190  private:
191 
192  template<typename Tuple, std::size_t...Idxs>
193  ebo_storage_impl( Tuple&& tuple, std::index_sequence<Idxs...> );
194  };
195 
196  //-----------------------------------------------------------------------
197 
198  template<std::size_t Idx, typename T0, typename T1, typename...Ts>
199  class ebo_storage_impl<Idx,T0,false,T1,Ts...>
200  : public ebo_storage_impl<Idx+1,T1,can_ebo<T1,Ts...>::value, Ts...>
201  {
202  using base_type = detail::ebo_storage_impl<Idx+1,T1,can_ebo<T1,Ts...>::value, Ts...>;
203 
204  //---------------------------------------------------------------------
205  // Protected Constructors / Assignment
206  //---------------------------------------------------------------------
207  protected:
208 
209  ebo_storage_impl() = default;
210  template<typename Tuple, typename...Tuples, typename = std::enable_if_t<!std::is_same<std::decay_t<Tuple>,ebo_storage_impl>::value>>
211  ebo_storage_impl( Tuple&& tuple, Tuples&&...tuples );
212  ebo_storage_impl( const ebo_storage_impl& other ) = default;
213  ebo_storage_impl( ebo_storage_impl&& other ) = default;
214 
215  //---------------------------------------------------------------------
216 
217  ebo_storage_impl& operator=( const ebo_storage_impl& other ) = default;
218  ebo_storage_impl& operator=( ebo_storage_impl&& other ) = default;
219 
220  //---------------------------------------------------------------------
221  // Protected Observers
222  //---------------------------------------------------------------------
223  protected:
224 
225  using base_type::get;
226 
227  T0& get( std::integral_constant<std::size_t,Idx> ) &;
228  const T0& get( std::integral_constant<std::size_t,Idx> ) const &;
229 
230  //---------------------------------------------------------------------
231  // Private Constructors
232  //---------------------------------------------------------------------
233  private:
234 
235  template<typename Tuple, std::size_t...Idxs, typename...Tuples>
236  ebo_storage_impl( Tuple&& tuple, std::index_sequence<Idxs...>, Tuples&&...tuples);
237 
238  //---------------------------------------------------------------------
239  // Private Members
240  //---------------------------------------------------------------------
241  private:
242 
243  T0 m_storage;
244  };
245 
246  //-----------------------------------------------------------------------
247 
248  template<std::size_t Idx, typename T0>
249  class ebo_storage_impl<Idx,T0,false>
250  {
251  //---------------------------------------------------------------------
252  // Protected Constructors / Assignment
253  //---------------------------------------------------------------------
254  protected:
255 
256  ebo_storage_impl() = default;
257  template<typename Tuple, typename = std::enable_if_t<!std::is_same<std::decay_t<Tuple>,ebo_storage_impl>::value>>
258  ebo_storage_impl( Tuple&& tuple );
259  ebo_storage_impl( const ebo_storage_impl& other ) = default;
260  ebo_storage_impl( ebo_storage_impl&& other ) = default;
261 
262  //---------------------------------------------------------------------
263 
264  ebo_storage_impl& operator=( const ebo_storage_impl& other ) = default;
265  ebo_storage_impl& operator=( ebo_storage_impl&& other ) = default;
266 
267  //---------------------------------------------------------------------
268  // Protected Observers
269  //---------------------------------------------------------------------
270  protected:
271 
272  T0& get( std::integral_constant<std::size_t,Idx> ) &;
273  const T0& get( std::integral_constant<std::size_t,Idx> ) const &;
274 
275  //---------------------------------------------------------------------
276  // Private Constructors
277  //---------------------------------------------------------------------
278  private:
279 
280  template<typename Tuple, std::size_t...Idxs>
281  ebo_storage_impl( Tuple&& tuple, std::index_sequence<Idxs...> );
282 
283  //---------------------------------------------------------------------
284  // Private Members
285  //---------------------------------------------------------------------
286  private:
287 
288  T0 m_storage;
289  };
290  } // namespace detail
291 
292  //=========================================================================
293  // base case: no members, no functionality
294  //=========================================================================
295 
296  template<>
297  class ebo_storage<>
298  {
299  //-----------------------------------------------------------------------
300  // Constructors
301  //-----------------------------------------------------------------------
302  public:
303 
304  ebo_storage() = default;
305 
306  ebo_storage( const ebo_storage& other ) = default;
307 
308  ebo_storage( ebo_storage&& other ) = default;
309 
310  ebo_storage& operator=( const ebo_storage& other ) = default;
311 
312  ebo_storage& operator=( ebo_storage&& other ) = default;
313  };
314 
315  //=========================================================================
316  // standard case, 1+ types
317  //=========================================================================
318 
319  template<typename T0, typename...Ts>
320  class ebo_storage<T0,Ts...>
321  : public detail::ebo_storage_impl<0,T0,detail::can_ebo<T0,Ts...>::value,Ts...>
322  {
323 
324  using base_type = detail::ebo_storage_impl<0,T0,detail::can_ebo<T0,Ts...>::value,Ts...>;
325 
326  //-----------------------------------------------------------------------
327  // Constructors
328  //-----------------------------------------------------------------------
329  public:
330 
331  ebo_storage() = default;
332 
333  template<typename...Tuples, typename = std::enable_if_t<sizeof...(Ts)+1==sizeof...(Tuples)>>
334  explicit ebo_storage( Tuples&&...tuples );
335 
336  ebo_storage( const ebo_storage& other ) = default;
337 
338  ebo_storage( ebo_storage&& other ) = default;
339 
340  //-----------------------------------------------------------------------
341 
342  ebo_storage& operator=( const ebo_storage& other ) = default;
343 
344  ebo_storage& operator=( ebo_storage&& other ) = default;
345 
346  //---------------------------------------------------------------------
347  // Friends
348  //---------------------------------------------------------------------
349  private:
350 
351  template<std::size_t Idx, typename...Types>
352  friend std::tuple_element_t<Idx,std::tuple<Types...>>&
353  get( ebo_storage<Types...>& );
354 
355  template<std::size_t Idx, typename...Types>
356  friend std::tuple_element_t<Idx,const std::tuple<Types...>>&
357  get( const ebo_storage<Types...>& );
358  };
359 
360  } // namespace memory
361 } // namespace bit
362 
363 #include "detail/ebo_storage.inl"
364 
365 #endif /* BIT_MEMORY_UTILITIES_DETAIL_EBO_STORAGE_HPP */
A utility class used for leveraging empty-base optimization for a generic sequence of types...
Definition: ebo_storage.hpp:62