1 //  (C) Copyright Steve Cleary, Beman Dawes, Howard Hinnant & John Maddock 2000.
2 //  Use, modification and distribution are subject to the Boost Software License,
3 //  Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
4 //  http://www.boost.org/LICENSE_1_0.txt).
5 //
6 //  See http://www.boost.org/libs/utility for most recent version including documentation.
7 
8 // compressed_pair: pair that "compresses" empty members
9 // (see libs/utility/doc/html/compressed_pair.html)
10 //
11 // JM changes 25 Jan 2004:
12 // For the case where T1 == T2 and both are empty, then first() and second()
13 // should return different objects.
14 // JM changes 25 Jan 2000:
15 // Removed default arguments from compressed_pair_switch to get
16 // C++ Builder 4 to accept them
17 // rewriten swap to get gcc and C++ builder to compile.
18 // added partial specialisations for case T1 == T2 to avoid duplicate constructor defs.
19 
20 #ifndef BOOST_DETAIL_COMPRESSED_PAIR_HPP
21 #define BOOST_DETAIL_COMPRESSED_PAIR_HPP
22 
23 #include <algorithm>
24 
25 #include <boost/type_traits/remove_cv.hpp>
26 #include <boost/type_traits/is_empty.hpp>
27 #include <boost/type_traits/is_final.hpp>
28 #include <boost/type_traits/is_same.hpp>
29 #include <boost/call_traits.hpp>
30 
31 #ifdef BOOST_MSVC
32 # pragma warning(push)
33 # pragma warning(disable:4512)
34 #endif
35 namespace boost
36 {
37 
38 template <class T1, class T2>
39 class compressed_pair;
40 
41 
42 // compressed_pair
43 
44 namespace details
45 {
46    template<class T, bool E = boost::is_final<T>::value>
47    struct compressed_pair_empty
48       : ::boost::false_type { };
49 
50    template<class T>
51    struct compressed_pair_empty<T, false>
52       : ::boost::is_empty<T> { };
53 
54    // JM altered 26 Jan 2000:
55    template <class T1, class T2, bool IsSame, bool FirstEmpty, bool SecondEmpty>
56    struct compressed_pair_switch;
57 
58    template <class T1, class T2>
59    struct compressed_pair_switch<T1, T2, false, false, false>
60       {static const int value = 0;};
61 
62    template <class T1, class T2>
63    struct compressed_pair_switch<T1, T2, false, true, true>
64       {static const int value = 3;};
65 
66    template <class T1, class T2>
67    struct compressed_pair_switch<T1, T2, false, true, false>
68       {static const int value = 1;};
69 
70    template <class T1, class T2>
71    struct compressed_pair_switch<T1, T2, false, false, true>
72       {static const int value = 2;};
73 
74    template <class T1, class T2>
75    struct compressed_pair_switch<T1, T2, true, true, true>
76       {static const int value = 4;};
77 
78    template <class T1, class T2>
79    struct compressed_pair_switch<T1, T2, true, false, false>
80       {static const int value = 5;};
81 
82    template <class T1, class T2, int Version> class compressed_pair_imp;
83 
84 #ifdef __GNUC__
85    // workaround for GCC (JM):
86    using std::swap;
87 #endif
88    //
89    // can't call unqualified swap from within classname::swap
90    // as Koenig lookup rules will find only the classname::swap
91    // member function not the global declaration, so use cp_swap
92    // as a forwarding function (JM):
93    template <typename T>
cp_swap(T & t1,T & t2)94    inline void cp_swap(T& t1, T& t2)
95    {
96 #ifndef __GNUC__
97       using std::swap;
98 #endif
99       swap(t1, t2);
100    }
101 
102    // 0    derive from neither
103 
104    template <class T1, class T2>
105    class compressed_pair_imp<T1, T2, 0>
106    {
107    public:
108       typedef T1                                                 first_type;
109       typedef T2                                                 second_type;
110       typedef typename call_traits<first_type>::param_type       first_param_type;
111       typedef typename call_traits<second_type>::param_type      second_param_type;
112       typedef typename call_traits<first_type>::reference        first_reference;
113       typedef typename call_traits<second_type>::reference       second_reference;
114       typedef typename call_traits<first_type>::const_reference  first_const_reference;
115       typedef typename call_traits<second_type>::const_reference second_const_reference;
116 
compressed_pair_imp()117       compressed_pair_imp() {}
118 
compressed_pair_imp(first_param_type x,second_param_type y)119       compressed_pair_imp(first_param_type x, second_param_type y)
120          : first_(x), second_(y) {}
121 
compressed_pair_imp(first_param_type x)122       compressed_pair_imp(first_param_type x)
123          : first_(x) {}
124 
compressed_pair_imp(second_param_type y)125       compressed_pair_imp(second_param_type y)
126          : second_(y) {}
127 
first()128       first_reference       first()       {return first_;}
first() const129       first_const_reference first() const {return first_;}
130 
second()131       second_reference       second()       {return second_;}
second() const132       second_const_reference second() const {return second_;}
133 
swap(::boost::compressed_pair<T1,T2> & y)134       void swap(::boost::compressed_pair<T1, T2>& y)
135       {
136          cp_swap(first_, y.first());
137          cp_swap(second_, y.second());
138       }
139    private:
140       first_type first_;
141       second_type second_;
142    };
143 
144    // 1    derive from T1
145 
146    template <class T1, class T2>
147    class compressed_pair_imp<T1, T2, 1>
148       : protected ::boost::remove_cv<T1>::type
149    {
150    public:
151       typedef T1                                                 first_type;
152       typedef T2                                                 second_type;
153       typedef typename call_traits<first_type>::param_type       first_param_type;
154       typedef typename call_traits<second_type>::param_type      second_param_type;
155       typedef typename call_traits<first_type>::reference        first_reference;
156       typedef typename call_traits<second_type>::reference       second_reference;
157       typedef typename call_traits<first_type>::const_reference  first_const_reference;
158       typedef typename call_traits<second_type>::const_reference second_const_reference;
159 
compressed_pair_imp()160       compressed_pair_imp() {}
161 
compressed_pair_imp(first_param_type x,second_param_type y)162       compressed_pair_imp(first_param_type x, second_param_type y)
163          : first_type(x), second_(y) {}
164 
compressed_pair_imp(first_param_type x)165       compressed_pair_imp(first_param_type x)
166          : first_type(x) {}
167 
compressed_pair_imp(second_param_type y)168       compressed_pair_imp(second_param_type y)
169          : second_(y) {}
170 
first()171       first_reference       first()       {return *this;}
first() const172       first_const_reference first() const {return *this;}
173 
second()174       second_reference       second()       {return second_;}
second() const175       second_const_reference second() const {return second_;}
176 
swap(::boost::compressed_pair<T1,T2> & y)177       void swap(::boost::compressed_pair<T1,T2>& y)
178       {
179          // no need to swap empty base class:
180          cp_swap(second_, y.second());
181       }
182    private:
183       second_type second_;
184    };
185 
186    // 2    derive from T2
187 
188    template <class T1, class T2>
189    class compressed_pair_imp<T1, T2, 2>
190       : protected ::boost::remove_cv<T2>::type
191    {
192    public:
193       typedef T1                                                 first_type;
194       typedef T2                                                 second_type;
195       typedef typename call_traits<first_type>::param_type       first_param_type;
196       typedef typename call_traits<second_type>::param_type      second_param_type;
197       typedef typename call_traits<first_type>::reference        first_reference;
198       typedef typename call_traits<second_type>::reference       second_reference;
199       typedef typename call_traits<first_type>::const_reference  first_const_reference;
200       typedef typename call_traits<second_type>::const_reference second_const_reference;
201 
compressed_pair_imp()202       compressed_pair_imp() {}
203 
compressed_pair_imp(first_param_type x,second_param_type y)204       compressed_pair_imp(first_param_type x, second_param_type y)
205          : second_type(y), first_(x) {}
206 
compressed_pair_imp(first_param_type x)207       compressed_pair_imp(first_param_type x)
208          : first_(x) {}
209 
compressed_pair_imp(second_param_type y)210       compressed_pair_imp(second_param_type y)
211          : second_type(y) {}
212 
first()213       first_reference       first()       {return first_;}
first() const214       first_const_reference first() const {return first_;}
215 
second()216       second_reference       second()       {return *this;}
second() const217       second_const_reference second() const {return *this;}
218 
swap(::boost::compressed_pair<T1,T2> & y)219       void swap(::boost::compressed_pair<T1,T2>& y)
220       {
221          // no need to swap empty base class:
222          cp_swap(first_, y.first());
223       }
224 
225    private:
226       first_type first_;
227    };
228 
229    // 3    derive from T1 and T2
230 
231    template <class T1, class T2>
232    class compressed_pair_imp<T1, T2, 3>
233       : protected ::boost::remove_cv<T1>::type,
234         protected ::boost::remove_cv<T2>::type
235    {
236    public:
237       typedef T1                                                 first_type;
238       typedef T2                                                 second_type;
239       typedef typename call_traits<first_type>::param_type       first_param_type;
240       typedef typename call_traits<second_type>::param_type      second_param_type;
241       typedef typename call_traits<first_type>::reference        first_reference;
242       typedef typename call_traits<second_type>::reference       second_reference;
243       typedef typename call_traits<first_type>::const_reference  first_const_reference;
244       typedef typename call_traits<second_type>::const_reference second_const_reference;
245 
compressed_pair_imp()246       compressed_pair_imp() {}
247 
compressed_pair_imp(first_param_type x,second_param_type y)248       compressed_pair_imp(first_param_type x, second_param_type y)
249          : first_type(x), second_type(y) {}
250 
compressed_pair_imp(first_param_type x)251       compressed_pair_imp(first_param_type x)
252          : first_type(x) {}
253 
compressed_pair_imp(second_param_type y)254       compressed_pair_imp(second_param_type y)
255          : second_type(y) {}
256 
first()257       first_reference       first()       {return *this;}
first() const258       first_const_reference first() const {return *this;}
259 
second()260       second_reference       second()       {return *this;}
second() const261       second_const_reference second() const {return *this;}
262       //
263       // no need to swap empty bases:
swap(::boost::compressed_pair<T1,T2> &)264       void swap(::boost::compressed_pair<T1,T2>&) {}
265    };
266 
267    // JM
268    // 4    T1 == T2, T1 and T2 both empty
269    //      Originally this did not store an instance of T2 at all
270    //      but that led to problems beause it meant &x.first() == &x.second()
271    //      which is not true for any other kind of pair, so now we store an instance
272    //      of T2 just in case the user is relying on first() and second() returning
273    //      different objects (albeit both empty).
274    template <class T1, class T2>
275    class compressed_pair_imp<T1, T2, 4>
276       : protected ::boost::remove_cv<T1>::type
277    {
278    public:
279       typedef T1                                                 first_type;
280       typedef T2                                                 second_type;
281       typedef typename call_traits<first_type>::param_type       first_param_type;
282       typedef typename call_traits<second_type>::param_type      second_param_type;
283       typedef typename call_traits<first_type>::reference        first_reference;
284       typedef typename call_traits<second_type>::reference       second_reference;
285       typedef typename call_traits<first_type>::const_reference  first_const_reference;
286       typedef typename call_traits<second_type>::const_reference second_const_reference;
287 
compressed_pair_imp()288       compressed_pair_imp() {}
289 
compressed_pair_imp(first_param_type x,second_param_type y)290       compressed_pair_imp(first_param_type x, second_param_type y)
291          : first_type(x), m_second(y) {}
292 
compressed_pair_imp(first_param_type x)293       compressed_pair_imp(first_param_type x)
294          : first_type(x), m_second(x) {}
295 
first()296       first_reference       first()       {return *this;}
first() const297       first_const_reference first() const {return *this;}
298 
second()299       second_reference       second()       {return m_second;}
second() const300       second_const_reference second() const {return m_second;}
301 
swap(::boost::compressed_pair<T1,T2> &)302       void swap(::boost::compressed_pair<T1,T2>&) {}
303    private:
304       T2 m_second;
305    };
306 
307    // 5    T1 == T2 and are not empty:   //JM
308 
309    template <class T1, class T2>
310    class compressed_pair_imp<T1, T2, 5>
311    {
312    public:
313       typedef T1                                                 first_type;
314       typedef T2                                                 second_type;
315       typedef typename call_traits<first_type>::param_type       first_param_type;
316       typedef typename call_traits<second_type>::param_type      second_param_type;
317       typedef typename call_traits<first_type>::reference        first_reference;
318       typedef typename call_traits<second_type>::reference       second_reference;
319       typedef typename call_traits<first_type>::const_reference  first_const_reference;
320       typedef typename call_traits<second_type>::const_reference second_const_reference;
321 
compressed_pair_imp()322       compressed_pair_imp() {}
323 
compressed_pair_imp(first_param_type x,second_param_type y)324       compressed_pair_imp(first_param_type x, second_param_type y)
325          : first_(x), second_(y) {}
326 
compressed_pair_imp(first_param_type x)327       compressed_pair_imp(first_param_type x)
328          : first_(x), second_(x) {}
329 
first()330       first_reference       first()       {return first_;}
first() const331       first_const_reference first() const {return first_;}
332 
second()333       second_reference       second()       {return second_;}
second() const334       second_const_reference second() const {return second_;}
335 
swap(::boost::compressed_pair<T1,T2> & y)336       void swap(::boost::compressed_pair<T1, T2>& y)
337       {
338          cp_swap(first_, y.first());
339          cp_swap(second_, y.second());
340       }
341    private:
342       first_type first_;
343       second_type second_;
344    };
345 
346 }  // details
347 
348 template <class T1, class T2>
349 class compressed_pair
350    : private ::boost::details::compressed_pair_imp<T1, T2,
351              ::boost::details::compressed_pair_switch<
352                     T1,
353                     T2,
354                     ::boost::is_same<typename remove_cv<T1>::type, typename remove_cv<T2>::type>::value,
355                     ::boost::details::compressed_pair_empty<T1>::value,
356                     ::boost::details::compressed_pair_empty<T2>::value>::value>
357 {
358 private:
359    typedef details::compressed_pair_imp<T1, T2,
360              ::boost::details::compressed_pair_switch<
361                     T1,
362                     T2,
363                     ::boost::is_same<typename remove_cv<T1>::type, typename remove_cv<T2>::type>::value,
364                     ::boost::details::compressed_pair_empty<T1>::value,
365                     ::boost::details::compressed_pair_empty<T2>::value>::value> base;
366 public:
367    typedef T1                                                 first_type;
368    typedef T2                                                 second_type;
369    typedef typename call_traits<first_type>::param_type       first_param_type;
370    typedef typename call_traits<second_type>::param_type      second_param_type;
371    typedef typename call_traits<first_type>::reference        first_reference;
372    typedef typename call_traits<second_type>::reference       second_reference;
373    typedef typename call_traits<first_type>::const_reference  first_const_reference;
374    typedef typename call_traits<second_type>::const_reference second_const_reference;
375 
compressed_pair()376             compressed_pair() : base() {}
compressed_pair(first_param_type x,second_param_type y)377             compressed_pair(first_param_type x, second_param_type y) : base(x, y) {}
compressed_pair(first_param_type x)378    explicit compressed_pair(first_param_type x) : base(x) {}
compressed_pair(second_param_type y)379    explicit compressed_pair(second_param_type y) : base(y) {}
380 
first()381    first_reference       first()       {return base::first();}
first() const382    first_const_reference first() const {return base::first();}
383 
second()384    second_reference       second()       {return base::second();}
second() const385    second_const_reference second() const {return base::second();}
386 
swap(compressed_pair & y)387    void swap(compressed_pair& y) { base::swap(y); }
388 };
389 
390 // JM
391 // Partial specialisation for case where T1 == T2:
392 //
393 template <class T>
394 class compressed_pair<T, T>
395    : private details::compressed_pair_imp<T, T,
396              ::boost::details::compressed_pair_switch<
397                     T,
398                     T,
399                     ::boost::is_same<typename remove_cv<T>::type, typename remove_cv<T>::type>::value,
400                     ::boost::details::compressed_pair_empty<T>::value,
401                     ::boost::details::compressed_pair_empty<T>::value>::value>
402 {
403 private:
404    typedef details::compressed_pair_imp<T, T,
405              ::boost::details::compressed_pair_switch<
406                     T,
407                     T,
408                     ::boost::is_same<typename remove_cv<T>::type, typename remove_cv<T>::type>::value,
409                     ::boost::details::compressed_pair_empty<T>::value,
410                     ::boost::details::compressed_pair_empty<T>::value>::value> base;
411 public:
412    typedef T                                                  first_type;
413    typedef T                                                  second_type;
414    typedef typename call_traits<first_type>::param_type       first_param_type;
415    typedef typename call_traits<second_type>::param_type      second_param_type;
416    typedef typename call_traits<first_type>::reference        first_reference;
417    typedef typename call_traits<second_type>::reference       second_reference;
418    typedef typename call_traits<first_type>::const_reference  first_const_reference;
419    typedef typename call_traits<second_type>::const_reference second_const_reference;
420 
compressed_pair()421             compressed_pair() : base() {}
compressed_pair(first_param_type x,second_param_type y)422             compressed_pair(first_param_type x, second_param_type y) : base(x, y) {}
423 #if !(defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530))
424    explicit
425 #endif
compressed_pair(first_param_type x)426       compressed_pair(first_param_type x) : base(x) {}
427 
first()428    first_reference       first()       {return base::first();}
first() const429    first_const_reference first() const {return base::first();}
430 
second()431    second_reference       second()       {return base::second();}
second() const432    second_const_reference second() const {return base::second();}
433 
swap(::boost::compressed_pair<T,T> & y)434    void swap(::boost::compressed_pair<T,T>& y) { base::swap(y); }
435 };
436 
437 template <class T1, class T2>
438 inline
439 void
swap(compressed_pair<T1,T2> & x,compressed_pair<T1,T2> & y)440 swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
441 {
442    x.swap(y);
443 }
444 
445 } // boost
446 
447 #ifdef BOOST_MSVC
448 # pragma warning(pop)
449 #endif
450 
451 #endif // BOOST_DETAIL_COMPRESSED_PAIR_HPP
452 
453