1 // (C) Copyright Steve Cleary, Beman Dawes, Howard Hinnant & John Maddock 2000.
2 // Permission to copy, use, modify, sell and
3 // distribute this software is granted provided this copyright notice appears
4 // in all copies. This software is provided "as is" without express or implied
5 // warranty, and with no claim as to its suitability for any purpose.
7 // See http://www.boost.org for most recent version including documentation.
8 // see libs/utility/compressed_pair.hpp
12 Fixed obvious bugs (David Abrahams)
14 Added better single argument constructor support.
16 Added VC6 support (JM).
18 Additional comments added. (JM)
20 Original version: this version crippled for use with crippled compilers
21 - John Maddock Jan 2000.
25 #ifndef BOOST_OB_COMPRESSED_PAIR_HPP
26 #define BOOST_OB_COMPRESSED_PAIR_HPP
29 #ifndef BOOST_OBJECT_TYPE_TRAITS_HPP
30 #include <boost/type_traits/object_traits.hpp>
32 #ifndef BOOST_SAME_TRAITS_HPP
33 #include <boost/type_traits/same_traits.hpp>
35 #ifndef BOOST_CALL_TRAITS_HPP
36 #include <boost/call_traits.hpp>
41 #ifdef BOOST_MSVC6_MEMBER_TEMPLATES
43 // use member templates to emulate
44 // partial specialisation. Note that due to
45 // problems with overload resolution with VC6
46 // each of the compressed_pair versions that follow
47 // have one template single-argument constructor
48 // in place of two specific constructors:
51 template <class T1, class T2>
52 class compressed_pair;
56 template <class A, class T1, class T2>
57 struct best_conversion_traits
60 typedef char (&two)[2];
65 enum { value = sizeof(test(a)) };
74 template <class A, class T1, class T2>
75 static void init(const A& a, T1* p1, T2*)
84 template <class A, class T1, class T2>
85 static void init(const A& a, T1*, T2* p2)
92 // T1 != T2, both non-empty
93 template <class T1, class T2>
94 class compressed_pair_0
100 typedef T1 first_type;
101 typedef T2 second_type;
102 typedef typename call_traits<first_type>::param_type first_param_type;
103 typedef typename call_traits<second_type>::param_type second_param_type;
104 typedef typename call_traits<first_type>::reference first_reference;
105 typedef typename call_traits<second_type>::reference second_reference;
106 typedef typename call_traits<first_type>::const_reference first_const_reference;
107 typedef typename call_traits<second_type>::const_reference second_const_reference;
109 compressed_pair_0() : _first(), _second() {}
110 compressed_pair_0(first_param_type x, second_param_type y) : _first(x), _second(y) {}
112 explicit compressed_pair_0(const A& val)
114 init_one<best_conversion_traits<A, T1, T2>::value>::init(val, &_first, &_second);
116 compressed_pair_0(const ::boost::compressed_pair<T1,T2>& x)
117 : _first(x.first()), _second(x.second()) {}
120 compressed_pair_0& operator=(const compressed_pair_0& x) {
121 cout << "assigning compressed pair 0" << endl;
124 cout << "finished assigning compressed pair 0" << endl;
129 first_reference first() { return _first; }
130 first_const_reference first() const { return _first; }
132 second_reference second() { return _second; }
133 second_const_reference second() const { return _second; }
135 void swap(compressed_pair_0& y)
138 swap(_first, y._first);
139 swap(_second, y._second);
143 // T1 != T2, T2 empty
144 template <class T1, class T2>
145 class compressed_pair_1 : T2
150 typedef T1 first_type;
151 typedef T2 second_type;
152 typedef typename call_traits<first_type>::param_type first_param_type;
153 typedef typename call_traits<second_type>::param_type second_param_type;
154 typedef typename call_traits<first_type>::reference first_reference;
155 typedef typename call_traits<second_type>::reference second_reference;
156 typedef typename call_traits<first_type>::const_reference first_const_reference;
157 typedef typename call_traits<second_type>::const_reference second_const_reference;
159 compressed_pair_1() : T2(), _first() {}
160 compressed_pair_1(first_param_type x, second_param_type y) : T2(y), _first(x) {}
163 explicit compressed_pair_1(const A& val)
165 init_one<best_conversion_traits<A, T1, T2>::value>::init(val, &_first, static_cast<T2*>(this));
168 compressed_pair_1(const ::boost::compressed_pair<T1,T2>& x)
169 : T2(x.second()), _first(x.first()) {}
172 // Total weirdness. If the assignment to _first is moved after
173 // the call to the inherited operator=, then this breaks graph/test/graph.cpp
174 // by way of iterator_adaptor.
175 compressed_pair_1& operator=(const compressed_pair_1& x) {
182 first_reference first() { return _first; }
183 first_const_reference first() const { return _first; }
185 second_reference second() { return *this; }
186 second_const_reference second() const { return *this; }
188 void swap(compressed_pair_1& y)
190 // no need to swap empty base class:
192 swap(_first, y._first);
196 // T1 != T2, T1 empty
197 template <class T1, class T2>
198 class compressed_pair_2 : T1
203 typedef T1 first_type;
204 typedef T2 second_type;
205 typedef typename call_traits<first_type>::param_type first_param_type;
206 typedef typename call_traits<second_type>::param_type second_param_type;
207 typedef typename call_traits<first_type>::reference first_reference;
208 typedef typename call_traits<second_type>::reference second_reference;
209 typedef typename call_traits<first_type>::const_reference first_const_reference;
210 typedef typename call_traits<second_type>::const_reference second_const_reference;
212 compressed_pair_2() : T1(), _second() {}
213 compressed_pair_2(first_param_type x, second_param_type y) : T1(x), _second(y) {}
215 explicit compressed_pair_2(const A& val)
217 init_one<best_conversion_traits<A, T1, T2>::value>::init(val, static_cast<T1*>(this), &_second);
219 compressed_pair_2(const ::boost::compressed_pair<T1,T2>& x)
220 : T1(x.first()), _second(x.second()) {}
223 compressed_pair_2& operator=(const compressed_pair_2& x) {
224 cout << "assigning compressed pair 2" << endl;
227 cout << "finished assigning compressed pair 2" << endl;
231 first_reference first() { return *this; }
232 first_const_reference first() const { return *this; }
234 second_reference second() { return _second; }
235 second_const_reference second() const { return _second; }
237 void swap(compressed_pair_2& y)
239 // no need to swap empty base class:
241 swap(_second, y._second);
245 // T1 != T2, both empty
246 template <class T1, class T2>
247 class compressed_pair_3 : T1, T2
250 typedef T1 first_type;
251 typedef T2 second_type;
252 typedef typename call_traits<first_type>::param_type first_param_type;
253 typedef typename call_traits<second_type>::param_type second_param_type;
254 typedef typename call_traits<first_type>::reference first_reference;
255 typedef typename call_traits<second_type>::reference second_reference;
256 typedef typename call_traits<first_type>::const_reference first_const_reference;
257 typedef typename call_traits<second_type>::const_reference second_const_reference;
259 compressed_pair_3() : T1(), T2() {}
260 compressed_pair_3(first_param_type x, second_param_type y) : T1(x), T2(y) {}
262 explicit compressed_pair_3(const A& val)
264 init_one<best_conversion_traits<A, T1, T2>::value>::init(val, static_cast<T1*>(this), static_cast<T2*>(this));
266 compressed_pair_3(const ::boost::compressed_pair<T1,T2>& x)
267 : T1(x.first()), T2(x.second()) {}
269 first_reference first() { return *this; }
270 first_const_reference first() const { return *this; }
272 second_reference second() { return *this; }
273 second_const_reference second() const { return *this; }
275 void swap(compressed_pair_3& y)
277 // no need to swap empty base classes:
281 // T1 == T2, and empty
282 template <class T1, class T2>
283 class compressed_pair_4 : T1
286 typedef T1 first_type;
287 typedef T2 second_type;
288 typedef typename call_traits<first_type>::param_type first_param_type;
289 typedef typename call_traits<second_type>::param_type second_param_type;
290 typedef typename call_traits<first_type>::reference first_reference;
291 typedef typename call_traits<second_type>::reference second_reference;
292 typedef typename call_traits<first_type>::const_reference first_const_reference;
293 typedef typename call_traits<second_type>::const_reference second_const_reference;
295 compressed_pair_4() : T1() {}
296 compressed_pair_4(first_param_type x, second_param_type) : T1(x) {}
297 // only one single argument constructor since T1 == T2
298 explicit compressed_pair_4(first_param_type x) : T1(x) {}
299 compressed_pair_4(const ::boost::compressed_pair<T1,T2>& x)
302 first_reference first() { return *this; }
303 first_const_reference first() const { return *this; }
305 second_reference second() { return *this; }
306 second_const_reference second() const { return *this; }
308 void swap(compressed_pair_4& y)
310 // no need to swap empty base classes:
314 // T1 == T2, not empty
315 template <class T1, class T2>
316 class compressed_pair_5
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;
331 compressed_pair_5() : _first(), _second() {}
332 compressed_pair_5(first_param_type x, second_param_type y) : _first(x), _second(y) {}
333 // only one single argument constructor since T1 == T2
334 explicit compressed_pair_5(first_param_type x) : _first(x), _second(x) {}
335 compressed_pair_5(const ::boost::compressed_pair<T1,T2>& c)
336 : _first(c.first()), _second(c.second()) {}
338 first_reference first() { return _first; }
339 first_const_reference first() const { return _first; }
341 second_reference second() { return _second; }
342 second_const_reference second() const { return _second; }
344 void swap(compressed_pair_5& y)
347 swap(_first, y._first);
348 swap(_second, y._second);
352 template <bool e1, bool e2, bool same>
353 struct compressed_pair_chooser
355 template <class T1, class T2>
358 typedef compressed_pair_0<T1, T2> type;
363 struct compressed_pair_chooser<false, true, false>
365 template <class T1, class T2>
368 typedef compressed_pair_1<T1, T2> type;
373 struct compressed_pair_chooser<true, false, false>
375 template <class T1, class T2>
378 typedef compressed_pair_2<T1, T2> type;
383 struct compressed_pair_chooser<true, true, false>
385 template <class T1, class T2>
388 typedef compressed_pair_3<T1, T2> type;
393 struct compressed_pair_chooser<true, true, true>
395 template <class T1, class T2>
398 typedef compressed_pair_4<T1, T2> type;
403 struct compressed_pair_chooser<false, false, true>
405 template <class T1, class T2>
408 typedef compressed_pair_5<T1, T2> type;
412 template <class T1, class T2>
413 struct compressed_pair_traits
416 typedef compressed_pair_chooser<is_empty<T1>::value, is_empty<T2>::value, is_same<T1,T2>::value> chooser;
417 typedef typename chooser::template rebind<T1, T2> bound_type;
419 typedef typename bound_type::type type;
422 } // namespace detail
424 template <class T1, class T2>
425 class compressed_pair : public detail::compressed_pair_traits<T1, T2>::type
428 typedef typename detail::compressed_pair_traits<T1, T2>::type base_type;
430 typedef T1 first_type;
431 typedef T2 second_type;
432 typedef typename call_traits<first_type>::param_type first_param_type;
433 typedef typename call_traits<second_type>::param_type second_param_type;
434 typedef typename call_traits<first_type>::reference first_reference;
435 typedef typename call_traits<second_type>::reference second_reference;
436 typedef typename call_traits<first_type>::const_reference first_const_reference;
437 typedef typename call_traits<second_type>::const_reference second_const_reference;
439 compressed_pair() : base_type() {}
440 compressed_pair(first_param_type x, second_param_type y) : base_type(x, y) {}
442 explicit compressed_pair(const A& x) : base_type(x){}
444 first_reference first() { return base_type::first(); }
445 first_const_reference first() const { return base_type::first(); }
447 second_reference second() { return base_type::second(); }
448 second_const_reference second() const { return base_type::second(); }
451 template <class T1, class T2>
452 inline void swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
458 // no partial specialisation, no member templates:
460 template <class T1, class T2>
461 class compressed_pair
467 typedef T1 first_type;
468 typedef T2 second_type;
469 typedef typename call_traits<first_type>::param_type first_param_type;
470 typedef typename call_traits<second_type>::param_type second_param_type;
471 typedef typename call_traits<first_type>::reference first_reference;
472 typedef typename call_traits<second_type>::reference second_reference;
473 typedef typename call_traits<first_type>::const_reference first_const_reference;
474 typedef typename call_traits<second_type>::const_reference second_const_reference;
476 compressed_pair() : _first(), _second() {}
477 compressed_pair(first_param_type x, second_param_type y) : _first(x), _second(y) {}
478 explicit compressed_pair(first_param_type x) : _first(x), _second() {}
479 // can't define this in case T1 == T2:
480 // explicit compressed_pair(second_param_type y) : _first(), _second(y) {}
482 first_reference first() { return _first; }
483 first_const_reference first() const { return _first; }
485 second_reference second() { return _second; }
486 second_const_reference second() const { return _second; }
488 void swap(compressed_pair& y)
491 swap(_first, y._first);
492 swap(_second, y._second);
496 template <class T1, class T2>
497 inline void swap(compressed_pair<T1, T2>& x, compressed_pair<T1, T2>& y)
506 #endif // BOOST_OB_COMPRESSED_PAIR_HPP