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_same.hpp>
28 #include <boost/call_traits.hpp>
29 
30 #ifdef BOOST_MSVC
31 # pragma warning(push)
32 # pragma warning(disable:4512)
33 #endif
34 namespace boost
35 {
36 
37 template <class T1, class T2>
38 class compressed_pair;
39 
40 
41 // compressed_pair
42 
43 namespace details
44 {
45    // JM altered 26 Jan 2000:
46    template <class T1, class T2, bool IsSame, bool FirstEmpty, bool SecondEmpty>
47    struct compressed_pair_switch;
48 
49    template <class T1, class T2>
50    struct compressed_pair_switch<T1, T2, false, false, false>
51       {static const int value = 0;};
52 
53    template <class T1, class T2>
54    struct compressed_pair_switch<T1, T2, false, true, true>
55       {static const int value = 3;};
56 
57    template <class T1, class T2>
58    struct compressed_pair_switch<T1, T2, false, true, false>
59       {static const int value = 1;};
60 
61    template <class T1, class T2>
62    struct compressed_pair_switch<T1, T2, false, false, true>
63       {static const int value = 2;};
64 
65    template <class T1, class T2>
66    struct compressed_pair_switch<T1, T2, true, true, true>
67       {static const int value = 4;};
68 
69    template <class T1, class T2>
70    struct compressed_pair_switch<T1, T2, true, false, false>
71       {static const int value = 5;};
72 
73    template <class T1, class T2, int Version> class compressed_pair_imp;
74 
75 #ifdef __GNUC__
76    // workaround for GCC (JM):
77    using std::swap;
78 #endif
79    //
80    // can't call unqualified swap from within classname::swap
81    // as Koenig lookup rules will find only the classname::swap
82    // member function not the global declaration, so use cp_swap
83    // as a forwarding function (JM):
84    template <typename T>
cp_swap(T & t1,T & t2)85    inline void cp_swap(T& t1, T& t2)
86    {
87 #ifndef __GNUC__
88       using std::swap;
89 #endif
90       swap(t1, t2);
91    }
92 
93    // 0    derive from neither
94 
95    template <class T1, class T2>
96    class compressed_pair_imp<T1, T2, 0>
97    {
98    public:
99       typedef T1                                                 first_type;
100       typedef T2                                                 second_type;
101       typedef typename call_traits<first_type>::param_type       first_param_type;
102       typedef typename call_traits<second_type>::param_type      second_param_type;
103       typedef typename call_traits<first_type>::reference        first_reference;
104       typedef typename call_traits<second_type>::reference       second_reference;
105       typedef typename call_traits<first_type>::const_reference  first_const_reference;
106       typedef typename call_traits<second_type>::const_reference second_const_reference;
107 
compressed_pair_imp()108       compressed_pair_imp() {}
109 
compressed_pair_imp(first_param_type x,second_param_type y)110       compressed_pair_imp(first_param_type x, second_param_type y)
111          : first_(x), second_(y) {}
112 
compressed_pair_imp(first_param_type x)113       compressed_pair_imp(first_param_type x)
114          : first_(x) {}
115 
compressed_pair_imp(second_param_type y)116       compressed_pair_imp(second_param_type y)
117          : second_(y) {}
118 
first()119       first_reference       first()       {return first_;}
first() const120       first_const_reference first() const {return first_;}
121 
second()122       second_reference       second()       {return second_;}
second() const123       second_const_reference second() const {return second_;}
124 
swap(::boost::compressed_pair<T1,T2> & y)125       void swap(::boost::compressed_pair<T1, T2>& y)
126       {
127          cp_swap(first_, y.first());
128          cp_swap(second_, y.second());
129       }
130    private:
131       first_type first_;
132       second_type second_;
133    };
134 
135    // 1    derive from T1
136 
137    template <class T1, class T2>
138    class compressed_pair_imp<T1, T2, 1>
139       : protected ::boost::remove_cv<T1>::type
140    {
141    public:
142       typedef T1                                                 first_type;
143       typedef T2                                                 second_type;
144       typedef typename call_traits<first_type>::param_type       first_param_type;
145       typedef typename call_traits<second_type>::param_type      second_param_type;
146       typedef typename call_traits<first_type>::reference        first_reference;
147       typedef typename call_traits<second_type>::reference       second_reference;
148       typedef typename call_traits<first_type>::const_reference  first_const_reference;
149       typedef typename call_traits<second_type>::const_reference second_const_reference;
150 
compressed_pair_imp()151       compressed_pair_imp() {}
152 
compressed_pair_imp(first_param_type x,second_param_type y)153       compressed_pair_imp(first_param_type x, second_param_type y)
154          : first_type(x), second_(y) {}
155 
compressed_pair_imp(first_param_type x)156       compressed_pair_imp(first_param_type x)
157          : first_type(x) {}
158 
compressed_pair_imp(second_param_type y)159       compressed_pair_imp(second_param_type y)
160          : second_(y) {}
161 
first()162       first_reference       first()       {return *this;}
first() const163       first_const_reference first() const {return *this;}
164 
second()165       second_reference       second()       {return second_;}
second() const166       second_const_reference second() const {return second_;}
167 
swap(::boost::compressed_pair<T1,T2> & y)168       void swap(::boost::compressed_pair<T1,T2>& y)
169       {
170          // no need to swap empty base class:
171          cp_swap(second_, y.second());
172       }
173    private:
174       second_type second_;
175    };
176 
177    // 2    derive from T2
178 
179    template <class T1, class T2>
180    class compressed_pair_imp<T1, T2, 2>
181       : protected ::boost::remove_cv<T2>::type
182    {
183    public:
184       typedef T1                                                 first_type;
185       typedef T2                                                 second_type;
186       typedef typename call_traits<first_type>::param_type       first_param_type;
187       typedef typename call_traits<second_type>::param_type      second_param_type;
188       typedef typename call_traits<first_type>::reference        first_reference;
189       typedef typename call_traits<second_type>::reference       second_reference;
190       typedef typename call_traits<first_type>::const_reference  first_const_reference;
191       typedef typename call_traits<second_type>::const_reference second_const_reference;
192 
compressed_pair_imp()193       compressed_pair_imp() {}
194 
compressed_pair_imp(first_param_type x,second_param_type y)195       compressed_pair_imp(first_param_type x, second_param_type y)
196          : second_type(y), first_(x) {}
197 
compressed_pair_imp(first_param_type x)198       compressed_pair_imp(first_param_type x)
199          : first_(x) {}
200 
compressed_pair_imp(second_param_type y)201       compressed_pair_imp(second_param_type y)
202          : second_type(y) {}
203 
first()204       first_reference       first()       {return first_;}
first() const205       first_const_reference first() const {return first_;}
206 
second()207       second_reference       second()       {return *this;}
second() const208       second_const_reference second() const {return *this;}
209 
swap(::boost::compressed_pair<T1,T2> & y)210       void swap(::boost::compressed_pair<T1,T2>& y)
211       {
212          // no need to swap empty base class:
213          cp_swap(first_, y.first());
214       }
215 
216    private:
217       first_type first_;
218    };
219 
220    // 3    derive from T1 and T2
221 
222    template <class T1, class T2>
223    class compressed_pair_imp<T1, T2, 3>
224       : protected ::boost::remove_cv<T1>::type,
225         protected ::boost::remove_cv<T2>::type
226    {
227    public:
228       typedef T1                                                 first_type;
229       typedef T2                                                 second_type;
230       typedef typename call_traits<first_type>::param_type       first_param_type;
231       typedef typename call_traits<second_type>::param_type      second_param_type;
232       typedef typename call_traits<first_type>::reference        first_reference;
233       typedef typename call_traits<second_type>::reference       second_reference;
234       typedef typename call_traits<first_type>::const_reference  first_const_reference;
235       typedef typename call_traits<second_type>::const_reference second_const_reference;
236 
compressed_pair_imp()237       compressed_pair_imp() {}
238 
compressed_pair_imp(first_param_type x,second_param_type y)239       compressed_pair_imp(first_param_type x, second_param_type y)
240          : first_type(x), second_type(y) {}
241 
compressed_pair_imp(first_param_type x)242       compressed_pair_imp(first_param_type x)
243          : first_type(x) {}
244 
compressed_pair_imp(second_param_type y)245       compressed_pair_imp(second_param_type y)
246          : second_type(y) {}
247 
first()248       first_reference       first()       {return *this;}
first() const249       first_const_reference first() const {return *this;}
250 
second()251       second_reference       second()       {return *this;}
second() const252       second_const_reference second() const {return *this;}
253       //
254       // no need to swap empty bases:
swap(::boost::compressed_pair<T1,T2> &)255       void swap(::boost::compressed_pair<T1,T2>&) {}
256    };
257 
258    // JM
259    // 4    T1 == T2, T1 and T2 both empty
260    //      Originally this did not store an instance of T2 at all
261    //      but that led to problems beause it meant &x.first() == &x.second()
262    //      which is not true for any other kind of pair, so now we store an instance
263    //      of T2 just in case the user is relying on first() and second() returning
264    //      different objects (albeit both empty).
265    template <class T1, class T2>
266    class compressed_pair_imp<T1, T2, 4>
267       : protected ::boost::remove_cv<T1>::type
268    {
269    public:
270       typedef T1                                                 first_type;
271       typedef T2                                                 second_type;
272       typedef typename call_traits<first_type>::param_type       first_param_type;
273       typedef typename call_traits<second_type>::param_type      second_param_type;
274       typedef typename call_traits<first_type>::reference        first_reference;
275       typedef typename call_traits<second_type>::reference       second_reference;
276       typedef typename call_traits<first_type>::const_reference  first_const_reference;
277       typedef typename call_traits<second_type>::const_reference second_const_reference;
278 
compressed_pair_imp()279       compressed_pair_imp() {}
280 
compressed_pair_imp(first_param_type x,second_param_type y)281       compressed_pair_imp(first_param_type x, second_param_type y)
282          : first_type(x), m_second(y) {}
283 
compressed_pair_imp(first_param_type x)284       compressed_pair_imp(first_param_type x)
285          : first_type(x), m_second(x) {}
286 
first()287       first_reference       first()       {return *this;}
first() const288       first_const_reference first() const {return *this;}
289 
second()290       second_reference       second()       {return m_second;}
second() const291       second_const_reference second() const {return m_second;}
292 
swap(::boost::compressed_pair<T1,T2> &)293       void swap(::boost::compressed_pair<T1,T2>&) {}
294    private:
295       T2 m_second;
296    };
297 
298    // 5    T1 == T2 and are not empty:   //JM
299 
300    template <class T1, class T2>
301    class compressed_pair_imp<T1, T2, 5>
302    {
303    public:
304       typedef T1                                                 first_type;
305       typedef T2                                                 second_type;
306       typedef typename call_traits<first_type>::param_type       first_param_type;
307       typedef typename call_traits<second_type>::param_type      second_param_type;
308       typedef typename call_traits<first_type>::reference        first_reference;
309       typedef typename call_traits<second_type>::reference       second_reference;
310       typedef typename call_traits<first_type>::const_reference  first_const_reference;
311       typedef typename call_traits<second_type>::const_reference second_const_reference;
312 
compressed_pair_imp()313       compressed_pair_imp() {}
314 
compressed_pair_imp(first_param_type x,second_param_type y)315       compressed_pair_imp(first_param_type x, second_param_type y)
316          : first_(x), second_(y) {}
317 
compressed_pair_imp(first_param_type x)318       compressed_pair_imp(first_param_type x)
319          : first_(x), second_(x) {}
320 
first()321       first_reference       first()       {return first_;}
first() const322       first_const_reference first() const {return first_;}
323 
second()324       second_reference       second()       {return second_;}
second() const325       second_const_reference second() const {return second_;}
326 
swap(::boost::compressed_pair<T1,T2> & y)327       void swap(::boost::compressed_pair<T1, T2>& y)
328       {
329          cp_swap(first_, y.first());
330          cp_swap(second_, y.second());
331       }
332    private:
333       first_type first_;
334       second_type second_;
335    };
336 
337 }  // details
338 
339 template <class T1, class T2>
340 class compressed_pair
341    : private ::boost::details::compressed_pair_imp<T1, T2,
342              ::boost::details::compressed_pair_switch<
343                     T1,
344                     T2,
345                     ::boost::is_same<typename remove_cv<T1>::type, typename remove_cv<T2>::type>::value,
346                     ::boost::is_empty<T1>::value,
347                     ::boost::is_empty<T2>::value>::value>
348 {
349 private:
350    typedef 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::is_empty<T1>::value,
356                     ::boost::is_empty<T2>::value>::value> base;
357 public:
358    typedef T1                                                 first_type;
359    typedef T2                                                 second_type;
360    typedef typename call_traits<first_type>::param_type       first_param_type;
361    typedef typename call_traits<second_type>::param_type      second_param_type;
362    typedef typename call_traits<first_type>::reference        first_reference;
363    typedef typename call_traits<second_type>::reference       second_reference;
364    typedef typename call_traits<first_type>::const_reference  first_const_reference;
365    typedef typename call_traits<second_type>::const_reference second_const_reference;
366 
compressed_pair()367             compressed_pair() : base() {}
compressed_pair(first_param_type x,second_param_type y)368             compressed_pair(first_param_type x, second_param_type y) : base(x, y) {}
compressed_pair(first_param_type x)369    explicit compressed_pair(first_param_type x) : base(x) {}
compressed_pair(second_param_type y)370    explicit compressed_pair(second_param_type y) : base(y) {}
371 
first()372    first_reference       first()       {return base::first();}
first() const373    first_const_reference first() const {return base::first();}
374 
second()375    second_reference       second()       {return base::second();}
second() const376    second_const_reference second() const {return base::second();}
377 
swap(compressed_pair & y)378    void swap(compressed_pair& y) { base::swap(y); }
379 };
380 
381 // JM
382 // Partial specialisation for case where T1 == T2:
383 //
384 template <class T>
385 class compressed_pair<T, T>
386    : private details::compressed_pair_imp<T, T,
387              ::boost::details::compressed_pair_switch<
388                     T,
389                     T,
390                     ::boost::is_same<typename remove_cv<T>::type, typename remove_cv<T>::type>::value,
391                     ::boost::is_empty<T>::value,
392                     ::boost::is_empty<T>::value>::value>
393 {
394 private:
395    typedef 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::is_empty<T>::value,
401                     ::boost::is_empty<T>::value>::value> base;
402 public:
403    typedef T                                                  first_type;
404    typedef T                                                  second_type;
405    typedef typename call_traits<first_type>::param_type       first_param_type;
406    typedef typename call_traits<second_type>::param_type      second_param_type;
407    typedef typename call_traits<first_type>::reference        first_reference;
408    typedef typename call_traits<second_type>::reference       second_reference;
409    typedef typename call_traits<first_type>::const_reference  first_const_reference;
410    typedef typename call_traits<second_type>::const_reference second_const_reference;
411 
compressed_pair()412             compressed_pair() : base() {}
compressed_pair(first_param_type x,second_param_type y)413             compressed_pair(first_param_type x, second_param_type y) : base(x, y) {}
414 #if !(defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x530))
415    explicit
416 #endif
compressed_pair(first_param_type x)417       compressed_pair(first_param_type x) : base(x) {}
418 
first()419    first_reference       first()       {return base::first();}
first() const420    first_const_reference first() const {return base::first();}
421 
second()422    second_reference       second()       {return base::second();}
second() const423    second_const_reference second() const {return base::second();}
424 
swap(::boost::compressed_pair<T,T> & y)425    void swap(::boost::compressed_pair<T,T>& y) { base::swap(y); }
426 };
427 
428 template <class T1, class T2>
429 inline
430 void
swap(compressed_pair<T1,T2> & x,compressed_pair<T1,T2> & y)431 swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
432 {
433    x.swap(y);
434 }
435 
436 } // boost
437 
438 #ifdef BOOST_MSVC
439 # pragma warning(pop)
440 #endif
441 
442 #endif // BOOST_DETAIL_COMPRESSED_PAIR_HPP
443 
444