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