Nugget
compressed_pair.h
1 // Copyright (c) Electronic Arts Inc. All rights reserved.
4 
6 // The compressed pair class is very similar to std::pair, but if either of the
7 // template arguments are empty classes, then the "empty base-class optimization"
8 // is applied to compress the size of the pair.
9 //
10 // The design for compressed_pair here is very similar to that found in template
11 // metaprogramming libraries such as Boost, GCC, and Metrowerks, given that
12 // these libraries have established this interface as a defacto standard for
13 // solving this problem. Also, these are described in various books on the
14 // topic of template metaprogramming, such as "Modern C++ Design".
15 //
16 // template <typename T1, typename T2>
17 // class compressed_pair
18 // {
19 // public:
20 // typedef T1 first_type;
21 // typedef T2 second_type;
22 // typedef typename call_traits<first_type>::param_type first_param_type;
23 // typedef typename call_traits<second_type>::param_type second_param_type;
24 // typedef typename call_traits<first_type>::reference first_reference;
25 // typedef typename call_traits<second_type>::reference second_reference;
26 // typedef typename call_traits<first_type>::const_reference first_const_reference;
27 // typedef typename call_traits<second_type>::const_reference second_const_reference;
28 //
29 // compressed_pair() : base() {}
30 // compressed_pair(first_param_type x, second_param_type y);
31 // explicit compressed_pair(first_param_type x);
32 // explicit compressed_pair(second_param_type y);
33 //
34 // compressed_pair& operator=(const compressed_pair&);
35 //
36 // first_reference first();
37 // first_const_reference first() const;
38 //
39 // second_reference second();
40 // second_const_reference second() const;
41 //
42 // void swap(compressed_pair& y);
43 // };
44 //
45 // The two members of the pair can be accessed using the member functions first()
46 // and second(). Note that not all member functions can be instantiated for all
47 // template parameter types. In particular compressed_pair can be instantiated for
48 // reference and array types, however in these cases the range of constructors that
49 // can be used are limited. If types T1 and T2 are the same type, then there is
50 // only one version of the single-argument constructor, and this constructor
51 // initialises both values in the pair to the passed value.
52 //
53 // Note that compressed_pair can not be instantiated if either of the template
54 // arguments is a union type, unless there is compiler support for is_union,
55 // or if is_union is specialised for the union type.
57 
58 
59 #ifndef EASTL_COMPRESSED_PAIR_H
60 #define EASTL_COMPRESSED_PAIR_H
61 
62 
63 #include <EASTL/internal/config.h>
64 #include <EASTL/type_traits.h>
65 #include <EASTL/bonus/call_traits.h>
66 
67 #if defined(EA_PRAGMA_ONCE_SUPPORTED)
68  #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
69 #endif
70 
71 #if defined(_MSC_VER) && (_MSC_VER >= 1900) // VS2015 or later
72  EA_DISABLE_VC_WARNING(4626 5027) // warning C4626: 'eastl::compressed_pair_imp<T1,T2,0>': assignment operator was implicitly defined as deleted because a base class assignment operator is inaccessible or deleted
73 #endif
74 
75 namespace eastl
76 {
77 
78  template <typename T1, typename T2>
79  class compressed_pair;
80 
81 
82  template <typename T1, typename T2, bool isSame, bool firstEmpty, bool secondEmpty>
84 
85  template <typename T1, typename T2>
86  struct compressed_pair_switch<T1, T2, false, false, false>{ static const int value = 0; };
87 
88  template <typename T1, typename T2>
89  struct compressed_pair_switch<T1, T2, false, true, false> { static const int value = 1; };
90 
91  template <typename T1, typename T2>
92  struct compressed_pair_switch<T1, T2, false, false, true> { static const int value = 2; };
93 
94  template <typename T1, typename T2>
95  struct compressed_pair_switch<T1, T2, false, true, true> { static const int value = 3; };
96 
97  template <typename T1, typename T2>
98  struct compressed_pair_switch<T1, T2, true, true, true> { static const int value = 4; };
99 
100  template <typename T1, typename T2>
101  struct compressed_pair_switch<T1, T2, true, false, false> { static const int value = 5; };
102 
103  template <typename T1, typename T2, int version>
105 
106 
107 
108  template <typename T>
109  inline void cp_swap(T& t1, T& t2)
110  {
111  T tTemp = t1;
112  t1 = t2;
113  t2 = tTemp;
114  }
115 
116 
117  // Derive from neither
118  template <typename T1, typename T2>
119  class compressed_pair_imp<T1, T2, 0>
120  {
121  public:
122  typedef T1 first_type;
123  typedef T2 second_type;
124  typedef typename call_traits<first_type>::param_type first_param_type;
125  typedef typename call_traits<second_type>::param_type second_param_type;
126  typedef typename call_traits<first_type>::reference first_reference;
127  typedef typename call_traits<second_type>::reference second_reference;
128  typedef typename call_traits<first_type>::const_reference first_const_reference;
129  typedef typename call_traits<second_type>::const_reference second_const_reference;
130 
131  compressed_pair_imp() {}
132 
133  compressed_pair_imp(first_param_type x, second_param_type y)
134  : mFirst(x), mSecond(y) {}
135 
136  compressed_pair_imp(first_param_type x)
137  : mFirst(x) {}
138 
139  compressed_pair_imp(second_param_type y)
140  : mSecond(y) {}
141 
142  first_reference first() { return mFirst; }
143  first_const_reference first() const { return mFirst; }
144 
145  second_reference second() { return mSecond; }
146  second_const_reference second() const { return mSecond; }
147 
148  void swap(compressed_pair<T1, T2>& y)
149  {
150  cp_swap(mFirst, y.first());
151  cp_swap(mSecond, y.second());
152  }
153 
154  private:
155  first_type mFirst;
156  second_type mSecond;
157  };
158 
159 
160  // Derive from T1
161  template <typename T1, typename T2>
162  class compressed_pair_imp<T1, T2, 1> : private T1
163  {
164  public:
165  typedef T1 first_type;
166  typedef T2 second_type;
167  typedef typename call_traits<first_type>::param_type first_param_type;
168  typedef typename call_traits<second_type>::param_type second_param_type;
169  typedef typename call_traits<first_type>::reference first_reference;
170  typedef typename call_traits<second_type>::reference second_reference;
171  typedef typename call_traits<first_type>::const_reference first_const_reference;
172  typedef typename call_traits<second_type>::const_reference second_const_reference;
173 
175 
176  compressed_pair_imp(first_param_type x, second_param_type y)
177  : first_type(x), mSecond(y) {}
178 
179  compressed_pair_imp(first_param_type x)
180  : first_type(x) {}
181 
182  compressed_pair_imp(second_param_type y)
183  : mSecond(y) {}
184 
185  first_reference first() { return *this; }
186  first_const_reference first() const { return *this; }
187 
188  second_reference second() { return mSecond; }
189  second_const_reference second() const { return mSecond; }
190 
191  void swap(compressed_pair<T1,T2>& y)
192  {
193  // No need to swap empty base class
194  cp_swap(mSecond, y.second());
195  }
196 
197  private:
198  second_type mSecond;
199  };
200 
201 
202 
203  // Derive from T2
204  template <typename T1, typename T2>
205  class compressed_pair_imp<T1, T2, 2> : private T2
206  {
207  public:
208  typedef T1 first_type;
209  typedef T2 second_type;
210  typedef typename call_traits<first_type>::param_type first_param_type;
211  typedef typename call_traits<second_type>::param_type second_param_type;
212  typedef typename call_traits<first_type>::reference first_reference;
213  typedef typename call_traits<second_type>::reference second_reference;
214  typedef typename call_traits<first_type>::const_reference first_const_reference;
215  typedef typename call_traits<second_type>::const_reference second_const_reference;
216 
218 
219  compressed_pair_imp(first_param_type x, second_param_type y)
220  : second_type(y), mFirst(x) {}
221 
222  compressed_pair_imp(first_param_type x)
223  : mFirst(x) {}
224 
225  compressed_pair_imp(second_param_type y)
226  : second_type(y) {}
227 
228  first_reference first() { return mFirst; }
229  first_const_reference first() const { return mFirst; }
230 
231  second_reference second() { return *this; }
232  second_const_reference second() const { return *this; }
233 
234  void swap(compressed_pair<T1,T2>& y)
235  {
236  // No need to swap empty base class
237  cp_swap(mFirst, y.first());
238  }
239 
240  private:
241  first_type mFirst;
242  };
243 
244 
245 
246  // Derive from T1 and T2
247  template <typename T1, typename T2>
248  class compressed_pair_imp<T1, T2, 3> : private T1, private T2
249  {
250  public:
251  typedef T1 first_type;
252  typedef T2 second_type;
253  typedef typename call_traits<first_type>::param_type first_param_type;
254  typedef typename call_traits<second_type>::param_type second_param_type;
255  typedef typename call_traits<first_type>::reference first_reference;
256  typedef typename call_traits<second_type>::reference second_reference;
257  typedef typename call_traits<first_type>::const_reference first_const_reference;
258  typedef typename call_traits<second_type>::const_reference second_const_reference;
259 
261 
262  compressed_pair_imp(first_param_type x, second_param_type y)
263  : first_type(x), second_type(y) {}
264 
265  compressed_pair_imp(first_param_type x)
266  : first_type(x) {}
267 
268  compressed_pair_imp(second_param_type y)
269  : second_type(y) {}
270 
271  first_reference first() { return *this; }
272  first_const_reference first() const { return *this; }
273 
274  second_reference second() { return *this; }
275  second_const_reference second() const { return *this; }
276 
277  // No need to swap empty bases
278  void swap(compressed_pair<T1, T2>&)
279  { }
280  };
281 
282 
283  // T1 == T2, T1 and T2 are both empty
284  // Note does not actually store an instance of T2 at all;
285  // but reuses T1 base class for both first() and second().
286  template <typename T1, typename T2>
287  class compressed_pair_imp<T1, T2, 4> : private T1
288  {
289  public:
290  typedef T1 first_type;
291  typedef T2 second_type;
292  typedef typename call_traits<first_type>::param_type first_param_type;
293  typedef typename call_traits<second_type>::param_type second_param_type;
294  typedef typename call_traits<first_type>::reference first_reference;
295  typedef typename call_traits<second_type>::reference second_reference;
296  typedef typename call_traits<first_type>::const_reference first_const_reference;
297  typedef typename call_traits<second_type>::const_reference second_const_reference;
298 
300 
301  compressed_pair_imp(first_param_type x, second_param_type)
302  : first_type(x) {}
303 
304  compressed_pair_imp(first_param_type x)
305  : first_type(x) {}
306 
307  first_reference first() { return *this; }
308  first_const_reference first() const { return *this; }
309 
310  second_reference second() { return *this; }
311  second_const_reference second() const { return *this; }
312 
313  void swap(compressed_pair<T1, T2>&) { }
314  };
315 
316 
317  // T1 == T2 and are not empty
318  template <typename T1, typename T2>
319  class compressed_pair_imp<T1, T2, 5>
320  {
321  public:
322  typedef T1 first_type;
323  typedef T2 second_type;
324  typedef typename call_traits<first_type>::param_type first_param_type;
325  typedef typename call_traits<second_type>::param_type second_param_type;
326  typedef typename call_traits<first_type>::reference first_reference;
327  typedef typename call_traits<second_type>::reference second_reference;
328  typedef typename call_traits<first_type>::const_reference first_const_reference;
329  typedef typename call_traits<second_type>::const_reference second_const_reference;
330 
332 
333  compressed_pair_imp(first_param_type x, second_param_type y)
334  : mFirst(x), mSecond(y) {}
335 
336  compressed_pair_imp(first_param_type x)
337  : mFirst(x), mSecond(x) {}
338 
339  first_reference first() { return mFirst; }
340  first_const_reference first() const { return mFirst; }
341 
342  second_reference second() { return mSecond; }
343  second_const_reference second() const { return mSecond; }
344 
345  void swap(compressed_pair<T1, T2>& y)
346  {
347  cp_swap(mFirst, y.first());
348  cp_swap(mSecond, y.second());
349  }
350 
351  private:
352  first_type mFirst;
353  second_type mSecond;
354  };
355 
356 
357 
358  template <typename T1, typename T2>
360  : private compressed_pair_imp<T1, T2,
361  compressed_pair_switch<
362  T1,
363  T2,
364  is_same<typename remove_cv<T1>::type, typename remove_cv<T2>::type>::value,
365  is_empty<T1>::value,
366  is_empty<T2>::value>::value>
367  {
368  private:
369  typedef compressed_pair_imp<T1, T2,
371  T1,
372  T2,
373  is_same<typename remove_cv<T1>::type, typename remove_cv<T2>::type>::value,
375  is_empty<T2>::value>::value> base;
376  public:
377  typedef T1 first_type;
378  typedef T2 second_type;
379  typedef typename call_traits<first_type>::param_type first_param_type;
380  typedef typename call_traits<second_type>::param_type second_param_type;
381  typedef typename call_traits<first_type>::reference first_reference;
382  typedef typename call_traits<second_type>::reference second_reference;
383  typedef typename call_traits<first_type>::const_reference first_const_reference;
384  typedef typename call_traits<second_type>::const_reference second_const_reference;
385 
386  compressed_pair() : base() {}
387  compressed_pair(first_param_type x, second_param_type y) : base(x, y) {}
388  explicit compressed_pair(first_param_type x) : base(x) {}
389  explicit compressed_pair(second_param_type y) : base(y) {}
390 
391  first_reference first() { return base::first(); }
392  first_const_reference first() const { return base::first(); }
393 
394  second_reference second() { return base::second(); }
395  second_const_reference second() const { return base::second(); }
396 
397  void swap(compressed_pair& y) { base::swap(y); }
398  };
399 
400 
401  // Partial specialisation for case where T1 == T2:
402  template <typename T>
403  class compressed_pair<T, T>
404  : private compressed_pair_imp<T, T,
405  compressed_pair_switch<
406  T,
407  T,
408  is_same<typename remove_cv<T>::type, typename remove_cv<T>::type>::value,
409  is_empty<T>::value,
410  is_empty<T>::value>::value>
411  {
412  private:
413  typedef compressed_pair_imp<T, T,
415  T,
416  T,
417  is_same<typename remove_cv<T>::type, typename remove_cv<T>::type>::value,
419  is_empty<T>::value>::value> base;
420  public:
421  typedef T first_type;
422  typedef T second_type;
423  typedef typename call_traits<first_type>::param_type first_param_type;
424  typedef typename call_traits<second_type>::param_type second_param_type;
425  typedef typename call_traits<first_type>::reference first_reference;
426  typedef typename call_traits<second_type>::reference second_reference;
427  typedef typename call_traits<first_type>::const_reference first_const_reference;
428  typedef typename call_traits<second_type>::const_reference second_const_reference;
429 
430  compressed_pair() : base() {}
431  compressed_pair(first_param_type x, second_param_type y) : base(x, y) {}
432  explicit compressed_pair(first_param_type x) : base(x) {}
433 
434  first_reference first() { return base::first(); }
435  first_const_reference first() const { return base::first(); }
436 
437  second_reference second() { return base::second(); }
438  second_const_reference second() const { return base::second(); }
439 
440  void swap(compressed_pair<T, T>& y) { base::swap(y); }
441  };
442 
443 
444  template <typename T1, typename T2>
445  inline void swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
446  {
447  x.swap(y);
448  }
449 
450 
451 } // namespace eastl
452 
453 #if defined(_MSC_VER) && (_MSC_VER >= 1900) // VS2015 or later
454  EA_RESTORE_VC_WARNING()
455 #endif
456 
457 #endif // Header include guard
458 
459 
460 
Definition: compressed_pair.h:411
Definition: compressed_pair.h:104
Definition: compressed_pair.h:367
EA Standard Template Library.
Definition: algorithm.h:288
Definition: compressed_pair.h:83
Definition: type_pod.h:57
Definition: type_traits.h:604